Index: .fossil-settings/clean-glob ================================================================== --- .fossil-settings/clean-glob +++ .fossil-settings/clean-glob @@ -6,10 +6,11 @@ *.exe *.framework *.library *.map *.o +*.sl *.so *.so.* */.deps .deps aclocal.m4 @@ -21,17 +22,19 @@ config.log config.status configure docs extra.mk -generators/gen_tables +generators/library/gen_libraries +generators/unicode/gen_tables src/Info.plist src/bridge/Info.plist +src/libobjfw.* src/objfw-defs.h src/runtime/Info.plist -src/runtime/amiga-library-functable.inc -src/runtime/inline.h +src/runtime/libobjfwrt.* +src/tls/Info.plist tests/DerivedData tests/EBOOT.PBP tests/Info.plist tests/PARAM.SFO tests/objc_sync/objc_sync @@ -44,6 +47,5 @@ utils/objfw-config utils/ofarc/ofarc utils/ofdns/ofdns utils/ofhash/ofhash utils/ofhttp/ofhttp -utils/ofsock/ofsock Index: .fossil-settings/ignore-glob ================================================================== --- .fossil-settings/ignore-glob +++ .fossil-settings/ignore-glob @@ -7,10 +7,11 @@ *.framework *.library *.map *.o *.orig +*.sl *.so *.so.* */.deps .deps .git @@ -23,17 +24,19 @@ config.log config.status configure docs extra.mk -generators/gen_tables +generators/library/gen_libraries +generators/unicode/gen_tables src/Info.plist src/bridge/Info.plist +src/libobjfw.* src/objfw-defs.h src/runtime/Info.plist -src/runtime/amiga-library-functable.inc -src/runtime/inline.h +src/runtime/libobjfwrt.* +src/tls/Info.plist tests/DerivedData tests/EBOOT.PBP tests/Info.plist tests/PARAM.SFO tests/iOS.xcodeproj/*.pbxuser @@ -49,6 +52,5 @@ utils/objfw-config utils/ofarc/ofarc utils/ofdns/ofdns utils/ofhash/ofhash utils/ofhttp/ofhttp -utils/ofsock/ofsock Index: .github/ISSUE_TEMPLATE/config.yml ================================================================== --- .github/ISSUE_TEMPLATE/config.yml +++ .github/ISSUE_TEMPLATE/config.yml @@ -13,9 +13,29 @@ about: Please use this if you have questions or want support. - name: ObjFW Matrix Room url: https://matrix.to/#/%23objfw:nil.im about: Please use this for interactive questions and support. - name: ObjFW IRC Channel - url: https://webchat.freenode.net/?channels=objfw + url: https://webchat.oftc.net/?channels=%23objfw + about: + Please use this for interactive questions and support - it is bridged to + the Matrix room above. + - name: ObjFW Slack Channel + url: https://objfw.nil.im/slack + about: + Please use this for interactive questions and support - it is bridged to + the Matrix room above. + - name: ObjFW Discord Channel + url: https://objfw.nil.im/discord + about: + Please use this for interactive questions and support - it is bridged to + the Matrix room above. + - name: ObjFW Telegram Room + url: https://t.me/objfw + about: + Please use this for interactive questions and support - it is bridged to + the Matrix room above. + - name: ObjFW Gitter Room + url: https://gitter.im/ObjFW/ObjFW about: Please use this for interactive questions and support - it is bridged to the Matrix room above. ADDED .github/workflows/amiga-gcc.yml Index: .github/workflows/amiga-gcc.yml ================================================================== --- /dev/null +++ .github/workflows/amiga-gcc.yml @@ -0,0 +1,37 @@ +name: amiga-gcc +on: [push, pull_request] +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + configure_flags: + - + - --disable-amiga-lib + 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 }}' + - 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)" + - 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)" ADDED .github/workflows/ios.yml Index: .github/workflows/ios.yml ================================================================== --- /dev/null +++ .github/workflows/ios.yml @@ -0,0 +1,35 @@ +name: ios +on: [push, pull_request] +jobs: + build: + runs-on: macos-latest + strategy: + matrix: + arch: + - arm64 + - x86_64 + configure_flags: + - + - --disable-shared + steps: + - name: Install dependencies + run: brew install autoconf automake + - uses: actions/checkout@v2 + - name: autogen.sh + run: ./autogen.sh + - name: configure + run: | + export IPHONEOS_DEPLOYMENT_TARGET="9.0" + if [ "${{ matrix.arch}}" = "x86_64" ]; then + sdk="iphonesimulator" + else + sdk="iphoneos" + fi + export OBJC="clang -isysroot $(xcrun --sdk $sdk --show-sdk-path)" + export OBJC="$OBJC -arch ${{ matrix.arch }}" + ./configure --host=${{ matrix.arch }}-apple-darwin \ + ${{ matrix.configure_flags }} + - name: make + run: make -j$(sysctl -n hw.logicalcpu) + - name: make install + run: sudo make install ADDED .github/workflows/macos-10.15.yml Index: .github/workflows/macos-10.15.yml ================================================================== --- /dev/null +++ .github/workflows/macos-10.15.yml @@ -0,0 +1,31 @@ +name: macos-10.15 +on: [push, pull_request] +jobs: + tests: + runs-on: macos-10.15 + strategy: + matrix: + configure_flags: + - + - --disable-threads + - --disable-threads --disable-sockets + - --disable-threads --disable-files + - --disable-threads --disable-sockets --disable-files + - --disable-sockets + - --disable-sockets --disable-files + - --disable-files + - --disable-shared + steps: + - name: Install dependencies + run: brew install autoconf automake + - uses: actions/checkout@v2 + - name: autogen.sh + run: ./autogen.sh + - name: configure + run: ./configure ${{ matrix.configure_flags }} + - name: make + run: make -j$(sysctl -n hw.logicalcpu) + - name: make check + run: make check + - name: make install + run: sudo make install ADDED .github/workflows/macos-11.yml Index: .github/workflows/macos-11.yml ================================================================== --- /dev/null +++ .github/workflows/macos-11.yml @@ -0,0 +1,31 @@ +name: macos-11 +on: [push, pull_request] +jobs: + tests: + runs-on: macos-11 + strategy: + matrix: + configure_flags: + - + - --disable-threads + - --disable-threads --disable-sockets + - --disable-threads --disable-files + - --disable-threads --disable-sockets --disable-files + - --disable-sockets + - --disable-sockets --disable-files + - --disable-files + - --disable-shared + steps: + - name: Install dependencies + run: brew install autoconf automake + - uses: actions/checkout@v2 + - name: autogen.sh + run: ./autogen.sh + - name: configure + run: ./configure ${{ matrix.configure_flags }} + - name: make + run: make -j$(sysctl -n hw.logicalcpu) + - name: make check + run: make check + - name: make install + run: sudo make install ADDED .github/workflows/morphos.yml Index: .github/workflows/morphos.yml ================================================================== --- /dev/null +++ .github/workflows/morphos.yml @@ -0,0 +1,37 @@ +name: morphos +on: [push, pull_request] +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + configure_flags: + - + - --disable-amiga-lib + 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 }}' + - 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)" + - 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)" ADDED .github/workflows/nintendo-3ds.yml Index: .github/workflows/nintendo-3ds.yml ================================================================== --- /dev/null +++ .github/workflows/nintendo-3ds.yml @@ -0,0 +1,35 @@ +name: nintendo-3ds +on: [push, pull_request] +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Install dependencies + run: docker pull devkitpro/devkitarm + - uses: actions/checkout@v2 + - name: autogen.sh + run: ./autogen.sh + - name: configure + run: | + docker run \ + -e DEVKITPRO=/opt/devkitpro \ + -e PATH="/opt/devkitpro/devkitARM/bin:$PATH" \ + -v "$PWD:/objfw" \ + devkitpro/devkitarm \ + sh -c 'cd /objfw && ./configure --host=arm-none-eabi --with-3ds' + - name: make + run: | + 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)" + - name: make install + run: | + 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)" ADDED .github/workflows/nintendo-ds.yml Index: .github/workflows/nintendo-ds.yml ================================================================== --- /dev/null +++ .github/workflows/nintendo-ds.yml @@ -0,0 +1,35 @@ +name: nintendo-ds +on: [push, pull_request] +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Install dependencies + run: docker pull devkitpro/devkitarm + - uses: actions/checkout@v2 + - name: autogen.sh + run: ./autogen.sh + - name: configure + run: | + docker run \ + -e DEVKITPRO=/opt/devkitpro \ + -e PATH="/opt/devkitpro/devkitARM/bin:$PATH" \ + -v "$PWD:/objfw" \ + devkitpro/devkitarm \ + sh -c 'cd /objfw && ./configure --host=arm-none-eabi --with-nds' + - name: make + run: | + 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)" + - name: make install + run: | + 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)" ADDED .github/workflows/ubuntu-18.04-32bit.yml Index: .github/workflows/ubuntu-18.04-32bit.yml ================================================================== --- /dev/null +++ .github/workflows/ubuntu-18.04-32bit.yml @@ -0,0 +1,37 @@ +name: ubuntu-18.04, 32 bit +on: [push, pull_request] +jobs: + tests: + runs-on: ubuntu-18.04 + strategy: + matrix: + configure_flags: + - --without-tls + - --without-tls --enable-seluid24 + - --without-tls --disable-compiler-tls + - --without-tls --disable-threads + - --without-tls --disable-threads --disable-sockets + - --without-tls --disable-threads --disable-files + - --without-tls --disable-threads --disable-sockets --disable-files + - --without-tls --disable-sockets + - --without-tls --disable-sockets --disable-files + - --without-tls --disable-files + - --without-tls --disable-shared + - --without-tls --disable-shared --enable-seluid24 + - --without-tls --disable-compiler-tls --disable-threads + steps: + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install gcc-multilib + - uses: actions/checkout@v2 + - name: autogen.sh + run: ./autogen.sh + - name: configure + run: ./configure OBJC="clang -m32" ${{ matrix.configure_flags }} + - name: make + run: make -j$(nproc) + - name: make check + run: make check + - name: make install + run: sudo make install ADDED .github/workflows/ubuntu-18.04-gcc-32bit.yml Index: .github/workflows/ubuntu-18.04-gcc-32bit.yml ================================================================== --- /dev/null +++ .github/workflows/ubuntu-18.04-gcc-32bit.yml @@ -0,0 +1,37 @@ +name: ubuntu-18.04, GCC, 32 bit +on: [push, pull_request] +jobs: + tests: + runs-on: ubuntu-18.04 + strategy: + matrix: + configure_flags: + - --without-tls + - --without-tls --enable-seluid24 + - --without-tls --disable-compiler-tls + - --without-tls --disable-threads + - --without-tls --disable-threads --disable-sockets + - --without-tls --disable-threads --disable-files + - --without-tls --disable-threads --disable-sockets --disable-files + - --without-tls --disable-sockets + - --without-tls --disable-sockets --disable-files + - --without-tls --disable-files + - --without-tls --disable-shared + - --without-tls --disable-shared --enable-seluid24 + - --without-tls --disable-compiler-tls --disable-threads + steps: + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install gcc-multilib gobjc + - uses: actions/checkout@v2 + - name: autogen.sh + run: ./autogen.sh + - name: configure + run: ./configure OBJC="gcc -m32" ${{ matrix.configure_flags }} + - name: make + run: make -j$(nproc) + - name: make check + run: make check + - name: make install + run: sudo make install ADDED .github/workflows/ubuntu-18.04-gcc.yml Index: .github/workflows/ubuntu-18.04-gcc.yml ================================================================== --- /dev/null +++ .github/workflows/ubuntu-18.04-gcc.yml @@ -0,0 +1,39 @@ +name: ubuntu-18.04, GCC +on: [push, pull_request] +jobs: + tests: + runs-on: ubuntu-18.04 + strategy: + matrix: + configure_flags: + - + - --enable-seluid24 + - --disable-compiler-tls + - --disable-threads + - --disable-threads --disable-sockets + - --disable-threads --disable-files + - --disable-threads --disable-sockets --disable-files + - --disable-sockets + - --disable-sockets --disable-files + - --disable-files + - --disable-shared + - --disable-shared --enable-seluid24 + - --disable-compiler-tls --disable-threads + - --with-tls=gnutls + - --with-tls=gnutls --disable-shared + steps: + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install gobjc libssl-dev gnutls-dev + - uses: actions/checkout@v2 + - name: autogen.sh + run: ./autogen.sh + - name: configure + run: ./configure OBJC="gcc" ${{ matrix.configure_flags }} + - name: make + run: make -j$(nproc) + - name: make check + run: make check + - name: make install + run: sudo make install ADDED .github/workflows/ubuntu-18.04.yml Index: .github/workflows/ubuntu-18.04.yml ================================================================== --- /dev/null +++ .github/workflows/ubuntu-18.04.yml @@ -0,0 +1,39 @@ +name: ubuntu-18.04 +on: [push, pull_request] +jobs: + tests: + runs-on: ubuntu-18.04 + strategy: + matrix: + configure_flags: + - + - --enable-seluid24 + - --disable-compiler-tls + - --disable-threads + - --disable-threads --disable-sockets + - --disable-threads --disable-files + - --disable-threads --disable-sockets --disable-files + - --disable-sockets + - --disable-sockets --disable-files + - --disable-files + - --disable-shared + - --disable-shared --enable-seluid24 + - --disable-compiler-tls --disable-threads + - --with-tls=gnutls + - --with-tls=gnutls --disable-shared + steps: + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install libssl-dev gnutls-dev + - uses: actions/checkout@v2 + - name: autogen.sh + run: ./autogen.sh + - name: configure + run: ./configure ${{ matrix.configure_flags }} + - name: make + run: make -j$(nproc) + - name: make check + run: make check + - name: make install + run: sudo make install ADDED .github/workflows/ubuntu-20.04-32bit.yml Index: .github/workflows/ubuntu-20.04-32bit.yml ================================================================== --- /dev/null +++ .github/workflows/ubuntu-20.04-32bit.yml @@ -0,0 +1,37 @@ +name: ubuntu-20.04, 32 bit +on: [push, pull_request] +jobs: + tests: + runs-on: ubuntu-20.04 + strategy: + matrix: + configure_flags: + - --without-tls + - --without-tls --enable-seluid24 + - --without-tls --disable-compiler-tls + - --without-tls --disable-threads + - --without-tls --disable-threads --disable-sockets + - --without-tls --disable-threads --disable-files + - --without-tls --disable-threads --disable-sockets --disable-files + - --without-tls --disable-sockets + - --without-tls --disable-sockets --disable-files + - --without-tls --disable-files + - --without-tls --disable-shared + - --without-tls --disable-shared --enable-seluid24 + - --without-tls --disable-compiler-tls --disable-threads + steps: + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install gcc-multilib + - uses: actions/checkout@v2 + - name: autogen.sh + run: ./autogen.sh + - name: configure + run: ./configure OBJC="clang -m32" ${{ matrix.configure_flags }} + - name: make + run: make -j$(nproc) + - name: make check + run: make check + - name: make install + run: sudo make install ADDED .github/workflows/ubuntu-20.04-gcc-32bit.yml Index: .github/workflows/ubuntu-20.04-gcc-32bit.yml ================================================================== --- /dev/null +++ .github/workflows/ubuntu-20.04-gcc-32bit.yml @@ -0,0 +1,37 @@ +name: ubuntu-20.04, GCC, 32 bit +on: [push, pull_request] +jobs: + tests: + runs-on: ubuntu-20.04 + strategy: + matrix: + configure_flags: + - --without-tls + - --without-tls --enable-seluid24 + - --without-tls --disable-compiler-tls + - --without-tls --disable-threads + - --without-tls --disable-threads --disable-sockets + - --without-tls --disable-threads --disable-files + - --without-tls --disable-threads --disable-sockets --disable-files + - --without-tls --disable-sockets + - --without-tls --disable-sockets --disable-files + - --without-tls --disable-files + - --without-tls --disable-shared + - --without-tls --disable-shared --enable-seluid24 + - --without-tls --disable-compiler-tls --disable-threads + steps: + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install gcc-multilib gobjc + - uses: actions/checkout@v2 + - name: autogen.sh + run: ./autogen.sh + - name: configure + run: ./configure OBJC="gcc -m32" ${{ matrix.configure_flags }} + - name: make + run: make -j$(nproc) + - name: make check + run: make check + - name: make install + run: sudo make install ADDED .github/workflows/ubuntu-20.04-gcc.yml Index: .github/workflows/ubuntu-20.04-gcc.yml ================================================================== --- /dev/null +++ .github/workflows/ubuntu-20.04-gcc.yml @@ -0,0 +1,39 @@ +name: ubuntu-20.04, GCC +on: [push, pull_request] +jobs: + tests: + runs-on: ubuntu-20.04 + strategy: + matrix: + configure_flags: + - + - --enable-seluid24 + - --disable-compiler-tls + - --disable-threads + - --disable-threads --disable-sockets + - --disable-threads --disable-files + - --disable-threads --disable-sockets --disable-files + - --disable-sockets + - --disable-sockets --disable-files + - --disable-files + - --disable-shared + - --disable-shared --enable-seluid24 + - --disable-compiler-tls --disable-threads + - --with-tls=gnutls + - --with-tls=gnutls --disable-shared + steps: + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install gobjc libssl-dev gnutls-dev + - uses: actions/checkout@v2 + - name: autogen.sh + run: ./autogen.sh + - name: configure + run: ./configure OBJC="gcc" ${{ matrix.configure_flags }} + - name: make + run: make -j$(nproc) + - name: make check + run: make check + - name: make install + run: sudo make install ADDED .github/workflows/ubuntu-20.04.yml Index: .github/workflows/ubuntu-20.04.yml ================================================================== --- /dev/null +++ .github/workflows/ubuntu-20.04.yml @@ -0,0 +1,39 @@ +name: ubuntu-20.04 +on: [push, pull_request] +jobs: + tests: + runs-on: ubuntu-20.04 + strategy: + matrix: + configure_flags: + - + - --enable-seluid24 + - --disable-compiler-tls + - --disable-threads + - --disable-threads --disable-sockets + - --disable-threads --disable-files + - --disable-threads --disable-sockets --disable-files + - --disable-sockets + - --disable-sockets --disable-files + - --disable-files + - --disable-shared + - --disable-shared --enable-seluid24 + - --disable-compiler-tls --disable-threads + - --with-tls=gnutls + - --with-tls=gnutls --disable-shared + steps: + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install libssl-dev gnutls-dev + - uses: actions/checkout@v2 + - name: autogen.sh + run: ./autogen.sh + - name: configure + run: ./configure ${{ matrix.configure_flags }} + - name: make + run: make -j$(nproc) + - name: make check + run: make check + - name: make install + run: sudo make install ADDED .github/workflows/wii.yml Index: .github/workflows/wii.yml ================================================================== --- /dev/null +++ .github/workflows/wii.yml @@ -0,0 +1,35 @@ +name: wii +on: [push, pull_request] +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Install dependencies + run: docker pull devkitpro/devkitppc + - uses: actions/checkout@v2 + - name: autogen.sh + run: ./autogen.sh + - name: configure + run: | + docker run \ + -e DEVKITPRO=/opt/devkitpro \ + -e PATH="/opt/devkitpro/devkitPPC/bin:$PATH" \ + -v "$PWD:/objfw" \ + devkitpro/devkitppc \ + sh -c 'cd /objfw && ./configure --host=powerpc-eabi --with-wii' + - name: make + run: | + 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)" + - name: make install + run: | + 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)" Index: .gitignore ================================================================== --- .gitignore +++ .gitignore @@ -7,10 +7,11 @@ *.framework *.library *.map *.o *.orig +*.sl *.so *.so.* .deps .fslckout _FOSSIL_ @@ -23,17 +24,19 @@ config.log config.status configure docs extra.mk -generators/gen_tables +generators/library/gen_libraries +generators/unicode/gen_tables src/Info.plist src/bridge/Info.plist +src/libobjfw.* src/objfw-defs.h src/runtime/Info.plist -src/runtime/amiga-library-functable.inc -src/runtime/inline.h +src/runtime/libobjfwrt.* +src/tls/Info.plist tests/DerivedData tests/EBOOT.PBP tests/Info.plist tests/PARAM.SFO tests/iOS.xcodeproj/*.pbxuser @@ -49,6 +52,5 @@ utils/objfw-config utils/ofarc/ofarc utils/ofdns/ofdns utils/ofhash/ofhash utils/ofhttp/ofhttp -utils/ofsock/ofsock DELETED .travis.yml Index: .travis.yml ================================================================== --- .travis.yml +++ /dev/null @@ -1,250 +0,0 @@ -language: c - -matrix: - include: - # Linux - - os: linux - compiler: clang - dist: precise - sudo: required - - - os: linux - compiler: gcc - dist: precise - sudo: required - - - os: linux - arch: arm64 - compiler: clang - dist: precise - sudo: required - - - os: linux - arch: arm64 - compiler: gcc - dist: precise - sudo: required - - - os: linux - arch: ppc64le - compiler: clang - dist: precise - sudo: required - - - os: linux - arch: ppc64le - compiler: gcc - dist: precise - sudo: required - - # Clang seems to have broken exceptions on s390x - #- os: linux - # arch: s390x - # compiler: clang - # dist: precise - # sudo: required - - - os: linux - arch: s390x - compiler: gcc - dist: precise - sudo: required - - - os: linux - compiler: clang - dist: trusty - sudo: required - - - os: linux - compiler: gcc - dist: trusty - sudo: required - - - os: linux - compiler: clang - dist: xenial - sudo: required - - - os: linux - compiler: gcc - dist: xenial - sudo: required - - - os: linux - compiler: clang - dist: bionic - sudo: required - - - os: linux - compiler: gcc - dist: bionic - sudo: required - - # macOS - - os: osx - osx_image: xcode11.2 - language: objective-c - env: - - no32bit=1 - - noruntime=1 # Broken compiler in this version of Xcode - - os: osx - osx_image: xcode11.1 - language: objective-c - env: - - no32bit=1 - - noruntime=1 # Broken compiler in this version of Xcode - - os: osx - osx_image: xcode11 - language: objective-c - env: - - no32bit=1 - - noruntime=1 # Broken compiler in this version of Xcode - - os: osx - osx_image: xcode10.3 - language: objective-c - env: - - no32bit=1 - - os: osx - osx_image: xcode10.2 - language: objective-c - env: - - no32bit=1 - - os: osx - osx_image: xcode10.1 - language: objective-c - - os: osx - osx_image: xcode10 - language: objective-c - - os: osx - osx_image: xcode9.4 - language: objective-c - - os: osx - osx_image: xcode9.3 - language: objective-c - - os: osx - osx_image: xcode9.2 - language: objective-c - - os: osx - osx_image: xcode9.1 - language: objective-c - - os: osx - osx_image: xcode9 - language: objective-c - - os: osx - osx_image: xcode8.3 - language: objective-c - - os: osx - osx_image: xcode8 - language: objective-c - - os: osx - osx_image: xcode7.3 - language: objective-c - - # iOS - - os: osx - osx_image: xcode11.2 - language: objective-c - env: - - config=ios - - os: osx - osx_image: xcode11.1 - language: objective-c - env: - - config=ios - - os: osx - osx_image: xcode11 - language: objective-c - env: - - config=ios - - os: osx - osx_image: xcode10.3 - language: objective-c - env: - - config=ios - - os: osx - osx_image: xcode10.2 - language: objective-c - env: - - config=ios - - os: osx - osx_image: xcode10.1 - language: objective-c - env: - - config=ios - - os: osx - osx_image: xcode10 - language: objective-c - env: - - config=ios - - os: osx - osx_image: xcode9.4 - language: objective-c - env: - - config=ios - - os: osx - osx_image: xcode9.3 - language: objective-c - env: - - config=ios - - os: osx - osx_image: xcode9.2 - language: objective-c - env: - - config=ios - - os: osx - osx_image: xcode9.1 - language: objective-c - env: - - config=ios - - os: osx - osx_image: xcode9 - language: objective-c - env: - - config=ios - - os: osx - osx_image: xcode8.3 - language: objective-c - env: - - config=ios - - os: osx - osx_image: xcode8 - language: objective-c - env: - - config=ios - - os: osx - osx_image: xcode7.3 - language: objective-c - env: - - config=ios - - # AmigaOS - - os: linux - dist: trusty - env: - - config=amigaos - - # Nintendo 3DS - - os: linux - dist: bionic - env: - - config=nintendo_3ds - - # Nintendo DS - - os: linux - dist: bionic - env: - - config=nintendo_ds - - # Nintendo Wii - - os: linux - dist: bionic - env: - - config=wii - -services: docker - -before_install: - - .travis/before_install.sh - -script: - - .travis/script.sh DELETED .travis/before_install.sh Index: .travis/before_install.sh ================================================================== --- .travis/before_install.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/sh -if [ "$TRAVIS_OS_NAME" = "linux" -a -z "$config" ]; then - case "$TRAVIS_CPU_ARCH" in - amd64 | s390x) - pkgs="gobjc-multilib" - ;; - *) - pkgs="gobjc" - ;; - esac - - pkgs="$pkgs libsctp-dev" - - if grep precise /etc/lsb-release >/dev/null; then - pkgs="$pkgs ipx" - fi - - # We don't need any of them and they're often broken. - sudo rm -f /etc/apt/sources.list.d/* - - if ! sudo apt-get -qq update >/tmp/apt_log 2>&1; then - cat /tmp/apt_log - exit 1 - fi - - if ! sudo apt-get -qq install -y $pkgs >>/tmp/apt_log 2>&1; then - cat /tmp/apt_log - exit 1 - fi - - if grep precise /etc/lsb-release >/dev/null; then - sudo ipx_internal_net add 1234 123456 - fi -fi - -if [ "$config" = "nintendo_3ds" -o "$config" = "nintendo_ds" ]; then - docker pull devkitpro/devkitarm -fi - -if [ "$config" = "wii" ]; then - docker pull devkitpro/devkitppc -fi - -if [ "$config" = "amigaos" ]; then - wget -q https://franke.ms/download/amiga-gcc.tgz - tar -C / -xzf amiga-gcc.tgz -fi DELETED .travis/build.sh Index: .travis/build.sh ================================================================== --- .travis/build.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/sh -cd $(dirname $0)/.. - -echo ">> Configuring with $@" -if ! ./configure ac_cv_path_TPUT= "$@"; then - cat config.log - exit 1 -fi - -echo ">> Building (configured with $@)" -if ! make -j4 >/tmp/make_log 2>&1; then - cat /tmp/make_log - exit 1 -fi - -echo ">> Installing (configured with $@)" -if ! sudo PATH="$PATH" make install >/tmp/install_log 2>&1; then - cat /tmp/install_log - exit 1 -fi DELETED .travis/script.sh Index: .travis/script.sh ================================================================== --- .travis/script.sh +++ /dev/null @@ -1,143 +0,0 @@ -#!/bin/sh -build() { - if ! git clean -fxd >/tmp/clean_log 2>&1; then - cat /tmp/clean_log - exit 1 - fi - - ./autogen.sh || exit 1 - .travis/build.sh "$@" || exit 1 -} - -if [ "$TRAVIS_OS_NAME" = "linux" -a -z "$config" ]; then - build_32_64() { - build OBJC="$CC" $@ - - case "$TRAVIS_CPU_ARCH" in - amd64) - build OBJC="$CC -m32" \ - --host=i686-pc-linux-gnu $@ - ;; - s390x) - build OBJC="$CC -m31" \ - --host=s390-pc-linux-gnu $@ - ;; - esac - } - - build_32_64 - build_32_64 --enable-seluid24 - build_32_64 --disable-compiler-tls - - # The following are not CPU-dependent, so only run them on amd64 - if [ "$TRAVIS_CPU_ARCH" = "amd64" ]; then - build_32_64 --disable-threads - build_32_64 --disable-threads --disable-sockets - build_32_64 --disable-threads --disable-files - build_32_64 --disable-threads --disable-sockets --disable-files - build_32_64 --disable-sockets - build_32_64 --disable-sockets --disable-files - build_32_64 --disable-files - build_32_64 --disable-shared - build_32_64 --disable-shared --enable-seluid24 - build_32_64 --disable-compiler-tls --disable-threads - fi -fi - -if [ "$TRAVIS_OS_NAME" = "osx" -a -z "$config" ]; then - build_mac_32_64() { - build $@ - - if [ -z "$no32bit" ]; then - build OBJC="clang -m32" --host=i386-apple-darwin $@ - fi - } - - if xcodebuild -version | grep 'Xcode 6' >/dev/null; then - export CPPFLAGS="-D_Null_unspecified=__null_unspecified" - export CPPFLAGS="$CPPFLAGS -D_Nullable=__nullable" - export CPPFLAGS="$CPPFLAGS -D_Nonnull=__nonnull" - fi - - build_mac_32_64 - build_mac_32_64 --disable-threads - build_mac_32_64 --disable-threads --disable-sockets - build_mac_32_64 --disable-threads --disable-files - build_mac_32_64 --disable-threads --disable-sockets --disable-files - build_mac_32_64 --disable-sockets - build_mac_32_64 --disable-sockets --disable-files - build_mac_32_64 --disable-files - build_mac_32_64 --disable-shared - - if [ -z "$noruntime" ]; then - build_mac_32_64 --enable-runtime - build_mac_32_64 --enable-runtime --enable-seluid24 - build_mac_32_64 --enable-runtime --disable-threads - build_mac_32_64 --enable-runtime --disable-threads \ - --disable-sockets - build_mac_32_64 --enable-runtime --disable-threads \ - --disable-files - build_mac_32_64 --enable-runtime --disable-threads \ - --disable-sockets --disable-files - build_mac_32_64 --enable-runtime --disable-sockets - build_mac_32_64 --enable-runtime --disable-sockets \ - --disable-files - build_mac_32_64 --enable-runtime --disable-files - build_mac_32_64 --enable-runtime --disable-shared - build_mac_32_64 --enable-runtime --disable-shared \ - --enable-seluid24 - fi -fi - -if [ "$config" = "ios" ]; then - if xcodebuild -version | grep 'Xcode 6' >/dev/null; then - export CPPFLAGS="-D_Null_unspecified=__null_unspecified" - export CPPFLAGS="$CPPFLAGS -D_Nullable=__nullable" - export CPPFLAGS="$CPPFLAGS -D_Nonnull=__nonnull" - fi - - export IPHONEOS_DEPLOYMENT_TARGET="9.0" - clang="clang -isysroot $(xcrun --sdk iphoneos --show-sdk-path)" - export OBJC="$clang -arch armv7 -arch arm64" - export OBJCPP="$clang -arch armv7 -E" - build --host=arm-apple-darwin --enable-static - - sysroot="$(xcrun --sdk iphonesimulator --show-sdk-path)" - clang="clang -isysroot $sysroot" - export OBJC="$clang -arch i386 -arch x86_64" - export OBJCPP="$clang -arch i386 -E" - build WRAPPER=true --host=i386-apple-darwin --enable-static -fi - -if [ "$config" = "amigaos" ]; then - export PATH="/opt/amiga/bin:$PATH" - - build --host=m68k-amigaos - build --host=m68k-amigaos --disable-amiga-lib - build --host=m68k-amigaos --enable-static -fi - -if [ "$config" = "nintendo_3ds" ]; then - ./autogen.sh - docker run -e DEVKITPRO=/opt/devkitpro \ - -e PATH="/opt/devkitpro/devkitARM/bin:$PATH" \ - -v $TRAVIS_BUILD_DIR:/objfw devkitpro/devkitarm \ - /objfw/.travis/build.sh --host=arm-none-eabi --with-3ds -fi - -if [ "$config" = "nintendo_ds" ]; then - ./autogen.sh - docker run -e DEVKITPRO=/opt/devkitpro \ - -e PATH="/opt/devkitpro/devkitARM/bin:$PATH" \ - -v $TRAVIS_BUILD_DIR:/objfw devkitpro/devkitarm \ - /objfw/.travis/build.sh --host=arm-none-eabi --with-nds -fi - -if [ "$config" = "wii" ]; then - ./autogen.sh - docker run -e DEVKITPRO=/opt/devkitpro \ - -e PATH="/opt/devkitpro/devkitPPC/bin:$PATH" \ - -v $TRAVIS_BUILD_DIR:/objfw devkitpro/devkitppc \ - /objfw/.travis/build.sh ac_cv_prog_wiiload= \ - --host=powerpc-eabi --with-wii -fi Index: Doxyfile ================================================================== --- Doxyfile +++ Doxyfile @@ -1,14 +1,18 @@ PROJECT_NAME = "ObjFW" OUTPUT_DIRECTORY = docs/ INPUT = src src/exceptions src/runtime FILE_PATTERNS = *.h *.m HTML_OUTPUT = . +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(...)= \ Index: Makefile ================================================================== --- Makefile +++ Makefile @@ -14,21 +14,23 @@ .PHONY: docs release utils tests: src +check: tests + cd tests && ${MAKE} -s run + docs: rm -fr docs doxygen >/dev/null release: docs echo "Generating tarball for version ${PACKAGE_VERSION}..." rm -fr objfw-${PACKAGE_VERSION} objfw-${PACKAGE_VERSION}.tar \ objfw-${PACKAGE_VERSION}.tar.gz fossil tarball --name objfw-${PACKAGE_VERSION} current - \ - --exclude '.cirrus*,.fossil*,.git*,.travis*' | \ - ofarc -ttgz -xq - + --exclude '.cirrus*,.fossil*,.git*' | ofarc -ttgz -xq - cp configure config.h.in objfw-${PACKAGE_VERSION}/ ofarc -cq objfw-${PACKAGE_VERSION}.tar \ $$(find objfw-${PACKAGE_VERSION} | sort) rm -fr objfw-${PACKAGE_VERSION} gzip -9 objfw-${PACKAGE_VERSION}.tar Index: PLATFORMS.md ================================================================== --- PLATFORMS.md +++ PLATFORMS.md @@ -65,10 +65,21 @@ * OS version: r1-alpha4 * Architectures: x86 * Compilers: Clang 3.2, GCC 4.6.3 * Runtimes: ObjFW + +HP-UX +----- + + * OS versions: 11i v1 (PA-RISC 2.0), 11i v3 (Itanium) + * Architectures: Itanium, PA-RISC 2.0 + * Compilers: GCC 4.7.2, GCC 7.5.0 + * Runtimes: ObjFW + * Notes: Exception handling on Itanium in 32 bit mode is broken, you need to + use 64 bit mode by passing `OBJC="gcc -mlp64"` to `configure`. + iOS --- * Architectures: ARMv7, ARM64 @@ -92,19 +103,28 @@ * OS Versions: 10.5, 10.7-10.15, Darling * Architectures: PowerPC, PowerPC64, x86, x86_64 * Compilers: Clang 3.1-10.0, Apple GCC 4.0.1 & 4.2.1 * Runtimes: Apple, ObjFW + +MiNT +---- + + * OS Versions: FreeMiNT 1.19 + * Architectures: m68k + * Runtimes: ObjFW + * Compilers: GCC 4.6.4 (MiNT 20130415) + * Limitations: No shared libraries, no threads + MorphOS ------- - * OS Versions: 3.9-3.11 + * OS Versions: 3.14 * Architectures: PowerPC - * Compilers: GCC 5.3.0, GCC 5.4.0 + * Compilers: GCC 9.3.0 * Runtimes: ObjFW - * Notes: libnix and ixemul are both supported NetBSD ------ @@ -183,16 +203,17 @@ Windows ------- - * OS Versions: 98 SE, NT 4.0, XP (x86), 7 (x64), 8 (x64), 8.1 (x64), 10, + * 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 + * Architectures: x86, x86_64, AArch64 * Compilers: GCC 5.3.0 & 6.2.0 from msys2 (x86 & x64), Clang 3.9.0 from msys2 (x86), - Clang 10.0 from msys2 (x86 & x86_64) + Clang 10.0 from msys2 (x86 & x86_64), + Clang 14.0.4 from msys2 (AArch64) * Runtimes: ObjFW Others ------ Index: README.md ================================================================== --- README.md +++ README.md @@ -1,10 +1,10 @@ There are three ways you are probably reading this right now: - * On [ObjFW](https://objfw.nil.im/)'s homepage, via Fossil + * On [ObjFW](https://objfw.nil.im/)'s homepage, via Fossil's web interface * On [GitHub](https://github.com/ObjFW/ObjFW) - * Via an editor or pager, by opening `README.md` from a checkout or tarball + * Via an editor or pager, by opening `README.md` from a clone or tarball ObjFW is developed using Fossil, so if you are reading this on GitHub or any other place, you are most likely using a mirror. @@ -19,12 +19,11 @@ * [Building as a framework](#building-framework) * [Using the macOS or iOS framework in Xcode](#framework-in-xcode) * [Broken Xcode versions](#broken-xcode-versions) * [Windows](#windows) * [Getting MSYS2](#getting-msys2) - * [Updating MSYS2](#updating-msys2) - * [Installing MinGW-w64 using MSYS2](#installing-mingw-w64) + * [Setting up MSYS2](#setting-up-msys2) * [Getting, building and installing ObjFW](#steps-windows) * [Nintendo DS, Nintendo 3DS and Wii](#nintendo) * [Nintendo DS](#nintendo-ds) * [Nintendo 3DS](#nintendo-3ds) * [Wii](#wii) @@ -31,10 +30,12 @@ * [Amiga](#amiga) * [Writing your first application with ObjFW](#first-app) * [Documentation](#documentation) * [Bugs and feature requests](#bugs) * [Support and community](#support) + * [Donating](#donating) + * [Thanks](#thanks) * [Commercial use](#commercial-use)

What is ObjFW?

@@ -106,17 +107,16 @@

Fossil

Clone the Fossil repository like this: - $ fossil clone https://objfw.nil.im objfw.fossil - $ mkdir objfw && cd objfw - $ fossil open ../objfw.fossil + $ fossil clone https://objfw.nil.im You can then use Fossil's web interface to browse the timeline, tickets, wiki pages, etc.: + $ cd objfw $ fossil ui It's also possible to open the same local repository multiple times, so that you have multiple working directories all backed by the same local repository. @@ -123,10 +123,16 @@ In order to verify the signature of the currently checked out checkin, you can use: $ fossil artifact current | gpg --verify + + Please note that not all checkins are signed, as the signing key only resides + on trusted systems. This means that checkins I perform on e.g. Windows are + unsigned. However, usually it should not take long until there is another + signed checkin. Alternatively, you can go back until the last signed checkin + and review changes from there on.

Git

To clone the Git repository, use the following: @@ -139,11 +145,12 @@ To install ObjFW, just run the following commands: $ ./configure $ make - $ make install + $ make check + $ sudo make install In case you checked out ObjFW from the Fossil or Git repository, you need to run the following command first: $ ./autogen.sh @@ -151,27 +158,33 @@

macOS and iOS

Building as a framework

When building for macOS or iOS, everything is built as a `.framework` by - default if `--disable-shared` has not been specified to `configure`. + default if `--disable-shared` has not been specified to `./configure`. The + frameworks will end up in `$PREFIX/Library/Frameworks`. - To build for iOS, use something like this: + To build for macOS, just follow the + 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" - $ ./configure --prefix=/usr/local/ios --host=arm-apple-darwin + $ ./configure --prefix=/usr/local/ios --host=arm64-apple-darwin - To build for the iOS simulator, use something like this: + 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 i386 -arch x86_64" - $ export OBJCPP="$clang -arch i386 -E" + $ 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=i386-apple-darwin + $ ./configure --prefix=/usr/local/iossim --host=arm64-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`: @@ -209,73 +222,61 @@

Getting MSYS2

The first thing to install is [MSYS2](https://www.msys2.org) to provide a basic UNIX-like environment for Windows. Unfortunately, the binaries are not - signed and there is no way to verify their integrity, so only download this - from a trusted connection. Everything else you will download using MSYS2 - later will be cryptographically signed. - -

Updating MSYS2

- - The first thing to do is updating MSYS2. It is important to update things in - a certain order, as `pacman` (the package manager MSYS2 uses, which comes - from Arch Linux) does not know about a few things that are special on - Windows. - - First, update the mirror list: - - $ pacman -Sy pacman-mirrors - - Then proceed to update the `msys2-runtime` itself, `bash` and `pacman`: - - $ pacman -S msys2-runtime bash pacman mintty - - Now close the current window and restart MSYS2, as the current window is now - defunct. In a new MSYS2 window, update the rest of MSYS2: - - $ pacman -Su - - Now you have a fully updated MSYS2. Whenever you want to update MSYS2, - proceed in this order. Notice that the first `pacman` invocation includes - `-y` to actually fetch a new list of packages. - -

Installing MinGW-w64 using MSYS2

- - Now it's time to install MinGW-w64. If you want to build 32 bit binaries: - - $ pacman -S mingw-w64-i686-clang mingw-w64-i686-gcc-objc - - For 64 bit binaries: - - $ pacman -S mingw-w64-x86_64-clang mingw-w64-x86_64-gcc-objc - - There is nothing wrong with installing them both, as MSYS2 has created two - entries in your start menu: `MinGW-w64 Win32 Shell` and - `MinGW-w64 Win64 Shell`. So if you want to build for 32 or 64 bit, you just - start the correct shell. - - Finally, install a few more things needed to build ObjFW: - - $ pacman -S autoconf automake fossil make + signed, so make sure you download it via HTTPS. However, packages you + download and install via MSYS2 are cryptographically signed. + +

Setting up MSYS2

+ + MSYS2 currently supports 5 different + [environments](https://www.msys2.org/docs/environments/). All of them except + for the one called just "MSYS" are supported, but which packages you need to + install depends on the environment(s) you want to use. + + For MINGW64, use: + + $ pacman -Syu mingw-w64-x86_64-clang mingw-w64-x86_64-fossil + + For UCRT64, use: + + $ pacman -Syu mingw-w64-ucrt-x86_64-clang mingw-w64-ucrt-x86_64-fossil + + For CLANG64, use: + + $ pacman -Syu mingw-w64-clang-x86_64-clang mingw-w64-clang-x86_64-fossil + + For MINGW32, use: + + $ pacman -Syu mingw-w64-i686-clang mingw-w64-i686-fossil + + When using `pacman` to install the packages, `pacman` might tell you to close + the window. If it does so, close the window, restart MSYS2 and execute the + `pacman` command again. + + There is nothing wrong with installing multiple environments, as MSYS2 has + created shortcuts for each of them in your start menu. Just make sure to use + the correct shortcut for the environment you want to use. + + Finally, install a few more things that are common between all environments: + + $ pacman -S autoconf automake make

Getting, building and installing ObjFW

- Start the MinGW-w64 Win32 or Win64 Shell (depening on what version you want - to build - do *not* use the MSYS2 Shell shortcut, but use the MinGW-w64 Win32 - or Win64 Shell shortcut instead!) and check out ObjFW: - - $ fossil clone https://objfw.nil.im objfw.fossil - $ mkdir objfw && cd objfw - $ fossil open ../objfw.fossil - - You can also download a release tarball if you want. Now go to the newly + Start the MSYS2 using the shortcut for the environment you want to use and + check out ObjFW: + + $ fossil clone https://objfw.nil.im + + You can also download a release tarball if you want. Now `cd` to the newly checked out repository and build and install it: $ ./autogen.sh && ./configure && make -j16 install - If everything was successfully, you can now build projects using ObjFW for + If everything was successful, you can now build projects using ObjFW for Windows using the normal `objfw-compile` and friends.

Nintendo DS, Nintendo 3DS and Wii

Download and install [devkitPro](https://devkitpro.org/wiki/Getting_Started). @@ -315,11 +316,11 @@ 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": - [of_stdout writeLine: @"Hello World!"]; + [OFStdOut writeLine: @"Hello World!"]; You can compile your new app using `objfw-compile`: $ objfw-compile -o MyFirstApp MyFirstApp.m @@ -336,11 +337,11 @@ In order to build the documentation yourself (necessary to have documentation for trunk / master), you need to have [Doxygen](https://www.doxygen.nl) installed. Once installed, you can build the documentation from the root directory of the repository: - $ doxygen >/dev/null + $ make docs

Bugs and feature requests

If you find any bugs or have feature requests, please @@ -354,19 +355,41 @@ If you have any questions about ObjFW or would like to talk to other ObjFW users, the following venues are available: * The [forum](https://objfw.nil.im/forum) - * A [Matrix](https://matrix.to/#/%23objfw:nil.im) room - * An [IRC channel](irc://chat.freenode.net/#objfw) on Freenode (`#objfw`, - [web chat](https://webchat.freenode.net/?channels=objfw)), bridged to the + * A [Matrix room](https://matrix.to/#/%23objfw:nil.im) + * An IRC channel named `#objfw` on `irc.oftc.net` + ([Web chat](https://webchat.oftc.net/?channels=%23objfw)), bridged to the Matrix room above + * A [Slack channel](https://objfw.nil.im/slack), bridged to the Matrix room + above + * A [Discord channel](https://objfw.nil.im/discord), bridged to the Matrix + room above + * A [Telegram room](https://t.me/objfw), bridged to the Matrix room above + * A [Gitter room](https://gitter.im/ObjFW/ObjFW), bridged to the Matrix room + above Please don't hesitate to join any or all of those! + +

Donating

+ + If you want to donate to ObjFW, you can read about possible ways to do so + [here](https://objfw.nil.im/wiki?name=Donating). + + +

Thanks

+ + * Thank you to [Jonathan Neuschäfer](https://github.com/neuschaefer) for + reviewing the *entirety* (all 84k LoC at the time) of ObjFW's codebase in + 2017! + * Thank you to [Hill Ma](https://github.com/mahiuchun) for donating an M1 Mac + Mini to the project! +

Commercial use

If for whatever reason neither the terms of the QPL nor those of the GPL work for you, a proprietary license for ObjFW including support is available upon request. Just write a mail to js@nil.im and we can find a reasonable solution for both parties. Index: build-aux/config.guess ================================================================== --- build-aux/config.guess +++ build-aux/config.guess @@ -1,10 +1,10 @@ #! /bin/sh # Attempt to guess a canonical system name. -# Copyright 1992-2018 Free Software Foundation, Inc. +# Copyright 1992-2019 Free Software Foundation, Inc. -timestamp='2018-03-08' +timestamp='2019-01-03' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. @@ -48,11 +48,11 @@ version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. -Copyright 1992-2018 Free Software Foundation, Inc. +Copyright 1992-2019 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" @@ -82,12 +82,10 @@ if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi -trap 'exit 1' 1 2 15 - # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. @@ -94,38 +92,42 @@ # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. -set_cc_for_build=' -trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; -trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; -: ${TMPDIR=/tmp} ; - { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || - { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || - { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || - { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; -dummy=$tmp/dummy ; -tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; -case $CC_FOR_BUILD,$HOST_CC,$CC in - ,,) echo "int x;" > "$dummy.c" ; - for c in cc gcc c89 c99 ; do - if ($c -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then - CC_FOR_BUILD="$c"; break ; - fi ; - done ; - if test x"$CC_FOR_BUILD" = x ; then - CC_FOR_BUILD=no_compiler_found ; - fi - ;; - ,,*) CC_FOR_BUILD=$CC ;; - ,*,*) CC_FOR_BUILD=$HOST_CC ;; -esac ; set_cc_for_build= ;' +tmp= +# shellcheck disable=SC2172 +trap 'test -z "$tmp" || rm -fr "$tmp"' 0 1 2 13 15 + +set_cc_for_build() { + : "${TMPDIR=/tmp}" + # shellcheck disable=SC2039 + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } + dummy=$tmp/dummy + case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in + ,,) echo "int x;" > "$dummy.c" + for driver in cc gcc c89 c99 ; do + if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then + CC_FOR_BUILD="$driver" + break + fi + done + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; + esac +} # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) -if (test -f /.attbin/uname) >/dev/null 2>&1 ; then +if test -f /.attbin/uname ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown @@ -136,11 +138,11 @@ Linux|GNU|GNU/*) # If the system lacks a compiler, then just pick glibc. # We could probably try harder. LIBC=gnu - eval "$set_cc_for_build" + set_cc_for_build cat <<-EOF > "$dummy.c" #include #if defined(__UCLIBC__) LIBC=uclibc #elif defined(__dietlibc__) @@ -178,17 +180,20 @@ UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ "/sbin/$sysctl" 2>/dev/null || \ "/usr/sbin/$sysctl" 2>/dev/null || \ echo unknown)` case "$UNAME_MACHINE_ARCH" in + aarch64eb) machine=aarch64_be-unknown ;; armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; - earmv*) - arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'` + earm*) + arch="${UNAME_MACHINE_ARCH#e}" + arch="${arch%eb}" + arch="${arch%hf}" endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'` machine="${arch}${endian}"-unknown ;; *) machine="$UNAME_MACHINE_ARCH"-unknown ;; esac @@ -197,11 +202,11 @@ case "$UNAME_MACHINE_ARCH" in earm*) os=netbsdelf ;; arm*|i386|m68k|ns32k|sh3*|sparc|vax) - eval "$set_cc_for_build" + set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? @@ -215,11 +220,11 @@ ;; esac # Determine ABI tags. case "$UNAME_MACHINE_ARCH" in earm*) - expr='s/^earmv[0-9]/-eabi/;s/eb$//' + expr='s/v[0-9]//;s/earm/-eabi/;s/eb$//' abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"` ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and @@ -235,11 +240,11 @@ ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. - echo "$machine-${os}${release}${abi}" + echo "$machine-${os}${release}${abi-}" exit ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` echo "$UNAME_MACHINE_ARCH"-unknown-bitrig"$UNAME_RELEASE" exit ;; @@ -381,17 +386,30 @@ exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) - echo sparc-sun-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`" + set_cc_for_build + SUN_ARCH=sparc + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if [ "$CC_FOR_BUILD" != no_compiler_found ]; then + if (echo '#ifdef __sparcv9'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH=sparcv9 + fi + fi + echo "$SUN_ARCH"-sun-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) echo i386-pc-auroraux"$UNAME_RELEASE" exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) - eval "$set_cc_for_build" + set_cc_for_build SUN_ARCH=i386 # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if [ "$CC_FOR_BUILD" != no_compiler_found ]; then @@ -480,11 +498,11 @@ exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix"$UNAME_RELEASE" exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) - eval "$set_cc_for_build" + set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else @@ -577,11 +595,11 @@ fi echo "$UNAME_MACHINE"-ibm-aix"$IBM_REV" exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then - eval "$set_cc_for_build" + set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #include main() { @@ -658,11 +676,11 @@ '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 esac ;; esac fi if [ "$HP_ARCH" = "" ]; then - eval "$set_cc_for_build" + set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #define _HPUX_SOURCE #include #include @@ -698,11 +716,11 @@ test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ "$HP_ARCH" = hppa2.0w ] then - eval "$set_cc_for_build" + set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # @@ -724,11 +742,11 @@ ia64:HP-UX:*:*) HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux"$HPUX_REV" exit ;; 3050*:HI-UX:*:*) - eval "$set_cc_for_build" + set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #include int main () { @@ -837,10 +855,21 @@ sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi"$UNAME_RELEASE" exit ;; *:BSD/OS:*:*) echo "$UNAME_MACHINE"-unknown-bsdi"$UNAME_RELEASE" + exit ;; + arm:FreeBSD:*:*) + UNAME_PROCESSOR=`uname -p` + set_cc_for_build + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + echo "${UNAME_PROCESSOR}"-unknown-freebsd"`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`"-gnueabi + else + echo "${UNAME_PROCESSOR}"-unknown-freebsd"`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`"-gnueabihf + fi exit ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` case "$UNAME_PROCESSOR" in amd64) @@ -879,11 +908,11 @@ esac ;; i*:UWIN*:*) echo "$UNAME_MACHINE"-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) - echo x86_64-unknown-cygwin + echo x86_64-pc-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" exit ;; *:GNU:*:*) @@ -892,12 +921,12 @@ exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo "$UNAME_MACHINE-unknown-`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`-$LIBC" exit ;; - i*86:Minix:*:*) - echo "$UNAME_MACHINE"-pc-minix + *:Minix:*:*) + echo "$UNAME_MACHINE"-unknown-minix exit ;; aarch64:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; aarch64_be:Linux:*:*) @@ -920,11 +949,11 @@ exit ;; arc:Linux:*:* | arceb:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; arm*:Linux:*:*) - eval "$set_cc_for_build" + set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" else @@ -969,11 +998,11 @@ exit ;; m68*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; mips:Linux:*:* | mips64:Linux:*:*) - eval "$set_cc_for_build" + set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #undef CPU #undef ${UNAME_MACHINE} #undef ${UNAME_MACHINE}el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) @@ -1283,11 +1312,11 @@ *:Rhapsody:*:*) echo "$UNAME_MACHINE"-apple-rhapsody"$UNAME_RELEASE" exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown - eval "$set_cc_for_build" + set_cc_for_build if test "$UNAME_PROCESSOR" = unknown ; then UNAME_PROCESSOR=powerpc fi if test "`echo "$UNAME_RELEASE" | sed -e 's/\..*//'`" -le 10 ; then if [ "$CC_FOR_BUILD" != no_compiler_found ]; then @@ -1356,10 +1385,11 @@ exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. + # shellcheck disable=SC2154 if test "$cputype" = 386; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi @@ -1412,10 +1442,13 @@ echo "$UNAME_MACHINE"-unknown-esx exit ;; amd64:Isilon\ OneFS:*:*) echo x86_64-unknown-onefs exit ;; + *:Unleashed:*:*) + echo "$UNAME_MACHINE"-unknown-unleashed"$UNAME_RELEASE" + exit ;; esac echo "$0: unable to guess system type" >&2 case "$UNAME_MACHINE:$UNAME_SYSTEM" in Index: build-aux/config.sub ================================================================== --- build-aux/config.sub +++ build-aux/config.sub @@ -1,10 +1,10 @@ #! /bin/sh # Configuration validation subroutine script. -# Copyright 1992-2018 Free Software Foundation, Inc. +# Copyright 1992-2019 Free Software Foundation, Inc. -timestamp='2018-03-08' +timestamp='2019-01-05' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. @@ -65,11 +65,11 @@ Report bugs and patches to ." version="\ GNU config.sub ($timestamp) -Copyright 1992-2018 Free Software Foundation, Inc. +Copyright 1992-2019 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" @@ -87,11 +87,11 @@ -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) - echo "$me: invalid option $1$help" + echo "$me: invalid option $1$help" >&2 exit 1 ;; *local*) # First pass through any local machine types. echo "$1" @@ -108,1431 +108,1418 @@ 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac -# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). -# Here we must recognize all the valid KERNEL-OS combinations. -maybe_os=`echo "$1" | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` -case $maybe_os in - nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ - linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ - knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \ - kopensolaris*-gnu* | cloudabi*-eabi* | \ - storm-chaos* | os2-emx* | rtmk-nova*) - os=-$maybe_os - basic_machine=`echo "$1" | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` - ;; - android-linux) - os=-linux-android - basic_machine=`echo "$1" | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown - ;; - *) - basic_machine=`echo "$1" | sed 's/-[^-]*$//'` - if [ "$basic_machine" != "$1" ] - then os=`echo "$1" | sed 's/.*-/-/'` - else os=; fi - ;; -esac - -### Let's recognize common machines as not being operating systems so -### that things like config.sub decstation-3100 work. We also -### recognize some manufacturers as not being operating systems, so we -### can provide default operating systems below. -case $os in - -sun*os*) - # Prevent following clause from handling this invalid input. - ;; - -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ - -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ - -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ - -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ - -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ - -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ - -apple | -axis | -knuth | -cray | -microblaze*) - os= - basic_machine=$1 - ;; - -bluegene*) - os=-cnk - ;; - -sim | -cisco | -oki | -wec | -winbond) - os= - basic_machine=$1 - ;; - -scout) - ;; - -wrs) - os=-vxworks - basic_machine=$1 - ;; - -chorusos*) - os=-chorusos - basic_machine=$1 - ;; - -chorusrdb) - os=-chorusrdb - basic_machine=$1 - ;; - -hiux*) - os=-hiuxwe2 - ;; - -sco6) - os=-sco5v6 - basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` - ;; - -sco5) - os=-sco3.2v5 - basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` - ;; - -sco4) - os=-sco3.2v4 - basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` - ;; - -sco3.2.[4-9]*) - os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` - basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` - ;; - -sco3.2v[4-9]*) - # Don't forget version if it is 3.2v4 or newer. - basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` - ;; - -sco5v6*) - # Don't forget version if it is 3.2v4 or newer. - basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` - ;; - -sco*) - os=-sco3.2v2 - basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` - ;; - -udk*) - basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` - ;; - -isc) - os=-isc2.2 - basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` - ;; - -clix*) - basic_machine=clipper-intergraph - ;; - -isc*) - basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` - ;; - -lynx*178) - os=-lynxos178 - ;; - -lynx*5) - os=-lynxos5 - ;; - -lynx*) - os=-lynxos - ;; - -ptx*) - basic_machine=`echo "$1" | sed -e 's/86-.*/86-sequent/'` - ;; - -psos*) - os=-psos - ;; - -mint | -mint[0-9]*) - basic_machine=m68k-atari - os=-mint - ;; -esac - -# Decode aliases for certain CPU-COMPANY combinations. +# Split fields of configuration type +# shellcheck disable=SC2162 +IFS="-" read field1 field2 field3 field4 <&2 + exit 1 + ;; + *-*-*-*) + basic_machine=$field1-$field2 + os=$field3-$field4 + ;; + *-*-*) + # Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two + # parts + maybe_os=$field2-$field3 + case $maybe_os in + nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc \ + | linux-newlib* | linux-musl* | linux-uclibc* | uclinux-uclibc* \ + | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \ + | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \ + | storm-chaos* | os2-emx* | rtmk-nova*) + basic_machine=$field1 + os=$maybe_os + ;; + android-linux) + basic_machine=$field1-unknown + os=linux-android + ;; + *) + basic_machine=$field1-$field2 + os=$field3 + ;; + esac + ;; + *-*) + # A lone config we happen to match not fitting any pattern + case $field1-$field2 in + decstation-3100) + basic_machine=mips-dec + os= + ;; + *-*) + # Second component is usually, but not always the OS + case $field2 in + # Prevent following clause from handling this valid os + sun*os*) + basic_machine=$field1 + os=$field2 + ;; + # Manufacturers + dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \ + | att* | 7300* | 3300* | delta* | motorola* | sun[234]* \ + | unicom* | ibm* | next | hp | isi* | apollo | altos* \ + | convergent* | ncr* | news | 32* | 3600* | 3100* \ + | hitachi* | c[123]* | convex* | sun | crds | omron* | dg \ + | ultra | tti* | harris | dolphin | highlevel | gould \ + | cbm | ns | masscomp | apple | axis | knuth | cray \ + | microblaze* | sim | cisco \ + | oki | wec | wrs | winbond) + basic_machine=$field1-$field2 + os= + ;; + *) + basic_machine=$field1 + os=$field2 + ;; + esac + ;; + esac + ;; + *) + # Convert single-component short-hands not valid as part of + # multi-component configurations. + case $field1 in + 386bsd) + basic_machine=i386-pc + os=bsd + ;; + a29khif) + basic_machine=a29k-amd + os=udi + ;; + adobe68k) + basic_machine=m68010-adobe + os=scout + ;; + alliant) + basic_machine=fx80-alliant + os= + ;; + altos | altos3068) + basic_machine=m68k-altos + os= + ;; + am29k) + basic_machine=a29k-none + os=bsd + ;; + amdahl) + basic_machine=580-amdahl + os=sysv + ;; + amiga) + basic_machine=m68k-unknown + os= + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=bsd + ;; + aros) + basic_machine=i386-pc + os=aros + ;; + aux) + basic_machine=m68k-apple + os=aux + ;; + balance) + basic_machine=ns32k-sequent + os=dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=linux + ;; + cegcc) + basic_machine=arm-unknown + os=cegcc + ;; + convex-c1) + basic_machine=c1-convex + os=bsd + ;; + convex-c2) + basic_machine=c2-convex + os=bsd + ;; + convex-c32) + basic_machine=c32-convex + os=bsd + ;; + convex-c34) + basic_machine=c34-convex + os=bsd + ;; + convex-c38) + basic_machine=c38-convex + os=bsd + ;; + cray) + basic_machine=j90-cray + os=unicos + ;; + crds | unos) + basic_machine=m68k-crds + os= + ;; + da30) + basic_machine=m68k-da30 + os= + ;; + decstation | pmax | pmin | dec3100 | decstatn) + basic_machine=mips-dec + os= + ;; + delta88) + basic_machine=m88k-motorola + os=sysv3 + ;; + dicos) + basic_machine=i686-pc + os=dicos + ;; + djgpp) + basic_machine=i586-pc + os=msdosdjgpp + ;; + ebmon29k) + basic_machine=a29k-amd + os=ebmon + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=ose + ;; + gmicro) + basic_machine=tron-gmicro + os=sysv + ;; + go32) + basic_machine=i386-pc + os=go32 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=hms + ;; + harris) + basic_machine=m88k-harris + os=sysv3 + ;; + hp300) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=hpux + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=proelf + ;; + i386mach) + basic_machine=i386-mach + os=mach + ;; + vsta) + basic_machine=i386-pc + os=vsta + ;; + isi68 | isi) + basic_machine=m68k-isi + os=sysv + ;; + m68knommu) + basic_machine=m68k-unknown + os=linux + ;; + magnum | m3230) + basic_machine=mips-mips + os=sysv + ;; + merlin) + basic_machine=ns32k-utek + os=sysv + ;; + mingw64) + basic_machine=x86_64-pc + os=mingw64 + ;; + mingw32) + basic_machine=i686-pc + os=mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=mingw32ce + ;; + monitor) + basic_machine=m68k-rom68k + os=coff + ;; + morphos) + basic_machine=powerpc-unknown + os=morphos + ;; + moxiebox) + basic_machine=moxie-unknown + os=moxiebox + ;; + msdos) + basic_machine=i386-pc + os=msdos + ;; + msys) + basic_machine=i686-pc + os=msys + ;; + mvs) + basic_machine=i370-ibm + os=mvs + ;; + nacl) + basic_machine=le32-unknown + os=nacl + ;; + ncr3000) + basic_machine=i486-ncr + os=sysv4 + ;; + netbsd386) + basic_machine=i386-pc + os=netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=newsos + ;; + news1000) + basic_machine=m68030-sony + os=newsos + ;; + necv70) + basic_machine=v70-nec + os=sysv + ;; + nh3000) + basic_machine=m68k-harris + os=cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=cxux + ;; + nindy960) + basic_machine=i960-intel + os=nindy + ;; + mon960) + basic_machine=i960-intel + os=mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=nonstopux + ;; + os400) + basic_machine=powerpc-ibm + os=os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=ose + ;; + os68k) + basic_machine=m68k-none + os=os68k + ;; + paragon) + basic_machine=i860-intel + os=osf + ;; + parisc) + basic_machine=hppa-unknown + os=linux + ;; + pw32) + basic_machine=i586-unknown + os=pw32 + ;; + rdos | rdos64) + basic_machine=x86_64-pc + os=rdos + ;; + rdos32) + basic_machine=i386-pc + os=rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=coff + ;; + sa29200) + basic_machine=a29k-amd + os=udi + ;; + sei) + basic_machine=mips-sei + os=seiux + ;; + sequent) + basic_machine=i386-sequent + os= + ;; + sps7) + basic_machine=m68k-bull + os=sysv2 + ;; + st2000) + basic_machine=m68k-tandem + os= + ;; + stratus) + basic_machine=i860-stratus + os=sysv4 + ;; + sun2) + basic_machine=m68000-sun + os= + ;; + sun2os3) + basic_machine=m68000-sun + os=sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=sunos4 + ;; + sun3) + basic_machine=m68k-sun + os= + ;; + sun3os3) + basic_machine=m68k-sun + os=sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=sunos4 + ;; + sun4) + basic_machine=sparc-sun + os= + ;; + sun4os3) + basic_machine=sparc-sun + os=sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=solaris2 + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + os= + ;; + sv1) + basic_machine=sv1-cray + os=unicos + ;; + symmetry) + basic_machine=i386-sequent + os=dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=unicos + ;; + t90) + basic_machine=t90-cray + os=unicos + ;; + toad1) + basic_machine=pdp10-xkl + os=tops20 + ;; + tpf) + basic_machine=s390x-ibm + os=tpf + ;; + udi29k) + basic_machine=a29k-amd + os=udi + ;; + ultra3) + basic_machine=a29k-nyu + os=sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=none + ;; + vaxv) + basic_machine=vax-dec + os=sysv + ;; + vms) + basic_machine=vax-dec + os=vms + ;; + vxworks960) + basic_machine=i960-wrs + os=vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=vxworks + ;; + xbox) + basic_machine=i686-pc + os=mingw32 + ;; + ymp) + basic_machine=ymp-cray + os=unicos + ;; + *) + basic_machine=$1 + os= + ;; + esac + ;; +esac + +# Decode 1-component or ad-hoc basic machines case $basic_machine in - # Recognize the basic CPU types without company name. - # Some are omitted here because they have special meanings below. - 1750a | 580 \ - | a29k \ - | aarch64 | aarch64_be | arm64 \ - | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ - | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ - | am33_2.0 \ - | arc | arceb \ - | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ - | avr | avr32 \ - | ba \ - | be32 | be64 \ - | bfin \ - | c4x | c8051 | clipper \ - | d10v | d30v | dlx | dsp16xx \ - | e2k | epiphany \ - | fido | fr30 | frv | ft32 \ - | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ - | hexagon \ - | i370 | i860 | i960 | ia16 | ia64 \ - | ip2k | iq2000 \ - | k1om \ - | le32 | le64 \ - | lm32 \ - | m32c | m32r | m32rle | m68000 | m68k | m88k \ - | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ - | mips | mipsbe | mipseb | mipsel | mipsle \ - | mips16 \ - | mips64 | mips64el \ - | mips64octeon | mips64octeonel \ - | mips64orion | mips64orionel \ - | mips64r5900 | mips64r5900el \ - | mips64vr | mips64vrel \ - | mips64vr4100 | mips64vr4100el \ - | mips64vr4300 | mips64vr4300el \ - | mips64vr5000 | mips64vr5000el \ - | mips64vr5900 | mips64vr5900el \ - | mipsisa32 | mipsisa32el \ - | mipsisa32r2 | mipsisa32r2el \ - | mipsisa32r6 | mipsisa32r6el \ - | mipsisa64 | mipsisa64el \ - | mipsisa64r2 | mipsisa64r2el \ - | mipsisa64r6 | mipsisa64r6el \ - | mipsisa64sb1 | mipsisa64sb1el \ - | mipsisa64sr71k | mipsisa64sr71kel \ - | mipsr5900 | mipsr5900el \ - | mipstx39 | mipstx39el \ - | mn10200 | mn10300 \ - | moxie \ - | mt \ - | msp430 \ - | nds32 | nds32le | nds32be \ - | nios | nios2 | nios2eb | nios2el \ - | ns16k | ns32k \ - | open8 | or1k | or1knd | or32 \ - | pdp10 | pj | pjl \ - | powerpc | powerpc64 | powerpc64le | powerpcle \ - | pru \ - | pyramid \ - | riscv32 | riscv64 \ - | rl78 | rx \ - | score \ - | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ - | sh64 | sh64le \ - | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ - | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ - | spu \ - | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ - | ubicom32 \ - | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ - | visium \ - | wasm32 \ - | x86 | xc16x | xstormy16 | xtensa \ - | z8k | z80) - basic_machine=$basic_machine-unknown - ;; - c54x) - basic_machine=tic54x-unknown - ;; - c55x) - basic_machine=tic55x-unknown - ;; - c6x) - basic_machine=tic6x-unknown + # Here we handle the default manufacturer of certain CPU types. It is in + # some cases the only manufacturer, in others, it is the most popular. + w89k) + cpu=hppa1.1 + vendor=winbond + ;; + op50n) + cpu=hppa1.1 + vendor=oki + ;; + op60c) + cpu=hppa1.1 + vendor=oki + ;; + ibm*) + cpu=i370 + vendor=ibm + ;; + orion105) + cpu=clipper + vendor=highlevel + ;; + mac | mpw | mac-mpw) + cpu=m68k + vendor=apple + ;; + pmac | pmac-mpw) + cpu=powerpc + vendor=apple + ;; + + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + cpu=m68000 + vendor=att + ;; + 3b*) + cpu=we32k + vendor=att + ;; + bluegene*) + cpu=powerpc + vendor=ibm + os=cnk + ;; + decsystem10* | dec10*) + cpu=pdp10 + vendor=dec + os=tops10 + ;; + decsystem20* | dec20*) + cpu=pdp10 + vendor=dec + os=tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + cpu=m68k + vendor=motorola + ;; + dpx2*) + cpu=m68k + vendor=bull + os=sysv3 + ;; + encore | umax | mmax) + cpu=ns32k + vendor=encore + ;; + elxsi) + cpu=elxsi + vendor=elxsi + os=${os:-bsd} + ;; + fx2800) + cpu=i860 + vendor=alliant + ;; + genix) + cpu=ns32k + vendor=ns + ;; + h3050r* | hiux*) + cpu=hppa1.1 + vendor=hitachi + os=hiuxwe2 + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + cpu=hppa1.0 + vendor=hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + cpu=m68000 + vendor=hp + ;; + hp9k3[2-9][0-9]) + cpu=m68k + vendor=hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + cpu=hppa1.0 + vendor=hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + cpu=hppa1.1 + vendor=hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + cpu=hppa1.1 + vendor=hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + cpu=hppa1.1 + vendor=hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + cpu=hppa1.1 + vendor=hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + cpu=hppa1.0 + vendor=hp + ;; + i*86v32) + cpu=`echo "$1" | sed -e 's/86.*/86/'` + vendor=pc + os=sysv32 + ;; + i*86v4*) + cpu=`echo "$1" | sed -e 's/86.*/86/'` + vendor=pc + os=sysv4 + ;; + i*86v) + cpu=`echo "$1" | sed -e 's/86.*/86/'` + vendor=pc + os=sysv + ;; + i*86sol2) + cpu=`echo "$1" | sed -e 's/86.*/86/'` + vendor=pc + os=solaris2 + ;; + j90 | j90-cray) + cpu=j90 + vendor=cray + os=${os:-unicos} + ;; + iris | iris4d) + cpu=mips + vendor=sgi + case $os in + irix*) + ;; + *) + os=irix4 + ;; + esac + ;; + miniframe) + cpu=m68000 + vendor=convergent + ;; + *mint | mint[0-9]* | *MiNT | *MiNT[0-9]*) + cpu=m68k + vendor=atari + os=mint + ;; + news-3600 | risc-news) + cpu=mips + vendor=sony + os=newsos + ;; + next | m*-next) + cpu=m68k + vendor=next + case $os in + nextstep* ) + ;; + ns2*) + os=nextstep2 + ;; + *) + os=nextstep3 + ;; + esac + ;; + np1) + cpu=np1 + vendor=gould + ;; + op50n-* | op60c-*) + cpu=hppa1.1 + vendor=oki + os=proelf + ;; + pa-hitachi) + cpu=hppa1.1 + vendor=hitachi + os=hiuxwe2 + ;; + pbd) + cpu=sparc + vendor=tti + ;; + pbb) + cpu=m68k + vendor=tti + ;; + pc532) + cpu=ns32k + vendor=pc532 + ;; + pn) + cpu=pn + vendor=gould + ;; + power) + cpu=power + vendor=ibm + ;; + ps2) + cpu=i386 + vendor=ibm + ;; + psp) + cpu=mipsallegrexel + vendor=psp + ;; + rm[46]00) + cpu=mips + vendor=siemens + ;; + rtpc | rtpc-*) + cpu=romp + vendor=ibm + ;; + sde) + cpu=mipsisa32 + vendor=sde + os=${os:-elf} + ;; + simso-wrs) + cpu=sparclite + vendor=wrs + os=vxworks + ;; + tower | tower-32) + cpu=m68k + vendor=ncr + ;; + vpp*|vx|vx-*) + cpu=f301 + vendor=fujitsu + ;; + w65) + cpu=w65 + vendor=wdc + ;; + w89k-*) + cpu=hppa1.1 + vendor=winbond + os=proelf + ;; + none) + cpu=none + vendor=none ;; leon|leon[3-9]) - basic_machine=sparc-$basic_machine - ;; - m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) - basic_machine=$basic_machine-unknown - os=-none - ;; - m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65) - ;; - ms1) - basic_machine=mt-unknown - ;; - - strongarm | thumb | xscale) - basic_machine=arm-unknown - ;; - xgate) - basic_machine=$basic_machine-unknown - os=-none - ;; - xscaleeb) - basic_machine=armeb-unknown - ;; - - xscaleel) - basic_machine=armel-unknown - ;; - + cpu=sparc + vendor=$basic_machine + ;; + leon-*|leon[3-9]-*) + cpu=sparc + vendor=`echo "$basic_machine" | sed 's/-.*//'` + ;; + + *-*) + # shellcheck disable=SC2162 + IFS="-" read cpu vendor <&2 - exit 1 - ;; - # Recognize the basic CPU types with company name. - 580-* \ - | a29k-* \ - | aarch64-* | aarch64_be-* | arm64-* \ - | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ - | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ - | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ - | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ - | avr-* | avr32-* \ - | ba-* \ - | be32-* | be64-* \ - | bfin-* | bs2000-* \ - | c[123]* | c30-* | [cjt]90-* | c4x-* \ - | c8051-* | clipper-* | craynv-* | cydra-* \ - | d10v-* | d30v-* | dlx-* \ - | e2k-* | elxsi-* \ - | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ - | h8300-* | h8500-* \ - | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ - | hexagon-* \ - | i*86-* | i860-* | i960-* | ia16-* | ia64-* \ - | ip2k-* | iq2000-* \ - | k1om-* \ - | le32-* | le64-* \ - | lm32-* \ - | m32c-* | m32r-* | m32rle-* \ - | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ - | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ - | microblaze-* | microblazeel-* \ - | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ - | mips16-* \ - | mips64-* | mips64el-* \ - | mips64octeon-* | mips64octeonel-* \ - | mips64orion-* | mips64orionel-* \ - | mips64r5900-* | mips64r5900el-* \ - | mips64vr-* | mips64vrel-* \ - | mips64vr4100-* | mips64vr4100el-* \ - | mips64vr4300-* | mips64vr4300el-* \ - | mips64vr5000-* | mips64vr5000el-* \ - | mips64vr5900-* | mips64vr5900el-* \ - | mipsisa32-* | mipsisa32el-* \ - | mipsisa32r2-* | mipsisa32r2el-* \ - | mipsisa32r6-* | mipsisa32r6el-* \ - | mipsisa64-* | mipsisa64el-* \ - | mipsisa64r2-* | mipsisa64r2el-* \ - | mipsisa64r6-* | mipsisa64r6el-* \ - | mipsisa64sb1-* | mipsisa64sb1el-* \ - | mipsisa64sr71k-* | mipsisa64sr71kel-* \ - | mipsr5900-* | mipsr5900el-* \ - | mipstx39-* | mipstx39el-* \ - | mmix-* \ - | mt-* \ - | msp430-* \ - | nds32-* | nds32le-* | nds32be-* \ - | nios-* | nios2-* | nios2eb-* | nios2el-* \ - | none-* | np1-* | ns16k-* | ns32k-* \ - | open8-* \ - | or1k*-* \ - | orion-* \ - | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ - | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ - | pru-* \ - | pyramid-* \ - | riscv32-* | riscv64-* \ - | rl78-* | romp-* | rs6000-* | rx-* \ - | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ - | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ - | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ - | sparclite-* \ - | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \ - | tahoe-* \ - | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ - | tile*-* \ - | tron-* \ - | ubicom32-* \ - | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ - | vax-* \ - | visium-* \ - | wasm32-* \ - | we32k-* \ - | x86-* | x86_64-* | xc16x-* | xps100-* \ - | xstormy16-* | xtensa*-* \ - | ymp-* \ - | z8k-* | z80-*) - ;; - # Recognize the basic CPU types without company name, with glob match. - xtensa*) - basic_machine=$basic_machine-unknown - ;; - # Recognize the various machine names and aliases which stand - # for a CPU type and a company and sometimes even an OS. - 386bsd) - basic_machine=i386-pc - os=-bsd - ;; - 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) - basic_machine=m68000-att - ;; - 3b*) - basic_machine=we32k-att - ;; - a29khif) - basic_machine=a29k-amd - os=-udi - ;; - abacus) - basic_machine=abacus-unknown - ;; - adobe68k) - basic_machine=m68010-adobe - os=-scout - ;; - alliant | fx80) - basic_machine=fx80-alliant - ;; - altos | altos3068) - basic_machine=m68k-altos - ;; - am29k) - basic_machine=a29k-none - os=-bsd - ;; - amd64) - basic_machine=x86_64-pc - ;; + cpu=$basic_machine + vendor=pc + ;; + # These rules are duplicated from below for sake of the special case above; + # i.e. things that normalized to x86 arches should also default to "pc" + pc98) + cpu=i386 + vendor=pc + ;; + x64 | amd64) + cpu=x86_64 + vendor=pc + ;; + # Recognize the basic CPU types without company name. + *) + cpu=$basic_machine + vendor=unknown + ;; +esac + +unset -v basic_machine + +# Decode basic machines in the full and proper CPU-Company form. +case $cpu-$vendor in + # Here we handle the default manufacturer of certain CPU types in canonical form. It is in + # some cases the only manufacturer, in others, it is the most popular. + craynv-unknown) + vendor=cray + os=${os:-unicosmp} + ;; + c90-unknown | c90-cray) + vendor=cray + os=${os:-unicos} + ;; + fx80-unknown) + vendor=alliant + ;; + romp-unknown) + vendor=ibm + ;; + mmix-unknown) + vendor=knuth + ;; + microblaze-unknown | microblazeel-unknown) + vendor=xilinx + ;; + rs6000-unknown) + vendor=ibm + ;; + vax-unknown) + vendor=dec + ;; + pdp11-unknown) + vendor=dec + ;; + we32k-unknown) + vendor=att + ;; + cydra-unknown) + vendor=cydrome + ;; + i370-ibm*) + vendor=ibm + ;; + orion-unknown) + vendor=highlevel + ;; + xps-unknown | xps100-unknown) + cpu=xps100 + vendor=honeywell + ;; + + # Here we normalize CPU types with a missing or matching vendor + dpx20-unknown | dpx20-bull) + cpu=rs6000 + vendor=bull + os=${os:-bosx} + ;; + + # Here we normalize CPU types irrespective of the vendor amd64-*) - basic_machine=x86_64-`echo "$basic_machine" | sed 's/^[^-]*-//'` - ;; - amdahl) - basic_machine=580-amdahl - os=-sysv - ;; - amiga | amiga-*) - basic_machine=m68k-unknown - ;; - amigaos | amigados) - basic_machine=m68k-unknown - os=-amigaos - ;; - amigaunix | amix) - basic_machine=m68k-unknown - os=-sysv4 - ;; - apollo68) - basic_machine=m68k-apollo - os=-sysv - ;; - apollo68bsd) - basic_machine=m68k-apollo - os=-bsd - ;; - aros) - basic_machine=i386-pc - os=-aros - ;; - asmjs) - basic_machine=asmjs-unknown - ;; - aux) - basic_machine=m68k-apple - os=-aux - ;; - balance) - basic_machine=ns32k-sequent - os=-dynix - ;; - blackfin) - basic_machine=bfin-unknown - os=-linux + cpu=x86_64 ;; blackfin-*) - basic_machine=bfin-`echo "$basic_machine" | sed 's/^[^-]*-//'` - os=-linux - ;; - bluegene*) - basic_machine=powerpc-ibm - os=-cnk + cpu=bfin + os=linux ;; c54x-*) - basic_machine=tic54x-`echo "$basic_machine" | sed 's/^[^-]*-//'` + cpu=tic54x ;; c55x-*) - basic_machine=tic55x-`echo "$basic_machine" | sed 's/^[^-]*-//'` + cpu=tic55x ;; c6x-*) - basic_machine=tic6x-`echo "$basic_machine" | sed 's/^[^-]*-//'` - ;; - c90) - basic_machine=c90-cray - os=-unicos - ;; - cegcc) - basic_machine=arm-unknown - os=-cegcc - ;; - convex-c1) - basic_machine=c1-convex - os=-bsd - ;; - convex-c2) - basic_machine=c2-convex - os=-bsd - ;; - convex-c32) - basic_machine=c32-convex - os=-bsd - ;; - convex-c34) - basic_machine=c34-convex - os=-bsd - ;; - convex-c38) - basic_machine=c38-convex - os=-bsd - ;; - cray | j90) - basic_machine=j90-cray - os=-unicos - ;; - craynv) - basic_machine=craynv-cray - os=-unicosmp - ;; - cr16 | cr16-*) - basic_machine=cr16-unknown - os=-elf - ;; - crds | unos) - basic_machine=m68k-crds - ;; - crisv32 | crisv32-* | etraxfs*) - basic_machine=crisv32-axis - ;; - cris | cris-* | etrax*) - basic_machine=cris-axis - ;; - crx) - basic_machine=crx-unknown - os=-elf - ;; - da30 | da30-*) - basic_machine=m68k-da30 - ;; - decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) - basic_machine=mips-dec - ;; - decsystem10* | dec10*) - basic_machine=pdp10-dec - os=-tops10 - ;; - decsystem20* | dec20*) - basic_machine=pdp10-dec - os=-tops20 - ;; - delta | 3300 | motorola-3300 | motorola-delta \ - | 3300-motorola | delta-motorola) - basic_machine=m68k-motorola - ;; - delta88) - basic_machine=m88k-motorola - os=-sysv3 - ;; - dicos) - basic_machine=i686-pc - os=-dicos - ;; - djgpp) - basic_machine=i586-pc - os=-msdosdjgpp - ;; - dpx20 | dpx20-*) - basic_machine=rs6000-bull - os=-bosx - ;; - dpx2*) - basic_machine=m68k-bull - os=-sysv3 - ;; - e500v[12]) - basic_machine=powerpc-unknown - os=$os"spe" - ;; - e500v[12]-*) - basic_machine=powerpc-`echo "$basic_machine" | sed 's/^[^-]*-//'` - os=$os"spe" - ;; - ebmon29k) - basic_machine=a29k-amd - os=-ebmon - ;; - elxsi) - basic_machine=elxsi-elxsi - os=-bsd - ;; - encore | umax | mmax) - basic_machine=ns32k-encore - ;; - es1800 | OSE68k | ose68k | ose | OSE) - basic_machine=m68k-ericsson - os=-ose - ;; - fx2800) - basic_machine=i860-alliant - ;; - genix) - basic_machine=ns32k-ns - ;; - gmicro) - basic_machine=tron-gmicro - os=-sysv - ;; - go32) - basic_machine=i386-pc - os=-go32 - ;; - h3050r* | hiux*) - basic_machine=hppa1.1-hitachi - os=-hiuxwe2 - ;; - h8300hms) - basic_machine=h8300-hitachi - os=-hms - ;; - h8300xray) - basic_machine=h8300-hitachi - os=-xray - ;; - h8500hms) - basic_machine=h8500-hitachi - os=-hms - ;; - harris) - basic_machine=m88k-harris - os=-sysv3 - ;; - hp300-*) - basic_machine=m68k-hp - ;; - hp300bsd) - basic_machine=m68k-hp - os=-bsd - ;; - hp300hpux) - basic_machine=m68k-hp - os=-hpux - ;; - hp3k9[0-9][0-9] | hp9[0-9][0-9]) - basic_machine=hppa1.0-hp - ;; - hp9k2[0-9][0-9] | hp9k31[0-9]) - basic_machine=m68000-hp - ;; - hp9k3[2-9][0-9]) - basic_machine=m68k-hp - ;; - hp9k6[0-9][0-9] | hp6[0-9][0-9]) - basic_machine=hppa1.0-hp - ;; - hp9k7[0-79][0-9] | hp7[0-79][0-9]) - basic_machine=hppa1.1-hp - ;; - hp9k78[0-9] | hp78[0-9]) - # FIXME: really hppa2.0-hp - basic_machine=hppa1.1-hp - ;; - hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) - # FIXME: really hppa2.0-hp - basic_machine=hppa1.1-hp - ;; - hp9k8[0-9][13679] | hp8[0-9][13679]) - basic_machine=hppa1.1-hp - ;; - hp9k8[0-9][0-9] | hp8[0-9][0-9]) - basic_machine=hppa1.0-hp - ;; - hppaosf) - basic_machine=hppa1.1-hp - os=-osf - ;; - hppro) - basic_machine=hppa1.1-hp - os=-proelf - ;; - i370-ibm* | ibm*) - basic_machine=i370-ibm - ;; - i*86v32) - basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'` - os=-sysv32 - ;; - i*86v4*) - basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'` - os=-sysv4 - ;; - i*86v) - basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'` - os=-sysv - ;; - i*86sol2) - basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'` - os=-solaris2 - ;; - i386mach) - basic_machine=i386-mach - os=-mach - ;; - vsta) - basic_machine=i386-unknown - os=-vsta - ;; - iris | iris4d) - basic_machine=mips-sgi - case $os in - -irix*) - ;; - *) - os=-irix4 - ;; - esac - ;; - isi68 | isi) - basic_machine=m68k-isi - os=-sysv - ;; - leon-*|leon[3-9]-*) - basic_machine=sparc-`echo "$basic_machine" | sed 's/-.*//'` - ;; - m68knommu) - basic_machine=m68k-unknown - os=-linux + cpu=tic6x + ;; + e500v[12]-*) + cpu=powerpc + os=$os"spe" + ;; + mips3*-*) + cpu=mips64 + ;; + ms1-*) + cpu=mt ;; m68knommu-*) - basic_machine=m68k-`echo "$basic_machine" | sed 's/^[^-]*-//'` - os=-linux - ;; - magnum | m3230) - basic_machine=mips-mips - os=-sysv - ;; - merlin) - basic_machine=ns32k-utek - os=-sysv - ;; - microblaze*) - basic_machine=microblaze-xilinx - ;; - mingw64) - basic_machine=x86_64-pc - os=-mingw64 - ;; - mingw32) - basic_machine=i686-pc - os=-mingw32 - ;; - mingw32ce) - basic_machine=arm-unknown - os=-mingw32ce - ;; - miniframe) - basic_machine=m68000-convergent - ;; - *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) - basic_machine=m68k-atari - os=-mint - ;; - mips3*-*) - basic_machine=`echo "$basic_machine" | sed -e 's/mips3/mips64/'` - ;; - mips3*) - basic_machine=`echo "$basic_machine" | sed -e 's/mips3/mips64/'`-unknown - ;; - monitor) - basic_machine=m68k-rom68k - os=-coff - ;; - morphos) - basic_machine=powerpc-unknown - os=-morphos - ;; - moxiebox) - basic_machine=moxie-unknown - os=-moxiebox - ;; - msdos) - basic_machine=i386-pc - os=-msdos - ;; - ms1-*) - basic_machine=`echo "$basic_machine" | sed -e 's/ms1-/mt-/'` - ;; - msys) - basic_machine=i686-pc - os=-msys - ;; - mvs) - basic_machine=i370-ibm - os=-mvs - ;; - nacl) - basic_machine=le32-unknown - os=-nacl - ;; - ncr3000) - basic_machine=i486-ncr - os=-sysv4 - ;; - netbsd386) - basic_machine=i386-unknown - os=-netbsd - ;; - netwinder) - basic_machine=armv4l-rebel - os=-linux - ;; - news | news700 | news800 | news900) - basic_machine=m68k-sony - os=-newsos - ;; - news1000) - basic_machine=m68030-sony - os=-newsos - ;; - news-3600 | risc-news) - basic_machine=mips-sony - os=-newsos - ;; - necv70) - basic_machine=v70-nec - os=-sysv - ;; - next | m*-next) - basic_machine=m68k-next - case $os in - -nextstep* ) - ;; - -ns2*) - os=-nextstep2 - ;; - *) - os=-nextstep3 - ;; - esac - ;; - nh3000) - basic_machine=m68k-harris - os=-cxux - ;; - nh[45]000) - basic_machine=m88k-harris - os=-cxux - ;; - nindy960) - basic_machine=i960-intel - os=-nindy - ;; - mon960) - basic_machine=i960-intel - os=-mon960 - ;; - nonstopux) - basic_machine=mips-compaq - os=-nonstopux - ;; - np1) - basic_machine=np1-gould + cpu=m68k + os=linux + ;; + m9s12z-* | m68hcs12z-* | hcs12z-* | s12z-*) + cpu=s12z + ;; + openrisc-*) + cpu=or32 + ;; + parisc-*) + cpu=hppa + os=linux + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + cpu=i586 + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-* | athalon_*-*) + cpu=i686 + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + cpu=i686 + ;; + pentium4-*) + cpu=i786 + ;; + pc98-*) + cpu=i386 + ;; + ppc-* | ppcbe-*) + cpu=powerpc + ;; + ppcle-* | powerpclittle-*) + cpu=powerpcle + ;; + ppc64-*) + cpu=powerpc64 + ;; + ppc64le-* | powerpc64little-*) + cpu=powerpc64le + ;; + sb1-*) + cpu=mipsisa64sb1 + ;; + sb1el-*) + cpu=mipsisa64sb1el + ;; + sh5e[lb]-*) + cpu=`echo "$cpu" | sed 's/^\(sh.\)e\(.\)$/\1\2e/'` + ;; + spur-*) + cpu=spur + ;; + strongarm-* | thumb-*) + cpu=arm + ;; + tx39-*) + cpu=mipstx39 + ;; + tx39el-*) + cpu=mipstx39el + ;; + x64-*) + cpu=x86_64 + ;; + xscale-* | xscalee[bl]-*) + cpu=`echo "$cpu" | sed 's/^xscale/arm/'` + ;; + + # Recognize the canonical CPU Types that limit and/or modify the + # company names they are paired with. + cr16-*) + os=${os:-elf} + ;; + crisv32-* | etraxfs*-*) + cpu=crisv32 + vendor=axis + ;; + cris-* | etrax*-*) + cpu=cris + vendor=axis + ;; + crx-*) + os=${os:-elf} ;; neo-tandem) - basic_machine=neo-tandem + cpu=neo + vendor=tandem ;; nse-tandem) - basic_machine=nse-tandem + cpu=nse + vendor=tandem ;; nsr-tandem) - basic_machine=nsr-tandem + cpu=nsr + vendor=tandem ;; nsv-tandem) - basic_machine=nsv-tandem + cpu=nsv + vendor=tandem ;; nsx-tandem) - basic_machine=nsx-tandem - ;; - op50n-* | op60c-*) - basic_machine=hppa1.1-oki - os=-proelf - ;; - openrisc | openrisc-*) - basic_machine=or32-unknown - ;; - os400) - basic_machine=powerpc-ibm - os=-os400 - ;; - OSE68000 | ose68000) - basic_machine=m68000-ericsson - os=-ose - ;; - os68k) - basic_machine=m68k-none - os=-os68k - ;; - pa-hitachi) - basic_machine=hppa1.1-hitachi - os=-hiuxwe2 - ;; - paragon) - basic_machine=i860-intel - os=-osf - ;; - parisc) - basic_machine=hppa-unknown - os=-linux - ;; - parisc-*) - basic_machine=hppa-`echo "$basic_machine" | sed 's/^[^-]*-//'` - os=-linux - ;; - pbd) - basic_machine=sparc-tti - ;; - pbb) - basic_machine=m68k-tti - ;; - pc532 | pc532-*) - basic_machine=ns32k-pc532 - ;; - pc98) - basic_machine=i386-pc - ;; - pc98-*) - basic_machine=i386-`echo "$basic_machine" | sed 's/^[^-]*-//'` - ;; - pentium | p5 | k5 | k6 | nexgen | viac3) - basic_machine=i586-pc - ;; - pentiumpro | p6 | 6x86 | athlon | athlon_*) - basic_machine=i686-pc - ;; - pentiumii | pentium2 | pentiumiii | pentium3) - basic_machine=i686-pc - ;; - pentium4) - basic_machine=i786-pc - ;; - pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) - basic_machine=i586-`echo "$basic_machine" | sed 's/^[^-]*-//'` - ;; - pentiumpro-* | p6-* | 6x86-* | athlon-*) - basic_machine=i686-`echo "$basic_machine" | sed 's/^[^-]*-//'` - ;; - pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) - basic_machine=i686-`echo "$basic_machine" | sed 's/^[^-]*-//'` - ;; - pentium4-*) - basic_machine=i786-`echo "$basic_machine" | sed 's/^[^-]*-//'` - ;; - pn) - basic_machine=pn-gould - ;; - power) basic_machine=power-ibm - ;; - ppc | ppcbe) basic_machine=powerpc-unknown - ;; - ppc-* | ppcbe-*) - basic_machine=powerpc-`echo "$basic_machine" | sed 's/^[^-]*-//'` - ;; - ppcle | powerpclittle) - basic_machine=powerpcle-unknown - ;; - ppcle-* | powerpclittle-*) - basic_machine=powerpcle-`echo "$basic_machine" | sed 's/^[^-]*-//'` - ;; - ppc64) basic_machine=powerpc64-unknown - ;; - ppc64-*) basic_machine=powerpc64-`echo "$basic_machine" | sed 's/^[^-]*-//'` - ;; - ppc64le | powerpc64little) - basic_machine=powerpc64le-unknown - ;; - ppc64le-* | powerpc64little-*) - basic_machine=powerpc64le-`echo "$basic_machine" | sed 's/^[^-]*-//'` - ;; - ps2) - basic_machine=i386-ibm - ;; - psp) - basic_machine=mipsallegrexel-psp - os=-elf - ;; - pw32) - basic_machine=i586-unknown - os=-pw32 - ;; - rdos | rdos64) - basic_machine=x86_64-pc - os=-rdos - ;; - rdos32) - basic_machine=i386-pc - os=-rdos - ;; - rom68k) - basic_machine=m68k-rom68k - os=-coff - ;; - rm[46]00) - basic_machine=mips-siemens - ;; - rtpc | rtpc-*) - basic_machine=romp-ibm - ;; - s390 | s390-*) - basic_machine=s390-ibm - ;; - s390x | s390x-*) - basic_machine=s390x-ibm - ;; - sa29200) - basic_machine=a29k-amd - os=-udi - ;; - sb1) - basic_machine=mipsisa64sb1-unknown - ;; - sb1el) - basic_machine=mipsisa64sb1el-unknown - ;; - sde) - basic_machine=mipsisa32-sde - os=-elf - ;; - sei) - basic_machine=mips-sei - os=-seiux - ;; - sequent) - basic_machine=i386-sequent - ;; - sh5el) - basic_machine=sh5le-unknown - ;; - simso-wrs) - basic_machine=sparclite-wrs - os=-vxworks - ;; - sps7) - basic_machine=m68k-bull - os=-sysv2 - ;; - spur) - basic_machine=spur-unknown - ;; - st2000) - basic_machine=m68k-tandem - ;; - stratus) - basic_machine=i860-stratus - os=-sysv4 - ;; - strongarm-* | thumb-*) - basic_machine=arm-`echo "$basic_machine" | sed 's/^[^-]*-//'` - ;; - sun2) - basic_machine=m68000-sun - ;; - sun2os3) - basic_machine=m68000-sun - os=-sunos3 - ;; - sun2os4) - basic_machine=m68000-sun - os=-sunos4 - ;; - sun3os3) - basic_machine=m68k-sun - os=-sunos3 - ;; - sun3os4) - basic_machine=m68k-sun - os=-sunos4 - ;; - sun4os3) - basic_machine=sparc-sun - os=-sunos3 - ;; - sun4os4) - basic_machine=sparc-sun - os=-sunos4 - ;; - sun4sol2) - basic_machine=sparc-sun - os=-solaris2 - ;; - sun3 | sun3-*) - basic_machine=m68k-sun - ;; - sun4) - basic_machine=sparc-sun - ;; - sun386 | sun386i | roadrunner) - basic_machine=i386-sun - ;; - sv1) - basic_machine=sv1-cray - os=-unicos - ;; - symmetry) - basic_machine=i386-sequent - os=-dynix - ;; - t3e) - basic_machine=alphaev5-cray - os=-unicos - ;; - t90) - basic_machine=t90-cray - os=-unicos - ;; - tile*) - basic_machine=$basic_machine-unknown - os=-linux-gnu - ;; - tx39) - basic_machine=mipstx39-unknown - ;; - tx39el) - basic_machine=mipstx39el-unknown - ;; - toad1) - basic_machine=pdp10-xkl - os=-tops20 - ;; - tower | tower-32) - basic_machine=m68k-ncr - ;; - tpf) - basic_machine=s390x-ibm - os=-tpf - ;; - udi29k) - basic_machine=a29k-amd - os=-udi - ;; - ultra3) - basic_machine=a29k-nyu - os=-sym1 - ;; - v810 | necv810) - basic_machine=v810-nec - os=-none - ;; - vaxv) - basic_machine=vax-dec - os=-sysv - ;; - vms) - basic_machine=vax-dec - os=-vms - ;; - vpp*|vx|vx-*) - basic_machine=f301-fujitsu - ;; - vxworks960) - basic_machine=i960-wrs - os=-vxworks - ;; - vxworks68) - basic_machine=m68k-wrs - os=-vxworks - ;; - vxworks29k) - basic_machine=a29k-wrs - os=-vxworks - ;; - w65*) - basic_machine=w65-wdc - os=-none - ;; - w89k-*) - basic_machine=hppa1.1-winbond - os=-proelf - ;; - x64) - basic_machine=x86_64-pc - ;; - xbox) - basic_machine=i686-pc - os=-mingw32 - ;; - xps | xps100) - basic_machine=xps100-honeywell - ;; - xscale-* | xscalee[bl]-*) - basic_machine=`echo "$basic_machine" | sed 's/^xscale/arm/'` - ;; - ymp) - basic_machine=ymp-cray - os=-unicos - ;; - none) - basic_machine=none-none - os=-none - ;; - -# Here we handle the default manufacturer of certain CPU types. It is in -# some cases the only manufacturer, in others, it is the most popular. - w89k) - basic_machine=hppa1.1-winbond - ;; - op50n) - basic_machine=hppa1.1-oki - ;; - op60c) - basic_machine=hppa1.1-oki - ;; - romp) - basic_machine=romp-ibm - ;; - mmix) - basic_machine=mmix-knuth - ;; - rs6000) - basic_machine=rs6000-ibm - ;; - vax) - basic_machine=vax-dec - ;; - pdp11) - basic_machine=pdp11-dec - ;; - we32k) - basic_machine=we32k-att - ;; - sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) - basic_machine=sh-unknown - ;; - cydra) - basic_machine=cydra-cydrome - ;; - orion) - basic_machine=orion-highlevel - ;; - orion105) - basic_machine=clipper-highlevel - ;; - mac | mpw | mac-mpw) - basic_machine=m68k-apple - ;; - pmac | pmac-mpw) - basic_machine=powerpc-apple - ;; - *-unknown) - # Make sure to match an already-canonicalized machine name. - ;; + cpu=nsx + vendor=tandem + ;; + s390-*) + cpu=s390 + vendor=ibm + ;; + s390x-*) + cpu=s390x + vendor=ibm + ;; + tile*-*) + os=${os:-linux-gnu} + ;; + *) - echo Invalid configuration \`"$1"\': machine \`"$basic_machine"\' not recognized 1>&2 - exit 1 + # Recognize the canonical CPU types that are allowed with any + # company name. + case $cpu in + 1750a | 580 \ + | a29k \ + | aarch64 | aarch64_be | arm64 \ + | abacus \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] \ + | alphapca5[67] | alpha64pca5[67] \ + | am33_2.0 \ + | amdgcn \ + | arc | arceb \ + | arm | arm[lb]e | arme[lb] | armv* \ + | avr | avr32 \ + | asmjs \ + | ba \ + | be32 | be64 \ + | bfin | bs2000 \ + | c[123]* | c30 | [cjt]90 | c4x \ + | c8051 | clipper | craynv | csky | cydra \ + | d10v | d30v | dlx | dsp16xx \ + | e2k | elxsi | epiphany \ + | f30[01] | f700 | fido | fr30 | frv | ft32 | fx80 \ + | h8300 | h8500 \ + | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | hexagon \ + | i370 | i*86 | i860 | i960 | ia16 | ia64 \ + | ip2k | iq2000 \ + | k1om \ + | le32 | le64 \ + | lm32 \ + | m32c | m32r | m32rle \ + | m5200 | m68000 | m680[012346]0 | m68360 | m683?2 | m68k \ + | m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x \ + | m88110 | m88k | maxq | mb | mcore | mep | metag \ + | microblaze | microblazeel \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64eb | mips64el \ + | mips64octeon | mips64octeonel \ + | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa32r6 | mipsisa32r6el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64r6 | mipsisa64r6el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipsr5900 | mipsr5900el \ + | mipstx39 | mipstx39el \ + | mmix \ + | mn10200 | mn10300 \ + | moxie \ + | mt \ + | msp430 \ + | nds32 | nds32le | nds32be \ + | nfp \ + | nios | nios2 | nios2eb | nios2el \ + | none | np1 | ns16k | ns32k | nvptx \ + | open8 \ + | or1k* \ + | or32 \ + | orion \ + | picochip \ + | pdp10 | pdp11 | pj | pjl | pn | power \ + | powerpc | powerpc64 | powerpc64le | powerpcle | powerpcspe \ + | pru \ + | pyramid \ + | riscv | riscv32 | riscv64 \ + | rl78 | romp | rs6000 | rx \ + | score \ + | sh | shl \ + | sh[1234] | sh[24]a | sh[24]ae[lb] | sh[23]e | she[lb] | sh[lb]e \ + | sh[1234]e[lb] | sh[12345][lb]e | sh[23]ele | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet \ + | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v | sv1 | sx* \ + | spu \ + | tahoe \ + | tic30 | tic4x | tic54x | tic55x | tic6x | tic80 \ + | tron \ + | ubicom32 \ + | v70 | v850 | v850e | v850e1 | v850es | v850e2 | v850e2v3 \ + | vax \ + | visium \ + | w65 | wasm32 \ + | we32k \ + | x86 | x86_64 | xc16x | xgate | xps100 \ + | xstormy16 | xtensa* \ + | ymp \ + | z8k | z80) + ;; + + *) + echo Invalid configuration \`"$1"\': machine \`"$cpu-$vendor"\' not recognized 1>&2 + exit 1 + ;; + esac ;; esac # Here we canonicalize certain aliases for manufacturers. -case $basic_machine in - *-digital*) - basic_machine=`echo "$basic_machine" | sed 's/digital.*/dec/'` +case $vendor in + digital*) + vendor=dec ;; - *-commodore*) - basic_machine=`echo "$basic_machine" | sed 's/commodore.*/cbm/'` + commodore*) + vendor=cbm ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. -if [ x"$os" != x"" ] +if [ x$os != x ] then case $os in # First match some system type aliases that might get confused # with valid system types. - # -solaris* is a basic system type, with this one exception. - -auroraux) - os=-auroraux + # solaris* is a basic system type, with this one exception. + auroraux) + os=auroraux ;; - -solaris1 | -solaris1.*) + bluegene*) + os=cnk + ;; + solaris1 | solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; - -solaris) - os=-solaris2 + solaris) + os=solaris2 ;; - -unixware*) - os=-sysv4.2uw + unixware*) + os=sysv4.2uw ;; - -gnu/linux*) + gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # es1800 is here to avoid being matched by es* (a different OS) - -es1800*) - os=-ose + es1800*) + os=ose + ;; + # Some version numbers need modification + chorusos*) + os=chorusos + ;; + isc) + os=isc2.2 + ;; + sco6) + os=sco5v6 + ;; + sco5) + os=sco3.2v5 + ;; + sco4) + os=sco3.2v4 + ;; + sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + ;; + sco3.2v[4-9]* | sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + ;; + scout) + # Don't match below + ;; + sco*) + os=sco3.2v2 + ;; + psos*) + os=psos ;; # Now accept the basic system types. # The portable systems comes first. # Each alternative MUST end in a * to match a version number. - # -sysv* is not here because it comes later, after sysvr4. - -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ - | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ - | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ - | -sym* | -kopensolaris* | -plan9* \ - | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ - | -aos* | -aros* | -cloudabi* | -sortix* \ - | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ - | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ - | -hiux* | -knetbsd* | -mirbsd* | -netbsd* \ - | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \ - | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ - | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ - | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ - | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* | -hcos* \ - | -chorusos* | -chorusrdb* | -cegcc* | -glidix* \ - | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ - | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ - | -linux-newlib* | -linux-musl* | -linux-uclibc* \ - | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ - | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* \ - | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ - | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ - | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ - | -morphos* | -superux* | -rtmk* | -windiss* \ - | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ - | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \ - | -onefs* | -tirtos* | -phoenix* | -fuchsia* | -redox* | -bme* \ - | -midnightbsd*) + # sysv* is not here because it comes later, after sysvr4. + gnu* | bsd* | mach* | minix* | genix* | ultrix* | irix* \ + | *vms* | esix* | aix* | cnk* | sunos | sunos[34]*\ + | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \ + | sym* | kopensolaris* | plan9* \ + | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \ + | aos* | aros* | cloudabi* | sortix* \ + | nindy* | vxsim* | vxworks* | ebmon* | hms* | mvs* \ + | clix* | riscos* | uniplus* | iris* | isc* | rtu* | xenix* \ + | knetbsd* | mirbsd* | netbsd* \ + | bitrig* | openbsd* | solidbsd* | libertybsd* \ + | ekkobsd* | kfreebsd* | freebsd* | riscix* | lynxos* \ + | bosx* | nextstep* | cxux* | aout* | elf* | oabi* \ + | ptx* | coff* | ecoff* | winnt* | domain* | vsta* \ + | udi* | eabi* | lites* | ieee* | go32* | aux* | hcos* \ + | chorusrdb* | cegcc* | glidix* \ + | cygwin* | msys* | pe* | moss* | proelf* | rtems* \ + | midipix* | mingw32* | mingw64* | linux-gnu* | linux-android* \ + | linux-newlib* | linux-musl* | linux-uclibc* \ + | uxpv* | beos* | mpeix* | udk* | moxiebox* \ + | interix* | uwin* | mks* | rhapsody* | darwin* \ + | openstep* | oskit* | conix* | pw32* | nonstopux* \ + | storm-chaos* | tops10* | tenex* | tops20* | its* \ + | os2* | vos* | palmos* | uclinux* | nucleus* \ + | morphos* | superux* | rtmk* | windiss* \ + | powermax* | dnix* | nx6 | nx7 | sei* | dragonfly* \ + | skyos* | haiku* | rdos* | toppers* | drops* | es* \ + | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \ + | midnightbsd* | amdhsa* | unleashed* | emscripten*) # Remember, each alternative MUST END IN *, to match a version number. ;; - -qnx*) - case $basic_machine in - x86-* | i*86-*) + qnx*) + case $cpu in + x86 | i*86) ;; *) - os=-nto$os + os=nto-$os ;; esac ;; - -nto-qnx*) + hiux*) + os=hiuxwe2 ;; - -nto*) + nto-qnx*) + ;; + nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; - -sim | -xray | -os68k* | -v88r* \ - | -windows* | -osx | -abug | -netware* | -os9* \ - | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) - ;; - -mac*) - os=`echo "$os" | sed -e 's|mac|macos|'` - ;; - -linux-dietlibc) - os=-linux-dietlibc - ;; - -linux*) + sim | xray | os68k* | v88r* \ + | windows* | osx | abug | netware* | os9* \ + | macos* | mpw* | magic* | mmixware* | mon960* | lnews*) + ;; + linux-dietlibc) + os=linux-dietlibc + ;; + linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; - -sunos5*) + lynx*178) + os=lynxos178 + ;; + lynx*5) + os=lynxos5 + ;; + lynx*) + os=lynxos + ;; + mac*) + os=`echo "$os" | sed -e 's|mac|macos|'` + ;; + opened*) + os=openedition + ;; + os400*) + os=os400 + ;; + sunos5*) os=`echo "$os" | sed -e 's|sunos5|solaris2|'` ;; - -sunos6*) + sunos6*) os=`echo "$os" | sed -e 's|sunos6|solaris3|'` ;; - -opened*) - os=-openedition - ;; - -os400*) - os=-os400 - ;; - -wince*) - os=-wince - ;; - -utek*) - os=-bsd - ;; - -dynix*) - os=-bsd - ;; - -acis*) - os=-aos - ;; - -atheos*) - os=-atheos - ;; - -syllable*) - os=-syllable - ;; - -386bsd) - os=-bsd - ;; - -ctix* | -uts*) - os=-sysv - ;; - -nova*) - os=-rtmk-nova - ;; - -ns2) - os=-nextstep2 - ;; - -nsk*) - os=-nsk + wince*) + os=wince + ;; + utek*) + os=bsd + ;; + dynix*) + os=bsd + ;; + acis*) + os=aos + ;; + atheos*) + os=atheos + ;; + syllable*) + os=syllable + ;; + 386bsd) + os=bsd + ;; + ctix* | uts*) + os=sysv + ;; + nova*) + os=rtmk-nova + ;; + ns2) + os=nextstep2 + ;; + nsk*) + os=nsk ;; # Preserve the version number of sinix5. - -sinix5.*) + sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; - -sinix*) - os=-sysv4 - ;; - -tpf*) - os=-tpf - ;; - -triton*) - os=-sysv3 - ;; - -oss*) - os=-sysv3 - ;; - -svr4*) - os=-sysv4 - ;; - -svr3) - os=-sysv3 - ;; - -sysvr4) - os=-sysv4 - ;; - # This must come after -sysvr4. - -sysv*) - ;; - -ose*) - os=-ose - ;; - -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) - os=-mint - ;; - -zvmoe) - os=-zvmoe - ;; - -dicos*) - os=-dicos - ;; - -pikeos*) + sinix*) + os=sysv4 + ;; + tpf*) + os=tpf + ;; + triton*) + os=sysv3 + ;; + oss*) + os=sysv3 + ;; + svr4*) + os=sysv4 + ;; + svr3) + os=sysv3 + ;; + sysvr4) + os=sysv4 + ;; + # This must come after sysvr4. + sysv*) + ;; + ose*) + os=ose + ;; + *mint | mint[0-9]* | *MiNT | MiNT[0-9]*) + os=mint + ;; + zvmoe) + os=zvmoe + ;; + dicos*) + os=dicos + ;; + pikeos*) # Until real need of OS specific support for # particular features comes up, bare metal # configurations are quite functional. - case $basic_machine in + case $cpu in arm*) - os=-eabi + os=eabi ;; *) - os=-elf + os=elf ;; esac ;; - -nacl*) + nacl*) + ;; + ios) ;; - -ios) + none) ;; - -none) + *-eabi) ;; *) - # Get rid of the `-' at the beginning of $os. - os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`"$1"\': system \`"$os"\' not recognized 1>&2 exit 1 ;; esac else @@ -1545,261 +1532,268 @@ # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. -case $basic_machine in +case $cpu-$vendor in score-*) - os=-elf + os=elf ;; spu-*) - os=-elf + os=elf ;; *-acorn) - os=-riscix1.2 + os=riscix1.2 ;; arm*-rebel) - os=-linux + os=linux ;; arm*-semi) - os=-aout + os=aout ;; c4x-* | tic4x-*) - os=-coff + os=coff ;; c8051-*) - os=-elf + os=elf + ;; + clipper-intergraph) + os=clix ;; hexagon-*) - os=-elf + os=elf ;; tic54x-*) - os=-coff + os=coff ;; tic55x-*) - os=-coff + os=coff ;; tic6x-*) - os=-coff + os=coff ;; # This must come before the *-dec entry. pdp10-*) - os=-tops20 + os=tops20 ;; pdp11-*) - os=-none + os=none ;; *-dec | vax-*) - os=-ultrix4.2 + os=ultrix4.2 ;; m68*-apollo) - os=-domain + os=domain ;; i386-sun) - os=-sunos4.0.2 + os=sunos4.0.2 ;; m68000-sun) - os=-sunos3 + os=sunos3 ;; m68*-cisco) - os=-aout + os=aout ;; mep-*) - os=-elf + os=elf ;; mips*-cisco) - os=-elf + os=elf ;; mips*-*) - os=-elf + os=elf ;; or32-*) - os=-coff + os=coff ;; *-tti) # must be before sparc entry or we get the wrong os. - os=-sysv3 + os=sysv3 ;; sparc-* | *-sun) - os=-sunos4.1.1 + os=sunos4.1.1 ;; pru-*) - os=-elf + os=elf ;; *-be) - os=-beos + os=beos ;; *-ibm) - os=-aix + os=aix ;; *-knuth) - os=-mmixware + os=mmixware ;; *-wec) - os=-proelf + os=proelf ;; *-winbond) - os=-proelf + os=proelf ;; *-oki) - os=-proelf + os=proelf ;; *-hp) - os=-hpux + os=hpux ;; *-hitachi) - os=-hiux + os=hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) - os=-sysv + os=sysv ;; *-cbm) - os=-amigaos + os=amigaos ;; *-dg) - os=-dgux + os=dgux ;; *-dolphin) - os=-sysv3 + os=sysv3 ;; m68k-ccur) - os=-rtu + os=rtu ;; m88k-omron*) - os=-luna + os=luna ;; *-next) - os=-nextstep + os=nextstep ;; *-sequent) - os=-ptx + os=ptx ;; *-crds) - os=-unos + os=unos ;; *-ns) - os=-genix + os=genix ;; i370-*) - os=-mvs + os=mvs ;; *-gould) - os=-sysv + os=sysv ;; *-highlevel) - os=-bsd + os=bsd ;; *-encore) - os=-bsd + os=bsd ;; *-sgi) - os=-irix + os=irix ;; *-siemens) - os=-sysv4 + os=sysv4 ;; *-masscomp) - os=-rtu + os=rtu ;; f30[01]-fujitsu | f700-fujitsu) - os=-uxpv + os=uxpv ;; *-rom68k) - os=-coff + os=coff ;; *-*bug) - os=-coff + os=coff ;; *-apple) - os=-macos + os=macos ;; *-atari*) - os=-mint + os=mint + ;; + *-wrs) + os=vxworks ;; *) - os=-none + os=none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. -vendor=unknown -case $basic_machine in - *-unknown) +case $vendor in + unknown) case $os in - -riscix*) + riscix*) vendor=acorn ;; - -sunos*) + sunos*) vendor=sun ;; - -cnk*|-aix*) + cnk*|-aix*) vendor=ibm ;; - -beos*) + beos*) vendor=be ;; - -hpux*) + hpux*) vendor=hp ;; - -mpeix*) + mpeix*) vendor=hp ;; - -hiux*) + hiux*) vendor=hitachi ;; - -unos*) + unos*) vendor=crds ;; - -dgux*) + dgux*) vendor=dg ;; - -luna*) + luna*) vendor=omron ;; - -genix*) - vendor=ns - ;; - -mvs* | -opened*) - vendor=ibm - ;; - -os400*) - vendor=ibm - ;; - -ptx*) - vendor=sequent - ;; - -tpf*) - vendor=ibm - ;; - -vxsim* | -vxworks* | -windiss*) - vendor=wrs - ;; - -aux*) - vendor=apple - ;; - -hms*) - vendor=hitachi - ;; - -mpw* | -macos*) - vendor=apple - ;; - -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) - vendor=atari - ;; - -vos*) + genix*) + vendor=ns + ;; + clix*) + vendor=intergraph + ;; + mvs* | opened*) + vendor=ibm + ;; + os400*) + vendor=ibm + ;; + ptx*) + vendor=sequent + ;; + tpf*) + vendor=ibm + ;; + vxsim* | vxworks* | windiss*) + vendor=wrs + ;; + aux*) + vendor=apple + ;; + hms*) + vendor=hitachi + ;; + mpw* | macos*) + vendor=apple + ;; + *mint | mint[0-9]* | *MiNT | MiNT[0-9]*) + vendor=atari + ;; + vos*) vendor=stratus ;; esac - basic_machine=`echo "$basic_machine" | sed "s/unknown/$vendor/"` ;; esac -echo "$basic_machine$os" +echo "$cpu-$vendor-$os" exit # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: Index: build-aux/install-sh ================================================================== --- build-aux/install-sh +++ build-aux/install-sh @@ -1,501 +1,301 @@ #!/bin/sh -# install - install a program, script, or datafile - -scriptversion=2013-12-25.23; # UTC - -# This originates from X11R5 (mit/util/scripts/install.sh), which was -# later released in X11R6 (xc/config/util/install.sh) with the -# following copyright and license. -# -# Copyright (C) 1994 X Consortium -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to -# deal in the Software without restriction, including without limitation the -# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -# sell copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- -# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# Except as contained in this notice, the name of the X Consortium shall not -# be used in advertising or otherwise to promote the sale, use or other deal- -# ings in this Software without prior written authorization from the X Consor- -# tium. -# -# -# FSF changes to this file are in the public domain. +# +# $NetBSD: install-sh.in,v 1.6 2012/01/11 13:07:31 hans Exp $ +# This script now also installs multiple files, but might choke on installing +# multiple files with spaces in the file names. +# +# install - install a program, script, or datafile +# This comes from X11R5 (mit/util/scripts/install.sh). +# +# Copyright 1991 by the Massachusetts Institute of Technology +# +# Permission to use, copy, modify, distribute, and sell this software and its +# documentation for any purpose is hereby granted without fee, provided that +# the above copyright notice appear in all copies and that both that +# copyright notice and this permission notice appear in supporting +# documentation, and that the name of M.I.T. not be used in advertising or +# publicity pertaining to distribution of the software without specific, +# written prior permission. M.I.T. makes no representations about the +# suitability of this software for any purpose. It is provided "as is" +# without express or implied warranty. # # Calling this script install-sh is preferred over install.sh, to prevent -# 'make' implicit rules from creating a file called install from it +# `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. -tab=' ' -nl=' -' -IFS=" $tab$nl" - -# Set DOITPROG to "echo" to test this script. - -doit=${DOITPROG-} -doit_exec=${doit:-exec} - -# Put in absolute file names if you don't have them in your path; -# or use environment vars. - -chgrpprog=${CHGRPPROG-chgrp} -chmodprog=${CHMODPROG-chmod} -chownprog=${CHOWNPROG-chown} -cmpprog=${CMPPROG-cmp} -cpprog=${CPPROG-cp} -mkdirprog=${MKDIRPROG-mkdir} -mvprog=${MVPROG-mv} -rmprog=${RMPROG-rm} -stripprog=${STRIPPROG-strip} - -posix_mkdir= - -# Desired mode of installed file. -mode=0755 - -chgrpcmd= -chmodcmd=$chmodprog -chowncmd= -mvcmd=$mvprog -rmcmd="$rmprog -f" -stripcmd= - -src= -dst= -dir_arg= -dst_arg= - -copy_on_change=false -is_target_a_directory=possibly - -usage="\ -Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE - or: $0 [OPTION]... SRCFILES... DIRECTORY - or: $0 [OPTION]... -t DIRECTORY SRCFILES... - or: $0 [OPTION]... -d DIRECTORIES... - -In the 1st form, copy SRCFILE to DSTFILE. -In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. -In the 4th, create DIRECTORIES. - -Options: - --help display this help and exit. - --version display version info and exit. - - -c (ignored) - -C install only if different (preserve the last data modification time) - -d create directories instead of installing files. - -g GROUP $chgrpprog installed files to GROUP. - -m MODE $chmodprog installed files to MODE. - -o USER $chownprog installed files to USER. - -s $stripprog installed files. - -t DIRECTORY install into DIRECTORY. - -T report an error if DSTFILE is a directory. - -Environment variables override the default commands: - CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG - RMPROG STRIPPROG -" - -while test $# -ne 0; do - case $1 in - -c) ;; - - -C) copy_on_change=true;; - - -d) dir_arg=true;; - - -g) chgrpcmd="$chgrpprog $2" - shift;; - - --help) echo "$usage"; exit $?;; - - -m) mode=$2 - case $mode in - *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) - echo "$0: invalid mode: $mode" >&2 - exit 1;; - esac - shift;; - - -o) chowncmd="$chownprog $2" - shift;; - - -s) stripcmd=$stripprog;; - - -t) - is_target_a_directory=always - dst_arg=$2 - # Protect names problematic for 'test' and other utilities. - case $dst_arg in - -* | [=\(\)!]) dst_arg=./$dst_arg;; - esac - shift;; - - -T) is_target_a_directory=never;; - - --version) echo "$0 $scriptversion"; exit $?;; - - --) shift - break;; - - -*) echo "$0: invalid option: $1" >&2 - exit 1;; - - *) break;; - esac - shift -done - -# We allow the use of options -d and -T together, by making -d -# take the precedence; this is for compatibility with GNU install. - -if test -n "$dir_arg"; then - if test -n "$dst_arg"; then - echo "$0: target directory not allowed when installing a directory." >&2 - exit 1 - fi -fi - -if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then - # When -d is used, all remaining arguments are directories to create. - # When -t is used, the destination is already specified. - # Otherwise, the last argument is the destination. Remove it from $@. - for arg - do - if test -n "$dst_arg"; then - # $@ is not empty: it contains at least $arg. - set fnord "$@" "$dst_arg" - shift # fnord - fi - shift # arg - dst_arg=$arg - # Protect names problematic for 'test' and other utilities. - case $dst_arg in - -* | [=\(\)!]) dst_arg=./$dst_arg;; - esac - done -fi - -if test $# -eq 0; then - if test -z "$dir_arg"; then - echo "$0: no input file specified." >&2 - exit 1 - fi - # It's OK to call 'install-sh -d' without argument. - # This can happen when creating conditional directories. - exit 0 -fi - -if test -z "$dir_arg"; then - if test $# -gt 1 || test "$is_target_a_directory" = always; then - if test ! -d "$dst_arg"; then - echo "$0: $dst_arg: Is not a directory." >&2 - exit 1 - fi - fi -fi - -if test -z "$dir_arg"; then - do_exit='(exit $ret); exit $ret' - trap "ret=129; $do_exit" 1 - trap "ret=130; $do_exit" 2 - trap "ret=141; $do_exit" 13 - trap "ret=143; $do_exit" 15 - - # Set umask so as not to create temps with too-generous modes. - # However, 'strip' requires both read and write access to temps. - case $mode in - # Optimize common cases. - *644) cp_umask=133;; - *755) cp_umask=22;; - - *[0-7]) - if test -z "$stripcmd"; then - u_plus_rw= - else - u_plus_rw='% 200' - fi - cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; - *) - if test -z "$stripcmd"; then - u_plus_rw= - else - u_plus_rw=,u+rw - fi - cp_umask=$mode$u_plus_rw;; - esac -fi - -for src -do - # Protect names problematic for 'test' and other utilities. - case $src in - -* | [=\(\)!]) src=./$src;; - esac - - if test -n "$dir_arg"; then - dst=$src - dstdir=$dst - test -d "$dstdir" - dstdir_status=$? - else - - # Waiting for this to be detected by the "$cpprog $src $dsttmp" command - # might cause directories to be created, which would be especially bad - # if $src (and thus $dsttmp) contains '*'. - if test ! -f "$src" && test ! -d "$src"; then - echo "$0: $src does not exist." >&2 - exit 1 - fi - - if test -z "$dst_arg"; then - echo "$0: no destination specified." >&2 - exit 1 - fi - dst=$dst_arg - - # If destination is a directory, append the input filename; won't work - # if double slashes aren't ignored. - if test -d "$dst"; then - if test "$is_target_a_directory" = never; then - echo "$0: $dst_arg: Is a directory" >&2 - exit 1 - fi - dstdir=$dst - dst=$dstdir/`basename "$src"` - dstdir_status=0 - else - dstdir=`dirname "$dst"` - test -d "$dstdir" - dstdir_status=$? - fi - fi - - obsolete_mkdir_used=false - - if test $dstdir_status != 0; then - case $posix_mkdir in - '') - # Create intermediate dirs using mode 755 as modified by the umask. - # This is like FreeBSD 'install' as of 1997-10-28. - umask=`umask` - case $stripcmd.$umask in - # Optimize common cases. - *[2367][2367]) mkdir_umask=$umask;; - .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; - - *[0-7]) - mkdir_umask=`expr $umask + 22 \ - - $umask % 100 % 40 + $umask % 20 \ - - $umask % 10 % 4 + $umask % 2 - `;; - *) mkdir_umask=$umask,go-w;; - esac - - # With -d, create the new directory with the user-specified mode. - # Otherwise, rely on $mkdir_umask. - if test -n "$dir_arg"; then - mkdir_mode=-m$mode - else - mkdir_mode= - fi - - posix_mkdir=false - case $umask in - *[123567][0-7][0-7]) - # POSIX mkdir -p sets u+wx bits regardless of umask, which - # is incompatible with FreeBSD 'install' when (umask & 300) != 0. - ;; - *) - tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ - trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 - - if (umask $mkdir_umask && - exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 - then - if test -z "$dir_arg" || { - # Check for POSIX incompatibilities with -m. - # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or - # other-writable bit of parent directory when it shouldn't. - # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. - ls_ld_tmpdir=`ls -ld "$tmpdir"` - case $ls_ld_tmpdir in - d????-?r-*) different_mode=700;; - d????-?--*) different_mode=755;; - *) false;; - esac && - $mkdirprog -m$different_mode -p -- "$tmpdir" && { - ls_ld_tmpdir_1=`ls -ld "$tmpdir"` - test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" - } - } - then posix_mkdir=: - fi - rmdir "$tmpdir/d" "$tmpdir" - else - # Remove any dirs left behind by ancient mkdir implementations. - rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null - fi - trap '' 0;; - esac;; - esac - - if - $posix_mkdir && ( - umask $mkdir_umask && - $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" - ) - then : - else - - # The umask is ridiculous, or mkdir does not conform to POSIX, - # or it failed possibly due to a race condition. Create the - # directory the slow way, step by step, checking for races as we go. - - case $dstdir in - /*) prefix='/';; - [-=\(\)!]*) prefix='./';; - *) prefix='';; - esac - - oIFS=$IFS - IFS=/ - set -f - set fnord $dstdir - shift - set +f - IFS=$oIFS - - prefixes= - - for d - do - test X"$d" = X && continue - - prefix=$prefix$d - if test -d "$prefix"; then - prefixes= - else - if $posix_mkdir; then - (umask=$mkdir_umask && - $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break - # Don't fail if two instances are running concurrently. - test -d "$prefix" || exit 1 - else - case $prefix in - *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; - *) qprefix=$prefix;; - esac - prefixes="$prefixes '$qprefix'" - fi - fi - prefix=$prefix/ - done - - if test -n "$prefixes"; then - # Don't fail if two instances are running concurrently. - (umask $mkdir_umask && - eval "\$doit_exec \$mkdirprog $prefixes") || - test -d "$dstdir" || exit 1 - obsolete_mkdir_used=true - fi - fi - fi - - if test -n "$dir_arg"; then - { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && - { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && - { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || - test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 - else - - # Make a couple of temp file names in the proper directory. - dsttmp=$dstdir/_inst.$$_ - rmtmp=$dstdir/_rm.$$_ - - # Trap to clean up those temp files at exit. - trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 - - # Copy the file name to the temp name. - (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && - - # and set any options; do chmod last to preserve setuid bits. - # - # If any of these fail, we abort the whole thing. If we want to - # ignore errors from any of these, just make sure not to ignore - # errors from the above "$doit $cpprog $src $dsttmp" command. - # - { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && - { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && - { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && - { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && - - # If -C, don't bother to copy if it wouldn't change the file. - if $copy_on_change && - old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && - new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && - set -f && - set X $old && old=:$2:$4:$5:$6 && - set X $new && new=:$2:$4:$5:$6 && - set +f && - test "$old" = "$new" && - $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 - then - rm -f "$dsttmp" - else - # Rename the file to the real destination. - $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || - - # The rename failed, perhaps because mv can't rename something else - # to itself, or perhaps because mv is so ancient that it does not - # support -f. - { - # Now remove or move aside any old file at destination location. - # We try this two ways since rm can't unlink itself on some - # systems and the destination file might be busy for other - # reasons. In this case, the final cleanup might fail but the new - # file should still install successfully. - { - test ! -f "$dst" || - $doit $rmcmd -f "$dst" 2>/dev/null || - { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && - { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } - } || - { echo "$0: cannot unlink or rename $dst" >&2 - (exit 1); exit 1 - } - } && - - # Now rename the file to the real destination. - $doit $mvcmd "$dsttmp" "$dst" - } - fi || exit 1 - - trap '' 0 - fi -done - -# Local variables: -# eval: (add-hook 'write-file-hooks 'time-stamp) -# time-stamp-start: "scriptversion=" -# time-stamp-format: "%:y-%02m-%02d.%02H" -# time-stamp-time-zone: "UTC" -# time-stamp-end: "; # UTC" -# End: +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +awkprog="${AWKPROG-awk}" +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +instcmd="$cpprog" +instflags="" +pathcompchmodcmd="$chmodprog 755" +chmodcmd="$chmodprog 755" +chowncmd="" +chgrpcmd="" +stripcmd="" +stripflags="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +msrc="" +dst="" +dir_arg="" +suffix="" +suffixfmt="" + +while [ x"$1" != x ]; do + case $1 in + -b) suffix=".old" + shift + continue;; + + -B) suffixfmt="$2" + shift + shift + continue;; + + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -m*) + chmodcmd="$chmodprog ${1#-m}" + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + -S) stripcmd="$stripprog" + stripflags="-S $2 $stripflags" + shift + shift + continue;; + + -p) instflags="-p" + shift + continue;; + + *) if [ x"$msrc" = x ] + then + msrc="$dst" + else + msrc="$msrc $dst" + fi + src="$dst" + dst="$1" + shift + continue;; + esac +done + +if [ x"$dir_arg" = x ] +then + dstisfile="" + if [ ! -d "$dst" ] + then + if [ x"$msrc" = x"$src" ] + then + dstisfile=true + else + echo "install: destination is not a directory" + exit 1 + fi + fi +else + msrc="$msrc $dst" +fi + +if [ x"$msrc" = x ] +then + echo "install: no destination specified" + exit 1 +fi + +for srcarg in $msrc; do + +if [ x"$dir_arg" != x ]; then + + dstarg="$srcarg" +else + dstarg="$dst" + +# Waiting for this to be detected by the "$instcmd $srcarg $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f "$srcarg" ] + then + doinst="$instcmd $instflags" + elif [ -d "$srcarg" ] + then + echo "install: $srcarg: not a regular file" + exit 1 + elif [ "$srcarg" = "/dev/null" ] + then + doinst="$cpprog" + else + echo "install: $srcarg does not exist" + exit 1 + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d "$dstarg" ] + then + dstarg="$dstarg"/`basename "$srcarg"` + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo "$dstarg" | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' +' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $doit $mkdirprog "${pathcomp}" + if [ x"$chowncmd" != x ]; then $doit $chowncmd "${pathcomp}"; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "${pathcomp}"; else true ; fi && + if [ x"$pathcompchmodcmd" != x ]; then $doit $pathcompchmodcmd "${pathcomp}"; else true ; fi + + else + true + fi + + pathcomp="${pathcomp}/" +done +fi + + if [ x"$dir_arg" != x ] + then + if [ -d "$dstarg" ]; then + true + else + $doit $mkdirprog "$dstarg" && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dstarg"; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dstarg"; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dstarg"; else true ; fi + fi + else + + if [ x"$dstisfile" = x ] + then + file=$srcarg + else + file=$dst + fi + + dstfile=`basename "$file"` + dstfinal="$dstdir/$dstfile" + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Make a backup file name in the proper directory. + case x$suffixfmt in + *%*) suffix=`echo x | + $awkprog -v bname="$dstfinal" -v fmt="$suffixfmt" ' + { cnt = 0; + do { + sfx = sprintf(fmt, cnt++); + name = bname sfx; + } while (system("test -f " name) == 0); + print sfx; }' -`;; + x) ;; + *) suffix="$suffixfmt";; + esac + dstbackup="$dstfinal$suffix" + +# Move or copy the file name to the temp name + + $doit $doinst $srcarg "$dsttmp" && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dsttmp"; else true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dsttmp"; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $stripflags "$dsttmp"; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dsttmp"; else true;fi && + +# Now rename the file to the real destination. + + if [ x"$suffix" != x ] && [ -f "$dstfinal" ] + then + $doit $mvcmd "$dstfinal" "$dstbackup" + else + $doit $rmcmd -f "$dstfinal" + fi && + $doit $mvcmd "$dsttmp" "$dstfinal" + fi + +done && + + +exit 0 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 +dnl 2018, 2020, 2021 dnl Jonathan Schleifer dnl dnl https://fossil.nil.im/buildsys dnl dnl Permission to use, copy, modify, and/or distribute this software for any @@ -24,18 +24,28 @@ AC_DEFUN([BUILDSYS_INIT], [ AC_REQUIRE([AC_CANONICAL_BUILD]) AC_REQUIRE([AC_CANONICAL_HOST]) - case "$build_os" in - darwin*) - case "$host_os" in - darwin*) - AC_SUBST(BUILD_AND_HOST_ARE_DARWIN, yes) - ;; - esac - ;; + AC_ARG_ENABLE(rpath, + AS_HELP_STRING([--disable-rpath], [do not use rpath])) + + case "$build_os" in + darwin*) + case "$host_os" in + darwin*) + AC_SUBST(BUILD_AND_HOST_ARE_DARWIN, yes) + ;; + esac + ;; + esac + + AC_PROG_INSTALL + case "$INSTALL" in + ./build-aux/install-sh*) + INSTALL="$PWD/$INSTALL" + ;; esac AC_CONFIG_COMMANDS_PRE([ AS_IF([test x"$GCC" = x"yes"], [AC_SUBST(DEP_CFLAGS, '-MD -MF $${out%.o}.dep')]) @@ -47,11 +57,21 @@ [AC_SUBST(DEP_OBJCXXFLAGS, '-MD -MF $${out%.o}.dep')]) AC_SUBST(AMIGA_LIB_CFLAGS) AC_SUBST(AMIGA_LIB_LDFLAGS) - AC_PATH_PROG(TPUT, tput) + case "$build_os" in + morphos*) + dnl Don't use tput on MorphOS: The colored output is + dnl quite unreadable and in some MorphOS versions the + dnl output from tput is not 8-bit safe, with awk (for + dnl AC_SUBST) failing as a result. + ;; + *) + AC_PATH_PROG(TPUT, tput) + ;; + esac AS_IF([test x"$TPUT" != x""], [ if x=$($TPUT el 2>/dev/null); then AC_SUBST(TERM_EL, "$x") else @@ -110,45 +130,44 @@ ]) ]) AC_DEFUN([BUILDSYS_CHECK_IOS], [ case "$host_os" in - darwin*) - AC_MSG_CHECKING(whether host is iOS) - AC_EGREP_CPP(yes, [ - #include - - #if (defined(TARGET_OS_IPHONE) && \ - TARGET_OS_IPHONE) || \ - (defined(TARGET_OS_SIMULATOR) && \ - TARGET_OS_SIMULATOR) - yes - #endif - ], [ - host_is_ios="yes" - ], [ - host_is_ios="no" - ]) - AC_MSG_RESULT($host_is_ios) - ;; + darwin*) + AC_MSG_CHECKING(whether host is iOS) + AC_EGREP_CPP(yes, [ + #include + + #if (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) || \ + (defined(TARGET_OS_SIMULATOR) && \ + TARGET_OS_SIMULATOR) + yes + #endif + ], [ + host_is_ios="yes" + ], [ + host_is_ios="no" + ]) + AC_MSG_RESULT($host_is_ios) + ;; esac ]) AC_DEFUN([BUILDSYS_PROG_IMPLIB], [ AC_REQUIRE([AC_CANONICAL_HOST]) AC_MSG_CHECKING(whether we need an implib) case "$host_os" in - cygwin* | mingw*) - AC_MSG_RESULT(yes) - PROG_IMPLIB_NEEDED='yes' - PROG_IMPLIB_LDFLAGS='-Wl,--export-all-symbols,--out-implib,lib${PROG}.a' - ;; - *) - AC_MSG_RESULT(no) - PROG_IMPLIB_NEEDED='no' - PROG_IMPLIB_LDFLAGS='' - ;; + cygwin* | mingw*) + AC_MSG_RESULT(yes) + PROG_IMPLIB_NEEDED='yes' + PROG_IMPLIB_LDFLAGS='-Wl,--export-all-symbols,--out-implib,lib${PROG}.a' + ;; + *) + AC_MSG_RESULT(no) + PROG_IMPLIB_NEEDED='no' + PROG_IMPLIB_LDFLAGS='' + ;; esac AC_SUBST(PROG_IMPLIB_NEEDED) AC_SUBST(PROG_IMPLIB_LDFLAGS) ]) @@ -156,130 +175,180 @@ AC_DEFUN([BUILDSYS_SHARED_LIB], [ AC_REQUIRE([AC_CANONICAL_HOST]) AC_REQUIRE([BUILDSYS_CHECK_IOS]) AC_MSG_CHECKING(for shared library system) - case "$host_os" in - darwin*) - AC_MSG_RESULT(Darwin) - LIB_CFLAGS='-fPIC -DPIC' - LIB_LDFLAGS='-dynamiclib -current_version ${LIB_MAJOR}.${LIB_MINOR} -compatibility_version ${LIB_MAJOR}' - LIB_LDFLAGS_INSTALL_NAME='-Wl,-install_name,${libdir}/$${out%.dylib}.${LIB_MAJOR}.dylib' - LIB_PREFIX='lib' - LIB_SUFFIX='.dylib' - 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='' - LIB_LDFLAGS='-shared -Wl,--export-all-symbols,--out-implib,lib${SHARED_LIB}.a' - LIB_LDFLAGS_INSTALL_NAME='' - LIB_PREFIX='' - LIB_SUFFIX='.dll' - LDFLAGS_RPATH='-Wl,-rpath,${libdir}' - PLUGIN_CFLAGS='' - PLUGIN_LDFLAGS='-shared' - 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.a ${DESTDIR}${libdir}/lib$$i.a' - UNINSTALL_LIB='&& rm -f ${DESTDIR}${bindir}/$$i ${DESTDIR}${libdir}/lib$$i.a' - INSTALL_PLUGIN='&& ${INSTALL} -m 755 $$i ${DESTDIR}${plugindir}/$$i' - UNINSTALL_PLUGIN='&& rm -f ${DESTDIR}${plugindir}/$$i' - CLEAN_LIB='${SHARED_LIB}.a' - ;; - openbsd* | mirbsd*) - AC_MSG_RESULT(OpenBSD) - LIB_CFLAGS='-fPIC -DPIC' - LIB_LDFLAGS='-shared' - LIB_LDFLAGS_INSTALL_NAME='' - LIB_PREFIX='lib' - LIB_SUFFIX='.so.${LIB_MAJOR}.${LIB_MINOR}' - 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' - LIB_LDFLAGS='-shared -Wl,-soname=${SHARED_LIB}.${LIB_MAJOR}.${LIB_MINOR}' - LIB_LDFLAGS_INSTALL_NAME='' - LIB_PREFIX='lib' - LIB_SUFFIX='.so' - 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=${SHARED_LIB}.${LIB_MAJOR}' - LIB_LDFLAGS_INSTALL_NAME='' - LIB_PREFIX='lib' - LIB_SUFFIX='.so' - LDFLAGS_RPATH='' - 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='' - ;; - *) - AC_MSG_RESULT(ELF) - LIB_CFLAGS='-fPIC -DPIC' - LIB_LDFLAGS='-shared -Wl,-soname=${SHARED_LIB}.${LIB_MAJOR}' - LIB_LDFLAGS_INSTALL_NAME='' - LIB_PREFIX='lib' - LIB_SUFFIX='.so' - 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='' - ;; + case "$host" in + *-*-darwin*) + AC_MSG_RESULT(Darwin) + LIB_CFLAGS='-fPIC -DPIC' + LIB_LDFLAGS='-dynamiclib -current_version ${LIB_MAJOR}.${LIB_MINOR} -compatibility_version ${LIB_MAJOR}' + LIB_LDFLAGS_INSTALL_NAME='-Wl,-install_name,${libdir}/$${out%.dylib}.${LIB_MAJOR}.dylib' + 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='' + LIB_LDFLAGS='-shared -Wl,--export-all-symbols' + LIB_LDFLAGS_INSTALL_NAME='' + LIB_PREFIX='' + LIB_SUFFIX='${LIB_MAJOR}.dll' + LINK_LIB='&& ${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' + LIB_LDFLAGS='-shared' + LIB_LDFLAGS_INSTALL_NAME='' + 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' + LIB_LDFLAGS='-shared -Wl,-soname=$$out.${LIB_MAJOR}.${LIB_MINOR}' + LIB_LDFLAGS_INSTALL_NAME='' + 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' + LIB_LDFLAGS='-shared -Wl,+h,$$out' + LIB_LDFLAGS_INSTALL_NAME='' + LIB_PREFIX='lib' + 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' + LIB_LDFLAGS='-shared -Wl,+h,$$out' + LIB_LDFLAGS_INSTALL_NAME='' + LIB_PREFIX='lib' + 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' + LIB_LDFLAGS='-shared -Wl,-soname=$$out.${LIB_MAJOR}' + LIB_LDFLAGS_INSTALL_NAME='' + 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) AC_SUBST(LIB_LDFLAGS) 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) @@ -296,21 +365,22 @@ 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}' - ], [ - 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}' - ]) - - AC_SUBST(FRAMEWORK_LDFLAGS) - AC_SUBST(FRAMEWORK_LDFLAGS_INSTALL_NAME) - - $1 - ;; + 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}' + ], [ + 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}' + ]) + + AC_SUBST(FRAMEWORK_LDFLAGS) + AC_SUBST(FRAMEWORK_LDFLAGS_INSTALL_NAME) + AC_SUBST(FRAMEWORK_LIBS) + + $1 + ;; esac ]) ADDED build-aux/m4/pkg.m4 Index: build-aux/m4/pkg.m4 ================================================================== --- /dev/null +++ build-aux/m4/pkg.m4 @@ -0,0 +1,343 @@ +# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- +# serial 11 (pkg-config-0.29.1) + +dnl Copyright © 2004 Scott James Remnant . +dnl Copyright © 2012-2015 Dan Nicholson +dnl +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2 of the License, or +dnl (at your option) any later version. +dnl +dnl This program is distributed in the hope that it will be useful, but +dnl WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +dnl General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +dnl 02111-1307, USA. +dnl +dnl As a special exception to the GNU General Public License, if you +dnl distribute this file as part of a program that contains a +dnl configuration script generated by Autoconf, you may include it under +dnl the same distribution terms that you use for the rest of that +dnl program. + +dnl PKG_PREREQ(MIN-VERSION) +dnl ----------------------- +dnl Since: 0.29 +dnl +dnl Verify that the version of the pkg-config macros are at least +dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's +dnl installed version of pkg-config, this checks the developer's version +dnl of pkg.m4 when generating configure. +dnl +dnl To ensure that this macro is defined, also add: +dnl m4_ifndef([PKG_PREREQ], +dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])]) +dnl +dnl See the "Since" comment for each macro you use to see what version +dnl of the macros you require. +m4_defun([PKG_PREREQ], +[m4_define([PKG_MACROS_VERSION], [0.29.1]) +m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1, + [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])]) +])dnl PKG_PREREQ + +dnl PKG_PROG_PKG_CONFIG([MIN-VERSION]) +dnl ---------------------------------- +dnl Since: 0.16 +dnl +dnl Search for the pkg-config tool and set the PKG_CONFIG variable to +dnl first found in the path. Checks that the version of pkg-config found +dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is +dnl used since that's the first version where most current features of +dnl pkg-config existed. +AC_DEFUN([PKG_PROG_PKG_CONFIG], +[m4_pattern_forbid([^_?PKG_[A-Z_]+$]) +m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) +m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) +AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) +AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) +AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) + +if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then + AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) +fi +if test -n "$PKG_CONFIG"; then + _pkg_min_version=m4_default([$1], [0.9.0]) + AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) + if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + PKG_CONFIG="" + fi +fi[]dnl +])dnl PKG_PROG_PKG_CONFIG + +dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +dnl ------------------------------------------------------------------- +dnl Since: 0.18 +dnl +dnl Check to see whether a particular set of modules exists. Similar to +dnl PKG_CHECK_MODULES(), but does not set variables or print errors. +dnl +dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) +dnl only at the first occurence in configure.ac, so if the first place +dnl it's called might be skipped (such as if it is within an "if", you +dnl have to call PKG_CHECK_EXISTS manually +AC_DEFUN([PKG_CHECK_EXISTS], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +if test -n "$PKG_CONFIG" && \ + AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then + m4_default([$2], [:]) +m4_ifvaln([$3], [else + $3])dnl +fi]) + +dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) +dnl --------------------------------------------- +dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting +dnl pkg_failed based on the result. +m4_define([_PKG_CONFIG], +[if test -n "$$1"; then + pkg_cv_[]$1="$$1" + elif test -n "$PKG_CONFIG"; then + PKG_CHECK_EXISTS([$3], + [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes ], + [pkg_failed=yes]) + else + pkg_failed=untried +fi[]dnl +])dnl _PKG_CONFIG + +dnl _PKG_SHORT_ERRORS_SUPPORTED +dnl --------------------------- +dnl Internal check to see if pkg-config supports short errors. +AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG]) +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi[]dnl +])dnl _PKG_SHORT_ERRORS_SUPPORTED + + +dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], +dnl [ACTION-IF-NOT-FOUND]) +dnl -------------------------------------------------------------- +dnl Since: 0.4.0 +dnl +dnl Note that if there is a possibility the first call to +dnl PKG_CHECK_MODULES might not happen, you should be sure to include an +dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac +AC_DEFUN([PKG_CHECK_MODULES], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl +AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl + +pkg_failed=no +AC_MSG_CHECKING([for $1]) + +_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) +_PKG_CONFIG([$1][_LIBS], [libs], [$2]) + +m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS +and $1[]_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details.]) + +if test $pkg_failed = yes; then + AC_MSG_RESULT([no]) + _PKG_SHORT_ERRORS_SUPPORTED + if test $_pkg_short_errors_supported = yes; then + $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` + else + $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD + + m4_default([$4], [AC_MSG_ERROR( +[Package requirements ($2) were not met: + +$$1_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +_PKG_TEXT])[]dnl + ]) +elif test $pkg_failed = untried; then + AC_MSG_RESULT([no]) + m4_default([$4], [AC_MSG_FAILURE( +[The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +_PKG_TEXT + +To get pkg-config, see .])[]dnl + ]) +else + $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS + $1[]_LIBS=$pkg_cv_[]$1[]_LIBS + AC_MSG_RESULT([yes]) + $3 +fi[]dnl +])dnl PKG_CHECK_MODULES + + +dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], +dnl [ACTION-IF-NOT-FOUND]) +dnl --------------------------------------------------------------------- +dnl Since: 0.29 +dnl +dnl Checks for existence of MODULES and gathers its build flags with +dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags +dnl and VARIABLE-PREFIX_LIBS from --libs. +dnl +dnl Note that if there is a possibility the first call to +dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to +dnl include an explicit call to PKG_PROG_PKG_CONFIG in your +dnl configure.ac. +AC_DEFUN([PKG_CHECK_MODULES_STATIC], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +_save_PKG_CONFIG=$PKG_CONFIG +PKG_CONFIG="$PKG_CONFIG --static" +PKG_CHECK_MODULES($@) +PKG_CONFIG=$_save_PKG_CONFIG[]dnl +])dnl PKG_CHECK_MODULES_STATIC + + +dnl PKG_INSTALLDIR([DIRECTORY]) +dnl ------------------------- +dnl Since: 0.27 +dnl +dnl Substitutes the variable pkgconfigdir as the location where a module +dnl should install pkg-config .pc files. By default the directory is +dnl $libdir/pkgconfig, but the default can be changed by passing +dnl DIRECTORY. The user can override through the --with-pkgconfigdir +dnl parameter. +AC_DEFUN([PKG_INSTALLDIR], +[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) +m4_pushdef([pkg_description], + [pkg-config installation directory @<:@]pkg_default[@:>@]) +AC_ARG_WITH([pkgconfigdir], + [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, + [with_pkgconfigdir=]pkg_default) +AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) +m4_popdef([pkg_default]) +m4_popdef([pkg_description]) +])dnl PKG_INSTALLDIR + + +dnl PKG_NOARCH_INSTALLDIR([DIRECTORY]) +dnl -------------------------------- +dnl Since: 0.27 +dnl +dnl Substitutes the variable noarch_pkgconfigdir as the location where a +dnl module should install arch-independent pkg-config .pc files. By +dnl default the directory is $datadir/pkgconfig, but the default can be +dnl changed by passing DIRECTORY. The user can override through the +dnl --with-noarch-pkgconfigdir parameter. +AC_DEFUN([PKG_NOARCH_INSTALLDIR], +[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) +m4_pushdef([pkg_description], + [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) +AC_ARG_WITH([noarch-pkgconfigdir], + [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, + [with_noarch_pkgconfigdir=]pkg_default) +AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) +m4_popdef([pkg_default]) +m4_popdef([pkg_description]) +])dnl PKG_NOARCH_INSTALLDIR + + +dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, +dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +dnl ------------------------------------------- +dnl Since: 0.28 +dnl +dnl Retrieves the value of the pkg-config variable for the given module. +AC_DEFUN([PKG_CHECK_VAR], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl + +_PKG_CONFIG([$1], [variable="][$3]["], [$2]) +AS_VAR_COPY([$1], [pkg_cv_][$1]) + +AS_VAR_IF([$1], [""], [$5], [$4])dnl +])dnl PKG_CHECK_VAR + +dnl PKG_WITH_MODULES(VARIABLE-PREFIX, MODULES, +dnl [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND], +dnl [DESCRIPTION], [DEFAULT]) +dnl ------------------------------------------ +dnl +dnl Prepare a "--with-" configure option using the lowercase +dnl [VARIABLE-PREFIX] name, merging the behaviour of AC_ARG_WITH and +dnl PKG_CHECK_MODULES in a single macro. +AC_DEFUN([PKG_WITH_MODULES], +[ +m4_pushdef([with_arg], m4_tolower([$1])) + +m4_pushdef([description], + [m4_default([$5], [build with ]with_arg[ support])]) + +m4_pushdef([def_arg], [m4_default([$6], [auto])]) +m4_pushdef([def_action_if_found], [AS_TR_SH([with_]with_arg)=yes]) +m4_pushdef([def_action_if_not_found], [AS_TR_SH([with_]with_arg)=no]) + +m4_case(def_arg, + [yes],[m4_pushdef([with_without], [--without-]with_arg)], + [m4_pushdef([with_without],[--with-]with_arg)]) + +AC_ARG_WITH(with_arg, + AS_HELP_STRING(with_without, description[ @<:@default=]def_arg[@:>@]),, + [AS_TR_SH([with_]with_arg)=def_arg]) + +AS_CASE([$AS_TR_SH([with_]with_arg)], + [yes],[PKG_CHECK_MODULES([$1],[$2],$3,$4)], + [auto],[PKG_CHECK_MODULES([$1],[$2], + [m4_n([def_action_if_found]) $3], + [m4_n([def_action_if_not_found]) $4])]) + +m4_popdef([with_arg]) +m4_popdef([description]) +m4_popdef([def_arg]) + +])dnl PKG_WITH_MODULES + +dnl PKG_HAVE_WITH_MODULES(VARIABLE-PREFIX, MODULES, +dnl [DESCRIPTION], [DEFAULT]) +dnl ----------------------------------------------- +dnl +dnl Convenience macro to trigger AM_CONDITIONAL after PKG_WITH_MODULES +dnl check._[VARIABLE-PREFIX] is exported as make variable. +AC_DEFUN([PKG_HAVE_WITH_MODULES], +[ +PKG_WITH_MODULES([$1],[$2],,,[$3],[$4]) + +AM_CONDITIONAL([HAVE_][$1], + [test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"]) +])dnl PKG_HAVE_WITH_MODULES + +dnl PKG_HAVE_DEFINE_WITH_MODULES(VARIABLE-PREFIX, MODULES, +dnl [DESCRIPTION], [DEFAULT]) +dnl ------------------------------------------------------ +dnl +dnl Convenience macro to run AM_CONDITIONAL and AC_DEFINE after +dnl PKG_WITH_MODULES check. HAVE_[VARIABLE-PREFIX] is exported as make +dnl and preprocessor variable. +AC_DEFUN([PKG_HAVE_DEFINE_WITH_MODULES], +[ +PKG_HAVE_WITH_MODULES([$1],[$2],[$3],[$4]) + +AS_IF([test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"], + [AC_DEFINE([HAVE_][$1], 1, [Enable ]m4_tolower([$1])[ support])]) +])dnl PKG_HAVE_DEFINE_WITH_MODULES 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 +# 2017, 2018, 2020, 2021 # Jonathan Schleifer # # https://fossil.nil.im/buildsys # # Permission to use, copy, modify, and/or distribute this software for any @@ -54,17 +54,19 @@ LIB_CFLAGS = @LIB_CFLAGS@ LIB_LDFLAGS = @LIB_LDFLAGS@ LIB_LDFLAGS_INSTALL_NAME = @LIB_LDFLAGS_INSTALL_NAME@ LIB_PREFIX = @LIB_PREFIX@ LIB_SUFFIX = @LIB_SUFFIX@ +LINK_LIB = @LINK_LIB@ AMIGA_LIB_CFLAGS = @AMIGA_LIB_CFLAGS@ AMIGA_LIB_LDFLAGS = @AMIGA_LIB_LDFLAGS@ PLUGIN_CFLAGS = @PLUGIN_CFLAGS@ PLUGIN_LDFLAGS = @PLUGIN_LDFLAGS@ PLUGIN_SUFFIX = @PLUGIN_SUFFIX@ FRAMEWORK_LDFLAGS = @FRAMEWORK_LDFLAGS@ FRAMEWORK_LDFLAGS_INSTALL_NAME = @FRAMEWORK_LDFLAGS_INSTALL_NAME@ +FRAMEWORK_LIBS = @FRAMEWORK_LIBS@ CODESIGN = @CODESIGN@ CODESIGN_IDENTITY ?= - CLEAN_LIB = @CLEAN_LIB@ DEP_ASFLAGS = @DEP_ASFLAGS@ DEP_CFLAGS = @DEP_CFLAGS@ @@ -146,11 +148,12 @@ ${DIR_LEAVE}; \ done depend: pre-depend : >.deps - for i in ${DEPS}; do \ + for i in "" ${DEPS}; do \ + test x"$$i" = x"" && continue; \ echo "-include \$${.CURDIR}/$$i" >>.deps; \ done pre-depend: @@ -180,11 +183,11 @@ fi ${SHARED_LIB} ${SHARED_LIB_NOINST}: ${EXT_DEPS} ${LIB_OBJS} ${LIB_OBJS_EXTRA} ${LINK_STATUS} out="$@"; \ - if ${LD} -o $@ ${LIB_OBJS} ${LIB_OBJS_EXTRA} ${LIB_LDFLAGS} ${LIB_LDFLAGS_INSTALL_NAME} ${LDFLAGS} ${LIBS}; then \ + if ${LD} -o $@ ${LIB_OBJS} ${LIB_OBJS_EXTRA} ${LIB_LDFLAGS} ${LIB_LDFLAGS_INSTALL_NAME} ${LDFLAGS} ${LIBS} ${LINK_LIB}; then \ ${LINK_OK}; \ else \ ${LINK_FAILED}; \ fi @@ -207,11 +210,11 @@ done if test x"${includesubdir}" = x"${COPY_HEADERS_IF_SUBDIR}"; then \ for i in "" ${INCLUDES}; do \ test x"$$i" = x"" && continue; \ - ${MKDIR_P} ${COPY_HEADERS_DESTINATION} || exit $$?; \ + ${MKDIR_P} $$(dirname ${COPY_HEADERS_DESTINATION}/$$i) || exit $$?; \ ${INSTALL} -m 644 $$i ${COPY_HEADERS_DESTINATION}/$$i || exit $$?; \ done \ fi ${AMIGA_LIB} ${AMIGA_LIB_NOINST}: ${EXT_DEPS} ${AMIGA_LIB_OBJS_START} ${AMIGA_LIB_OBJS} ${AMIGA_LIB_OBJS_EXTRA} @@ -246,16 +249,16 @@ out="$@"; \ objs=""; \ ars=""; \ for i in ${OBJS} ${OBJS_EXTRA}; do \ case $$i in \ - *.a) \ - ars="$$ars $$i" \ - ;; \ - *.o) \ - objs="$$objs $$i" \ - ;; \ + *.a) \ + ars="$$ars $$i" \ + ;; \ + *.o) \ + objs="$$objs $$i" \ + ;; \ esac \ done; \ for i in $$ars; do \ dir=".$$(echo $$i | sed 's/\//_/g').objs"; \ rm -fr $$dir; \ @@ -293,16 +296,16 @@ out="$@"; \ objs=""; \ ars=""; \ for i in ${LIB_OBJS} ${LIB_OBJS_EXTRA}; do \ case $$i in \ - *.a) \ - ars="$$ars $$i" \ - ;; \ - *.o) \ - objs="$$objs $$i" \ - ;; \ + *.a) \ + ars="$$ars $$i" \ + ;; \ + *.o) \ + objs="$$objs $$i" \ + ;; \ esac \ done; \ for i in $$ars; do \ dir=".$$(echo $$i | sed 's/\//_/g').objs"; \ rm -fr $$dir; \ @@ -332,16 +335,16 @@ out="$@"; \ objs=""; \ ars=""; \ for i in ${AMIGA_LIB_OBJS} ${AMIGA_LIB_OBJS_EXTRA}; do \ case $$i in \ - *.a) \ - ars="$$ars $$i" \ - ;; \ - *.o) \ - objs="$$objs $$i" \ - ;; \ + *.a) \ + ars="$$ars $$i" \ + ;; \ + *.o) \ + objs="$$objs $$i" \ + ;; \ esac \ done; \ for i in $$ars; do \ dir=".$$(echo $$i | sed 's/\//_/g').objs"; \ rm -fr $$dir; \ @@ -728,11 +731,11 @@ if test x"${INSTALL_INCLUDES}" = x"yes"; then \ for i in "" ${INCLUDES}; do \ test x"$$i" = x"" && continue; \ ${INSTALL_STATUS}; \ - if ${MKDIR_P} ${DESTDIR}${includedir}/${includesubdir} && ${INSTALL} -m 644 $$i ${DESTDIR}${includedir}/${includesubdir}/$$i; then \ + if ${MKDIR_P} $$(dirname ${DESTDIR}${includedir}/${includesubdir}/$$i) && ${INSTALL} -m 644 $$i ${DESTDIR}${includedir}/${includesubdir}/$$i; then \ ${INSTALL_OK}; \ else \ ${INSTALL_FAILED}; \ fi \ done \ @@ -883,11 +886,11 @@ ${DIR_LEAVE}; \ done : >.deps - for i in "" ${DEPS} ${OBJS} ${OBJS_EXTRA} ${LIB_OBJS} ${LIB_OBJS_EXTRA} ${AMIGA_LIB_OBJS} ${AMIGA_LIB_OBJS_EXTRA} ${PLUGIN_OBJS} ${PROG} ${PROG_NOINST} ${SHARED_LIB} ${SHARED_LIB_NOINST} ${AMIGA_LIB} ${AMIGA_LIB_NOINST} ${STATIC_LIB} ${STATIC_LIB_NOINST} ${STATIC_PIC_LIB} ${STATIC_PIC_LIB_NOINST} ${STATIC_AMIGA_LIB} ${STATIC_AMIGA_LIB_NOINST} ${FRAMEWORK} ${PLUGIN} ${PLUGIN_NOINST} ${CLEAN_LIB} ${MO_FILES} ${CLEAN}; do \ + for i in "" ${DEPS} ${OBJS} ${OBJS_EXTRA} ${LIB_OBJS} ${LIB_OBJS_EXTRA} ${AMIGA_LIB_OBJS} ${AMIGA_LIB_OBJS_START} ${AMIGA_LIB_OBJS_EXTRA} ${PLUGIN_OBJS} ${PROG} ${PROG_NOINST} ${SHARED_LIB} ${SHARED_LIB_NOINST} ${AMIGA_LIB} ${AMIGA_LIB_NOINST} ${STATIC_LIB} ${STATIC_LIB_NOINST} ${STATIC_PIC_LIB} ${STATIC_PIC_LIB_NOINST} ${STATIC_AMIGA_LIB} ${STATIC_AMIGA_LIB_NOINST} ${FRAMEWORK} ${PLUGIN} ${PLUGIN_NOINST} ${CLEAN_LIB} ${MO_FILES} ${CLEAN}; do \ test x"$$i" = x"" && continue; \ if test -f $$i -o -d $$i; then \ if rm -fr $$i; then \ ${DELETE_OK}; \ else \ Index: configure.ac ================================================================== --- configure.ac +++ configure.ac @@ -1,6 +1,6 @@ -AC_INIT(ObjFW, 1.1-dev, js@nil.im) +AC_INIT(ObjFW, 1.1dev, js@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]) @@ -17,131 +17,135 @@ BUILDSYS_INIT AC_CANONICAL_HOST -AC_ARG_WITH(ixemul, - AS_HELP_STRING([--with-ixemul], [build with ixemul])) - dnl Used to disable checking for -pedantic on some platforms where it's broken check_pedantic="yes" case "$host" in - arm-*-riscos*) - AS_IF([test x"$OBJCFLAGS" = x""], [ - OBJCFLAGS="-O2 -g" - ]) - flags="-mfloat-abi=softfp -mfpu=vfp -mlibscl" - ASFLAGS="$ASFLAGS -mfloat-abi=softfp -mfpu=vfp" - OBJCFLAGS="$OBJCFLAGS $flags" - OBJFW_OBJCFLAGS="$OBJFW_OBJCFLAGS $flags" - LDFLAGS="$LDFLAGS $flags" - - enable_shared="no" - enable_threads="no" - enable_sockets="no" - enable_files="no" - ;; - m68k-*-amigaos*) - AS_IF([test x"$OBJCFLAGS" = x""], [ - OBJCFLAGS="-O0" - ]) - OBJCFLAGS="$OBJCFLAGS -noixemul" - OBJFW_OBJCFLAGS="$OBJFW_OBJCFLAGS -noixemul" - CPPFLAGS="$CPPFLAGS -D__NO_NET_API" - LDFLAGS="$LDFLAGS -noixemul" - - 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, objfwrt68k.library) - AC_SUBST(SFDC_TARGET, m68k-amigaos) - AC_SUBST(SFD_FILE, amigaos3.sfd) - AC_SUBST(SFDC_INLINE_H, inline.h) - dnl For 68000, GCC emits calls to helper functions that - dnl do not work properly in a library. - t="-mcpu=68020 -fbaserel -noixemul" - AC_SUBST(AMIGA_LIB_CFLAGS, "$t -ffreestanding") - AC_SUBST(AMIGA_LIB_LDFLAGS, - "$t -resident -nostartfiles") - ]) - - AC_SUBST(LIBBASES_M, libbases.m) - ;; - powerpc-*-amigaos*) - CPPFLAGS="$CPPFLAGS -D__USE_INLINE__" - - enable_files="yes" # Required for reading ENV: - enable_shared="no" - - AC_SUBST(LIBBASES_M, libbases.m) - ;; - *-morphos*) - AS_IF([test x"$with_ixemul" != x"yes"], [ - AS_IF([test x"$OBJCFLAGS" = x""], [ - OBJCFLAGS="-O2 -g" - ]) - OBJCFLAGS="$OBJCFLAGS -noixemul" - OBJFW_OBJCFLAGS="$OBJFW_OBJCFLAGS -noixemul" - LDFLAGS="$LDFLAGS -noixemul" - enable_files="yes" # Required for reading ENV: - supports_amiga_lib="yes" - check_pedantic="no" # Breaks generated inlines - - AS_IF([test x"$enable_amiga_lib" != x"no"], [ - AC_SUBST(OBJFWRT_AMIGA_LIB, objfwrt.library) - AC_SUBST(CVINCLUDE_INLINE_H, inline.h) - t="-mresident32 -ffreestanding -noixemul" - AC_SUBST(AMIGA_LIB_CFLAGS, $t) - t="-mresident32 -nostartfiles -nodefaultlibs" - t="$t -noixemul -lc" - AC_SUBST(AMIGA_LIB_LDFLAGS, $t) - ]) - - AC_SUBST(LIBBASES_M, libbases.m) - ]) - - enable_shared="no" - enable_threads="no" - ;; - *-msdosdjgpp*) - enable_shared="no" - enable_threads="no" - enable_sockets="no" - ;; - *-*-mingw*) - LDFLAGS="$LDFLAGS -Wl,--allow-multiple-definition" - LIBS="$LIBS -lversion" - - AC_SUBST(USE_SRCS_WINDOWS, '${SRCS_WINDOWS}') - ;; - *-psp-*) - AS_IF([test x"$DEVKITPSP" = x""], [ - AC_MSG_ERROR( - [DEVKITPSP is not set! Please set DEVKITPSP.]) - ]) - - AS_IF([test x"$OBJCFLAGS" = x""], [ - OBJCFLAGS="-O2" - ]) - OBJCFLAGS="$OBJCFLAGS -G0" - OBJFW_OBJCFLAGS="$OBJFW_OBJCFLAGS -G0" - CPPFLAGS="$CPPFLAGS -I$DEVKITPSP/psp/sdk/include" - LDFLAGS="$LDFLAGS -G0" - LIBS="$LIBS -L$DEVKITPSP/psp/sdk/lib -lpspdebug -lpspdisplay" - LIBS="$LIBS -lpspge -lpspctrl -lpspsdk -lc -lpspnet" - LIBS="$LIBS -lpspnet_inet -lpspnet_apctl -lpspnet_resolver" - LIBS="$LIBS -lpsputility -lpspuser -lpspkernel -lgcc -lpsplibc" - enable_shared="no" - enable_threads="no" # TODO - enable_sockets="no" # TODO - check_pedantic="no" - - AC_SUBST(MAP_LDFLAGS, ['-Wl,-Map,$@.map']) - ;; +arm-*-riscos*) + AS_IF([test x"$OBJCFLAGS" = x""], [OBJCFLAGS="-O2 -g"]) + flags="-mfloat-abi=softfp -mfpu=vfp -mlibscl" + ASFLAGS="$ASFLAGS -mfloat-abi=softfp -mfpu=vfp" + OBJCFLAGS="$OBJCFLAGS $flags" + OBJFW_OBJCFLAGS="$OBJFW_OBJCFLAGS $flags" + LDFLAGS="$LDFLAGS $flags" + + enable_shared="no" + enable_threads="no" + enable_sockets="no" + enable_files="no" + ;; +m68k-*-amigaos*) + AS_IF([test x"$OBJCFLAGS" = x""], [OBJCFLAGS="-O0"]) + OBJCFLAGS="$OBJCFLAGS -noixemul" + OBJFW_OBJCFLAGS="$OBJFW_OBJCFLAGS -noixemul" + CPPFLAGS="$CPPFLAGS -D__NO_NET_API" + LDFLAGS="$LDFLAGS -noixemul" + 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__" + + enable_files="yes" # Required for reading ENV: + enable_shared="no" + with_tls="no" + + AC_SUBST(LIBBASES_M, libbases.m) + ;; +*-morphos*) + AS_IF([test x"$OBJCFLAGS" = x""], [OBJCFLAGS="-O2 -g"]) + OBJCFLAGS="$OBJCFLAGS -noixemul" + OBJFW_OBJCFLAGS="$OBJFW_OBJCFLAGS -noixemul" + 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" + LIBS="$LIBS -lversion" + + AC_SUBST(USE_SRCS_WINDOWS, '${SRCS_WINDOWS}') + ;; +*-psp-*) + AS_IF([test x"$DEVKITPSP" = x""], [ + AC_MSG_ERROR([DEVKITPSP is not set! Please set DEVKITPSP.]) + ]) + + AS_IF([test x"$OBJCFLAGS" = x""], [OBJCFLAGS="-O2"]) + OBJCFLAGS="$OBJCFLAGS -G0" + OBJFW_OBJCFLAGS="$OBJFW_OBJCFLAGS -G0" + CPPFLAGS="$CPPFLAGS -I$DEVKITPSP/psp/sdk/include" + LDFLAGS="$LDFLAGS -G0" + LIBS="$LIBS -L$DEVKITPSP/psp/sdk/lib -lpspdebug -lpspdisplay" + LIBS="$LIBS -lpspge -lpspctrl -lpspsdk -lc -lpspnet" + LIBS="$LIBS -lpspnet_inet -lpspnet_apctl -lpspnet_resolver" + LIBS="$LIBS -lpsputility -lpspuser -lpspkernel -lgcc -lpsplibc" + enable_shared="no" + enable_threads="no" # TODO + enable_sockets="no" # TODO + check_pedantic="no" + + AC_SUBST(MAP_LDFLAGS, ['-Wl,-Map,$@.map']) + ;; +hppa*-*-hpux*) + dnl Don't default to -g: It creates errors from the assembler and breaks + dnl exceptions. + AS_IF([test x"$OBJCFLAGS" = x""], [OBJCFLAGS="-O2"]) + dnl HP-UX 11.11's inttypes.h defines UINTPTR_MAX etc. to nothing. GCC's + dnl stdint.h defines those correctly, but if inttypes.h gets included + dnl after something included stdint.h, it gets broken again. Therefore, + dnl always include inttypes.h as the very first thing. + dnl We need to put this into OBJCFLAGS and not CPPFLAGS as CPPFLAGS are + dnl also used for .S files. + OBJCFLAGS="$OBJCFLAGS -include inttypes.h" + dnl We need -latomic for GCC's atomics to work. + LIBS="$LIBS -latomic" + ;; +*-*-mint*) + enable_shared="no" + enable_threads="no" # TODO + with_tls="no" + ;; 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} @@ -148,14 +152,23 @@ : ${GREP:=grep.exe} : ${RANLIB:=ranlib.exe} ]) AC_LANG([Objective C]) -AC_PROG_OBJC([clang egcc gcc]) +case "$host_os" in +morphos*) + dnl Don't use clang on MorphOS - it does not support baserel, which is + dnl required for the .library. + potential_compilers="gcc" + ;; +*) + potential_compilers="clang egcc gcc" + ;; +esac +AC_PROG_OBJC($potential_compilers) AC_PROG_OBJCPP AC_PROG_LN_S -AC_PROG_INSTALL AC_PROG_EGREP BUILDSYS_CHECK_IOS AC_ARG_WITH(wii, @@ -173,10 +186,11 @@ LDFLAGS="$LDFLAGS -mrvl -mcpu=750 -meabi -mhard-float" LIBS="$LIBS -L$DEVKITPRO/libogc/lib/wii -lfat -logc" TESTS_LIBS="$TESTS_LIBS -lwiiuse -lbte" enable_shared="no" enable_threads="no" # TODO + with_tls="no" AC_DEFINE(OF_WII, 1, [Whether we are compiling for Wii]) AC_SUBST(MAP_LDFLAGS, ['-Wl,-Map,$@.map']) ]) @@ -244,10 +258,11 @@ LDFLAGS="$LDFLAGS -specs=3dsx.specs -march=armv6k -mtune=mpcore" LDFLAGS="$LDFLAGS -mfloat-abi=hard -mtp=soft -mword-relocations" LIBS="$LIBS -L$DEVKITPRO/libctru/lib -lctru" enable_shared="no" enable_threads="no" # TODO + with_tls="no" check_pedantic="no" AC_DEFINE(OF_NINTENDO_3DS, 1, [Whether we are compiling for Nintendo 3DS]) AC_SUBST(MAP_LDFLAGS, ['-Wl,-Map,$@.map']) @@ -262,44 +277,34 @@ dnl amiga-gcc requires -fexceptions in LDFLAGS in order to link in the glue code dnl for registering the frames. LDFLAGS="$LDFLAGS -fexceptions" case "$OBJC" in - *clang*) - case "$host" in - dnl Clang generates MIPS assembly not accepted by GNU - dnl as, however, Clang's integrated assembler doesn't - dnl accept everything used in ObjFW's assembly files. - dnl Therefore, use the integrated assembler for ObjC - dnl files, but not for assembly files. - mips*-*-*) - flag="-integrated-as" - OBJCFLAGS="$OBJCFLAGS $flag" - OBJFW_OBJCFLAGS="$OBJFW_OBJCFLAGS $flag" - ;; - dnl Don't use -no-integrated-as on Darwin. It breaks - dnl building for the iOS simulator. - i?86-*-darwin* | x86_64-*-darwin*) - ;; - dnl Many older Clang versions don't support jmp short. - i?86-*-* | x86_64-*-*) - ASFLAGS="$ASFLAGS -no-integrated-as" - ;; - dnl Clang's assembler on Windows is not complete yet - dnl and cannot compile all .S files. - *-*-mingw*) - ASFLAGS="$ASFLAGS -no-integrated-as" - ;; - dnl Clang generates assembly output on SPARC64 that - dnl OpenBSD's assembler does not accept. - sparc64-*-*openbsd*) - flag="-integrated-as" - OBJCFLAGS="$OBJCFLAGS $flag" - OBJFW_OBJCFLAGS="$OBJFW_OBJCFLAGS $flag" - ;; - esac - ;; +*clang*) + case "$host" in + mips*-*-*) + dnl Clang generates MIPS assembly not accepted by GNU as, + dnl however, Clang's integrated assembler doesn't accept + dnl everything used in ObjFW's assembly files. Therefore, use + dnl the integrated assembler for ObjC files, but not for + dnl assembly files. + OBJCFLAGS="$OBJCFLAGS -integrated-as" + OBJFW_OBJCFLAGS="$OBJFW_OBJCFLAGS -integrated-as" + ;; + i?86-*-darwin* | x86_64-*-darwin*) + dnl Don't use -no-integrated-as on Darwin. It breaks building + dnl for the iOS simulator. + ;; + sparc64-*-*openbsd*) + dnl Clang generates assembly output on SPARC64 that OpenBSD's + dnl assembler does not accept. + flag="-integrated-as" + OBJCFLAGS="$OBJCFLAGS $flag" + OBJFW_OBJCFLAGS="$OBJFW_OBJCFLAGS $flag" + ;; + esac + ;; esac AX_CHECK_COMPILER_FLAGS(-std=gnu11, [ OBJCFLAGS="$OBJCFLAGS -std=gnu11" ], [ @@ -309,18 +314,11 @@ AX_CHECK_COMPILER_FLAGS(-std=gnu99, [OBJCFLAGS="$OBJCFLAGS -std=gnu99"]) ]) ]) -case "$build_os" in - morphos*) - # MorphOS 3.10 has a buggy ixemul that does not work with -pipe. - ;; - *) - AX_CHECK_COMPILER_FLAGS(-pipe, [OBJCFLAGS="$OBJCFLAGS -pipe"]) - ;; -esac +AX_CHECK_COMPILER_FLAGS(-pipe, [OBJCFLAGS="$OBJCFLAGS -pipe"]) AX_CHECK_COMPILER_FLAGS(-fno-common, [OBJCFLAGS="$OBJCFLAGS -fno-common"]) AX_CHECK_COMPILER_FLAGS(-Xclang -fno-constant-cfstrings, [ flag="-Xclang -fno-constant-cfstrings" OBJCFLAGS="$OBJCFLAGS $flag" OBJFW_OBJCFLAGS="$OBJFW_OBJCFLAGS $flag" @@ -341,35 +339,36 @@ [OBJCFLAGS="$OBJCFLAGS -Wobjc-missing-property-synthesis"]) AX_CHECK_COMPILER_FLAGS([-Wmissing-method-return-type -Werror], [OBJCFLAGS="$OBJCFLAGS -Wmissing-method-return-type"]) case "$host" in - m68k-*-amigaos*) - dnl The inline headers generate code that triggers - dnl -Wpointer-sign. - OBJCFLAGS="$OBJCFLAGS -Wno-pointer-sign" - ;; +m68k-*-amigaos*) + dnl The inline headers generate code that triggers -Wpointer-sign. + OBJCFLAGS="$OBJCFLAGS -Wno-pointer-sign" + ;; esac AC_MSG_CHECKING(whether Objective C compiler supports properties) -AC_TRY_COMPILE([ - #ifdef __has_attribute - # if __has_attribute(objc_root_class) - __attribute__((__objc_root_class__)) - # endif - #endif - @interface Foo - { - id bar; - } - - @property (nonatomic, retain) id bar; - @end -], [ - Foo *foo = (id)0; - [foo setBar: (id)0]; - foo = [foo bar]; +AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([ + #ifdef __has_attribute + # if __has_attribute(objc_root_class) + __attribute__((__objc_root_class__)) + # endif + #endif + @interface Foo + { + id bar; + } + + @property (nonatomic, retain) id bar; + @end + ], [[ + Foo *foo = (id)0; + [foo setBar: (id)0]; + foo = [foo bar]; + ]]) ], [ AC_MSG_RESULT(yes) ], [ AC_MSG_RESULT(no) AC_MSG_ERROR(Compiler does not support properties!) @@ -382,17 +381,12 @@ 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}") AC_SUBST(EXCEPTIONS_LIB_A, "exceptions.lib.a") - AC_SUBST(EXCEPTIONS_EXCEPTIONS_LIB_A, "exceptions/exceptions.lib.a") AC_SUBST(FORWARDING_LIB_A, "forwarding.lib.a") - AC_SUBST(FORWARDING_FORWARDING_LIB_A, "forwarding/forwarding.lib.a") - AC_SUBST(INVOCATION_LIB_A, "invocation.lib.a") - AC_SUBST(INVOCATION_INVOCATION_LIB_A, "invocation/invocation.lib.a") AC_SUBST(LOOKUP_ASM_LIB_A, "lookup-asm.lib.a") - AC_SUBST(LOOKUP_ASM_LOOKUP_ASM_LIB_A, "lookup-asm/lookup-asm.lib.a") BUILDSYS_FRAMEWORK([ AC_SUBST(OBJFW_FRAMEWORK, "ObjFW.framework") build_framework="yes" ]) @@ -412,26 +406,26 @@ ]) 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_shared" = x"no" -a x"$enable_amiga_lib" = x"no"], [ - enable_static="yes" +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_static" = x"yes" -o x"$enable_amiga_lib" != x"no"], [ +AS_IF([test x"$enable_shared" = x"no" -a x"$enable_amiga_lib" = 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") - AC_SUBST(EXCEPTIONS_EXCEPTIONS_A, "exceptions/exceptions.a") AC_SUBST(FORWARDING_A, "forwarding.a") - AC_SUBST(FORWARDING_FORWARDING_A, "forwarding/forwarding.a") - AC_SUBST(INVOCATION_A, "invocation.a") - AC_SUBST(INVOCATION_INVOCATION_A, "invocation/invocation.a") AC_SUBST(LOOKUP_ASM_A, "lookup-asm.a") - AC_SUBST(LOOKUP_ASM_LOOKUP_ASM_A, "lookup-asm/lookup-asm.a") ]) AC_DEFINE_UNQUOTED(PLUGIN_SUFFIX, "$PLUGIN_SUFFIX", [Suffix for plugins]) AS_IF([test x"$enable_files" != x"no" -a x"$PLUGIN_SUFFIX" != x""], [ AC_SUBST(USE_SRCS_PLUGINS, '${SRCS_PLUGINS}') @@ -453,11 +447,11 @@ AC_MSG_CHECKING(whether we need -D_GNU_SOURCE) AC_EGREP_CPP(egrep_cpp_yes, [ #include #if defined(__GLIBC__) || defined(__MINGW32__) || \ - defined(__NEWLIB__) || defined(__MORPHOS__) + defined(__NEWLIB__) || defined(__MORPHOS__) || defined(__MINT__) egrep_cpp_yes #endif ], [ AC_MSG_RESULT(yes) CPPFLAGS="-D_GNU_SOURCE $CPPFLAGS" @@ -465,13 +459,13 @@ ], [ AC_MSG_RESULT(no) ]) case "$host_os" in - solaris*) - CPPFLAGS="-D__EXTENSIONS__ -D_POSIX_PTHREAD_SEMANTICS $CPPFLAGS" - ;; +solaris*) + CPPFLAGS="-D__EXTENSIONS__ -D_POSIX_PTHREAD_SEMANTICS $CPPFLAGS" + ;; esac objc_runtime="ObjFW runtime" AC_CHECK_HEADER(objc/objc.h) AC_MSG_CHECKING(which Objective C runtime to use) @@ -497,19 +491,19 @@ ]) ]) AC_MSG_RESULT($objc_runtime) case "$objc_runtime" in - "ObjFW runtime") - AC_DEFINE(OF_OBJFW_RUNTIME, 1, - [Whether we use the ObjFW runtime]) - - AC_MSG_CHECKING([whether -fobjc-runtime=objfw is supported]) - - old_OBJCFLAGS="$OBJCFLAGS" - OBJCFLAGS="$OBJCFLAGS -Xclang -fobjc-runtime=objfw" - AC_TRY_LINK([ +"ObjFW runtime") + AC_DEFINE(OF_OBJFW_RUNTIME, 1, [Whether we use the ObjFW runtime]) + + AC_MSG_CHECKING([whether -fobjc-runtime=objfw is supported]) + + old_OBJCFLAGS="$OBJCFLAGS" + OBJCFLAGS="$OBJCFLAGS -Xclang -fobjc-runtime=objfw" + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([ #ifdef __has_attribute # if __has_attribute(objc_root_class) __attribute__((__objc_root_class__)) # endif #endif @@ -531,205 +525,217 @@ void __objc_exec_class(void *module) { } - ], [ + ], [[ [Test test]; - ], [ - flag="-Xclang -fobjc-runtime=objfw" - OBJFW_OBJCFLAGS="$OBJFW_OBJCFLAGS $flag" - AC_MSG_RESULT(yes) - ], [ - flag="-fgnu-runtime" - OBJCFLAGS="$old_OBJCFLAGS $flag" - OBJFW_OBJCFLAGS="$OBJFW_OBJCFLAGS $flag" - AC_MSG_RESULT(no) - old_compiler="yes" - ]) - - 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}") - ]) - - AS_IF([test x"$enable_static" = x"yes"], [ - AC_SUBST(OBJFWRT_STATIC_LIB, "libobjfwrt.a") - ]) - - 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"], [ - tmp="../src/runtime/libobjfwrt.a" - AC_SUBST(LIBOBJFWRT_DEP, "$tmp") - AC_SUBST(LIBOBJFWRT_DEP_LVL2, "../$tmp") - ]) - - AS_IF([test x"$enable_seluid24" = x"yes"], [ - AC_DEFINE(OF_SELUID24, 1, - [Whether to use 24 bit selector UIDs]) - ]) - - AC_MSG_CHECKING(for exception type) - AC_TRY_COMPILE([ + ]]) + ], [ + OBJFW_OBJCFLAGS="$OBJFW_OBJCFLAGS -Xclang -fobjc-runtime=objfw" + AC_MSG_RESULT(yes) + ], [ + OBJCFLAGS="$old_OBJCFLAGS -fgnu-runtime" + OBJFW_OBJCFLAGS="$OBJFW_OBJCFLAGS -fgnu-runtime" + AC_MSG_RESULT(no) + old_compiler="yes" + ]) + + 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}") + ]) + + AS_IF([test x"$enable_static" = x"yes"], [ + AC_SUBST(OBJFWRT_STATIC_LIB, "libobjfwrt.a") + ]) + + 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(LIBOBJFWRT_DEP, "../src/runtime/libobjfwrt.a") + AC_SUBST(LIBOBJFWRT_DEP_LVL2, "../../src/runtime/libobjfwrt.a") + ]) + + AS_IF([test x"$enable_seluid24" = x"yes"], [ + AC_DEFINE(OF_SELUID24, 1, [Whether to use 24 bit selector UIDs]) + ]) + + AC_MSG_CHECKING(for exception type) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([ extern void foo(); ], [ @try { foo(); } @finally { foo(); } - ], [ - AS_IF([$EGREP __gnu_objc_personality_v0 \ - conftest.$ac_objext >/dev/null], [ - exception_type="DWARF" - ]) - AS_IF([$EGREP __gnu_objc_personality_sj0 \ - conftest.$ac_objext >/dev/null], [ - exception_type="SjLj" - ]) - AS_IF([$EGREP __gnu_objc_personality_seh0 \ - conftest.$ac_objext >/dev/null], [ - exception_type="SEH" - ]) - - raise_exception="_Unwind_RaiseException" - - case "$exception_type" in - DWARF) - AC_DEFINE(HAVE_DWARF_EXCEPTIONS, 1, - [Whether DWARF exceptions are used]) - ;; - SjLj) - AC_DEFINE(HAVE_SJLJ_EXCEPTIONS, 1, - [Whether SjLj exceptions are used]) - raise_exception="_Unwind_SjLj_RaiseException" - ;; - SEH) - AC_DEFINE(HAVE_SEH_EXCEPTIONS, 1, - [Whether SEH exceptions are used]) - ;; - *) - AC_MSG_RESULT(unknown) - AC_MSG_ERROR([Exception type not detected!]) - ;; - esac - - AC_MSG_RESULT($exception_type) - ], [ - AC_MSG_RESULT(exceptions unavailable!) - AC_MSG_ERROR([Exceptions not accepted by compiler!]) - ]) - - AC_SEARCH_LIBS($raise_exception, [c++abi gcc_s gcc], [ - dnl c++abi requires pthread on OpenBSD - AS_IF([test x"$ac_lib" = x"c++abi"], [ - LIBS="$LIBS -lpthread" - ]) - ], [ - AC_MSG_ERROR([$raise_exception missing!]) - ], [-lpthread]) - - AC_CHECK_FUNCS(_Unwind_GetDataRelBase _Unwind_GetTextRelBase) - ;; - "Apple runtime") - AC_DEFINE(OF_APPLE_RUNTIME, 1, - [Whether we use the Apple ObjC runtime]) - - AC_CHECK_LIB(objc, objc_msgSend, [ - AC_SUBST(RUNTIME_LIBS, "-lobjc") - AC_SUBST(RUNTIME_FRAMEWORK_LIBS, "-lobjc") - ], [ - AC_MSG_ERROR([libobjc not found!]) - ]) - - AC_CHECK_FUNC(objc_autoreleasePoolPush, [], [ - AC_SUBST(RUNTIME_AUTORELEASE_M, "runtime/autorelease.m") - ]) - AC_CHECK_FUNC(objc_constructInstance, [], [ - AC_SUBST(RUNTIME_INSTANCE_M, "runtime/instance.m") - ]) - ;; -esac - -AC_CHECK_FUNCS(_Unwind_Backtrace) - -case "$host_os" in - darwin*) - AC_SUBST(LDFLAGS_REEXPORT, ["-Wl,-reexport-lobjfw"]) - AS_IF([test x"$objc_runtime" = x"Apple runtime"], [ - AC_SUBST(REEXPORT_RUNTIME, ["-Wl,-reexport-lobjc"]) - AC_SUBST(REEXPORT_RUNTIME_FRAMEWORK, - ["-Wl,-reexport-lobjc"]) - LDFLAGS="$LDFLAGS -Wl,-U,_NSFoundationVersionNumber" - ]) - - AS_IF([test x"$objc_runtime" = x"ObjFW runtime"], [ - AS_IF([test x"$exception_type" = x"DWARF"], [ - LDFLAGS="$LDFLAGS -Wl,-U,___gxx_personality_v0" - ]) - AS_IF([test x"$exception_type" = x"SjLj"], [ - LDFLAGS="$LDFLAGS -Wl,-U,___gxx_personality_sj0" - ]) - AC_SUBST(REEXPORT_RUNTIME, ["-Wl,-reexport-lobjfwrt"]) - AC_SUBST(REEXPORT_RUNTIME_FRAMEWORK, - ["-Wl,-reexport_framework,ObjFWRT"]) - ]) - - AC_CHECK_HEADERS(sysdir.h) - AC_CHECK_FUNCS(sysdir_start_search_path_enumeration) - - AS_IF([test x"$host_is_ios" = x"yes"], [ - AC_SUBST(TESTS_STATIC_LIB, tests.a) - TESTS_LIBS="$TESTS_LIBS -framework CoreFoundation" - ]) - ;; + ]) + ], [ + AS_IF([$EGREP __gnu_objc_personality_v0 conftest.$ac_objext \ + >/dev/null], [ + exception_type="DWARF" + ]) + AS_IF([$EGREP __gnu_objc_personality_sj0 conftest.$ac_objext \ + >/dev/null], [ + exception_type="SjLj" + ]) + AS_IF([$EGREP __gnu_objc_personality_seh0 conftest.$ac_objext \ + >/dev/null], [ + exception_type="SEH" + ]) + + case "$exception_type" in + DWARF) + AC_DEFINE(HAVE_DWARF_EXCEPTIONS, 1, + [Whether DWARF exceptions are used]) + raise_exception="_Unwind_RaiseException" + ;; + SjLj) + AC_DEFINE(HAVE_SJLJ_EXCEPTIONS, 1, + [Whether SjLj exceptions are used]) + raise_exception="_Unwind_SjLj_RaiseException" + ;; + SEH) + AC_DEFINE(HAVE_SEH_EXCEPTIONS, 1, + [Whether SEH exceptions are used]) + raise_exception="_Unwind_RaiseException" + ;; + *) + AC_MSG_RESULT(unknown) + AC_MSG_ERROR([Exception type not detected!]) + ;; + esac + + AC_MSG_RESULT($exception_type) + ], [ + AC_MSG_RESULT(exceptions unavailable!) + AC_MSG_ERROR([Exceptions not accepted by compiler!]) + ]) + + AC_SEARCH_LIBS($raise_exception, [c++abi gcc_s gcc unwind], [ + dnl c++abi requires pthread on OpenBSD + AS_IF([test x"$ac_lib" = x"c++abi"], [LIBS="$LIBS -lpthread"]) + ], [ + AC_MSG_ERROR([$raise_exception missing!]) + ], [-lpthread]) + + AC_CHECK_FUNCS(_Unwind_GetDataRelBase _Unwind_GetTextRelBase) + ;; +"Apple runtime") + AC_DEFINE(OF_APPLE_RUNTIME, 1, [Whether we use the Apple ObjC runtime]) + + AC_CHECK_LIB(objc, objc_msgSend, [ + AC_SUBST(RUNTIME_LIBS, "-lobjc") + AC_SUBST(RUNTIME_FRAMEWORK_LIBS, "-lobjc") + ], [ + AC_MSG_ERROR([libobjc not found!]) + ]) + + old_OBJCFLAGS="$OBJCFLAGS" + OBJCFLAGS="$OBJCFLAGS -lobjc" + + AC_CHECK_FUNC(objc_autoreleasePoolPush, [], [ + AC_SUBST(RUNTIME_AUTORELEASE_M, "runtime/autorelease.m") + ]) + AC_CHECK_FUNC(objc_constructInstance, [], [ + AC_SUBST(RUNTIME_INSTANCE_M, "runtime/instance.m") + ]) + + OBJCFLAGS="$old_OBJCFLAGS" + ;; +esac + +case "$host_os" in +mint*) + dnl _Unwind_Backtrace crashes on MiNT + ;; +hpux*) + dnl _Unwind_Backtrace() returns complete garbage on HP-UX. + ;; +*) + AC_CHECK_FUNCS(_Unwind_Backtrace) + ;; +esac + +case "$host_os" in +darwin*) + AC_SUBST(LDFLAGS_REEXPORT, ["-Wl,-reexport-lobjfw"]) + AS_IF([test x"$objc_runtime" = x"Apple runtime"], [ + AC_SUBST(REEXPORT_RUNTIME, ["-Wl,-reexport-lobjc"]) + AC_SUBST(REEXPORT_RUNTIME_FRAMEWORK, ["-Wl,-reexport-lobjc"]) + LDFLAGS="$LDFLAGS -Wl,-U,_NSFoundationVersionNumber" + ]) + + AS_IF([test x"$objc_runtime" = x"ObjFW runtime"], [ + AS_IF([test x"$exception_type" = x"DWARF"], [ + LDFLAGS="$LDFLAGS -Wl,-U,___gxx_personality_v0" + ]) + AS_IF([test x"$exception_type" = x"SjLj"], [ + LDFLAGS="$LDFLAGS -Wl,-U,___gxx_personality_sj0" + ]) + AC_SUBST(REEXPORT_RUNTIME, ["-Wl,-reexport-lobjfwrt"]) + AC_SUBST(REEXPORT_RUNTIME_FRAMEWORK, + ["-Wl,-reexport_framework,ObjFWRT"]) + ]) + + AC_CHECK_HEADERS(sysdir.h) + AC_CHECK_FUNCS(sysdir_start_search_path_enumeration) + + AS_IF([test x"$host_is_ios" = x"yes"], [ + AC_SUBST(TESTS_STATIC_LIB, tests.a) + TESTS_LIBS="$TESTS_LIBS -framework CoreFoundation" + ]) + ;; esac AC_MSG_CHECKING(whether Objective C compiler supports ARC) old_OBJCFLAGS="$OBJCFLAGS" OBJCFLAGS="$OBJCFLAGS -fobjc-arc -fobjc-arc-exceptions" -AC_TRY_COMPILE([ - #ifdef __has_attribute - # if __has_attribute(objc_root_class) - __attribute__((__objc_root_class__)) - # endif - #endif - @interface Foo - { - struct objc_class *_isa; - } - - + (id)alloc; - @end - - @implementation Foo - + (id)alloc - { - return (id)0; - } - @end -], [ - __weak id foo = [Foo alloc]; - (void)foo; +AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([ + #ifdef __has_attribute + # if __has_attribute(objc_root_class) + __attribute__((__objc_root_class__)) + # endif + #endif + @interface Foo + { + struct objc_class *_isa; + } + + + (id)alloc; + @end + + @implementation Foo + + (id)alloc + { + return (id)0; + } + @end + ], [[ + __weak id foo = [Foo alloc]; + (void)foo; + ]]) ], [ AC_MSG_RESULT(yes) AC_DEFINE(COMPILER_SUPPORTS_ARC, 1, [Whether the compiler supports ARC]) AC_SUBST(RUNTIME_ARC_TESTS_M, RuntimeARCTests.m) ], [ @@ -742,39 +748,10 @@ ]) AS_IF([test x"$ac_cv_c_bigendian" = x"universal"], [ AC_DEFINE(OF_UNIVERSAL, 1, [Whether we are building a universal binary]) ]) -AC_MSG_CHECKING(for SIZE_MAX) -AC_EGREP_CPP(egrep_cpp_yes, [ - #include - #include - - #ifdef SIZE_MAX - egrep_cpp_yes - #endif -], [ - AC_MSG_RESULT(yes) -], [ - AC_MSG_RESULT(no) - AC_MSG_CHECKING(for SIZE_T_MAX) - AC_EGREP_CPP(egrep_cpp_yes, [ - #include - #include - - #ifdef SIZE_T_MAX - egrep_cpp_yes - #endif - ], [ - AC_MSG_RESULT(yes) - size_max="SIZE_T_MAX" - ], [ - AC_MSG_RESULT(no) - size_max="(~(size_t)0)" - ]) - AC_DEFINE_UNQUOTED(SIZE_MAX, $size_max, [Maximum value for size_t]) -]) AC_MSG_CHECKING(for SSIZE_MAX) AC_EGREP_CPP(egrep_cpp_yes, [ #include #include @@ -783,12 +760,11 @@ #endif ], [ AC_MSG_RESULT(yes) ], [ AC_MSG_RESULT(no) - AC_DEFINE(SSIZE_MAX, [((ssize_t)(SIZE_MAX / 2))], - [Maximum value for ssize_t]) + AC_DEFINE(SSIZE_MAX, [(SIZE_MAX / 2)], [Maximum value for ssize_t]) ]) AC_MSG_CHECKING(for UINTPTR_MAX) AC_EGREP_CPP(egrep_cpp_yes, [ #include #include @@ -798,11 +774,13 @@ #endif ], [ AC_MSG_RESULT(yes) ], [ AC_MSG_RESULT(no) - AC_DEFINE(UINTPTR_MAX, [(~(uintptr_t)0)], [Maximum value for uintptr_t]) + AC_CHECK_SIZEOF(uintptr_t) + AC_DEFINE(UINTPTR_MAX, + [(SIZEOF_UINTPTR_T * CHAR_BIT)], [Maximum value for uintptr_t]) ]) AC_CHECK_HEADER(inttypes.h, [AC_DEFINE(OF_HAVE_INTTYPES_H, 1, [Whether we have inttypes.h])]) @@ -825,13 +803,14 @@ [Floating point implementation does not conform to IEEE 754!])]) AC_MSG_CHECKING(for floating point endianess) fp_endianess="unknown" AS_IF([test x"$ac_cv_c_bigendian" != x"universal"], [ - AC_TRY_COMPILE([ - double endianess = 2.993700760838795055656993580068609688772747263874402942272934826871811872228512759832626847251963763755836687759498519784550143745834860002945223766052808125982053455555265216112722718870586961456110693379343178124592311441022662940307099598578775368547768968914916965731708568179631324904813506101190853720749196062963892799499230635163056742330563321122389331703618066046034494287335316842529021563862331183541255013987734473643350285400060357711238514186776429325214739886098119655678483017894951556639821088508565036657794343031121375178126860889964700274558728491825977274341798997758923017217660272136611938897932105874133412726223468780517578125e-259; - ], [ + AC_COMPILE_IFELSE([ + AC_LANG_SOURCE([ + double endianess = 2.993700760838795055656993580068609688772747263874402942272934826871811872228512759832626847251963763755836687759498519784550143745834860002945223766052808125982053455555265216112722718870586961456110693379343178124592311441022662940307099598578775368547768968914916965731708568179631324904813506101190853720749196062963892799499230635163056742330563321122389331703618066046034494287335316842529021563862331183541255013987734473643350285400060357711238514186776429325214739886098119655678483017894951556639821088508565036657794343031121375178126860889964700274558728491825977274341798997758923017217660272136611938897932105874133412726223468780517578125e-259; + ]) ], [ AS_IF([$EGREP BigEnd conftest.$ac_objext >/dev/null], [ AC_DEFINE(OF_FLOAT_BIG_ENDIAN, 1, [Whether floats are big endian]) fp_endianess="big endian" @@ -847,74 +826,53 @@ AC_MSG_RESULT($fp_endianess) AS_IF([test x"$fp_endianess" = x"unknown"], [ AC_MSG_ERROR( [Floating point implementation does not conform to IEEE 754!])]) -AC_MSG_CHECKING(for INFINITY) -AC_TRY_COMPILE([ - #include - #include -], [ - printf("%f", INFINITY); -], [ - AC_MSG_RESULT(yes) -], [ - AC_MSG_RESULT(no) - - AC_MSG_CHECKING(for __builtin_inf) - AC_TRY_COMPILE([ - #include - ], [ - printf("%f", __builtin_inf()); - ], [ - AC_MSG_RESULT(yes) - AC_DEFINE(INFINITY, [(__builtin_inf())], - [Workaround for missing INFINITY]) - ], [ - AC_MSG_RESULT(no) - - AC_MSG_ERROR([Neither INFINITY or __builtin_inf was found!]) - ]) -]) - case "$host_cpu" in - arm* | earm*) - AC_MSG_CHECKING(for VFP2 or above) - AC_TRY_COMPILE([], [ +arm* | earm*) + AC_MSG_CHECKING(for VFP2 or above) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([], [ #if !defined(__arm64__) && !defined(__aarch64__) && \ !defined(__ARM64_ARCH_8__) __asm__ __volatile__ ( "vstmdb sp!, {d0-d7}" ); #endif - ], [ - AC_DEFINE(HAVE_VFP2, 1, [Whether we have VFP2 or above]) - AC_MSG_RESULT(yes) - ], [ - AC_MSG_RESULT(no) ]) - ;; + ], [ + AC_DEFINE(HAVE_VFP2, 1, [Whether we have VFP2 or above]) + AC_MSG_RESULT(yes) + ], [ + AC_MSG_RESULT(no) + ]) + ;; esac AC_CHECK_LIB(m, fmod, LIBS="$LIBS -lm") AC_CHECK_LIB(complex, creal, TESTS_LIBS="$TESTS_LIBS -lcomplex") +AC_CHECK_FUNCS(strtof truncf) + AC_CHECK_FUNC(asprintf, [ case "$host" in - *-*-mingw*) - dnl asprintf from MinGW is broken on older Windows - dnl versions - have_asprintf="no" - ;; - *-psp-*) - dnl asprintf is broken on the PSP - have_asprintf="no" - ;; - *) - have_asprintf="yes" - AC_DEFINE(HAVE_ASPRINTF, 1, - [Whether we have asprintf()]) + *-*-mint*) + dnl asprintf is not in headers + have_asprintf="no" + ;; + *-*-mingw*) + dnl asprintf from MinGW is broken on older Windows versions + have_asprintf="no" + ;; + *-psp-*) + dnl asprintf is broken on the PSP + have_asprintf="no" + ;; + *) + have_asprintf="yes" + AC_DEFINE(HAVE_ASPRINTF, 1, [Whether we have asprintf()]) ;; esac ], [ have_asprintf="no" ]) @@ -931,58 +889,54 @@ AC_DEFUN([ENCODING_FLAG], [ AC_ARG_ENABLE($1, AS_HELP_STRING([--disable-$1], [Disables support for $3])) AS_IF([test x"$enable_$2" != x"no"], [ - AC_DEFINE($4, 1, - [Whether we have support for $3]) - ENCODINGS_SRCS="$ENCODINGS_SRCS $2.m" + AC_DEFINE($4, 1, [Whether we have support for $3]) + ENCODINGS_SRCS="$ENCODINGS_SRCS $1.m" ]) ]) ENCODING_FLAG(codepage-437, codepage_437, [Codepage 437], HAVE_CODEPAGE_437) ENCODING_FLAG(codepage-850, codepage_850, [Codepage 850], HAVE_CODEPAGE_850) ENCODING_FLAG(codepage-858, codepage_858, [Codepage 858], HAVE_CODEPAGE_858) -ENCODING_FLAG(iso-8859-2, iso_8859-2, [ISO 8859-2], HAVE_ISO_8859_2) -ENCODING_FLAG(iso-8859-3, iso_8859-3, [ISO 8859-3], HAVE_ISO_8859_3) -ENCODING_FLAG(iso-8859-15, iso_8859-15, [ISO 8859-15], HAVE_ISO_8859_15) -ENCODING_FLAG(koi8-r, koi8-r, [KOI8-R], HAVE_KOI8_R) -ENCODING_FLAG(koi8-u, koi8-u, [KOI8-U], HAVE_KOI8_U) +ENCODING_FLAG(iso-8859-2, iso_8859_2, [ISO 8859-2], HAVE_ISO_8859_2) +ENCODING_FLAG(iso-8859-3, iso_8859_3, [ISO 8859-3], HAVE_ISO_8859_3) +ENCODING_FLAG(iso-8859-15, iso_8859_15, [ISO 8859-15], HAVE_ISO_8859_15) +ENCODING_FLAG(koi8-r, koi8_r, [KOI8-R], HAVE_KOI8_R) +ENCODING_FLAG(koi8-u, koi8_u, [KOI8-U], HAVE_KOI8_U) ENCODING_FLAG(mac-roman, mac_roman, [Mac Roman encoding], HAVE_MAC_ROMAN) -ENCODING_FLAG(windows-1251, windows-1251, [Windows-1251], HAVE_WINDOWS_1251) -ENCODING_FLAG(windows-1252, windows-1252, [Windows-1252], HAVE_WINDOWS_1252) +ENCODING_FLAG(windows-1251, windows_1251, [Windows-1251], HAVE_WINDOWS_1251) +ENCODING_FLAG(windows-1252, windows_1252, [Windows-1252], HAVE_WINDOWS_1252) +AS_IF([test x"$ENCODINGS_SRCS" = x""], [ + ENCODINGS_SRCS="dummy.m" +]) AC_SUBST(ENCODINGS_SRCS) -AS_IF([test x"$ENCODINGS_SRCS" != x""], [ - AC_SUBST(ENCODINGS, "encodings") - - AS_IF([test x"$enable_shared" != x"no"], [ - AC_SUBST(ENCODINGS_LIB_A, "encodings.lib.a") - AC_SUBST(ENCODINGS_ENCODINGS_LIB_A, "encodings/encodings.lib.a") - ]) - AS_IF([test x"$enable_static" = x"yes" -o x"$enable_shared" = x"no"], [ - AC_SUBST(ENCODINGS_A, "encodings.a") - AC_SUBST(ENCODINGS_ENCODINGS_A, "encodings/encodings.a") - ]) +AS_IF([test x"$enable_shared" != x"no"], [ + AC_SUBST(ENCODINGS_LIB_A, "encodings.lib.a") +]) +AS_IF([test x"$enable_static" = x"yes" -o x"$enable_shared" = x"no"], [ + AC_SUBST(ENCODINGS_A, "encodings.a") ]) AC_CHECK_FUNCS(arc4random arc4random_buf getrandom random, break) AS_IF([test x"$host_os" != x"morphos"], [ AC_CHECK_LIB(dl, dlopen, LIBS="$LIBS -ldl") ]) AC_CHECK_HEADERS_ONCE(dlfcn.h) case "$host_os" in - netbsd*) - dnl dladdr exists on NetBSD, but it is completely broken. - dnl When using it with code that uses __thread, it freezes the - dnl process so that it has to be killed using SIGKILL. - dnl When disabling __thread, it doesn't freeze, but all symbols - dnl are wrong. - ;; - *) - AC_CHECK_FUNCS(dladdr) - ;; +netbsd*) + dnl dladdr exists on NetBSD, but it is completely broken. + dnl When using it with code that uses __thread, it freezes the process + dnl so that it has to be killed using SIGKILL. + dnl When disabling __thread, it doesn't freeze, but all symbols are + dnl wrong. + ;; +*) + AC_CHECK_FUNCS(dladdr) + ;; esac AC_CHECK_HEADERS(sys/mman.h) AC_CHECK_FUNCS(mmap mlock) @@ -1007,28 +961,32 @@ CPPFLAGS="$CPPFLAGS -Wp,-pthread" ], [ CPPFLAGS="$CPPFLAGS -D_REENTRANT -D_THREAD_SAFE" ]) - AC_CHECK_LIB(pthread, pthread_create, LIBS="$LIBS -lpthread") + AC_CHECK_LIB(pthread, main, LIBS="$LIBS -lpthread") - AC_TRY_LINK([ - #include - ], [ - pthread_create(NULL, NULL, NULL, NULL); + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([ + #include + ], [ + pthread_create(NULL, NULL, NULL, NULL); + ]) ], [], [ AC_MSG_ERROR(No supported threads found!) ]) AC_DEFINE(OF_HAVE_PTHREADS, 1, [Whether we have pthreads]) - AC_TRY_COMPILE([ - #include - ], [ - pthread_mutexattr_t attr; - pthread_mutexattr_settype(&attr, - PTHREAD_MUTEX_RECURSIVE); + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([ + #include + ], [ + pthread_mutexattr_t attr; + pthread_mutexattr_settype(&attr, + PTHREAD_MUTEX_RECURSIVE); + ]) ], [ AC_DEFINE(OF_HAVE_RECURSIVE_PTHREAD_MUTEXES, 1, [If pthread mutexes can be recursive]) ]) @@ -1051,45 +1009,55 @@ ;; esac AC_DEFINE(OF_HAVE_THREADS, 1, [Whether we have threads]) AC_SUBST(USE_SRCS_THREADS, '${SRCS_THREADS}') + AC_SUBST(OBJC_SYNC, objc_sync) AC_ARG_ENABLE(compiler-tls, AS_HELP_STRING([--disable-compiler-tls], [disable compiler thread local storage])) case "$host" in - aarch64*-*-android*) - # Compiler TLS is broken on AArch64 Android with Clang - enable_compiler_tls="no" - ;; - m68k-*-amigaos | powerpc-*-amigaos) - # Compiler TLS is broken on AmigaOS - enable_compiler_tls="no" - ;; + aarch64*-*-android*) + dnl Compiler TLS is broken on AArch64 Android with Clang + enable_compiler_tls="no" + ;; + m68k-*-amigaos* | powerpc-*-amigaos*) + dnl Compiler TLS is broken on AmigaOS + enable_compiler_tls="no" + ;; + *-*-morphos*) + dnl Compiler TLS needs helpers that we don't want in the + dnl .library + enable_compiler_tls="no" + ;; esac AS_IF([test x"$enable_compiler_tls" != x"no"], [ AC_CHECK_HEADER(threads.h, [ AC_DEFINE(OF_HAVE_THREADS_H, 1, [Whether we have threads.h]) ]) AC_MSG_CHECKING(whether _Thread_local works) - AC_TRY_LINK([ - static _Thread_local int x = 0; - ], [ - x++; + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([ + static _Thread_local int x = 0; + ], [ + x++; + ]) ], [ AS_IF([test x"$enable_shared" != x"no"], [ old_OBJCFLAGS="$OBJCFLAGS" OBJCFLAGS="$OBJCFLAGS -fPIC" - AC_TRY_COMPILE([ - static _Thread_local int x = 0; - ], [ - x++; + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([ + static _Thread_local int x = 0; + ], [ + x++; + ]) ], [ AC_MSG_RESULT(yes) AC_DEFINE(OF_HAVE__THREAD_LOCAL, 1, [Whether _Thread_local works]) have_thread_local="yes" @@ -1107,27 +1075,33 @@ AC_MSG_RESULT(no) ]) AS_IF([test x"$have_thread_local" != x"yes"], [ AC_MSG_CHECKING(whether __thread works) - AC_TRY_LINK([ - /* It seems __thread is buggy with GCC 4.1 */ - #if __GNUC__ == 4 && __GNUC_MINOR__ < 2 - # error buggy - #endif - - __thread int x = 0; - ], [ - x++; + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([ + /* + * It seems __thread is buggy with + * GCC 4.1 */ + #if __GNUC__ == 4 && __GNUC_MINOR__ < 2 + # error buggy + #endif + + __thread int x = 0; + ], [ + x++; + ]) ], [ AS_IF([test x"$enable_shared" != x"no"], [ old_OBJCFLAGS="$OBJCFLAGS" OBJCFLAGS="$OBJCFLAGS -fPIC" - AC_TRY_COMPILE([ - __thread int x = 0; - ], [ - x++; + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([ + __thread int x = 0; + ], [ + x++; + ]) ], [ AC_MSG_RESULT(yes) AC_DEFINE(OF_HAVE___THREAD, 1, [Whether __thread works] ) @@ -1162,20 +1136,22 @@ ], [ AC_MSG_RESULT(no) ]) AC_MSG_CHECKING(whether __atomic_* works) - AC_TRY_LINK([ - #include - #include - ], [ - int32_t i, j; - if (__atomic_add_fetch(&i, 1, __ATOMIC_RELAXED)) - j = __atomic_sub_fetch(&i, 1, __ATOMIC_RELAXED); - while (!__atomic_compare_exchange_n(&i, &j, 1, false, - __ATOMIC_RELAXED, __ATOMIC_RELAXED)); - __atomic_thread_fence(__ATOMIC_SEQ_CST); + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([ + #include + #include + ], [ + int32_t i, j; + if (__atomic_add_fetch(&i, 1, __ATOMIC_RELAXED)) + j = __atomic_sub_fetch(&i, 1, __ATOMIC_RELAXED); + while (!__atomic_compare_exchange_n(&i, &j, 1, false, + __ATOMIC_RELAXED, __ATOMIC_RELAXED)); + __atomic_thread_fence(__ATOMIC_SEQ_CST); + ]) ], [ AC_MSG_RESULT(yes) test x"$atomic_ops" = x"none" && \ atomic_ops="__atomic_* builtins" AC_DEFINE(OF_HAVE_ATOMIC_BUILTINS, 1, @@ -1183,15 +1159,19 @@ ], [ AC_MSG_RESULT(no) ]) AC_MSG_CHECKING(whether __sync_* works) - AC_TRY_LINK([#include ], [ - int32_t i, j; - if (__sync_add_and_fetch(&i, 1)) - j = __sync_sub_and_fetch(&i, 1); - while (!__sync_bool_compare_and_swap(&i, 0, 1)); + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([ + #include + ], [ + int32_t i, j; + if (__sync_add_and_fetch(&i, 1)) + j = __sync_sub_and_fetch(&i, 1); + while (!__sync_bool_compare_and_swap(&i, 0, 1)); + ]) ], [ AC_MSG_RESULT(yes) test x"$atomic_ops" = x"none" && \ atomic_ops="__sync_* builtins" AC_DEFINE(OF_HAVE_SYNC_BUILTINS, 1, @@ -1224,20 +1204,19 @@ AC_SUBST(USE_SRCS_FILES, '${SRCS_FILES}') AC_SUBST(OFARC, "ofarc") AC_SUBST(OFHASH, "ofhash") case "$host_os" in - msdosdjgpp*) - dnl DJGPP has the type, but it's not really usable. - ;; - *) - AC_CHECK_TYPE(off64_t, [ - AC_DEFINE(OF_HAVE_OFF64_T, 1, - [Whether we have off64_t]) - AC_CHECK_FUNCS([lseek64 lstat64 open64 stat64]) - ]) - ;; + msdosdjgpp*) + dnl DJGPP has the type, but it's not really usable. + ;; + *) + AC_CHECK_TYPE(off64_t, [ + AC_DEFINE(OF_HAVE_OFF64_T, 1, [Whether we have off64_t]) + AC_CHECK_FUNCS([lseek64 lstat64 open64 stat64]) + ]) + ;; esac AC_CHECK_HEADERS([pwd.h grp.h]) AC_CHECK_FUNC(chmod, [ AC_DEFINE(OF_HAVE_CHMOD, 1, [Whether we have chmod()]) @@ -1257,53 +1236,70 @@ ]) old_OBJCFLAGS="$OBJCFLAGS" OBJCFLAGS="$OBJCFLAGS -Werror" AC_MSG_CHECKING(for readdir_r) - AC_TRY_COMPILE([ - #include - ], [ - DIR *dir = 0; - struct dirent entry, *result; + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([ + #include + ], [ + DIR *dir = 0; + struct dirent entry, *result; - readdir_r(dir, &entry, &result); + readdir_r(dir, &entry, &result); + ]) ], [ AC_MSG_RESULT(yes) AC_DEFINE(HAVE_READDIR_R, 1, [Whether we have readdir_r()]) ], [ AC_MSG_RESULT(no) ]) OBJCFLAGS="$old_OBJCFLAGS" ]) -AC_CHECK_HEADERS(fcntl.h dirent.h) -AC_CHECK_FUNCS([sysconf gmtime_r localtime_r nanosleep fcntl]) +AC_CHECK_HEADERS(dirent.h) +AC_CHECK_FUNCS([sysconf gmtime_r localtime_r]) + +case "$host_os" in +amigaos* | morphos*) + dnl We don't want fcntl() or nanosleep() on AmigaOS / MorphOS, despite + dnl a symbol existing. The reason is that we cannot use fcntl() for + dnl sockets and that nanosleep() is yet another function that uses + dnl errno, so would need to be passed from the linklib. + ;; +*) + AC_CHECK_HEADERS(fcntl.h) + AC_CHECK_FUNCS([fcntl nanosleep]) + ;; +esac AC_CHECK_HEADERS(xlocale.h) AC_CHECK_FUNCS([strtod_l strtof_l asprintf_l]) 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_TRY_COMPILE([ - #include - #include - - #include - #ifdef HAVE_XLOCALE_H - # include - #endif - ], [ - #ifdef HAVE_STRTOD_L - (void)strtod_l; - #endif - #ifdef HAVE_STRTOF_L - (void)strtof_l; - #endif - #ifdef HAVE_ASPRINTF_L - (void)asprintf_l; - #endif + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([ + #include + #include + + #include + #ifdef HAVE_XLOCALE_H + # include + #endif + ], [ + #ifdef HAVE_STRTOD_L + (void)strtod_l; + #endif + #ifdef HAVE_STRTOF_L + (void)strtof_l; + #endif + #ifdef HAVE_ASPRINTF_L + (void)asprintf_l; + #endif + ]) ], [ AC_MSG_RESULT(no) ], [ AC_MSG_RESULT(yes) CPPFLAGS="-D_GNU_SOURCE $CPPFLAGS" @@ -1312,17 +1308,19 @@ dnl This check needs to happen after the above, as _GNU_SOURCE can change the dnl return type. AC_CHECK_FUNCS(strerror_r, [ AC_MSG_CHECKING(for return type of strerror_r) - AC_TRY_COMPILE([ - #include - #include - ], [ - switch (strerror_r(0, NULL, 0)) { - case 0:; - } + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([ + #include + #include + ], [ + switch (strerror_r(0, NULL, 0)) { + case 0:; + } + ]) ], [ AC_MSG_RESULT(int) ], [ AC_MSG_RESULT(char *) AC_DEFINE(STRERROR_R_RETURNS_CHARP, 1, @@ -1331,38 +1329,32 @@ ]) AC_CHECK_HEADERS(sys/utsname.h) AC_CHECK_FUNCS(uname) -case "$host_os" in - amigaos*) - ;; - *) - AC_CHECK_FUNC(pipe, [ - AC_DEFINE(OF_HAVE_PIPE, 1, [Whether we have pipe()]) - ]) - ;; -esac +AC_CHECK_FUNC(pipe, [ + AC_DEFINE(OF_HAVE_PIPE, 1, [Whether we have pipe()]) +]) AC_ARG_ENABLE(sockets, AS_HELP_STRING([--disable-sockets], [disable socket support])) AS_IF([test x"$enable_sockets" != x"no"], [ AC_DEFINE(OF_HAVE_SOCKETS, 1, [Whether we have sockets]) AC_SUBST(USE_SRCS_SOCKETS, '${SRCS_SOCKETS}') case "$host_os" in - amigaos*) - ;; - haiku*) - LIBS="$LIBS -lnetwork" - ;; - mingw*) - LIBS="$LIBS -lws2_32 -liphlpapi" - ;; - *) - AC_CHECK_LIB(socket, socket, LIBS="$LIBS -lsocket") - ;; + amigaos* | morphos*) + ;; + haiku*) + LIBS="$LIBS -lnetwork" + ;; + mingw*) + LIBS="$LIBS -lws2_32 -liphlpapi" + ;; + *) + AC_CHECK_LIB(socket, socket, LIBS="$LIBS -lsocket") + ;; esac AC_CHECK_HEADER(sys/socket.h, [ AC_DEFINE(OF_HAVE_SYS_SOCKET_H, 1, [Whether we have sys/socket.h]) @@ -1373,21 +1365,18 @@ ]) AC_CHECK_HEADER(netinet/tcp.h, [ AC_DEFINE(OF_HAVE_NETINET_TCP_H, 1, [Whether we have netinet/tcp.h]) ]) - AC_CHECK_HEADER(netinet/sctp.h, [ - AC_DEFINE(OF_HAVE_SCTP, 1, [Whether we have SCTP]) - AC_DEFINE(OF_HAVE_NETINET_SCTP_H, 1, - [Whether we have netinet/sctp.h]) - AC_SUBST(USE_SRCS_SCTP, '${SRCS_SCTP}') - ]) AC_CHECK_HEADERS([arpa/inet.h netdb.h]) AC_CHECK_HEADER(netipx/ipx.h, [ AC_DEFINE(OF_HAVE_NETIPX_IPX_H, 1, [Whether we have netipx/ipx.h]) ]) + AC_CHECK_HEADER(sys/un.h, [ + AC_DEFINE(OF_HAVE_SYS_UN_H, 1, [Whether we have sys/un.h]) + ]) AC_CHECK_MEMBER([struct sockaddr_in6.sin6_addr], [ AC_EGREP_CPP(egrep_cpp_yes, [ #ifdef _WIN32 typedef int BOOL; @@ -1413,10 +1402,13 @@ #endif ], [ AC_DEFINE(OF_HAVE_IPV6, 1, [Whether we have IPv6]) ]) ], [ + dnl Work around a bug in autoconf 2.61 that creates a broken + dnl configure if this branch is empty. + : ], [ #ifdef _WIN32 typedef int BOOL; #endif @@ -1505,10 +1497,44 @@ ], [ AC_DEFINE(OF_HAVE_IPX, 1, [Whether we have IPX/SPX]) AC_SUBST(USE_SRCS_IPX, '${SRCS_IPX}') ]) ]) + + AC_CHECK_HEADERS(afunix.h, [ + AC_DEFINE(OF_HAVE_AFUNIX_H, 1, [Whether we have afunix.h]) + ], [], [ + #ifdef _WIN32 + # include + #endif + ]) + 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}') + ], [], [ + #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 __morphos__ + # error MorphOS has the struct but does not support it + #endif + + #ifdef __MINT__ + # error Gives invalid argument at runtime + #endif + ]) AC_CHECK_FUNCS(paccept accept4, break) AC_CHECK_FUNCS(kqueue1 kqueue, [ AC_DEFINE(HAVE_KQUEUE, 1, [Whether we have kqueue]) @@ -1535,47 +1561,153 @@ "OFPollKernelEventObserver.m") ]) ]) case "$host_os" in - amigaos* | mingw* | morphos*) + amigaos* | mingw* | morphos*) + AC_DEFINE(HAVE_SELECT, 1, [Whether we have select() or similar]) + AC_SUBST(OF_SELECT_KERNEL_EVENT_OBSERVER_M, + "OFSelectKernelEventObserver.m") + ;; + *) + AC_CHECK_HEADERS(sys/select.h) + AC_CHECK_FUNC(select, [ AC_DEFINE(HAVE_SELECT, 1, [Whether we have select() or similar]) AC_SUBST(OF_SELECT_KERNEL_EVENT_OBSERVER_M, "OFSelectKernelEventObserver.m") + ]) + ;; + esac + + 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"], [ + 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, + "OFSecureTransportTLSStream.m") + + AC_CHECK_FUNCS(SSLCreateContext) + ], []) + + LIBS="$old_LIBS" + ]) + ]) + + AS_IF([test x"$with_tls" = x"openssl" \ + -o \( x"$with_tls" = x"yes" -a x"$tls_support" = x"no" \)], [ + case "$host_os" in + morphos*) + ssl="ssl_shared" + crypto="crypto_shared" ;; *) - AC_CHECK_HEADERS(sys/select.h) - AC_CHECK_FUNC(select, [ - AC_DEFINE(HAVE_SELECT, 1, - [Whether we have select() or similar]) - AC_SUBST(OF_SELECT_KERNEL_EVENT_OBSERVER_M, - "OFSelectKernelEventObserver.m") - ]) + ssl="ssl" + crypto="crypto" ;; - esac + 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, + [Whether we have an implementation for TLS]) + AC_CONFIG_FILES(src/tls/Info.plist) + + 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}") + ]) + AS_IF([test x"$enable_static" = x"yes" \ + -o x"$enable_shared" = x"no"], [ + AC_SUBST(OBJFWTLS_STATIC_LIB, "libobjfwtls.a") + ]) + AS_IF([test x"$build_framework" = x"yes"], [ + AC_SUBST(OBJFWTLS_FRAMEWORK, "ObjFWTLS.framework") + ]) + ]) + + AS_IF([test x"$with_tls" != x"no" -a x"$tls_support" = x"no"], [ + AC_MSG_ERROR(m4_normalize([ + No TLS implementation was found. Please install OpenSSL, + GnuTLS or use --without-tls. + ])) + ]) AS_IF([test x"$enable_threads" != x"no"], [ AC_SUBST(OF_HTTP_CLIENT_TESTS_M, "OFHTTPClientTests.m") ]) AC_SUBST(OFDNS, "ofdns") AS_IF([test x"$enable_files" != x"no"], [ AC_SUBST(OFHTTP, "ofhttp") + AC_SUBST(OFHTTP_LIBS) ]) - AC_SUBST(OFSOCK, "ofsock") ]) AC_DEFUN([CHECK_BUILTIN_BSWAP], [ AC_MSG_CHECKING(for __builtin_bswap$1) - AC_TRY_LINK([ - #include - #include - #include - ], [ - uint$1_t i = errno; - printf("%d", (int)__builtin_bswap$1(i)); + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([ + #include + #include + #include + ], [ + uint$1_t i = errno; + printf("%d", (int)__builtin_bswap$1(i)); + ]) ], [ AC_MSG_RESULT(yes) AC_DEFINE(OF_HAVE_BUILTIN_BSWAP$1, 1, [Whether we have __builtin_bswap$1]) ], [ @@ -1584,49 +1716,66 @@ ]) CHECK_BUILTIN_BSWAP(16) CHECK_BUILTIN_BSWAP(32) CHECK_BUILTIN_BSWAP(64) -case "$host" in - arm*-apple-darwin*) - have_processes="no" - ;; - *-*-mingw*) - have_processes="yes" - ;; - *-*-msdosdjgpp*) - have_processes="no" - ;; - *) - AC_HEADER_SYS_WAIT - AC_CHECK_FUNCS(kill) - - AC_CHECK_FUNCS(posix_spawnp, [ - AS_IF([test x"$ac_cv_func_kill" = x"yes"], [ - have_processes="yes" - - AC_CHECK_HEADERS(spawn.h) - ]) - ], [ - 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" \ - -a x"$ac_cv_func_kill" = x"yes" \ - -a x"$ac_cv_func__exit" = x"yes"], [ - have_processes="yes" - ]) - ], [ - break - ]) - ]) - ;; -esac -AS_IF([test x"$have_processes" = x"yes"], [ - AC_SUBST(OF_PROCESS_M, "OFProcess.m") - AC_DEFINE(OF_HAVE_PROCESSES, 1, [Whether we have processes]) +case "$host_os" in +darwin*) + AC_MSG_CHECKING(whether we are compiling for macOS) + AC_EGREP_CPP(egrep_cpp_yes, [ + #include + + #if (!defined(TARGET_OS_IPHONE) || !TARGET_OS_IPHONE) && \ + (!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" + ]) + ;; +mingw*) + have_subprocesses="yes" + ;; +msdosdjgpp*) + have_subprocesses="no" + ;; +*) + 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_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" \ + -a x"$ac_cv_func_kill" = x"yes" \ + -a x"$ac_cv_func__exit" = x"yes"], [ + have_subprocesses="yes" + ]) + ], [ + 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) @@ -1658,13 +1807,15 @@ dnl which in old glibc versions uses __block. This is worked around in the code dnl by providing a wrapper for unistd.h which takes care of this. AC_MSG_CHECKING(whether Objective C compiler supports blocks) old_OBJCFLAGS="$OBJCFLAGS" OBJCFLAGS="$OBJCFLAGS -Xclang -fblocks" -AC_TRY_COMPILE([], [ - int (^foo)(int bar); - foo = ^ (int bar) { return 0; } +AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([], [ + int (^foo)(int bar); + foo = ^ (int bar) { return 0; } + ]) ], [ OBJFW_OBJCFLAGS="$OBJFW_OBJCFLAGS -Xclang -fblocks" AC_SUBST(OF_BLOCK_TESTS_M, "OFBlockTests.m") AC_MSG_RESULT(yes) ], [ @@ -1674,63 +1825,66 @@ AS_IF([test x"$GOBJC" = x"yes"], [ OBJCFLAGS="$OBJCFLAGS -Wwrite-strings -Wpointer-arith -Werror" AC_MSG_CHECKING(whether we need -Wno-strict-aliasing due to GCC bugs) - AC_TRY_COMPILE([ - #ifdef __has_attribute - # if __has_attribute(objc_root_class) - __attribute__((__objc_root_class__)) - # endif - #endif - @interface Foo - { - struct objc_class *_isa; - } - @end - - static struct { - struct objc_class *_isa; - } object; - ], [ - Foo *test = (Foo *)&object; - (void)test; /* Get rid of unused variable warning */ + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([ + #ifdef __has_attribute + # if __has_attribute(objc_root_class) + __attribute__((__objc_root_class__)) + # endif + #endif + @interface Foo + { + struct objc_class *_isa; + } + @end + + static struct { + struct objc_class *_isa; + } object; + ], [ + Foo *test = (Foo *)&object; + (void)test; /* Get rid of unused variable warning */ + ]) ], [ AC_MSG_RESULT(no) ], [ AC_MSG_RESULT(yes) OBJCFLAGS="$OBJCFLAGS -Wno-strict-aliasing" ]) AC_MSG_CHECKING( whether we need -Wno-unused-property-ivar due to Clang bugs) - AC_TRY_COMPILE([ - #ifdef __has_attribute - # if __has_attribute(objc_root_class) - __attribute__((__objc_root_class__)) - # endif - #endif - @interface Foo - { - struct objc_class *_isa; - Foo *_foo; - } - - @property (readonly, nonatomic) Foo *foo; - - + (Foo *)foo; - @end - - @implementation Foo - @synthesize foo = _foo; - - + (Foo *)foo - { - return (Foo *)0; - } - @end - ], [ + AC_COMPILE_IFELSE([ + AC_LANG_SOURCE([ + #ifdef __has_attribute + # if __has_attribute(objc_root_class) + __attribute__((__objc_root_class__)) + # endif + #endif + @interface Foo + { + struct objc_class *_isa; + Foo *_foo; + } + + @property (readonly, nonatomic) Foo *foo; + + + (Foo *)foo; + @end + + @implementation Foo + @synthesize foo = _foo; + + + (Foo *)foo + { + return (Foo *)0; + } + @end + ]) ], [ AC_MSG_RESULT(no) ], [ AC_MSG_RESULT(yes) OBJCFLAGS="$OBJCFLAGS -Wno-unused-property-ivar" @@ -1737,30 +1891,31 @@ ]) old_OBJCFLAGS="$OBJCFLAGS" OBJCFLAGS="$OBJCFLAGS -Wcast-align" AC_MSG_CHECKING(whether -Wcast-align is buggy) - AC_TRY_COMPILE([ - #ifdef __has_attribute - # if __has_attribute(objc_root_class) - __attribute__((__objc_root_class__)) - # endif - #endif - @interface Foo - { - struct objc_class *_isa; - } - @end - - @implementation Foo - - (void)foo - { - struct objc_class *c = _isa; - (void)c; - } - @end - ], [ + AC_COMPILE_IFELSE([ + AC_LANG_SOURCE([ + #ifdef __has_attribute + # if __has_attribute(objc_root_class) + __attribute__((__objc_root_class__)) + # endif + #endif + @interface Foo + { + struct objc_class *_isa; + } + @end + + @implementation Foo + - (void)foo + { + struct objc_class *c = _isa; + (void)c; + } + @end + ]) ], [ AC_MSG_RESULT(no) ], [ AC_MSG_RESULT(yes) OBJCFLAGS="$old_OBJCFLAGS" @@ -1767,93 +1922,103 @@ ]) old_OBJCFLAGS="$OBJCFLAGS" OBJCFLAGS="$OBJCFLAGS -Wunreachable-code" AC_MSG_CHECKING(whether -Wunreachable-code can be used) - AC_TRY_COMPILE([ - #include - - typedef void *SEL; - - #ifdef __has_attribute - # if __has_attribute(objc_root_class) - __attribute__((__objc_root_class__)) - # endif - #endif - @interface Object - - (void)doesNotRecognizeSelector: (SEL)selector - #ifdef __clang__ - __attribute__((__noreturn__)) - #endif - ; - - (void)dealloc; - @end - - @interface Foo: Object - @end - - void - test(void) - { - if (sizeof(int) == 4) - __asm__ (""); - else if (sizeof(int) == 8) - __asm__ (""); - else - abort(); - } - - /* - * Unfortunately, this cannot be shorter, as it only works when - * it is used inside a macro. - */ - #ifdef __clang__ - # define OF_DEALLOC_UNSUPPORTED \ - [self doesNotRecognizeSelector: _cmd]; \ - \ - abort(); \ - \ - _Pragma("clang diagnostic push ignore \"-Wunreachable-code\""); \ - [super dealloc]; \ - _Pragma("clang diagnostic pop"); - #else - # define OF_DEALLOC_UNSUPPORTED \ - [self doesNotRecognizeSelector: _cmd]; \ - \ - abort(); \ - \ - [super dealloc]; - #endif - - @implementation Foo - - (void)dealloc - { - OF_DEALLOC_UNSUPPORTED - } - @end - ], [], [ + AC_COMPILE_IFELSE([ + AC_LANG_SOURCE([[ + #include + + struct objc_selector; + typedef const struct objc_selector *SEL; + + #ifdef __has_attribute + # if __has_attribute(objc_root_class) + __attribute__((__objc_root_class__)) + # endif + #endif + @interface Object + - (void)doesNotRecognizeSelector: (SEL)selector + #ifdef __clang__ + __attribute__((__noreturn__)) + #endif + ; + - (void)dealloc; + @end + + @interface Foo: Object + @end + + void + test(void) + { + if (sizeof(int) == 4) + __asm__ (""); + else if (sizeof(int) == 8) + __asm__ (""); + else + abort(); + } + + /* + * Unfortunately, this cannot be shorter, as it only + * works when it is used inside a macro. + */ + #ifdef __clang__ + # define OF_DEALLOC_UNSUPPORTED \ + [self doesNotRecognizeSelector: _cmd]; \ + \ + abort(); \ + \ + _Pragma("clang diagnostic push ignore \ + \"-Wunreachable-code\""); \ + [super dealloc]; \ + _Pragma("clang diagnostic pop"); + #else + # define OF_DEALLOC_UNSUPPORTED \ + [self doesNotRecognizeSelector: _cmd]; \ + \ + abort(); \ + \ + [super dealloc]; + #endif + + @implementation Foo + - (void)dealloc + { + OF_DEALLOC_UNSUPPORTED + } + @end + ]]) + ], [ AC_MSG_RESULT(yes) ], [ AC_MSG_RESULT(no) OBJCFLAGS="$old_OBJCFLAGS" ]) old_OBJCFLAGS="$OBJCFLAGS" OBJCFLAGS="$OBJCFLAGS -Wdocumentation" AC_MSG_CHECKING(whether -Wdocumentation works correctly) - AC_TRY_COMPILE([ - /** - * @class Test conftest.m conftest.m - */ - #ifdef __has_attribute - # if __has_attribute(objc_root_class) - __attribute__((__objc_root_class__)) - # endif - #endif - @interface Test - @end - ], [ + AC_COMPILE_IFELSE([ + AC_LANG_SOURCE([ + /** + * @class Test conftest.m conftest.m + */ + #ifdef __has_attribute + # if __has_attribute(objc_root_class) + __attribute__((__objc_root_class__)) + # endif + #endif + @interface Test + @end + + /** + * @struct Foo conftest.m conftest.m + */ + typedef struct {} Foo; + ]) ], [ AC_MSG_RESULT(yes) ], [ AC_MSG_RESULT(no) OBJCFLAGS="$old_OBJCFLAGS" @@ -1861,55 +2026,59 @@ AS_IF([test x"$check_pedantic" = x"yes"], [ old_OBJCFLAGS="$OBJCFLAGS" OBJCFLAGS="$OBJCFLAGS -pedantic" AC_MSG_CHECKING(whether -pedantic is buggy) - AC_TRY_COMPILE([ - #include - - #include - - #ifdef __has_attribute - # if __has_attribute(objc_root_class) - __attribute__((__objc_root_class__)) - # endif - #endif - @interface Foo - { - void *foo; - } - @end - - @interface Bar: Foo - - (void)assert; - @end - - @implementation Bar - - (void)assert - { - /* - * Some versions of glibc break with -pedantic - * when using assert. - */ - assert(1); - } - @end - ], [], [ + AC_COMPILE_IFELSE([ + AC_LANG_SOURCE([ + #include + + #include + + #ifdef __has_attribute + # if __has_attribute(objc_root_class) + __attribute__((__objc_root_class__)) + # endif + #endif + @interface Foo + { + void *foo; + } + @end + + @interface Bar: Foo + - (void)assert; + @end + + @implementation Bar + - (void)assert + { + /* + * Some versions of glibc break with + * -pedantic when using assert. + */ + assert(1); + } + @end + ]) + ], [ AC_MSG_RESULT(no) ], [ AC_MSG_RESULT(yes) OBJCFLAGS="$old_OBJCFLAGS" ]) ]) AS_IF([test x"$ac_cv_header_complex_h" = x"yes"], [ AC_MSG_CHECKING(whether we need -Wno-gnu-imaginary-constant) - AC_TRY_COMPILE([ - #include - ], [ - complex float f = 0.5 + 0.5 * I; - (void)f; + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([ + #include + ], [ + complex float f = 0.5 + 0.5 * I; + (void)f; + ]) ], [ AC_MSG_RESULT(no) ], [ AC_MSG_RESULT(yes) OBJCFLAGS="$OBJCFLAGS -Wno-gnu-imaginary-constant" @@ -1919,20 +2088,19 @@ AS_IF([test x"$cross_compiling" = x"yes"], [ AC_SUBST(BIN_PREFIX, "${host_alias}-") case "$host" in - i?86-*-mingw*) - AC_CHECK_PROG(WINE, wine, wine) - ;; - x86_64-*-mingw*) - AC_CHECK_PROG(WINE, wine64, wine64) - ;; + i?86-*-mingw*) + AC_CHECK_PROG(WINE, wine, wine) + ;; + x86_64-*-mingw*) + AC_CHECK_PROG(WINE, wine64, wine64) + ;; esac AS_IF([test x"$WINE" != x""], [ - AC_SUBST(RUN_TESTS, "run") AC_SUBST(WRAPPER, "$WINE") ]) AS_IF([test x"$with_wii" = x"yes"], [ dnl Keep this lowercase, as WIILOAD is a variable used by @@ -1942,17 +2110,19 @@ AS_IF([test x"$wiiload" != x""], [ AC_SUBST(WRAPPER, "$wiiload") ]) ]) -], [ - AC_SUBST(RUN_TESTS, "run") ]) 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 Index: extra.mk.in ================================================================== --- extra.mk.in +++ extra.mk.in @@ -1,91 +1,88 @@ OBJFW_SHARED_LIB = @OBJFW_SHARED_LIB@ OBJFW_STATIC_LIB = @OBJFW_STATIC_LIB@ OBJFW_FRAMEWORK = @OBJFW_FRAMEWORK@ -OBJFW_LIB_MAJOR = 9 -OBJFW_LIB_MINOR = 1 +OBJFW_LIB_MAJOR = 0 +OBJFW_LIB_MINOR = 0 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 = 1 +OBJFWRT_LIB_MAJOR = 0 OBJFWRT_LIB_MINOR = 0 OBJFWRT_LIB_MAJOR_MINOR = ${OBJFWRT_LIB_MAJOR}.${OBJFWRT_LIB_MINOR} OBJFWBRIDGE_SHARED_LIB = @OBJFWBRIDGE_SHARED_LIB@ OBJFWBRIDGE_STATIC_LIB = @OBJFWBRIDGE_STATIC_LIB@ OBJFWBRIDGE_FRAMEWORK = @OBJFWBRIDGE_FRAMEWORK@ +OBJFWTLS_SHARED_LIB = @OBJFWTLS_SHARED_LIB@ +OBJFWTLS_STATIC_LIB = @OBJFWTLS_STATIC_LIB@ +OBJFWTLS_FRAMEWORK = @OBJFWTLS_FRAMEWORK@ + BIN_PREFIX = @BIN_PREFIX@ BRIDGE = @BRIDGE@ CVINCLUDE_INLINE_H = @CVINCLUDE_INLINE_H@ -ENCODINGS = @ENCODINGS@ ENCODINGS_A = @ENCODINGS_A@ -ENCODINGS_ENCODINGS_A = @ENCODINGS_ENCODINGS_A@ -ENCODINGS_ENCODINGS_LIB_A = @ENCODINGS_ENCODINGS_LIB_A@ ENCODINGS_LIB_A = @ENCODINGS_LIB_A@ ENCODINGS_SRCS = @ENCODINGS_SRCS@ EXCEPTIONS_A = @EXCEPTIONS_A@ -EXCEPTIONS_EXCEPTIONS_A = @EXCEPTIONS_EXCEPTIONS_A@ -EXCEPTIONS_EXCEPTIONS_LIB_A = @EXCEPTIONS_EXCEPTIONS_LIB_A@ EXCEPTIONS_LIB_A = @EXCEPTIONS_LIB_A@ FISH_COMPLETIONS = @FISH_COMPLETIONS@ FORWARDING_A = @FORWARDING_A@ -FORWARDING_FORWARDING_A = @FORWARDING_FORWARDING_A@ -FORWARDING_FORWARDING_LIB_A = @FORWARDING_FORWARDING_LIB_A@ FORWARDING_LIB_A = @FORWARDING_LIB_A@ -INVOCATION_A = @INVOCATION_A@ -INVOCATION_INVOCATION_A = @INVOCATION_INVOCATION_A@ -INVOCATION_INVOCATION_LIB_A = @INVOCATION_INVOCATION_LIB_A@ -INVOCATION_LIB_A = @INVOCATION_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@ -LOOKUP_ASM_LOOKUP_ASM_A = @LOOKUP_ASM_LOOKUP_ASM_A@ -LOOKUP_ASM_LOOKUP_ASM_LIB_A = @LOOKUP_ASM_LOOKUP_ASM_LIB_A@ MAP_LDFLAGS = @MAP_LDFLAGS@ +OBJC_SYNC = @OBJC_SYNC@ OFARC = @OFARC@ OFDNS = @OFDNS@ OFHASH = @OFHASH@ OFHTTP = @OFHTTP@ -OFSOCK = @OFSOCK@ +OFHTTP_LIBS = @OFHTTP_LIBS@ OF_BLOCK_TESTS_M = @OF_BLOCK_TESTS_M@ OF_EPOLL_KERNEL_EVENT_OBSERVER_M = @OF_EPOLL_KERNEL_EVENT_OBSERVER_M@ +OF_GNUTLS_TLS_STREAM_M = @OF_GNUTLS_TLS_STREAM_M@ OF_HTTP_CLIENT_TESTS_M = @OF_HTTP_CLIENT_TESTS_M@ OF_KQUEUE_KERNEL_EVENT_OBSERVER_M = @OF_KQUEUE_KERNEL_EVENT_OBSERVER_M@ +OF_OPENSSL_TLS_STREAM_M = @OF_OPENSSL_TLS_STREAM_M@ OF_POLL_KERNEL_EVENT_OBSERVER_M = @OF_POLL_KERNEL_EVENT_OBSERVER_M@ -OF_PROCESS_M = @OF_PROCESS_M@ -OF_SCTP_SOCKET_M = @OF_SCTP_SOCKET_M@ +OF_SECURE_TRANSPORT_TLS_STREAM_M = @OF_SECURE_TRANSPORT_TLS_STREAM_M@ OF_SELECT_KERNEL_EVENT_OBSERVER_M = @OF_SELECT_KERNEL_EVENT_OBSERVER_M@ +OF_SUBPROCESS_M = @OF_SUBPROCESS_M@ REEXPORT_RUNTIME = @REEXPORT_RUNTIME@ REEXPORT_RUNTIME_FRAMEWORK = @REEXPORT_RUNTIME_FRAMEWORK@ RUNTIME = @RUNTIME@ RUNTIME_ARC_TESTS_M = @RUNTIME_ARC_TESTS_M@ RUNTIME_AUTORELEASE_M = @RUNTIME_AUTORELEASE_M@ RUNTIME_FRAMEWORK_LIBS = @RUNTIME_FRAMEWORK_LIBS@ RUNTIME_INSTANCE_M = @RUNTIME_INSTANCE_M@ RUNTIME_LIBS = @RUNTIME_LIBS@ -RUN_TESTS = @RUN_TESTS@ SFDC_INLINE_H = @SFDC_INLINE_H@ SFDC_TARGET = @SFDC_TARGET@ SFD_FILE = @SFD_FILE@ TESTPLUGIN = @TESTPLUGIN@ TESTPLUGIN_LIBS = @TESTPLUGIN_LIBS@ TESTS_LIBS = @TESTS_LIBS@ TESTS_STATIC_LIB = @TESTS_STATIC_LIB@ +TLS = @TLS@ +TLS_CPPFLAGS = @TLS_CPPFLAGS@ +TLS_LIBS = @TLS_LIBS@ UNICODE_M = @UNICODE_M@ USE_INCLUDES_ATOMIC = @USE_INCLUDES_ATOMIC@ USE_SRCS_FILES = @USE_SRCS_FILES@ USE_SRCS_IPX = @USE_SRCS_IPX@ USE_SRCS_PLUGINS = @USE_SRCS_PLUGINS@ -USE_SRCS_SCTP = @USE_SRCS_SCTP@ 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/Makefile Index: generators/Makefile ================================================================== --- generators/Makefile +++ /dev/null @@ -1,67 +0,0 @@ -include ../extra.mk - -PROG_NOINST = gen_tables${PROG_SUFFIX} -SRCS = TableGenerator.m - -.PHONY: run -run: all - rm -f libobjfw.so.${OBJFW_LIB_MAJOR} - rm -f libobjfw.so.${OBJFW_LIB_MAJOR_MINOR} - rm -f objfw.dll libobjfw.${OBJFW_LIB_MAJOR}.dylib - rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR} - rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR} - rm -f objfwrt.dll 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.dll; then \ - ${LN_S} ../src/objfw.dll objfw.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.dll; then \ - ${LN_S} ../src/runtime/objfwrt.dll objfwrt.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 objfw.so.${OBJFW_LIB_MAJOR_MINOR} objfw.dll; \ - rm -f libobjfw.${OBJFW_LIB_MAJOR}.dylib; \ - rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR}; \ - rm -f objfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR} objfwrt.dll; \ - rm -f libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib; \ - exit $$EXIT - -include ../buildsys.mk - -CPPFLAGS += -I../src -I../src/exceptions -I../src/runtime -I.. -LIBS := -L../src -lobjfw -L../src/runtime ${RUNTIME_LIBS} ${LIBS} -LD = ${OBJC} DELETED generators/TableGenerator.h Index: generators/TableGenerator.h ================================================================== --- generators/TableGenerator.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "OFHTTPClient.h" - -@class OFString; - -@interface TableGenerator: OFObject -{ - OFHTTPClient *_HTTPClient; - of_unichar_t _uppercaseTable[0x110000]; - of_unichar_t _lowercaseTable[0x110000]; - of_unichar_t _titlecaseTable[0x110000]; - of_unichar_t _casefoldingTable[0x110000]; - OFString *_decompositionTable[0x110000]; - OFString *_decompositionCompatTable[0x110000]; - char _uppercaseTableUsed[0x1100]; - char _lowercaseTableUsed[0x1100]; - char _titlecaseTableUsed[0x1100]; - char _casefoldingTableUsed[0x1100]; - char _decompositionTableUsed[0x1100]; - char _decompositionCompatTableUsed[0x1100]; - size_t _uppercaseTableSize; - size_t _lowercaseTableSize; - size_t _titlecaseTableSize; - size_t _casefoldingTableSize; - size_t _decompositionTableSize; - size_t _decompositionCompatTableSize; - enum { - STATE_UNICODE_DATA, - STATE_CASE_FOLDING - } _state; -} - -- (void)parseUnicodeData: (OFHTTPResponse *)response; -- (void)parseCaseFolding: (OFHTTPResponse *)response; -- (void)applyDecompositionRecursivelyForTable: (OFString *[0x110000])table; -- (void)writeFiles; -- (void)writeTablesToFile: (OFString *)path; -- (void)writeHeaderToFile: (OFString *)path; -@end DELETED generators/TableGenerator.m Index: generators/TableGenerator.m ================================================================== --- generators/TableGenerator.m +++ /dev/null @@ -1,776 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "OFString.h" -#import "OFArray.h" -#import "OFApplication.h" -#import "OFURL.h" -#import "OFHTTPRequest.h" -#import "OFHTTPResponse.h" -#import "OFHTTPClient.h" -#import "OFFile.h" -#import "OFStdIOStream.h" - -#import "OFOutOfRangeException.h" - -#import "TableGenerator.h" -#import "copyright.h" - -#define UNICODE_DATA_URL \ - @"http://www.unicode.org/Public/UNIDATA/UnicodeData.txt" -#define CASE_FOLDING_URL \ - @"http://www.unicode.org/Public/UNIDATA/CaseFolding.txt" - -OF_APPLICATION_DELEGATE(TableGenerator) - -@implementation TableGenerator -- (instancetype)init -{ - self = [super init]; - - @try { - _HTTPClient = [[OFHTTPClient alloc] init]; - _HTTPClient.delegate = self; - - _uppercaseTableSize = SIZE_MAX; - _lowercaseTableSize = SIZE_MAX; - _titlecaseTableSize = SIZE_MAX; - _casefoldingTableSize = SIZE_MAX; - _decompositionTableSize = SIZE_MAX; - _decompositionCompatTableSize = SIZE_MAX; - } @catch (id e) { - @throw e; - [self release]; - } - - return self; -} - -- (void)applicationDidFinishLaunching -{ - OFHTTPRequest *request; - - [of_stdout writeString: @"Downloading UnicodeData.txt…"]; - _state = STATE_UNICODE_DATA; - request = [OFHTTPRequest requestWithURL: - [OFURL URLWithString: UNICODE_DATA_URL]]; - [_HTTPClient asyncPerformRequest: request]; -} - -- (void)client: (OFHTTPClient *)client - didPerformRequest: (OFHTTPRequest *)request - response: (OFHTTPResponse *)response - exception: (id)exception -{ - if (exception != nil) - @throw exception; - - [of_stdout writeLine: @" done"]; - - switch (_state) { - case STATE_UNICODE_DATA: - [self parseUnicodeData: response]; - break; - case STATE_CASE_FOLDING: - [self parseCaseFolding: response]; - break; - } -} - -- (void)parseUnicodeData: (OFHTTPResponse *)response -{ - OFString *line; - OFHTTPRequest *request; - - [of_stdout writeString: @"Parsing UnicodeData.txt…"]; - - while ((line = [response readLine]) != nil) { - void *pool2; - OFArray OF_GENERIC(OFString *) *components; - of_unichar_t codePoint; - - if (line.length == 0) - continue; - - pool2 = objc_autoreleasePoolPush(); - - components = [line componentsSeparatedByString: @";"]; - if (components.count != 15) { - of_log(@"Invalid line: %@\n", line); - [OFApplication terminateWithStatus: 1]; - } - - codePoint = (of_unichar_t)[[components objectAtIndex: 0] - unsignedLongLongValueWithBase: 16]; - - if (codePoint > 0x10FFFF) - @throw [OFOutOfRangeException exception]; - - _uppercaseTable[codePoint] = (of_unichar_t)[[components - objectAtIndex: 12] unsignedLongLongValueWithBase: 16]; - _lowercaseTable[codePoint] = (of_unichar_t)[[components - objectAtIndex: 13] unsignedLongLongValueWithBase: 16]; - _titlecaseTable[codePoint] = (of_unichar_t)[[components - objectAtIndex: 14] unsignedLongLongValueWithBase: 16]; - - if ([[components objectAtIndex: 5] length] > 0) { - OFArray *decomposed = [[components objectAtIndex: 5] - componentsSeparatedByString: @" "]; - bool compat = false; - OFMutableString *string; - - if ([decomposed.firstObject hasPrefix: @"<"]) { - decomposed = [decomposed objectsInRange: - of_range(1, decomposed.count - 1)]; - compat = true; - } - - string = [OFMutableString string]; - - for (OFString *character in decomposed) { - of_unichar_t unichar = (of_unichar_t)[character - unsignedLongLongValueWithBase: 16]; - - [string appendCharacters: &unichar - length: 1]; - } - - [string makeImmutable]; - - if (!compat) - _decompositionTable[codePoint] = [string copy]; - _decompositionCompatTable[codePoint] = [string copy]; - } - - objc_autoreleasePoolPop(pool2); - } - - [self applyDecompositionRecursivelyForTable: _decompositionTable]; - [self applyDecompositionRecursivelyForTable: _decompositionCompatTable]; - - [of_stdout writeLine: @" done"]; - - [of_stdout writeString: @"Downloading CaseFolding.txt…"]; - _state = STATE_CASE_FOLDING; - request = [OFHTTPRequest requestWithURL: - [OFURL URLWithString: CASE_FOLDING_URL]]; - [_HTTPClient asyncPerformRequest: request]; -} - -- (void)parseCaseFolding: (OFHTTPResponse *)response -{ - OFString *line; - - [of_stdout writeString: @"Parsing CaseFolding.txt…"]; - - while ((line = [response readLine]) != nil) { - void *pool2; - OFArray OF_GENERIC(OFString *) *components; - of_unichar_t codePoint; - - if (line.length == 0 || [line hasPrefix: @"#"]) - continue; - - pool2 = objc_autoreleasePoolPush(); - - components = [line componentsSeparatedByString: @"; "]; - if (components.count != 4) { - of_log(@"Invalid line: %s\n", line); - [OFApplication terminateWithStatus: 1]; - } - - if (![[components objectAtIndex: 1] isEqual: @"S"] && - ![[components objectAtIndex: 1] isEqual: @"C"]) - continue; - - codePoint = (of_unichar_t)[[components objectAtIndex: 0] - unsignedLongLongValueWithBase: 16]; - - if (codePoint > 0x10FFFF) - @throw [OFOutOfRangeException exception]; - - _casefoldingTable[codePoint] = (of_unichar_t)[[components - objectAtIndex: 2] unsignedLongLongValueWithBase: 16]; - - objc_autoreleasePoolPop(pool2); - } - - [of_stdout writeLine: @" done"]; - - [self writeFiles]; -} - -- (void)applyDecompositionRecursivelyForTable: (OFString *[0x110000])table -{ - bool done; - - do { - done = true; - - for (of_unichar_t i = 0; i < 0x110000; i++) { - void *pool; - const of_unichar_t *characters; - size_t length; - OFMutableString *replacement; - bool changed = false; - - if (table[i] == nil) - continue; - - pool = objc_autoreleasePoolPush(); - characters = table[i].characters; - length = table[i].length; - replacement = [OFMutableString string]; - - for (size_t j = 0; j < length; j++) { - if (characters[j] > 0x10FFFF) - @throw [OFOutOfRangeException - exception]; - - if (table[characters[j]] == nil) - [replacement - appendCharacters: &characters[j] - length: 1]; - else { - [replacement - appendString: table[characters[j]]]; - changed = true; - } - } - - [replacement makeImmutable]; - - if (changed) { - [table[i] release]; - table[i] = [replacement copy]; - - done = false; - } - - objc_autoreleasePoolPop(pool); - } - } while (!done); -} - -- (void)writeFiles -{ - OFURL *URL; - - [of_stdout writeString: @"Writing files…"]; - - URL = [OFURL fileURLWithPath: @"../src/unicode.m"]; - [self writeTablesToFile: URL.fileSystemRepresentation]; - - URL = [OFURL fileURLWithPath: @"../src/unicode.h"]; - [self writeHeaderToFile: URL.fileSystemRepresentation]; - - [of_stdout writeLine: @" done"]; - - [OFApplication terminate]; -} - -- (void)writeTablesToFile: (OFString *)path -{ - void *pool = objc_autoreleasePoolPush(); - OFFile *file = [OFFile fileWithPath: path - mode: @"w"]; - - [file writeString: COPYRIGHT - @"#include \"config.h\"\n" - @"\n" - @"#import \"OFString.h\"\n\n" - @"static const of_unichar_t emptyPage[0x100] = { 0 };\n" - @"static const char *emptyDecompositionPage[0x100] = { NULL };\n" - @"\n"]; - - /* Write uppercasePage%u */ - for (of_unichar_t i = 0; i < 0x110000; i += 0x100) { - bool isEmpty = true; - - for (of_unichar_t j = i; j < i + 0x100; j++) { - if (_uppercaseTable[j] != 0) { - isEmpty = false; - _uppercaseTableSize = i >> 8; - _uppercaseTableUsed[_uppercaseTableSize] = 1; - break; - } - } - - if (!isEmpty) { - void *pool2 = objc_autoreleasePoolPush(); - - [file writeFormat: @"static const of_unichar_t " - @"uppercasePage%u[0x100] = {\n", - i >> 8]; - - for (of_unichar_t j = i; j < i + 0x100; j += 8) - [file writeFormat: - @"\t%u, %u, %u, %u, %u, %u, %u, %u,\n", - _uppercaseTable[j], - _uppercaseTable[j + 1], - _uppercaseTable[j + 2], - _uppercaseTable[j + 3], - _uppercaseTable[j + 4], - _uppercaseTable[j + 5], - _uppercaseTable[j + 6], - _uppercaseTable[j + 7]]; - - [file writeString: @"};\n\n"]; - - objc_autoreleasePoolPop(pool2); - } - } - - /* Write lowercasePage%u */ - for (of_unichar_t i = 0; i < 0x110000; i += 0x100) { - bool isEmpty = true; - - for (of_unichar_t j = i; j < i + 0x100; j++) { - if (_lowercaseTable[j] != 0) { - isEmpty = false; - _lowercaseTableSize = i >> 8; - _lowercaseTableUsed[_lowercaseTableSize] = 1; - break; - } - } - - if (!isEmpty) { - void *pool2 = objc_autoreleasePoolPush(); - - [file writeFormat: @"static const of_unichar_t " - @"lowercasePage%u[0x100] = {\n", - i >> 8]; - - for (of_unichar_t j = i; j < i + 0x100; j += 8) - [file writeFormat: - @"\t%u, %u, %u, %u, %u, %u, %u, %u,\n", - _lowercaseTable[j], - _lowercaseTable[j + 1], - _lowercaseTable[j + 2], - _lowercaseTable[j + 3], - _lowercaseTable[j + 4], - _lowercaseTable[j + 5], - _lowercaseTable[j + 6], - _lowercaseTable[j + 7]]; - - [file writeString: @"};\n\n"]; - - objc_autoreleasePoolPop(pool2); - } - } - - /* Write titlecasePage%u if it does NOT match uppercasePage%u */ - for (of_unichar_t i = 0; i < 0x110000; i += 0x100) { - bool isEmpty = true; - - for (of_unichar_t j = i; j < i + 0x100; j++) { - if (_titlecaseTable[j] != 0) { - isEmpty = !memcmp(_uppercaseTable + i, - _titlecaseTable + i, - 256 * sizeof(of_unichar_t)); - _titlecaseTableSize = i >> 8; - _titlecaseTableUsed[_titlecaseTableSize] = - (isEmpty ? 2 : 1); - break; - } - } - - if (!isEmpty) { - void *pool2 = objc_autoreleasePoolPush(); - - [file writeFormat: @"static const of_unichar_t " - @"titlecasePage%u[0x100] = {\n", - i >> 8]; - - for (of_unichar_t j = i; j < i + 0x100; j += 8) - [file writeFormat: - @"\t%u, %u, %u, %u, %u, %u, %u, %u,\n", - _titlecaseTable[j], - _titlecaseTable[j + 1], - _titlecaseTable[j + 2], - _titlecaseTable[j + 3], - _titlecaseTable[j + 4], - _titlecaseTable[j + 5], - _titlecaseTable[j + 6], - _titlecaseTable[j + 7]]; - - [file writeString: @"};\n\n"]; - - objc_autoreleasePoolPop(pool2); - } - } - - /* Write casefoldingPage%u if it does NOT match lowercasePage%u */ - for (of_unichar_t i = 0; i < 0x110000; i += 0x100) { - bool isEmpty = true; - - for (of_unichar_t j = i; j < i + 0x100; j++) { - if (_casefoldingTable[j] != 0) { - isEmpty = !memcmp(_lowercaseTable + i, - _casefoldingTable + i, - 256 * sizeof(of_unichar_t)); - _casefoldingTableSize = i >> 8; - _casefoldingTableUsed[_casefoldingTableSize] = - (isEmpty ? 2 : 1); - break; - } - } - - if (!isEmpty) { - void *pool2 = objc_autoreleasePoolPush(); - - [file writeFormat: @"static const of_unichar_t " - @"casefoldingPage%u[0x100] = {\n", - i >> 8]; - - for (of_unichar_t j = i; j < i + 0x100; j += 8) - [file writeFormat: - @"\t%u, %u, %u, %u, %u, %u, %u, %u,\n", - _casefoldingTable[j], - _casefoldingTable[j + 1], - _casefoldingTable[j + 2], - _casefoldingTable[j + 3], - _casefoldingTable[j + 4], - _casefoldingTable[j + 5], - _casefoldingTable[j + 6], - _casefoldingTable[j + 7]]; - - [file writeString: @"};\n\n"]; - - objc_autoreleasePoolPop(pool2); - } - } - - /* Write decompositionPage%u */ - for (of_unichar_t i = 0; i < 0x110000; i += 0x100) { - bool isEmpty = true; - - for (of_unichar_t j = i; j < i + 0x100; j++) { - if (_decompositionTable[j] != nil) { - isEmpty = false; - _decompositionTableSize = i >> 8; - _decompositionTableUsed[ - _decompositionTableSize] = 1; - break; - } - } - - if (!isEmpty) { - void *pool2 = objc_autoreleasePoolPush(); - - [file writeFormat: @"static const char *const " - @"decompositionPage%u[0x100] = {\n", - i >> 8]; - - for (of_unichar_t j = i; j < i + 0x100; j++) { - if ((j - i) % 2 == 0) - [file writeString: @"\t"]; - else - [file writeString: @" "]; - - if (_decompositionTable[j] != nil) { - const char *UTF8String = - _decompositionTable[j].UTF8String; - size_t length = _decompositionTable[j] - .UTF8StringLength; - - [file writeString: @"\""]; - - for (size_t k = 0; k < length; k++) - [file writeFormat: - @"\\x%02X", - (uint8_t)UTF8String[k]]; - - [file writeString: @"\","]; - } else - [file writeString: @"NULL,"]; - - if ((j - i) % 2 == 1) - [file writeString: @"\n"]; - } - - [file writeString: @"};\n\n"]; - - objc_autoreleasePoolPop(pool2); - } - } - - /* Write decompCompatPage%u if it does NOT match decompositionPage%u */ - for (of_unichar_t i = 0; i < 0x110000; i += 0x100) { - bool isEmpty = true; - - for (of_unichar_t j = i; j < i + 0x100; j++) { - if (_decompositionCompatTable[j] != 0) { - /* - * We bulk-compare pointers via memcmp here. - * This is safe, as we always set the same - * pointer in both tables if both are the same. - */ - isEmpty = !memcmp(_decompositionTable + i, - _decompositionCompatTable + i, - 256 * sizeof(const char *)); - _decompositionCompatTableSize = i >> 8; - _decompositionCompatTableUsed[ - _decompositionCompatTableSize] = - (isEmpty ? 2 : 1); - - break; - } - } - - if (!isEmpty) { - void *pool2 = objc_autoreleasePoolPush(); - - [file writeFormat: @"static const char *const " - @"decompCompatPage%u[0x100] = {\n", - i >> 8]; - - for (of_unichar_t j = i; j < i + 0x100; j++) { - if ((j - i) % 2 == 0) - [file writeString: @"\t"]; - else - [file writeString: @" "]; - - if (_decompositionCompatTable[j] != nil) { - const char *UTF8String = - _decompositionCompatTable[j] - .UTF8String; - size_t length = - _decompositionCompatTable[j] - .UTF8StringLength; - - [file writeString: @"\""]; - - for (size_t k = 0; k < length; k++) - [file writeFormat: - @"\\x%02X", - (uint8_t)UTF8String[k]]; - - [file writeString: @"\","]; - } else - [file writeString: @"NULL,"]; - - if ((j - i) % 2 == 1) - [file writeString: @"\n"]; - } - - [file writeString: @"};\n\n"]; - - objc_autoreleasePoolPop(pool2); - } - } - - /* - * Those are currently set to the last index. - * But from now on, we need the size. - */ - _uppercaseTableSize++; - _lowercaseTableSize++; - _titlecaseTableSize++; - _casefoldingTableSize++; - _decompositionTableSize++; - _decompositionCompatTableSize++; - - /* Write of_unicode_uppercase_table */ - [file writeFormat: @"const of_unichar_t *const " - @"of_unicode_uppercase_table[0x%X] = {\n\t", - _uppercaseTableSize]; - - for (of_unichar_t i = 0; i < _uppercaseTableSize; i++) { - if (_uppercaseTableUsed[i]) - [file writeFormat: @"uppercasePage%u", i]; - else - [file writeString: @"emptyPage"]; - - if (i + 1 < _uppercaseTableSize) { - if ((i + 1) % 4 == 0) - [file writeString: @",\n\t"]; - else - [file writeString: @", "]; - } - } - - [file writeString: @"\n};\n\n"]; - - /* Write of_unicode_lowercase_table */ - [file writeFormat: @"const of_unichar_t *const " - @"of_unicode_lowercase_table[0x%X] = {\n\t", - _lowercaseTableSize]; - - for (of_unichar_t i = 0; i < _lowercaseTableSize; i++) { - if (_lowercaseTableUsed[i]) - [file writeFormat: @"lowercasePage%u", i]; - else - [file writeString: @"emptyPage"]; - - if (i + 1 < _lowercaseTableSize) { - if ((i + 1) % 4 == 0) - [file writeString: @",\n\t"]; - else - [file writeString: @", "]; - } - } - - [file writeString: @"\n};\n\n"]; - - /* Write of_unicode_titlecase_table */ - [file writeFormat: @"const of_unichar_t *const " - @"of_unicode_titlecase_table[0x%X] = {\n\t", - _titlecaseTableSize]; - - for (of_unichar_t i = 0; i < _titlecaseTableSize; i++) { - if (_titlecaseTableUsed[i] == 1) - [file writeFormat: @"titlecasePage%u", i]; - else if (_titlecaseTableUsed[i] == 2) - [file writeFormat: @"uppercasePage%u", i]; - else - [file writeString: @"emptyPage"]; - - if (i + 1 < _titlecaseTableSize) { - if ((i + 1) % 4 == 0) - [file writeString: @",\n\t"]; - else - [file writeString: @", "]; - } - } - - [file writeString: @"\n};\n\n"]; - - /* Write of_unicode_casefolding_table */ - [file writeFormat: @"const of_unichar_t *const " - @"of_unicode_casefolding_table[0x%X] = {\n\t", - _casefoldingTableSize]; - - for (of_unichar_t i = 0; i < _casefoldingTableSize; i++) { - if (_casefoldingTableUsed[i] == 1) - [file writeFormat: @"casefoldingPage%u", i]; - else if (_casefoldingTableUsed[i] == 2) - [file writeFormat: @"lowercasePage%u", i]; - else - [file writeString: @"emptyPage"]; - - if (i + 1 < _casefoldingTableSize) { - if ((i + 1) % 3 == 0) - [file writeString: @",\n\t"]; - else - [file writeString: @", "]; - } - } - - [file writeString: @"\n};\n\n"]; - - /* Write of_unicode_decomposition_table */ - [file writeFormat: @"const char *const " - @"*of_unicode_decomposition_table[0x%X] = {\n\t", - _decompositionTableSize]; - - for (of_unichar_t i = 0; i < _decompositionTableSize; i++) { - if (_decompositionTableUsed[i]) - [file writeFormat: @"decompositionPage%u", i]; - else - [file writeString: @"emptyDecompositionPage"]; - - if (i + 1 < _decompositionTableSize) { - if ((i + 1) % 3 == 0) - [file writeString: @",\n\t"]; - else - [file writeString: @", "]; - } - } - - [file writeString: @"\n};\n\n"]; - - /* Write of_unicode_decomposition_compat_table */ - [file writeFormat: @"const char *const " - @"*of_unicode_decomposition_compat_table[0x%X] = {" - @"\n\t", - _decompositionCompatTableSize]; - - for (of_unichar_t i = 0; i < _decompositionCompatTableSize; i++) { - if (_decompositionCompatTableUsed[i] == 1) - [file writeFormat: @"decompCompatPage%u", i]; - else if (_decompositionCompatTableUsed[i] == 2) - [file writeFormat: @"decompositionPage%u", i]; - else - [file writeString: @"emptyDecompositionPage"]; - - if (i + 1 < _decompositionCompatTableSize) { - if ((i + 1) % 3 == 0) - [file writeString: @",\n\t"]; - else - [file writeString: @", "]; - } - } - - [file writeString: @"\n};\n"]; - - objc_autoreleasePoolPop(pool); -} - -- (void)writeHeaderToFile: (OFString *)path -{ - void *pool = objc_autoreleasePoolPush(); - OFFile *file = [OFFile fileWithPath: path - mode: @"w"]; - - [file writeString: COPYRIGHT - @"#import \"OFString.h\"\n\n"]; - - [file writeFormat: - @"#define OF_UNICODE_UPPERCASE_TABLE_SIZE 0x%X\n" - @"#define OF_UNICODE_LOWERCASE_TABLE_SIZE 0x%X\n" - @"#define OF_UNICODE_TITLECASE_TABLE_SIZE 0x%X\n" - @"#define OF_UNICODE_CASEFOLDING_TABLE_SIZE 0x%X\n" - @"#define OF_UNICODE_DECOMPOSITION_TABLE_SIZE 0x%X\n" - @"#define OF_UNICODE_DECOMPOSITION_COMPAT_TABLE_SIZE 0x%X\n\n", - _uppercaseTableSize, _lowercaseTableSize, _titlecaseTableSize, - _casefoldingTableSize, _decompositionTableSize, - _decompositionCompatTableSize]; - - [file writeString: - @"#ifdef __cplusplus\n" - @"extern \"C\" {\n" - @"#endif\n" - @"extern const of_unichar_t *const _Nonnull\n" - @" of_unicode_uppercase_table[" - @"OF_UNICODE_UPPERCASE_TABLE_SIZE];\n" - @"extern const of_unichar_t *const _Nonnull\n" - @" of_unicode_lowercase_table[" - @"OF_UNICODE_LOWERCASE_TABLE_SIZE];\n" - @"extern const of_unichar_t *const _Nonnull\n" - @" of_unicode_titlecase_table[" - @"OF_UNICODE_TITLECASE_TABLE_SIZE];\n" - @"extern const of_unichar_t *const _Nonnull\n" - @" of_unicode_casefolding_table[" - @"OF_UNICODE_CASEFOLDING_TABLE_SIZE];\n" - @"extern const char *const _Nullable *const _Nonnull\n" - @" of_unicode_decomposition_table[" - @"OF_UNICODE_DECOMPOSITION_TABLE_SIZE];\n" - @"extern const char *const _Nullable *const _Nonnull\n" - @" of_unicode_decomposition_compat_table[" - @"OF_UNICODE_DECOMPOSITION_COMPAT_TABLE_SIZE];\n" - @"#ifdef __cplusplus\n" - @"}\n" - @"#endif\n"]; - - objc_autoreleasePoolPop(pool); -} -@end DELETED generators/copyright.h Index: generators/copyright.h ================================================================== --- generators/copyright.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, " \ - @"2017,\n" \ - @" * 2018, 2019, 2020\n" \ - @" * 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" ADDED generators/library/FuncArrayGenerator.h Index: generators/library/FuncArrayGenerator.h ================================================================== --- /dev/null +++ generators/library/FuncArrayGenerator.h @@ -0,0 +1,30 @@ +/* + * 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 ADDED generators/library/FuncArrayGenerator.m Index: generators/library/FuncArrayGenerator.m ================================================================== --- /dev/null +++ generators/library/FuncArrayGenerator.m @@ -0,0 +1,78 @@ +/* + * 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 ADDED generators/library/GlueGenerator.h Index: generators/library/GlueGenerator.h ================================================================== --- /dev/null +++ generators/library/GlueGenerator.h @@ -0,0 +1,31 @@ +/* + * 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 ADDED generators/library/GlueGenerator.m Index: generators/library/GlueGenerator.m ================================================================== --- /dev/null +++ generators/library/GlueGenerator.m @@ -0,0 +1,207 @@ +/* + * 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 ADDED generators/library/LibraryGenerator.m Index: generators/library/LibraryGenerator.m ================================================================== --- /dev/null +++ generators/library/LibraryGenerator.m @@ -0,0 +1,81 @@ +/* + * 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 "OFURL.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 +{ + OFURL *sourcesURL = [[OFFileManager defaultManager].currentDirectoryURL + URLByAppendingPathComponent: @"../../src"]; + OFURL *runtimeLibraryURL = [sourcesURL + URLByAppendingPathComponent: @"runtime/amiga-library.xml"]; + OFURL *runtimeLinkLibURL = [sourcesURL + URLByAppendingPathComponent: @"runtime/linklib/linklib.m"]; + OFURL *runtimeGlueHeaderURL = [sourcesURL + URLByAppendingPathComponent: @"runtime/amiga-glue.h"]; + OFURL *runtimeGlueURL = [sourcesURL + URLByAppendingPathComponent: @"runtime/amiga-glue.m"]; + OFURL *runtimeFuncArrayURL = [sourcesURL + URLByAppendingPathComponent: @"runtime/amiga-funcarray.inc"]; + OFXMLElement *runtimeLibrary = [OFXMLElement elementWithStream: + [OFFile fileWithPath: runtimeLibraryURL.fileSystemRepresentation + mode: @"r"]]; + OFFile *runtimeLinkLib = + [OFFile fileWithPath: runtimeLinkLibURL.fileSystemRepresentation + mode: @"w"]; + OFFile *runtimeGlueHeader = + [OFFile fileWithPath: runtimeGlueHeaderURL.fileSystemRepresentation + mode: @"w"]; + OFFile *runtimeGlue = + [OFFile fileWithPath: runtimeGlueURL.fileSystemRepresentation + mode: @"w"]; + OFFile *runtimeFuncArray = + [OFFile fileWithPath: runtimeFuncArrayURL.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 ADDED generators/library/LinkLibGenerator.h Index: generators/library/LinkLibGenerator.h ================================================================== --- /dev/null +++ generators/library/LinkLibGenerator.h @@ -0,0 +1,29 @@ +/* + * 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 ADDED generators/library/LinkLibGenerator.m Index: generators/library/LinkLibGenerator.m ================================================================== --- /dev/null +++ generators/library/LinkLibGenerator.m @@ -0,0 +1,226 @@ +/* + * 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 ADDED generators/library/Makefile Index: generators/library/Makefile ================================================================== --- /dev/null +++ generators/library/Makefile @@ -0,0 +1,75 @@ +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} ADDED generators/library/copyright.h Index: generators/library/copyright.h ================================================================== --- /dev/null +++ generators/library/copyright.h @@ -0,0 +1,38 @@ +/* + * 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" ADDED generators/unicode/Makefile Index: generators/unicode/Makefile ================================================================== --- /dev/null +++ generators/unicode/Makefile @@ -0,0 +1,72 @@ +include ../../extra.mk + +PROG_NOINST = gen_tables${PROG_SUFFIX} +SRCS = TableGenerator.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} ADDED generators/unicode/TableGenerator.h Index: generators/unicode/TableGenerator.h ================================================================== --- /dev/null +++ generators/unicode/TableGenerator.h @@ -0,0 +1,55 @@ +/* + * 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 "OFHTTPClient.h" + +@class OFString; + +@interface TableGenerator: OFObject +{ + OFHTTPClient *_HTTPClient; + OFUnichar _uppercaseTable[0x110000]; + OFUnichar _lowercaseTable[0x110000]; + OFUnichar _titlecaseTable[0x110000]; + OFUnichar _caseFoldingTable[0x110000]; + OFString *_decompositionTable[0x110000]; + OFString *_decompositionCompatTable[0x110000]; + char _uppercaseTableUsed[0x1100]; + char _lowercaseTableUsed[0x1100]; + char _titlecaseTableUsed[0x1100]; + char _caseFoldingTableUsed[0x1100]; + char _decompositionTableUsed[0x1100]; + char _decompositionCompatTableUsed[0x1100]; + size_t _uppercaseTableSize; + size_t _lowercaseTableSize; + size_t _titlecaseTableSize; + size_t _caseFoldingTableSize; + size_t _decompositionTableSize; + size_t _decompositionCompatTableSize; + enum { + stateUnicodeData, + stateCaseFolding + } _state; +} + +- (void)parseUnicodeData: (OFHTTPResponse *)response; +- (void)parseCaseFolding: (OFHTTPResponse *)response; +- (void)applyDecompositionRecursivelyForTable: (OFString *[0x110000])table; +- (void)writeFiles; +- (void)writeTablesToFile: (OFString *)path; +- (void)writeHeaderToFile: (OFString *)path; +@end ADDED generators/unicode/TableGenerator.m Index: generators/unicode/TableGenerator.m ================================================================== --- /dev/null +++ generators/unicode/TableGenerator.m @@ -0,0 +1,770 @@ +/* + * 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 "OFString.h" +#import "OFArray.h" +#import "OFApplication.h" +#import "OFURL.h" +#import "OFHTTPRequest.h" +#import "OFHTTPResponse.h" +#import "OFHTTPClient.h" +#import "OFFile.h" +#import "OFStdIOStream.h" + +#import "OFOutOfRangeException.h" + +#import "TableGenerator.h" +#import "copyright.h" + +static OFString *const unicodeDataURL = + @"http://www.unicode.org/Public/UNIDATA/UnicodeData.txt"; +static OFString *const caseFoldingURL = + @"http://www.unicode.org/Public/UNIDATA/CaseFolding.txt"; + +OF_APPLICATION_DELEGATE(TableGenerator) + +@implementation TableGenerator +- (instancetype)init +{ + self = [super init]; + + @try { + _HTTPClient = [[OFHTTPClient alloc] init]; + _HTTPClient.delegate = self; + + _uppercaseTableSize = SIZE_MAX; + _lowercaseTableSize = SIZE_MAX; + _titlecaseTableSize = SIZE_MAX; + _caseFoldingTableSize = SIZE_MAX; + _decompositionTableSize = SIZE_MAX; + _decompositionCompatTableSize = SIZE_MAX; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)applicationDidFinishLaunching +{ + OFHTTPRequest *request; + + [OFStdOut writeString: @"Downloading UnicodeData.txt…"]; + _state = stateUnicodeData; + request = [OFHTTPRequest requestWithURL: + [OFURL URLWithString: unicodeDataURL]]; + [_HTTPClient asyncPerformRequest: request]; +} + +- (void)client: (OFHTTPClient *)client + didPerformRequest: (OFHTTPRequest *)request + response: (OFHTTPResponse *)response + exception: (id)exception +{ + if (exception != nil) + @throw exception; + + [OFStdOut writeLine: @" done"]; + + switch (_state) { + case stateUnicodeData: + [self parseUnicodeData: response]; + break; + case stateCaseFolding: + [self parseCaseFolding: response]; + break; + } +} + +- (void)parseUnicodeData: (OFHTTPResponse *)response +{ + OFString *line; + OFHTTPRequest *request; + + [OFStdOut writeString: @"Parsing UnicodeData.txt…"]; + + while ((line = [response readLine]) != nil) { + void *pool2; + OFArray OF_GENERIC(OFString *) *components; + OFUnichar codePoint; + + if (line.length == 0) + continue; + + pool2 = objc_autoreleasePoolPush(); + + components = [line componentsSeparatedByString: @";"]; + if (components.count != 15) { + OFLog(@"Invalid line: %@\n", line); + [OFApplication terminateWithStatus: 1]; + } + + codePoint = (OFUnichar)[[components objectAtIndex: 0] + unsignedLongLongValueWithBase: 16]; + + if (codePoint > 0x10FFFF) + @throw [OFOutOfRangeException exception]; + + _uppercaseTable[codePoint] = (OFUnichar)[[components + objectAtIndex: 12] unsignedLongLongValueWithBase: 16]; + _lowercaseTable[codePoint] = (OFUnichar)[[components + objectAtIndex: 13] unsignedLongLongValueWithBase: 16]; + _titlecaseTable[codePoint] = (OFUnichar)[[components + objectAtIndex: 14] unsignedLongLongValueWithBase: 16]; + + if ([[components objectAtIndex: 5] length] > 0) { + OFArray *decomposed = [[components objectAtIndex: 5] + componentsSeparatedByString: @" "]; + bool compat = false; + OFMutableString *string; + + if ([decomposed.firstObject hasPrefix: @"<"]) { + decomposed = [decomposed objectsInRange: + OFRangeMake(1, decomposed.count - 1)]; + compat = true; + } + + string = [OFMutableString string]; + + for (OFString *character in decomposed) { + OFUnichar unichar = (OFUnichar)[character + unsignedLongLongValueWithBase: 16]; + + [string appendCharacters: &unichar + length: 1]; + } + + [string makeImmutable]; + + if (!compat) + _decompositionTable[codePoint] = [string copy]; + _decompositionCompatTable[codePoint] = [string copy]; + } + + objc_autoreleasePoolPop(pool2); + } + + [self applyDecompositionRecursivelyForTable: _decompositionTable]; + [self applyDecompositionRecursivelyForTable: _decompositionCompatTable]; + + [OFStdOut writeLine: @" done"]; + + [OFStdOut writeString: @"Downloading CaseFolding.txt…"]; + _state = stateCaseFolding; + request = [OFHTTPRequest requestWithURL: + [OFURL URLWithString: caseFoldingURL]]; + [_HTTPClient asyncPerformRequest: request]; +} + +- (void)parseCaseFolding: (OFHTTPResponse *)response +{ + OFString *line; + + [OFStdOut writeString: @"Parsing CaseFolding.txt…"]; + + while ((line = [response readLine]) != nil) { + void *pool2; + OFArray OF_GENERIC(OFString *) *components; + OFUnichar codePoint; + + if (line.length == 0 || [line hasPrefix: @"#"]) + continue; + + pool2 = objc_autoreleasePoolPush(); + + components = [line componentsSeparatedByString: @"; "]; + if (components.count != 4) { + OFLog(@"Invalid line: %s\n", line); + [OFApplication terminateWithStatus: 1]; + } + + if (![[components objectAtIndex: 1] isEqual: @"S"] && + ![[components objectAtIndex: 1] isEqual: @"C"]) + continue; + + codePoint = (OFUnichar)[[components objectAtIndex: 0] + unsignedLongLongValueWithBase: 16]; + + if (codePoint > 0x10FFFF) + @throw [OFOutOfRangeException exception]; + + _caseFoldingTable[codePoint] = (OFUnichar)[[components + objectAtIndex: 2] unsignedLongLongValueWithBase: 16]; + + objc_autoreleasePoolPop(pool2); + } + + [OFStdOut writeLine: @" done"]; + + [self writeFiles]; +} + +- (void)applyDecompositionRecursivelyForTable: (OFString *[0x110000])table +{ + bool done; + + do { + done = true; + + for (OFUnichar i = 0; i < 0x110000; i++) { + void *pool; + const OFUnichar *characters; + size_t length; + OFMutableString *replacement; + bool changed = false; + + if (table[i] == nil) + continue; + + pool = objc_autoreleasePoolPush(); + characters = table[i].characters; + length = table[i].length; + replacement = [OFMutableString string]; + + for (size_t j = 0; j < length; j++) { + if (characters[j] > 0x10FFFF) + @throw [OFOutOfRangeException + exception]; + + if (table[characters[j]] == nil) + [replacement + appendCharacters: &characters[j] + length: 1]; + else { + [replacement + appendString: table[characters[j]]]; + changed = true; + } + } + + [replacement makeImmutable]; + + if (changed) { + [table[i] release]; + table[i] = [replacement copy]; + + done = false; + } + + objc_autoreleasePoolPop(pool); + } + } while (!done); +} + +- (void)writeFiles +{ + OFURL *URL; + + [OFStdOut writeString: @"Writing files…"]; + + URL = [OFURL fileURLWithPath: @"../../src/unicode.m"]; + [self writeTablesToFile: URL.fileSystemRepresentation]; + + URL = [OFURL fileURLWithPath: @"../../src/unicode.h"]; + [self writeHeaderToFile: URL.fileSystemRepresentation]; + + [OFStdOut writeLine: @" done"]; + + [OFApplication terminate]; +} + +- (void)writeTablesToFile: (OFString *)path +{ + void *pool = objc_autoreleasePoolPush(); + OFFile *file = [OFFile fileWithPath: path + mode: @"w"]; + + [file writeString: COPYRIGHT + @"#include \"config.h\"\n" + @"\n" + @"#import \"OFString.h\"\n\n" + @"static const OFUnichar emptyPage[0x100] = { 0 };\n" + @"static const char *emptyDecompositionPage[0x100] = { NULL };\n" + @"\n"]; + + /* Write uppercasePage%u */ + for (OFUnichar i = 0; i < 0x110000; i += 0x100) { + bool isEmpty = true; + + for (OFUnichar j = i; j < i + 0x100; j++) { + if (_uppercaseTable[j] != 0) { + isEmpty = false; + _uppercaseTableSize = i >> 8; + _uppercaseTableUsed[_uppercaseTableSize] = 1; + break; + } + } + + if (!isEmpty) { + void *pool2 = objc_autoreleasePoolPush(); + + [file writeFormat: @"static const OFUnichar " + @"uppercasePage%u[0x100] = {\n", + i >> 8]; + + for (OFUnichar j = i; j < i + 0x100; j += 8) + [file writeFormat: + @"\t%u, %u, %u, %u, %u, %u, %u, %u,\n", + _uppercaseTable[j], + _uppercaseTable[j + 1], + _uppercaseTable[j + 2], + _uppercaseTable[j + 3], + _uppercaseTable[j + 4], + _uppercaseTable[j + 5], + _uppercaseTable[j + 6], + _uppercaseTable[j + 7]]; + + [file writeString: @"};\n\n"]; + + objc_autoreleasePoolPop(pool2); + } + } + + /* Write lowercasePage%u */ + for (OFUnichar i = 0; i < 0x110000; i += 0x100) { + bool isEmpty = true; + + for (OFUnichar j = i; j < i + 0x100; j++) { + if (_lowercaseTable[j] != 0) { + isEmpty = false; + _lowercaseTableSize = i >> 8; + _lowercaseTableUsed[_lowercaseTableSize] = 1; + break; + } + } + + if (!isEmpty) { + void *pool2 = objc_autoreleasePoolPush(); + + [file writeFormat: @"static const OFUnichar " + @"lowercasePage%u[0x100] = {\n", + i >> 8]; + + for (OFUnichar j = i; j < i + 0x100; j += 8) + [file writeFormat: + @"\t%u, %u, %u, %u, %u, %u, %u, %u,\n", + _lowercaseTable[j], + _lowercaseTable[j + 1], + _lowercaseTable[j + 2], + _lowercaseTable[j + 3], + _lowercaseTable[j + 4], + _lowercaseTable[j + 5], + _lowercaseTable[j + 6], + _lowercaseTable[j + 7]]; + + [file writeString: @"};\n\n"]; + + objc_autoreleasePoolPop(pool2); + } + } + + /* Write titlecasePage%u if it does NOT match uppercasePage%u */ + for (OFUnichar i = 0; i < 0x110000; i += 0x100) { + bool isEmpty = true; + + for (OFUnichar j = i; j < i + 0x100; j++) { + if (_titlecaseTable[j] != 0) { + isEmpty = !memcmp(_uppercaseTable + i, + _titlecaseTable + i, + 256 * sizeof(OFUnichar)); + _titlecaseTableSize = i >> 8; + _titlecaseTableUsed[_titlecaseTableSize] = + (isEmpty ? 2 : 1); + break; + } + } + + if (!isEmpty) { + void *pool2 = objc_autoreleasePoolPush(); + + [file writeFormat: @"static const OFUnichar " + @"titlecasePage%u[0x100] = {\n", + i >> 8]; + + for (OFUnichar j = i; j < i + 0x100; j += 8) + [file writeFormat: + @"\t%u, %u, %u, %u, %u, %u, %u, %u,\n", + _titlecaseTable[j], + _titlecaseTable[j + 1], + _titlecaseTable[j + 2], + _titlecaseTable[j + 3], + _titlecaseTable[j + 4], + _titlecaseTable[j + 5], + _titlecaseTable[j + 6], + _titlecaseTable[j + 7]]; + + [file writeString: @"};\n\n"]; + + objc_autoreleasePoolPop(pool2); + } + } + + /* Write caseFoldingPage%u if it does NOT match lowercasePage%u */ + for (OFUnichar i = 0; i < 0x110000; i += 0x100) { + bool isEmpty = true; + + for (OFUnichar j = i; j < i + 0x100; j++) { + if (_caseFoldingTable[j] != 0) { + isEmpty = !memcmp(_lowercaseTable + i, + _caseFoldingTable + i, + 256 * sizeof(OFUnichar)); + _caseFoldingTableSize = i >> 8; + _caseFoldingTableUsed[_caseFoldingTableSize] = + (isEmpty ? 2 : 1); + break; + } + } + + if (!isEmpty) { + void *pool2 = objc_autoreleasePoolPush(); + + [file writeFormat: @"static const OFUnichar " + @"caseFoldingPage%u[0x100] = {\n", + i >> 8]; + + for (OFUnichar j = i; j < i + 0x100; j += 8) + [file writeFormat: + @"\t%u, %u, %u, %u, %u, %u, %u, %u,\n", + _caseFoldingTable[j], + _caseFoldingTable[j + 1], + _caseFoldingTable[j + 2], + _caseFoldingTable[j + 3], + _caseFoldingTable[j + 4], + _caseFoldingTable[j + 5], + _caseFoldingTable[j + 6], + _caseFoldingTable[j + 7]]; + + [file writeString: @"};\n\n"]; + + objc_autoreleasePoolPop(pool2); + } + } + + /* Write decompositionPage%u */ + for (OFUnichar i = 0; i < 0x110000; i += 0x100) { + bool isEmpty = true; + + for (OFUnichar j = i; j < i + 0x100; j++) { + if (_decompositionTable[j] != nil) { + isEmpty = false; + _decompositionTableSize = i >> 8; + _decompositionTableUsed[ + _decompositionTableSize] = 1; + break; + } + } + + if (!isEmpty) { + void *pool2 = objc_autoreleasePoolPush(); + + [file writeFormat: @"static const char *const " + @"decompositionPage%u[0x100] = {\n", + i >> 8]; + + for (OFUnichar j = i; j < i + 0x100; j++) { + if ((j - i) % 2 == 0) + [file writeString: @"\t"]; + else + [file writeString: @" "]; + + if (_decompositionTable[j] != nil) { + const char *UTF8String = + _decompositionTable[j].UTF8String; + size_t length = _decompositionTable[j] + .UTF8StringLength; + + [file writeString: @"\""]; + + for (size_t k = 0; k < length; k++) + [file writeFormat: + @"\\x%02X", + (uint8_t)UTF8String[k]]; + + [file writeString: @"\","]; + } else + [file writeString: @"NULL,"]; + + if ((j - i) % 2 == 1) + [file writeString: @"\n"]; + } + + [file writeString: @"};\n\n"]; + + objc_autoreleasePoolPop(pool2); + } + } + + /* Write decompCompatPage%u if it does NOT match decompositionPage%u */ + for (OFUnichar i = 0; i < 0x110000; i += 0x100) { + bool isEmpty = true; + + for (OFUnichar j = i; j < i + 0x100; j++) { + if (_decompositionCompatTable[j] != 0) { + /* + * We bulk-compare pointers via memcmp here. + * This is safe, as we always set the same + * pointer in both tables if both are the same. + */ + isEmpty = !memcmp(_decompositionTable + i, + _decompositionCompatTable + i, + 256 * sizeof(const char *)); + _decompositionCompatTableSize = i >> 8; + _decompositionCompatTableUsed[ + _decompositionCompatTableSize] = + (isEmpty ? 2 : 1); + + break; + } + } + + if (!isEmpty) { + void *pool2 = objc_autoreleasePoolPush(); + + [file writeFormat: @"static const char *const " + @"decompCompatPage%u[0x100] = {\n", + i >> 8]; + + for (OFUnichar j = i; j < i + 0x100; j++) { + if ((j - i) % 2 == 0) + [file writeString: @"\t"]; + else + [file writeString: @" "]; + + if (_decompositionCompatTable[j] != nil) { + const char *UTF8String = + _decompositionCompatTable[j] + .UTF8String; + size_t length = + _decompositionCompatTable[j] + .UTF8StringLength; + + [file writeString: @"\""]; + + for (size_t k = 0; k < length; k++) + [file writeFormat: + @"\\x%02X", + (uint8_t)UTF8String[k]]; + + [file writeString: @"\","]; + } else + [file writeString: @"NULL,"]; + + if ((j - i) % 2 == 1) + [file writeString: @"\n"]; + } + + [file writeString: @"};\n\n"]; + + objc_autoreleasePoolPop(pool2); + } + } + + /* + * Those are currently set to the last index. + * But from now on, we need the size. + */ + _uppercaseTableSize++; + _lowercaseTableSize++; + _titlecaseTableSize++; + _caseFoldingTableSize++; + _decompositionTableSize++; + _decompositionCompatTableSize++; + + /* Write OFUnicodeUppercaseTable */ + [file writeFormat: @"const OFUnichar *const " + @"OFUnicodeUppercaseTable[0x%X] = {\n\t", + _uppercaseTableSize]; + + for (OFUnichar i = 0; i < _uppercaseTableSize; i++) { + if (_uppercaseTableUsed[i]) + [file writeFormat: @"uppercasePage%u", i]; + else + [file writeString: @"emptyPage"]; + + if (i + 1 < _uppercaseTableSize) { + if ((i + 1) % 4 == 0) + [file writeString: @",\n\t"]; + else + [file writeString: @", "]; + } + } + + [file writeString: @"\n};\n\n"]; + + /* Write OFUnicodeLowercaseTable */ + [file writeFormat: @"const OFUnichar *const " + @"OFUnicodeLowercaseTable[0x%X] = {\n\t", + _lowercaseTableSize]; + + for (OFUnichar i = 0; i < _lowercaseTableSize; i++) { + if (_lowercaseTableUsed[i]) + [file writeFormat: @"lowercasePage%u", i]; + else + [file writeString: @"emptyPage"]; + + if (i + 1 < _lowercaseTableSize) { + if ((i + 1) % 4 == 0) + [file writeString: @",\n\t"]; + else + [file writeString: @", "]; + } + } + + [file writeString: @"\n};\n\n"]; + + /* Write OFUnicodeTitlecaseTable */ + [file writeFormat: @"const OFUnichar *const " + @"OFUnicodeTitlecaseTable[0x%X] = {\n\t", + _titlecaseTableSize]; + + for (OFUnichar i = 0; i < _titlecaseTableSize; i++) { + if (_titlecaseTableUsed[i] == 1) + [file writeFormat: @"titlecasePage%u", i]; + else if (_titlecaseTableUsed[i] == 2) + [file writeFormat: @"uppercasePage%u", i]; + else + [file writeString: @"emptyPage"]; + + if (i + 1 < _titlecaseTableSize) { + if ((i + 1) % 4 == 0) + [file writeString: @",\n\t"]; + else + [file writeString: @", "]; + } + } + + [file writeString: @"\n};\n\n"]; + + /* Write OFUnicodeCaseFoldingTable */ + [file writeFormat: @"const OFUnichar *const " + @"OFUnicodeCaseFoldingTable[0x%X] = {\n\t", + _caseFoldingTableSize]; + + for (OFUnichar i = 0; i < _caseFoldingTableSize; i++) { + if (_caseFoldingTableUsed[i] == 1) + [file writeFormat: @"caseFoldingPage%u", i]; + else if (_caseFoldingTableUsed[i] == 2) + [file writeFormat: @"lowercasePage%u", i]; + else + [file writeString: @"emptyPage"]; + + if (i + 1 < _caseFoldingTableSize) { + if ((i + 1) % 3 == 0) + [file writeString: @",\n\t"]; + else + [file writeString: @", "]; + } + } + + [file writeString: @"\n};\n\n"]; + + /* Write OFUnicodeDecompositionTable */ + [file writeFormat: @"const char *const " + @"*OFUnicodeDecompositionTable[0x%X] = {\n\t", + _decompositionTableSize]; + + for (OFUnichar i = 0; i < _decompositionTableSize; i++) { + if (_decompositionTableUsed[i]) + [file writeFormat: @"decompositionPage%u", i]; + else + [file writeString: @"emptyDecompositionPage"]; + + if (i + 1 < _decompositionTableSize) { + if ((i + 1) % 3 == 0) + [file writeString: @",\n\t"]; + else + [file writeString: @", "]; + } + } + + [file writeString: @"\n};\n\n"]; + + /* Write OFUnicodeDecompositionCompatTable */ + [file writeFormat: @"const char *const " + @"*OFUnicodeDecompositionCompatTable[0x%X] = {" + @"\n\t", + _decompositionCompatTableSize]; + + for (OFUnichar i = 0; i < _decompositionCompatTableSize; i++) { + if (_decompositionCompatTableUsed[i] == 1) + [file writeFormat: @"decompCompatPage%u", i]; + else if (_decompositionCompatTableUsed[i] == 2) + [file writeFormat: @"decompositionPage%u", i]; + else + [file writeString: @"emptyDecompositionPage"]; + + if (i + 1 < _decompositionCompatTableSize) { + if ((i + 1) % 3 == 0) + [file writeString: @",\n\t"]; + else + [file writeString: @", "]; + } + } + + [file writeString: @"\n};\n"]; + + objc_autoreleasePoolPop(pool); +} + +- (void)writeHeaderToFile: (OFString *)path +{ + void *pool = objc_autoreleasePoolPush(); + OFFile *file = [OFFile fileWithPath: path + mode: @"w"]; + + [file writeString: COPYRIGHT + @"#import \"OFString.h\"\n\n"]; + + [file writeFormat: + @"#define OFUnicodeUppercaseTableSize 0x%X\n" + @"#define OFUnicodeLowercaseTableSize 0x%X\n" + @"#define OFUnicodeTitlecaseTableSize 0x%X\n" + @"#define OFUnicodeCaseFoldingTableSize 0x%X\n" + @"#define OFUnicodeDecompositionTableSize 0x%X\n" + @"#define OFUnicodeDecompositionCompatTableSize 0x%X\n\n", + _uppercaseTableSize, _lowercaseTableSize, _titlecaseTableSize, + _caseFoldingTableSize, _decompositionTableSize, + _decompositionCompatTableSize]; + + [file writeString: + @"#ifdef __cplusplus\n" + @"extern \"C\" {\n" + @"#endif\n" + @"extern const OFUnichar *const _Nonnull\n" + @" OFUnicodeUppercaseTable[OFUnicodeUppercaseTableSize];\n" + @"extern const OFUnichar *const _Nonnull\n" + @" OFUnicodeLowercaseTable[OFUnicodeLowercaseTableSize];\n" + @"extern const OFUnichar *const _Nonnull\n" + @" OFUnicodeTitlecaseTable[OFUnicodeTitlecaseTableSize];\n" + @"extern const OFUnichar *const _Nonnull\n" + @" OFUnicodeCaseFoldingTable[OFUnicodeCaseFoldingTableSize];\n" + @"extern const char *const _Nullable *const _Nonnull\n" + @" OFUnicodeDecompositionTable[" + @"OFUnicodeDecompositionTableSize];\n" + @"extern const char *const _Nullable *const _Nonnull\n" + @" OFUnicodeDecompositionCompatTable[" + @"OFUnicodeDecompositionCompatTableSize];\n" + @"#ifdef __cplusplus\n" + @"}\n" + @"#endif\n"]; + + objc_autoreleasePoolPop(pool); +} +@end ADDED generators/unicode/copyright.h Index: generators/unicode/copyright.h ================================================================== --- /dev/null +++ generators/unicode/copyright.h @@ -0,0 +1,38 @@ +/* + * 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" ADDED objfw.spec Index: objfw.spec ================================================================== --- /dev/null +++ objfw.spec @@ -0,0 +1,248 @@ +%global libobjfw_major 0 +%global libobjfw_minor 0 +%global libobjfwrt_major 0 +%global libobjfwrt_minor 0 +%global libobjfwtls_major 0 +%global libobjfwtls_minor 0 +%if 0%{?suse_version} +%global libobjfw_pkgname libobjfw%{libobjfw_major} +%global libobjfwrt_pkgname libobjfwrt%{libobjfwrt_major} +%global libobjfwtls_pkgname libobjfwtls%{libobjfwtls_major} +%else +%global libobjfw_pkgname libobjfw +%global libobjfwrt_pkgname libobjfwrt +%global libobjfwtls_pkgname libobjfwtls +%endif + +Name: objfw +Version: 1.1dev +Release: 1%{?dist} +Summary: Portable, lightweight framework for the Objective-C language + +%if 0%{?suse_version} +License: QPL-1.0 or GPL-3.0 or GPL-2.0 +Group: Development/Languages/C and C++ +%else +License: QPL or GPLv3 or GPLv2 +%endif +URL: https://objfw.nil.im +Source0: objfw-%{version}.tar.gz + +BuildRequires: autoconf +BuildRequires: automake +BuildRequires: clang +BuildRequires: make +BuildRequires: pkgconfig(openssl) +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} +Requires: ofdns%{_isa} = %{version}-%{release} +Requires: ofhash%{_isa} = %{version}-%{release} +Requires: ofhttp%{_isa} = %{version}-%{release} + +%description +ObjFW is a portable, lightweight framework for the Objective-C language. It +enables you to write an application in Objective-C that will run on any +platform supported by ObjFW without having to worry about differences between +operating systems or various frameworks you would otherwise need if you want to +be portable. + +It supports all modern Objective-C features when using Clang, but is also +compatible with GCC ≥ 4.6 to allow maximum portability. + +ObjFW also comes with its own lightweight and extremely fast Objective-C +runtime, which in real world use cases was found to be significantly faster +than both GNU's and Apple's runtime. + +%package -n %{libobjfw_pkgname} +Summary: ObjFW library +Requires: %{libobjfwrt_pkgname}%{_isa} = %{version}-%{release} + +%description -n %{libobjfw_pkgname} +The %{libobjfw_pkgname} package contains the library needed by programs using +ObjFW. + +%package -n %{libobjfw_pkgname}-devel +Summary: Header files, libraries and tools for %{libobjfw_pkgname} +Requires: %{libobjfw_pkgname}%{_isa} = %{version}-%{release} +Requires: %{libobjfwrt_pkgname}-devel = %{version}-%{release} + +%description -n %{libobjfw_pkgname}-devel +The %{libobjfw_pkgname}-devel package contains the header files, libraries and +tools to develop programs using ObjFW. + +%package -n %{libobjfwrt_pkgname} +Summary: ObjFW Objective-C runtime library + +%description -n %{libobjfwrt_pkgname} +The %{libobjfwrt_pkgname} package contains ObjFW's Objective-C runtime library. + +%package -n %{libobjfwrt_pkgname}-devel +Summary: Header files and libraries for %{libobjfwrt_pkgname} +Requires: %{libobjfwrt_pkgname}%{_isa} = %{version}-%{release} + +%description -n %{libobjfwrt_pkgname}-devel +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 + +%description -n %{libobjfwtls_pkgname} +The %{libobjfwtls_pkgname} package contains TLS support for ObjFW + +%package -n %{libobjfwtls_pkgname}-devel +Summary: Header files and libraries for %{libobjfwtls_pkgname} +Requires: %{libobjfwtls_pkgname}%{_isa} = %{version}-%{release} + +%description -n %{libobjfwtls_pkgname}-devel +The %{libobjfwtls_pkgname}-devel package contains header files and libraries +for TLS support for ObjFW. + +%package -n ofarc +Summary: Utility for handling ZIP, Tar and LHA archives +Requires: %{libobjfw_pkgname}%{_isa} = %{version}-%{release} +Requires: %{libobjfwrt_pkgname}%{_isa} = %{version}-%{release} + +%description -n ofarc +ofarc is a multi-format archive utility that allows creating, listing, +extracting and modifying ZIP, Tar and LHA archives using ObjFW's classes for +various archive types. + +%package -n ofdns +Summary: Utility for performing DNS requests on the command line +Requires: %{libobjfw_pkgname}%{_isa} = %{version}-%{release} +Requires: %{libobjfwrt_pkgname}%{_isa} = %{version}-%{release} + +%description -n ofdns +ofdns is an utility for performing DNS requests on the command line using +ObjFW's DNS resolver. + +%package -n ofhash +Summary: Utility to hash files with various cryptographic hash functions +Requires: %{libobjfw_pkgname}%{_isa} = %{version}-%{release} +Requires: %{libobjfwrt_pkgname}%{_isa} = %{version}-%{release} + +%description -n ofhash +ofhash is an utility to hash files with various cryptographic hash functions +(even using different algorithms at once) using ObjFW's classes for various +cryptographic hashes. + +%package -n ofhttp +Summary: Command line downloader for HTTP(S) +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. + +%prep +%autosetup +./autogen.sh + +%build +%configure OBJC=clang --disable-rpath +%make_build + +%install +%make_install + +%check +make -C tests run + +%if 0%{?suse_version} +%post -n %{libobjfw_pkgname} -p /sbin/ldconfig +%postun -n %{libobjfw_pkgname} -p /sbin/ldconfig +%post -n %{libobjfwrt_pkgname} -p /sbin/ldconfig +%postun -n %{libobjfwrt_pkgname} -p /sbin/ldconfig +%endif + +%files +%license LICENSE.QPL +%license LICENSE.GPLv3 +%license LICENSE.GPLv2 + +%files -n %{libobjfw_pkgname} +%{_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 +%{_bindir}/objfw-compile +%{_bindir}/objfw-config +%{_bindir}/objfw-new +%license LICENSE.QPL +%license LICENSE.GPLv3 +%license LICENSE.GPLv2 + +%files -n %{libobjfwrt_pkgname} +%{_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.QPL +%license LICENSE.GPLv3 +%license LICENSE.GPLv2 + +%files -n %{libobjfwtls_pkgname} +%{_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.QPL +%license LICENSE.GPLv3 +%license LICENSE.GPLv2 + +%files -n ofarc +%{_bindir}/ofarc +%{_datadir}/ofarc/lang/de.json +%{_datadir}/ofarc/lang/languages.json +%license LICENSE.QPL +%license LICENSE.GPLv3 +%license LICENSE.GPLv2 + +%files -n ofdns +%{_bindir}/ofdns +%{_datadir}/ofdns/lang/de.json +%{_datadir}/ofdns/lang/languages.json +%license LICENSE.QPL +%license LICENSE.GPLv3 +%license LICENSE.GPLv2 + +%files -n ofhash +%{_bindir}/ofhash +%{_datadir}/ofhash/lang/de.json +%{_datadir}/ofhash/lang/languages.json +%license LICENSE.QPL +%license LICENSE.GPLv3 +%license LICENSE.GPLv2 + +%files -n ofhttp +%{_bindir}/ofhttp +%{_datadir}/ofhttp/lang/de.json +%{_datadir}/ofhttp/lang/languages.json +%license LICENSE.QPL +%license LICENSE.GPLv3 +%license LICENSE.GPLv2 Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -1,38 +1,26 @@ include ../extra.mk -SUBDIRS = ${RUNTIME} exceptions ${ENCODINGS} forwarding invocation -SUBDIRS_AFTER = ${BRIDGE} +SUBDIRS = ${RUNTIME} exceptions encodings forwarding +SUBDIRS_AFTER = ${BRIDGE} ${TLS} DISTCLEAN = Info.plist objfw-defs.h SHARED_LIB = ${OBJFW_SHARED_LIB} STATIC_LIB = ${OBJFW_STATIC_LIB} FRAMEWORK = ${OBJFW_FRAMEWORK} LIB_MAJOR = ${OBJFW_LIB_MAJOR} LIB_MINOR = ${OBJFW_LIB_MINOR} -SRCS = OFASN1BitString.m \ - OFASN1Boolean.m \ - OFASN1Enumerated.m \ - OFASN1IA5String.m \ - OFASN1Integer.m \ - OFASN1NumericString.m \ - OFASN1ObjectIdentifier.m \ - OFASN1OctetString.m \ - OFASN1PrintableString.m \ - OFASN1UTF8String.m \ - OFASN1Value.m \ - OFApplication.m \ +SRCS = OFApplication.m \ OFArray.m \ OFBlock.m \ OFCharacterSet.m \ OFColor.m \ OFConstantString.m \ OFCountedSet.m \ OFData.m \ - OFData+ASN1DERParsing.m \ - OFData+CryptoHashing.m \ + OFData+CryptographicHashing.m \ OFData+MessagePackParsing.m \ OFDate.m \ OFDictionary.m \ OFEnumerator.m \ OFFileManager.m \ @@ -43,12 +31,12 @@ OFInvocation.m \ OFLHAArchive.m \ OFLHAArchiveEntry.m \ OFList.m \ OFLocale.m \ - OFMapTable.m \ OFMD5Hash.m \ + OFMapTable.m \ OFMessagePackExtension.m \ OFMethodSignature.m \ OFMutableArray.m \ OFMutableData.m \ OFMutableDictionary.m \ @@ -58,50 +46,56 @@ OFMutableString.m \ OFMutableTarArchiveEntry.m \ OFMutableTriple.m \ OFMutableURL.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 \ - ${OF_PROCESS_M} \ OFRIPEMD160Hash.m \ OFRunLoop.m \ - OFSandbox.m \ - OFSecureData.m \ - OFSeekableStream.m \ - OFSet.m \ OFSHA1Hash.m \ OFSHA224Hash.m \ OFSHA224Or256Hash.m \ OFSHA256Hash.m \ OFSHA384Hash.m \ OFSHA384Or512Hash.m \ OFSHA512Hash.m \ + OFScrypt.m \ + OFSecureData.m \ + OFSeekableStream.m \ + OFSerialization.m \ + OFSet.m \ OFSortedList.m \ OFStdIOStream.m \ OFStream.m \ OFString.m \ - OFString+CryptoHashing.m \ + OFString+CryptographicHashing.m \ OFString+JSONParsing.m \ OFString+PropertyListParsing.m \ OFString+Serialization.m \ OFString+URLEncoding.m \ OFString+XMLEscaping.m \ OFString+XMLUnescaping.m \ + ${OF_SUBPROCESS_M} \ OFSystemInfo.m \ OFTarArchive.m \ OFTarArchiveEntry.m \ OFThread.m \ OFTimer.m \ OFTriple.m \ OFURL.m \ OFURLHandler.m \ + OFUUID.m \ OFValue.m \ OFXMLAttribute.m \ OFXMLCDATA.m \ OFXMLCharacters.m \ OFXMLComment.m \ @@ -108,23 +102,13 @@ OFXMLElement.m \ OFXMLElement+Serialization.m \ OFXMLElementBuilder.m \ OFXMLNode.m \ OFXMLParser.m \ - OFXMLProcessingInstructions.m \ + OFXMLProcessingInstruction.m \ OFZIPArchive.m \ OFZIPArchiveEntry.m \ - base64.m \ - crc16.m \ - crc32.m \ - huffman_tree.m \ - of_asprintf.m \ - of_strptime.m \ - once.m \ - pbkdf2.m \ - scrypt.m \ - ${UNICODE_M} \ ${USE_SRCS_FILES} \ ${USE_SRCS_PLUGINS} \ ${USE_SRCS_SOCKETS} \ ${USE_SRCS_THREADS} \ ${USE_SRCS_WINDOWS} @@ -131,15 +115,11 @@ SRCS_FILES = OFFile.m \ OFINICategory.m \ OFINIFile.m \ OFSettings.m \ OFString+PathAdditions.m -SRCS_IPX = OFIPXSocket.m \ - OFSPXSocket.m \ - OFSPXStreamSocket.m SRCS_PLUGINS = OFPlugin.m -SRCS_SCTP = OFSCTPSocket.m SRCS_SOCKETS = OFDNSQuery.m \ OFDNSResolver.m \ OFDNSResourceRecord.m \ OFDNSResponse.m \ OFDatagramSocket.m \ @@ -148,58 +128,62 @@ OFHTTPCookieManager.m \ OFHTTPRequest.m \ OFHTTPResponse.m \ OFHTTPServer.m \ OFSequencedPacketSocket.m \ + OFSocket.m \ OFStreamSocket.m \ OFTCPSocket.m \ + OFTLSStream.m \ OFUDPSocket.m \ - socket.m \ ${USE_SRCS_IPX} \ - ${USE_SRCS_SCTP} + ${USE_SRCS_UNIX_SOCKETS} +SRCS_IPX = OFIPXSocket.m \ + OFSPXSocket.m \ + OFSPXStreamSocket.m +SRCS_UNIX_SOCKETS = OFUNIXDatagramSocket.m \ + OFUNIXStreamSocket.m SRCS_THREADS = OFCondition.m \ OFMutex.m \ + OFPlainCondition.m \ + OFPlainMutex.m \ + OFPlainThread.m \ OFRecursiveMutex.m \ - OFThreadPool.m \ - condition.m \ - mutex.m \ - thread.m \ - tlskey.m + OFTLSKey.m SRCS_WINDOWS = OFWin32ConsoleStdIOStream.m \ OFWindowsRegistryKey.m -INCLUDES_ATOMIC = atomic.h \ - atomic_builtins.h \ - atomic_no_threads.h \ - atomic_osatomic.h \ - atomic_powerpc.h \ - atomic_sync_builtins.h \ - atomic_x86.h +INCLUDES_ATOMIC = OFAtomic.h \ + platform/GCC4/OFAtomic.h \ + platform/GCC4.7/OFAtomic.h \ + platform/PowerPC/OFAtomic.h \ + platform/macOS/OFAtomic.h \ + platform/x86/OFAtomic.h INCLUDES := ${SRCS:.m=.h} \ - OFASN1DERRepresentation.h \ OFCollection.h \ - OFCryptoHash.h \ + OFCryptographicHash.h \ OFJSONRepresentation.h \ OFKernelEventObserver.h \ OFKeyValueCoding.h \ OFLocking.h \ OFMessagePackRepresentation.h \ - OFSerialization.h \ - OFTLSSocket.h \ ObjFW.h \ - block.h \ macros.h \ objfw-defs.h \ platform.h \ ${USE_INCLUDES_ATOMIC} -SRCS += OFAdjacentArray.m \ +SRCS += OFASPrintF.m \ + OFAdjacentArray.m \ OFAdjacentSubarray.m \ + OFBase64.m \ OFBitSetCharacterSet.m \ OFBytesValue.m \ + OFCRC16.m \ + OFCRC32.m \ OFCountedMapTableSet.m \ - OFDimensionValue.m \ + OFHuffmanTree.m \ OFInvertedCharacterSet.m \ OFLHADecompressingStream.m \ OFMapTableDictionary.m \ OFMapTableSet.m \ OFMutableAdjacentArray.m \ @@ -209,39 +193,39 @@ OFNonretainedObjectValue.m \ OFPointValue.m \ OFPointerValue.m \ OFRangeCharacterSet.m \ OFRangeValue.m \ - OFRectangleValue.m \ + OFRectValue.m \ + OFSandbox.m \ + OFSizeValue.m \ + OFStrPTime.m \ OFSubarray.m \ OFUTF8String.m \ ${LIBBASES_M} \ ${RUNTIME_AUTORELEASE_M} \ - ${RUNTIME_INSTANCE_M} + ${RUNTIME_INSTANCE_M} \ + ${UNICODE_M} SRCS_FILES += OFFileURLHandler.m \ OFINIFileSettings.m SRCS_SOCKETS += OFDNSResolverSettings.m \ + ${OF_EPOLL_KERNEL_EVENT_OBSERVER_M} \ OFHTTPURLHandler.m \ OFHostAddressResolver.m \ OFIPSocketAsyncConnector.m \ OFKernelEventObserver.m \ - ${OF_EPOLL_KERNEL_EVENT_OBSERVER_M} \ ${OF_KQUEUE_KERNEL_EVENT_OBSERVER_M} \ ${OF_POLL_KERNEL_EVENT_OBSERVER_M} \ ${OF_SELECT_KERNEL_EVENT_OBSERVER_M} \ OFTCPSocketSOCKS5Connector.m -OBJS_EXTRA = ${RUNTIME_RUNTIME_A} \ - ${EXCEPTIONS_EXCEPTIONS_A} \ - ${ENCODINGS_ENCODINGS_A} \ - ${FORWARDING_FORWARDING_A} \ - ${INVOCATION_INVOCATION_A} -LIB_OBJS_EXTRA = ${RUNTIME_RUNTIME_LIB_A} \ - ${EXCEPTIONS_EXCEPTIONS_LIB_A} \ - ${ENCODINGS_ENCODINGS_LIB_A} \ - ${FORWARDING_FORWARDING_LIB_A} \ - ${INVOCATION_INVOCATION_LIB_A} +OBJS_EXTRA = exceptions/exceptions.a \ + encodings/encodings.a \ + forwarding/forwarding.a +LIB_OBJS_EXTRA = exceptions/exceptions.lib.a \ + encodings/encodings.lib.a \ + forwarding/forwarding.lib.a include ../buildsys.mk CPPFLAGS += -I. -I.. -Iexceptions -Iruntime LD = ${OBJC} DELETED src/OFASN1BitString.h Index: src/OFASN1BitString.h ================================================================== --- src/OFASN1BitString.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "OFASN1DERRepresentation.h" -#import "OFASN1Value.h" - -OF_ASSUME_NONNULL_BEGIN - -@class OFData; - -/** - * @brief An ASN.1 BitString. - */ -OF_SUBCLASSING_RESTRICTED -@interface OFASN1BitString: OFObject -{ - OFData *_bitStringValue; - size_t _bitStringLength; -} - -/** - * @brief The BitString value. - */ -@property (readonly, nonatomic) OFData *bitStringValue; - -/** - * @brief The length of the BitString in bits. - */ -@property (readonly, nonatomic) size_t bitStringLength; - -/** - * @brief Creates an ASN.1 BitString with the specified BitString value and - * length. - * - * @param bitStringValue The value of the BitString - * @param bitStringLength The length of the BitString in bits - * @return A new, autoreleased OFASN1BitString - */ -+ (instancetype)bitStringWithBitStringValue: (OFData *)bitStringValue - bitStringLength: (size_t)bitStringLength; - -- (instancetype)init OF_UNAVAILABLE; - -/** - * @brief Initializes an already allocated ASN.1 BitString with the specified - * BitString value and length. - * - * @param bitStringValue The value of the BitString - * @param bitStringLength The length of the BitString in bits - * @return An initialized OFASN1BitString - */ -- (instancetype)initWithBitStringValue: (OFData *)bitStringValue - bitStringLength: (size_t)bitStringLength - OF_DESIGNATED_INITIALIZER; - -/** - * @brief Initializes an already allocated ASN.1 BitString with the specified - * arguments. - * - * @param tagClass The tag class of the value's type - * @param tagNumber The tag number of the value's type - * @param constructed Whether the value if of a constructed type - * @param DEREncodedContents The DER-encoded contents octets of the value. - * @return An initialized OFASN1BitString - */ -- (instancetype)initWithTagClass: (of_asn1_tag_class_t)tagClass - tagNumber: (of_asn1_tag_number_t)tagNumber - constructed: (bool)constructed - DEREncodedContents: (OFData *)DEREncodedContents; -@end - -OF_ASSUME_NONNULL_END DELETED src/OFASN1BitString.m Index: src/OFASN1BitString.m ================================================================== --- src/OFASN1BitString.m +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "OFASN1BitString.h" -#import "OFData.h" -#import "OFString.h" - -#import "OFInvalidArgumentException.h" -#import "OFInvalidFormatException.h" -#import "OFOutOfRangeException.h" - -@implementation OFASN1BitString -@synthesize bitStringValue = _bitStringValue; -@synthesize bitStringLength = _bitStringLength; - -+ (instancetype)bitStringWithBitStringValue: (OFData *)bitStringValue - bitStringLength: (size_t)bitStringLength -{ - return [[[self alloc] - initWithBitStringValue: bitStringValue - bitStringLength: bitStringLength] autorelease]; -} - -- (instancetype)initWithBitStringValue: (OFData *)bitStringValue - bitStringLength: (size_t)bitStringLength -{ - self = [super init]; - - @try { - if (bitStringValue.count * bitStringValue.itemSize != - OF_ROUND_UP_POW2(8, bitStringLength) / 8) - @throw [OFInvalidFormatException exception]; - - _bitStringValue = [bitStringValue copy]; - _bitStringLength = bitStringLength; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (instancetype)initWithTagClass: (of_asn1_tag_class_t)tagClass - tagNumber: (of_asn1_tag_number_t)tagNumber - constructed: (bool)constructed - DEREncodedContents: (OFData *)DEREncodedContents -{ - void *pool = objc_autoreleasePoolPush(); - OFData *bitStringValue; - size_t bitStringLength; - - @try { - unsigned char unusedBits; - size_t count = DEREncodedContents.count; - - if (tagClass != OF_ASN1_TAG_CLASS_UNIVERSAL || - tagNumber != OF_ASN1_TAG_NUMBER_BIT_STRING || constructed) - @throw [OFInvalidArgumentException exception]; - - if (DEREncodedContents.itemSize != 1 || count == 0) - @throw [OFInvalidFormatException exception]; - - unusedBits = - *(unsigned char *)[DEREncodedContents itemAtIndex: 0]; - - if (unusedBits > 7) - @throw [OFInvalidFormatException exception]; - - /* - * Can't have any bits of the last byte unused if we have no - * byte. - */ - if (count == 1 && unusedBits != 0) - @throw [OFInvalidFormatException exception]; - - if (SIZE_MAX / 8 < count - 1) - @throw [OFOutOfRangeException exception]; - - bitStringLength = (count - 1) * 8; - bitStringValue = [DEREncodedContents subdataWithRange: - of_range(1, count - 1)]; - - if (unusedBits != 0) - bitStringLength -= unusedBits; - } @catch (id e) { - [self release]; - @throw e; - } - - self = [self initWithBitStringValue: bitStringValue - bitStringLength: bitStringLength]; - - objc_autoreleasePoolPop(pool); - - return self; -} - -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - -- (void)dealloc -{ - [_bitStringValue release]; - - [super dealloc]; -} - -- (OFData *)ASN1DERRepresentation -{ - size_t bitStringValueCount = [_bitStringValue count]; - size_t roundedUpLength = OF_ROUND_UP_POW2(8, _bitStringLength); - unsigned char unusedBits = roundedUpLength - _bitStringLength; - unsigned char header[] = { - OF_ASN1_TAG_NUMBER_BIT_STRING, - bitStringValueCount + 1, - unusedBits - }; - OFMutableData *data; - - if (bitStringValueCount + 1 > UINT8_MAX || - bitStringValueCount != roundedUpLength / 8) - @throw [OFInvalidFormatException exception]; - - data = [OFMutableData - dataWithCapacity: sizeof(header) + bitStringValueCount]; - [data addItems: header - count: sizeof(header)]; - [data addItems: [_bitStringValue items] - count: bitStringValueCount]; - - [data makeImmutable]; - - return data; -} - -- (bool)isEqual: (id)object -{ - OFASN1BitString *bitString; - - if (object == self) - return true; - - if (![object isKindOfClass: [OFASN1BitString class]]) - return false; - - bitString = object; - - if (![bitString->_bitStringValue isEqual: _bitStringValue]) - return false; - if (bitString->_bitStringLength != _bitStringLength) - return false; - - return true; -} - -- (unsigned long)hash -{ - return _bitStringValue.hash + (unsigned long)_bitStringLength; -} - -- (OFString *)description -{ - return [OFString stringWithFormat: @"", - _bitStringValue, _bitStringLength]; -} -@end DELETED src/OFASN1Boolean.h Index: src/OFASN1Boolean.h ================================================================== --- src/OFASN1Boolean.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "OFASN1DERRepresentation.h" -#import "OFASN1Value.h" - -OF_ASSUME_NONNULL_BEGIN - -/** - * @brief An ASN.1 Boolean. - */ -OF_SUBCLASSING_RESTRICTED -@interface OFASN1Boolean: OFObject -{ - bool _booleanValue; -} - -/** - * @brief The Boolean value. - */ -@property (readonly, nonatomic) bool booleanValue; - -/** - * @brief Creates an ASN.1 Boolean with the specified Boolean value. - * - * @param booleanValue The value of the Boolean - * @return A new, autoreleased OFASN1Boolean - */ -+ (instancetype)booleanWithBooleanValue: (bool)booleanValue; - -- (instancetype)init OF_UNAVAILABLE; - -/** - * @brief Initializes an already allocated ASN.1 Boolean with the specified - * Boolean value. - * - * @param booleanValue The value of the Boolean - * @return An initialized OFASN1Boolean - */ -- (instancetype)initWithBooleanValue: (bool)booleanValue - OF_DESIGNATED_INITIALIZER; - -/** - * @brief Initializes an already allocated ASN.1 Boolean with the specified - * arguments. - * - * @param tagClass The tag class of the value's type - * @param tagNumber The tag number of the value's type - * @param constructed Whether the value if of a constructed type - * @param DEREncodedContents The DER-encoded contents octets of the value. - * @return An initialized OFASN1Boolean - */ -- (instancetype)initWithTagClass: (of_asn1_tag_class_t)tagClass - tagNumber: (of_asn1_tag_number_t)tagNumber - constructed: (bool)constructed - DEREncodedContents: (OFData *)DEREncodedContents; -@end - -OF_ASSUME_NONNULL_END DELETED src/OFASN1Boolean.m Index: src/OFASN1Boolean.m ================================================================== --- src/OFASN1Boolean.m +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "OFASN1Boolean.h" -#import "OFData.h" -#import "OFString.h" - -#import "OFInvalidArgumentException.h" -#import "OFInvalidFormatException.h" - -@implementation OFASN1Boolean -@synthesize booleanValue = _booleanValue; - -+ (instancetype)booleanWithBooleanValue: (bool)booleanValue -{ - return [[[self alloc] initWithBooleanValue: booleanValue] autorelease]; -} - -- (instancetype)initWithBooleanValue: (bool)booleanValue -{ - self = [super init]; - - _booleanValue = booleanValue; - - return self; -} - -- (instancetype)initWithTagClass: (of_asn1_tag_class_t)tagClass - tagNumber: (of_asn1_tag_number_t)tagNumber - constructed: (bool)constructed - DEREncodedContents: (OFData *)DEREncodedContents -{ - unsigned char value; - - @try { - if (tagClass != OF_ASN1_TAG_CLASS_UNIVERSAL || - tagNumber != OF_ASN1_TAG_NUMBER_BOOLEAN || constructed) - @throw [OFInvalidArgumentException exception]; - - if (DEREncodedContents.itemSize != 1 || - DEREncodedContents.count != 1) - @throw [OFInvalidFormatException exception]; - - value = *(unsigned char *)[DEREncodedContents itemAtIndex: 0]; - - if (value != 0 && value != 0xFF) - @throw [OFInvalidFormatException exception]; - } @catch (id e) { - [self release]; - @throw e; - } - - return [self initWithBooleanValue: !!value]; -} - -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - -- (OFData *)ASN1DERRepresentation -{ - char buffer[] = { - OF_ASN1_TAG_NUMBER_BOOLEAN, - 1, - (_booleanValue ? 0xFF : 0x00) - }; - - return [OFData dataWithItems: buffer - count: sizeof(buffer)]; -} - -- (bool)isEqual: (id)object -{ - OFASN1Boolean *boolean; - - if (object == self) - return true; - - if (![object isKindOfClass: [OFASN1Boolean class]]) - return false; - - boolean = object; - - if (boolean->_booleanValue != _booleanValue) - return false; - - return true; -} - -- (unsigned long)hash -{ - return _booleanValue; -} - -- (OFString *)description -{ - return (_booleanValue - ? @"" - : @""); -} -@end DELETED src/OFASN1DERRepresentation.h Index: src/OFASN1DERRepresentation.h ================================================================== --- src/OFASN1DERRepresentation.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 OFData; - -/** - * @protocol OFASN1DERRepresentation \ - * OFASN1DERRepresentation.h ObjFW/OFASN1DERRepresentation.h - * - * @brief A protocol implemented by classes that support encoding to ASN.1 DER - * representation. - */ -@protocol OFASN1DERRepresentation -/** - * @brief The object in ASN.1 DER representation. - */ -@property (readonly, nonatomic) OFData *ASN1DERRepresentation; -@end - -OF_ASSUME_NONNULL_END DELETED src/OFASN1Enumerated.h Index: src/OFASN1Enumerated.h ================================================================== --- src/OFASN1Enumerated.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "OFASN1Value.h" - -OF_ASSUME_NONNULL_BEGIN - -/** - * @brief An ASN.1 Enumerated. - */ -OF_SUBCLASSING_RESTRICTED -@interface OFASN1Enumerated: OFObject -{ - long long _longLongValue; -} - -/** - * @brief The integer value. - */ -@property (readonly, nonatomic) long long longLongValue; - -/** - * @brief Creates an ASN.1 Enumerated with the specified integer value. - * - * @param value The `long long` value of the Enumerated - * @return A new, autoreleased OFASN1Enumerated - */ -+ (instancetype)enumeratedWithLongLong: (long long)value; - -- (instancetype)init OF_UNAVAILABLE; - -/** - * @brief Initializes an already allocated ASN.1 Enumerated with the specified - * integer value. - * - * @param value The `long long` value of the Enumerated - * @return An initialized OFASN1Enumerated - */ -- (instancetype)initWithLongLong: (long long)value OF_DESIGNATED_INITIALIZER; - -/** - * @brief Initializes an already allocated ASN.1 Enumerated with the specified - * arguments. - * - * @param tagClass The tag class of the value's type - * @param tagNumber The tag number of the value's type - * @param constructed Whether the value if of a constructed type - * @param DEREncodedContents The DER-encoded contents octets of the value. - * @return An initialized OFASN1Enumerated - */ -- (instancetype)initWithTagClass: (of_asn1_tag_class_t)tagClass - tagNumber: (of_asn1_tag_number_t)tagNumber - constructed: (bool)constructed - DEREncodedContents: (OFData *)DEREncodedContents; -@end - -OF_ASSUME_NONNULL_END DELETED src/OFASN1Enumerated.m Index: src/OFASN1Enumerated.m ================================================================== --- src/OFASN1Enumerated.m +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "OFASN1Enumerated.h" -#import "OFData.h" -#import "OFString.h" - -#import "OFInvalidArgumentException.h" - -extern long long of_asn1_der_integer_parse(const unsigned char *buffer, - size_t length); - -@implementation OFASN1Enumerated -@synthesize longLongValue = _longLongValue; - -+ (instancetype)enumeratedWithLongLong: (long long)value -{ - return [[[self alloc] initWithLongLong: value] autorelease]; -} - -- (instancetype)initWithLongLong: (long long)value -{ - self = [super init]; - - _longLongValue = value; - - return self; -} - -- (instancetype)initWithTagClass: (of_asn1_tag_class_t)tagClass - tagNumber: (of_asn1_tag_number_t)tagNumber - constructed: (bool)constructed - DEREncodedContents: (OFData *)DEREncodedContents -{ - long long value; - - @try { - if (tagClass != OF_ASN1_TAG_CLASS_UNIVERSAL || - tagNumber != OF_ASN1_TAG_NUMBER_ENUMERATED || constructed) - @throw [OFInvalidArgumentException exception]; - - if (DEREncodedContents.itemSize != 1) - @throw [OFInvalidArgumentException exception]; - - value = of_asn1_der_integer_parse( - DEREncodedContents.items, DEREncodedContents.count); - } @catch (id e) { - [self release]; - @throw e; - } - - return [self initWithLongLong: value]; -} - -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - -- (bool)isEqual: (id)object -{ - OFASN1Enumerated *enumerated; - - if (object == self) - return true; - - if (![object isKindOfClass: [OFASN1Enumerated class]]) - return false; - - enumerated = object; - - if (enumerated->_longLongValue != _longLongValue) - return false; - - return true; -} - -- (unsigned long)hash -{ - return (unsigned long)_longLongValue; -} - -- (OFString *)description -{ - return [OFString stringWithFormat: @"", - _longLongValue]; -} -@end DELETED src/OFASN1IA5String.h Index: src/OFASN1IA5String.h ================================================================== --- src/OFASN1IA5String.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "OFASN1Value.h" - -OF_ASSUME_NONNULL_BEGIN - -@class OFString; - -/** - * @brief An ASN.1 IA5String. - */ -OF_SUBCLASSING_RESTRICTED -@interface OFASN1IA5String: OFObject -{ - OFString *_IA5StringValue; -} - -/** - * @brief The IA5String value. - */ -@property (readonly, nonatomic) OFString *IA5StringValue; - -/** - * @brief The string value. - */ -@property (readonly, nonatomic) OFString *stringValue; - -/** - * @brief Creates an IA5String with the specified string value. - * - * @param stringValue The string value of the IA5String - * @return A new, autoreleased OFASN1IA5String - */ -+ (instancetype)stringWithStringValue: (OFString *)stringValue; - -- (instancetype)init OF_UNAVAILABLE; - -/** - * @brief Initializes an already allocated IA5String with the specified string - * value. - * - * @param stringValue The string value of the IA5String - * @return An initialized OFASN1IA5String - */ -- (instancetype)initWithStringValue: (OFString *)stringValue - OF_DESIGNATED_INITIALIZER; - -/** - * @brief Initializes an already allocated ASN.1 IA5String with the specified - * arguments. - * - * @param tagClass The tag class of the value's type - * @param tagNumber The tag number of the value's type - * @param constructed Whether the value if of a constructed type - * @param DEREncodedContents The DER-encoded contents octets of the value. - * @return An initialized OFASN1IA5String - */ -- (instancetype)initWithTagClass: (of_asn1_tag_class_t)tagClass - tagNumber: (of_asn1_tag_number_t)tagNumber - constructed: (bool)constructed - DEREncodedContents: (OFData *)DEREncodedContents; -@end - -OF_ASSUME_NONNULL_END DELETED src/OFASN1IA5String.m Index: src/OFASN1IA5String.m ================================================================== --- src/OFASN1IA5String.m +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "OFASN1IA5String.h" -#import "OFData.h" -#import "OFString.h" - -#import "OFInvalidArgumentException.h" - -@implementation OFASN1IA5String -@synthesize IA5StringValue = _IA5StringValue; - -+ (instancetype)stringWithStringValue: (OFString *)stringValue -{ - return [[[self alloc] initWithStringValue: stringValue] autorelease]; -} - -- (instancetype)initWithStringValue: (OFString *)stringValue -{ - self = [super init]; - - @try { - _IA5StringValue = [stringValue copy]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (instancetype)initWithTagClass: (of_asn1_tag_class_t)tagClass - tagNumber: (of_asn1_tag_number_t)tagNumber - constructed: (bool)constructed - DEREncodedContents: (OFData *)DEREncodedContents -{ - void *pool = objc_autoreleasePoolPush(); - OFString *IA5StringValue; - - @try { - if (tagClass != OF_ASN1_TAG_CLASS_UNIVERSAL || - tagNumber != OF_ASN1_TAG_NUMBER_IA5_STRING || constructed) - @throw [OFInvalidArgumentException exception]; - - if (DEREncodedContents.itemSize != 1) - @throw [OFInvalidArgumentException exception]; - - IA5StringValue = [OFString - stringWithCString: DEREncodedContents.items - encoding: OF_STRING_ENCODING_ASCII - length: DEREncodedContents.count]; - } @catch (id e) { - [self release]; - @throw e; - } - - self = [self initWithStringValue: IA5StringValue]; - - objc_autoreleasePoolPop(pool); - - return self; -} - -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - -- (void)dealloc -{ - [_IA5StringValue release]; - - [super dealloc]; -} - -- (OFString *)stringValue -{ - return self.IA5StringValue; -} - -- (bool)isEqual: (id)object -{ - OFASN1IA5String *IA5String; - - if (object == self) - return true; - - if (![object isKindOfClass: [OFASN1IA5String class]]) - return false; - - IA5String = object; - - if (![IA5String->_IA5StringValue isEqual: _IA5StringValue]) - return false; - - return true; -} - -- (unsigned long)hash -{ - return _IA5StringValue.hash; -} - -- (OFString *)description -{ - return [OFString stringWithFormat: @"", - _IA5StringValue]; -} -@end DELETED src/OFASN1Integer.h Index: src/OFASN1Integer.h ================================================================== --- src/OFASN1Integer.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "OFASN1Value.h" - -OF_ASSUME_NONNULL_BEGIN - -/** - * @brief An ASN.1 Integer. - */ -OF_SUBCLASSING_RESTRICTED -@interface OFASN1Integer: OFObject -{ - long long _longLongValue; -} - -/** - * @brief The Integer value. - */ -@property (readonly, nonatomic) long long longLongValue; - -/** - * @brief Creates an ASN.1 Integer with the specified integer value. - * - * @param value The `long long` value of the Integer - * @return A new, autoreleased OFASN1Integer - */ -+ (instancetype)integerWithLongLong: (long long)value; - -- (instancetype)init OF_UNAVAILABLE; - -/** - * @brief Initializes an already allocated ASN.1 Integer with the specified - * integer value. - * - * @param value The `long long` value of the Integer - * @return An initialized OFASN1Integer - */ -- (instancetype)initWithLongLong: (long long)value OF_DESIGNATED_INITIALIZER; - -/** - * @brief Initializes an already allocated ASN.1 Integer with the specified - * arguments. - * - * @param tagClass The tag class of the value's type - * @param tagNumber The tag number of the value's type - * @param constructed Whether the value if of a constructed type - * @param DEREncodedContents The DER-encoded contents octets of the value. - * @return An initialized OFASN1Integer - */ -- (instancetype)initWithTagClass: (of_asn1_tag_class_t)tagClass - tagNumber: (of_asn1_tag_number_t)tagNumber - constructed: (bool)constructed - DEREncodedContents: (OFData *)DEREncodedContents; -@end - -OF_ASSUME_NONNULL_END DELETED src/OFASN1Integer.m Index: src/OFASN1Integer.m ================================================================== --- src/OFASN1Integer.m +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "OFASN1Integer.h" -#import "OFData.h" -#import "OFString.h" - -#import "OFInvalidArgumentException.h" -#import "OFInvalidFormatException.h" -#import "OFOutOfRangeException.h" - -long long -of_asn1_der_integer_parse(const unsigned char *buffer, size_t length) -{ - unsigned long long value = 0; - - /* TODO: Support for big numbers */ - if (length > sizeof(unsigned long long) && - (length != sizeof(unsigned long long) + 1 || buffer[0] != 0)) - @throw [OFOutOfRangeException exception]; - - if (length >= 2 && ((buffer[0] == 0 && !(buffer[1] & 0x80)) || - (buffer[0] == 0xFF && buffer[1] & 0x80))) - @throw [OFInvalidFormatException exception]; - - if (length >= 1 && buffer[0] & 0x80) - value = ~0ull; - - while (length--) - value = (value << 8) | *buffer++; - - return value; -} - -@implementation OFASN1Integer -@synthesize longLongValue = _longLongValue; - -+ (instancetype)integerWithLongLong: (long long)value -{ - return [[[self alloc] initWithLongLong: value] autorelease]; -} - -- (instancetype)initWithLongLong: (long long)value -{ - self = [super init]; - - _longLongValue = value; - - return self; -} - -- (instancetype)initWithTagClass: (of_asn1_tag_class_t)tagClass - tagNumber: (of_asn1_tag_number_t)tagNumber - constructed: (bool)constructed - DEREncodedContents: (OFData *)DEREncodedContents -{ - long long value; - - @try { - if (tagClass != OF_ASN1_TAG_CLASS_UNIVERSAL || - tagNumber != OF_ASN1_TAG_NUMBER_INTEGER || constructed) - @throw [OFInvalidArgumentException exception]; - - if (DEREncodedContents.itemSize != 1) - @throw [OFInvalidArgumentException exception]; - - value = of_asn1_der_integer_parse( - DEREncodedContents.items, DEREncodedContents.count); - } @catch (id e) { - [self release]; - @throw e; - } - - return [self initWithLongLong: value]; -} - -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - -- (bool)isEqual: (id)object -{ - OFASN1Integer *integer; - - if (object == self) - return true; - - if (![object isKindOfClass: [OFASN1Integer class]]) - return false; - - integer = object; - - if (integer->_longLongValue != _longLongValue) - return false; - - return true; -} - -- (unsigned long)hash -{ - return (unsigned long)_longLongValue; -} - -- (OFString *)description -{ - return [OFString stringWithFormat: @"", - _longLongValue]; -} -@end DELETED src/OFASN1NumericString.h Index: src/OFASN1NumericString.h ================================================================== --- src/OFASN1NumericString.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "OFASN1Value.h" - -OF_ASSUME_NONNULL_BEGIN - -@class OFString; - -/** - * @brief An ASN.1 NumericString. - */ -OF_SUBCLASSING_RESTRICTED -@interface OFASN1NumericString: OFObject -{ - OFString *_numericStringValue; -} - -/** - * @brief The NumericString value. - */ -@property (readonly, nonatomic) OFString *numericStringValue; - -/** - * @brief The string value. - */ -@property (readonly, nonatomic) OFString *stringValue; - -/** - * @brief Creates an NumericString with the specified string value. - * - * @param stringValue The string value of the NumericString - * @return A new, autoreleased OFASN1NumericString - */ -+ (instancetype)stringWithStringValue: (OFString *)stringValue; - -- (instancetype)init OF_UNAVAILABLE; - -/** - * @brief Initializes an already allocated NumericString with the specified - * string value. - * - * @param stringValue The string value of the NumericString - * @return An initialized OFASN1NumericString - */ -- (instancetype)initWithStringValue: (OFString *)stringValue - OF_DESIGNATED_INITIALIZER; - -/** - * @brief Initializes an already allocated ASN.1 NumericString with the - * specified arguments. - * - * @param tagClass The tag class of the value's type - * @param tagNumber The tag number of the value's type - * @param constructed Whether the value if of a constructed type - * @param DEREncodedContents The DER-encoded contents octets of the value. - * @return An initialized ASN.1 NumericString - */ -- (instancetype)initWithTagClass: (of_asn1_tag_class_t)tagClass - tagNumber: (of_asn1_tag_number_t)tagNumber - constructed: (bool)constructed - DEREncodedContents: (OFData *)DEREncodedContents; -@end - -OF_ASSUME_NONNULL_END DELETED src/OFASN1NumericString.m Index: src/OFASN1NumericString.m ================================================================== --- src/OFASN1NumericString.m +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "OFASN1NumericString.h" -#import "OFData.h" -#import "OFString.h" - -#import "OFInvalidArgumentException.h" -#import "OFInvalidEncodingException.h" - -@implementation OFASN1NumericString -@synthesize numericStringValue = _numericStringValue; - -+ (instancetype)stringWithStringValue: (OFString *)stringValue -{ - return [[[self alloc] initWithStringValue: stringValue] autorelease]; -} - -- (instancetype)initWithStringValue: (OFString *)stringValue -{ - self = [super init]; - - @try { - void *pool = objc_autoreleasePoolPush(); - const char *cString = stringValue.UTF8String; - size_t length = stringValue.UTF8StringLength; - - for (size_t i = 0; i < length; i++) - if (!of_ascii_isdigit(cString[i]) && cString[i] != ' ') - @throw [OFInvalidEncodingException exception]; - - _numericStringValue = [stringValue copy]; - - objc_autoreleasePoolPop(pool); - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (instancetype)initWithTagClass: (of_asn1_tag_class_t)tagClass - tagNumber: (of_asn1_tag_number_t)tagNumber - constructed: (bool)constructed - DEREncodedContents: (OFData *)DEREncodedContents -{ - void *pool = objc_autoreleasePoolPush(); - OFString *numericStringValue; - - @try { - if (tagClass != OF_ASN1_TAG_CLASS_UNIVERSAL || - tagNumber != OF_ASN1_TAG_NUMBER_NUMERIC_STRING || - constructed) - @throw [OFInvalidArgumentException exception]; - - if (DEREncodedContents.itemSize != 1) - @throw [OFInvalidArgumentException exception]; - - numericStringValue = [OFString - stringWithCString: DEREncodedContents.items - encoding: OF_STRING_ENCODING_ASCII - length: DEREncodedContents.count]; - } @catch (id e) { - [self release]; - @throw e; - } - - self = [self initWithStringValue: numericStringValue]; - - objc_autoreleasePoolPop(pool); - - return self; -} - -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - -- (void)dealloc -{ - [_numericStringValue release]; - - [super dealloc]; -} - -- (OFString *)stringValue -{ - return self.numericStringValue; -} - -- (bool)isEqual: (id)object -{ - OFASN1NumericString *numericString; - - if (object == self) - return true; - - if (![object isKindOfClass: [OFASN1NumericString class]]) - return false; - - numericString = object; - - if (![numericString->_numericStringValue isEqual: _numericStringValue]) - return false; - - return true; -} - -- (unsigned long)hash -{ - return _numericStringValue.hash; -} - -- (OFString *)description -{ - return [OFString stringWithFormat: @"", - _numericStringValue]; -} -@end DELETED src/OFASN1ObjectIdentifier.h Index: src/OFASN1ObjectIdentifier.h ================================================================== --- src/OFASN1ObjectIdentifier.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "OFASN1Value.h" - -OF_ASSUME_NONNULL_BEGIN - -@class OFArray OF_GENERIC(ObjetType); -@class OFNumber; - -/** - * @brief An ASN.1 ObjectIdentifier. - */ -OF_SUBCLASSING_RESTRICTED -@interface OFASN1ObjectIdentifier: OFObject -{ - OFArray OF_GENERIC(OFNumber *) *_subidentifiers; -} - -/** - * @brief The subidentifiers of the ObjectIdentifier. - */ -@property (readonly, nonatomic) OFArray OF_GENERIC(OFNumber *) *subidentifiers; - -/** - * @brief Creates an ASN.1 ObjectIdentifier with the specified subidentifiers. - * - * @param subidentifiers The subidentifiers of the ASN.1 ObjectIdentifier - * @return A new, autoreleased OFASN1ObjectIdentifier - */ -+ (instancetype)objectIdentifierWithSubidentifiers: - (OFArray OF_GENERIC(OFNumber *) *)subidentifiers; - -- (instancetype)init OF_UNAVAILABLE; - -/** - * @brief Initializes an already allocated ASN.1 ObjectIdentifier with the - * specified subidentifiers. - * - * @param subidentifiers The subidentifiers of the ASN.1 ObjectIdentifier - * @return An initialized OFASN1ObjectIdentifier - */ -- (instancetype)initWithSubidentifiers: - (OFArray OF_GENERIC(OFNumber *) *)subidentifiers OF_DESIGNATED_INITIALIZER; - -/** - * @brief Initializes an already allocated ASN.1 ObjectIdentifier with the - * specified arguments. - * - * @param tagClass The tag class of the value's type - * @param tagNumber The tag number of the value's type - * @param constructed Whether the value if of a constructed type - * @param DEREncodedContents The DER-encoded contents octets of the value. - * @return An initialized OFASN1ObjectIdentifier - */ -- (instancetype)initWithTagClass: (of_asn1_tag_class_t)tagClass - tagNumber: (of_asn1_tag_number_t)tagNumber - constructed: (bool)constructed - DEREncodedContents: (OFData *)DEREncodedContents; -@end - -OF_ASSUME_NONNULL_END DELETED src/OFASN1ObjectIdentifier.m Index: src/OFASN1ObjectIdentifier.m ================================================================== --- src/OFASN1ObjectIdentifier.m +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "OFASN1ObjectIdentifier.h" -#import "OFArray.h" -#import "OFData.h" -#import "OFNumber.h" -#import "OFString.h" - -#import "OFInvalidArgumentException.h" -#import "OFInvalidFormatException.h" -#import "OFOutOfRangeException.h" - -@implementation OFASN1ObjectIdentifier -@synthesize subidentifiers = _subidentifiers; - -+ (instancetype)objectIdentifierWithSubidentifiers: - (OFArray OF_GENERIC(OFNumber *) *)subidentifiers -{ - return [[[self alloc] - initWithSubidentifiers: subidentifiers] autorelease]; -} - -- (instancetype)initWithSubidentifiers: - (OFArray OF_GENERIC(OFNumber *) *)subidentifiers -{ - self = [super init]; - - @try { - if (subidentifiers.count < 1) - @throw [OFInvalidFormatException exception]; - - switch ([[subidentifiers objectAtIndex: 0] longLongValue]) { - case 0: - case 1: - case 2: - break; - default: - @throw [OFInvalidFormatException exception]; - } - - _subidentifiers = [subidentifiers copy]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (instancetype)initWithTagClass: (of_asn1_tag_class_t)tagClass - tagNumber: (of_asn1_tag_number_t)tagNumber - constructed: (bool)constructed - DEREncodedContents: (OFData *)DEREncodedContents -{ - void *pool = objc_autoreleasePoolPush(); - OFMutableArray OF_GENERIC(OFNumber *) *subidentifiers; - - @try { - const unsigned char *items = DEREncodedContents.items; - size_t count = DEREncodedContents.count; - unsigned long long value = 0; - uint_fast8_t bits = 0; - - if (tagClass != OF_ASN1_TAG_CLASS_UNIVERSAL || - tagNumber != OF_ASN1_TAG_NUMBER_OBJECT_IDENTIFIER || - constructed) - @throw [OFInvalidArgumentException exception]; - - if (DEREncodedContents.itemSize != 1 || count == 0) - @throw [OFInvalidArgumentException exception]; - - subidentifiers = [OFMutableArray array]; - - for (size_t i = 0; i < count; i++) { - if (bits == 0 && items[i] == 0x80) - @throw [OFInvalidFormatException exception]; - - value = (value << 7) | (items[i] & 0x7F); - bits += 7; - - if (bits > sizeof(unsigned long long) * 8) - @throw [OFOutOfRangeException exception]; - - if (items[i] & 0x80) - continue; - - if (subidentifiers.count == 0) { - if (value < 40) - [subidentifiers addObject: - [OFNumber numberWithInt: 0]]; - else if (value < 80) { - [subidentifiers addObject: - [OFNumber numberWithInt: 1]]; - value -= 40; - } else { - [subidentifiers addObject: - [OFNumber numberWithInt: 2]]; - value -= 80; - } - } - - [subidentifiers addObject: - [OFNumber numberWithUnsignedLongLong: value]]; - - value = 0; - bits = 0; - } - - if (items[count - 1] & 0x80) - @throw [OFInvalidFormatException exception]; - - [subidentifiers makeImmutable]; - } @catch (id e) { - [self release]; - @throw e; - } - - self = [self initWithSubidentifiers: subidentifiers]; - - objc_autoreleasePoolPop(pool); - - return self; -} - -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - -- (void)dealloc -{ - [_subidentifiers release]; - - [super dealloc]; -} - -- (bool)isEqual: (id)object -{ - OFASN1ObjectIdentifier *objectIdentifier; - - if (object == self) - return true; - - if (![object isKindOfClass: [OFASN1ObjectIdentifier class]]) - return false; - - objectIdentifier = object; - - if (![objectIdentifier->_subidentifiers isEqual: _subidentifiers]) - return false; - - return true; -} - -- (unsigned long)hash -{ - return _subidentifiers.hash; -} - -- (OFString *)description -{ - return [OFString stringWithFormat: - @"", - [_subidentifiers componentsJoinedByString: @"."]]; -} -@end DELETED src/OFASN1OctetString.h Index: src/OFASN1OctetString.h ================================================================== --- src/OFASN1OctetString.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "OFASN1Value.h" - -OF_ASSUME_NONNULL_BEGIN - -@class OFData; - -/** - * @brief An ASN.1 OctetString. - */ -OF_SUBCLASSING_RESTRICTED -@interface OFASN1OctetString: OFObject -{ - OFData *_octetStringValue; -} - -/** - * @brief The OctetString value. - */ -@property (readonly, nonatomic) OFData *octetStringValue; - -/** - * @brief Creates an OctetString with the specified value. - * - * @param octetStringValue The OctetString value - * @return A new, autoreleased OFASN1OctetString - */ -+ (instancetype)octetStringWithOctetStringValue: (OFData *)octetStringValue; - -- (instancetype)init OF_UNAVAILABLE; - -/** - * @brief Initializes an already allocated OctetString with the specified - * value. - * - * @param octetStringValue The OctetString value - * @return An initialized OFASN1OctetString - */ -- (instancetype)initWithOctetStringValue: (OFData *)octetStringValue - OF_DESIGNATED_INITIALIZER; - -/** - * @brief Initializes an already allocated ASN.1 OctetString with the specified - * arguments. - * - * @param tagClass The tag class of the value's type - * @param tagNumber The tag number of the value's type - * @param constructed Whether the value if of a constructed type - * @param DEREncodedContents The DER-encoded contents octets of the value. - * @return An initialized ASN.1 OctetString - */ -- (instancetype)initWithTagClass: (of_asn1_tag_class_t)tagClass - tagNumber: (of_asn1_tag_number_t)tagNumber - constructed: (bool)constructed - DEREncodedContents: (OFData *)DEREncodedContents; -@end - -OF_ASSUME_NONNULL_END DELETED src/OFASN1OctetString.m Index: src/OFASN1OctetString.m ================================================================== --- src/OFASN1OctetString.m +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "OFASN1OctetString.h" -#import "OFData.h" -#import "OFString.h" - -#import "OFInvalidArgumentException.h" - -@implementation OFASN1OctetString -@synthesize octetStringValue = _octetStringValue; - -+ (instancetype)octetStringWithOctetStringValue: (OFData *)octetStringValue -{ - return [[[self alloc] - initWithOctetStringValue: octetStringValue] autorelease]; -} - -- (instancetype)initWithOctetStringValue: (OFData *)octetStringValue -{ - self = [super init]; - - @try { - _octetStringValue = [octetStringValue copy]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (instancetype)initWithTagClass: (of_asn1_tag_class_t)tagClass - tagNumber: (of_asn1_tag_number_t)tagNumber - constructed: (bool)constructed - DEREncodedContents: (OFData *)DEREncodedContents -{ - @try { - if (tagClass != OF_ASN1_TAG_CLASS_UNIVERSAL || - tagNumber != OF_ASN1_TAG_NUMBER_OCTET_STRING || - constructed) - @throw [OFInvalidArgumentException exception]; - - if (DEREncodedContents.itemSize != 1) - @throw [OFInvalidArgumentException exception]; - } @catch (id e) { - [self release]; - @throw e; - } - - return [self initWithOctetStringValue: DEREncodedContents]; -} - -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - -- (void)dealloc -{ - [_octetStringValue release]; - - [super dealloc]; -} - -- (bool)isEqual: (id)object -{ - OFASN1OctetString *octetString; - - if (object == self) - return true; - - if (![object isKindOfClass: [OFASN1OctetString class]]) - return false; - - octetString = object; - - if (![octetString->_octetStringValue isEqual: _octetStringValue]) - return false; - - return true; -} - -- (unsigned long)hash -{ - return _octetStringValue.hash; -} - -- (OFString *)description -{ - return [OFString stringWithFormat: @"", - _octetStringValue]; -} -@end DELETED src/OFASN1PrintableString.h Index: src/OFASN1PrintableString.h ================================================================== --- src/OFASN1PrintableString.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "OFASN1Value.h" - -OF_ASSUME_NONNULL_BEGIN - -@class OFString; - -/** - * @brief An ASN.1 PrintableString. - */ -OF_SUBCLASSING_RESTRICTED -@interface OFASN1PrintableString: OFObject -{ - OFString *_printableStringValue; -} - -/** - * @brief The PrintableString value. - */ -@property (readonly, nonatomic) OFString *printableStringValue; - -/** - * @brief The string value. - */ -@property (readonly, nonatomic) OFString *stringValue; - -/** - * @brief Creates a PrintableString with the specified string value. - * - * @param stringValue The string value of the PrintableString - * @return A new, autoreleased OFASN1PrintableString - */ -+ (instancetype)stringWithStringValue: (OFString *)stringValue; - -- (instancetype)init OF_UNAVAILABLE; - -/** - * @brief Initializes an already allocated PrintableString with the specified - * string value. - * - * @param stringValue The string value of the PrintableString - * @return An initialized OFASN1PrintableString - */ -- (instancetype)initWithStringValue: (OFString *)stringValue - OF_DESIGNATED_INITIALIZER; - -/** - * @brief Initializes an already allocated ASN.1 PrintableString with the - * specified arguments. - * - * @param tagClass The tag class of the value's type - * @param tagNumber The tag number of the value's type - * @param constructed Whether the value if of a constructed type - * @param DEREncodedContents The DER-encoded contents octets of the value. - * @return An initialized OFASN1PrintableString - */ -- (instancetype)initWithTagClass: (of_asn1_tag_class_t)tagClass - tagNumber: (of_asn1_tag_number_t)tagNumber - constructed: (bool)constructed - DEREncodedContents: (OFData *)DEREncodedContents; -@end - -OF_ASSUME_NONNULL_END DELETED src/OFASN1PrintableString.m Index: src/OFASN1PrintableString.m ================================================================== --- src/OFASN1PrintableString.m +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "OFASN1PrintableString.h" -#import "OFData.h" -#import "OFString.h" - -#import "OFInvalidArgumentException.h" -#import "OFInvalidEncodingException.h" - -@implementation OFASN1PrintableString -@synthesize printableStringValue = _printableStringValue; - -+ (instancetype)stringWithStringValue: (OFString *)stringValue -{ - return [[[self alloc] initWithStringValue: stringValue] autorelease]; -} - -- (instancetype)initWithStringValue: (OFString *)stringValue -{ - self = [super init]; - - @try { - void *pool = objc_autoreleasePoolPush(); - const char *cString = stringValue.UTF8String; - size_t length = stringValue.UTF8StringLength; - - for (size_t i = 0; i < length; i++) { - if (of_ascii_isalnum(cString[i])) - continue; - - switch (cString[i]) { - case ' ': - case '\'': - case '(': - case ')': - case '+': - case ',': - case '-': - case '.': - case '/': - case ':': - case '=': - case '?': - continue; - default: - @throw [OFInvalidEncodingException exception]; - } - } - - _printableStringValue = [stringValue copy]; - - objc_autoreleasePoolPop(pool); - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (instancetype)initWithTagClass: (of_asn1_tag_class_t)tagClass - tagNumber: (of_asn1_tag_number_t)tagNumber - constructed: (bool)constructed - DEREncodedContents: (OFData *)DEREncodedContents -{ - void *pool = objc_autoreleasePoolPush(); - OFString *printableStringValue; - - @try { - if (tagClass != OF_ASN1_TAG_CLASS_UNIVERSAL || - tagNumber != OF_ASN1_TAG_NUMBER_PRINTABLE_STRING || - constructed) - @throw [OFInvalidArgumentException exception]; - - if (DEREncodedContents.itemSize != 1) - @throw [OFInvalidArgumentException exception]; - - printableStringValue = [OFString - stringWithCString: DEREncodedContents.items - encoding: OF_STRING_ENCODING_ASCII - length: DEREncodedContents.count]; - } @catch (id e) { - [self release]; - @throw e; - } - - self = [self initWithStringValue: printableStringValue]; - - objc_autoreleasePoolPop(pool); - - return self; -} - -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - -- (void)dealloc -{ - [_printableStringValue release]; - - [super dealloc]; -} - -- (OFString *)stringValue -{ - return self.printableStringValue; -} - -- (bool)isEqual: (id)object -{ - OFASN1PrintableString *printableString; - - if (object == self) - return true; - - if (![object isKindOfClass: [OFASN1PrintableString class]]) - return false; - - printableString = object; - - if (![printableString->_printableStringValue isEqual: - _printableStringValue]) - return false; - - return true; -} - -- (unsigned long)hash -{ - return _printableStringValue.hash; -} - -- (OFString *)description -{ - return [OFString stringWithFormat: @"", - _printableStringValue]; -} -@end DELETED src/OFASN1UTF8String.h Index: src/OFASN1UTF8String.h ================================================================== --- src/OFASN1UTF8String.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "OFASN1Value.h" - -OF_ASSUME_NONNULL_BEGIN - -@class OFString; - -/** - * @brief An ASN.1 UTF8String. - */ -OF_SUBCLASSING_RESTRICTED -@interface OFASN1UTF8String: OFObject -{ - OFString *_UTF8StringValue; -} - -/** - * @brief The UTF8String value. - */ -@property (readonly, nonatomic) OFString *UTF8StringValue; - -/** - * @brief The string value. - */ -@property (readonly, nonatomic) OFString *stringValue; - -/** - * @brief Creates a UTF8String with the specified string value. - * - * @param stringValue The string value of the UTF8String - * @return A new, autoreleased OFASN1UTF8String - */ -+ (instancetype)stringWithStringValue: (OFString *)stringValue; - -- (instancetype)init OF_UNAVAILABLE; - -/** - * @brief Initializes an already allocated UTF8String with the specified - * string value. - * - * @param stringValue The string value of the UTF8String - * @return An initialized OFASN1UTF8String - */ -- (instancetype)initWithStringValue: (OFString *)stringValue - OF_DESIGNATED_INITIALIZER; - -/** - * @brief Initializes an already allocated ASN.1 UTF8String with the specified - * arguments. - * - * @param tagClass The tag class of the value's type - * @param tagNumber The tag number of the value's type - * @param constructed Whether the value if of a constructed type - * @param DEREncodedContents The DER-encoded contents octets of the value. - * @return An initialized OFASN1UTF8String - */ -- (instancetype)initWithTagClass: (of_asn1_tag_class_t)tagClass - tagNumber: (of_asn1_tag_number_t)tagNumber - constructed: (bool)constructed - DEREncodedContents: (OFData *)DEREncodedContents; -@end - -OF_ASSUME_NONNULL_END DELETED src/OFASN1UTF8String.m Index: src/OFASN1UTF8String.m ================================================================== --- src/OFASN1UTF8String.m +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "OFASN1UTF8String.h" -#import "OFData.h" -#import "OFString.h" - -#import "OFInvalidArgumentException.h" - -@implementation OFASN1UTF8String -@synthesize UTF8StringValue = _UTF8StringValue; - -+ (instancetype)stringWithStringValue: (OFString *)stringValue -{ - return [[[self alloc] initWithStringValue: stringValue] autorelease]; -} - -- (instancetype)initWithStringValue: (OFString *)stringValue -{ - self = [super init]; - - @try { - _UTF8StringValue = [stringValue copy]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (instancetype)initWithTagClass: (of_asn1_tag_class_t)tagClass - tagNumber: (of_asn1_tag_number_t)tagNumber - constructed: (bool)constructed - DEREncodedContents: (OFData *)DEREncodedContents -{ - void *pool = objc_autoreleasePoolPush(); - OFString *UTF8StringValue; - - @try { - if (tagClass != OF_ASN1_TAG_CLASS_UNIVERSAL || - tagNumber != OF_ASN1_TAG_NUMBER_UTF8_STRING || constructed) - @throw [OFInvalidArgumentException exception]; - - if (DEREncodedContents.itemSize != 1) - @throw [OFInvalidArgumentException exception]; - - UTF8StringValue = [OFString - stringWithUTF8String: DEREncodedContents.items - length: DEREncodedContents.count]; - } @catch (id e) { - [self release]; - @throw e; - } - - self = [self initWithStringValue: UTF8StringValue]; - - objc_autoreleasePoolPop(pool); - - return self; -} - -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - -- (void)dealloc -{ - [_UTF8StringValue release]; - - [super dealloc]; -} - -- (OFString *)stringValue -{ - return self.UTF8StringValue; -} - -- (bool)isEqual: (id)object -{ - OFASN1UTF8String *UTF8String; - - if (object == self) - return true; - - if (![object isKindOfClass: [OFASN1UTF8String class]]) - return false; - - UTF8String = object; - - if (![UTF8String->_UTF8StringValue isEqual: _UTF8StringValue]) - return false; - - return true; -} - -- (unsigned long)hash -{ - return _UTF8StringValue.hash; -} - -- (OFString *)description -{ - return [OFString stringWithFormat: @"", - _UTF8StringValue]; -} -@end DELETED src/OFASN1Value.h Index: src/OFASN1Value.h ================================================================== --- src/OFASN1Value.h +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 - -/** @file */ - -@class OFData; - -/** - * @brief ASN.1 tag class. - */ -typedef enum { - /** Universal */ - OF_ASN1_TAG_CLASS_UNIVERSAL = 0x0, - /** Application */ - OF_ASN1_TAG_CLASS_APPLICATION = 0x1, - /** Context specific */ - OF_ASN1_TAG_CLASS_CONTEXT_SPECIFIC = 0x2, - /** Private */ - OF_ASN1_TAG_CLASS_PRIVATE = 0x3 -} of_asn1_tag_class_t; - -/** - * @brief ASN.1 tag number. - */ -typedef enum { - /** Boolean */ - OF_ASN1_TAG_NUMBER_BOOLEAN = 0x01, - /** Integer */ - OF_ASN1_TAG_NUMBER_INTEGER = 0x02, - /** Bit string */ - OF_ASN1_TAG_NUMBER_BIT_STRING = 0x03, - /** Octet string */ - OF_ASN1_TAG_NUMBER_OCTET_STRING = 0x04, - /** Null */ - OF_ASN1_TAG_NUMBER_NULL = 0x05, - /** Object Identifier */ - OF_ASN1_TAG_NUMBER_OBJECT_IDENTIFIER = 0x06, - /** Enumerated */ - OF_ASN1_TAG_NUMBER_ENUMERATED = 0x0A, - /** UTF-8 string */ - OF_ASN1_TAG_NUMBER_UTF8_STRING = 0x0C, - /** Sequence */ - OF_ASN1_TAG_NUMBER_SEQUENCE = 0x10, - /** Set */ - OF_ASN1_TAG_NUMBER_SET = 0x11, - /** NumericString */ - OF_ASN1_TAG_NUMBER_NUMERIC_STRING = 0x12, - /** PrintableString */ - OF_ASN1_TAG_NUMBER_PRINTABLE_STRING = 0x13, - /** IA5String */ - OF_ASN1_TAG_NUMBER_IA5_STRING = 0x16 -} of_asn1_tag_number_t; - -/** - * @brief A class representing an ASN.1 value. - */ -OF_SUBCLASSING_RESTRICTED -@interface OFASN1Value: OFObject -{ - of_asn1_tag_class_t _tagClass; - of_asn1_tag_number_t _tagNumber; - bool _constructed; - OFData *_DEREncodedContents; -} - -/** - * @brief The tag class of the value's type. - */ -@property (readonly, nonatomic) of_asn1_tag_class_t tagClass; - -/** - * @brief The tag number of the value's type. - */ -@property (readonly, nonatomic) of_asn1_tag_number_t tagNumber; - -/** - * @brief Whether the value if of a constructed type. - */ -@property (readonly, nonatomic, getter=isConstructed) bool constructed; - -/** - * @brief The DER-encoded contents octets of the value. - */ -@property (readonly, nonatomic) OFData *DEREncodedContents; - -/** - * @brief Creates a new ASN.1 value with the specified arguments. - * - * @param tagClass The tag class of the value's type - * @param tagNumber The tag number of the value's type - * @param constructed Whether the value if of a constructed type - * @param DEREncodedContents The DER-encoded contents octets of the value. - * @return A new ASN.1 value - */ -+ (instancetype)valueWithTagClass: (of_asn1_tag_class_t)tagClass - tagNumber: (of_asn1_tag_number_t)tagNumber - constructed: (bool)constructed - DEREncodedContents: (OFData *)DEREncodedContents; - -- (instancetype)init OF_UNAVAILABLE; - -/** - * @brief Initializes an already allocated ASN.1 value with the specified - * arguments. - * - * @param tagClass The tag class of the value's type - * @param tagNumber The tag number of the value's type - * @param constructed Whether the value if of a constructed type - * @param DEREncodedContents The DER-encoded contents octets of the value. - * @return An initialized ASN.1 value - */ -- (instancetype)initWithTagClass: (of_asn1_tag_class_t)tagClass - tagNumber: (of_asn1_tag_number_t)tagNumber - constructed: (bool)constructed - DEREncodedContents: (OFData *)DEREncodedContents - OF_DESIGNATED_INITIALIZER; -@end - -OF_ASSUME_NONNULL_END DELETED src/OFASN1Value.m Index: src/OFASN1Value.m ================================================================== --- src/OFASN1Value.m +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "OFASN1Value.h" -#import "OFData.h" -#import "OFString.h" - -#import "OFInvalidFormatException.h" - -@implementation OFASN1Value -@synthesize tagClass = _tagClass, tagNumber = _tagNumber; -@synthesize constructed = _constructed; -@synthesize DEREncodedContents = _DEREncodedContents; - -+ (instancetype)valueWithTagClass: (of_asn1_tag_class_t)tagClass - tagNumber: (of_asn1_tag_number_t)tagNumber - constructed: (bool)constructed - DEREncodedContents: (OFData *)DEREncodedContents -{ - return [[[self alloc] - initWithTagClass: tagClass - tagNumber: tagNumber - constructed: constructed - DEREncodedContents: DEREncodedContents] autorelease]; -} - -- (instancetype)initWithTagClass: (of_asn1_tag_class_t)tagClass - tagNumber: (of_asn1_tag_number_t)tagNumber - constructed: (bool)constructed - DEREncodedContents: (OFData *)DEREncodedContents -{ - self = [super init]; - - @try { - if (DEREncodedContents.itemSize != 1) - @throw [OFInvalidFormatException exception]; - - _tagClass = tagClass; - _tagNumber = tagNumber; - _constructed = constructed; - _DEREncodedContents = [DEREncodedContents copy]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - -- (void)dealloc -{ - [_DEREncodedContents release]; - - [super dealloc]; -} - -- (bool)isEqual: (id)object -{ - OFASN1Value *value; - - if (object == self) - return true; - - if (![object isKindOfClass: [OFASN1Value class]]) - return false; - - value = object; - - if (value->_tagClass != _tagClass) - return false; - if (value->_tagNumber != _tagNumber) - return false; - if (value->_constructed != _constructed) - return false; - if (![value->_DEREncodedContents isEqual: _DEREncodedContents]) - return false; - - return true; -} - -- (unsigned long)hash -{ - uint32_t hash; - - OF_HASH_INIT(hash); - - OF_HASH_ADD(hash, _tagClass & 0xFF); - OF_HASH_ADD(hash, _tagNumber & 0xFF); - OF_HASH_ADD(hash, _constructed); - OF_HASH_ADD_HASH(hash, _DEREncodedContents.hash); - - OF_HASH_FINALIZE(hash); - - return hash; -} - -- (OFString *)description -{ - return [OFString stringWithFormat: - @"", - _tagClass, _tagNumber, _constructed, - _DEREncodedContents.description]; -} -@end ADDED src/OFASPrintF.h Index: src/OFASPrintF.h ================================================================== --- /dev/null +++ src/OFASPrintF.h @@ -0,0 +1,38 @@ +/* + * 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. + */ + +#ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS +#endif +#ifndef __STDC_CONSTANT_MACROS +# define __STDC_CONSTANT_MACROS +#endif + +#include + +#import "macros.h" + +OF_ASSUME_NONNULL_BEGIN + +#ifdef __cplusplus +extern "C" { +#endif +extern int OFVASPrintF( + char *_Nullable *_Nonnull, const char *_Nonnull, va_list); +#ifdef __cplusplus +} +#endif + +OF_ASSUME_NONNULL_END ADDED src/OFASPrintF.m Index: src/OFASPrintF.m ================================================================== --- /dev/null +++ src/OFASPrintF.m @@ -0,0 +1,783 @@ +/* + * 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 +#include +#include + +#ifdef HAVE_WCHAR_H +# include +#endif + +#ifdef HAVE_ASPRINTF_L +# include +#endif +#ifdef HAVE_XLOCALE_H +# include +#endif + +#ifdef OF_HAVE_SYS_TYPES_H +# include +#endif + +#import "OFString.h" +#import "OFLocale.h" + +#import "OFInitializationFailedException.h" + +#define maxSubformatLen 64 + +#ifndef HAVE_ASPRINTF +/* + * (v)asprintf might be declared, but HAVE_ASPRINTF not defined because + * configure determined it is broken. In this case, we must make sure there is + * no name clash. + */ +# define asprintf asprintf_ +# define vasprintf vasprintf_ +#endif + +struct Context { + const char *format; + size_t formatLen; + char subformat[maxSubformatLen + 1]; + size_t subformatLen; + va_list arguments; + char *buffer; + size_t bufferLen; + size_t i, last; + enum { + stateString, + stateFormatFlags, + stateFormatFieldWidth, + stateFormatLengthModifier, + stateFormatConversionSpecifier + } state; + enum { + lengthModifierNone, + lengthModifierHH, + lengthModifierH, + lengthModifierL, + lengthModifierLL, + lengthModifierJ, + lengthModifierZ, + lengthModifierT, + lengthModifierCapitalL + } lengthModifier; + bool useLocale; +}; + +#ifdef HAVE_ASPRINTF_L +static locale_t cLocale; + +OF_CONSTRUCTOR() +{ + if ((cLocale = newlocale(LC_ALL_MASK, "C", NULL)) == NULL) + @throw [OFInitializationFailedException exception]; +} +#endif + +#ifndef HAVE_ASPRINTF +static int +vasprintf(char **string, const char *format, va_list arguments) +{ + int length; + size_t bufferLength = 128; + + *string = NULL; + + for (;;) { + free(*string); + + if ((*string = malloc(bufferLength)) == NULL) + return -1; + + length = vsnprintf(*string, bufferLength - 1, format, + arguments); + + if (length >= 0 && (size_t)length < bufferLength - 1) + break; + + if (bufferLength > INT_MAX / 2) { + free(*string); + return -1; + } + + bufferLength <<= 1; + } + + if (length > 0 && (size_t)length != bufferLength - 1) { + char *resized = realloc(*string, length + 1); + + /* Ignore if making it smaller failed. */ + if (resized != NULL) + *string = resized; + } + + return length; +} + +static int +asprintf(char **string, const char *format, ...) +{ + int ret; + va_list arguments; + + va_start(arguments, format); + ret = vasprintf(string, format, arguments); + va_end(arguments); + + return ret; +} +#endif + +static bool +appendString(struct Context *ctx, const char *append, size_t appendLen) +{ + char *newBuf; + + if (appendLen == 0) + return true; + + if ((newBuf = realloc(ctx->buffer, + ctx->bufferLen + appendLen + 1)) == NULL) + return false; + + memcpy(newBuf + ctx->bufferLen, append, appendLen); + + ctx->buffer = newBuf; + ctx->bufferLen += appendLen; + + return true; +} + +static bool +appendSubformat(struct Context *ctx, const char *subformat, + size_t subformatLen) +{ + if (ctx->subformatLen + subformatLen > maxSubformatLen) + return false; + + memcpy(ctx->subformat + ctx->subformatLen, subformat, subformatLen); + ctx->subformatLen += subformatLen; + ctx->subformat[ctx->subformatLen] = 0; + + return true; +} + +static bool +stringState(struct Context *ctx) +{ + if (ctx->format[ctx->i] == '%') { + if (ctx->i > 0) + if (!appendString(ctx, ctx->format + ctx->last, + ctx->i - ctx->last)) + return false; + + if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) + return false; + + ctx->last = ctx->i + 1; + ctx->state = stateFormatFlags; + } + + return true; +} + +static bool +formatFlagsState(struct Context *ctx) +{ + switch (ctx->format[ctx->i]) { + case '-': + case '+': + case ' ': + case '#': + case '0': + if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) + return false; + + break; + case ',': + /* ObjFW extension: Use decimal point from locale */ + ctx->useLocale = true; + break; + default: + ctx->state = stateFormatFieldWidth; + ctx->i--; + + break; + } + + return true; +} + +static bool +formatFieldWidthState(struct Context *ctx) +{ + if ((ctx->format[ctx->i] >= '0' && ctx->format[ctx->i] <= '9') || + ctx->format[ctx->i] == '*' || ctx->format[ctx->i] == '.') { + if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) + return false; + } else { + ctx->state = stateFormatLengthModifier; + ctx->i--; + } + + return true; +} + +static bool +formatLengthModifierState(struct Context *ctx) +{ + /* Only one allowed */ + switch (ctx->format[ctx->i]) { + case 'h': /* and also hh */ + if (ctx->formatLen > ctx->i + 1 && + ctx->format[ctx->i + 1] == 'h') { + if (!appendSubformat(ctx, ctx->format + ctx->i, 2)) + return false; + + ctx->i++; + ctx->lengthModifier = lengthModifierHH; + } else { + if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) + return false; + + ctx->lengthModifier = lengthModifierH; + } + + break; + case 'l': /* and also ll */ + if (ctx->formatLen > ctx->i + 1 && + ctx->format[ctx->i + 1] == 'l') { +#ifndef OF_WINDOWS + if (!appendSubformat(ctx, ctx->format + ctx->i, 2)) + return false; +#else + if (!appendSubformat(ctx, "I64", 3)) + return false; +#endif + + ctx->i++; + ctx->lengthModifier = lengthModifierLL; + } else { + if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) + return false; + + ctx->lengthModifier = lengthModifierL; + } + + break; + case 'j': +#if defined(OF_WINDOWS) + if (!appendSubformat(ctx, "I64", 3)) + return false; +#elif defined(_NEWLIB_VERSION) || defined(OF_HPUX) + if (!appendSubformat(ctx, "ll", 2)) + return false; +#else + if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) + return false; +#endif + + ctx->lengthModifier = lengthModifierJ; + + break; + case 'z': +#if defined(OF_WINDOWS) + if (sizeof(size_t) == 8) + if (!appendSubformat(ctx, "I64", 3)) + return false; +#elif defined(_NEWLIB_VERSION) || defined(OF_HPUX) + if (!appendSubformat(ctx, "l", 1)) + return false; +#else + if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) + return false; +#endif + + ctx->lengthModifier = lengthModifierZ; + + break; + case 't': +#if defined(OF_WINDOWS) + if (sizeof(ptrdiff_t) == 8) + if (!appendSubformat(ctx, "I64", 3)) + return false; +#elif defined(_NEWLIB_VERSION) || defined(OF_HPUX) + if (!appendSubformat(ctx, "l", 1)) + return false; +#else + if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) + return false; +#endif + + ctx->lengthModifier = lengthModifierT; + + break; + case 'L': + if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) + return false; + + ctx->lengthModifier = lengthModifierCapitalL; + + break; +#ifdef OF_WINDOWS + case 'I': /* win32 strangeness (I64 instead of ll or j) */ + if (ctx->formatLen > ctx->i + 2 && + ctx->format[ctx->i + 1] == '6' && + ctx->format[ctx->i + 2] == '4') { + if (!appendSubformat(ctx, ctx->format + ctx->i, 3)) + return false; + + ctx->i += 2; + ctx->lengthModifier = lengthModifierLL; + } else + ctx->i--; + + break; +#endif +#ifdef OF_IOS + case 'q': /* iOS uses this for PRI?64 */ + if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) + return false; + + ctx->lengthModifier = lengthModifierLL; + + break; +#endif + default: + ctx->i--; + + break; + } + + ctx->state = stateFormatConversionSpecifier; + return true; +} + +static bool +formatConversionSpecifierState(struct Context *ctx) +{ + char *tmp = NULL; + int tmpLen = 0; +#ifndef HAVE_ASPRINTF_L + OFString *point; +#endif + + if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) + return false; + + switch (ctx->format[ctx->i]) { + case '@': + if (ctx->lengthModifier != lengthModifierNone) + return false; + + ctx->subformat[ctx->subformatLen - 1] = 's'; + + @try { + id object; + + if ((object = va_arg(ctx->arguments, id)) != nil) { + void *pool = objc_autoreleasePoolPush(); + + tmpLen = asprintf(&tmp, ctx->subformat, + [object description].UTF8String); + + objc_autoreleasePoolPop(pool); + } else + tmpLen = asprintf(&tmp, ctx->subformat, + "(nil)"); + } @catch (id e) { + free(ctx->buffer); + @throw e; + } + + break; + case 'C': + if (ctx->lengthModifier != lengthModifierNone) + return false; + + ctx->subformat[ctx->subformatLen - 1] = 's'; + + { + char buffer[5]; + size_t len = OFUTF8StringEncode( + va_arg(ctx->arguments, OFUnichar), buffer); + + if (len == 0) + return false; + + buffer[len] = 0; + tmpLen = asprintf(&tmp, ctx->subformat, buffer); + } + + break; + case 'S': + if (ctx->lengthModifier != lengthModifierNone) + return false; + + ctx->subformat[ctx->subformatLen - 1] = 's'; + + { + const OFUnichar *arg = + va_arg(ctx->arguments, const OFUnichar *); + size_t j, len = OFUTF32StringLength(arg); + char *buffer; + + if (SIZE_MAX / 4 < len || (SIZE_MAX / 4) - len < 1) + return false; + + if ((buffer = malloc((len * 4) + 1)) == NULL) + return false; + + j = 0; + for (size_t i = 0; i < len; i++) { + size_t clen = OFUTF8StringEncode(arg[i], + buffer + j); + + if (clen == 0) { + free(buffer); + return false; + } + + j += clen; + } + buffer[j] = 0; + + tmpLen = asprintf(&tmp, ctx->subformat, buffer); + + free(buffer); + } + + break; + case 'd': + case 'i': + switch (ctx->lengthModifier) { + case lengthModifierNone: + case lengthModifierHH: + case lengthModifierH: + tmpLen = asprintf(&tmp, ctx->subformat, + va_arg(ctx->arguments, int)); + break; + case lengthModifierL: + tmpLen = asprintf(&tmp, ctx->subformat, + va_arg(ctx->arguments, long)); + break; + case lengthModifierLL: + tmpLen = asprintf(&tmp, ctx->subformat, + va_arg(ctx->arguments, long long)); + break; + case lengthModifierJ: + tmpLen = asprintf(&tmp, ctx->subformat, + va_arg(ctx->arguments, intmax_t)); + break; + case lengthModifierZ: + tmpLen = asprintf(&tmp, ctx->subformat, + va_arg(ctx->arguments, ssize_t)); + break; + case lengthModifierT: + tmpLen = asprintf(&tmp, ctx->subformat, + va_arg(ctx->arguments, ptrdiff_t)); + break; + default: + return false; + } + + break; + case 'o': + case 'u': + case 'x': + case 'X': + switch (ctx->lengthModifier) { + case lengthModifierNone: + case lengthModifierHH: + case lengthModifierH: + tmpLen = asprintf(&tmp, ctx->subformat, + va_arg(ctx->arguments, unsigned int)); + break; + case lengthModifierL: + tmpLen = asprintf(&tmp, ctx->subformat, + va_arg(ctx->arguments, unsigned long)); + break; + case lengthModifierLL: + tmpLen = asprintf(&tmp, ctx->subformat, + va_arg(ctx->arguments, unsigned long long)); + break; + case lengthModifierJ: + tmpLen = asprintf(&tmp, ctx->subformat, + va_arg(ctx->arguments, uintmax_t)); + break; + case lengthModifierZ: + tmpLen = asprintf(&tmp, ctx->subformat, + va_arg(ctx->arguments, size_t)); + break; + case lengthModifierT: + tmpLen = asprintf(&tmp, ctx->subformat, + va_arg(ctx->arguments, ptrdiff_t)); + break; + default: + return false; + } + + break; + case 'f': + case 'F': + case 'e': + case 'E': + case 'g': + case 'G': + case 'a': + case 'A': + switch (ctx->lengthModifier) { + case lengthModifierNone: + case lengthModifierL: +#ifdef HAVE_ASPRINTF_L + if (!ctx->useLocale) + tmpLen = asprintf_l(&tmp, cLocale, + ctx->subformat, + va_arg(ctx->arguments, double)); + else +#endif + tmpLen = asprintf(&tmp, ctx->subformat, + va_arg(ctx->arguments, double)); + break; + case lengthModifierCapitalL: +#ifdef HAVE_ASPRINTF_L + if (!ctx->useLocale) + tmpLen = asprintf_l(&tmp, cLocale, + ctx->subformat, + va_arg(ctx->arguments, long double)); + else +#endif + tmpLen = asprintf(&tmp, ctx->subformat, + va_arg(ctx->arguments, long double)); + break; + default: + return false; + } + +#ifndef HAVE_ASPRINTF_L + 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 ".". + */ + point = [OFLocale decimalPoint]; + + if (!ctx->useLocale && point != nil && ![point isEqual: @"."]) { + void *pool = objc_autoreleasePoolPush(); + char *tmp2; + + @try { + OFMutableString *tmpStr = [OFMutableString + stringWithUTF8String: tmp + length: tmpLen]; + [tmpStr replaceOccurrencesOfString: point + withString: @"."]; + + if (tmpStr.UTF8StringLength > INT_MAX) + return false; + + tmpLen = (int)tmpStr.UTF8StringLength; + tmp2 = malloc(tmpLen); + memcpy(tmp2, tmpStr.UTF8String, tmpLen); + } @finally { + free(tmp); + objc_autoreleasePoolPop(pool); + } + + tmp = tmp2; + } +#endif + + break; + case 'c': + switch (ctx->lengthModifier) { + case lengthModifierNone: + tmpLen = asprintf(&tmp, ctx->subformat, + va_arg(ctx->arguments, int)); + break; + case lengthModifierL: +#ifdef HAVE_WCHAR_H +# if WINT_MAX >= INT_MAX + tmpLen = asprintf(&tmp, ctx->subformat, + va_arg(ctx->arguments, wint_t)); +# else + tmpLen = asprintf(&tmp, ctx->subformat, + va_arg(ctx->arguments, int)); +# endif + break; +#endif + default: + return false; + } + + break; + case 's': + switch (ctx->lengthModifier) { + case lengthModifierNone: + tmpLen = asprintf(&tmp, ctx->subformat, + va_arg(ctx->arguments, const char *)); + break; +#ifdef HAVE_WCHAR_T + case lengthModifierL: + tmpLen = asprintf(&tmp, ctx->subformat, + va_arg(ctx->arguments, const wchar_t *)); + break; +#endif + default: + return false; + } + + break; + case 'p': + if (ctx->lengthModifier != lengthModifierNone) + return false; + + tmpLen = asprintf(&tmp, ctx->subformat, + va_arg(ctx->arguments, void *)); + + break; + case 'n': + switch (ctx->lengthModifier) { + case lengthModifierNone: + *va_arg(ctx->arguments, int *) = (int)ctx->bufferLen; + break; + case lengthModifierHH: + *va_arg(ctx->arguments, signed char *) = + (signed char)ctx->bufferLen; + break; + case lengthModifierH: + *va_arg(ctx->arguments, short *) = + (short)ctx->bufferLen; + break; + case lengthModifierL: + *va_arg(ctx->arguments, long *) = + (long)ctx->bufferLen; + break; + case lengthModifierLL: + *va_arg(ctx->arguments, long long *) = + (long long)ctx->bufferLen; + break; + case lengthModifierJ: + *va_arg(ctx->arguments, intmax_t *) = + (intmax_t)ctx->bufferLen; + break; + case lengthModifierZ: + *va_arg(ctx->arguments, size_t *) = + (size_t)ctx->bufferLen; + break; + case lengthModifierT: + *va_arg(ctx->arguments, ptrdiff_t *) = + (ptrdiff_t)ctx->bufferLen; + break; + default: + return false; + } + + break; + case '%': + if (ctx->lengthModifier != lengthModifierNone) + return false; + + if (!appendString(ctx, "%", 1)) + return false; + + break; + default: + return false; + } + + if (tmpLen == -1) + return false; + + if (tmp != NULL) { + if (!appendString(ctx, tmp, tmpLen)) { + free(tmp); + return false; + } + + free(tmp); + } + + memset(ctx->subformat, 0, maxSubformatLen); + ctx->subformatLen = 0; + ctx->lengthModifier = lengthModifierNone; + ctx->useLocale = false; + + ctx->last = ctx->i + 1; + ctx->state = stateString; + + return true; +} + +static bool (*states[])(struct Context *) = { + stringState, + formatFlagsState, + formatFieldWidthState, + formatLengthModifierState, + formatConversionSpecifierState +}; + +int +OFVASPrintF(char **string, const char *format, va_list arguments) +{ + struct Context ctx; + + ctx.format = format; + ctx.formatLen = strlen(format); + memset(ctx.subformat, 0, maxSubformatLen + 1); + ctx.subformatLen = 0; + va_copy(ctx.arguments, arguments); + ctx.bufferLen = 0; + ctx.last = 0; + ctx.state = stateString; + ctx.lengthModifier = lengthModifierNone; + ctx.useLocale = false; + + if ((ctx.buffer = malloc(1)) == NULL) + return -1; + + for (ctx.i = 0; ctx.i < ctx.formatLen; ctx.i++) { + if (!states[ctx.state](&ctx)) { + free(ctx.buffer); + return -1; + } + } + + if (ctx.state != stateString) { + free(ctx.buffer); + return -1; + } + + if (!appendString(&ctx, ctx.format + ctx.last, + ctx.formatLen - ctx.last)) { + free(ctx.buffer); + return -1; + } + + ctx.buffer[ctx.bufferLen] = 0; + + *string = ctx.buffer; + return (ctx.bufferLen <= INT_MAX ? (int)ctx.bufferLen : -1); +} Index: src/OFAdjacentArray.h ================================================================== --- src/OFAdjacentArray.h +++ src/OFAdjacentArray.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFAdjacentArray.m ================================================================== --- src/OFAdjacentArray.m +++ src/OFAdjacentArray.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -61,12 +59,11 @@ } return self; } -- (instancetype)initWithObject: (id)firstObject - arguments: (va_list)arguments +- (instancetype)initWithObject: (id)firstObject arguments: (va_list)arguments { self = [self init]; @try { id object; @@ -109,12 +106,11 @@ @try { for (size_t i = 0; i < count; i++) [objects[i] retain]; - [_array addItems: objects - count: count]; + [_array addItems: objects count: count]; } @catch (id e) { for (size_t i = 0; i < count; i++) [objects[i] release]; /* Prevent double-release of objects */ @@ -126,12 +122,11 @@ } return self; } -- (instancetype)initWithObjects: (id const *)objects - count: (size_t)count +- (instancetype)initWithObjects: (id const *)objects count: (size_t)count { self = [self init]; @try { bool ok = true; @@ -144,12 +139,11 @@ } if (!ok) @throw [OFInvalidArgumentException exception]; - [_array addItems: objects - count: count]; + [_array addItems: objects count: count]; } @catch (id e) { for (size_t i = 0; i < count; i++) [objects[i] release]; [self release]; @@ -166,15 +160,15 @@ @try { void *pool = objc_autoreleasePoolPush(); if ((![element.name isEqual: @"OFArray"] && ![element.name isEqual: @"OFMutableArray"]) || - ![element.namespace isEqual: OF_SERIALIZATION_NS]) + ![element.namespace isEqual: OFSerializationNS]) @throw [OFInvalidArgumentException exception]; for (OFXMLElement *child in - [element elementsForNamespace: OF_SERIALIZATION_NS]) { + [element elementsForNamespace: OFSerializationNS]) { void *pool2 = objc_autoreleasePoolPush(); id object; object = child.objectByDeserializing; [_array addItem: &object]; @@ -210,12 +204,11 @@ - (id)objectAtIndexedSubscript: (size_t)idx { return *((id *)[_array itemAtIndex: idx]); } -- (void)getObjects: (id *)buffer - inRange: (of_range_t)range +- (void)getObjects: (id *)buffer inRange: (OFRange)range { id const *objects = _array.items; size_t count = _array.count; if (range.length > SIZE_MAX - range.location || @@ -230,42 +223,42 @@ { id const *objects; size_t count; if (object == nil) - return OF_NOT_FOUND; + return OFNotFound; objects = _array.items; count = _array.count; for (size_t i = 0; i < count; i++) if ([objects[i] isEqual: object]) return i; - return OF_NOT_FOUND; + return OFNotFound; } - (size_t)indexOfObjectIdenticalTo: (id)object { id const *objects; size_t count; if (object == nil) - return OF_NOT_FOUND; + return OFNotFound; objects = _array.items; count = _array.count; for (size_t i = 0; i < count; i++) if (objects[i] == object) return i; - return OF_NOT_FOUND; + return OFNotFound; } -- (OFArray *)objectsInRange: (of_range_t)range +- (OFArray *)objectsInRange: (OFRange)range { if (range.length > SIZE_MAX - range.location || range.location + range.length > _array.count) @throw [OFOutOfRangeException exception]; @@ -272,12 +265,11 @@ if ([self isKindOfClass: [OFMutableArray class]]) return [OFArray arrayWithObjects: (id *)_array.items + range.location count: range.length]; - return [OFAdjacentSubarray arrayWithArray: self - range: range]; + return [OFAdjacentSubarray arrayWithArray: self range: range]; } - (bool)isEqual: (id)object { OFArray *otherArray; @@ -310,23 +302,23 @@ - (unsigned long)hash { id const *objects = _array.items; size_t count = _array.count; - uint32_t hash; + unsigned long hash; - OF_HASH_INIT(hash); + OFHashInit(&hash); for (size_t i = 0; i < count; i++) - OF_HASH_ADD_HASH(hash, [objects[i] hash]); + OFHashAddHash(&hash, [objects[i] hash]); - OF_HASH_FINALIZE(hash); + OFHashFinalize(&hash); return hash; } -- (int)countByEnumeratingWithState: (of_fast_enumeration_state_t *)state +- (int)countByEnumeratingWithState: (OFFastEnumerationState *)state objects: (id *)objects count: (int)count_ { size_t count = _array.count; @@ -348,11 +340,11 @@ return (int)count; } #ifdef OF_HAVE_BLOCKS -- (void)enumerateObjectsUsingBlock: (of_array_enumeration_block_t)block +- (void)enumerateObjectsUsingBlock: (OFArrayEnumerationBlock)block { id const *objects = _array.items; size_t count = _array.count; bool stop = false; Index: src/OFAdjacentSubarray.h ================================================================== --- src/OFAdjacentSubarray.h +++ src/OFAdjacentSubarray.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFAdjacentSubarray.m ================================================================== --- src/OFAdjacentSubarray.m +++ src/OFAdjacentSubarray.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -53,15 +51,15 @@ return true; } #ifdef OF_HAVE_BLOCKS -- (void)enumerateObjectsUsingBlock: (of_array_enumeration_block_t)block +- (void)enumerateObjectsUsingBlock: (OFArrayEnumerationBlock)block { id const *objects = self.objects; bool stop = false; for (size_t i = 0; i < _range.length && !stop; i++) block(objects[i], i, &stop); } #endif @end Index: src/OFApplication.h ================================================================== --- src/OFApplication.h +++ src/OFApplication.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -16,10 +14,11 @@ */ #include #import "OFObject.h" +#import "OFNotification.h" OF_ASSUME_NONNULL_BEGIN /** @file */ @@ -28,10 +27,15 @@ @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 will terminate. + */ +extern const OFNotificationName OFApplicationWillTerminateNotification; + /** * @brief Specify the class to be used as the application delegate. * * An instance of this class will be created and act as the application * delegate. @@ -52,16 +56,16 @@ * [OFApplication terminate]; * } * @end * @endcode */ -#define OF_APPLICATION_DELEGATE(class_) \ - int \ - main(int argc, char *argv[]) \ - { \ - return of_application_main(&argc, &argv, \ - (class_ *)[[class_ alloc] init]); \ +#define OF_APPLICATION_DELEGATE(class_) \ + int \ + main(int argc, char *argv[]) \ + { \ + return OFApplicationMain(&argc, &argv, \ + (class_ *)[[class_ alloc] init]); \ } #ifdef OF_HAVE_PLEDGE # define OF_HAVE_SANDBOX #endif @@ -145,10 +149,14 @@ * @brief A class which represents the application as an object. * * 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 + * delegate and an @ref OFApplicationWillTerminateNotification will be sent. */ OF_SUBCLASSING_RESTRICTED @interface OFApplication: OFObject { OFString *_programName; @@ -200,18 +208,11 @@ */ @property OF_NULLABLE_PROPERTY (assign, nonatomic) id delegate; #ifdef OF_HAVE_SANDBOX -/** - * @brief The sandbox currently active for this application. - */ @property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFSandbox *activeSandbox; - -/** - * @brief The sandbox currently active for child processes of this application. - */ @property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFSandbox *activeSandboxForChildProcesses; #endif /** @@ -253,41 +254,12 @@ * @param status The status with which the application will terminate */ + (void)terminateWithStatus: (int)status OF_NO_RETURN; #ifdef OF_HAVE_SANDBOX -/** - * @brief Activates the specified sandbox for the application. - * - * This is only available if `OF_HAVE_SANDBOX` is defined. - * - * @warning If you allow `exec()`, but do not call - * @ref activateSandboxForChildProcesses:, an `exec()`'d process does - * not have its permissions restricted! - * - * @note Once a sandbox has been activated, you cannot activate a different - * sandbox. You can however change the active sandbox and reactivate it. - * - * @param sandbox The sandbox to activate - */ -+ (void)activateSandbox: (OFSandbox *)sandbox; - -/** - * @brief Activates the specified sandbox for child processes of the - * application. - * - * This is only available if `OF_HAVE_SANDBOX` is defined. - * - * `unveiledPaths` on the sandbox must *not* be empty, otherwise an - * @ref OFInvalidArgumentException is raised. - * - * @note Once a sandbox has been activated, you cannot activate a different - * sandbox. You can however change the active sandbox and reactivate it. - * - * @param sandbox The sandbox to activate - */ -+ (void)activateSandboxForChildProcesses: (OFSandbox *)sandbox; ++ (void)of_activateSandbox: (OFSandbox *)sandbox; ++ (void)of_activateSandboxForChildProcesses: (OFSandbox *)sandbox; #endif - (instancetype)init OF_UNAVAILABLE; /** @@ -310,49 +282,20 @@ * @param status The status with which the application will terminate */ - (void)terminateWithStatus: (int)status OF_NO_RETURN; #ifdef OF_HAVE_SANDBOX -/** - * @brief Activates the specified sandbox for the application. - * - * This is only available if `OF_HAVE_SANDBOX` is defined. - * - * @warning If you allow `exec()`, but do not call - * @ref activateSandboxForChildProcesses:, an `exec()`'d process does - * not have its permissions restricted! - * - * @note Once a sandbox has been activated, you cannot activate a different - * sandbox. You can however change the active sandbox and reactivate it. - * - * @param sandbox The sandbox to activate - */ -- (void)activateSandbox: (OFSandbox *)sandbox; - -/** - * @brief Activates the specified sandbox for child processes of the - * application. - * - * This is only available if `OF_HAVE_SANDBOX` is defined. - * - * `unveiledPaths` on the sandbox must *not* be empty, otherwise an - * @ref OFInvalidArgumentException is raised. - * - * @note Once a sandbox has been activated, you cannot activate a different - * sandbox. You can however change the active sandbox and reactivate it. - * - * @param sandbox The sandbox to activate - */ -- (void)activateSandboxForChildProcesses: (OFSandbox *)sandbox; +- (void)of_activateSandbox: (OFSandbox *)sandbox; +- (void)of_activateSandboxForChildProcesses: (OFSandbox *)sandbox; #endif @end #ifdef __cplusplus extern "C" { #endif -extern int of_application_main(int *_Nonnull, - char *_Nullable *_Nonnull[_Nonnull], id ); +extern int OFApplicationMain(int *_Nonnull, char *_Nullable *_Nonnull[_Nonnull], + id ); #ifdef __cplusplus } #endif OF_ASSUME_NONNULL_END Index: src/OFApplication.m ================================================================== --- src/OFApplication.m +++ src/OFApplication.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -32,10 +30,11 @@ #ifdef OF_AMIGAOS # import "OFFile.h" # import "OFFileManager.h" #endif #import "OFLocale.h" +#import "OFNotificationCenter.h" #import "OFPair.h" #import "OFRunLoop+Private.h" #import "OFRunLoop.h" #import "OFSandbox.h" #import "OFString.h" @@ -73,39 +72,46 @@ #endif OF_DIRECT_MEMBERS @interface OFApplication () - (instancetype)of_init OF_METHOD_FAMILY(init); +- (void)of_setArgumentCount: (int *)argc andArgumentValues: (char **[])argv; +#ifdef OF_WINDOWS - (void)of_setArgumentCount: (int *)argc - andArgumentValues: (char **[])argv; -#ifdef OF_WINDOWS -- (void)of_setArgumentCount: (int)argc - andWideArgumentValues: (wchar_t *[])argv; + andArgumentValues: (char **[])argv + andWideArgumentCount: (int)wargc + andWideArgumentValues: (wchar_t *[])wargv; #endif - (void)of_run; @end +const OFNotificationName OFApplicationWillTerminateNotification = + @"OFApplicationWillTerminateNotification"; static OFApplication *app = nil; static void atexitHandler(void) { id delegate = app.delegate; + + [[OFNotificationCenter defaultCenter] + postNotificationName: OFApplicationWillTerminateNotification + object: app]; if ([delegate respondsToSelector: @selector(applicationWillTerminate)]) [delegate applicationWillTerminate]; [delegate release]; -#if defined(OF_HAVE_THREADS) && defined(OF_HAVE_SOCKETS) && defined(OF_AMIGAOS) - of_socket_deinit(); +#if defined(OF_HAVE_THREADS) && defined(OF_HAVE_SOCKETS) && \ + defined(OF_AMIGAOS) && !defined(OF_MORPHOS) + OFSocketDeinit(); #endif } int -of_application_main(int *argc, char **argv[], - id delegate) +OFApplicationMain(int *argc, char **argv[], id delegate) { #ifdef OF_WINDOWS wchar_t **wargv, **wenvp; int wargc, si = 0; #endif @@ -115,16 +121,17 @@ app = [[OFApplication alloc] of_init]; #ifdef OF_WINDOWS if ([OFSystemInfo isWindowsNT]) { __wgetmainargs(&wargc, &wargv, &wenvp, _CRT_glob, &si); - [app of_setArgumentCount: wargc + [app of_setArgumentCount: argc + andArgumentValues: argv + andWideArgumentCount: wargc andWideArgumentValues: wargv]; } else #endif - [app of_setArgumentCount: argc - andArgumentValues: argv]; + [app of_setArgumentCount: argc andArgumentValues: argv]; app.delegate = delegate; [app of_run]; @@ -199,18 +206,18 @@ OF_UNREACHABLE #endif } #ifdef OF_HAVE_SANDBOX -+ (void)activateSandbox: (OFSandbox *)sandbox ++ (void)of_activateSandbox: (OFSandbox *)sandbox { - [app activateSandbox: sandbox]; + [app of_activateSandbox: sandbox]; } -+ (void)activateSandboxForChildProcesses: (OFSandbox *)sandbox ++ (void)of_activateSandboxForChildProcesses: (OFSandbox *)sandbox { - [app activateSandboxForChildProcesses: sandbox]; + [app of_activateSandboxForChildProcesses: sandbox]; } #endif - (instancetype)init { @@ -226,19 +233,19 @@ atexit(atexitHandler); #if defined(OF_WINDOWS) if ([OFSystemInfo isWindowsNT]) { - of_char16_t *env, *env0; + OFChar16 *env, *env0; env = env0 = GetEnvironmentStringsW(); while (*env != 0) { void *pool = objc_autoreleasePoolPush(); OFString *tmp, *key, *value; size_t length, pos; - length = of_string_utf16_length(env); + length = OFUTF16StringLength(env); tmp = [OFString stringWithUTF16String: env length: length]; env += length + 1; /* @@ -250,22 +257,20 @@ objc_autoreleasePoolPop(pool); continue; } pos = [tmp rangeOfString: @"="].location; - if (pos == OF_NOT_FOUND) { + if (pos == OFNotFound) { fprintf(stderr, "Warning: Invalid environment " "variable: %s\n", tmp.UTF8String); continue; } key = [tmp substringToIndex: pos]; - value = [tmp substringFromRange: pos + 1]; - - [_environment setObject: value - forKey: key]; + value = [tmp substringFromIndex: pos + 1]; + [_environment setObject: value forKey: key]; objc_autoreleasePoolPop(pool); } FreeEnvironmentStringsW(env0); @@ -294,22 +299,20 @@ objc_autoreleasePoolPop(pool); continue; } pos = [tmp rangeOfString: @"="].location; - if (pos == OF_NOT_FOUND) { + if (pos == OFNotFound) { fprintf(stderr, "Warning: Invalid environment " "variable: %s\n", tmp.UTF8String); continue; } key = [tmp substringToIndex: pos]; value = [tmp substringFromIndex: pos + 1]; - - [_environment setObject: value - forKey: key]; + [_environment setObject: value forKey: key]; objc_autoreleasePoolPop(pool); } FreeEnvironmentStringsA(env0); @@ -317,11 +320,11 @@ #elif defined(OF_AMIGAOS) void *pool = objc_autoreleasePoolPush(); OFFileManager *fileManager = [OFFileManager defaultManager]; OFArray *envContents = [fileManager contentsOfDirectoryAtPath: @"ENV:"]; - const of_string_encoding_t encoding = [OFLocale encoding]; + OFStringEncoding encoding = [OFLocale encoding]; struct Process *proc; struct LocalVar *firstLocalVar; for (OFString *name in envContents) { void *pool2 = objc_autoreleasePoolPush(); @@ -334,17 +337,15 @@ path = [@"ENV:" stringByAppendingString: name]; if ([fileManager directoryExistsAtPath: path]) continue; - file = [OFFile fileWithPath: path - mode: @"r"]; + file = [OFFile fileWithPath: path mode: @"r"]; value = [file readLineWithEncoding: encoding]; if (value != nil) - [_environment setObject: value - forKey: name]; + [_environment setObject: value forKey: name]; objc_autoreleasePoolPop(pool2); } /* Local variables override global variables */ @@ -373,13 +374,11 @@ encoding: encoding]; value = [OFString stringWithCString: (const char *)iter->lv_Value encoding: encoding length: length]; - - [_environment setObject: value - forKey: key]; + [_environment setObject: value forKey: key]; } objc_autoreleasePoolPop(pool); #elif !defined(OF_IOS) # ifndef OF_MACOS @@ -387,12 +386,11 @@ # else char **env = *_NSGetEnviron(); # endif if (env != NULL) { - const of_string_encoding_t encoding = - [OFLocale encoding]; + OFStringEncoding encoding = [OFLocale encoding]; for (; *env != NULL; env++) { void *pool = objc_autoreleasePoolPush(); OFString *key, *value; char *sep; @@ -408,13 +406,11 @@ encoding: encoding length: sep - *env]; value = [OFString stringWithCString: sep + 1 encoding: encoding]; - - [_environment setObject: value - forKey: key]; + [_environment setObject: value forKey: key]; objc_autoreleasePoolPop(pool); } } #else @@ -430,40 +426,35 @@ if ((env = getenv("HOME")) != NULL) { OFString *home = [[[OFString alloc] initWithUTF8StringNoCopy: env freeWhenDone: false] autorelease]; - [_environment setObject: home - forKey: @"HOME"]; + [_environment setObject: home forKey: @"HOME"]; } if ((env = getenv("PATH")) != NULL) { OFString *path = [[[OFString alloc] initWithUTF8StringNoCopy: env freeWhenDone: false] autorelease]; - [_environment setObject: path - forKey: @"PATH"]; + [_environment setObject: path forKey: @"PATH"]; } if ((env = getenv("SHELL")) != NULL) { OFString *shell = [[[OFString alloc] initWithUTF8StringNoCopy: env freeWhenDone: false] autorelease]; - [_environment setObject: shell - forKey: @"SHELL"]; + [_environment setObject: shell forKey: @"SHELL"]; } if ((env = getenv("TMPDIR")) != NULL) { OFString *tmpdir = [[[OFString alloc] initWithUTF8StringNoCopy: env freeWhenDone: false] autorelease]; - [_environment setObject: tmpdir - forKey: @"TMPDIR"]; + [_environment setObject: tmpdir forKey: @"TMPDIR"]; } if ((env = getenv("USER")) != NULL) { OFString *user = [[[OFString alloc] initWithUTF8StringNoCopy: env freeWhenDone: false] autorelease]; - [_environment setObject: user - forKey: @"USER"]; + [_environment setObject: user forKey: @"USER"]; } objc_autoreleasePoolPop(pool); #endif @@ -482,16 +473,15 @@ [_environment release]; [super dealloc]; } -- (void)of_setArgumentCount: (int *)argc - andArgumentValues: (char ***)argv +- (void)of_setArgumentCount: (int *)argc andArgumentValues: (char **[])argv { void *pool = objc_autoreleasePoolPush(); OFMutableArray *arguments; - of_string_encoding_t encoding; + OFStringEncoding encoding; _argc = argc; _argv = argv; encoding = [OFLocale encoding]; @@ -516,34 +506,38 @@ objc_autoreleasePoolPop(pool); } #ifdef OF_WINDOWS -- (void)of_setArgumentCount: (int)argc - andWideArgumentValues: (wchar_t **)argv +- (void)of_setArgumentCount: (int *)argc + andArgumentValues: (char **[])argv + andWideArgumentCount: (int)wargc + andWideArgumentValues: (wchar_t *[])wargv { void *pool = objc_autoreleasePoolPush(); OFMutableArray *arguments; - if (argc > 0) { - _programName = [[OFString alloc] initWithUTF16String: argv[0]]; + _argc = argc; + _argv = argv; + + if (wargc > 0) { + _programName = [[OFString alloc] initWithUTF16String: wargv[0]]; arguments = [[OFMutableArray alloc] init]; - for (int i = 1; i < argc; i++) + for (int i = 1; i < wargc; i++) [arguments addObject: - [OFString stringWithUTF16String: argv[i]]]; + [OFString stringWithUTF16String: wargv[i]]]; [arguments makeImmutable]; _arguments = arguments; } objc_autoreleasePoolPop(pool); } #endif -- (void)getArgumentCount: (int **)argc - andArgumentValues: (char ****)argv +- (void)getArgumentCount: (int **)argc andArgumentValues: (char ****)argv { *argc = _argc; *argv = _argv; } @@ -624,16 +618,16 @@ OF_UNREACHABLE } #ifdef OF_HAVE_SANDBOX -- (void)activateSandbox: (OFSandbox *)sandbox +- (void)of_activateSandbox: (OFSandbox *)sandbox { # ifdef OF_HAVE_PLEDGE void *pool = objc_autoreleasePoolPush(); - of_string_encoding_t encoding = [OFLocale encoding]; - OFArray OF_GENERIC(of_sandbox_unveil_path_t) *unveiledPaths; + OFStringEncoding encoding = [OFLocale encoding]; + OFArray OF_GENERIC(OFSandboxUnveilPath) *unveiledPaths; size_t unveiledPathsCount; const char *promises; if (_activeSandbox != nil && sandbox != _activeSandbox) @throw [OFInvalidArgumentException exception]; @@ -641,11 +635,11 @@ unveiledPaths = sandbox.unveiledPaths; unveiledPathsCount = unveiledPaths.count; for (size_t i = sandbox->_unveiledPathsIndex; i < unveiledPathsCount; i++) { - of_sandbox_unveil_path_t unveiledPath = + OFSandboxUnveilPath unveiledPath = [unveiledPaths objectAtIndex: i]; OFString *path = unveiledPath.firstObject; OFString *permissions = unveiledPath.secondObject; if (path == nil || permissions == nil) @@ -669,11 +663,11 @@ if (_activeSandbox == nil) _activeSandbox = [sandbox retain]; # endif } -- (void)activateSandboxForChildProcesses: (OFSandbox *)sandbox +- (void)of_activateSandboxForChildProcesses: (OFSandbox *)sandbox { # ifdef OF_HAVE_PLEDGE void *pool = objc_autoreleasePoolPush(); const char *promises; Index: src/OFArray+Private.h ================================================================== --- src/OFArray+Private.h +++ src/OFArray+Private.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFArray.h ================================================================== --- src/OFArray.h +++ src/OFArray.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -35,14 +33,29 @@ /** @file */ @class OFString; -enum { - OF_ARRAY_SKIP_EMPTY = 1, - OF_ARRAY_SORT_DESCENDING = 2 -}; +/** + * @brief Options for joining the objects of an array. + * + * This is a bit mask. + */ +typedef enum { + /** Skip empty components */ + OFArraySkipEmptyComponents = 1 +} OFArrayJoinOptions; + +/** + * @brief Options for sorting an array. + * + * This is a bit mask. + */ +typedef enum { + /** Sort the array descending */ + OFArraySortDescending = 1 +} OFArraySortOptions; #ifdef OF_HAVE_BLOCKS /** * @brief A block for enumerating an OFArray. * @@ -49,39 +62,38 @@ * @param object The current object * @param index The index of the current object * @param stop A pointer to a variable that can be set to true to stop the * enumeration */ -typedef void (^of_array_enumeration_block_t)(id object, size_t index, - bool *stop); +typedef void (^OFArrayEnumerationBlock)(id object, size_t index, bool *stop); /** * @brief A block for filtering an OFArray. * * @param object The object to inspect * @param index The index of the object to inspect * @return Whether the object should be in the filtered array */ -typedef bool (^of_array_filter_block_t)(id object, size_t index); +typedef bool (^OFArrayFilterBlock)(id object, size_t index); /** * @brief A block for mapping objects to objects in an OFArray. * * @param object The object to map * @param index The index of the object to map * @return The object to map to */ -typedef id _Nonnull (^of_array_map_block_t)(id object, size_t index); +typedef id _Nonnull (^OFArrayMapBlock)(id object, size_t index); /** * @brief A block for folding an OFArray. * * @param left The object to which the object has been folded so far * @param right The object that should be added to the left object * @return The left and right side folded into one object */ -typedef id _Nullable (^of_array_fold_block_t)(id _Nullable left, id right); +typedef id _Nullable (^OFArrayFoldBlock)(id _Nullable left, id right); #endif /** * @class OFArray OFArray.h ObjFW/OFArray.h * @@ -168,13 +180,12 @@ * * @param objects A C array of objects * @param count The length of the C array * @return A new autoreleased OFArray */ -+ (instancetype) - arrayWithObjects: (ObjectType const _Nonnull *_Nonnull)objects - count: (size_t)count; ++ (instancetype)arrayWithObjects: (ObjectType const _Nonnull *_Nonnull)objects + count: (size_t)count; /** * @brief Initializes an OFArray with the specified object. * * @param object An object @@ -217,10 +228,17 @@ * @return An initialized OFArray */ - (instancetype)initWithObjects: (ObjectType const _Nonnull *_Nonnull)objects count: (size_t)count; +/** + * @brief Returns an OFEnumerator to enumerate through all objects of the array. + * + * @return An OFEnumerator to enumerate through all objects of the array + */ +- (OFEnumerator OF_GENERIC(ObjectType) *)objectEnumerator; + /** * @brief Returns the object at the specified index in the array. * * @warning The returned object is *not* retained and autoreleased for * performance reasons! @@ -254,39 +272,38 @@ * @note A @ref OFNull value is translated to nil! * * @param value The value for the specified key * @param key The key of the value to set */ -- (void)setValue: (nullable id)value - forKey: (OFString *)key; +- (void)setValue: (nullable id)value forKey: (OFString *)key; /** * @brief Copies the objects at the specified range to the specified buffer. * * @param buffer The buffer to copy the objects to * @param range The range to copy */ - (void)getObjects: (ObjectType __unsafe_unretained _Nonnull *_Nonnull)buffer - inRange: (of_range_t)range; + inRange: (OFRange)range; /** * @brief Returns the index of the first object that is equivalent to the - * specified object or `OF_NOT_FOUND` if it was not found. + * specified object or `OFNotFound` if it was not found. * * @param object The object whose index is returned * @return The index of the first object equivalent to the specified object - * or `OF_NOT_FOUND` if it was not found + * or `OFNotFound` if it was not found */ - (size_t)indexOfObject: (ObjectType)object; /** * @brief Returns the index of the first object that has the same address as the - * specified object or `OF_NOT_FOUND` if it was not found. + * specified object or `OFNotFound` if it was not found. * * @param object The object whose index is returned * @return The index of the first object that has the same address as - * the specified object or `OF_NOT_FOUND` if it was not found + * the specified object or `OFNotFound` if it was not found */ - (size_t)indexOfObjectIdenticalTo: (ObjectType)object; /** * @brief Checks whether the array contains an object equal to the specified @@ -311,11 +328,11 @@ * @brief Returns the objects in the specified range as a new OFArray. * * @param range The range for the subarray * @return The subarray as a new autoreleased OFArray */ -- (OFArray OF_GENERIC(ObjectType) *)objectsInRange: (of_range_t)range; +- (OFArray OF_GENERIC(ObjectType) *)objectsInRange: (OFRange)range; /** * @brief Creates a string by joining all objects of the array. * * @param separator The string with which the objects should be joined @@ -325,19 +342,15 @@ /** * @brief Creates a string by joining all objects of the array. * * @param separator The string with which the objects should be joined - * @param options Options according to which the objects should be joined.@n - * Possible values are: - * Value | Description - * ----------------------|---------------------- - * `OF_ARRAY_SKIP_EMPTY` | Skip empty components + * @param options Options according to which the objects should be joined * @return A string containing all objects joined by the separator */ - (OFString *)componentsJoinedByString: (OFString *)separator - options: (int)options; + options: (OFArrayJoinOptions)options; /** * @brief Creates a string by calling the selector on all objects of the array * and joining the strings returned by calling the selector. * @@ -352,20 +365,16 @@ * @brief Creates a string by calling the selector on all objects of the array * and joining the strings returned by calling the selector. * * @param separator The string with which the objects should be joined * @param selector The selector to perform on the objects - * @param options Options according to which the objects should be joined.@n - * Possible values are: - * Value | Description - * ----------------------|---------------------- - * `OF_ARRAY_SKIP_EMPTY` | Skip empty components + * @param options Options according to which the objects should be joined * @return A string containing all objects joined by the separator */ - (OFString *)componentsJoinedByString: (OFString *)separator usingSelector: (SEL)selector - options: (int)options; + options: (OFArrayJoinOptions)options; /** * @brief Performs the specified selector on all objects in the array. * * @param selector The selector to perform on all objects in the array @@ -387,36 +396,29 @@ * @brief Returns a copy of the array sorted using the specified selector and * options. * * @param selector The selector to use to sort the array. It's signature * should be the same as that of -[compare:]. - * @param options The options to use when sorting the array.@n - * Possible values are: - * Value | Description - * ---------------------------|------------------------- - * `OF_ARRAY_SORT_DESCENDING` | Sort in descending order + * @param options The options to use when sorting the array * @return A sorted copy of the array */ -- (OFArray OF_GENERIC(ObjectType) *)sortedArrayUsingSelector: (SEL)selector - options: (int)options; +- (OFArray OF_GENERIC(ObjectType) *) + sortedArrayUsingSelector: (SEL)selector + options: (OFArraySortOptions)options; #ifdef OF_HAVE_BLOCKS /** * @brief Returns a copy of the array sorted using the specified selector and * options. * * @param comparator The comparator to use to sort the array - * @param options The options to use when sorting the array.@n - * Possible values are: - * Value | Description - * ---------------------------|------------------------- - * `OF_ARRAY_SORT_DESCENDING` | Sort in descending order + * @param options The options to use when sorting the array * @return A sorted copy of the array */ - (OFArray OF_GENERIC(ObjectType) *) - sortedArrayUsingComparator: (of_comparator_t)comparator - options: (int)options; + sortedArrayUsingComparator: (OFComparator)comparator + options: (OFArraySortOptions)options; #endif /** * @brief Creates a new array with the specified object added. * @@ -432,33 +434,25 @@ * @return A new array with the objects from the specified array added */ - (OFArray OF_GENERIC(ObjectType) *)arrayByAddingObjectsFromArray: (OFArray OF_GENERIC(ObjectType) *)array; -/** - * @brief Creates a new array with the specified object removed. - * - * @param object The object to remove - * @return A new array with the specified object removed - */ -- (OFArray OF_GENERIC(ObjectType) *)arrayByRemovingObject: (ObjectType)object; - #ifdef OF_HAVE_BLOCKS /** * @brief Executes a block for each object. * * @param block The block to execute for each object */ -- (void)enumerateObjectsUsingBlock: (of_array_enumeration_block_t)block; +- (void)enumerateObjectsUsingBlock: (OFArrayEnumerationBlock)block; /** * @brief Creates a new array, mapping each object using the specified block. * * @param block A block which maps an object for each object * @return A new, autoreleased OFArray */ -- (OFArray *)mappedArrayUsingBlock: (of_array_map_block_t)block; +- (OFArray *)mappedArrayUsingBlock: (OFArrayMapBlock)block; /** * @brief Creates a new array, only containing the objects for which the block * returns true. * @@ -465,11 +459,11 @@ * @param block A block which determines if the object should be in the new * array * @return A new, autoreleased OFArray */ - (OFArray OF_GENERIC(ObjectType) *)filteredArrayUsingBlock: - (of_array_filter_block_t)block; + (OFArrayFilterBlock)block; /** * @brief Folds the array to a single object using the specified block. * * If the array is empty, it will return `nil`. @@ -483,11 +477,11 @@ * * @param block A block which folds two objects into one, which is called for * all objects except the first * @return The array folded to a single object */ -- (nullable id)foldUsingBlock: (of_array_fold_block_t)block; +- (nullable id)foldUsingBlock: (OFArrayFoldBlock)block; #endif #if !defined(OF_HAVE_GENERICS) && !defined(DOXYGEN) # undef ObjectType #endif @end Index: src/OFArray.m ================================================================== --- src/OFArray.m +++ src/OFArray.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -38,12 +36,13 @@ static struct { Class isa; } placeholder; @interface OFArray () -- (OFString *)of_JSONRepresentationWithOptions: (int)options - depth: (size_t)depth; +- (OFString *) + of_JSONRepresentationWithOptions: (OFJSONRepresentationOptions)options + depth: (size_t)depth; @end @interface OFPlaceholderArray: OFArray @end @@ -195,12 +194,11 @@ { id ret; va_list arguments; va_start(arguments, firstObject); - ret = [self initWithObject: firstObject - arguments: arguments]; + ret = [self initWithObject: firstObject arguments: arguments]; va_end(arguments); return ret; } @@ -229,32 +227,35 @@ - (size_t)count { OF_UNRECOGNIZED_SELECTOR } -- (void)getObjects: (id *)buffer - inRange: (of_range_t)range +- (void)getObjects: (id *)buffer inRange: (OFRange)range { for (size_t i = 0; i < range.length; i++) buffer[i] = [self objectAtIndex: range.location + i]; } - (id const *)objects { - OFObject *container; - size_t count; - id *buffer; - - container = [[[OFObject alloc] init] autorelease]; - count = self.count; - buffer = [container allocMemoryWithSize: sizeof(*buffer) - count: count]; - - [self getObjects: buffer - inRange: of_range(0, count)]; - - return buffer; + size_t count = self.count; + id *buffer = OFAllocMemory(count, sizeof(id)); + id const *ret; + + @try { + [self getObjects: buffer inRange: OFRangeMake(0, count)]; + + ret = [[OFData dataWithItemsNoCopy: buffer + count: count + itemSize: sizeof(id) + freeWhenDone: true] items]; + } @catch (id e) { + OFFreeMemory(buffer); + @throw e; + } + + return ret; } - (id)copy { return [self retain]; @@ -296,60 +297,58 @@ [ret makeImmutable]; return ret; } -- (void)setValue: (id)value - forKey: (OFString *)key +- (void)setValue: (id)value forKey: (OFString *)key { for (id object in self) - [object setValue: value - forKey: key]; + [object setValue: value forKey: key]; } - (size_t)indexOfObject: (id)object { size_t i = 0; if (object == nil) - return OF_NOT_FOUND; + return OFNotFound; for (id objectIter in self) { if ([objectIter isEqual: object]) return i; i++; } - return OF_NOT_FOUND; + return OFNotFound; } - (size_t)indexOfObjectIdenticalTo: (id)object { size_t i = 0; if (object == nil) - return OF_NOT_FOUND; + return OFNotFound; for (id objectIter in self) { if (objectIter == object) return i; i++; } - return OF_NOT_FOUND; + return OFNotFound; } - (bool)containsObject: (id)object { - return ([self indexOfObject: object] != OF_NOT_FOUND); + return ([self indexOfObject: object] != OFNotFound); } - (bool)containsObjectIdenticalTo: (id)object { - return ([self indexOfObjectIdenticalTo: object] != OF_NOT_FOUND); + return ([self indexOfObjectIdenticalTo: object] != OFNotFound); } - (id)firstObject { if (self.count > 0) @@ -366,34 +365,29 @@ return [self objectAtIndex: count - 1]; return nil; } -- (OFArray *)objectsInRange: (of_range_t)range +- (OFArray *)objectsInRange: (OFRange)range { OFArray *ret; id *buffer; if (range.length > SIZE_MAX - range.location || range.location + range.length < self.count) @throw [OFOutOfRangeException exception]; if (![self isKindOfClass: [OFMutableArray class]]) - return [OFSubarray arrayWithArray: self - range: range]; + return [OFSubarray arrayWithArray: self range: range]; - buffer = [self allocMemoryWithSize: sizeof(*buffer) - count: range.length]; - + buffer = OFAllocMemory(range.length, sizeof(*buffer)); @try { - [self getObjects: buffer - inRange: range]; + [self getObjects: buffer inRange: range]; - ret = [OFArray arrayWithObjects: buffer - count: range.length]; + ret = [OFArray arrayWithObjects: buffer count: range.length]; } @finally { - [self freeMemory: buffer]; + OFFreeMemory(buffer); } return ret; } @@ -403,11 +397,11 @@ usingSelector: @selector(description) options: 0]; } - (OFString *)componentsJoinedByString: (OFString *)separator - options: (int)options + options: (OFArrayJoinOptions)options { return [self componentsJoinedByString: separator usingSelector: @selector(description) options: options]; } @@ -420,11 +414,11 @@ options: 0]; } - (OFString *)componentsJoinedByString: (OFString *)separator usingSelector: (SEL)selector - options: (int)options + options: (OFArrayJoinOptions)options { OFMutableString *ret; if (separator == nil) @throw [OFInvalidArgumentException exception]; @@ -432,21 +426,21 @@ if (self.count == 0) return @""; if (self.count == 1) { OFString *component = - [[self firstObject] performSelector: selector]; + [[self objectAtIndex: 0] performSelector: selector]; if (component == nil) @throw [OFInvalidArgumentException exception]; return component; } ret = [OFMutableString string]; - if (options & OF_ARRAY_SKIP_EMPTY) { + if (options & OFArraySkipEmptyComponents) { for (id object in self) { void *pool = objc_autoreleasePoolPush(); OFString *component = [object performSelector: selector]; @@ -515,18 +509,18 @@ return true; } - (unsigned long)hash { - uint32_t hash; + unsigned long hash; - OF_HASH_INIT(hash); + OFHashInit(&hash); for (id object in self) - OF_HASH_ADD_HASH(hash, [object hash]); + OFHashAddHash(&hash, [object hash]); - OF_HASH_FINALIZE(hash); + OFHashFinalize(&hash); return hash; } - (OFString *)description @@ -540,12 +534,11 @@ pool = objc_autoreleasePoolPush(); ret = [[self componentsJoinedByString: @",\n"] mutableCopy]; @try { [ret prependString: @"(\n"]; - [ret replaceOccurrencesOfString: @"\n" - withString: @"\n\t"]; + [ret replaceOccurrencesOfString: @"\n" withString: @"\n\t"]; [ret appendString: @"\n)"]; } @catch (id e) { [ret release]; @throw e; } @@ -562,14 +555,14 @@ void *pool = objc_autoreleasePoolPush(); OFXMLElement *element; if ([self isKindOfClass: [OFMutableArray class]]) element = [OFXMLElement elementWithName: @"OFMutableArray" - namespace: OF_SERIALIZATION_NS]; + namespace: OFSerializationNS]; else element = [OFXMLElement elementWithName: @"OFArray" - namespace: OF_SERIALIZATION_NS]; + namespace: OFSerializationNS]; for (id object in self) { void *pool2 = objc_autoreleasePoolPush(); [element addChild: object.XMLElementBySerializing]; @@ -584,28 +577,28 @@ return [element autorelease]; } - (OFString *)JSONRepresentation { - return [self of_JSONRepresentationWithOptions: 0 - depth: 0]; + return [self of_JSONRepresentationWithOptions: 0 depth: 0]; } -- (OFString *)JSONRepresentationWithOptions: (int)options +- (OFString *)JSONRepresentationWithOptions: + (OFJSONRepresentationOptions)options { - return [self of_JSONRepresentationWithOptions: options - depth: 0]; + return [self of_JSONRepresentationWithOptions: options depth: 0]; } -- (OFString *)of_JSONRepresentationWithOptions: (int)options - depth: (size_t)depth +- (OFString *) + of_JSONRepresentationWithOptions: (OFJSONRepresentationOptions)options + depth: (size_t)depth { OFMutableString *JSON = [OFMutableString stringWithString: @"["]; void *pool = objc_autoreleasePoolPush(); size_t i, count = self.count; - if (options & OF_JSON_REPRESENTATION_PRETTY) { + if (options & OFJSONRepresentationOptionPretty) { OFMutableString *indentation = [OFMutableString string]; for (i = 0; i < depth; i++) [indentation appendString: @"\t"]; @@ -666,22 +659,20 @@ if (count <= 15) { uint8_t tmp = 0x90 | ((uint8_t)count & 0xF); [data addItem: &tmp]; } else if (count <= UINT16_MAX) { uint8_t type = 0xDC; - uint16_t tmp = OF_BSWAP16_IF_LE((uint16_t)count); + uint16_t tmp = OFToBigEndian16((uint16_t)count); [data addItem: &type]; - [data addItems: &tmp - count: sizeof(tmp)]; + [data addItems: &tmp count: sizeof(tmp)]; } else if (count <= UINT32_MAX) { uint8_t type = 0xDD; - uint32_t tmp = OF_BSWAP32_IF_LE((uint32_t)count); + uint32_t tmp = OFToBigEndian32((uint32_t)count); [data addItem: &type]; - [data addItems: &tmp - count: sizeof(tmp)]; + [data addItems: &tmp count: sizeof(tmp)]; } else @throw [OFOutOfRangeException exception]; pool = objc_autoreleasePoolPush(); @@ -691,12 +682,11 @@ OFData *child; i++; child = [object messagePackRepresentation]; - [data addItems: child.items - count: child.count]; + [data addItems: child.items count: child.count]; objc_autoreleasePoolPop(pool2); } assert(i == count); @@ -716,78 +706,62 @@ - (void)makeObjectsPerformSelector: (SEL)selector withObject: (id)object { for (id objectIter in self) - [objectIter performSelector: selector - withObject: object]; + [objectIter performSelector: selector withObject: object]; } - (OFArray *)sortedArray { OFMutableArray *new = [[self mutableCopy] autorelease]; - [new sort]; - [new makeImmutable]; - return new; } - (OFArray *)sortedArrayUsingSelector: (SEL)selector - options: (int)options + options: (OFArraySortOptions)options { OFMutableArray *new = [[self mutableCopy] autorelease]; - - [new sortUsingSelector: selector - options: options]; - + [new sortUsingSelector: selector options: options]; [new makeImmutable]; - return new; } #ifdef OF_HAVE_BLOCKS -- (OFArray *)sortedArrayUsingComparator: (of_comparator_t)comparator - options: (int)options +- (OFArray *)sortedArrayUsingComparator: (OFComparator)comparator + options: (OFArraySortOptions)options { OFMutableArray *new = [[self mutableCopy] autorelease]; - - [new sortUsingComparator: comparator - options: options]; - + [new sortUsingComparator: comparator options: options]; [new makeImmutable]; - return new; } #endif - (OFArray *)reversedArray { OFMutableArray *new = [[self mutableCopy] autorelease]; - [new reverse]; - [new makeImmutable]; - return new; } -- (int)countByEnumeratingWithState: (of_fast_enumeration_state_t *)state +- (int)countByEnumeratingWithState: (OFFastEnumerationState *)state objects: (id *)objects count: (int)count { - of_range_t range = of_range(state->state, count); + OFRange range = OFRangeMake(state->state, count); if (range.length > SIZE_MAX - range.location) @throw [OFOutOfRangeException exception]; if (range.location + range.length > self.count) range.length = self.count - range.location; - [self getObjects: objects - inRange: range]; + [self getObjects: objects inRange: range]; if (range.location + range.length > ULONG_MAX) @throw [OFOutOfRangeException exception]; state->state = (unsigned long)(range.location + range.length); @@ -802,11 +776,11 @@ return [[[OFArrayEnumerator alloc] initWithArray: self mutationsPtr: NULL] autorelease]; } #ifdef OF_HAVE_BLOCKS -- (void)enumerateObjectsUsingBlock: (of_array_enumeration_block_t)block +- (void)enumerateObjectsUsingBlock: (OFArrayEnumerationBlock)block { size_t i = 0; bool stop = false; for (id object in self) { @@ -824,66 +798,51 @@ if (object == nil) @throw [OFInvalidArgumentException exception]; ret = [[self mutableCopy] autorelease]; - [ret addObject: object]; [ret makeImmutable]; return ret; } - (OFArray *)arrayByAddingObjectsFromArray: (OFArray *)array { OFMutableArray *ret = [[self mutableCopy] autorelease]; - [ret addObjectsFromArray: array]; [ret makeImmutable]; return ret; } -- (OFArray *)arrayByRemovingObject: (id)object -{ - OFMutableArray *ret = [[self mutableCopy] autorelease]; - - [ret removeObject: object]; - [ret makeImmutable]; - - return ret; -} - #ifdef OF_HAVE_BLOCKS -- (OFArray *)mappedArrayUsingBlock: (of_array_map_block_t)block +- (OFArray *)mappedArrayUsingBlock: (OFArrayMapBlock)block { OFArray *ret; size_t count = self.count; - id *tmp = [self allocMemoryWithSize: sizeof(id) - count: count]; + id *tmp = OFAllocMemory(count, sizeof(id)); @try { [self enumerateObjectsUsingBlock: ^ (id object, size_t idx, bool *stop) { tmp[idx] = block(object, idx); }]; - ret = [OFArray arrayWithObjects: tmp - count: count]; + ret = [OFArray arrayWithObjects: tmp count: count]; } @finally { - [self freeMemory: tmp]; + OFFreeMemory(tmp); } return ret; } -- (OFArray *)filteredArrayUsingBlock: (of_array_filter_block_t)block +- (OFArray *)filteredArrayUsingBlock: (OFArrayFilterBlock)block { OFArray *ret; size_t count = self.count; - id *tmp = [self allocMemoryWithSize: sizeof(id) - count: count]; + id *tmp = OFAllocMemory(count, sizeof(id)); @try { __block size_t i = 0; [self enumerateObjectsUsingBlock: ^ (id object, size_t idx, @@ -890,28 +849,27 @@ bool *stop) { if (block(object, idx)) tmp[i++] = object; }]; - ret = [OFArray arrayWithObjects: tmp - count: i]; + ret = [OFArray arrayWithObjects: tmp count: i]; } @finally { - [self freeMemory: tmp]; + OFFreeMemory(tmp); } return ret; } -- (id)foldUsingBlock: (of_array_fold_block_t)block +- (id)foldUsingBlock: (OFArrayFoldBlock)block { size_t count = self.count; __block id current; if (count == 0) return nil; if (count == 1) - return [[[self firstObject] retain] autorelease]; + return [[[self objectAtIndex: 0] retain] autorelease]; [self enumerateObjectsUsingBlock: ^ (id object, size_t idx, bool *stop) { id new; ADDED src/OFAtomic.h Index: src/OFAtomic.h ================================================================== --- /dev/null +++ src/OFAtomic.h @@ -0,0 +1,185 @@ +/* + * 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 + +#import "macros.h" + +#ifndef OF_HAVE_ATOMIC_OPS +# error No atomic operations available! +#endif + +#if !defined(OF_HAVE_THREADS) +static OF_INLINE int +OFAtomicIntAdd(volatile int *_Nonnull p, int i) +{ + return (*p += i); +} + +static OF_INLINE int32_t +OFAtomicInt32Add(volatile int32_t *_Nonnull p, int32_t i) +{ + return (*p += i); +} + +static OF_INLINE void *_Nullable +OFAtomicPointerAdd(void *volatile _Nullable *_Nonnull p, intptr_t i) +{ + return (*(char *volatile *)p += i); +} + +static OF_INLINE int +OFAtomicIntSubtract(volatile int *_Nonnull p, int i) +{ + return (*p -= i); +} + +static OF_INLINE int32_t +OFAtomicInt32Subtract(volatile int32_t *_Nonnull p, int32_t i) +{ + return (*p -= i); +} + +static OF_INLINE void *_Nullable +OFAtomicPointerSubtract(void *volatile _Nullable *_Nonnull p, intptr_t i) +{ + return (*(char *volatile *)p -= i); +} + +static OF_INLINE int +OFAtomicIntIncrease(volatile int *_Nonnull p) +{ + return ++*p; +} + +static OF_INLINE int32_t +OFAtomicInt32Increase(volatile int32_t *_Nonnull p) +{ + return ++*p; +} + +static OF_INLINE int +OFAtomicIntDecrease(volatile int *_Nonnull p) +{ + return --*p; +} + +static OF_INLINE int32_t +OFAtomicInt32Decrease(volatile int32_t *_Nonnull p) +{ + return --*p; +} + +static OF_INLINE unsigned int +OFAtomicIntOr(volatile unsigned int *_Nonnull p, unsigned int i) +{ + return (*p |= i); +} + +static OF_INLINE uint32_t +OFAtomicInt32Or(volatile uint32_t *_Nonnull p, uint32_t i) +{ + return (*p |= i); +} + +static OF_INLINE unsigned int +OFAtomicIntAnd(volatile unsigned int *_Nonnull p, unsigned int i) +{ + return (*p &= i); +} + +static OF_INLINE uint32_t +OFAtomicInt32And(volatile uint32_t *_Nonnull p, uint32_t i) +{ + return (*p &= i); +} + +static OF_INLINE unsigned int +OFAtomicIntXor(volatile unsigned int *_Nonnull p, unsigned int i) +{ + return (*p ^= i); +} + +static OF_INLINE uint32_t +OFAtomicInt32Xor(volatile uint32_t *_Nonnull p, uint32_t i) +{ + return (*p ^= i); +} + +static OF_INLINE bool +OFAtomicIntCompareAndSwap(volatile int *_Nonnull p, int o, int n) +{ + if (*p == o) { + *p = n; + return true; + } + + return false; +} + +static OF_INLINE bool +OFAtomicInt32CompareAndSwap(volatile int32_t *_Nonnull p, int32_t o, int32_t n) +{ + if (*p == o) { + *p = n; + return true; + } + + return false; +} + +static OF_INLINE bool +OFAtomicPointerCompareAndSwap(void *volatile _Nullable *_Nonnull p, + void *_Nullable o, void *_Nullable n) +{ + if (*p == o) { + *p = n; + return true; + } + + return false; +} + +static OF_INLINE void +OFMemoryBarrier(void) +{ + /* nop */ +} + +static OF_INLINE void +OFAcquireMemoryBarrier(void) +{ + /* nop */ +} + +static OF_INLINE void +OFReleaseMemoryBarrier(void) +{ + /* nop */ +} +#elif (defined(OF_X86_64) || 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) +# import "platform/GCC4.7/OFAtomic.h" +#elif defined(OF_HAVE_SYNC_BUILTINS) +# import "platform/GCC4/OFAtomic.h" +#elif defined(OF_HAVE_OSATOMIC) +# import "platform/macOS/OFAtomic.h" +#else +# error No atomic operations available! +#endif ADDED src/OFBase64.h Index: src/OFBase64.h ================================================================== --- /dev/null +++ src/OFBase64.h @@ -0,0 +1,39 @@ +/* + * 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. + */ + +#ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS +#endif +#ifndef __STDC_CONSTANT_MACROS +# define __STDC_CONSTANT_MACROS +#endif + +#import "macros.h" + +OF_ASSUME_NONNULL_BEGIN + +@class OFString; +@class OFMutableData; + +#ifdef __cplusplus +extern "C" { +#endif +extern OFString *OFBase64Encode(const void *, size_t); +extern bool OFBase64Decode(OFMutableData *, const char *, size_t); +#ifdef __cplusplus +} +#endif + +OF_ASSUME_NONNULL_END ADDED src/OFBase64.m Index: src/OFBase64.m ================================================================== --- /dev/null +++ src/OFBase64.m @@ -0,0 +1,156 @@ +/* + * 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 "OFBase64.h" +#import "OFString.h" +#import "OFData.h" + +static const unsigned char encodeTable[64] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', + 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', + 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', + 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '+', '/' +}; + +static const signed char decodeTable[128] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, 0, -1, -1, -1, 0, 1, 2, + 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, -1, -1, -1, -1, -1 +}; + +OFString * +OFBase64Encode(const void *data, size_t length) +{ + OFMutableString *ret = [OFMutableString string]; + uint8_t *buffer = (uint8_t *)data; + size_t i; + uint8_t rest; + char tb[4]; + uint32_t sb; + + rest = length % 3; + + for (i = 0; i < length - rest; i += 3) { + sb = (buffer[i] << 16) | (buffer[i + 1] << 8) | buffer[i + 2]; + + tb[0] = encodeTable[(sb & 0xFC0000) >> 18]; + tb[1] = encodeTable[(sb & 0x03F000) >> 12]; + tb[2] = encodeTable[(sb & 0x000FC0) >> 6]; + tb[3] = encodeTable[sb & 0x00003F]; + + [ret appendCString: tb + encoding: OFStringEncodingASCII + length: 4]; + } + + switch (rest) { + case 1: + tb[0] = encodeTable[buffer[i] >> 2]; + tb[1] = encodeTable[(buffer[i] & 3) << 4]; + tb[2] = tb[3] = '='; + + [ret appendCString: tb + encoding: OFStringEncodingASCII + length: 4]; + + break; + case 2: + sb = (buffer[i] << 16) | (buffer[i + 1] << 8); + + tb[0] = encodeTable[(sb & 0xFC0000) >> 18]; + tb[1] = encodeTable[(sb & 0x03F000) >> 12]; + tb[2] = encodeTable[(sb & 0x000FC0) >> 6]; + tb[3] = '='; + + [ret appendCString: tb + encoding: OFStringEncodingASCII + length: 4]; + + break; + } + + [ret makeImmutable]; + + return ret; +} + +bool +OFBase64Decode(OFMutableData *data, const char *string, size_t length) +{ + const uint8_t *buffer = (const uint8_t *)string; + size_t i; + + if ((length & 3) != 0) + return false; + + if (data.itemSize != 1) + return false; + + for (i = 0; i < length; i += 4) { + uint32_t sb = 0; + uint8_t count = 3; + char db[3]; + int8_t tmp; + + if (buffer[i] > 0x7F || buffer[i + 1] > 0x7F || + buffer[i + 2] > 0x7F || buffer[i + 3] > 0x7F) + return false; + + if (buffer[i] == '=' || buffer[i + 1] == '=' || + (buffer[i + 2] == '=' && buffer[i + 3] != '=')) + return false; + + if (buffer[i + 2] == '=') + count--; + if (buffer[i + 3] == '=') + count--; + + if ((tmp = decodeTable[buffer[i]]) == -1) + return false; + + sb |= tmp << 18; + + if ((tmp = decodeTable[buffer[i + 1]]) == -1) + return false; + + sb |= tmp << 12; + + if ((tmp = decodeTable[buffer[i + 2]]) == -1) + return false; + + sb |= tmp << 6; + + if ((tmp = decodeTable[buffer[i + 3]]) == -1) + return false; + + sb |= tmp; + + db[0] = (sb & 0xFF0000) >> 16; + db[1] = (sb & 0x00FF00) >> 8; + db[2] = sb & 0x0000FF; + + [data addItems: db count: count]; + } + + return true; +} Index: src/OFBitSetCharacterSet.h ================================================================== --- src/OFBitSetCharacterSet.h +++ src/OFBitSetCharacterSet.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFBitSetCharacterSet.m ================================================================== --- src/OFBitSetCharacterSet.m +++ src/OFBitSetCharacterSet.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -32,33 +30,33 @@ { self = [super init]; @try { void *pool = objc_autoreleasePoolPush(); - const of_unichar_t *characters = string.characters; + const OFUnichar *characters = string.characters; size_t length = string.length; for (size_t i = 0; i < length; i++) { - of_unichar_t c = characters[i]; + OFUnichar c = characters[i]; - if (c / 8 >= _size) { + if (c / CHAR_BIT >= _size) { size_t newSize; if (UINT32_MAX - c < 1) @throw [OFOutOfRangeException exception]; - newSize = OF_ROUND_UP_POW2(8, c + 1) / 8; + newSize = OFRoundUpToPowerOf2(CHAR_BIT, c + 1) / + CHAR_BIT; - _bitset = [self resizeMemory: _bitset - size: newSize]; + _bitset = OFResizeMemory(_bitset, newSize, 1); memset(_bitset + _size, '\0', newSize - _size); _size = newSize; } - of_bitset_set(_bitset, c); + OFBitsetSet(_bitset, c); } objc_autoreleasePoolPop(pool); } @catch (id e) { [self release]; @@ -66,13 +64,20 @@ } return self; } -- (bool)characterIsMember: (of_unichar_t)character +- (void)dealloc +{ + OFFreeMemory(_bitset); + + [super dealloc]; +} + +- (bool)characterIsMember: (OFUnichar)character { - if (character / 8 >= _size) + if (character / CHAR_BIT >= _size) return false; - return of_bitset_isset(_bitset, character); + return OFBitsetIsSet(_bitset, character); } @end Index: src/OFBlock.h ================================================================== --- src/OFBlock.h +++ src/OFBlock.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -15,12 +13,10 @@ * file. */ #import "OFObject.h" -#import "block.h" - OF_ASSUME_NONNULL_BEGIN /** * @class OFBlock OFBlock.h ObjFW/OFBlock.h * @@ -40,7 +36,39 @@ @end OF_SUBCLASSING_RESTRICTED @interface OFMallocBlock: OFBlock @end + +#ifdef __cplusplus +extern "C" { +#endif +extern void *_Nullable _Block_copy(const void *_Nullable); +extern void _Block_release(const void *_Nullable); + +# if defined(OF_WINDOWS) && \ + (defined(OF_NO_SHARED) || defined(OF_COMPILING_OBJFW)) +/* + * Clang has implicit declarations for these, but they are dllimport. When + * compiling ObjFW itself or using it as a static library, these need to be + * dllexport. Interestingly, this still works when using it as a shared library. + */ +extern __declspec(dllexport) struct objc_class _NSConcreteStackBlock; +extern __declspec(dllexport) struct objc_class _NSConcreteGlobalBlock; +extern __declspec(dllexport) void _Block_object_assign(void *, const void *, + const int); +extern __declspec(dllexport) void _Block_object_dispose(const void *, + const int); +# endif +#ifdef __cplusplus +} +#endif + +#ifndef Block_copy +# define Block_copy(...) \ + ((__typeof__(__VA_ARGS__))_Block_copy((const void *)(__VA_ARGS__))) +#endif +#ifndef Block_release +# define Block_release(...) _Block_release((const void *)(__VA_ARGS__)) +#endif OF_ASSUME_NONNULL_END Index: src/OFBlock.m ================================================================== --- src/OFBlock.m +++ src/OFBlock.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -20,50 +18,62 @@ #include #include #include #import "OFBlock.h" +#ifdef OF_HAVE_ATOMIC_OPS +# import "OFAtomic.h" +#endif +#ifdef OF_HAVE_THREADS +# import "OFPlainMutex.h" +#endif #import "OFAllocFailedException.h" #import "OFInitializationFailedException.h" #if defined(OF_OBJFW_RUNTIME) # import "runtime/private.h" #endif -#ifdef OF_HAVE_ATOMIC_OPS -# import "atomic.h" -#endif -#ifdef OF_HAVE_THREADS -# import "mutex.h" -#endif - -typedef struct of_block_byref_t of_block_byref_t; -struct of_block_byref_t { +struct Block { + Class isa; + int flags; + int reserved; + void (*invoke)(void *block, ...); + struct { + unsigned long reserved; + unsigned long size; + void (*_Nullable copyHelper)(void *dest, void *src); + void (*_Nullable disposeHelper)(void *src); + const char *signature; + } *descriptor; +}; + +struct Byref { Class isa; - of_block_byref_t *forwarding; + struct Byref *forwarding; int flags; int size; - void (*byref_keep)(void *dest, void *src); - void (*byref_dispose)(void *); -}; - -enum { - OF_BLOCK_HAS_COPY_DISPOSE = (1 << 25), - OF_BLOCK_HAS_CTOR = (1 << 26), - OF_BLOCK_IS_GLOBAL = (1 << 28), - OF_BLOCK_HAS_STRET = (1 << 29), - OF_BLOCK_HAS_SIGNATURE = (1 << 30) -}; -#define OF_BLOCK_REFCOUNT_MASK 0xFFFF - -enum { - OF_BLOCK_FIELD_IS_OBJECT = 3, - OF_BLOCK_FIELD_IS_BLOCK = 7, - OF_BLOCK_FIELD_IS_BYREF = 8, - OF_BLOCK_FIELD_IS_WEAK = 16, - OF_BLOCK_BYREF_CALLER = 128 + void (*keepByref)(void *dest, void *src); + void (*disposeByref)(void *); +}; + +enum { + OFBlockHasCopyDispose = (1 << 25), + OFBlockHasCtor = (1 << 26), + OFBlockIsGlobal = (1 << 28), + OFBlockHasStret = (1 << 29), + OFBlockHasSignature = (1 << 30) +}; +#define OFBlockRefCountMask 0xFFFF + +enum { + OFBlockFieldIsObject = 3, + OFBlockFieldIsBlock = 7, + OFBlockFieldIsByref = 8, + OFBlockFieldIsWeak = 16, + OFBlockByrefCaller = 128 }; @protocol RetainRelease - (instancetype)retain; - (void)release; @@ -76,11 +86,11 @@ sizeof(_NSConcreteStackBlock_metaclass), NULL, NULL }; struct objc_class _NSConcreteStackBlock = { &_NSConcreteStackBlock_metaclass, (Class)(void *)"OFBlock", - "OFStackBlock", 8, OBJC_CLASS_INFO_CLASS, sizeof(of_block_literal_t), + "OFStackBlock", 8, OBJC_CLASS_INFO_CLASS, sizeof(struct Block), NULL, NULL }; static struct objc_class _NSConcreteGlobalBlock_metaclass = { Nil, Nil, "OFGlobalBlock", 8, OBJC_CLASS_INFO_METACLASS, @@ -87,11 +97,11 @@ sizeof(_NSConcreteGlobalBlock_metaclass), NULL, NULL }; struct objc_class _NSConcreteGlobalBlock = { &_NSConcreteGlobalBlock_metaclass, (Class)(void *)"OFBlock", - "OFGlobalBlock", 8, OBJC_CLASS_INFO_CLASS, sizeof(of_block_literal_t), + "OFGlobalBlock", 8, OBJC_CLASS_INFO_CLASS, sizeof(struct Block), NULL, NULL }; static struct objc_class _NSConcreteMallocBlock_metaclass = { Nil, Nil, "OFMallocBlock", 8, OBJC_CLASS_INFO_METACLASS, @@ -98,11 +108,11 @@ sizeof(_NSConcreteMallocBlock_metaclass), NULL, NULL }; struct objc_class _NSConcreteMallocBlock = { &_NSConcreteMallocBlock_metaclass, (Class)(void *)"OFBlock", - "OFMallocBlock", 8, OBJC_CLASS_INFO_CLASS, sizeof(of_block_literal_t), + "OFMallocBlock", 8, OBJC_CLASS_INFO_CLASS, sizeof(struct Block), NULL, NULL }; static struct { unsigned long unknown; @@ -154,23 +164,23 @@ static struct { Class isa; } alloc_failed_exception; #ifndef OF_HAVE_ATOMIC_OPS -# define NUM_SPINLOCKS 8 /* needs to be a power of 2 */ -# define SPINLOCK_HASH(p) ((uintptr_t)p >> 4) & (NUM_SPINLOCKS - 1) -static of_spinlock_t blockSpinlocks[NUM_SPINLOCKS]; -static of_spinlock_t byrefSpinlocks[NUM_SPINLOCKS]; +# define numSpinlocks 8 /* needs to be a power of 2 */ +# define SPINLOCK_HASH(p) ((uintptr_t)p >> 4) & (numSpinlocks - 1) +static OFSpinlock blockSpinlocks[numSpinlocks]; +static OFSpinlock byrefSpinlocks[numSpinlocks]; #endif void * _Block_copy(const void *block_) { - of_block_literal_t *block = (of_block_literal_t *)block_; + struct Block *block = (struct Block *)block_; if ([(id)block isMemberOfClass: (Class)&_NSConcreteStackBlock]) { - of_block_literal_t *copy; + struct Block *copy; if ((copy = malloc(block->descriptor->size)) == NULL) { alloc_failed_exception.isa = [OFAllocFailedException class]; @throw (OFAllocFailedException *) @@ -179,196 +189,196 @@ memcpy(copy, block, block->descriptor->size); object_setClass((id)copy, (Class)&_NSConcreteMallocBlock); copy->flags++; - if (block->flags & OF_BLOCK_HAS_COPY_DISPOSE) - block->descriptor->copy_helper(copy, block); + if (block->flags & OFBlockHasCopyDispose) + block->descriptor->copyHelper(copy, block); return copy; } if ([(id)block isMemberOfClass: (Class)&_NSConcreteMallocBlock]) { #ifdef OF_HAVE_ATOMIC_OPS - of_atomic_int_inc(&block->flags); + OFAtomicIntIncrease(&block->flags); #else unsigned hash = SPINLOCK_HASH(block); - OF_ENSURE(of_spinlock_lock(&blockSpinlocks[hash])); + OFEnsure(OFSpinlockLock(&blockSpinlocks[hash]) == 0); block->flags++; - OF_ENSURE(of_spinlock_unlock(&blockSpinlocks[hash])); + OFEnsure(OFSpinlockUnlock(&blockSpinlocks[hash]) == 0); #endif } return block; } void _Block_release(const void *block_) { - of_block_literal_t *block = (of_block_literal_t *)block_; + struct Block *block = (struct Block *)block_; if (object_getClass((id)block) != (Class)&_NSConcreteMallocBlock) return; #ifdef OF_HAVE_ATOMIC_OPS - if ((of_atomic_int_dec(&block->flags) & OF_BLOCK_REFCOUNT_MASK) == 0) { - if (block->flags & OF_BLOCK_HAS_COPY_DISPOSE) - block->descriptor->dispose_helper(block); + if ((OFAtomicIntDecrease(&block->flags) & OFBlockRefCountMask) == 0) { + if (block->flags & OFBlockHasCopyDispose) + block->descriptor->disposeHelper(block); free(block); } #else unsigned hash = SPINLOCK_HASH(block); - OF_ENSURE(of_spinlock_lock(&blockSpinlocks[hash])); - if ((--block->flags & OF_BLOCK_REFCOUNT_MASK) == 0) { - OF_ENSURE(of_spinlock_unlock(&blockSpinlocks[hash])); + OFEnsure(OFSpinlockLock(&blockSpinlocks[hash]) == 0); + if ((--block->flags & OFBlockRefCountMask) == 0) { + OFEnsure(OFSpinlockUnlock(&blockSpinlocks[hash]) == 0); - if (block->flags & OF_BLOCK_HAS_COPY_DISPOSE) - block->descriptor->dispose_helper(block); + if (block->flags & OFBlockHasCopyDispose) + block->descriptor->disposeHelper(block); free(block); return; } - OF_ENSURE(of_spinlock_unlock(&blockSpinlocks[hash])); + OFEnsure(OFSpinlockUnlock(&blockSpinlocks[hash]) == 0); #endif } void _Block_object_assign(void *dst_, const void *src_, const int flags_) { - int flags = flags_ & (OF_BLOCK_FIELD_IS_BLOCK | - OF_BLOCK_FIELD_IS_OBJECT | OF_BLOCK_FIELD_IS_BYREF); + int flags = flags_ & (OFBlockFieldIsBlock | OFBlockFieldIsObject | + OFBlockFieldIsByref); if (src_ == NULL) return; switch (flags) { - case OF_BLOCK_FIELD_IS_BLOCK: - *(of_block_literal_t **)dst_ = _Block_copy(src_); + case OFBlockFieldIsBlock: + *(struct Block **)dst_ = _Block_copy(src_); break; - case OF_BLOCK_FIELD_IS_OBJECT: - if (!(flags_ & OF_BLOCK_BYREF_CALLER)) + case OFBlockFieldIsObject: + if (!(flags_ & OFBlockByrefCaller)) *(id *)dst_ = [(id)src_ retain]; break; - case OF_BLOCK_FIELD_IS_BYREF:; - of_block_byref_t *src = (of_block_byref_t *)src_; - of_block_byref_t **dst = (of_block_byref_t **)dst_; + case OFBlockFieldIsByref:; + struct Byref *src = (struct Byref *)src_; + struct Byref **dst = (struct Byref **)dst_; src = src->forwarding; - if ((src->flags & OF_BLOCK_REFCOUNT_MASK) == 0) { + if ((src->flags & OFBlockRefCountMask) == 0) { if ((*dst = malloc(src->size)) == NULL) { alloc_failed_exception.isa = [OFAllocFailedException class]; @throw (OFAllocFailedException *) &alloc_failed_exception; } memcpy(*dst, src, src->size); (*dst)->flags = - ((*dst)->flags & ~OF_BLOCK_REFCOUNT_MASK) | 1; + ((*dst)->flags & ~OFBlockRefCountMask) | 1; (*dst)->forwarding = *dst; - if (src->flags & OF_BLOCK_HAS_COPY_DISPOSE) - src->byref_keep(*dst, src); + if (src->flags & OFBlockHasCopyDispose) + src->keepByref(*dst, src); #ifdef OF_HAVE_ATOMIC_OPS - if (!of_atomic_ptr_cmpswap((void **)&src->forwarding, - src, *dst)) { - src->byref_dispose(*dst); + if (!OFAtomicPointerCompareAndSwap( + (void **)&src->forwarding, src, *dst)) { + src->disposeByref(*dst); free(*dst); *dst = src->forwarding; } #else unsigned hash = SPINLOCK_HASH(src); - OF_ENSURE(of_spinlock_lock(&byrefSpinlocks[hash])); + OFEnsure(OFSpinlockLock(&byrefSpinlocks[hash]) == 0); if (src->forwarding == src) src->forwarding = *dst; else { - src->byref_dispose(*dst); + src->disposeByref(*dst); free(*dst); *dst = src->forwarding; } - OF_ENSURE(of_spinlock_unlock(&byrefSpinlocks[hash])); + OFEnsure(OFSpinlockUnlock(&byrefSpinlocks[hash]) == 0); #endif } else *dst = src; #ifdef OF_HAVE_ATOMIC_OPS - of_atomic_int_inc(&(*dst)->flags); + OFAtomicIntIncrease(&(*dst)->flags); #else unsigned hash = SPINLOCK_HASH(*dst); - OF_ENSURE(of_spinlock_lock(&byrefSpinlocks[hash])); + OFEnsure(OFSpinlockLock(&byrefSpinlocks[hash]) == 0); (*dst)->flags++; - OF_ENSURE(of_spinlock_unlock(&byrefSpinlocks[hash])); + OFEnsure(OFSpinlockUnlock(&byrefSpinlocks[hash]) == 0); #endif break; } } void _Block_object_dispose(const void *object_, const int flags_) { - const int flags = flags_ & (OF_BLOCK_FIELD_IS_BLOCK | - OF_BLOCK_FIELD_IS_OBJECT | OF_BLOCK_FIELD_IS_BYREF); + const int flags = flags_ & (OFBlockFieldIsBlock | OFBlockFieldIsObject | + OFBlockFieldIsByref); if (object_ == NULL) return; switch (flags) { - case OF_BLOCK_FIELD_IS_BLOCK: + case OFBlockFieldIsBlock: _Block_release(object_); break; - case OF_BLOCK_FIELD_IS_OBJECT: - if (!(flags_ & OF_BLOCK_BYREF_CALLER)) + case OFBlockFieldIsObject: + if (!(flags_ & OFBlockByrefCaller)) [(id)object_ release]; break; - case OF_BLOCK_FIELD_IS_BYREF:; - of_block_byref_t *object = (of_block_byref_t *)object_; + case OFBlockFieldIsByref:; + struct Byref *object = (struct Byref *)object_; object = object->forwarding; #ifdef OF_HAVE_ATOMIC_OPS - if ((of_atomic_int_dec(&object->flags) & - OF_BLOCK_REFCOUNT_MASK) == 0) { - if (object->flags & OF_BLOCK_HAS_COPY_DISPOSE) - object->byref_dispose(object); + if ((OFAtomicIntDecrease(&object->flags) & + OFBlockRefCountMask) == 0) { + if (object->flags & OFBlockHasCopyDispose) + object->disposeByref(object); free(object); } #else unsigned hash = SPINLOCK_HASH(object); - OF_ENSURE(of_spinlock_lock(&byrefSpinlocks[hash])); - if ((--object->flags & OF_BLOCK_REFCOUNT_MASK) == 0) { - OF_ENSURE(of_spinlock_unlock(&byrefSpinlocks[hash])); + OFEnsure(OFSpinlockLock(&byrefSpinlocks[hash]) == 0); + if ((--object->flags & OFBlockRefCountMask) == 0) { + OFEnsure(OFSpinlockUnlock(&byrefSpinlocks[hash]) == 0); - if (object->flags & OF_BLOCK_HAS_COPY_DISPOSE) - object->byref_dispose(object); + if (object->flags & OFBlockHasCopyDispose) + object->disposeByref(object); free(object); } - OF_ENSURE(of_spinlock_unlock(&byrefSpinlocks[hash])); + OFEnsure(OFSpinlockUnlock(&byrefSpinlocks[hash]) == 0); #endif break; } } @implementation OFBlock + (void)load { #ifndef OF_HAVE_ATOMIC_OPS - for (size_t i = 0; i < NUM_SPINLOCKS; i++) - if (!of_spinlock_new(&blockSpinlocks[i]) || - !of_spinlock_new(&byrefSpinlocks[i])) + for (size_t i = 0; i < numSpinlocks; i++) + if (OFSpinlockNew(&blockSpinlocks[i]) != 0 || + OFSpinlockNew(&byrefSpinlocks[i]) != 0) @throw [OFInitializationFailedException exceptionWithClass: self]; #endif #ifdef OF_APPLE_RUNTIME @@ -437,39 +447,10 @@ - (instancetype)init { OF_INVALID_INIT_METHOD } -- (void *)allocMemoryWithSize: (size_t)size -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (void *)allocMemoryWithSize: (size_t)size - count: (size_t)count -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (void *)resizeMemory: (void *)ptr - size: (size_t)size -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (void *)resizeMemory: (void *)ptr - size: (size_t)size - count: (size_t)count -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (void)freeMemory: (void *)ptr -{ - OF_UNRECOGNIZED_SELECTOR -} - - (instancetype)retain { if ([self isMemberOfClass: (Class)&_NSConcreteMallocBlock]) return Block_copy(self); @@ -490,14 +471,13 @@ } - (unsigned int)retainCount { if ([self isMemberOfClass: (Class)&_NSConcreteMallocBlock]) - return ((of_block_literal_t *)self)->flags & - OF_BLOCK_REFCOUNT_MASK; + return ((struct Block *)self)->flags & OFBlockRefCountMask; - return OF_RETAIN_COUNT_MAX; + return OFMaxRetainCount; } - (void)release { if ([self isMemberOfClass: (Class)&_NSConcreteMallocBlock]) Index: src/OFBytesValue.h ================================================================== --- src/OFBytesValue.h +++ src/OFBytesValue.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFBytesValue.m ================================================================== --- src/OFBytesValue.m +++ src/OFBytesValue.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -27,13 +25,13 @@ objCType: (const char *)objCType { self = [super init]; @try { - _size = of_sizeof_type_encoding(objCType); + _size = OFSizeOfTypeEncoding(objCType); _objCType = objCType; - _bytes = [self allocMemoryWithSize: _size]; + _bytes = OFAllocMemory(1, _size); memcpy(_bytes, bytes, _size); } @catch (id e) { [self release]; @throw e; @@ -40,14 +38,20 @@ } return self; } -- (void)getValue: (void *)value - size: (size_t)size +- (void)dealloc +{ + OFFreeMemory(_bytes); + + [super dealloc]; +} + +- (void)getValue: (void *)value size: (size_t)size { if (size != _size) @throw [OFOutOfRangeException exception]; memcpy(value, _bytes, _size); } @end ADDED src/OFCRC16.h Index: src/OFCRC16.h ================================================================== --- /dev/null +++ src/OFCRC16.h @@ -0,0 +1,32 @@ +/* + * 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. + */ + +#ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS +#endif +#ifndef __STDC_CONSTANT_MACROS +# define __STDC_CONSTANT_MACROS +#endif + +#import "macros.h" + +#ifdef __cplusplus +extern "C" { +#endif +extern uint16_t OFCRC16(uint16_t crc, const void *_Nonnull bytes, + size_t length); +#ifdef __cplusplus +} +#endif ADDED src/OFCRC16.m Index: src/OFCRC16.m ================================================================== --- /dev/null +++ src/OFCRC16.m @@ -0,0 +1,35 @@ +/* + * 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 "OFCRC16.h" + +static const uint16_t CRC16Magic = 0xA001; + +uint16_t +OFCRC16(uint16_t CRC, const void *bytes_, size_t length) +{ + const unsigned char *bytes = bytes_; + + for (size_t i = 0; i < length; i++) { + CRC ^= bytes[i]; + + for (uint8_t j = 0; j < 8; j++) + CRC = (CRC >> 1) ^ (CRC16Magic & (~(CRC & 1) + 1)); + } + + return CRC; +} ADDED src/OFCRC32.h Index: src/OFCRC32.h ================================================================== --- /dev/null +++ src/OFCRC32.h @@ -0,0 +1,32 @@ +/* + * 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. + */ + +#ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS +#endif +#ifndef __STDC_CONSTANT_MACROS +# define __STDC_CONSTANT_MACROS +#endif + +#import "macros.h" + +#ifdef __cplusplus +extern "C" { +#endif +extern uint32_t OFCRC32(uint32_t crc, const void *_Nonnull bytes, + size_t length); +#ifdef __cplusplus +} +#endif ADDED src/OFCRC32.m Index: src/OFCRC32.m ================================================================== --- /dev/null +++ src/OFCRC32.m @@ -0,0 +1,35 @@ +/* + * 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 "OFCRC32.h" + +static const uint32_t CRC32Magic = 0xEDB88320; + +uint32_t +OFCRC32(uint32_t CRC, const void *bytes_, size_t length) +{ + const unsigned char *bytes = bytes_; + + for (size_t i = 0; i < length; i++) { + CRC ^= bytes[i]; + + for (uint8_t j = 0; j < 8; j++) + CRC = (CRC >> 1) ^ (CRC32Magic & (~(CRC & 1) + 1)); + } + + return CRC; +} Index: src/OFCharacterSet.h ================================================================== --- src/OFCharacterSet.h +++ src/OFCharacterSet.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -56,11 +54,11 @@ * range. * * @param range The range of characters for the character set * @return A new OFCharacterSet */ -+ (instancetype)characterSetWithRange: (of_range_t)range; ++ (instancetype)characterSetWithRange: (OFRange)range; /** * @brief A character set containing all Unicode characters in the category * `Zs` plus CHARACTER TABULATION (U+0009). */ @@ -80,19 +78,19 @@ * the specified range. * * @param range The range of characters for the character set * @return An initialized OFCharacterSet */ -- (instancetype)initWithRange: (of_range_t)range; +- (instancetype)initWithRange: (OFRange)range; /** * @brief Returns whether the specified character is a member of the character * set. * * @param character The character that is checked for being a member of the * character set * @return Whether the specified character is a member of the character set. */ -- (bool)characterIsMember: (of_unichar_t)character; +- (bool)characterIsMember: (OFUnichar)character; @end OF_ASSUME_NONNULL_END Index: src/OFCharacterSet.m ================================================================== --- src/OFCharacterSet.m +++ src/OFCharacterSet.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -18,14 +16,13 @@ #include "config.h" #import "OFCharacterSet.h" #import "OFBitSetCharacterSet.h" #import "OFInvertedCharacterSet.h" +#import "OFOnce.h" #import "OFRangeCharacterSet.h" -#import "once.h" - @interface OFPlaceholderCharacterSet: OFCharacterSet @end @interface OFWhitespaceCharacterSet: OFCharacterSet @end @@ -52,11 +49,11 @@ { return (id)[[OFBitSetCharacterSet alloc] initWithCharactersInString: characters]; } -- (instancetype)initWithRange: (of_range_t)range +- (instancetype)initWithRange: (OFRange)range { return (id)[[OFRangeCharacterSet alloc] initWithRange: range]; } - (instancetype)retain @@ -100,19 +97,19 @@ { return [[[self alloc] initWithCharactersInString: characters] autorelease]; } -+ (instancetype)characterSetWithRange: (of_range_t)range ++ (instancetype)characterSetWithRange: (OFRange)range { return [[[self alloc] initWithRange: range] autorelease]; } + (OFCharacterSet *)whitespaceCharacterSet { - static of_once_t onceControl = OF_ONCE_INIT; - of_once(&onceControl, initWhitespaceCharacterSet); + static OFOnceControl onceControl = OFOnceControlInitValue; + OFOnce(&onceControl, initWhitespaceCharacterSet); return whitespaceCharacterSet; } - (instancetype)init @@ -134,16 +131,16 @@ - (instancetype)initWithCharactersInString: (OFString *)characters { OF_INVALID_INIT_METHOD } -- (instancetype)initWithRange: (of_range_t)range +- (instancetype)initWithRange: (OFRange)range { OF_INVALID_INIT_METHOD } -- (bool)characterIsMember: (of_unichar_t)character +- (bool)characterIsMember: (OFUnichar)character { OF_UNRECOGNIZED_SELECTOR } - (OFCharacterSet *)invertedSet @@ -168,14 +165,14 @@ { } - (unsigned int)retainCount { - return OF_RETAIN_COUNT_MAX; + return OFMaxRetainCount; } -- (bool)characterIsMember: (of_unichar_t)character +- (bool)characterIsMember: (OFUnichar)character { switch (character) { case 0x0009: case 0x0020: case 0x00A0: Index: src/OFCollection.h ================================================================== --- src/OFCollection.h +++ src/OFCollection.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -22,11 +20,11 @@ /** * @protocol OFCollection OFCollection.h ObjFW/OFCollection.h * * @brief A protocol with methods common for all collections. */ -@protocol OFCollection +@protocol OFCollection /** * @brief The number of objects in the collection */ @property (readonly, nonatomic) size_t count; Index: src/OFColor.h ================================================================== --- src/OFColor.h +++ src/OFColor.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFColor.m ================================================================== --- src/OFColor.m +++ src/OFColor.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -16,34 +14,33 @@ */ #include "config.h" #import "OFColor.h" - -#import "once.h" +#import "OFOnce.h" #import "OFInvalidArgumentException.h" @implementation OFColor -#define PREDEFINED_COLOR(name, r, g, b) \ - static OFColor *name##Color = nil; \ - \ - static void \ - initPredefinedColor_##name(void) \ - { \ - name##Color = [[OFColor alloc] initWithRed: r \ - green: g \ - blue: b \ - alpha: 1]; \ - } \ - \ - + (OFColor *)name \ - { \ - static of_once_t onceControl = OF_ONCE_INIT; \ - of_once(&onceControl, initPredefinedColor_##name); \ - \ - return name##Color; \ +#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]; \ + } \ + \ + + (OFColor *)name \ + { \ + static OFOnceControl onceControl = OFOnceControlInitValue; \ + OFOnce(&onceControl, initPredefinedColor_##name); \ + \ + return name##Color; \ } PREDEFINED_COLOR(black, 0.00f, 0.00f, 0.00f) PREDEFINED_COLOR(silver, 0.75f, 0.75f, 0.75f) PREDEFINED_COLOR(grey, 0.50f, 0.50f, 0.50f) @@ -122,32 +119,32 @@ return true; } - (unsigned long)hash { - uint32_t hash; + unsigned long hash; float tmp; - OF_HASH_INIT(hash); - - tmp = OF_BSWAP_FLOAT_IF_LE(_red); - for (uint_fast8_t i = 0; i < sizeof(float); i++) - OF_HASH_ADD(hash, ((char *)&tmp)[i]); - - tmp = OF_BSWAP_FLOAT_IF_LE(_green); - for (uint_fast8_t i = 0; i < sizeof(float); i++) - OF_HASH_ADD(hash, ((char *)&tmp)[i]); - - tmp = OF_BSWAP_FLOAT_IF_LE(_blue); - for (uint_fast8_t i = 0; i < sizeof(float); i++) - OF_HASH_ADD(hash, ((char *)&tmp)[i]); - - tmp = OF_BSWAP_FLOAT_IF_LE(_alpha); - for (uint_fast8_t i = 0; i < sizeof(float); i++) - OF_HASH_ADD(hash, ((char *)&tmp)[i]); - - OF_HASH_FINALIZE(hash); + OFHashInit(&hash); + + tmp = OFToLittleEndianFloat(_red); + for (uint_fast8_t i = 0; i < sizeof(float); i++) + OFHashAdd(&hash, ((char *)&tmp)[i]); + + tmp = OFToLittleEndianFloat(_green); + for (uint_fast8_t i = 0; i < sizeof(float); i++) + OFHashAdd(&hash, ((char *)&tmp)[i]); + + tmp = OFToLittleEndianFloat(_blue); + for (uint_fast8_t i = 0; i < sizeof(float); i++) + OFHashAdd(&hash, ((char *)&tmp)[i]); + + tmp = OFToLittleEndianFloat(_alpha); + for (uint_fast8_t i = 0; i < sizeof(float); i++) + OFHashAdd(&hash, ((char *)&tmp)[i]); + + OFHashFinalize(&hash); return hash; } - (void)getRed: (float *)red Index: src/OFCondition.h ================================================================== --- src/OFCondition.h +++ src/OFCondition.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -14,12 +12,11 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #import "OFMutex.h" - -#import "condition.h" +#import "OFPlainCondition.h" OF_ASSUME_NONNULL_BEGIN @class OFDate; @@ -29,11 +26,11 @@ * @brief A class implementing a condition variable for thread synchronization. */ OF_SUBCLASSING_RESTRICTED @interface OFCondition: OFMutex { - of_condition_t _condition; + OFPlainCondition _condition; bool _conditionInitialized; } /** * @brief Creates a new condition. @@ -72,11 +69,11 @@ * 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 */ -- (bool)waitForTimeInterval: (of_time_interval_t)timeInterval; +- (bool)waitForTimeInterval: (OFTimeInterval)timeInterval; #ifdef OF_AMIGAOS /** * @brief Blocks the current thread until another thread calls @ref signal, * @ref broadcast, the timeout is reached or an Exec Signal is received. @@ -86,11 +83,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 */ -- (bool)waitForTimeInterval: (of_time_interval_t)timeInterval +- (bool)waitForTimeInterval: (OFTimeInterval)timeInterval orExecSignal: (ULONG *)signalMask; #endif /** * @brief Blocks the current thread until another thread calls @ref signal, @@ -114,12 +111,11 @@ * @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 */ -- (bool)waitUntilDate: (OFDate *)date - orExecSignal: (ULONG *)signalMask; +- (bool)waitUntilDate: (OFDate *)date orExecSignal: (ULONG *)signalMask; #endif /** * @brief Signals the next waiting thread to continue. */ Index: src/OFCondition.m ================================================================== --- src/OFCondition.m +++ src/OFCondition.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -36,11 +34,11 @@ - (instancetype)init { self = [super init]; - if (!of_condition_new(&_condition)) { + if (OFPlainConditionNew(&_condition) != 0) { Class c = self.class; [self release]; @throw [OFInitializationFailedException exceptionWithClass: c]; } @@ -50,12 +48,14 @@ } - (void)dealloc { if (_conditionInitialized) { - if (!of_condition_free(&_condition)) { - OF_ENSURE(errno == EBUSY); + int error = OFPlainConditionFree(&_condition); + + if (error != 0) { + OFEnsure(error == EBUSY); @throw [OFConditionStillWaitingException exceptionWithCondition: self]; } } @@ -63,53 +63,61 @@ [super dealloc]; } - (void)wait { - if (!of_condition_wait(&_condition, &_mutex)) + int error = OFPlainConditionWait(&_condition, &_mutex); + + if (error != 0) @throw [OFConditionWaitFailedException exceptionWithCondition: self - errNo: errno]; + errNo: error]; } #ifdef OF_AMIGAOS - (void)waitForConditionOrExecSignal: (ULONG *)signalMask { - if (!of_condition_wait_or_signal(&_condition, &_mutex, signalMask)) + int error = OFPlainConditionWaitOrExecSignal(&_condition, &_mutex, + signalMask); + + if (error != 0) @throw [OFConditionWaitFailedException exceptionWithCondition: self - errNo: errno]; + errNo: error]; } #endif -- (bool)waitForTimeInterval: (of_time_interval_t)timeInterval -{ - if (!of_condition_timed_wait(&_condition, &_mutex, timeInterval)) { - if (errno == ETIMEDOUT) - return false; - else - @throw [OFConditionWaitFailedException - exceptionWithCondition: self - errNo: errno]; - } +- (bool)waitForTimeInterval: (OFTimeInterval)timeInterval +{ + int error = OFPlainConditionTimedWait(&_condition, &_mutex, + timeInterval); + + if (error == ETIMEDOUT) + return false; + + if (error != 0) + @throw [OFConditionWaitFailedException + exceptionWithCondition: self + errNo: error]; return true; } #ifdef OF_AMIGAOS -- (bool)waitForTimeInterval: (of_time_interval_t)timeInterval +- (bool)waitForTimeInterval: (OFTimeInterval)timeInterval orExecSignal: (ULONG *)signalMask { - if (!of_condition_timed_wait_or_signal(&_condition, &_mutex, - timeInterval, signalMask)) { - if (errno == ETIMEDOUT) - return false; - else - @throw [OFConditionWaitFailedException - exceptionWithCondition: self - errNo: errno]; - } + int error = OFPlainConditionTimedWaitOrExecSignal(&_condition, &_mutex, + timeInterval, signalMask); + + if (error == ETIMEDOUT) + return false; + + if (error != 0) + @throw [OFConditionWaitFailedException + exceptionWithCondition: self + errNo: error]; return true; } #endif @@ -117,29 +125,32 @@ { return [self waitForTimeInterval: date.timeIntervalSinceNow]; } #ifdef OF_AMIGAOS -- (bool)waitUntilDate: (OFDate *)date - orExecSignal: (ULONG *)signalMask +- (bool)waitUntilDate: (OFDate *)date orExecSignal: (ULONG *)signalMask { return [self waitForTimeInterval: date.timeIntervalSinceNow orExecSignal: signalMask]; } #endif - (void)signal { - if (!of_condition_signal(&_condition)) + int error = OFPlainConditionSignal(&_condition); + + if (error != 0) @throw [OFConditionSignalFailedException exceptionWithCondition: self - errNo: errno]; + errNo: error]; } - (void)broadcast { - if (!of_condition_broadcast(&_condition)) + int error = OFPlainConditionBroadcast(&_condition); + + if (error != 0) @throw [OFConditionBroadcastFailedException exceptionWithCondition: self - errNo: errno]; + errNo: error]; } @end Index: src/OFConstantString.h ================================================================== --- src/OFConstantString.h +++ src/OFConstantString.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFConstantString.m ================================================================== --- src/OFConstantString.m +++ src/OFConstantString.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -52,39 +50,10 @@ + (instancetype)alloc { OF_UNRECOGNIZED_SELECTOR } -- (void *)allocMemoryWithSize: (size_t)size -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (void *)allocMemoryWithSize: (size_t)size - count: (size_t)count -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (void *)resizeMemory: (void *)pointer - size: (size_t)size -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (void *)resizeMemory: (void *)pointer - size: (size_t)size - count: (size_t)count -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (void)freeMemory: (void *)pointer -{ - OF_UNRECOGNIZED_SELECTOR -} - - (instancetype)retain { return self; } @@ -93,11 +62,11 @@ return self; } - (unsigned int)retainCount { - return OF_RETAIN_COUNT_MAX; + return OFMaxRetainCount; } - (void)release { } @@ -135,69 +104,36 @@ } - (void)finishInitialization { @synchronized (self) { - struct of_string_utf8_ivars *ivars; + struct OFUTF8StringIvars *ivars; if ([self isMemberOfClass: [OFConstantUTF8String class]]) return; - if ((ivars = calloc(1, sizeof(*ivars))) == NULL) - @throw [OFOutOfMemoryException - exceptionWithRequestedSize: sizeof(*ivars)]; - + ivars = OFAllocZeroedMemory(1, sizeof(*ivars)); ivars->cString = _cString; ivars->cStringLength = _cStringLength; - switch (of_string_utf8_check(ivars->cString, - ivars->cStringLength, - &ivars->length)) { - case 1: - ivars->isUTF8 = true; - break; - case -1: - free(ivars); - @throw [OFInvalidEncodingException exception]; + switch (OFUTF8StringCheck(ivars->cString, ivars->cStringLength, + &ivars->length)) { + case 1: + ivars->isUTF8 = true; + break; + case -1: + OFFreeMemory(ivars); + @throw [OFInvalidEncodingException exception]; } _cString = (char *)ivars; object_setClass(self, [OFConstantUTF8String class]); } } + (instancetype)alloc { - OF_UNRECOGNIZED_SELECTOR -} - -- (void *)allocMemoryWithSize: (size_t)size -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (void *)allocMemoryWithSize: (size_t)size - count: (size_t)count -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (void *)resizeMemory: (void *)pointer - size: (size_t)size -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (void *)resizeMemory: (void *)pointer - size: (size_t)size - count: (size_t)count -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (void)freeMemory: (void *)pointer -{ OF_UNRECOGNIZED_SELECTOR } - (instancetype)retain { @@ -209,11 +145,11 @@ return self; } - (unsigned int)retainCount { - return OF_RETAIN_COUNT_MAX; + return OFMaxRetainCount; } - (void)release { } @@ -230,521 +166,442 @@ /* From protocol OFCopying */ - (id)copy { [self finishInitialization]; - return [self copy]; } /* From protocol OFMutableCopying */ - (id)mutableCopy { [self finishInitialization]; - return [self mutableCopy]; } -/* From protocol OFComparing */ -- (of_comparison_result_t)compare: (id )object +/* From protocol OFComparing, but overridden in OFString */ +- (OFComparisonResult)compare: (OFString *)string { [self finishInitialization]; - - return [self compare: object]; + return [self compare: string]; } /* From OFObject, but reimplemented in OFString */ - (bool)isEqual: (id)object { [self finishInitialization]; - return [self isEqual: object]; } - (unsigned long)hash { [self finishInitialization]; - return self.hash; } - (OFString *)description { [self finishInitialization]; - return self.description; } /* From OFString */ - (const char *)UTF8String { [self finishInitialization]; - return self.UTF8String; } - (size_t)getCString: (char *)cString_ maxLength: (size_t)maxLength - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding { [self finishInitialization]; - return [self getCString: cString_ maxLength: maxLength encoding: encoding]; } -- (const char *)cStringWithEncoding: (of_string_encoding_t)encoding +- (const char *)cStringWithEncoding: (OFStringEncoding)encoding { [self finishInitialization]; - return [self cStringWithEncoding: encoding]; } - (size_t)length { [self finishInitialization]; - return self.length; } - (size_t)UTF8StringLength { [self finishInitialization]; - return self.UTF8StringLength; } -- (size_t)cStringLengthWithEncoding: (of_string_encoding_t)encoding +- (size_t)cStringLengthWithEncoding: (OFStringEncoding)encoding { [self finishInitialization]; - return [self cStringLengthWithEncoding: encoding]; } -- (of_comparison_result_t)caseInsensitiveCompare: (OFString *)otherString +- (OFComparisonResult)caseInsensitiveCompare: (OFString *)string { [self finishInitialization]; - - return [self caseInsensitiveCompare: otherString]; + return [self caseInsensitiveCompare: string]; } -- (of_unichar_t)characterAtIndex: (size_t)idx +- (OFUnichar)characterAtIndex: (size_t)idx { [self finishInitialization]; - return [self characterAtIndex: idx]; } -- (void)getCharacters: (of_unichar_t *)buffer - inRange: (of_range_t)range +- (void)getCharacters: (OFUnichar *)buffer inRange: (OFRange)range { [self finishInitialization]; - - [self getCharacters: buffer - inRange: range]; + [self getCharacters: buffer inRange: range]; } -- (of_range_t)rangeOfString: (OFString *)string +- (OFRange)rangeOfString: (OFString *)string { [self finishInitialization]; - return [self rangeOfString: string]; } -- (of_range_t)rangeOfString: (OFString *)string - options: (int)options -{ - [self finishInitialization]; - - return [self rangeOfString: string - options: options]; -} - -- (of_range_t)rangeOfString: (OFString *)string - options: (int)options - range: (of_range_t)range -{ - [self finishInitialization]; - - return [self rangeOfString: string - options: options - range: range]; +- (OFRange)rangeOfString: (OFString *)string + options: (OFStringSearchOptions)options +{ + [self finishInitialization]; + return [self rangeOfString: string options: options]; +} + +- (OFRange)rangeOfString: (OFString *)string + options: (OFStringSearchOptions)options + range: (OFRange)range +{ + [self finishInitialization]; + return [self rangeOfString: string options: options range: range]; } - (size_t)indexOfCharacterFromSet: (OFCharacterSet *)characterSet { [self finishInitialization]; - return [self indexOfCharacterFromSet: characterSet]; } - (size_t)indexOfCharacterFromSet: (OFCharacterSet *)characterSet - options: (int)options + options: (OFStringSearchOptions)options { [self finishInitialization]; - - return [self indexOfCharacterFromSet: characterSet - options: options]; + return [self indexOfCharacterFromSet: characterSet options: options]; } - (size_t)indexOfCharacterFromSet: (OFCharacterSet *)characterSet - options: (int)options - range: (of_range_t)range + options: (OFStringSearchOptions)options + range: (OFRange)range { [self finishInitialization]; - return [self indexOfCharacterFromSet: characterSet options: options range: range]; } - (bool)containsString: (OFString *)string { [self finishInitialization]; - return [self containsString: string]; } - (OFString *)substringFromIndex: (size_t)idx { [self finishInitialization]; - return [self substringFromIndex: idx]; } - (OFString *)substringToIndex: (size_t)idx { [self finishInitialization]; - return [self substringToIndex: idx]; } -- (OFString *)substringWithRange: (of_range_t)range +- (OFString *)substringWithRange: (OFRange)range { [self finishInitialization]; - return [self substringWithRange: range]; } - (OFString *)stringByAppendingString: (OFString *)string { [self finishInitialization]; - return [self stringByAppendingString: string]; } - (OFString *)stringByAppendingFormat: (OFConstantString *)format arguments: (va_list)arguments { [self finishInitialization]; - - return [self stringByAppendingFormat: format - arguments: arguments]; + return [self stringByAppendingFormat: format arguments: arguments]; } - (OFString *)stringByAppendingPathComponent: (OFString *)component { [self finishInitialization]; - return [self stringByAppendingPathComponent: component]; } - (OFString *)stringByPrependingString: (OFString *)string { [self finishInitialization]; - return [self stringByPrependingString: string]; } - (OFString *)stringByReplacingOccurrencesOfString: (OFString *)string withString: (OFString *)replacement { [self finishInitialization]; - return [self stringByReplacingOccurrencesOfString: string withString: replacement]; } - (OFString *)stringByReplacingOccurrencesOfString: (OFString *)string withString: (OFString *)replacement options: (int)options - range: (of_range_t)range + range: (OFRange)range { [self finishInitialization]; - return [self stringByReplacingOccurrencesOfString: string withString: replacement options: options range: range]; } - (OFString *)uppercaseString { [self finishInitialization]; - return self.uppercaseString; } - (OFString *)lowercaseString { [self finishInitialization]; - return self.lowercaseString; } - (OFString *)capitalizedString { [self finishInitialization]; - return self.capitalizedString; } - (OFString *)stringByDeletingLeadingWhitespaces { [self finishInitialization]; - return self.stringByDeletingLeadingWhitespaces; } - (OFString *)stringByDeletingTrailingWhitespaces { [self finishInitialization]; - return self.stringByDeletingTrailingWhitespaces; } - (OFString *)stringByDeletingEnclosingWhitespaces { [self finishInitialization]; - return self.stringByDeletingEnclosingWhitespaces; } - (bool)hasPrefix: (OFString *)prefix { [self finishInitialization]; - return [self hasPrefix: prefix]; } - (bool)hasSuffix: (OFString *)suffix { [self finishInitialization]; - return [self hasSuffix: suffix]; } - (OFArray *)componentsSeparatedByString: (OFString *)delimiter { [self finishInitialization]; - return [self componentsSeparatedByString: delimiter]; } - (OFArray *)componentsSeparatedByString: (OFString *)delimiter - options: (int)options + options: (OFStringSeparationOptions)options { [self finishInitialization]; - - return [self componentsSeparatedByString: delimiter - options: options]; + return [self componentsSeparatedByString: delimiter options: options]; } - (OFArray *) componentsSeparatedByCharactersInSet: (OFCharacterSet *)characterSet { [self finishInitialization]; - return [self componentsSeparatedByCharactersInSet: characterSet]; } - (OFArray *) componentsSeparatedByCharactersInSet: (OFCharacterSet *)characterSet - options: (int)options + options: (OFStringSeparationOptions)options { [self finishInitialization]; - return [self componentsSeparatedByCharactersInSet: characterSet options: options]; } - (OFArray *)pathComponents { [self finishInitialization]; - return self.pathComponents; } - (OFString *)lastPathComponent { [self finishInitialization]; - return self.lastPathComponent; } - (OFString *)stringByDeletingLastPathComponent { [self finishInitialization]; - return self.stringByDeletingLastPathComponent; } - (long long)longLongValue { [self finishInitialization]; - return self.longLongValue; } - (long long)longLongValueWithBase: (int)base { [self finishInitialization]; - return [self longLongValueWithBase: base]; } - (unsigned long long)unsignedLongLongValue { [self finishInitialization]; - return self.unsignedLongLongValue; } - (unsigned long long)unsignedLongLongValueWithBase: (int)base { [self finishInitialization]; - return [self unsignedLongLongValueWithBase: base]; } - (float)floatValue { [self finishInitialization]; - return self.floatValue; } - (double)doubleValue { [self finishInitialization]; - return self.doubleValue; } -- (const of_unichar_t *)characters +- (const OFUnichar *)characters { [self finishInitialization]; - return self.characters; } -- (const of_char16_t *)UTF16String +- (const OFChar16 *)UTF16String { [self finishInitialization]; - return self.UTF16String; } -- (const of_char16_t *)UTF16StringWithByteOrder: (of_byte_order_t)byteOrder +- (const OFChar16 *)UTF16StringWithByteOrder: (OFByteOrder)byteOrder { [self finishInitialization]; - return [self UTF16StringWithByteOrder: byteOrder]; } - (size_t)UTF16StringLength { [self finishInitialization]; - return self.UTF16StringLength; } -- (const of_char32_t *)UTF32String +- (const OFChar32 *)UTF32String { [self finishInitialization]; - return self.UTF32String; } -- (const of_char32_t *)UTF32StringWithByteOrder: (of_byte_order_t)byteOrder +- (const OFChar32 *)UTF32StringWithByteOrder: (OFByteOrder)byteOrder { [self finishInitialization]; - return [self UTF32StringWithByteOrder: byteOrder]; } -- (OFData *)dataWithEncoding: (of_string_encoding_t)encoding +- (OFData *)dataWithEncoding: (OFStringEncoding)encoding { [self finishInitialization]; - return [self dataWithEncoding: encoding]; } #ifdef OF_HAVE_UNICODE_TABLES - (OFString *)decomposedStringWithCanonicalMapping { [self finishInitialization]; - return self.decomposedStringWithCanonicalMapping; } - (OFString *)decomposedStringWithCompatibilityMapping { [self finishInitialization]; - return self.decomposedStringWithCompatibilityMapping; } #endif #ifdef OF_WINDOWS - (OFString *)stringByExpandingWindowsEnvironmentStrings { [self finishInitialization]; - return self.stringByExpandingWindowsEnvironmentStrings; } #endif #ifdef OF_HAVE_FILES - (void)writeToFile: (OFString *)path { [self finishInitialization]; - [self writeToFile: path]; } -- (void)writeToFile: (OFString *)path - encoding: (of_string_encoding_t)encoding +- (void)writeToFile: (OFString *)path encoding: (OFStringEncoding)encoding { [self finishInitialization]; - - [self writeToFile: path - encoding: encoding]; + [self writeToFile: path encoding: encoding]; } #endif - (void)writeToURL: (OFURL *)URL { [self finishInitialization]; - [self writeToURL: URL]; } -- (void)writeToURL: (OFURL *)URL - encoding: (of_string_encoding_t)encoding +- (void)writeToURL: (OFURL *)URL encoding: (OFStringEncoding)encoding { [self finishInitialization]; - - [self writeToURL: URL - encoding: encoding]; + [self writeToURL: URL encoding: encoding]; } #ifdef OF_HAVE_BLOCKS -- (void)enumerateLinesUsingBlock: (of_string_line_enumeration_block_t)block +- (void)enumerateLinesUsingBlock: (OFStringLineEnumerationBlock)block { [self finishInitialization]; - [self enumerateLinesUsingBlock: block]; } #endif @end Index: src/OFCountedMapTableSet.h ================================================================== --- src/OFCountedMapTableSet.h +++ src/OFCountedMapTableSet.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFCountedMapTableSet.m ================================================================== --- src/OFCountedMapTableSet.m +++ src/OFCountedMapTableSet.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -43,11 +41,11 @@ @try { void *pool = objc_autoreleasePoolPush(); if ([set isKindOfClass: [OFCountedSet class]]) { - OFCountedSet *countedSet = (OFCountedSet *)countedSet; + OFCountedSet *countedSet = (OFCountedSet *)set; for (id object in countedSet) { size_t count = [countedSet countForObject: object]; @@ -83,12 +81,11 @@ } return self; } -- (instancetype)initWithObjects: (id const *)objects - count: (size_t)count +- (instancetype)initWithObjects: (id const *)objects count: (size_t)count { self = [self init]; @try { for (size_t i = 0; i < count; i++) @@ -99,12 +96,11 @@ } return self; } -- (instancetype)initWithObject: (id)firstObject - arguments: (va_list)arguments +- (instancetype)initWithObject: (id)firstObject arguments: (va_list)arguments { self = [self init]; @try { id object; @@ -127,23 +123,23 @@ @try { void *pool = objc_autoreleasePoolPush(); if (![element.name isEqual: @"OFCountedSet"] || - ![element.namespace isEqual: OF_SERIALIZATION_NS]) + ![element.namespace isEqual: OFSerializationNS]) @throw [OFInvalidArgumentException exception]; for (OFXMLElement *objectElement in [element elementsForName: @"object" - namespace: OF_SERIALIZATION_NS]) { + namespace: OFSerializationNS]) { void *pool2 = objc_autoreleasePoolPush(); OFXMLElement *object; OFXMLAttribute *countAttribute; unsigned long long count; object = [objectElement elementsForNamespace: - OF_SERIALIZATION_NS].firstObject; + OFSerializationNS].firstObject; countAttribute = [objectElement attributeForName: @"count"]; if (object == nil || countAttribute == nil) @throw [OFInvalidFormatException exception]; @@ -171,12 +167,11 @@ { return (size_t)(uintptr_t)[_mapTable objectForKey: object]; } #ifdef OF_HAVE_BLOCKS -- (void)enumerateObjectsAndCountUsingBlock: - (of_counted_set_enumeration_block_t)block +- (void)enumerateObjectsAndCountUsingBlock: (OFCountedSetEnumerationBlock)block { @try { [_mapTable enumerateKeysAndObjectsUsingBlock: ^ (void *key, void *object, bool *stop) { block(key, (size_t)(uintptr_t)object, stop); @@ -193,12 +188,11 @@ size_t count = (size_t)(uintptr_t)[_mapTable objectForKey: object]; if (SIZE_MAX - count < 1 || UINTPTR_MAX - count < 1) @throw [OFOutOfRangeException exception]; - [_mapTable setObject: (void *)(uintptr_t)(count + 1) - forKey: object]; + [_mapTable setObject: (void *)(uintptr_t)(count + 1) forKey: object]; } - (void)removeObject: (id)object { size_t count = (size_t)(uintptr_t)[_mapTable objectForKey: object]; @@ -207,12 +201,11 @@ return; count--; if (count > 0) - [_mapTable setObject: (void *)(uintptr_t)count - forKey: object]; + [_mapTable setObject: (void *)(uintptr_t)count forKey: object]; else [_mapTable removeObjectForKey: object]; } - (void)removeAllObjects Index: src/OFCountedSet.h ================================================================== --- src/OFCountedSet.h +++ src/OFCountedSet.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -28,11 +26,11 @@ * @param object The current object * @param count The count of the object * @param stop A pointer to a variable that can be set to true to stop the * enumeration */ -typedef void (^of_counted_set_enumeration_block_t)(id object, size_t count, +typedef void (^OFCountedSetEnumerationBlock)(id object, size_t count, bool *stop); #endif /** * @class OFCountedSet OFCountedSet.h ObjFW/OFCountedSet.h @@ -59,14 +57,13 @@ /** * @brief Executes a block for each object in the set. * * @param block The block to execute for each object in the set */ -- (void)enumerateObjectsAndCountUsingBlock: - (of_counted_set_enumeration_block_t)block; +- (void)enumerateObjectsAndCountUsingBlock: (OFCountedSetEnumerationBlock)block; #endif #if !defined(OF_HAVE_GENERICS) && !defined(DOXYGEN) # undef ObjectType #endif @end OF_ASSUME_NONNULL_END Index: src/OFCountedSet.m ================================================================== --- src/OFCountedSet.m +++ src/OFCountedSet.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -59,19 +57,17 @@ va_end(arguments); return ret; } -- (instancetype)initWithObjects: (id const *)objects - count: (size_t)count +- (instancetype)initWithObjects: (id const *)objects count: (size_t)count { return (id)[[OFCountedMapTableSet alloc] initWithObjects: objects count: count]; } -- (instancetype)initWithObject: (id)firstObject - arguments: (va_list)arguments +- (instancetype)initWithObject: (id)firstObject arguments: (va_list)arguments { return (id)[[OFCountedMapTableSet alloc] initWithObject: firstObject arguments: arguments]; } @@ -160,14 +156,12 @@ if (++i < count) [ret appendString: @",\n"]; objc_autoreleasePoolPop(pool2); } - [ret replaceOccurrencesOfString: @"\n" - withString: @"\n\t"]; + [ret replaceOccurrencesOfString: @"\n" withString: @"\n\t"]; [ret appendString: @"\n)}"]; - [ret makeImmutable]; objc_autoreleasePoolPop(pool); return ret; @@ -187,11 +181,11 @@ { void *pool = objc_autoreleasePoolPush(); OFXMLElement *element; element = [OFXMLElement elementWithName: @"OFCountedSet" - namespace: OF_SERIALIZATION_NS]; + namespace: OFSerializationNS]; for (id object in self) { void *pool2 = objc_autoreleasePoolPush(); OFXMLElement *objectElement; @@ -201,11 +195,11 @@ [OFString stringWithFormat: @"%zu", [self countForObject: object]]; objectElement = [OFXMLElement elementWithName: @"object" - namespace: OF_SERIALIZATION_NS]; + namespace: OFSerializationNS]; [objectElement addAttributeWithName: @"count" stringValue: count]; [objectElement addChild: object.XMLElementBySerializing]; [element addChild: objectElement]; @@ -218,12 +212,11 @@ return [element autorelease]; } #ifdef OF_HAVE_BLOCKS -- (void)enumerateObjectsAndCountUsingBlock: - (of_counted_set_enumeration_block_t)block +- (void)enumerateObjectsAndCountUsingBlock: (OFCountedSetEnumerationBlock)block { [self enumerateObjectsUsingBlock: ^ (id object, bool *stop) { block(object, [self countForObject: object], stop); }]; } DELETED src/OFCryptoHash.h Index: src/OFCryptoHash.h ================================================================== --- src/OFCryptoHash.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 - -/** - * @protocol OFCryptoHash OFCryptoHash.h ObjFW/OFCryptoHash.h - * - * @brief A protocol for classes providing cryptographic hash functions. - * - * A cryptographic hash implementing this protocol can be copied. The entire - * state is copied, allowing to calculate a new hash from there. This is - * especially useful for generating many hashes with a common prefix. - */ -@protocol OFCryptoHash -#ifdef OF_HAVE_CLASS_PROPERTIES -@property (class, readonly, nonatomic) size_t digestSize; -@property (class, readonly, nonatomic) size_t blockSize; -#endif - -/** - * @brief The digest size of the cryptographic hash, in bytes. - */ -@property (readonly, nonatomic) size_t digestSize; - -/** - * @brief The block size of the cryptographic hash, in bytes. - */ -@property (readonly, nonatomic) size_t blockSize; - -/** - * @brief Whether data may be stored in swappable memory. - */ -@property (readonly, nonatomic) bool allowsSwappableMemory; - -/** - * @brief A boolean whether the hash has already been calculated. - */ -@property (readonly, nonatomic, getter=isCalculated) bool calculated; - -/** - * @brief A buffer containing the cryptographic hash. - * - * The size of the buffer depends on the hash used. The buffer is part of the - * receiver's memory pool. - */ -@property (readonly, nonatomic) const unsigned char *digest - OF_RETURNS_INNER_POINTER; - -/** - * @brief Creates a new cryptographic hash. - * - * @return A new autoreleased cryptographic hash - */ -+ (instancetype)cryptoHashWithAllowsSwappableMemory: - (bool)allowsSwappableMemory; - -/** - * @brief Returns the digest size of the cryptographic hash, in bytes. - * - * @return The digest size of the cryptographic hash, in bytes - */ -+ (size_t)digestSize; - -/** - * @brief Returns the block size of the cryptographic hash, in bytes. - * - * @return The block size of the cryptographic hash, in bytes - */ -+ (size_t)blockSize; - -/** - * @brief Initializes an already allocated cryptographic hash. - * - * @return An initialized cryptographic hash - */ -- (instancetype)initWithAllowsSwappableMemory: (bool)allowsSwappableMemory; - -- (instancetype)init OF_UNAVAILABLE; - -/** - * @brief Adds a buffer to the cryptographic hash to be calculated. - * - * @param buffer The buffer which should be included into the calculation - * @param length The length of the buffer - */ -- (void)updateWithBuffer: (const void *)buffer - length: (size_t)length; - -/** - * @brief Resets all state so that a new hash can be calculated. - * - * @warning This invalidates any pointer previously returned by @ref digest. If - * you are still interested in the previous digest, you need to memcpy - * it yourself before calling @ref reset! - */ -- (void)reset; -@end - -OF_ASSUME_NONNULL_END ADDED src/OFCryptographicHash.h Index: src/OFCryptographicHash.h ================================================================== --- /dev/null +++ src/OFCryptographicHash.h @@ -0,0 +1,118 @@ +/* + * 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 + +/** + * @protocol OFCryptographicHash \ + * OFCryptographicHash.h ObjFW/OFCryptographicHash.h + * + * @brief A protocol for classes providing cryptographic hash functions. + * + * A cryptographic hash implementing this protocol can be copied. The entire + * state is copied, allowing to calculate a new hash from there. This is + * especially useful for generating many hashes with a common prefix. + */ +@protocol OFCryptographicHash +#ifdef OF_HAVE_CLASS_PROPERTIES +@property (class, readonly, nonatomic) size_t digestSize; +@property (class, readonly, nonatomic) size_t blockSize; +#endif + +/** + * @brief The digest size of the cryptographic hash, in bytes. + */ +@property (readonly, nonatomic) size_t digestSize; + +/** + * @brief The block size of the cryptographic hash, in bytes. + */ +@property (readonly, nonatomic) size_t blockSize; + +/** + * @brief Whether data may be stored in swappable memory. + */ +@property (readonly, nonatomic) bool allowsSwappableMemory; + +/** + * @brief A boolean whether the hash has already been calculated. + */ +@property (readonly, nonatomic, getter=isCalculated) bool calculated; + +/** + * @brief A buffer containing the cryptographic hash. + * + * The size of the buffer depends on the hash used. The buffer is part of the + * receiver's memory pool. + */ +@property (readonly, nonatomic) const unsigned char *digest + OF_RETURNS_INNER_POINTER; + +/** + * @brief Creates a new cryptographic hash. + * + * @return A new autoreleased cryptographic hash + */ ++ (instancetype)hashWithAllowsSwappableMemory: (bool)allowsSwappableMemory; + +/** + * @brief Returns the digest size of the cryptographic hash, in bytes. + * + * @return The digest size of the cryptographic hash, in bytes + */ ++ (size_t)digestSize; + +/** + * @brief Returns the block size of the cryptographic hash, in bytes. + * + * @return The block size of the cryptographic hash, in bytes + */ ++ (size_t)blockSize; + +/** + * @brief Initializes an already allocated cryptographic hash. + * + * @return An initialized cryptographic hash + */ +- (instancetype)initWithAllowsSwappableMemory: (bool)allowsSwappableMemory; + +- (instancetype)init OF_UNAVAILABLE; + +/** + * @brief Adds a buffer to the cryptographic hash to be calculated. + * + * @param buffer The buffer which should be included into the calculation + * @param length The length of the buffer + */ +- (void)updateWithBuffer: (const void *)buffer length: (size_t)length; + +/** + * @brief Performs the final calculation of the cryptographic hash. + */ +- (void)calculate; + +/** + * @brief Resets all state so that a new hash can be calculated. + * + * @warning This invalidates any pointer previously returned by @ref digest. If + * you are still interested in the previous digest, you need to memcpy + * it yourself before calling @ref reset! + */ +- (void)reset; +@end + +OF_ASSUME_NONNULL_END Index: src/OFDNSQuery.h ================================================================== --- src/OFDNSQuery.h +++ src/OFDNSQuery.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -28,12 +26,12 @@ * @brief A class representing a DNS query. */ @interface OFDNSQuery: OFObject { OFString *_domainName; - of_dns_class_t _DNSClass; - of_dns_record_type_t _recordType; + OFDNSClass _DNSClass; + OFDNSRecordType _recordType; OF_RESERVE_IVARS(OFDNSQuery, 4) } /** * @brief The domain name of the query. @@ -41,16 +39,16 @@ @property (readonly, nonatomic) OFString *domainName; /** * @brief The DNS class of the query. */ -@property (readonly, nonatomic) of_dns_class_t DNSClass; +@property (readonly, nonatomic) OFDNSClass DNSClass; /** * @brief The record type of the query. */ -@property (readonly, nonatomic) of_dns_record_type_t recordType; +@property (readonly, nonatomic) OFDNSRecordType recordType; /** * @brief Creates a new, autoreleased OFDNSQuery. * * @param domainName The domain name to query @@ -57,12 +55,12 @@ * @param DNSClass The DNS class of the query * @param recordType The record type of the query * @return A new, autoreleased OFDNSQuery */ + (instancetype)queryWithDomainName: (OFString *)domainName - DNSClass: (of_dns_class_t)DNSClass - recordType: (of_dns_record_type_t)recordType; + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType; /** * @brief Initializes an already allocated OFDNSQuery. * * @param domainName The domain name to query @@ -69,13 +67,13 @@ * @param DNSClass The DNS class of the query * @param recordType The record type of the query * @return An initialized OFDNSQuery */ - (instancetype)initWithDomainName: (OFString *)domainName - DNSClass: (of_dns_class_t)DNSClass - recordType: (of_dns_record_type_t)recordType + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType OF_DESIGNATED_INITIALIZER; - (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/OFDNSQuery.m ================================================================== --- src/OFDNSQuery.m +++ src/OFDNSQuery.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -23,21 +21,21 @@ @implementation OFDNSQuery @synthesize domainName = _domainName, DNSClass = _DNSClass; @synthesize recordType = _recordType; + (instancetype)queryWithDomainName: (OFString *)domainName - DNSClass: (of_dns_class_t)DNSClass - recordType: (of_dns_record_type_t)recordType + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType { return [[[self alloc] initWithDomainName: domainName DNSClass: DNSClass recordType: recordType] autorelease]; } - (instancetype)initWithDomainName: (OFString *)domainName - DNSClass: (of_dns_class_t)DNSClass - recordType: (of_dns_record_type_t)recordType + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType { self = [super init]; @try { void *pool = objc_autoreleasePoolPush(); @@ -93,17 +91,17 @@ return true; } - (unsigned long)hash { - uint32_t hash; + unsigned long hash; - OF_HASH_INIT(hash); - OF_HASH_ADD_HASH(hash, _domainName.hash); - OF_HASH_ADD(hash, _DNSClass); - OF_HASH_ADD(hash, _recordType); - OF_HASH_FINALIZE(hash); + OFHashInit(&hash); + OFHashAddHash(&hash, _domainName.hash); + OFHashAdd(&hash, _DNSClass); + OFHashAdd(&hash, _recordType); + OFHashFinalize(&hash); return hash; } - (id)copy @@ -112,9 +110,9 @@ } - (OFString *)description { return [OFString stringWithFormat: @"<%@ %@ %@ %@>", - self.className, _domainName, of_dns_class_to_string(_DNSClass), - of_dns_record_type_to_string(_recordType)]; + self.className, _domainName, OFDNSClassName(_DNSClass), + OFDNSRecordTypeName(_recordType)]; } @end Index: src/OFDNSResolver.h ================================================================== --- src/OFDNSResolver.h +++ src/OFDNSResolver.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -22,11 +20,11 @@ #import "OFRunLoop.h" #import "OFString.h" OF_ASSUME_NONNULL_BEGIN -#define OF_DNS_RESOLVER_BUFFER_LENGTH 512 +#define OFDNSResolverBufferLength 512 @class OFArray OF_GENERIC(ObjectType); @class OFDNSResolver; @class OFDNSResolverContext; @class OFDNSResolverSettings; @@ -36,41 +34,41 @@ @class OFNumber; @class OFTCPSocket; @class OFUDPSocket; /** - * @enum of_dns_resolver_error_t OFDNSResolver.h ObjFW/OFDNSResolver.h + * @enum OFDNSResolverErrorCode OFDNSResolver.h ObjFW/OFDNSResolver.h * * @brief An enum describing why resolving a host failed. */ -typedef enum of_dns_resolver_error_t { +typedef enum { /** An unknown error */ - OF_DNS_RESOLVER_ERROR_UNKNOWN, + OFDNSResolverErrorCodeUnknown, /** The query timed out */ - OF_DNS_RESOLVER_ERROR_TIMEOUT, + OFDNSResolverErrorCodeTimeout, /** The query was canceled */ - OF_DNS_RESOLVER_ERROR_CANCELED, + OFDNSResolverErrorCodeCanceled, /** * No result for the specified host with the specified type and class. * * This is only used in situations where this is an error, e.g. when * trying to connect to a host. */ - OF_DNS_RESOLVER_ERROR_NO_RESULT, + OFDNSResolverErrorCodeNoResult, /** The server considered the query to be malformed */ - OF_DNS_RESOLVER_ERROR_SERVER_INVALID_FORMAT, + OFDNSResolverErrorCodeServerInvalidFormat, /** The server was unable to process due to an internal error */ - OF_DNS_RESOLVER_ERROR_SERVER_FAILURE, + OFDNSResolverErrorCodeServerFailure, /** The server returned an error that the domain does not exist */ - OF_DNS_RESOLVER_ERROR_SERVER_NAME_ERROR, + OFDNSResolverErrorCodeServerNameError, /** The server does not have support for the requested query */ - OF_DNS_RESOLVER_ERROR_SERVER_NOT_IMPLEMENTED, + OFDNSResolverErrorCodeServerNotImplemented, /** The server refused the query */ - OF_DNS_RESOLVER_ERROR_SERVER_REFUSED, + OFDNSResolverErrorCodeServerRefused, /** There was no name server to query */ - OF_DNS_RESOLVER_ERROR_NO_NAME_SERVER -} of_dns_resolver_error_t; + OFDNSResolverErrorCodeNoNameServer +} OFDNSResolverErrorCode; /** * @protocol OFDNSResolverQueryDelegate OFDNSResolver.h ObjFW/OFDNSResolver.h * * @brief A delegate for performed DNS queries. @@ -101,11 +99,11 @@ * @brief This method is called when a DNS resolver resolved a host to * addresses. * * @param resolver The acting resolver * @param host The host the resolver resolved - * @param addresses OFData containing several of_socket_address_t + * @param addresses OFData containing several OFSocketAddress * @param exception The exception that occurred during resolving, or nil on * success */ - (void)resolver: (OFDNSResolver *)resolver didResolveHost: (OFString *)host @@ -129,11 +127,11 @@ OFDNSResolverSettings *_settings; OFUDPSocket *_IPv4Socket; #ifdef OF_HAVE_IPV6 OFUDPSocket *_IPv6Socket; #endif - char _buffer[OF_DNS_RESOLVER_BUFFER_LENGTH]; + char _buffer[OFDNSResolverBufferLength]; OFMutableDictionary OF_GENERIC(OFNumber *, OFDNSResolverContext *) *_queries; OFMutableDictionary OF_GENERIC(OFTCPSocket *, OFDNSResolverContext *) *_TCPQueries; } @@ -165,11 +163,11 @@ /** * @brief The timeout, in seconds, after which the next name server should be * tried. */ -@property (nonatomic) of_time_interval_t timeout; +@property (nonatomic) OFTimeInterval timeout; /** * @brief The number of attempts before giving up to resolve a host. * * Trying all name servers once is considered a single attempt. @@ -189,11 +187,11 @@ /** * @brief The interval in seconds in which the config should be reloaded. * * Setting this to 0 disables config reloading. */ -@property (nonatomic) of_time_interval_t configReloadInterval; +@property (nonatomic) OFTimeInterval configReloadInterval; /** * @brief Creates a new, autoreleased OFDNSResolver. */ + (instancetype)resolver; @@ -218,11 +216,11 @@ * @param query The query to perform * @param runLoopMode The run loop mode in which to resolve * @param delegate The delegate to use for callbacks */ - (void)asyncPerformQuery: (OFDNSQuery *)query - runLoopMode: (of_run_loop_mode_t)runLoopMode + runLoopMode: (OFRunLoopMode)runLoopMode delegate: (id )delegate; /** * @brief Asynchronously resolves the specified host to socket addresses. * @@ -238,11 +236,11 @@ * @param host The host to resolve * @param addressFamily The desired socket address family * @param delegate The delegate to use for callbacks */ - (void)asyncResolveAddressesForHost: (OFString *)host - addressFamily: (of_socket_address_family_t)addressFamily + addressFamily: (OFSocketAddressFamily)addressFamily delegate: (id )delegate; /** * @brief Asynchronously resolves the specified host to socket addresses. * @@ -250,26 +248,26 @@ * @param addressFamily The desired socket address family * @param runLoopMode The run loop mode in which to resolve * @param delegate The delegate to use for callbacks */ - (void)asyncResolveAddressesForHost: (OFString *)host - addressFamily: (of_socket_address_family_t)addressFamily - runLoopMode: (of_run_loop_mode_t)runLoopMode + addressFamily: (OFSocketAddressFamily)addressFamily + runLoopMode: (OFRunLoopMode)runLoopMode delegate: (id )delegate; /** * @brief Synchronously resolves the specified host to socket addresses. * * @param host The host to resolve * @param addressFamily The desired socket address family - * @return OFData containing several of_socket_address_t + * @return OFData containing several OFSocketAddress */ - (OFData *)resolveAddressesForHost: (OFString *)host - addressFamily: (of_socket_address_family_t)addressFamily; + addressFamily: (OFSocketAddressFamily)addressFamily; /** * @brief Closes all sockets and cancels all ongoing queries. */ - (void)close; @end OF_ASSUME_NONNULL_END Index: src/OFDNSResolver.m ================================================================== --- src/OFDNSResolver.m +++ src/OFDNSResolver.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -39,29 +37,28 @@ #import "OFDNSQueryFailedException.h" #import "OFInitializationFailedException.h" #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFInvalidServerReplyException.h" +#import "OFNotImplementedException.h" #import "OFOutOfRangeException.h" #import "OFTruncatedDataException.h" #ifndef SOCK_DNS # define SOCK_DNS 0 #endif -#define BUFFER_LENGTH OF_DNS_RESOLVER_BUFFER_LENGTH -#define MAX_DNS_RESPONSE_LENGTH 65536 +static const size_t bufferLength = OFDNSResolverBufferLength; +static const size_t maxDNSResponseLength = 65536; /* * RFC 1035 doesn't specify if pointers to pointers are allowed, and if so how * many. Since it's unspecified, we have to assume that it might happen, but we * also want to limit it to avoid DoS. Limiting it to 16 levels of pointers and * immediately rejecting pointers to itself seems like a fair balance. */ -#define MAX_ALLOWED_POINTERS 16 - -#define CNAME_RECURSION 3 +static const uint_fast8_t maxAllowedPointers = 16; @interface OFDNSResolver () - (void)of_contextTimedOut: (OFDNSResolverContext *)context; @end @@ -74,11 +71,11 @@ OFDNSResolverSettings *_settings; size_t _nameServersIndex; unsigned int _attempt; id _delegate; OFData *_queryData; - of_socket_address_t _usedNameServer; + OFSocketAddress _usedNameServer; OFTCPSocket *_TCPSocket; OFMutableData *_TCPQueryData; void *_TCPBuffer; size_t _responseLength; OFTimer *_cancelTimer; @@ -168,70 +165,70 @@ return [components componentsJoinedByString: @"."]; } static OF_KINDOF(OFDNSResourceRecord *) -parseResourceRecord(OFString *name, of_dns_class_t DNSClass, - of_dns_record_type_t recordType, uint32_t TTL, const unsigned char *buffer, +parseResourceRecord(OFString *name, OFDNSClass DNSClass, + OFDNSRecordType recordType, uint32_t TTL, const unsigned char *buffer, size_t length, size_t i, uint16_t dataLength) { - if (recordType == OF_DNS_RECORD_TYPE_A && DNSClass == OF_DNS_CLASS_IN) { - of_socket_address_t address; + if (recordType == OFDNSRecordTypeA && DNSClass == OFDNSClassIN) { + OFSocketAddress address; if (dataLength != 4) @throw [OFInvalidServerReplyException exception]; memset(&address, 0, sizeof(address)); - address.family = OF_SOCKET_ADDRESS_FAMILY_IPV4; + address.family = OFSocketAddressFamilyIPv4; address.length = sizeof(address.sockaddr.in); address.sockaddr.in.sin_family = AF_INET; memcpy(&address.sockaddr.in.sin_addr.s_addr, buffer + i, 4); return [[[OFADNSResourceRecord alloc] initWithName: name address: &address TTL: TTL] autorelease]; - } else if (recordType == OF_DNS_RECORD_TYPE_NS) { + } else if (recordType == OFDNSRecordTypeNS) { size_t j = i; OFString *authoritativeHost = parseName(buffer, length, &j, - MAX_ALLOWED_POINTERS); + maxAllowedPointers); if (j != i + dataLength) @throw [OFInvalidServerReplyException exception]; return [[[OFNSDNSResourceRecord alloc] initWithName: name DNSClass: DNSClass authoritativeHost: authoritativeHost TTL: TTL] autorelease]; - } else if (recordType == OF_DNS_RECORD_TYPE_CNAME) { + } else if (recordType == OFDNSRecordTypeCNAME) { size_t j = i; OFString *alias = parseName(buffer, length, &j, - MAX_ALLOWED_POINTERS); + maxAllowedPointers); if (j != i + dataLength) @throw [OFInvalidServerReplyException exception]; return [[[OFCNAMEDNSResourceRecord alloc] initWithName: name DNSClass: DNSClass alias: alias TTL: TTL] autorelease]; - } else if (recordType == OF_DNS_RECORD_TYPE_SOA) { + } else if (recordType == OFDNSRecordTypeSOA) { size_t j = i; OFString *primaryNameServer = parseName(buffer, length, &j, - MAX_ALLOWED_POINTERS); + maxAllowedPointers); OFString *responsiblePerson; uint32_t serialNumber, refreshInterval, retryInterval; uint32_t expirationInterval, minTTL; if (j > i + dataLength) @throw [OFInvalidServerReplyException exception]; responsiblePerson = parseName(buffer, length, &j, - MAX_ALLOWED_POINTERS); + maxAllowedPointers); if (dataLength - (j - i) != 20) @throw [OFInvalidServerReplyException exception]; serialNumber = (buffer[j] << 24) | (buffer[j + 1] << 16) | @@ -256,24 +253,24 @@ refreshInterval: refreshInterval retryInterval: retryInterval expirationInterval: expirationInterval minTTL: minTTL TTL: TTL] autorelease]; - } else if (recordType == OF_DNS_RECORD_TYPE_PTR) { + } else if (recordType == OFDNSRecordTypePTR) { size_t j = i; OFString *domainName = parseName(buffer, length, &j, - MAX_ALLOWED_POINTERS); + maxAllowedPointers); if (j != i + dataLength) @throw [OFInvalidServerReplyException exception]; return [[[OFPTRDNSResourceRecord alloc] initWithName: name DNSClass: DNSClass domainName: domainName TTL: TTL] autorelease]; - } else if (recordType == OF_DNS_RECORD_TYPE_HINFO) { + } else if (recordType == OFDNSRecordTypeHINFO) { size_t j = i; OFString *CPU = parseString(buffer, length, &j); OFString *OS; if (j > i + dataLength) @@ -288,11 +285,11 @@ initWithName: name DNSClass: DNSClass CPU: CPU OS: OS TTL: TTL] autorelease]; - } else if (recordType == OF_DNS_RECORD_TYPE_MX) { + } else if (recordType == OFDNSRecordTypeMX) { uint16_t preference; size_t j; OFString *mailExchange; if (dataLength < 2) @@ -300,11 +297,11 @@ preference = (buffer[i] << 8) | buffer[i + 1]; j = i + 2; mailExchange = parseName(buffer, length, &j, - MAX_ALLOWED_POINTERS); + maxAllowedPointers); if (j != i + dataLength) @throw [OFInvalidServerReplyException exception]; return [[[OFMXDNSResourceRecord alloc] @@ -311,11 +308,11 @@ initWithName: name DNSClass: DNSClass preference: preference mailExchange: mailExchange TTL: TTL] autorelease]; - } else if (recordType == OF_DNS_RECORD_TYPE_TXT) { + } else if (recordType == OFDNSRecordTypeTXT) { OFMutableArray *textStrings = [OFMutableArray array]; while (dataLength > 0) { uint_fast8_t stringLength = buffer[i++]; dataLength--; @@ -337,21 +334,21 @@ return [[[OFTXTDNSResourceRecord alloc] initWithName: name DNSClass: DNSClass textStrings: textStrings TTL: TTL] autorelease]; - } else if (recordType == OF_DNS_RECORD_TYPE_RP) { + } else if (recordType == OFDNSRecordTypeRP) { size_t j = i; OFString *mailbox = parseName(buffer, length, &j, - MAX_ALLOWED_POINTERS); + maxAllowedPointers); OFString *TXTDomainName; if (j > i + dataLength) @throw [OFInvalidServerReplyException exception]; TXTDomainName = parseName(buffer, length, &j, - MAX_ALLOWED_POINTERS); + maxAllowedPointers); if (j != i + dataLength) @throw [OFInvalidServerReplyException exception]; return [[[OFRPDNSResourceRecord alloc] @@ -358,19 +355,19 @@ initWithName: name DNSClass: DNSClass mailbox: mailbox TXTDomainName: TXTDomainName TTL: TTL] autorelease]; - } else if (recordType == OF_DNS_RECORD_TYPE_AAAA && - DNSClass == OF_DNS_CLASS_IN) { - of_socket_address_t address; + } else if (recordType == OFDNSRecordTypeAAAA && + DNSClass == OFDNSClassIN) { + OFSocketAddress address; if (dataLength != 16) @throw [OFInvalidServerReplyException exception]; memset(&address, 0, sizeof(address)); - address.family = OF_SOCKET_ADDRESS_FAMILY_IPV6; + address.family = OFSocketAddressFamilyIPv6; address.length = sizeof(address.sockaddr.in6); #ifdef AF_INET6 address.sockaddr.in6.sin6_family = AF_INET6; #else @@ -380,12 +377,12 @@ return [[[OFAAAADNSResourceRecord alloc] initWithName: name address: &address TTL: TTL] autorelease]; - } else if (recordType == OF_DNS_RECORD_TYPE_SRV && - DNSClass == OF_DNS_CLASS_IN) { + } else if (recordType == OFDNSRecordTypeSRV && + DNSClass == OFDNSClassIN) { uint16_t priority, weight, port; size_t j; OFString *target; if (dataLength < 6) @@ -394,11 +391,11 @@ priority = (buffer[i] << 8) | buffer[i + 1]; weight = (buffer[i + 2] << 8) | buffer[i + 3]; port = (buffer[i + 4] << 8) | buffer[i + 5]; j = i + 6; - target = parseName(buffer, length, &j, MAX_ALLOWED_POINTERS); + target = parseName(buffer, length, &j, maxAllowedPointers); if (j != i + dataLength) @throw [OFInvalidServerReplyException exception]; return [[[OFSRVDNSResourceRecord alloc] @@ -424,13 +421,13 @@ OFEnumerator OF_GENERIC(OFMutableArray *) *objectEnumerator; OFMutableArray *array; for (uint_fast16_t j = 0; j < count; j++) { OFString *name = parseName(buffer, length, i, - MAX_ALLOWED_POINTERS); - of_dns_class_t DNSClass; - of_dns_record_type_t recordType; + maxAllowedPointers); + OFDNSClass DNSClass; + OFDNSRecordType recordType; uint32_t TTL; uint16_t dataLength; OFDNSResourceRecord *record; if (*i + 10 > length) @@ -453,12 +450,11 @@ array = [ret objectForKey: name]; if (array == nil) { array = [OFMutableArray array]; - [ret setObject: array - forKey: name]; + [ret setObject: array forKey: name]; } [array addObject: record]; } @@ -491,24 +487,18 @@ queryData = [OFMutableData dataWithCapacity: 512]; /* Header */ - tmp = OF_BSWAP16_IF_LE(_ID.unsignedShortValue); - [queryData addItems: &tmp - count: 2]; - + tmp = OFToBigEndian16(_ID.unsignedShortValue); + [queryData addItems: &tmp count: 2]; /* RD */ - tmp = OF_BSWAP16_IF_LE(1u << 8); - [queryData addItems: &tmp - count: 2]; - + tmp = OFToBigEndian16(1u << 8); + [queryData addItems: &tmp count: 2]; /* QDCOUNT */ - tmp = OF_BSWAP16_IF_LE(1); - [queryData addItems: &tmp - count: 2]; - + tmp = OFToBigEndian16(1); + [queryData addItems: &tmp count: 2]; /* ANCOUNT, NSCOUNT and ARCOUNT */ [queryData increaseCountBy: 6]; /* Question */ @@ -526,19 +516,15 @@ [queryData addItems: component.UTF8String count: length]; } /* QTYPE */ - tmp = OF_BSWAP16_IF_LE(_query.recordType); - [queryData addItems: &tmp - count: 2]; - + tmp = OFToBigEndian16(_query.recordType); + [queryData addItems: &tmp count: 2]; /* QCLASS */ - tmp = OF_BSWAP16_IF_LE(_query.DNSClass); - [queryData addItems: &tmp - count: 2]; - + tmp = OFToBigEndian16(_query.DNSClass); + [queryData addItems: &tmp count: 2]; [queryData makeImmutable]; _queryData = [queryData copy]; objc_autoreleasePoolPop(pool); @@ -557,10 +543,11 @@ [_settings release]; [_delegate release]; [_queryData release]; [_TCPSocket release]; [_TCPQueryData release]; + OFFreeMemory(_TCPBuffer); [_cancelTimer release]; [super dealloc]; } @end @@ -570,11 +557,11 @@ + (void)initialize { if (self != [OFDNSResolver class]) return; - if (!of_socket_init()) + if (!OFSocketInit()) @throw [OFInitializationFailedException exceptionWithClass: self]; } #endif @@ -657,16 +644,16 @@ OFArray *old = _settings->_searchDomains; _settings->_searchDomains = [searchDomains copy]; [old release]; } -- (of_time_interval_t)timeout +- (OFTimeInterval)timeout { return _settings->_timeout; } -- (void)setTimeout: (of_time_interval_t)timeout +- (void)setTimeout: (OFTimeInterval)timeout { _settings->_timeout = timeout; } - (unsigned int)maxAttempts @@ -699,28 +686,27 @@ - (void)setUsesTCP: (bool)usesTCP { _settings->_usesTCP = usesTCP; } -- (of_time_interval_t)configReloadInterval +- (OFTimeInterval)configReloadInterval { return _settings->_configReloadInterval; } -- (void)setConfigReloadInterval: (of_time_interval_t)configReloadInterval +- (void)setConfigReloadInterval: (OFTimeInterval)configReloadInterval { _settings->_configReloadInterval = configReloadInterval; } - (void)of_sendQueryForContext: (OFDNSResolverContext *)context - runLoopMode: (of_run_loop_mode_t)runLoopMode + runLoopMode: (OFRunLoopMode)runLoopMode { OFUDPSocket *sock; OFString *nameServer; - [_queries setObject: context - forKey: context->_ID]; + [_queries setObject: context forKey: context->_ID]; [context->_cancelTimer invalidate]; [context->_cancelTimer release]; context->_cancelTimer = nil; context->_cancelTimer = [[OFTimer alloc] @@ -736,51 +722,58 @@ nameServer = [context->_settings->_nameServers objectAtIndex: context->_nameServersIndex]; if (context->_settings->_usesTCP) { - OF_ENSURE(context->_TCPSocket == nil); + OFEnsure(context->_TCPSocket == nil); context->_TCPSocket = [[OFTCPSocket alloc] init]; - [_TCPQueries setObject: context - forKey: context->_TCPSocket]; + [_TCPQueries setObject: context forKey: context->_TCPSocket]; context->_TCPSocket.delegate = self; [context->_TCPSocket asyncConnectToHost: nameServer port: 53 runLoopMode: runLoopMode]; return; } - context->_usedNameServer = of_socket_address_parse_ip(nameServer, 53); + context->_usedNameServer = OFSocketAddressParseIP(nameServer, 53); switch (context->_usedNameServer.family) { #ifdef OF_HAVE_IPV6 - case OF_SOCKET_ADDRESS_FAMILY_IPV6: + case OFSocketAddressFamilyIPv6: if (_IPv6Socket == nil) { - of_socket_address_t address = - of_socket_address_parse_ip(@"::", 0); + OFSocketAddress address = + OFSocketAddressParseIPv6(@"::", 0); _IPv6Socket = [[OFUDPSocket alloc] init]; [_IPv6Socket of_bindToAddress: &address extraType: SOCK_DNS]; - _IPv6Socket.canBlock = false; + @try { + _IPv6Socket.canBlock = false; + } @catch (OFNotImplementedException *e) { + /* Can't do anything about it... */ + } _IPv6Socket.delegate = self; } sock = _IPv6Socket; break; #endif - case OF_SOCKET_ADDRESS_FAMILY_IPV4: + case OFSocketAddressFamilyIPv4: if (_IPv4Socket == nil) { - of_socket_address_t address = - of_socket_address_parse_ip(@"0.0.0.0", 0); + OFSocketAddress address = + OFSocketAddressParseIPv4(@"0.0.0.0", 0); _IPv4Socket = [[OFUDPSocket alloc] init]; [_IPv4Socket of_bindToAddress: &address extraType: SOCK_DNS]; - _IPv4Socket.canBlock = false; + @try { + _IPv4Socket.canBlock = false; + } @catch (OFNotImplementedException *e) { + /* Can't do anything about it... */ + } _IPv4Socket.delegate = self; } sock = _IPv4Socket; break; @@ -790,42 +783,42 @@ [sock asyncSendData: context->_queryData receiver: &context->_usedNameServer runLoopMode: runLoopMode]; [sock asyncReceiveIntoBuffer: _buffer - length: BUFFER_LENGTH + length: bufferLength runLoopMode: runLoopMode]; } - (void)asyncPerformQuery: (OFDNSQuery *)query delegate: (id )delegate { [self asyncPerformQuery: query - runLoopMode: of_run_loop_mode_default + runLoopMode: OFDefaultRunLoopMode delegate: delegate]; } - (void)asyncPerformQuery: (OFDNSQuery *)query - runLoopMode: (of_run_loop_mode_t)runLoopMode + runLoopMode: (OFRunLoopMode)runLoopMode delegate: (id )delegate { void *pool = objc_autoreleasePoolPush(); OFNumber *ID; OFDNSResolverContext *context; /* Random, unused ID */ do { - ID = [OFNumber numberWithUnsignedShort: of_random16()]; + ID = [OFNumber numberWithUnsignedShort: OFRandom16()]; } while ([_queries objectForKey: ID] != nil); if (query.domainName.UTF8StringLength > 253) @throw [OFOutOfRangeException exception]; if (_settings->_nameServers.count == 0) { id exception = [OFDNSQueryFailedException exceptionWithQuery: query - error: OF_DNS_RESOLVER_ERROR_NO_NAME_SERVER]; + errorCode: OFDNSResolverErrorCodeNoNameServer]; [delegate resolver: self didPerformQuery: query response: nil exception: exception]; return; @@ -834,19 +827,18 @@ context = [[[OFDNSResolverContext alloc] initWithQuery: query ID: ID settings: _settings delegate: delegate] autorelease]; - [self of_sendQueryForContext: context - runLoopMode: runLoopMode]; + [self of_sendQueryForContext: context runLoopMode: runLoopMode]; objc_autoreleasePoolPop(pool); } - (void)of_contextTimedOut: (OFDNSResolverContext *)context { - of_run_loop_mode_t runLoopMode = [OFRunLoop currentRunLoop].currentMode; + OFRunLoopMode runLoopMode = [OFRunLoop currentRunLoop].currentMode; OFDNSQueryFailedException *exception; if (context->_TCPSocket != nil) { context->_TCPSocket.delegate = nil; [context->_TCPSocket cancelAsyncRequests]; @@ -858,19 +850,17 @@ } if (context->_nameServersIndex + 1 < context->_settings->_nameServers.count) { context->_nameServersIndex++; - [self of_sendQueryForContext: context - runLoopMode: runLoopMode]; + [self of_sendQueryForContext: context runLoopMode: runLoopMode]; return; } if (++context->_attempt < context->_settings->_maxAttempts) { context->_nameServersIndex = 0; - [self of_sendQueryForContext: context - runLoopMode: runLoopMode]; + [self of_sendQueryForContext: context runLoopMode: runLoopMode]; return; } context = [[context retain] autorelease]; [_queries removeObjectForKey: context->_ID]; @@ -878,31 +868,29 @@ /* * Cancel any pending queries, to avoid a send being still pending and * trying to access the query once it no longer exists. */ [_IPv4Socket cancelAsyncRequests]; - [_IPv4Socket asyncReceiveIntoBuffer: _buffer - length: BUFFER_LENGTH]; + [_IPv4Socket asyncReceiveIntoBuffer: _buffer length: bufferLength]; #ifdef OF_HAVE_IPV6 [_IPv6Socket cancelAsyncRequests]; - [_IPv6Socket asyncReceiveIntoBuffer: _buffer - length: BUFFER_LENGTH]; + [_IPv6Socket asyncReceiveIntoBuffer: _buffer length: bufferLength]; #endif exception = [OFDNSQueryFailedException exceptionWithQuery: context->_query - error: OF_DNS_RESOLVER_ERROR_TIMEOUT]; + errorCode: OFDNSResolverErrorCodeTimeout]; [context->_delegate resolver: self didPerformQuery: context->_query response: nil exception: exception]; } - (bool)of_handleResponseBuffer: (unsigned char *)buffer length: (size_t)length - sender: (const of_socket_address_t *)sender + sender: (const OFSocketAddress *)sender { OFDictionary *answerRecords = nil, *authorityRecords = nil; OFDictionary *additionalRecords = nil; OFDNSResponse *response = nil; id exception = nil; @@ -920,20 +908,20 @@ return true; if (context->_TCPSocket != nil) { if ([_TCPQueries objectForKey: context->_TCPSocket] != context) return true; - } else if (!of_socket_address_equal(sender, &context->_usedNameServer)) + } else if (!OFSocketAddressEqual(sender, &context->_usedNameServer)) return true; [context->_cancelTimer invalidate]; [context->_cancelTimer release]; context->_cancelTimer = nil; [_queries removeObjectForKey: ID]; @try { - of_dns_resolver_error_t error = 0; + OFDNSResolverErrorCode errorCode = 0; bool tryNextNameServer = false; const unsigned char *queryDataBuffer; size_t i; uint16_t numQuestions, numAnswers, numAuthorityRecords; uint16_t numAdditionalRecords; @@ -955,11 +943,11 @@ if ((buffer[2] & 0x78) != (queryDataBuffer[2] & 0x78)) @throw [OFInvalidServerReplyException exception]; /* TC */ if (buffer[2] & 0x02) { - of_run_loop_mode_t runLoopMode; + OFRunLoopMode runLoopMode; if (context->_settings->_usesTCP) @throw [OFTruncatedDataException exception]; context->_settings->_usesTCP = true; @@ -972,37 +960,37 @@ /* RCODE */ switch (buffer[3] & 0x0F) { case 0: break; case 1: - error = OF_DNS_RESOLVER_ERROR_SERVER_INVALID_FORMAT; + errorCode = OFDNSResolverErrorCodeServerInvalidFormat; break; case 2: - error = OF_DNS_RESOLVER_ERROR_SERVER_FAILURE; + errorCode = OFDNSResolverErrorCodeServerFailure; tryNextNameServer = true; break; case 3: - error = OF_DNS_RESOLVER_ERROR_SERVER_NAME_ERROR; + errorCode = OFDNSResolverErrorCodeServerNameError; break; case 4: - error = OF_DNS_RESOLVER_ERROR_SERVER_NOT_IMPLEMENTED; + errorCode = OFDNSResolverErrorCodeServerNotImplemented; tryNextNameServer = true; break; case 5: - error = OF_DNS_RESOLVER_ERROR_SERVER_REFUSED; + errorCode = OFDNSResolverErrorCodeServerRefused; tryNextNameServer = true; break; default: - error = OF_DNS_RESOLVER_ERROR_UNKNOWN; + errorCode = OFDNSResolverErrorCodeUnknown; tryNextNameServer = true; break; } if (tryNextNameServer) { if (context->_nameServersIndex + 1 < context->_settings->_nameServers.count) { - of_run_loop_mode_t runLoopMode = + OFRunLoopMode runLoopMode = [OFRunLoop currentRunLoop].currentMode; context->_nameServersIndex++; [self of_sendQueryForContext: context @@ -1012,11 +1000,11 @@ } if (buffer[3] & 0x0F) @throw [OFDNSQueryFailedException exceptionWithQuery: context->_query - error: error]; + errorCode: errorCode]; numQuestions = (buffer[4] << 8) | buffer[5]; numAnswers = (buffer[6] << 8) | buffer[7]; numAuthorityRecords = (buffer[8] << 8) | buffer[9]; numAdditionalRecords = (buffer[10] << 8) | buffer[11]; @@ -1028,11 +1016,11 @@ * query. * * TODO: Compare to our query, just in case? */ for (uint_fast16_t j = 0; j < numQuestions; j++) { - parseName(buffer, length, &i, MAX_ALLOWED_POINTERS); + parseName(buffer, length, &i, maxAllowedPointers); i += 4; } answerRecords = parseSection(buffer, length, &i, numAnswers); authorityRecords = parseSection(buffer, length, &i, @@ -1060,11 +1048,11 @@ } - (bool)socket: (OFDatagramSocket *)sock didReceiveIntoBuffer: (void *)buffer length: (size_t)length - sender: (const of_socket_address_t *)sender + sender: (const OFSocketAddress *)sender exception: (id)exception { if (exception != nil) return true; @@ -1078,11 +1066,11 @@ port: (uint16_t)port exception: (id)exception { OFDNSResolverContext *context = [_TCPQueries objectForKey: sock]; - OF_ENSURE(context != nil); + OFEnsure(context != nil); if (exception != nil) { /* * TODO: Handle error immediately instead of waiting for the * timer to try the next nameserver or to retry. @@ -1102,13 +1090,12 @@ @throw [OFOutOfRangeException exception]; context->_TCPQueryData = [[OFMutableData alloc] initWithCapacity: queryDataCount + 2]; - tmp = OF_BSWAP16_IF_LE(queryDataCount); - [context->_TCPQueryData addItems: &tmp - count: sizeof(tmp)]; + tmp = OFToBigEndian16(queryDataCount); + [context->_TCPQueryData addItems: &tmp count: sizeof(tmp)]; [context->_TCPQueryData addItems: context->_queryData.items count: queryDataCount]; } [sock asyncWriteData: context->_TCPQueryData]; @@ -1120,11 +1107,11 @@ exception: (id)exception { OFTCPSocket *sock = (OFTCPSocket *)stream; OFDNSResolverContext *context = [_TCPQueries objectForKey: sock]; - OF_ENSURE(context != nil); + OFEnsure(context != nil); if (exception != nil) { /* * TODO: Handle error immediately instead of waiting for the * timer to try the next nameserver or to retry. @@ -1135,15 +1122,13 @@ context->_responseLength = 0; return nil; } if (context->_TCPBuffer == nil) - context->_TCPBuffer = - [context allocMemoryWithSize: MAX_DNS_RESPONSE_LENGTH]; + context->_TCPBuffer = OFAllocMemory(maxDNSResponseLength, 1); - [sock asyncReadIntoBuffer: context->_TCPBuffer - exactLength: 2]; + [sock asyncReadIntoBuffer: context->_TCPBuffer exactLength: 2]; return nil; } - (bool)stream: (OFStream *)stream didReadIntoBuffer: (void *)buffer @@ -1151,11 +1136,11 @@ exception: (id)exception { OFTCPSocket *sock = (OFTCPSocket *)stream; OFDNSResolverContext *context = [_TCPQueries objectForKey: sock]; - OF_ENSURE(context != nil); + OFEnsure(context != nil); if (exception != nil) { /* * TODO: Handle error immediately instead of waiting for the * timer to try the next nameserver or to retry. @@ -1164,15 +1149,15 @@ } if (context->_responseLength == 0) { unsigned char *ucBuffer = buffer; - OF_ENSURE(length == 2); + OFEnsure(length == 2); context->_responseLength = (ucBuffer[0] << 8) | ucBuffer[1]; - if (context->_responseLength > MAX_DNS_RESPONSE_LENGTH) + if (context->_responseLength > maxDNSResponseLength) @throw [OFOutOfRangeException exception]; if (context->_responseLength == 0) goto done; @@ -1186,13 +1171,11 @@ * The connection was closed before we received the entire * response. */ goto done; - [self of_handleResponseBuffer: buffer - length: length - sender: NULL]; + [self of_handleResponseBuffer: buffer length: length sender: NULL]; done: [_TCPQueries removeObjectForKey: context->_TCPSocket]; [context->_TCPSocket release]; context->_TCPSocket = nil; @@ -1203,28 +1186,28 @@ - (void)asyncResolveAddressesForHost: (OFString *)host delegate: (id )delegate { [self asyncResolveAddressesForHost: host - addressFamily: OF_SOCKET_ADDRESS_FAMILY_ANY - runLoopMode: of_run_loop_mode_default + addressFamily: OFSocketAddressFamilyAny + runLoopMode: OFDefaultRunLoopMode delegate: delegate]; } - (void)asyncResolveAddressesForHost: (OFString *)host - addressFamily: (of_socket_address_family_t)addressFamily + addressFamily: (OFSocketAddressFamily)addressFamily delegate: (id )delegate { [self asyncResolveAddressesForHost: host addressFamily: addressFamily - runLoopMode: of_run_loop_mode_default + runLoopMode: OFDefaultRunLoopMode delegate: delegate]; } - (void)asyncResolveAddressesForHost: (OFString *)host - addressFamily: (of_socket_address_family_t)addressFamily - runLoopMode: (of_run_loop_mode_t)runLoopMode + addressFamily: (OFSocketAddressFamily)addressFamily + runLoopMode: (OFRunLoopMode)runLoopMode delegate: (id )delegate { void *pool = objc_autoreleasePoolPush(); OFHostAddressResolver *resolver = [[[OFHostAddressResolver alloc] initWithHost: host @@ -1238,11 +1221,11 @@ objc_autoreleasePoolPop(pool); } - (OFData *)resolveAddressesForHost: (OFString *)host - addressFamily: (of_socket_address_family_t)addressFamily + addressFamily: (OFSocketAddressFamily)addressFamily { void *pool = objc_autoreleasePoolPush(); OFHostAddressResolver *resolver = [[[OFHostAddressResolver alloc] initWithHost: host addressFamily: addressFamily @@ -1279,11 +1262,11 @@ while ((context = [enumerator nextObject]) != nil) { OFDNSQueryFailedException *exception; exception = [OFDNSQueryFailedException exceptionWithQuery: context->_query - error: OF_DNS_RESOLVER_ERROR_CANCELED]; + errorCode: OFDNSResolverErrorCodeCanceled]; [context->_delegate resolver: self didPerformQuery: context->_query response: nil exception: exception]; Index: src/OFDNSResolverSettings.h ================================================================== --- src/OFDNSResolverSettings.h +++ src/OFDNSResolverSettings.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -29,17 +27,17 @@ OFDictionary OF_GENERIC(OFString *, OFArray OF_GENERIC(OFString *) *) *_staticHosts; OFArray OF_GENERIC(OFString *) *_nameServers; OFString *_Nullable _localDomain; OFArray OF_GENERIC(OFString *) *_searchDomains; - of_time_interval_t _timeout; + OFTimeInterval _timeout; unsigned int _maxAttempts, _minNumberOfDotsInAbsoluteName; bool _usesTCP; - of_time_interval_t _configReloadInterval; + OFTimeInterval _configReloadInterval; @protected OFDate *_lastConfigReload; } - (void)reload; @end OF_ASSUME_NONNULL_END Index: src/OFDNSResolverSettings.m ================================================================== --- src/OFDNSResolverSettings.m +++ src/OFDNSResolverSettings.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -24,10 +22,11 @@ #import "OFCharacterSet.h" #import "OFDate.h" #import "OFDictionary.h" #import "OFFile.h" #import "OFLocale.h" +#import "OFSocket+Private.h" #import "OFString.h" #ifdef OF_WINDOWS # import "OFWindowsRegistryKey.h" #endif @@ -47,18 +46,19 @@ # define id id_3ds # include <3ds.h> # undef id #endif -#import "socket_helpers.h" +#ifdef OF_MORPHOS +# include +# include +# include +#endif #if defined(OF_HAIKU) # define HOSTS_PATH @"/system/settings/network/hosts" # define RESOLV_CONF_PATH @"/system/settings/network/resolv.conf" -#elif defined(OF_MORPHOS) -# define HOSTS_PATH @"ENV:sys/net/hosts" -# define RESOLV_CONF_PATH @"ENV:sys/net/resolv.conf" #elif defined(OF_AMIGAOS4) # define HOSTS_PATH @"DEVS:Internet/hosts" #elif defined(OF_AMIGAOS) # define HOSTS_PATH @"AmiTCP:db/hosts" # define RESOLV_CONF_PATH @"AmiTCP:db/resolv.conf" @@ -67,42 +67,124 @@ # define RESOLV_CONF_PATH @"/etc/resolv.conf" #endif #ifndef OF_WII static OFString * -domainFromHostname(void) +domainFromHostname(OFString *hostname) { - char hostname[256]; - OFString *domain, *ret; + OFString *ret; - if (gethostname(hostname, 256) != 0) + if (hostname == nil) return nil; - domain = [OFString stringWithCString: hostname - encoding: [OFLocale encoding]]; - @try { - of_socket_address_parse_ip(domain, 0); + OFSocketAddressParseIP(hostname, 0); /* * If we are still here, the host name is a valid IP address. * We can't use that as local domain. */ - return nil; + ret = nil; } @catch (OFInvalidFormatException *e) { /* Not an IP address -> we can use it if it contains a dot. */ - size_t pos = [domain rangeOfString: @"."].location; + size_t pos = [hostname rangeOfString: @"."].location; - if (pos == OF_NOT_FOUND) - return nil; - - ret = [domain substringFromIndex: pos + 1]; + if (pos != OFNotFound) + ret = [hostname substringFromIndex: pos + 1]; + else + ret = nil; } return ret; } #endif + +#if !defined(OF_WII) && !defined(OF_MORPHOS) +static OFString * +obtainHostname(void) +{ + char hostname[256]; + + if (gethostname(hostname, 256) != 0) + return nil; + + return [OFString stringWithCString: hostname + encoding: [OFLocale encoding]]; +} +#endif + +#ifdef OF_MORPHOS +static OFString * +arexxCommand(const char *port, const char *command) +{ + struct Library *RexxSysBase; + struct MsgPort *replyPort = NULL; + struct RexxMsg *msg = NULL; + + if ((RexxSysBase = OpenLibrary("rexxsyslib.library", 36)) == NULL) + return nil; + + @try { + struct MsgPort *rexxPort; + + if ((replyPort = CreateMsgPort()) == NULL) + return nil; + + if ((msg = CreateRexxMsg(replyPort, NULL, port)) == NULL) + return nil; + + msg->rm_Action = RXCOMM | RXFF_RESULT; + + if ((msg->rm_Args[0] = (char *)CreateArgstring( + command, strlen(command))) == NULL) + return nil; + + Forbid(); + + if ((rexxPort = FindPort(port)) == NULL) { + Permit(); + return nil; + } + + PutMsg(rexxPort, &msg->rm_Node); + Permit(); + WaitPort(replyPort); + GetMsg(replyPort); + + if (msg->rm_Result1 != RC_OK || msg->rm_Result2 == 0) + return nil; + + return [OFString stringWithCString: (char *)msg->rm_Result2 + encoding: [OFLocale encoding]]; + } @finally { + if (msg != NULL) { + if (msg->rm_Args[0] != NULL) + DeleteArgstring(msg->rm_Args[0]); + if (msg->rm_Result2 != 0) + DeleteArgstring((char *)msg->rm_Result2); + + DeleteRexxMsg(msg); + } + + if (replyPort != NULL) + DeleteMsgPort(replyPort); + + CloseLibrary(RexxSysBase); + } +} + +static OFArray OF_GENERIC(OFString *) * +parseNetStackArray(OFString *string) +{ + if (![string hasPrefix: @"["] || ![string hasSuffix: @"]"]) + return nil; + + string = [string substringWithRange: OFRangeMake(1, string.length - 2)]; + + return [string componentsSeparatedByString: @"|"]; +} +#endif @implementation OFDNSResolverSettings - (void)dealloc { [_staticHosts release]; @@ -161,77 +243,65 @@ #else _configReloadInterval = 0; #endif } -#if defined(OF_HAVE_FILES) && !defined(OF_NINTENDO_3DS) +#if defined(OF_HAVE_FILES) && !defined(OF_MORPHOS) && !defined(OF_NINTENDO_3DS) - (void)parseHosts: (OFString *)path { void *pool = objc_autoreleasePoolPush(); OFCharacterSet *whitespaceCharacterSet = [OFCharacterSet whitespaceCharacterSet]; OFMutableDictionary *staticHosts; OFFile *file; OFString *line; - OFEnumerator *enumerator; - OFMutableArray *addresses; @try { - file = [OFFile fileWithPath: path - mode: @"r"]; + file = [OFFile fileWithPath: path mode: @"r"]; } @catch (OFOpenItemFailedException *e) { objc_autoreleasePoolPop(pool); return; } staticHosts = [OFMutableDictionary dictionary]; while ((line = [file readLine]) != nil) { - void *pool2 = objc_autoreleasePoolPush(); OFArray *components, *hosts; size_t pos; OFString *address; pos = [line rangeOfString: @"#"].location; - if (pos != OF_NOT_FOUND) + if (pos != OFNotFound) line = [line substringToIndex: pos]; components = [line componentsSeparatedByCharactersInSet: whitespaceCharacterSet - options: OF_STRING_SKIP_EMPTY]; + options: OFStringSkipEmptyComponents]; - if (components.count < 2) { - objc_autoreleasePoolPop(pool2); + if (components.count < 2) continue; - } address = components.firstObject; hosts = [components objectsInRange: - of_range(1, components.count - 1)]; + OFRangeMake(1, components.count - 1)]; for (OFString *host in hosts) { - addresses = [staticHosts objectForKey: host]; + OFMutableArray *addresses = + [staticHosts objectForKey: host]; if (addresses == nil) { addresses = [OFMutableArray array]; - [staticHosts setObject: addresses - forKey: host]; + [staticHosts setObject: addresses forKey: host]; } [addresses addObject: address]; } - - objc_autoreleasePoolPop(pool2); } - - enumerator = [staticHosts objectEnumerator]; - while ((addresses = [enumerator nextObject]) != nil) + for (OFMutableArray *addresses in [staticHosts objectEnumerator]) [addresses makeImmutable]; [staticHosts makeImmutable]; - - [_staticHosts release]; _staticHosts = [staticHosts copy]; objc_autoreleasePoolPop(pool); } @@ -283,12 +353,11 @@ OFMutableArray *nameServers = [[_nameServers mutableCopy] autorelease]; OFFile *file; OFString *line; @try { - file = [OFFile fileWithPath: path - mode: @"r"]; + file = [OFFile fileWithPath: path mode: @"r"]; } @catch (OFOpenItemFailedException *e) { objc_autoreleasePoolPop(pool); return; } @@ -300,33 +369,33 @@ size_t pos; OFArray *components, *arguments; OFString *option; pos = [line indexOfCharacterFromSet: commentCharacters]; - if (pos != OF_NOT_FOUND) + if (pos != OFNotFound) line = [line substringToIndex: pos]; components = [line componentsSeparatedByCharactersInSet: whitespaceCharacterSet - options: OF_STRING_SKIP_EMPTY]; + options: OFStringSkipEmptyComponents]; if (components.count < 2) { objc_autoreleasePoolPop(pool2); continue; } option = components.firstObject; arguments = [components objectsInRange: - of_range(1, components.count - 1)]; + OFRangeMake(1, components.count - 1)]; if ([option isEqual: @"nameserver"]) { if (arguments.count != 1) { objc_autoreleasePoolPop(pool2); continue; } - [nameServers addObject: [arguments firstObject]]; + [nameServers addObject: arguments.firstObject]; } else if ([option isEqual: @"domain"]) { if (arguments.count != 1) { objc_autoreleasePoolPop(pool2); continue; } @@ -354,11 +423,11 @@ #endif #ifdef OF_WINDOWS - (void)obtainWindowsSystemConfig { - of_string_encoding_t encoding = [OFLocale encoding]; + OFStringEncoding encoding = [OFLocale encoding]; OFMutableArray *nameServers; /* * We need more space than FIXED_INFO in case we have more than one * name server, but we also want it to be properly aligned, meaning we * can't just get a buffer of bytes. Thus, we just get space for 8. @@ -386,16 +455,66 @@ _localDomain = [[OFString alloc] initWithCString: fixedInfo->DomainName encoding: encoding]; } #endif + +#ifdef OF_MORPHOS +- (void)obtainMorphOSSystemConfig +{ + void *pool = objc_autoreleasePoolPush(); + OFMutableDictionary *staticHosts; + + _nameServers = [parseNetStackArray(arexxCommand("NETSTACK", + "QUERY NAMESERVERS")) copy]; + _localDomain = [domainFromHostname(arexxCommand("NETSTACK", + "QUERY HOSTNAME")) copy]; + _searchDomains = [parseNetStackArray(arexxCommand("NETSTACK", + "QUERY DOMAINS")) copy]; + + staticHosts = [OFMutableDictionary dictionary]; + + for (OFString *entry in parseNetStackArray(arexxCommand("NETSTACK", + "QUERY HOSTS"))) { + OFArray *components = [entry componentsSeparatedByString: @" "]; + OFString *address; + OFArray *hosts; + + if (components.count < 2) + continue; + + address = components.firstObject; + hosts = [components objectsInRange: + OFRangeMake(1, components.count - 1)]; + + for (OFString *host in hosts) { + OFMutableArray *addresses = + [staticHosts objectForKey: host]; + + if (addresses == nil) { + addresses = [OFMutableArray array]; + [staticHosts setObject: addresses forKey: host]; + } + + [addresses addObject: address]; + } + } + for (OFMutableArray *addresses in [staticHosts objectEnumerator]) + [addresses makeImmutable]; + + [staticHosts makeImmutable]; + _staticHosts = [staticHosts copy]; + + objc_autoreleasePoolPop(pool); +} +#endif #ifdef OF_AMIGAOS4 - (void)obtainAmigaOS4SystemConfig { OFMutableArray *nameServers = [OFMutableArray array]; - of_string_encoding_t encoding = [OFLocale encoding]; + OFStringEncoding encoding = [OFLocale encoding]; struct List *nameServerList = ObtainDomainNameServerList(); char buffer[MAXHOSTNAMELEN]; if (nameServerList == NULL) @throw [OFOutOfMemoryException exception]; @@ -456,11 +575,11 @@ */ if (optLen < sizeof(buffer.entries)) return; for (uint_fast8_t i = 0; i < 2; i++) { - uint32_t ip = OF_BSWAP32_IF_LE(buffer.entries[i].ip.s_addr); + uint32_t ip = OFFromBigEndian32(buffer.entries[i].ip.s_addr); if (ip == 0) continue; [nameServers addObject: [OFString stringWithFormat: @@ -499,19 +618,21 @@ # ifdef OF_HAVE_FILES OFWindowsRegistryKey *key = [[OFWindowsRegistryKey localMachineKey] openSubkeyAtPath: @"SYSTEM\\CurrentControlSet\\Services\\" @"Tcpip\\Parameters" securityAndAccessRights: KEY_QUERY_VALUE]; - path = [[[key stringForValue: @"DataBasePath"] + path = [[[key stringForValueNamed: @"DataBasePath"] stringByAppendingPathComponent: @"hosts"] stringByExpandingWindowsEnvironmentStrings]; if (path != nil) [self parseHosts: path]; # endif [self obtainWindowsSystemConfig]; +#elif defined(OF_MORPHOS) + [self obtainMorphOSSystemConfig]; #elif defined(OF_AMIGAOS4) [self parseHosts: HOSTS_PATH]; [self obtainAmigaOS4SystemConfig]; #elif defined(OF_NINTENDO_3DS) [self obtainNintendo3DSSytemConfig]; @@ -539,13 +660,13 @@ initWithObjects: @"127.0.0.1", @"::1", nil]; #else _nameServers = [[OFArray alloc] initWithObject: @"127.0.0.1"]; #endif -#ifndef OF_WII +#if !defined(OF_WII) && !defined(OF_MORPHOS) if (_localDomain == nil) - _localDomain = [domainFromHostname() copy]; + _localDomain = [domainFromHostname(obtainHostname()) copy]; #endif if (_searchDomains == nil) { if (_localDomain != nil) _searchDomains = [[OFArray alloc] Index: src/OFDNSResourceRecord.h ================================================================== --- src/OFDNSResourceRecord.h +++ src/OFDNSResourceRecord.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -14,14 +12,13 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #import "OFObject.h" +#import "OFSocket.h" #import "OFString.h" -#import "socket.h" - OF_ASSUME_NONNULL_BEGIN /** @file */ @class OFArray OF_GENERIC(ObjectType); @@ -30,55 +27,55 @@ /** * @brief The DNS class. */ typedef enum { /** IN */ - OF_DNS_CLASS_IN = 1, + OFDNSClassIN = 1, /** Any class. Only for queries. */ - OF_DNS_CLASS_ANY = 255, -} of_dns_class_t; + OFDNSClassAny = 255, +} OFDNSClass; /** * @brief The type of a DNS resource record. */ typedef enum { /** A */ - OF_DNS_RECORD_TYPE_A = 1, + OFDNSRecordTypeA = 1, /** NS */ - OF_DNS_RECORD_TYPE_NS = 2, + OFDNSRecordTypeNS = 2, /** CNAME */ - OF_DNS_RECORD_TYPE_CNAME = 5, + OFDNSRecordTypeCNAME = 5, /** SOA */ - OF_DNS_RECORD_TYPE_SOA = 6, + OFDNSRecordTypeSOA = 6, /** PTR */ - OF_DNS_RECORD_TYPE_PTR = 12, + OFDNSRecordTypePTR = 12, /** HINFO */ - OF_DNS_RECORD_TYPE_HINFO = 13, + OFDNSRecordTypeHINFO = 13, /** MX */ - OF_DNS_RECORD_TYPE_MX = 15, + OFDNSRecordTypeMX = 15, /** TXT */ - OF_DNS_RECORD_TYPE_TXT = 16, + OFDNSRecordTypeTXT = 16, /** RP */ - OF_DNS_RECORD_TYPE_RP = 17, + OFDNSRecordTypeRP = 17, /** AAAA */ - OF_DNS_RECORD_TYPE_AAAA = 28, + OFDNSRecordTypeAAAA = 28, /** SRV */ - OF_DNS_RECORD_TYPE_SRV = 33, + OFDNSRecordTypeSRV = 33, /** All types. Only for queries. */ - OF_DNS_RECORD_TYPE_ALL = 255, -} of_dns_record_type_t; + OFDNSRecordTypeAll = 255, +} OFDNSRecordType; /** * @class OFDNSResourceRecord OFDNSResourceRecord.h ObjFW/OFDNSResourceRecord.h * * @brief A class representing a DNS resource record. */ @interface OFDNSResourceRecord: OFObject { OFString *_name; - of_dns_class_t _DNSClass; - of_dns_record_type_t _recordType; + OFDNSClass _DNSClass; + OFDNSRecordType _recordType; uint32_t _TTL; OF_RESERVE_IVARS(OFDNSResourceRecord, 4) } /** @@ -87,16 +84,16 @@ @property (readonly, nonatomic) OFString *name; /** * @brief The DNS class. */ -@property (readonly, nonatomic) of_dns_class_t DNSClass; +@property (readonly, nonatomic) OFDNSClass DNSClass; /** * @brief The resource record type code. */ -@property (readonly, nonatomic) of_dns_record_type_t recordType; +@property (readonly, nonatomic) OFDNSRecordType recordType; /** * @brief The number of seconds after which the resource record should be * discarded from the cache. */ @@ -111,12 +108,12 @@ * @param recordType The type code for the resource record * @param TTL The time to live for the resource record * @return An initialized OFDNSResourceRecord */ - (instancetype)initWithName: (OFString *)name - DNSClass: (of_dns_class_t)DNSClass - recordType: (of_dns_record_type_t)recordType + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; @end /** * @class OFADNSResourceRecord OFDNSResourceRecord.h ObjFW/OFDNSResourceRecord.h @@ -124,21 +121,21 @@ * @brief A class representing an A DNS resource record. */ OF_SUBCLASSING_RESTRICTED @interface OFADNSResourceRecord: OFDNSResourceRecord { - of_socket_address_t _address; + OFSocketAddress _address; } /** * @brief The IPv4 address of the resource record. */ -@property (readonly, nonatomic) const of_socket_address_t *address; +@property (readonly, nonatomic) const OFSocketAddress *address; - (instancetype)initWithName: (OFString *)name - DNSClass: (of_dns_class_t)DNSClass - recordType: (of_dns_record_type_t)recordType + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType TTL: (uint32_t)TTL OF_UNAVAILABLE; /** * @brief Initializes an already allocated OFADNSResourceRecord with the * specified name, class, address and time to live. @@ -147,11 +144,11 @@ * @param address The address for the resource record * @param TTL The time to live for the resource record * @return An initialized OFADNSResourceRecord */ - (instancetype)initWithName: (OFString *)name - address: (const of_socket_address_t *)address + address: (const OFSocketAddress *)address TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; @end /** * @class OFAAAADNSResourceRecord \ @@ -160,21 +157,21 @@ * @brief A class represenging a DNS resource record. */ OF_SUBCLASSING_RESTRICTED @interface OFAAAADNSResourceRecord: OFDNSResourceRecord { - of_socket_address_t _address; + OFSocketAddress _address; } /** * @brief The IPv6 address of the resource record. */ -@property (readonly, nonatomic) const of_socket_address_t *address; +@property (readonly, nonatomic) const OFSocketAddress *address; - (instancetype)initWithName: (OFString *)name - DNSClass: (of_dns_class_t)DNSClass - recordType: (of_dns_record_type_t)recordType + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType TTL: (uint32_t)TTL OF_UNAVAILABLE; /** * @brief Initializes an already allocated OFAAAADNSResourceRecord with the * specified name, class, address and time to live. @@ -183,11 +180,11 @@ * @param address The address for the resource record * @param TTL The time to live for the resource record * @return An initialized OFAAAADNSResourceRecord */ - (instancetype)initWithName: (OFString *)name - address: (const of_socket_address_t *)address + address: (const OFSocketAddress *)address TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; @end /** * @class OFCNAMEDNSResourceRecord \ @@ -205,12 +202,12 @@ * @brief The alias of the resource record. */ @property (readonly, nonatomic) OFString *alias; - (instancetype)initWithName: (OFString *)name - DNSClass: (of_dns_class_t)DNSClass - recordType: (of_dns_record_type_t)recordType + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType TTL: (uint32_t)TTL OF_UNAVAILABLE; /** * @brief Initializes an already allocated OFCNAMEDNSResourceRecord with the * specified name, class, alias and time to live. @@ -220,11 +217,11 @@ * @param alias The alias for the resource record * @param TTL The time to live for the resource record * @return An initialized OFCNAMEDNSResourceRecord */ - (instancetype)initWithName: (OFString *)name - DNSClass: (of_dns_class_t)DNSClass + DNSClass: (OFDNSClass)DNSClass alias: (OFString *)alias TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; @end /** @@ -248,12 +245,12 @@ * @brief The OS of the host info of the resource record. */ @property (readonly, nonatomic) OFString *OS; - (instancetype)initWithName: (OFString *)name - DNSClass: (of_dns_class_t)DNSClass - recordType: (of_dns_record_type_t)recordType + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType TTL: (uint32_t)TTL OF_UNAVAILABLE; /** * @brief Initializes an already allocated OFHINFODNSResourceRecord with the * specified name, class, domain name and time to live. @@ -264,11 +261,11 @@ * @param OS The OS of the host info for the resource record * @param TTL The time to live for the resource record * @return An initialized OFHINFODNSResourceRecord */ - (instancetype)initWithName: (OFString *)name - DNSClass: (of_dns_class_t)DNSClass + DNSClass: (OFDNSClass)DNSClass CPU: (OFString *)CPU OS: (OFString *)OS TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; @end @@ -294,12 +291,12 @@ * @brief The mail exchange of the resource record. */ @property (readonly, nonatomic) OFString *mailExchange; - (instancetype)initWithName: (OFString *)name - DNSClass: (of_dns_class_t)DNSClass - recordType: (of_dns_record_type_t)recordType + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType TTL: (uint32_t)TTL OF_UNAVAILABLE; /** * @brief Initializes an already allocated OFMXDNSResourceRecord with the * specified name, class, preference, mail exchange and time to live. @@ -310,11 +307,11 @@ * @param mailExchange The mail exchange for the resource record * @param TTL The time to live for the resource record * @return An initialized OFMXDNSResourceRecord */ - (instancetype)initWithName: (OFString *)name - DNSClass: (of_dns_class_t)DNSClass + DNSClass: (OFDNSClass)DNSClass preference: (uint16_t)preference mailExchange: (OFString *)mailExchange TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; @end @@ -334,12 +331,12 @@ * @brief The authoritative host of the resource record. */ @property (readonly, nonatomic) OFString *authoritativeHost; - (instancetype)initWithName: (OFString *)name - DNSClass: (of_dns_class_t)DNSClass - recordType: (of_dns_record_type_t)recordType + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType TTL: (uint32_t)TTL OF_UNAVAILABLE; /** * @brief Initializes an already allocated OFNSDNSResourceRecord with the * specified name, class, authoritative host and time to live. @@ -349,11 +346,11 @@ * @param authoritativeHost The authoritative host for the resource record * @param TTL The time to live for the resource record * @return An initialized OFNSDNSResourceRecord */ - (instancetype)initWithName: (OFString *)name - DNSClass: (of_dns_class_t)DNSClass + DNSClass: (OFDNSClass)DNSClass authoritativeHost: (OFString *)authoritativeHost TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; @end /** @@ -372,12 +369,12 @@ * @brief The domain name of the resource record. */ @property (readonly, nonatomic) OFString *domainName; - (instancetype)initWithName: (OFString *)name - DNSClass: (of_dns_class_t)DNSClass - recordType: (of_dns_record_type_t)recordType + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType TTL: (uint32_t)TTL OF_UNAVAILABLE; /** * @brief Initializes an already allocated OFPTRDNSResourceRecord with the * specified name, class, domain name and time to live. @@ -387,11 +384,11 @@ * @param domainName The domain name for the resource record * @param TTL The time to live for the resource record * @return An initialized OFPTRDNSResourceRecord */ - (instancetype)initWithName: (OFString *)name - DNSClass: (of_dns_class_t)DNSClass + DNSClass: (OFDNSClass)DNSClass domainName: (OFString *)domainName TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; @end /** @@ -416,12 +413,12 @@ * person of the resource record. */ @property (readonly, nonatomic) OFString *TXTDomainName; - (instancetype)initWithName: (OFString *)name - DNSClass: (of_dns_class_t)DNSClass - recordType: (of_dns_record_type_t)recordType + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType TTL: (uint32_t)TTL OF_UNAVAILABLE; /** * @brief Initializes an already allocated OFRPDNSResourceRecord with the * specified name, class, alias and time to live. @@ -433,11 +430,11 @@ * the responsible person of the resource record * @param TTL The time to live for the resource record * @return An initialized OFRPDNSResourceRecord */ - (instancetype)initWithName: (OFString *)name - DNSClass: (of_dns_class_t)DNSClass + DNSClass: (OFDNSClass)DNSClass mailbox: (OFString *)mailbox TXTDomainName: (OFString *)TXTDomainName TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; @end @@ -489,12 +486,12 @@ * @brief The minimum TTL of the zone. */ @property (readonly, nonatomic) uint32_t minTTL; - (instancetype)initWithName: (OFString *)name - DNSClass: (of_dns_class_t)DNSClass - recordType: (of_dns_record_type_t)recordType + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType TTL: (uint32_t)TTL OF_UNAVAILABLE; /** * @brief Initializes an already allocated OFSOADNSResourceRecord with the * specified name, class, text data and time to live. @@ -510,11 +507,11 @@ * @param minTTL The minimum TTL of the zone * @param TTL The time to live for the resource record * @return An initialized OFSOADNSResourceRecord */ - (instancetype)initWithName: (OFString *)name - DNSClass: (of_dns_class_t)DNSClass + DNSClass: (OFDNSClass)DNSClass primaryNameServer: (OFString *)primaryNameServer responsiblePerson: (OFString *)responsiblePerson serialNumber: (uint32_t)serialNumber refreshInterval: (uint32_t)refreshInterval retryInterval: (uint32_t)retryInterval @@ -556,12 +553,12 @@ * @brief The port on the target of the resource record. */ @property (readonly, nonatomic) uint16_t port; - (instancetype)initWithName: (OFString *)name - DNSClass: (of_dns_class_t)DNSClass - recordType: (of_dns_record_type_t)recordType + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType TTL: (uint32_t)TTL OF_UNAVAILABLE; /** * @brief Initializes an already allocated OFSRVDNSResourceRecord with the * specified name, class, preference, mail exchange and time to live. @@ -598,12 +595,12 @@ * @brief The text of the resource record. */ @property (readonly, nonatomic) OFArray OF_GENERIC(OFData *) *textStrings; - (instancetype)initWithName: (OFString *)name - DNSClass: (of_dns_class_t)DNSClass - recordType: (of_dns_record_type_t)recordType + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType TTL: (uint32_t)TTL OF_UNAVAILABLE; /** * @brief Initializes an already allocated OFTXTDNSResourceRecord with the * specified name, class, text data and time to live. @@ -613,23 +610,49 @@ * @param textStrings An array of text strings for the resource record * @param TTL The time to live for the resource record * @return An initialized OFTXTDNSResourceRecord */ - (instancetype)initWithName: (OFString *)name - DNSClass: (of_dns_class_t)DNSClass + DNSClass: (OFDNSClass)DNSClass textStrings: (OFArray OF_GENERIC(OFData *) *)textStrings TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; @end #ifdef __cplusplus extern "C" { #endif -extern OFString *_Nonnull of_dns_class_to_string(of_dns_class_t DNSClass); -extern OFString *_Nonnull of_dns_record_type_to_string( - of_dns_record_type_t recordType); -extern of_dns_class_t of_dns_class_parse(OFString *_Nonnull string); -extern of_dns_record_type_t of_dns_record_type_parse(OFString *_Nonnull string); +/** + * @brief Returns the name for the specified OFDNSClass. + * + * @param DNSClass The OFDNSClass to return the name for + * @return The name for the specified OFDNSClass + */ +extern OFString *_Nonnull OFDNSClassName(OFDNSClass DNSClass); + +/** + * @brief Returns the name for the specified OFDNSRecordType. + * + * @param recordType The OFDNSRecordType to return the name for + * @return The name for the specified OFDNSRecordType + */ +extern OFString *_Nonnull OFDNSRecordTypeName(OFDNSRecordType recordType); + +/** + * @brief Parses the specified string as an @ref OFDNSClass. + * + * @param string The string to parse as an @ref OFDNSClass + * @return The parsed OFDNSClass + */ +extern OFDNSClass OFDNSClassParseName(OFString *_Nonnull string); + +/** + * @brief Parses the specified string as an @ref OFDNSRecordType. + * + * @param string The string to parse as an @ref OFDNSRecordType + * @return The parsed OFDNSRecordType + */ +extern OFDNSRecordType OFDNSRecordTypeParseName(OFString *_Nonnull string); #ifdef __cplusplus } #endif OF_ASSUME_NONNULL_END Index: src/OFDNSResourceRecord.m ================================================================== --- src/OFDNSResourceRecord.m +++ src/OFDNSResourceRecord.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -23,67 +21,68 @@ #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" OFString * -of_dns_class_to_string(of_dns_class_t DNSClass) +OFDNSClassName(OFDNSClass DNSClass) { switch (DNSClass) { - case OF_DNS_CLASS_IN: + case OFDNSClassIN: return @"IN"; - case OF_DNS_CLASS_ANY: + case OFDNSClassAny: return @"any"; default: return [OFString stringWithFormat: @"%u", DNSClass]; } } OFString * -of_dns_record_type_to_string(of_dns_record_type_t recordType) +OFDNSRecordTypeName(OFDNSRecordType recordType) { switch (recordType) { - case OF_DNS_RECORD_TYPE_A: + case OFDNSRecordTypeA: return @"A"; - case OF_DNS_RECORD_TYPE_NS: + case OFDNSRecordTypeNS: return @"NS"; - case OF_DNS_RECORD_TYPE_CNAME: + case OFDNSRecordTypeCNAME: return @"CNAME"; - case OF_DNS_RECORD_TYPE_SOA: + case OFDNSRecordTypeSOA: return @"SOA"; - case OF_DNS_RECORD_TYPE_PTR: + case OFDNSRecordTypePTR: return @"PTR"; - case OF_DNS_RECORD_TYPE_HINFO: + case OFDNSRecordTypeHINFO: return @"HINFO"; - case OF_DNS_RECORD_TYPE_MX: + case OFDNSRecordTypeMX: return @"MX"; - case OF_DNS_RECORD_TYPE_TXT: + case OFDNSRecordTypeTXT: return @"TXT"; - case OF_DNS_RECORD_TYPE_RP: + case OFDNSRecordTypeRP: return @"RP"; - case OF_DNS_RECORD_TYPE_AAAA: + case OFDNSRecordTypeAAAA: return @"AAAA"; - case OF_DNS_RECORD_TYPE_SRV: + case OFDNSRecordTypeSRV: return @"SRV"; - case OF_DNS_RECORD_TYPE_ALL: + case OFDNSRecordTypeAll: return @"all"; default: return [OFString stringWithFormat: @"%u", recordType]; } } -of_dns_class_t of_dns_class_parse(OFString *string) +OFDNSClass +OFDNSClassParseName(OFString *string) { void *pool = objc_autoreleasePoolPush(); - of_dns_class_t DNSClass; + OFDNSClass DNSClass; string = string.uppercaseString; if ([string isEqual: @"IN"]) - DNSClass = OF_DNS_CLASS_IN; + DNSClass = OFDNSClassIN; else { @try { - DNSClass = (of_dns_class_t) + DNSClass = (OFDNSClass) [string unsignedLongLongValueWithBase: 0]; } @catch (OFInvalidFormatException *e) { @throw [OFInvalidArgumentException exception]; } } @@ -91,44 +90,45 @@ objc_autoreleasePoolPop(pool); return DNSClass; } -of_dns_record_type_t of_dns_record_type_parse(OFString *string) +OFDNSRecordType +OFDNSRecordTypeParseName(OFString *string) { void *pool = objc_autoreleasePoolPush(); - of_dns_record_type_t recordType; + OFDNSRecordType recordType; string = string.uppercaseString; if ([string isEqual: @"A"]) - recordType = OF_DNS_RECORD_TYPE_A; + recordType = OFDNSRecordTypeA; else if ([string isEqual: @"NS"]) - recordType = OF_DNS_RECORD_TYPE_NS; + recordType = OFDNSRecordTypeNS; else if ([string isEqual: @"CNAME"]) - recordType = OF_DNS_RECORD_TYPE_CNAME; + recordType = OFDNSRecordTypeCNAME; else if ([string isEqual: @"SOA"]) - recordType = OF_DNS_RECORD_TYPE_SOA; + recordType = OFDNSRecordTypeSOA; else if ([string isEqual: @"PTR"]) - recordType = OF_DNS_RECORD_TYPE_PTR; + recordType = OFDNSRecordTypePTR; else if ([string isEqual: @"HINFO"]) - recordType = OF_DNS_RECORD_TYPE_HINFO; + recordType = OFDNSRecordTypeHINFO; else if ([string isEqual: @"MX"]) - recordType = OF_DNS_RECORD_TYPE_MX; + recordType = OFDNSRecordTypeMX; else if ([string isEqual: @"TXT"]) - recordType = OF_DNS_RECORD_TYPE_TXT; + recordType = OFDNSRecordTypeTXT; else if ([string isEqual: @"RP"]) - recordType = OF_DNS_RECORD_TYPE_RP; + recordType = OFDNSRecordTypeRP; else if ([string isEqual: @"AAAA"]) - recordType = OF_DNS_RECORD_TYPE_AAAA; + recordType = OFDNSRecordTypeAAAA; else if ([string isEqual: @"SRV"]) - recordType = OF_DNS_RECORD_TYPE_SRV; + recordType = OFDNSRecordTypeSRV; else if ([string isEqual: @"ALL"]) - recordType = OF_DNS_RECORD_TYPE_ALL; + recordType = OFDNSRecordTypeAll; else { @try { - recordType = (of_dns_record_type_t) + recordType = (OFDNSRecordType) [string unsignedLongLongValueWithBase: 0]; } @catch (OFInvalidFormatException *e) { @throw [OFInvalidArgumentException exception]; } } @@ -141,12 +141,12 @@ @implementation OFDNSResourceRecord @synthesize name = _name, DNSClass = _DNSClass, recordType = _recordType; @synthesize TTL = _TTL; - (instancetype)initWithName: (OFString *)name - DNSClass: (of_dns_class_t)DNSClass - recordType: (of_dns_record_type_t)recordType + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType TTL: (uint32_t)TTL { self = [super init]; @try { @@ -181,39 +181,39 @@ @"\tName = %@\n" @"\tClass = %@\n" @"\tType = %@\n" @"\tTTL = %" PRIu32 "\n" @">", - self.className, _name, of_dns_class_to_string(_DNSClass), - of_dns_record_type_to_string(_recordType), _TTL]; + self.className, _name, OFDNSClassName(_DNSClass), + OFDNSRecordTypeName(_recordType), _TTL]; } @end @implementation OFADNSResourceRecord - (instancetype)initWithName: (OFString *)name - DNSClass: (of_dns_class_t)DNSClass - recordType: (of_dns_record_type_t)recordType + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType TTL: (uint32_t)TTL { OF_INVALID_INIT_METHOD } - (instancetype)initWithName: (OFString *)name - address: (const of_socket_address_t *)address + address: (const OFSocketAddress *)address TTL: (uint32_t)TTL { self = [super initWithName: name - DNSClass: OF_DNS_CLASS_IN - recordType: OF_DNS_RECORD_TYPE_A + DNSClass: OFDNSClassIN + recordType: OFDNSRecordTypeA TTL: TTL]; _address = *address; return self; } -- (const of_socket_address_t *)address +- (const OFSocketAddress *)address { return &_address; } - (bool)isEqual: (id)object @@ -235,30 +235,30 @@ return false; if (record->_recordType != _recordType) return false; - if (!of_socket_address_equal(&record->_address, &_address)) + if (!OFSocketAddressEqual(&record->_address, &_address)) return false; return true; } - (unsigned long)hash { - uint32_t hash; - - OF_HASH_INIT(hash); - - OF_HASH_ADD_HASH(hash, _name.hash); - OF_HASH_ADD(hash, _DNSClass >> 8); - OF_HASH_ADD(hash, _DNSClass); - OF_HASH_ADD(hash, _recordType >> 8); - OF_HASH_ADD(hash, _recordType); - OF_HASH_ADD_HASH(hash, of_socket_address_hash(&_address)); - - OF_HASH_FINALIZE(hash); + unsigned long hash; + + OFHashInit(&hash); + + OFHashAddHash(&hash, _name.hash); + OFHashAdd(&hash, _DNSClass >> 8); + OFHashAdd(&hash, _DNSClass); + OFHashAdd(&hash, _recordType >> 8); + OFHashAdd(&hash, _recordType); + OFHashAddHash(&hash, OFSocketAddressHash(&_address)); + + OFHashFinalize(&hash); return hash; } - (OFString *)description @@ -267,39 +267,38 @@ @"<%@:\n" @"\tName = %@\n" @"\tAddress = %@\n" @"\tTTL = %" PRIu32 "\n" @">", - self.className, _name, - of_socket_address_ip_string(&_address, NULL), _TTL]; + self.className, _name, OFSocketAddressString(&_address), _TTL]; } @end @implementation OFAAAADNSResourceRecord - (instancetype)initWithName: (OFString *)name - DNSClass: (of_dns_class_t)DNSClass - recordType: (of_dns_record_type_t)recordType + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType TTL: (uint32_t)TTL { OF_INVALID_INIT_METHOD } - (instancetype)initWithName: (OFString *)name - address: (const of_socket_address_t *)address + address: (const OFSocketAddress *)address TTL: (uint32_t)TTL { self = [super initWithName: name - DNSClass: OF_DNS_CLASS_IN - recordType: OF_DNS_RECORD_TYPE_AAAA + DNSClass: OFDNSClassIN + recordType: OFDNSRecordTypeAAAA TTL: TTL]; _address = *address; return self; } -- (const of_socket_address_t *)address +- (const OFSocketAddress *)address { return &_address; } - (bool)isEqual: (id)object @@ -321,30 +320,30 @@ return false; if (record->_recordType != _recordType) return false; - if (!of_socket_address_equal(&record->_address, &_address)) + if (!OFSocketAddressEqual(&record->_address, &_address)) return false; return true; } - (unsigned long)hash { - uint32_t hash; - - OF_HASH_INIT(hash); - - OF_HASH_ADD_HASH(hash, _name.hash); - OF_HASH_ADD(hash, _DNSClass >> 8); - OF_HASH_ADD(hash, _DNSClass); - OF_HASH_ADD(hash, _recordType >> 8); - OF_HASH_ADD(hash, _recordType); - OF_HASH_ADD_HASH(hash, of_socket_address_hash(&_address)); - - OF_HASH_FINALIZE(hash); + unsigned long hash; + + OFHashInit(&hash); + + OFHashAddHash(&hash, _name.hash); + OFHashAdd(&hash, _DNSClass >> 8); + OFHashAdd(&hash, _DNSClass); + OFHashAdd(&hash, _recordType >> 8); + OFHashAdd(&hash, _recordType); + OFHashAddHash(&hash, OFSocketAddressHash(&_address)); + + OFHashFinalize(&hash); return hash; } - (OFString *)description @@ -353,34 +352,33 @@ @"<%@:\n" @"\tName = %@\n" @"\tAddress = %@\n" @"\tTTL = %" PRIu32 "\n" @">", - self.className, _name, - of_socket_address_ip_string(&_address, NULL), _TTL]; + self.className, _name, OFSocketAddressString(&_address), _TTL]; } @end @implementation OFCNAMEDNSResourceRecord @synthesize alias = _alias; - (instancetype)initWithName: (OFString *)name - DNSClass: (of_dns_class_t)DNSClass - recordType: (of_dns_record_type_t)recordType + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType TTL: (uint32_t)TTL { OF_INVALID_INIT_METHOD } - (instancetype)initWithName: (OFString *)name - DNSClass: (of_dns_class_t)DNSClass + DNSClass: (OFDNSClass)DNSClass alias: (OFString *)alias TTL: (uint32_t)TTL { self = [super initWithName: name DNSClass: DNSClass - recordType: OF_DNS_RECORD_TYPE_CNAME + recordType: OFDNSRecordTypeCNAME TTL: TTL]; @try { _alias = [alias copy]; } @catch (id e) { @@ -425,22 +423,22 @@ return true; } - (unsigned long)hash { - uint32_t hash; - - OF_HASH_INIT(hash); - - OF_HASH_ADD_HASH(hash, _name.hash); - OF_HASH_ADD(hash, _DNSClass >> 8); - OF_HASH_ADD(hash, _DNSClass); - OF_HASH_ADD(hash, _recordType >> 8); - OF_HASH_ADD(hash, _recordType); - OF_HASH_ADD_HASH(hash, _alias.hash); - - OF_HASH_FINALIZE(hash); + unsigned long hash; + + OFHashInit(&hash); + + OFHashAddHash(&hash, _name.hash); + OFHashAdd(&hash, _DNSClass >> 8); + OFHashAdd(&hash, _DNSClass); + OFHashAdd(&hash, _recordType >> 8); + OFHashAdd(&hash, _recordType); + OFHashAddHash(&hash, _alias.hash); + + OFHashFinalize(&hash); return hash; } - (OFString *)description @@ -450,35 +448,34 @@ @"\tName = %@\n" @"\tClass = %@\n" @"\tAlias = %@\n" @"\tTTL = %" PRIu32 "\n" @">", - self.className, _name, of_dns_class_to_string(_DNSClass), _alias, - _TTL]; + self.className, _name, OFDNSClassName(_DNSClass), _alias, _TTL]; } @end @implementation OFHINFODNSResourceRecord @synthesize CPU = _CPU, OS = _OS; - (instancetype)initWithName: (OFString *)name - DNSClass: (of_dns_class_t)DNSClass - recordType: (of_dns_record_type_t)recordType + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType TTL: (uint32_t)TTL { OF_INVALID_INIT_METHOD } - (instancetype)initWithName: (OFString *)name - DNSClass: (of_dns_class_t)DNSClass + DNSClass: (OFDNSClass)DNSClass CPU: (OFString *)CPU OS: (OFString *)OS TTL: (uint32_t)TTL { self = [super initWithName: name DNSClass: DNSClass - recordType: OF_DNS_RECORD_TYPE_HINFO + recordType: OFDNSRecordTypeHINFO TTL: TTL]; @try { _CPU = [CPU copy]; _OS = [OS copy]; @@ -528,23 +525,23 @@ return true; } - (unsigned long)hash { - uint32_t hash; - - OF_HASH_INIT(hash); - - OF_HASH_ADD_HASH(hash, _name.hash); - OF_HASH_ADD(hash, _DNSClass >> 8); - OF_HASH_ADD(hash, _DNSClass); - OF_HASH_ADD(hash, _recordType >> 8); - OF_HASH_ADD(hash, _recordType); - OF_HASH_ADD_HASH(hash, _CPU.hash); - OF_HASH_ADD_HASH(hash, _OS.hash); - - OF_HASH_FINALIZE(hash); + unsigned long hash; + + OFHashInit(&hash); + + OFHashAddHash(&hash, _name.hash); + OFHashAdd(&hash, _DNSClass >> 8); + OFHashAdd(&hash, _DNSClass); + OFHashAdd(&hash, _recordType >> 8); + OFHashAdd(&hash, _recordType); + OFHashAddHash(&hash, _CPU.hash); + OFHashAddHash(&hash, _OS.hash); + + OFHashFinalize(&hash); return hash; } - (OFString *)description @@ -555,35 +552,34 @@ @"\tClass = %@\n" @"\tCPU = %@\n" @"\tOS = %@\n" @"\tTTL = %" PRIu32 "\n" @">", - self.className, _name, of_dns_class_to_string(_DNSClass), _CPU, _OS, - _TTL]; + self.className, _name, OFDNSClassName(_DNSClass), _CPU, _OS, _TTL]; } @end @implementation OFMXDNSResourceRecord @synthesize preference = _preference, mailExchange = _mailExchange; - (instancetype)initWithName: (OFString *)name - DNSClass: (of_dns_class_t)DNSClass - recordType: (of_dns_record_type_t)recordType + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType TTL: (uint32_t)TTL { OF_INVALID_INIT_METHOD } - (instancetype)initWithName: (OFString *)name - DNSClass: (of_dns_class_t)DNSClass + DNSClass: (OFDNSClass)DNSClass preference: (uint16_t)preference mailExchange: (OFString *)mailExchange TTL: (uint32_t)TTL { self = [super initWithName: name DNSClass: DNSClass - recordType: OF_DNS_RECORD_TYPE_MX + recordType: OFDNSRecordTypeMX TTL: TTL]; @try { _preference = preference; _mailExchange = [mailExchange copy]; @@ -633,24 +629,24 @@ return true; } - (unsigned long)hash { - uint32_t hash; - - OF_HASH_INIT(hash); - - OF_HASH_ADD_HASH(hash, _name.hash); - OF_HASH_ADD(hash, _DNSClass >> 8); - OF_HASH_ADD(hash, _DNSClass); - OF_HASH_ADD(hash, _recordType >> 8); - OF_HASH_ADD(hash, _recordType); - OF_HASH_ADD(hash, _preference >> 8); - OF_HASH_ADD(hash, _preference); - OF_HASH_ADD_HASH(hash, _mailExchange.hash); - - OF_HASH_FINALIZE(hash); + unsigned long hash; + + OFHashInit(&hash); + + OFHashAddHash(&hash, _name.hash); + OFHashAdd(&hash, _DNSClass >> 8); + OFHashAdd(&hash, _DNSClass); + OFHashAdd(&hash, _recordType >> 8); + OFHashAdd(&hash, _recordType); + OFHashAdd(&hash, _preference >> 8); + OFHashAdd(&hash, _preference); + OFHashAddHash(&hash, _mailExchange.hash); + + OFHashFinalize(&hash); return hash; } - (OFString *)description @@ -661,34 +657,34 @@ @"\tClass = %@\n" @"\tPreference = %" PRIu16 "\n" @"\tMail Exchange = %@\n" @"\tTTL = %" PRIu32 "\n" @">", - self.className, _name, of_dns_class_to_string(_DNSClass), - _preference, _mailExchange, _TTL]; + self.className, _name, OFDNSClassName(_DNSClass), _preference, + _mailExchange, _TTL]; } @end @implementation OFNSDNSResourceRecord @synthesize authoritativeHost = _authoritativeHost; - (instancetype)initWithName: (OFString *)name - DNSClass: (of_dns_class_t)DNSClass - recordType: (of_dns_record_type_t)recordType + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType TTL: (uint32_t)TTL { OF_INVALID_INIT_METHOD } - (instancetype)initWithName: (OFString *)name - DNSClass: (of_dns_class_t)DNSClass + DNSClass: (OFDNSClass)DNSClass authoritativeHost: (OFString *)authoritativeHost TTL: (uint32_t)TTL { self = [super initWithName: name DNSClass: DNSClass - recordType: OF_DNS_RECORD_TYPE_NS + recordType: OFDNSRecordTypeNS TTL: TTL]; @try { _authoritativeHost = [authoritativeHost copy]; } @catch (id e) { @@ -734,22 +730,22 @@ return true; } - (unsigned long)hash { - uint32_t hash; - - OF_HASH_INIT(hash); - - OF_HASH_ADD_HASH(hash, _name.hash); - OF_HASH_ADD(hash, _DNSClass >> 8); - OF_HASH_ADD(hash, _DNSClass); - OF_HASH_ADD(hash, _recordType >> 8); - OF_HASH_ADD(hash, _recordType); - OF_HASH_ADD_HASH(hash, _authoritativeHost.hash); - - OF_HASH_FINALIZE(hash); + unsigned long hash; + + OFHashInit(&hash); + + OFHashAddHash(&hash, _name.hash); + OFHashAdd(&hash, _DNSClass >> 8); + OFHashAdd(&hash, _DNSClass); + OFHashAdd(&hash, _recordType >> 8); + OFHashAdd(&hash, _recordType); + OFHashAddHash(&hash, _authoritativeHost.hash); + + OFHashFinalize(&hash); return hash; } - (OFString *)description @@ -759,34 +755,34 @@ @"\tName = %@\n" @"\tClass = %@\n" @"\tAuthoritative Host = %@\n" @"\tTTL = %" PRIu32 "\n" @">", - self.className, _name, of_dns_class_to_string(_DNSClass), + self.className, _name, OFDNSClassName(_DNSClass), _authoritativeHost, _TTL]; } @end @implementation OFPTRDNSResourceRecord @synthesize domainName = _domainName; - (instancetype)initWithName: (OFString *)name - DNSClass: (of_dns_class_t)DNSClass - recordType: (of_dns_record_type_t)recordType + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType TTL: (uint32_t)TTL { OF_INVALID_INIT_METHOD } - (instancetype)initWithName: (OFString *)name - DNSClass: (of_dns_class_t)DNSClass + DNSClass: (OFDNSClass)DNSClass domainName: (OFString *)domainName TTL: (uint32_t)TTL { self = [super initWithName: name DNSClass: DNSClass - recordType: OF_DNS_RECORD_TYPE_PTR + recordType: OFDNSRecordTypePTR TTL: TTL]; @try { _domainName = [domainName copy]; } @catch (id e) { @@ -832,22 +828,22 @@ return true; } - (unsigned long)hash { - uint32_t hash; - - OF_HASH_INIT(hash); - - OF_HASH_ADD_HASH(hash, _name.hash); - OF_HASH_ADD(hash, _DNSClass >> 8); - OF_HASH_ADD(hash, _DNSClass); - OF_HASH_ADD(hash, _recordType >> 8); - OF_HASH_ADD(hash, _recordType); - OF_HASH_ADD_HASH(hash, _domainName.hash); - - OF_HASH_FINALIZE(hash); + unsigned long hash; + + OFHashInit(&hash); + + OFHashAddHash(&hash, _name.hash); + OFHashAdd(&hash, _DNSClass >> 8); + OFHashAdd(&hash, _DNSClass); + OFHashAdd(&hash, _recordType >> 8); + OFHashAdd(&hash, _recordType); + OFHashAddHash(&hash, _domainName.hash); + + OFHashFinalize(&hash); return hash; } - (OFString *)description @@ -857,35 +853,35 @@ @"\tName = %@\n" @"\tClass = %@\n" @"\tDomain Name = %@\n" @"\tTTL = %" PRIu32 "\n" @">", - self.className, _name, of_dns_class_to_string(_DNSClass), - _domainName, _TTL]; + self.className, _name, OFDNSClassName(_DNSClass), _domainName, + _TTL]; } @end @implementation OFRPDNSResourceRecord @synthesize mailbox = _mailbox, TXTDomainName = _TXTDomainName; - (instancetype)initWithName: (OFString *)name - DNSClass: (of_dns_class_t)DNSClass - recordType: (of_dns_record_type_t)recordType + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType TTL: (uint32_t)TTL { OF_INVALID_INIT_METHOD } - (instancetype)initWithName: (OFString *)name - DNSClass: (of_dns_class_t)DNSClass + DNSClass: (OFDNSClass)DNSClass mailbox: (OFString *)mailbox TXTDomainName: (OFString *)TXTDomainName TTL: (uint32_t)TTL { self = [super initWithName: name DNSClass: DNSClass - recordType: OF_DNS_RECORD_TYPE_RP + recordType: OFDNSRecordTypeRP TTL: TTL]; @try { _mailbox = [mailbox copy]; _TXTDomainName = [TXTDomainName copy]; @@ -937,23 +933,23 @@ return true; } - (unsigned long)hash { - uint32_t hash; - - OF_HASH_INIT(hash); - - OF_HASH_ADD_HASH(hash, _name.hash); - OF_HASH_ADD(hash, _DNSClass >> 8); - OF_HASH_ADD(hash, _DNSClass); - OF_HASH_ADD(hash, _recordType >> 8); - OF_HASH_ADD(hash, _recordType); - OF_HASH_ADD_HASH(hash, _mailbox.hash); - OF_HASH_ADD_HASH(hash, _TXTDomainName.hash); - - OF_HASH_FINALIZE(hash); + unsigned long hash; + + OFHashInit(&hash); + + OFHashAddHash(&hash, _name.hash); + OFHashAdd(&hash, _DNSClass >> 8); + OFHashAdd(&hash, _DNSClass); + OFHashAdd(&hash, _recordType >> 8); + OFHashAdd(&hash, _recordType); + OFHashAddHash(&hash, _mailbox.hash); + OFHashAddHash(&hash, _TXTDomainName.hash); + + OFHashFinalize(&hash); return hash; } - (OFString *)description @@ -964,11 +960,11 @@ @"\tClass = %@\n" @"\tMailbox = %@\n" @"\tTXT Domain Name = %@\n" @"\tTTL = %" PRIu32 "\n" @">", - self.className, _name, of_dns_class_to_string(_DNSClass), _mailbox, + self.className, _name, OFDNSClassName(_DNSClass), _mailbox, _TXTDomainName, _TTL]; } @end @implementation OFSOADNSResourceRecord @@ -977,19 +973,19 @@ @synthesize serialNumber = _serialNumber, refreshInterval = _refreshInterval; @synthesize retryInterval = _retryInterval; @synthesize expirationInterval = _expirationInterval, minTTL = _minTTL; - (instancetype)initWithName: (OFString *)name - DNSClass: (of_dns_class_t)DNSClass - recordType: (of_dns_record_type_t)recordType + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType TTL: (uint32_t)TTL { OF_INVALID_INIT_METHOD } - (instancetype)initWithName: (OFString *)name - DNSClass: (of_dns_class_t)DNSClass + DNSClass: (OFDNSClass)DNSClass primaryNameServer: (OFString *)primaryNameServer responsiblePerson: (OFString *)responsiblePerson serialNumber: (uint32_t)serialNumber refreshInterval: (uint32_t)refreshInterval retryInterval: (uint32_t)retryInterval @@ -997,11 +993,11 @@ minTTL: (uint32_t)minTTL TTL: (uint32_t)TTL { self = [super initWithName: name DNSClass: DNSClass - recordType: OF_DNS_RECORD_TYPE_SOA + recordType: OFDNSRecordTypeSOA TTL: TTL]; @try { _primaryNameServer = [primaryNameServer copy]; _responsiblePerson = [responsiblePerson copy]; @@ -1073,43 +1069,43 @@ return true; } - (unsigned long)hash { - uint32_t hash; - - OF_HASH_INIT(hash); - - OF_HASH_ADD_HASH(hash, _name.hash); - OF_HASH_ADD(hash, _DNSClass >> 8); - OF_HASH_ADD(hash, _DNSClass); - OF_HASH_ADD(hash, _recordType >> 8); - OF_HASH_ADD(hash, _recordType); - OF_HASH_ADD_HASH(hash, _primaryNameServer.hash); - OF_HASH_ADD_HASH(hash, _responsiblePerson.hash); - OF_HASH_ADD(hash, _serialNumber >> 24); - OF_HASH_ADD(hash, _serialNumber >> 16); - OF_HASH_ADD(hash, _serialNumber >> 8); - OF_HASH_ADD(hash, _serialNumber); - OF_HASH_ADD(hash, _refreshInterval >> 24); - OF_HASH_ADD(hash, _refreshInterval >> 16); - OF_HASH_ADD(hash, _refreshInterval >> 8); - OF_HASH_ADD(hash, _refreshInterval); - OF_HASH_ADD(hash, _retryInterval >> 24); - OF_HASH_ADD(hash, _retryInterval >> 16); - OF_HASH_ADD(hash, _retryInterval >> 8); - OF_HASH_ADD(hash, _retryInterval); - OF_HASH_ADD(hash, _expirationInterval >> 24); - OF_HASH_ADD(hash, _expirationInterval >> 16); - OF_HASH_ADD(hash, _expirationInterval >> 8); - OF_HASH_ADD(hash, _expirationInterval); - OF_HASH_ADD(hash, _minTTL >> 24); - OF_HASH_ADD(hash, _minTTL >> 16); - OF_HASH_ADD(hash, _minTTL >> 8); - OF_HASH_ADD(hash, _minTTL); - - OF_HASH_FINALIZE(hash); + unsigned long hash; + + OFHashInit(&hash); + + OFHashAddHash(&hash, _name.hash); + OFHashAdd(&hash, _DNSClass >> 8); + OFHashAdd(&hash, _DNSClass); + OFHashAdd(&hash, _recordType >> 8); + OFHashAdd(&hash, _recordType); + OFHashAddHash(&hash, _primaryNameServer.hash); + OFHashAddHash(&hash, _responsiblePerson.hash); + OFHashAdd(&hash, _serialNumber >> 24); + OFHashAdd(&hash, _serialNumber >> 16); + OFHashAdd(&hash, _serialNumber >> 8); + OFHashAdd(&hash, _serialNumber); + OFHashAdd(&hash, _refreshInterval >> 24); + OFHashAdd(&hash, _refreshInterval >> 16); + OFHashAdd(&hash, _refreshInterval >> 8); + OFHashAdd(&hash, _refreshInterval); + OFHashAdd(&hash, _retryInterval >> 24); + OFHashAdd(&hash, _retryInterval >> 16); + OFHashAdd(&hash, _retryInterval >> 8); + OFHashAdd(&hash, _retryInterval); + OFHashAdd(&hash, _expirationInterval >> 24); + OFHashAdd(&hash, _expirationInterval >> 16); + OFHashAdd(&hash, _expirationInterval >> 8); + OFHashAdd(&hash, _expirationInterval); + OFHashAdd(&hash, _minTTL >> 24); + OFHashAdd(&hash, _minTTL >> 16); + OFHashAdd(&hash, _minTTL >> 8); + OFHashAdd(&hash, _minTTL); + + OFHashFinalize(&hash); return hash; } - (OFString *)description @@ -1125,11 +1121,11 @@ @"\tRetry Interval = %" PRIu32 "\n" @"\tExpiration Interval = %" PRIu32 "\n" @"\tMinimum TTL = %" PRIu32 "\n" @"\tTTL = %" PRIu32 "\n" @">", - self.className, _name, of_dns_class_to_string(_DNSClass), + self.className, _name, OFDNSClassName(_DNSClass), _primaryNameServer, _responsiblePerson, _serialNumber, _refreshInterval, _retryInterval, _expirationInterval, _minTTL, _TTL]; } @end @@ -1137,12 +1133,12 @@ @implementation OFSRVDNSResourceRecord @synthesize priority = _priority, weight = _weight, target = _target; @synthesize port = _port; - (instancetype)initWithName: (OFString *)name - DNSClass: (of_dns_class_t)DNSClass - recordType: (of_dns_record_type_t)recordType + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType TTL: (uint32_t)TTL { OF_INVALID_INIT_METHOD } @@ -1152,12 +1148,12 @@ target: (OFString *)target port: (uint16_t)port TTL: (uint32_t)TTL { self = [super initWithName: name - DNSClass: OF_DNS_CLASS_IN - recordType: OF_DNS_RECORD_TYPE_SRV + DNSClass: OFDNSClassIN + recordType: OFDNSRecordTypeSRV TTL: TTL]; @try { _priority = priority; _weight = weight; @@ -1214,28 +1210,28 @@ return true; } - (unsigned long)hash { - uint32_t hash; - - OF_HASH_INIT(hash); - - OF_HASH_ADD_HASH(hash, _name.hash); - OF_HASH_ADD(hash, _DNSClass >> 8); - OF_HASH_ADD(hash, _DNSClass); - OF_HASH_ADD(hash, _recordType >> 8); - OF_HASH_ADD(hash, _recordType); - OF_HASH_ADD(hash, _priority >> 8); - OF_HASH_ADD(hash, _priority); - OF_HASH_ADD(hash, _weight >> 8); - OF_HASH_ADD(hash, _weight); - OF_HASH_ADD_HASH(hash, _target.hash); - OF_HASH_ADD(hash, _port >> 8); - OF_HASH_ADD(hash, _port); - - OF_HASH_FINALIZE(hash); + unsigned long hash; + + OFHashInit(&hash); + + OFHashAddHash(&hash, _name.hash); + OFHashAdd(&hash, _DNSClass >> 8); + OFHashAdd(&hash, _DNSClass); + OFHashAdd(&hash, _recordType >> 8); + OFHashAdd(&hash, _recordType); + OFHashAdd(&hash, _priority >> 8); + OFHashAdd(&hash, _priority); + OFHashAdd(&hash, _weight >> 8); + OFHashAdd(&hash, _weight); + OFHashAddHash(&hash, _target.hash); + OFHashAdd(&hash, _port >> 8); + OFHashAdd(&hash, _port); + + OFHashFinalize(&hash); return hash; } - (OFString *)description @@ -1255,25 +1251,25 @@ @implementation OFTXTDNSResourceRecord @synthesize textStrings = _textStrings; - (instancetype)initWithName: (OFString *)name - DNSClass: (of_dns_class_t)DNSClass - recordType: (of_dns_record_type_t)recordType + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType TTL: (uint32_t)TTL { OF_INVALID_INIT_METHOD } - (instancetype)initWithName: (OFString *)name - DNSClass: (of_dns_class_t)DNSClass + DNSClass: (OFDNSClass)DNSClass textStrings: (OFArray OF_GENERIC(OFData *) *)textStrings TTL: (uint32_t)TTL { self = [super initWithName: name DNSClass: DNSClass - recordType: OF_DNS_RECORD_TYPE_TXT + recordType: OFDNSRecordTypeTXT TTL: TTL]; @try { _textStrings = [textStrings copy]; } @catch (id e) { @@ -1319,22 +1315,22 @@ return true; } - (unsigned long)hash { - uint32_t hash; - - OF_HASH_INIT(hash); - - OF_HASH_ADD_HASH(hash, _name.hash); - OF_HASH_ADD(hash, _DNSClass >> 8); - OF_HASH_ADD(hash, _DNSClass); - OF_HASH_ADD(hash, _recordType >> 8); - OF_HASH_ADD(hash, _recordType); - OF_HASH_ADD_HASH(hash, _textStrings.hash); - - OF_HASH_FINALIZE(hash); + unsigned long hash; + + OFHashInit(&hash); + + OFHashAddHash(&hash, _name.hash); + OFHashAdd(&hash, _DNSClass >> 8); + OFHashAdd(&hash, _DNSClass); + OFHashAdd(&hash, _recordType >> 8); + OFHashAdd(&hash, _recordType); + OFHashAddHash(&hash, _textStrings.hash); + + OFHashFinalize(&hash); return hash; } - (OFString *)description @@ -1375,15 +1371,14 @@ @"\tName = %@\n" @"\tClass = %@\n" @"\tText strings = %@\n" @"\tTTL = %" PRIu32 "\n" @">", - self.className, _name, of_dns_class_to_string(_DNSClass), text, - _TTL]; + self.className, _name, OFDNSClassName(_DNSClass), text, _TTL]; [ret retain]; objc_autoreleasePoolPop(pool); return [ret autorelease]; } @end Index: src/OFDNSResponse.h ================================================================== --- src/OFDNSResponse.h +++ src/OFDNSResponse.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -22,23 +20,22 @@ @class OFArray OF_GENERIC(ObjectType); @class OFDictionary OF_GENERIC(KeyType, ObjectType); typedef OFDictionary OF_GENERIC(OFString *, OFArray OF_GENERIC( - OF_KINDOF(OFDNSResourceRecord *)) *) *of_dns_response_records_t; + OF_KINDOF(OFDNSResourceRecord *)) *) *OFDNSResponseRecords; /** * @class OFDNSResponse OFDNSResponse.h ObjFW/OFDNSResponse.h * * @brief A class storing a response from @ref OFDNSResolver. */ @interface OFDNSResponse: OFObject { OFString *_domainName; - of_dns_response_records_t _answerRecords; - of_dns_response_records_t _authorityRecords; - of_dns_response_records_t _additionalRecords; + OFDNSResponseRecords _answerRecords, _authorityRecords; + OFDNSResponseRecords _additionalRecords; OF_RESERVE_IVARS(OFDNSResponse, 4) } /** * @brief The domain name of the response. @@ -49,27 +46,27 @@ * @brief The answer records of the response. * * This is a dictionary with the key being the domain name and the value being * an array of @ref OFDNSResourceRecord. */ -@property (readonly, nonatomic) of_dns_response_records_t answerRecords; +@property (readonly, nonatomic) OFDNSResponseRecords answerRecords; /** * @brief The authority records of the response. * * This is a dictionary with the key being the domain name and the value being * an array of @ref OFDNSResourceRecord. */ -@property (readonly, nonatomic) of_dns_response_records_t authorityRecords; +@property (readonly, nonatomic) OFDNSResponseRecords authorityRecords; /** * @brief The additional records of the response. * * This is a dictionary with the key being the domain name and the value being * an array of @ref OFDNSResourceRecord. */ -@property (readonly, nonatomic) of_dns_response_records_t additionalRecords; +@property (readonly, nonatomic) OFDNSResponseRecords additionalRecords; /** * @brief Creates a new, autoreleased OFDNSResponse. * * @param domainName The domain name the response is for @@ -76,15 +73,14 @@ * @param answerRecords The answer records of the response * @param authorityRecords The authority records of the response * @param additionalRecords The additional records of the response * @return A new, autoreleased OFDNSResponse */ -+ (instancetype) - responseWithDomainName: (OFString *)domainName - answerRecords: (of_dns_response_records_t)answerRecords - authorityRecords: (of_dns_response_records_t)authorityRecords - additionalRecords: (of_dns_response_records_t)additionalRecords; ++ (instancetype)responseWithDomainName: (OFString *)domainName + answerRecords: (OFDNSResponseRecords)answerRecords + authorityRecords: (OFDNSResponseRecords)authorityRecords + additionalRecords: (OFDNSResponseRecords)additionalRecords; /** * @brief Initializes an already allocated OFDNSResponse. * * @param domainName The domain name the response is for @@ -91,16 +87,15 @@ * @param answerRecords The answer records of the response * @param authorityRecords The authority records of the response * @param additionalRecords The additional records of the response * @return An initialized OFDNSResponse */ -- (instancetype) - initWithDomainName: (OFString *)domainName - answerRecords: (of_dns_response_records_t)answerRecords - authorityRecords: (of_dns_response_records_t)authorityRecords - additionalRecords: (of_dns_response_records_t)additionalRecords +- (instancetype)initWithDomainName: (OFString *)domainName + answerRecords: (OFDNSResponseRecords)answerRecords + authorityRecords: (OFDNSResponseRecords)authorityRecords + additionalRecords: (OFDNSResponseRecords)additionalRecords OF_DESIGNATED_INITIALIZER; - (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/OFDNSResponse.m ================================================================== --- src/OFDNSResponse.m +++ src/OFDNSResponse.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -24,27 +22,26 @@ @implementation OFDNSResponse @synthesize domainName = _domainName, answerRecords = _answerRecords; @synthesize authorityRecords = _authorityRecords; @synthesize additionalRecords = _additionalRecords; -+ (instancetype) - responseWithDomainName: (OFString *)domainName - answerRecords: (of_dns_response_records_t)answerRecords - authorityRecords: (of_dns_response_records_t)authorityRecords - additionalRecords: (of_dns_response_records_t)additionalRecords ++ (instancetype)responseWithDomainName: (OFString *)domainName + answerRecords: (OFDNSResponseRecords)answerRecords + authorityRecords: (OFDNSResponseRecords)authorityRecords + additionalRecords: (OFDNSResponseRecords)additionalRecords { return [[[self alloc] initWithDomainName: domainName answerRecords: answerRecords authorityRecords: authorityRecords additionalRecords: additionalRecords] autorelease]; } - (instancetype)initWithDomainName: (OFString *)domainName - answerRecords: (of_dns_response_records_t)answerRecords - authorityRecords: (of_dns_response_records_t)authorityRecords - additionalRecords: (of_dns_response_records_t)additionalRecords + answerRecords: (OFDNSResponseRecords)answerRecords + authorityRecords: (OFDNSResponseRecords)authorityRecords + additionalRecords: (OFDNSResponseRecords)additionalRecords { self = [super init]; @try { _domainName = [domainName copy]; @@ -57,11 +54,11 @@ } return self; } -- (instancetype)init OF_UNAVAILABLE +- (instancetype)init { OF_INVALID_INIT_METHOD } - (void)dealloc @@ -102,18 +99,18 @@ return true; } - (unsigned long)hash { - uint32_t hash; - - OF_HASH_INIT(hash); - OF_HASH_ADD_HASH(hash, _domainName.hash); - OF_HASH_ADD_HASH(hash, [_answerRecords hash]); - OF_HASH_ADD_HASH(hash, [_authorityRecords hash]); - OF_HASH_ADD_HASH(hash, [_additionalRecords hash]); - OF_HASH_FINALIZE(hash); + unsigned long hash; + + OFHashInit(&hash); + OFHashAddHash(&hash, _domainName.hash); + OFHashAddHash(&hash, [_answerRecords hash]); + OFHashAddHash(&hash, [_authorityRecords hash]); + OFHashAddHash(&hash, [_additionalRecords hash]); + OFHashFinalize(&hash); return hash; } - (OFString *)description DELETED src/OFData+ASN1DERParsing.h Index: src/OFData+ASN1DERParsing.h ================================================================== --- src/OFData+ASN1DERParsing.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "OFData.h" -#import "OFASN1Value.h" - -OF_ASSUME_NONNULL_BEGIN - -#ifdef __cplusplus -extern "C" { -#endif -extern int _OFData_ASN1DERParsing_reference; -#ifdef __cplusplus -} -#endif - -@interface OFData (ASN1DERParsing) -/** - * @brief The data interpreted as ASN.1 in DER representation and parsed as an - * object. - * - * This is either an OFArray (for a sequence), an OFSet (for a set) or an - * OFASN1Value. - */ -@property (readonly, nonatomic) id objectByParsingASN1DER; - -/** - * @brief Parses the ASN.1 DER representation and returns it as an object. - * - * This is either an OFArray (for a sequence), an OFSet (for a set) or an - * OFASN1Value. - * - * @param depthLimit The maximum depth the parser should accept (defaults to 32 - * if not specified, 0 means no limit (insecure!)) - * @return The ASN.1 DER representation as an object - */ -- (id)objectByParsingASN1DERWithDepthLimit: (size_t)depthLimit; -@end - -OF_ASSUME_NONNULL_END DELETED src/OFData+ASN1DERParsing.m Index: src/OFData+ASN1DERParsing.m ================================================================== --- src/OFData+ASN1DERParsing.m +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "OFData+ASN1DERParsing.h" -#import "OFASN1BitString.h" -#import "OFASN1Boolean.h" -#import "OFASN1Enumerated.h" -#import "OFASN1IA5String.h" -#import "OFASN1Integer.h" -#import "OFASN1NumericString.h" -#import "OFASN1ObjectIdentifier.h" -#import "OFASN1OctetString.h" -#import "OFASN1PrintableString.h" -#import "OFASN1UTF8String.h" -#import "OFASN1Value.h" -#import "OFArray.h" -#import "OFNull.h" -#import "OFSet.h" - -#import "OFInvalidArgumentException.h" -#import "OFInvalidFormatException.h" -#import "OFOutOfRangeException.h" -#import "OFTruncatedDataException.h" - -enum { - ASN1_TAG_CONSTRUCTED_MASK = 0x20 -}; - -int _OFData_ASN1DERParsing_reference; - -static size_t parseObject(OFData *self, id *object, size_t depthLimit); - -static OFArray * -parseSequence(OFData *contents, size_t depthLimit) -{ - OFMutableArray *ret = [OFMutableArray array]; - size_t count = contents.count; - - if (depthLimit == 0) - @throw [OFOutOfRangeException exception]; - - while (count > 0) { - id object; - size_t objectLength; - - objectLength = parseObject(contents, &object, depthLimit); - - count -= objectLength; - contents = [contents subdataWithRange: - of_range(objectLength, count)]; - - [ret addObject: object]; - } - - [ret makeImmutable]; - - return ret; -} - -static OFSet * -parseSet(OFData *contents, size_t depthLimit) -{ - OFMutableSet *ret = [OFMutableSet set]; - size_t count = contents.count; - OFData *previousObjectData = nil; - - if (depthLimit == 0) - @throw [OFOutOfRangeException exception]; - - while (count > 0) { - id object; - size_t objectLength; - OFData *objectData; - - objectLength = parseObject(contents, &object, depthLimit); - objectData = [contents subdataWithRange: - of_range(0, objectLength)]; - - if (previousObjectData != nil && - [objectData compare: previousObjectData] != - OF_ORDERED_DESCENDING) - @throw [OFInvalidFormatException exception]; - - count -= objectLength; - contents = [contents subdataWithRange: - of_range(objectLength, count)]; - - [ret addObject: object]; - - previousObjectData = objectData; - } - - [ret makeImmutable]; - - return ret; -} - -static size_t -parseObject(OFData *self, id *object, size_t depthLimit) -{ - const unsigned char *items = self.items; - size_t count = self.count; - unsigned char tag; - size_t contentsLength, bytesConsumed = 0; - Class valueClass; - OFData *contents; - - if (count < 2) - @throw [OFTruncatedDataException exception]; - - tag = *items++; - contentsLength = *items++; - bytesConsumed += 2; - - if (contentsLength > 127) { - uint_fast8_t lengthLength = contentsLength & 0x7F; - - if (lengthLength > sizeof(size_t)) - @throw [OFOutOfRangeException exception]; - - if (count - bytesConsumed < lengthLength) - @throw [OFTruncatedDataException exception]; - - if (lengthLength == 0 || - (lengthLength == 1 && items[0] < 0x80) || - (lengthLength >= 2 && items[0] == 0)) - @throw [OFInvalidFormatException exception]; - - contentsLength = 0; - - for (uint_fast8_t i = 0; i < lengthLength; i++) - contentsLength = (contentsLength << 8) | *items++; - - bytesConsumed += lengthLength; - - if (contentsLength <= 127) - @throw [OFInvalidFormatException exception]; - } - - if (count - bytesConsumed < contentsLength) - @throw [OFTruncatedDataException exception]; - - contents = [self subdataWithRange: - of_range(bytesConsumed, contentsLength)]; - bytesConsumed += contentsLength; - - switch (tag & ~ASN1_TAG_CONSTRUCTED_MASK) { - case OF_ASN1_TAG_NUMBER_BOOLEAN: - valueClass = [OFASN1Boolean class]; - break; - case OF_ASN1_TAG_NUMBER_INTEGER: - valueClass = [OFASN1Integer class]; - break; - case OF_ASN1_TAG_NUMBER_BIT_STRING: - valueClass = [OFASN1BitString class]; - break; - case OF_ASN1_TAG_NUMBER_OCTET_STRING: - valueClass = [OFASN1OctetString class]; - break; - case OF_ASN1_TAG_NUMBER_NULL: - if (tag & ASN1_TAG_CONSTRUCTED_MASK) - @throw [OFInvalidFormatException exception]; - - if (contents.count != 0) - @throw [OFInvalidFormatException exception]; - - *object = [OFNull null]; - return bytesConsumed; - case OF_ASN1_TAG_NUMBER_OBJECT_IDENTIFIER: - valueClass = [OFASN1ObjectIdentifier class]; - break; - case OF_ASN1_TAG_NUMBER_ENUMERATED: - valueClass = [OFASN1Enumerated class]; - break; - case OF_ASN1_TAG_NUMBER_UTF8_STRING: - valueClass = [OFASN1UTF8String class]; - break; - case OF_ASN1_TAG_NUMBER_SEQUENCE: - if (!(tag & ASN1_TAG_CONSTRUCTED_MASK)) - @throw [OFInvalidFormatException exception]; - - *object = parseSequence(contents, depthLimit - 1); - return bytesConsumed; - case OF_ASN1_TAG_NUMBER_SET: - if (!(tag & ASN1_TAG_CONSTRUCTED_MASK)) - @throw [OFInvalidFormatException exception]; - - *object = parseSet(contents, depthLimit - 1); - return bytesConsumed; - case OF_ASN1_TAG_NUMBER_NUMERIC_STRING: - valueClass = [OFASN1NumericString class]; - break; - case OF_ASN1_TAG_NUMBER_PRINTABLE_STRING: - valueClass = [OFASN1PrintableString class]; - break; - case OF_ASN1_TAG_NUMBER_IA5_STRING: - valueClass = [OFASN1IA5String class]; - break; - default: - valueClass = [OFASN1Value class]; - break; - } - - *object = [[[valueClass alloc] - initWithTagClass: tag >> 6 - tagNumber: tag & 0x1F - constructed: tag & ASN1_TAG_CONSTRUCTED_MASK - DEREncodedContents: contents] autorelease]; - return bytesConsumed; -} - -@implementation OFData (ASN1DERParsing) -- (id)objectByParsingASN1DER -{ - return [self objectByParsingASN1DERWithDepthLimit: 32]; -} - -- (id)objectByParsingASN1DERWithDepthLimit: (size_t)depthLimit -{ - void *pool = objc_autoreleasePoolPush(); - id object; - - if (self.itemSize != 1) - @throw [OFInvalidArgumentException exception]; - - if (parseObject(self, &object, depthLimit) != self.count) - @throw [OFInvalidFormatException exception]; - - [object retain]; - - objc_autoreleasePoolPop(pool); - - return [object autorelease]; -} -@end DELETED src/OFData+CryptoHashing.h Index: src/OFData+CryptoHashing.h ================================================================== --- src/OFData+CryptoHashing.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "OFData.h" - -OF_ASSUME_NONNULL_BEGIN - -@class OFString; - -#ifdef __cplusplus -extern "C" { -#endif -extern int _OFData_CryptoHashing_reference; -#ifdef __cplusplus -} -#endif - -@interface OFData (CryptoHashing) -/** - * @brief The MD5 hash of the data as a string. - */ -@property (readonly, nonatomic) OFString *MD5Hash; - -/** - * @brief The RIPEMD-160 hash of the data as a string. - */ -@property (readonly, nonatomic) OFString *RIPEMD160Hash; - -/** - * @brief The SHA-1 hash of the data as a string. - */ -@property (readonly, nonatomic) OFString *SHA1Hash; - -/** - * @brief The SHA-224 hash of the data as a string. - */ -@property (readonly, nonatomic) OFString *SHA224Hash; - -/** - * @brief The SHA-256 hash of the data as a string. - */ -@property (readonly, nonatomic) OFString *SHA256Hash; - -/** - * @brief The SHA-384 hash of the data as a string. - */ -@property (readonly, nonatomic) OFString *SHA384Hash; - -/** - * @brief The SHA-512 hash of the data as a string. - */ -@property (readonly, nonatomic) OFString *SHA512Hash; -@end - -OF_ASSUME_NONNULL_END DELETED src/OFData+CryptoHashing.m Index: src/OFData+CryptoHashing.m ================================================================== --- src/OFData+CryptoHashing.m +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "OFData+CryptoHashing.h" -#import "OFString.h" -#import "OFCryptoHash.h" -#import "OFMD5Hash.h" -#import "OFRIPEMD160Hash.h" -#import "OFSHA1Hash.h" -#import "OFSHA224Hash.h" -#import "OFSHA256Hash.h" -#import "OFSHA384Hash.h" -#import "OFSHA512Hash.h" - -int _OFData_CryptoHashing_reference; - -@implementation OFData (CryptoHashing) -- (OFString *)of_cryptoHashWithClass: (Class )class OF_DIRECT -{ - void *pool = objc_autoreleasePoolPush(); - id hash = - [class cryptoHashWithAllowsSwappableMemory: true]; - size_t digestSize = [class digestSize]; - const unsigned char *digest; - char cString[digestSize * 2]; - - [hash updateWithBuffer: _items - length: _count * _itemSize]; - digest = hash.digest; - - for (size_t i = 0; i < digestSize; i++) { - uint8_t high, low; - - high = digest[i] >> 4; - low = digest[i] & 0x0F; - - cString[i * 2] = (high > 9 ? high - 10 + 'a' : high + '0'); - cString[i * 2 + 1] = (low > 9 ? low - 10 + 'a' : low + '0'); - } - - objc_autoreleasePoolPop(pool); - - return [OFString stringWithCString: cString - encoding: OF_STRING_ENCODING_ASCII - length: digestSize * 2]; -} - -- (OFString *)MD5Hash -{ - return [self of_cryptoHashWithClass: [OFMD5Hash class]]; -} - -- (OFString *)RIPEMD160Hash -{ - return [self of_cryptoHashWithClass: [OFRIPEMD160Hash class]]; -} - -- (OFString *)SHA1Hash -{ - return [self of_cryptoHashWithClass: [OFSHA1Hash class]]; -} - -- (OFString *)SHA224Hash -{ - return [self of_cryptoHashWithClass: [OFSHA224Hash class]]; -} - -- (OFString *)SHA256Hash -{ - return [self of_cryptoHashWithClass: [OFSHA256Hash class]]; -} - -- (OFString *)SHA384Hash -{ - return [self of_cryptoHashWithClass: [OFSHA384Hash class]]; -} - -- (OFString *)SHA512Hash -{ - return [self of_cryptoHashWithClass: [OFSHA512Hash class]]; -} -@end ADDED src/OFData+CryptographicHashing.h Index: src/OFData+CryptographicHashing.h ================================================================== --- /dev/null +++ src/OFData+CryptographicHashing.h @@ -0,0 +1,67 @@ +/* + * 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 "OFData.h" + +OF_ASSUME_NONNULL_BEGIN + +@class OFString; + +#ifdef __cplusplus +extern "C" { +#endif +extern int _OFData_CryptographicHashing_reference; +#ifdef __cplusplus +} +#endif + +@interface OFData (CryptographicHashing) +/** + * @brief The MD5 hash of the data as a string. + */ +@property (readonly, nonatomic) OFString *stringByMD5Hashing; + +/** + * @brief The RIPEMD-160 hash of the data as a string. + */ +@property (readonly, nonatomic) OFString *stringByRIPEMD160Hashing; + +/** + * @brief The SHA-1 hash of the data as a string. + */ +@property (readonly, nonatomic) OFString *stringBySHA1Hashing; + +/** + * @brief The SHA-224 hash of the data as a string. + */ +@property (readonly, nonatomic) OFString *stringBySHA224Hashing; + +/** + * @brief The SHA-256 hash of the data as a string. + */ +@property (readonly, nonatomic) OFString *stringBySHA256Hashing; + +/** + * @brief The SHA-384 hash of the data as a string. + */ +@property (readonly, nonatomic) OFString *stringBySHA384Hashing; + +/** + * @brief The SHA-512 hash of the data as a string. + */ +@property (readonly, nonatomic) OFString *stringBySHA512Hashing; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFData+CryptographicHashing.m Index: src/OFData+CryptographicHashing.m ================================================================== --- /dev/null +++ src/OFData+CryptographicHashing.m @@ -0,0 +1,98 @@ +/* + * 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 "OFData+CryptographicHashing.h" +#import "OFString.h" +#import "OFCryptographicHash.h" +#import "OFMD5Hash.h" +#import "OFRIPEMD160Hash.h" +#import "OFSHA1Hash.h" +#import "OFSHA224Hash.h" +#import "OFSHA256Hash.h" +#import "OFSHA384Hash.h" +#import "OFSHA512Hash.h" + +int _OFData_CryptographicHashing_reference; + +@implementation OFData (CryptographicHashing) +static OFString * +stringByHashing(Class class, OFData *self) +{ + void *pool = objc_autoreleasePoolPush(); + id hash = + [class hashWithAllowsSwappableMemory: true]; + size_t digestSize = [class digestSize]; + const unsigned char *digest; + char cString[digestSize * 2]; + + [hash updateWithBuffer: self->_items + length: self->_count * self->_itemSize]; + [hash calculate]; + digest = hash.digest; + + for (size_t i = 0; i < digestSize; i++) { + uint8_t high, low; + + high = digest[i] >> 4; + low = digest[i] & 0x0F; + + cString[i * 2] = (high > 9 ? high - 10 + 'a' : high + '0'); + cString[i * 2 + 1] = (low > 9 ? low - 10 + 'a' : low + '0'); + } + + objc_autoreleasePoolPop(pool); + + return [OFString stringWithCString: cString + encoding: OFStringEncodingASCII + length: digestSize * 2]; +} + +- (OFString *)stringByMD5Hashing +{ + return stringByHashing([OFMD5Hash class], self); +} + +- (OFString *)stringByRIPEMD160Hashing +{ + return stringByHashing([OFRIPEMD160Hash class], self); +} + +- (OFString *)stringBySHA1Hashing +{ + return stringByHashing([OFSHA1Hash class], self); +} + +- (OFString *)stringBySHA224Hashing +{ + return stringByHashing([OFSHA224Hash class], self); +} + +- (OFString *)stringBySHA256Hashing +{ + return stringByHashing([OFSHA256Hash class], self); +} + +- (OFString *)stringBySHA384Hashing +{ + return stringByHashing([OFSHA384Hash class], self); +} + +- (OFString *)stringBySHA512Hashing +{ + return stringByHashing([OFSHA512Hash class], self); +} +@end Index: src/OFData+MessagePackParsing.h ================================================================== --- src/OFData+MessagePackParsing.h +++ src/OFData+MessagePackParsing.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFData+MessagePackParsing.m ================================================================== --- src/OFData+MessagePackParsing.m +++ src/OFData+MessagePackParsing.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -118,12 +116,11 @@ pos += parseObject(buffer + pos, length - pos, &key, depthLimit); pos += parseObject(buffer + pos, length - pos, &value, depthLimit); - [*object setObject: value - forKey: key]; + [*object setObject: value forKey: key]; objc_autoreleasePoolPop(pool); } return pos; @@ -135,19 +132,19 @@ switch (data.count) { case 4: { uint32_t timestamp; memcpy(×tamp, data.items, 4); - timestamp = OF_BSWAP32_IF_LE(timestamp); + timestamp = OFFromBigEndian32(timestamp); return [OFDate dateWithTimeIntervalSince1970: timestamp]; } case 8: { uint64_t combined; memcpy(&combined, data.items, 8); - combined = OF_BSWAP64_IF_LE(combined); + combined = OFFromBigEndian64(combined); return [OFDate dateWithTimeIntervalSince1970: (double)(combined & 0x3FFFFFFFF) + (double)(combined >> 34) / 1000000000]; } @@ -156,12 +153,12 @@ int64_t seconds; memcpy(&nanoseconds, data.items, 4); memcpy(&seconds, (char *)data.items + 4, 8); - nanoseconds = OF_BSWAP32_IF_LE(nanoseconds); - seconds = OF_BSWAP64_IF_LE(seconds); + nanoseconds = OFFromBigEndian32(nanoseconds); + seconds = OFFromBigEndian64(seconds); return [OFDate dateWithTimeIntervalSince1970: (double)seconds + (double)nanoseconds / 1000000000]; } default: @@ -288,21 +285,21 @@ if (length < 5) @throw [OFTruncatedDataException exception]; memcpy(&f, buffer + 1, 4); - *object = [OFNumber numberWithFloat: OF_BSWAP_FLOAT_IF_LE(f)]; + *object = [OFNumber numberWithFloat: OFFromBigEndianFloat(f)]; return 5; case 0xCB:; /* float 64 */ double d; if (length < 9) @throw [OFTruncatedDataException exception]; memcpy(&d, buffer + 1, 8); - *object = [OFNumber numberWithDouble: OF_BSWAP_DOUBLE_IF_LE(d)]; + *object = [OFNumber numberWithDouble: OFFromBigEndianDouble(d)]; return 9; /* nil */ case 0xC0: *object = [OFNull null]; return 1; @@ -322,12 +319,11 @@ count = buffer[1]; if (length < count + 2) @throw [OFTruncatedDataException exception]; - *object = [OFData dataWithItems: buffer + 2 - count: count]; + *object = [OFData dataWithItems: buffer + 2 count: count]; return count + 2; case 0xC5: /* bin 16 */ if (length < 3) @throw [OFTruncatedDataException exception]; @@ -335,12 +331,11 @@ count = readUInt16(buffer + 1); if (length < count + 3) @throw [OFTruncatedDataException exception]; - *object = [OFData dataWithItems: buffer + 3 - count: count]; + *object = [OFData dataWithItems: buffer + 3 count: count]; return count + 3; case 0xC6: /* bin 32 */ if (length < 5) @throw [OFTruncatedDataException exception]; @@ -348,12 +343,11 @@ count = readUInt32(buffer + 1); if (length < count + 5) @throw [OFTruncatedDataException exception]; - *object = [OFData dataWithItems: buffer + 5 - count: count]; + *object = [OFData dataWithItems: buffer + 5 count: count]; return count + 5; /* Extensions */ case 0xC7: /* ext 8 */ if (length < 3) @@ -362,12 +356,11 @@ count = buffer[1]; if (length < count + 3) @throw [OFTruncatedDataException exception]; - data = [[OFData alloc] initWithItems: buffer + 3 - count: count]; + data = [[OFData alloc] initWithItems: buffer + 3 count: count]; @try { *object = createExtension(buffer[2], data); } @finally { [data release]; } @@ -380,12 +373,11 @@ count = readUInt16(buffer + 1); if (length < count + 4) @throw [OFTruncatedDataException exception]; - data = [[OFData alloc] initWithItems: buffer + 4 - count: count]; + data = [[OFData alloc] initWithItems: buffer + 4 count: count]; @try { *object = createExtension(buffer[3], data); } @finally { [data release]; } @@ -398,12 +390,11 @@ count = readUInt32(buffer + 1); if (length < count + 6) @throw [OFTruncatedDataException exception]; - data = [[OFData alloc] initWithItems: buffer + 6 - count: count]; + data = [[OFData alloc] initWithItems: buffer + 6 count: count]; @try { *object = createExtension(buffer[5], data); } @finally { [data release]; } @@ -411,12 +402,11 @@ return count + 6; case 0xD4: /* fixext 1 */ if (length < 3) @throw [OFTruncatedDataException exception]; - data = [[OFData alloc] initWithItems: buffer + 2 - count: 1]; + data = [[OFData alloc] initWithItems: buffer + 2 count: 1]; @try { *object = createExtension(buffer[1], data); } @finally { [data release]; } @@ -424,12 +414,11 @@ return 3; case 0xD5: /* fixext 2 */ if (length < 4) @throw [OFTruncatedDataException exception]; - data = [[OFData alloc] initWithItems: buffer + 2 - count: 2]; + data = [[OFData alloc] initWithItems: buffer + 2 count: 2]; @try { *object = createExtension(buffer[1], data); } @finally { [data release]; } @@ -437,12 +426,11 @@ return 4; case 0xD6: /* fixext 4 */ if (length < 6) @throw [OFTruncatedDataException exception]; - data = [[OFData alloc] initWithItems: buffer + 2 - count: 4]; + data = [[OFData alloc] initWithItems: buffer + 2 count: 4]; @try { *object = createExtension(buffer[1], data); } @finally { [data release]; } @@ -450,12 +438,11 @@ return 6; case 0xD7: /* fixext 8 */ if (length < 10) @throw [OFTruncatedDataException exception]; - data = [[OFData alloc] initWithItems: buffer + 2 - count: 8]; + data = [[OFData alloc] initWithItems: buffer + 2 count: 8]; @try { *object = createExtension(buffer[1], data); } @finally { [data release]; } @@ -463,12 +450,11 @@ return 10; case 0xD8: /* fixext 16 */ if (length < 18) @throw [OFTruncatedDataException exception]; - data = [[OFData alloc] initWithItems: buffer + 2 - count: 16]; + data = [[OFData alloc] initWithItems: buffer + 2 count: 16]; @try { *object = createExtension(buffer[1], data); } @finally { [data release]; } Index: src/OFData.h ================================================================== --- src/OFData.h +++ src/OFData.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -16,19 +14,27 @@ */ #import "OFObject.h" #import "OFSerialization.h" #import "OFMessagePackRepresentation.h" + +/*! @file */ OF_ASSUME_NONNULL_BEGIN @class OFString; @class OFURL; -enum { - OF_DATA_SEARCH_BACKWARDS = 1 -}; +/** + * @brief Options for searching in data. + * + * This is a bit mask. + */ +typedef enum { + /** Search backwards in the data */ + OFDataSearchBackwards = 1 +} OFDataSearchOptions; /** * @class OFData OFData.h ObjFW/OFData.h * * @brief A class for storing arbitrary data in an array. @@ -37,15 +43,15 @@ * for OFData with item size 1. */ @interface OFData: OFObject { - unsigned char *_items; + unsigned char *_Nullable _items; size_t _count, _itemSize; bool _freeWhenDone; @private - OFData *_parentData; + OFData *_Nullable _parentData; OF_RESERVE_IVARS(OFData, 4) } /** * @brief The size of a single item in the OFData in bytes. @@ -60,11 +66,12 @@ /** * @brief All elements of the OFData as a C array. * * @warning The pointer is only valid until the OFData is changed! */ -@property (readonly, nonatomic) const void *items OF_RETURNS_INNER_POINTER; +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) const void *items + OF_RETURNS_INNER_POINTER; /** * @brief The first item of the OFData or `NULL`. */ @property OF_NULLABLE_PROPERTY (readonly, nonatomic) const void *firstItem @@ -94,29 +101,31 @@ * * @param items The items to store in the OFData * @param count The number of items * @return A new autoreleased OFData */ -+ (instancetype)dataWithItems: (const void *)items - count: (size_t)count; ++ (instancetype)dataWithItems: (const void *)items count: (size_t)count; /** * @brief Creates a new OFData with the specified `count` items of the * specified size. * * @param items The items to store in the OFData - * @param itemSize The item size of a single item in bytes * @param count The number of items + * @param itemSize The item size of a single item in bytes * @return A new autoreleased OFData */ + (instancetype)dataWithItems: (const void *)items - itemSize: (size_t)itemSize - count: (size_t)count; + count: (size_t)count + itemSize: (size_t)itemSize; /** * @brief Creates a new OFData with the specified `count` items of size 1 by * taking over ownership of the specified items pointer. + * + * If initialization fails for whatever reason, the passed memory is *not* + * free'd if `freeWhenDone` is true. * * @param items The items to store in the OFData * @param count The number of items * @param freeWhenDone Whether to free the pointer when it is no longer needed * by the OFData @@ -127,21 +136,24 @@ freeWhenDone: (bool)freeWhenDone; /** * @brief Creates a new OFData with the specified `count` items of the * specified size by taking ownership of the specified items pointer. + * + * If initialization fails for whatever reason, the passed memory is *not* + * free'd if `freeWhenDone` is true. * * @param items The items to store in the OFData - * @param itemSize The item size of a single item in bytes * @param count The number of items + * @param itemSize The item size of a single item in bytes * @param freeWhenDone Whether to free the pointer when it is no longer needed * by the OFData * @return A new autoreleased OFData */ + (instancetype)dataWithItemsNoCopy: (void *)items - itemSize: (size_t)itemSize count: (size_t)count + itemSize: (size_t)itemSize freeWhenDone: (bool)freeWhenDone; #ifdef OF_HAVE_FILES /** * @brief Creates a new OFData with an item size of 1, containing the data of @@ -162,13 +174,13 @@ */ + (instancetype)dataWithContentsOfURL: (OFURL *)URL; /** * @brief Creates a new OFData with an item size of 1, containing the data of - * the string representation. + * the hex string representation. * - * @param string The string representation of the data + * @param string The hex string representation of the data * @return A new autoreleased OFData */ + (instancetype)dataWithStringRepresentation: (OFString *)string; /** @@ -179,37 +191,39 @@ * @return A new autoreleased OFData */ + (instancetype)dataWithBase64EncodedString: (OFString *)string; /** - * @brief Initialized an already allocated OFData with the specified `count` + * @brief Initializes an already allocated OFData with the specified `count` * items of size 1. * * @param items The items to store in the OFData * @param count The number of items * @return An initialized OFData */ -- (instancetype)initWithItems: (const void *)items - count: (size_t)count; +- (instancetype)initWithItems: (const void *)items count: (size_t)count; /** - * @brief Initialized an already allocated OFData with the specified `count` + * @brief Initializes an already allocated OFData with the specified `count` * items of the specified size. * * @param items The items to store in the OFData - * @param itemSize The item size of a single item in bytes * @param count The number of items + * @param itemSize The item size of a single item in bytes * @return An initialized OFData */ - (instancetype)initWithItems: (const void *)items - itemSize: (size_t)itemSize - count: (size_t)count; + count: (size_t)count + itemSize: (size_t)itemSize; /** * @brief Initializes an already allocated OFData with the specified `count` * items of size 1 by taking over ownership of the specified items * pointer. + * + * If initialization fails for whatever reason, the passed memory is *not* + * free'd if `freeWhenDone` is true. * * @param items The items to store in the OFData * @param count The number of items * @param freeWhenDone Whether to free the pointer when it is no longer needed * by the OFData @@ -221,21 +235,24 @@ /** * @brief Initializes an already allocated OFData with the specified `count` * items of the specified size by taking ownership of the specified * items pointer. + * + * If initialization fails for whatever reason, the passed memory is *not* + * free'd if `freeWhenDone` is true. * * @param items The items to store in the OFData - * @param itemSize The item size of a single item in bytes * @param count The number of items + * @param itemSize The item size of a single item in bytes * @param freeWhenDone Whether to free the pointer when it is no longer needed * by the OFData * @return An initialized OFData */ - (instancetype)initWithItemsNoCopy: (void *)items - itemSize: (size_t)itemSize count: (size_t)count + itemSize: (size_t)itemSize freeWhenDone: (bool)freeWhenDone; #ifdef OF_HAVE_FILES /** * @brief Initializes an already allocated OFData with an item size of 1, @@ -256,13 +273,13 @@ */ - (instancetype)initWithContentsOfURL: (OFURL *)URL; /** * @brief Initializes an already allocated OFData with an item size of 1, - * containing the data of the string representation. + * containing the data of the hex string representation. * - * @param string The string representation of the data + * @param string The hex string representation of the data * @return A new autoreleased OFData */ - (instancetype)initWithStringRepresentation: (OFString *)string; /** @@ -272,10 +289,18 @@ * @param string The string with the Base64-encoded data * @return An initialized OFData */ - (instancetype)initWithBase64EncodedString: (OFString *)string; +/** + * @brief Compares the data to other data. + * + * @param data Data to compare the data to + * @return The result of the comparison + */ +- (OFComparisonResult)compare: (OFData *)data; + /** * @brief Returns a specific item of the OFData. * * @param index The number of the item to return * @return The specified item of the OFData @@ -286,28 +311,24 @@ * @brief Returns the data in the specified range as a new OFData. * * @param range The range of the data for the new OFData * @return The data in the specified range as a new OFData */ -- (OFData *)subdataWithRange: (of_range_t)range; +- (OFData *)subdataWithRange: (OFRange)range; /** * @brief Returns the range of the data. * * @param data The data to search for - * @param options Options modifying search behavior.@n - * Possible values are: - * Value | Description - * ---------------------------|----------------------------- - * `OF_DATA_SEARCH_BACKWARDS` | Search backwards in the data + * @param options Options modifying search behavior * @param range The range in which to search * @return The range of the first occurrence of the data or a range with - * `OF_NOT_FOUND` as start position if it was not found. + * `OFNotFound` as start position if it was not found. */ -- (of_range_t)rangeOfData: (OFData *)data - options: (int)options - range: (of_range_t)range; +- (OFRange)rangeOfData: (OFData *)data + options: (OFDataSearchOptions)options + range: (OFRange)range; #ifdef OF_HAVE_FILES /** * @brief Writes the OFData into the specified file. * @@ -325,8 +346,7 @@ @end OF_ASSUME_NONNULL_END #import "OFMutableData.h" -#import "OFData+ASN1DERParsing.h" -#import "OFData+CryptoHashing.h" +#import "OFData+CryptographicHashing.h" #import "OFData+MessagePackParsing.h" Index: src/OFData.m ================================================================== --- src/OFData.m +++ src/OFData.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -20,10 +18,11 @@ #include #include #include #import "OFData.h" +#import "OFBase64.h" #import "OFDictionary.h" #ifdef OF_HAVE_FILES # import "OFFile.h" # import "OFFileManager.h" #endif @@ -40,38 +39,33 @@ #import "OFOutOfMemoryException.h" #import "OFOutOfRangeException.h" #import "OFTruncatedDataException.h" #import "OFUnsupportedProtocolException.h" -#import "base64.h" - /* References for static linking */ void _references_to_categories_of_OFData(void) { - _OFData_ASN1DERParsing_reference = 1; - _OFData_CryptoHashing_reference = 1; + _OFData_CryptographicHashing_reference = 1; _OFData_MessagePackParsing_reference = 1; } @implementation OFData @synthesize itemSize = _itemSize; -+ (instancetype)dataWithItems: (const void *)items - count: (size_t)count ++ (instancetype)dataWithItems: (const void *)items count: (size_t)count { - return [[[self alloc] initWithItems: items - count: count] autorelease]; + return [[[self alloc] initWithItems: items count: count] autorelease]; } + (instancetype)dataWithItems: (const void *)items - itemSize: (size_t)itemSize count: (size_t)count + itemSize: (size_t)itemSize { return [[[self alloc] initWithItems: items - itemSize: itemSize - count: count] autorelease]; + count: count + itemSize: itemSize] autorelease]; } + (instancetype)dataWithItemsNoCopy: (void *)items count: (size_t)count freeWhenDone: (bool)freeWhenDone @@ -80,17 +74,17 @@ count: count freeWhenDone: freeWhenDone] autorelease]; } + (instancetype)dataWithItemsNoCopy: (void *)items - itemSize: (size_t)itemSize count: (size_t)count + itemSize: (size_t)itemSize freeWhenDone: (bool)freeWhenDone { return [[[self alloc] initWithItemsNoCopy: items - itemSize: itemSize count: count + itemSize: itemSize freeWhenDone: freeWhenDone] autorelease]; } #ifdef OF_HAVE_FILES + (instancetype)dataWithContentsOfFile: (OFString *)path @@ -113,32 +107,29 @@ + (instancetype)dataWithBase64EncodedString: (OFString *)string { return [[[self alloc] initWithBase64EncodedString: string] autorelease]; } -- (instancetype)initWithItems: (const void *)items - count: (size_t)count +- (instancetype)initWithItems: (const void *)items count: (size_t)count { - return [self initWithItems: items - itemSize: 1 - count: count]; + return [self initWithItems: items count: count itemSize: 1]; } - (instancetype)initWithItems: (const void *)items - itemSize: (size_t)itemSize count: (size_t)count + itemSize: (size_t)itemSize { self = [super init]; @try { if (itemSize == 0) @throw [OFInvalidArgumentException exception]; - _items = [self allocMemoryWithSize: itemSize - count: count]; + _items = OFAllocMemory(count, itemSize); + _count = count; _itemSize = itemSize; - _count = count; + _freeWhenDone = true; memcpy(_items, items, count * itemSize); } @catch (id e) { [self release]; @throw e; @@ -150,29 +141,29 @@ - (instancetype)initWithItemsNoCopy: (void *)items count: (size_t)count freeWhenDone: (bool)freeWhenDone { return [self initWithItemsNoCopy: items - itemSize: 1 count: count + itemSize: 1 freeWhenDone: freeWhenDone]; } - (instancetype)initWithItemsNoCopy: (void *)items - itemSize: (size_t)itemSize count: (size_t)count + itemSize: (size_t)itemSize freeWhenDone: (bool)freeWhenDone { self = [super init]; @try { if (itemSize == 0) @throw [OFInvalidArgumentException exception]; _items = (unsigned char *)items; - _itemSize = itemSize; _count = count; + _itemSize = itemSize; _freeWhenDone = freeWhenDone; } @catch (id e) { [self release]; @throw e; } @@ -195,21 +186,19 @@ # if ULLONG_MAX > SIZE_MAX if (size > SIZE_MAX) @throw [OFOutOfRangeException exception]; # endif - buffer = of_malloc(1, (size_t)size); - file = [[OFFile alloc] initWithPath: path - mode: @"r"]; + buffer = OFAllocMemory((size_t)size, 1); + file = [[OFFile alloc] initWithPath: path mode: @"r"]; @try { - [file readIntoBuffer: buffer - exactLength: (size_t)size]; + [file readIntoBuffer: buffer exactLength: (size_t)size]; } @finally { [file release]; } } @catch (id e) { - of_free(buffer); + OFFreeMemory(buffer); [self release]; @throw e; } @@ -216,11 +205,11 @@ @try { self = [self initWithItemsNoCopy: buffer count: (size_t)size freeWhenDone: true]; } @catch (id e) { - of_free(buffer); + OFFreeMemory(buffer); @throw e; } return self; } @@ -239,30 +228,36 @@ if ((URLHandler = [OFURLHandler handlerForURL: URL]) == nil) @throw [OFUnsupportedProtocolException exceptionWithURL: URL]; - stream = [URLHandler openItemAtURL: URL - mode: @"r"]; + stream = [URLHandler openItemAtURL: URL mode: @"r"]; + _count = 0; _itemSize = 1; - _count = 0; + _freeWhenDone = true; pageSize = [OFSystemInfo pageSize]; - buffer = [self allocMemoryWithSize: pageSize]; - - while (!stream.atEndOfStream) { - size_t length = [stream readIntoBuffer: buffer - length: pageSize]; - - if (SIZE_MAX - _count < length) - @throw [OFOutOfRangeException exception]; - - _items = [self resizeMemory: _items - size: _count + length]; - memcpy(_items + _count, buffer, length); - _count += length; + buffer = OFAllocMemory(1, pageSize); + + @try { + while (!stream.atEndOfStream) { + size_t length = [stream + readIntoBuffer: buffer + length: pageSize]; + + if (SIZE_MAX - _count < length) + @throw [OFOutOfRangeException + exception]; + + _items = OFResizeMemory(_items, + _count + length, 1); + memcpy(_items + _count, buffer, length); + _count += length; + } + } @finally { + OFFreeMemory(buffer); } objc_autoreleasePoolPop(pool); } @catch (id e) { [self release]; @@ -276,24 +271,24 @@ { self = [super init]; @try { size_t count = [string - cStringLengthWithEncoding: OF_STRING_ENCODING_ASCII]; + cStringLengthWithEncoding: OFStringEncodingASCII]; const char *cString; if (count % 2 != 0) @throw [OFInvalidFormatException exception]; count /= 2; - _items = [self allocMemoryWithSize: count]; - _itemSize = 1; + _items = OFAllocMemory(count, 1); _count = count; + _itemSize = 1; + _freeWhenDone = true; - cString = [string - cStringWithEncoding: OF_STRING_ENCODING_ASCII]; + cString = [string cStringWithEncoding: OFStringEncodingASCII]; for (size_t i = 0; i < count; i++) { uint8_t c1 = cString[2 * i]; uint8_t c2 = cString[2 * i + 1]; uint8_t byte; @@ -336,14 +331,13 @@ } self = [(OFMutableData *)self initWithCapacity: string.length / 3]; @try { - if (!of_base64_decode((OFMutableData *)self, - [string cStringWithEncoding: OF_STRING_ENCODING_ASCII], - [string cStringLengthWithEncoding: - OF_STRING_ENCODING_ASCII])) + if (!OFBase64Decode((OFMutableData *)self, + [string cStringWithEncoding: OFStringEncodingASCII], + [string cStringLengthWithEncoding: OFStringEncodingASCII])) @throw [OFInvalidFormatException exception]; } @catch (id e) { [self release]; @throw e; } @@ -359,11 +353,11 @@ void *pool = objc_autoreleasePoolPush(); OFString *stringValue; @try { if (![element.name isEqual: self.className] || - ![element.namespace isEqual: OF_SERIALIZATION_NS]) + ![element.namespace isEqual: OFSerializationNS]) @throw [OFInvalidArgumentException exception]; stringValue = element.stringValue; } @catch (id e) { [self release]; @@ -378,11 +372,11 @@ } - (void)dealloc { if (_freeWhenDone) - of_free(_items); + OFFreeMemory(_items); [_parentData release]; [super dealloc]; } @@ -427,12 +421,12 @@ } - (id)mutableCopy { return [[OFMutableData alloc] initWithItems: _items - itemSize: _itemSize - count: _count]; + count: _count + itemSize: _itemSize]; } - (bool)isEqual: (id)object { OFData *data; @@ -451,68 +445,65 @@ return false; return true; } -- (of_comparison_result_t)compare: (id )object +- (OFComparisonResult)compare: (OFData *)data { - OFData *data; int comparison; size_t count, minCount; - if (![(id)object isKindOfClass: [OFData class]]) + if (![data isKindOfClass: [OFData class]]) @throw [OFInvalidArgumentException exception]; - data = (OFData *)object; - if (data.itemSize != _itemSize) @throw [OFInvalidArgumentException exception]; count = data.count; minCount = (_count > count ? count : _count); if ((comparison = memcmp(_items, data.items, minCount * _itemSize)) == 0) { if (_count > count) - return OF_ORDERED_DESCENDING; + return OFOrderedDescending; if (_count < count) - return OF_ORDERED_ASCENDING; + return OFOrderedAscending; - return OF_ORDERED_SAME; + return OFOrderedSame; } if (comparison > 0) - return OF_ORDERED_DESCENDING; + return OFOrderedDescending; else - return OF_ORDERED_ASCENDING; + return OFOrderedAscending; } - (unsigned long)hash { - uint32_t hash; + unsigned long hash; - OF_HASH_INIT(hash); + OFHashInit(&hash); for (size_t i = 0; i < _count * _itemSize; i++) - OF_HASH_ADD(hash, ((uint8_t *)_items)[i]); + OFHashAdd(&hash, ((uint8_t *)_items)[i]); - OF_HASH_FINALIZE(hash); + OFHashFinalize(&hash); return hash; } -- (OFData *)subdataWithRange: (of_range_t)range +- (OFData *)subdataWithRange: (OFRange)range { OFData *ret; if (range.length > SIZE_MAX - range.location || range.location + range.length > _count) @throw [OFOutOfRangeException exception]; ret = [OFData dataWithItemsNoCopy: _items + (range.location * _itemSize) - itemSize: _itemSize count: range.length + itemSize: _itemSize freeWhenDone: false]; ret->_parentData = [(_parentData != nil ? _parentData : self) copy]; return ret; } @@ -547,16 +538,16 @@ return ret; } - (OFString *)stringByBase64Encoding { - return of_base64_encode(_items, _count * _itemSize); + return OFBase64Encode(_items, _count * _itemSize); } -- (of_range_t)rangeOfData: (OFData *)data - options: (int)options - range: (of_range_t)range +- (OFRange)rangeOfData: (OFData *)data + options: (OFDataSearchOptions)options + range: (OFRange)range { const char *search; size_t searchLength; if (range.length > SIZE_MAX - range.location || @@ -565,22 +556,22 @@ if (data == nil || data.itemSize != _itemSize) @throw [OFInvalidArgumentException exception]; if ((searchLength = data.count) == 0) - return of_range(0, 0); + return OFRangeMake(0, 0); if (searchLength > range.length) - return of_range(OF_NOT_FOUND, 0); + return OFRangeMake(OFNotFound, 0); search = data.items; - if (options & OF_DATA_SEARCH_BACKWARDS) { + if (options & OFDataSearchBackwards) { for (size_t i = range.length - searchLength;; i--) { if (memcmp(_items + i * _itemSize, search, searchLength * _itemSize) == 0) - return of_range(i, searchLength); + return OFRangeMake(i, searchLength); /* No match and we're at the last item */ if (i == 0) break; } @@ -587,25 +578,22 @@ } else { for (size_t i = range.location; i <= range.length - searchLength; i++) if (memcmp(_items + i * _itemSize, search, searchLength * _itemSize) == 0) - return of_range(i, searchLength); + return OFRangeMake(i, searchLength); } - return of_range(OF_NOT_FOUND, 0); + return OFRangeMake(OFNotFound, 0); } #ifdef OF_HAVE_FILES - (void)writeToFile: (OFString *)path { - OFFile *file = [[OFFile alloc] initWithPath: path - mode: @"w"]; - + OFFile *file = [[OFFile alloc] initWithPath: path mode: @"w"]; @try { - [file writeBuffer: _items - length: _count * _itemSize]; + [file writeBuffer: _items length: _count * _itemSize]; } @finally { [file release]; } } #endif @@ -612,18 +600,15 @@ - (void)writeToURL: (OFURL *)URL { void *pool = objc_autoreleasePoolPush(); OFURLHandler *URLHandler; - OFStream *stream; if ((URLHandler = [OFURLHandler handlerForURL: URL]) == nil) @throw [OFUnsupportedProtocolException exceptionWithURL: URL]; - stream = [URLHandler openItemAtURL: URL - mode: @"w"]; - [stream writeData: self]; + [[URLHandler openItemAtURL: URL mode: @"w"] writeData: self]; objc_autoreleasePoolPop(pool); } - (OFXMLElement *)XMLElementBySerializing @@ -635,12 +620,12 @@ @throw [OFInvalidArgumentException exception]; pool = objc_autoreleasePoolPush(); element = [OFXMLElement elementWithName: self.className - namespace: OF_SERIALIZATION_NS - stringValue: of_base64_encode(_items, _count * _itemSize)]; + namespace: OFSerializationNS + stringValue: OFBase64Encode(_items, _count * _itemSize)]; [element retain]; objc_autoreleasePoolPop(pool); @@ -656,41 +641,31 @@ if (_count <= UINT8_MAX) { uint8_t type = 0xC4; uint8_t tmp = (uint8_t)_count; - data = [OFMutableData dataWithItemSize: 1 - capacity: _count + 2]; - + data = [OFMutableData dataWithCapacity: _count + 2]; [data addItem: &type]; [data addItem: &tmp]; } else if (_count <= UINT16_MAX) { uint8_t type = 0xC5; - uint16_t tmp = OF_BSWAP16_IF_LE((uint16_t)_count); - - data = [OFMutableData dataWithItemSize: 1 - capacity: _count + 3]; - - [data addItem: &type]; - [data addItems: &tmp - count: sizeof(tmp)]; + uint16_t tmp = OFToBigEndian16((uint16_t)_count); + + data = [OFMutableData dataWithCapacity: _count + 3]; + [data addItem: &type]; + [data addItems: &tmp count: sizeof(tmp)]; } else if (_count <= UINT32_MAX) { uint8_t type = 0xC6; - uint32_t tmp = OF_BSWAP32_IF_LE((uint32_t)_count); - - data = [OFMutableData dataWithItemSize: 1 - capacity: _count + 5]; - - [data addItem: &type]; - [data addItems: &tmp - count: sizeof(tmp)]; + uint32_t tmp = OFToBigEndian32((uint32_t)_count); + + data = [OFMutableData dataWithCapacity: _count + 5]; + [data addItem: &type]; + [data addItems: &tmp count: sizeof(tmp)]; } else @throw [OFOutOfRangeException exception]; - [data addItems: _items - count: _count]; - + [data addItems: _items count: _count]; [data makeImmutable]; return data; } @end Index: src/OFDatagramSocket.h ================================================================== --- src/OFDatagramSocket.h +++ src/OFDatagramSocket.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -16,12 +14,11 @@ */ #import "OFObject.h" #import "OFKernelEventObserver.h" #import "OFRunLoop.h" - -#import "socket.h" +#import "OFSocket.h" OF_ASSUME_NONNULL_BEGIN /** @file */ @@ -36,25 +33,21 @@ * @param sender The address of the sender of the packet * @param exception An exception which occurred while receiving or `nil` on * success * @return A bool whether the same block should be used for the next receive */ -typedef bool (^of_datagram_socket_async_receive_block_t)( - size_t length, const of_socket_address_t *_Nonnull sender, - id _Nullable exception); +typedef bool (^OFDatagramSocketAsyncReceiveBlock)(size_t length, + const OFSocketAddress *_Nonnull sender, id _Nullable exception); /** * @brief A block which is called when a packet has been sent. * - * @param data The data which was sent - * @param receiver The receiver for the packet * @param exception An exception which occurred while reading or `nil` on * success * @return The data to repeat the send with or nil if it should not repeat */ -typedef OFData *_Nullable (^of_datagram_socket_async_send_data_block_t)( - OFData *_Nonnull data, const of_socket_address_t *_Nonnull receiver, +typedef OFData *_Nullable (^OFDatagramSocketAsyncSendDataBlock)( id _Nullable exception); #endif /** * @protocol OFDatagramSocketDelegate OFDatagramSocket.h \ @@ -76,11 +69,11 @@ * @return A bool whether the same block should be used for the next receive */ - (bool)socket: (OFDatagramSocket *)socket didReceiveIntoBuffer: (void *)buffer length: (size_t)length - sender: (const of_socket_address_t *_Nonnull)sender + sender: (const OFSocketAddress *_Nonnull)sender exception: (nullable id)exception; /** * @brief This method is called when a packet has been sent. * @@ -90,11 +83,11 @@ * @param exception An exception that occurred while sending, or nil on success * @return The data to repeat the send with or nil if it should not repeat */ - (nullable OFData *)socket: (OFDatagramSocket *)socket didSendData: (OFData *)data - receiver: (const of_socket_address_t *_Nonnull)receiver + receiver: (const OFSocketAddress *_Nonnull)receiver exception: (nullable id)exception; @end /** * @class OFDatagramSocket OFDatagramSocket.h ObjFW/OFDatagramSocket.h @@ -109,11 +102,11 @@ * was called to create one "instance" for every thread! */ @interface OFDatagramSocket: OFObject { - of_socket_t _socket; + OFSocketHandle _socket; bool _canBlock; #ifdef OF_WII bool _canSendToBroadcastAddresses; #endif id _Nullable _delegate; @@ -153,17 +146,17 @@ * * If the buffer is too small, the datagram is truncated. * * @param buffer The buffer to write the datagram to * @param length The length of the buffer - * @param sender A pointer to an @ref of_socket_address_t, which will be set to - * the address of the sender + * @param sender A pointer to an @ref OFSocketAddress, which will be set to the + * address of the sender * @return The length of the received datagram */ - (size_t)receiveIntoBuffer: (void *)buffer length: (size_t)length - sender: (of_socket_address_t *)sender; + sender: (OFSocketAddress *)sender; /** * @brief Asynchronously receives a datagram and stores it into the specified * buffer. * @@ -170,12 +163,11 @@ * If the buffer is too small, the datagram is truncated. * * @param buffer The buffer to write the datagram to * @param length The length of the buffer */ -- (void)asyncReceiveIntoBuffer: (void *)buffer - length: (size_t)length; +- (void)asyncReceiveIntoBuffer: (void *)buffer length: (size_t)length; /** * @brief Asynchronously receives a datagram and stores it into the specified * buffer. * @@ -185,11 +177,11 @@ * @param length The length of the buffer * @param runLoopMode The run loop mode in which to perform the async receive */ - (void)asyncReceiveIntoBuffer: (void *)buffer length: (size_t)length - runLoopMode: (of_run_loop_mode_t)runLoopMode; + runLoopMode: (OFRunLoopMode)runLoopMode; #ifdef OF_HAVE_BLOCKS /** * @brief Asynchronously receives a datagram and stores it into the specified * buffer. @@ -205,11 +197,11 @@ * the datagram received next, you need to return false from the * method. */ - (void)asyncReceiveIntoBuffer: (void *)buffer length: (size_t)length - block: (of_datagram_socket_async_receive_block_t)block; + block: (OFDatagramSocketAsyncReceiveBlock)block; /** * @brief Asynchronously receives a datagram and stores it into the specified * buffer. * @@ -225,78 +217,78 @@ * the datagram received next, you need to return false from the * method. */ - (void)asyncReceiveIntoBuffer: (void *)buffer length: (size_t)length - runLoopMode: (of_run_loop_mode_t)runLoopMode - block: (of_datagram_socket_async_receive_block_t)block; + runLoopMode: (OFRunLoopMode)runLoopMode + block: (OFDatagramSocketAsyncReceiveBlock)block; #endif /** * @brief Sends the specified datagram to the specified address. * * @param buffer The buffer to send as a datagram * @param length The length of the buffer - * @param receiver A pointer to an @ref of_socket_address_t to which the - * datagram should be sent + * @param receiver A pointer to an @ref OFSocketAddress to which the datagram + * should be sent */ - (void)sendBuffer: (const void *)buffer length: (size_t)length - receiver: (const of_socket_address_t *)receiver; + receiver: (const OFSocketAddress *)receiver; /** * @brief Asynchronously sends the specified datagram to the specified address. * * @param data The data to send as a datagram - * @param receiver A pointer to an @ref of_socket_address_t to which the - * datagram should be sent. The receiver is copied. + * @param receiver A pointer to an @ref OFSocketAddress to which the datagram + * should be sent. The receiver is copied. */ - (void)asyncSendData: (OFData *)data - receiver: (const of_socket_address_t *)receiver; + receiver: (const OFSocketAddress *)receiver; /** * @brief Asynchronously sends the specified datagram to the specified address. * * @param data The data to send as a datagram - * @param receiver A pointer to an @ref of_socket_address_t to which the - * datagram should be sent. The receiver is copied. + * @param receiver A pointer to an @ref OFSocketAddress to which the datgram + * should be sent. The receiver is copied. * @param runLoopMode The run loop mode in which to perform the async send */ - (void)asyncSendData: (OFData *)data - receiver: (const of_socket_address_t *)receiver - runLoopMode: (of_run_loop_mode_t)runLoopMode; + receiver: (const OFSocketAddress *)receiver + runLoopMode: (OFRunLoopMode)runLoopMode; #ifdef OF_HAVE_BLOCKS /** * @brief Asynchronously sends the specified datagram to the specified address. * * @param data The data to send as a datagram - * @param receiver A pointer to an @ref of_socket_address_t to which the - * datagram should be sent. The receiver is copied. + * @param receiver A pointer to an @ref OFSocketAddress to which the datagram + * should be sent. The receiver is copied. * @param block The block to call when the packet has been sent. It should * return the data for the next send with the same callback or nil * if it should not repeat. */ - (void)asyncSendData: (OFData *)data - receiver: (const of_socket_address_t *)receiver - block: (of_datagram_socket_async_send_data_block_t)block; + receiver: (const OFSocketAddress *)receiver + block: (OFDatagramSocketAsyncSendDataBlock)block; /** * @brief Asynchronously sends the specified datagram to the specified address. * * @param data The data to send as a datagram - * @param receiver A pointer to an @ref of_socket_address_t to which the - * datagram should be sent. The receiver is copied. + * @param receiver A pointer to an @ref OFSocketAddress to which the datagram + * should be sent. The receiver is copied. * @param runLoopMode The run loop mode in which to perform the async send * @param block The block to call when the packet has been sent. It should * return the data for the next send with the same callback or nil * if it should not repeat. */ - (void)asyncSendData: (OFData *)data - receiver: (const of_socket_address_t *)receiver - runLoopMode: (of_run_loop_mode_t)runLoopMode - block: (of_datagram_socket_async_send_data_block_t)block; + receiver: (const OFSocketAddress *)receiver + runLoopMode: (OFRunLoopMode)runLoopMode + block: (OFDatagramSocketAsyncSendDataBlock)block; #endif /** * @brief Cancels all pending asynchronous requests on the socket. */ Index: src/OFDatagramSocket.m ================================================================== --- src/OFDatagramSocket.m +++ src/OFDatagramSocket.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -15,20 +13,27 @@ * file. */ #include "config.h" +#ifndef _XOPEN_SOURCE_EXTENDED +# define _XOPEN_SOURCE_EXTENDED +#endif +#define _HPUX_ALT_XOPEN_SOCKET_API + #include #ifdef HAVE_FCNTL_H # include #endif #import "OFDatagramSocket.h" #import "OFData.h" -#import "OFRunLoop+Private.h" #import "OFRunLoop.h" +#import "OFRunLoop+Private.h" +#import "OFSocket.h" +#import "OFSocket+Private.h" #import "OFGetOptionFailedException.h" #import "OFInitializationFailedException.h" #import "OFNotOpenException.h" #import "OFOutOfRangeException.h" @@ -35,22 +40,19 @@ #import "OFReadFailedException.h" #import "OFSetOptionFailedException.h" #import "OFSetOptionFailedException.h" #import "OFWriteFailedException.h" -#import "socket.h" -#import "socket_helpers.h" - @implementation OFDatagramSocket @synthesize delegate = _delegate; + (void)initialize { if (self != [OFDatagramSocket class]) return; - if (!of_socket_init()) + if (!OFSocketInit()) @throw [OFInitializationFailedException exceptionWithClass: self]; } + (instancetype)socket @@ -66,11 +68,11 @@ if (self.class == [OFDatagramSocket class]) { [self doesNotRecognizeSelector: _cmd]; abort(); } - _socket = INVALID_SOCKET; + _socket = OFInvalidSocketHandle; _canBlock = true; } @catch (id e) { [self release]; @throw e; } @@ -78,11 +80,11 @@ return self; } - (void)dealloc { - if (_socket != INVALID_SOCKET) + if (_socket != OFInvalidSocketHandle) [self close]; [super dealloc]; } @@ -114,16 +116,16 @@ @throw [OFSetOptionFailedException exceptionWithObject: self errNo: errno]; _canBlock = canBlock; #elif defined(OF_WINDOWS) - u_long v = canBlock; + u_long v = !canBlock; if (ioctlsocket(_socket, FIONBIO, &v) == SOCKET_ERROR) @throw [OFSetOptionFailedException exceptionWithObject: self - errNo: of_socket_errno()]; + errNo: OFSocketErrNo()]; _canBlock = canBlock; #else OF_UNRECOGNIZED_SELECTOR #endif @@ -135,11 +137,11 @@ if (setsockopt(_socket, SOL_SOCKET, SO_BROADCAST, (char *)&v, (socklen_t)sizeof(v)) != 0) @throw [OFSetOptionFailedException exceptionWithObject: self - errNo: of_socket_errno()]; + errNo: OFSocketErrNo()]; #ifdef OF_WII _canSendToBroadcastAddresses = canSendToBroadcastAddresses; #endif } @@ -152,25 +154,25 @@ if (getsockopt(_socket, SOL_SOCKET, SO_BROADCAST, (char *)&v, &len) != 0 || len != sizeof(v)) @throw [OFGetOptionFailedException exceptionWithObject: self - errNo: of_socket_errno()]; + errNo: OFSocketErrNo()]; return v; #else return _canSendToBroadcastAddresses; #endif } - (size_t)receiveIntoBuffer: (void *)buffer length: (size_t)length - sender: (of_socket_address_t *)sender + sender: (OFSocketAddress *)sender { ssize_t ret; - if (_socket == INVALID_SOCKET) + if (_socket == OFInvalidSocketHandle) @throw [OFNotOpenException exceptionWithObject: self]; sender->length = (socklen_t)sizeof(sender->sockaddr); #ifndef OF_WINDOWS @@ -177,56 +179,60 @@ if ((ret = recvfrom(_socket, buffer, length, 0, &sender->sockaddr.sockaddr, &sender->length)) < 0) @throw [OFReadFailedException exceptionWithObject: self requestedLength: length - errNo: of_socket_errno()]; + errNo: OFSocketErrNo()]; #else if (length > INT_MAX) @throw [OFOutOfRangeException exception]; if ((ret = recvfrom(_socket, buffer, (int)length, 0, &sender->sockaddr.sockaddr, &sender->length)) < 0) @throw [OFReadFailedException exceptionWithObject: self requestedLength: length - errNo: of_socket_errno()]; + errNo: OFSocketErrNo()]; #endif switch (sender->sockaddr.sockaddr.sa_family) { case AF_INET: - sender->family = OF_SOCKET_ADDRESS_FAMILY_IPV4; + sender->family = OFSocketAddressFamilyIPv4; break; #ifdef OF_HAVE_IPV6 case AF_INET6: - sender->family = OF_SOCKET_ADDRESS_FAMILY_IPV6; + sender->family = OFSocketAddressFamilyIPv6; break; #endif #ifdef OF_HAVE_IPX case AF_IPX: - sender->family = OF_SOCKET_ADDRESS_FAMILY_IPX; + sender->family = OFSocketAddressFamilyIPX; + break; +#endif +#ifdef OF_HAVE_UNIX_SOCKETS + case AF_UNIX: + sender->family = OFSocketAddressFamilyUNIX; break; #endif default: - sender->family = OF_SOCKET_ADDRESS_FAMILY_UNKNOWN; + sender->family = OFSocketAddressFamilyUnknown; break; } return ret; } -- (void)asyncReceiveIntoBuffer: (void *)buffer - length: (size_t)length +- (void)asyncReceiveIntoBuffer: (void *)buffer length: (size_t)length { [self asyncReceiveIntoBuffer: buffer length: length - runLoopMode: of_run_loop_mode_default]; + runLoopMode: OFDefaultRunLoopMode]; } - (void)asyncReceiveIntoBuffer: (void *)buffer length: (size_t)length - runLoopMode: (of_run_loop_mode_t)runLoopMode + runLoopMode: (OFRunLoopMode)runLoopMode { [OFRunLoop of_addAsyncReceiveForDatagramSocket: self buffer: buffer length: length mode: runLoopMode @@ -237,22 +243,22 @@ } #ifdef OF_HAVE_BLOCKS - (void)asyncReceiveIntoBuffer: (void *)buffer length: (size_t)length - block: (of_datagram_socket_async_receive_block_t)block + block: (OFDatagramSocketAsyncReceiveBlock)block { [self asyncReceiveIntoBuffer: buffer length: length - runLoopMode: of_run_loop_mode_default + runLoopMode: OFDefaultRunLoopMode block: block]; } - (void)asyncReceiveIntoBuffer: (void *)buffer length: (size_t)length - runLoopMode: (of_run_loop_mode_t)runLoopMode - block: (of_datagram_socket_async_receive_block_t)block + runLoopMode: (OFRunLoopMode)runLoopMode + block: (OFDatagramSocketAsyncReceiveBlock)block { [OFRunLoop of_addAsyncReceiveForDatagramSocket: self buffer: buffer length: length mode: runLoopMode @@ -261,13 +267,13 @@ } #endif - (void)sendBuffer: (const void *)buffer length: (size_t)length - receiver: (const of_socket_address_t *)receiver + receiver: (const OFSocketAddress *)receiver { - if (_socket == INVALID_SOCKET) + if (_socket == OFInvalidSocketHandle) @throw [OFNotOpenException exceptionWithObject: self]; #ifndef OF_WINDOWS ssize_t bytesWritten; @@ -279,11 +285,11 @@ receiver->length)) < 0) @throw [OFWriteFailedException exceptionWithObject: self requestedLength: length bytesWritten: 0 - errNo: of_socket_errno()]; + errNo: OFSocketErrNo()]; #else int bytesWritten; if (length > INT_MAX) @throw [OFOutOfRangeException exception]; @@ -292,11 +298,11 @@ &receiver->sockaddr.sockaddr, receiver->length)) < 0) @throw [OFWriteFailedException exceptionWithObject: self requestedLength: length bytesWritten: 0 - errNo: of_socket_errno()]; + errNo: OFSocketErrNo()]; #endif if ((size_t)bytesWritten != length) @throw [OFWriteFailedException exceptionWithObject: self requestedLength: length @@ -303,20 +309,20 @@ bytesWritten: bytesWritten errNo: 0]; } - (void)asyncSendData: (OFData *)data - receiver: (const of_socket_address_t *)receiver + receiver: (const OFSocketAddress *)receiver { [self asyncSendData: data receiver: receiver - runLoopMode: of_run_loop_mode_default]; + runLoopMode: OFDefaultRunLoopMode]; } - (void)asyncSendData: (OFData *)data - receiver: (const of_socket_address_t *)receiver - runLoopMode: (of_run_loop_mode_t)runLoopMode + receiver: (const OFSocketAddress *)receiver + runLoopMode: (OFRunLoopMode)runLoopMode { [OFRunLoop of_addAsyncSendForDatagramSocket: self data: data receiver: receiver mode: runLoopMode @@ -326,23 +332,23 @@ delegate: _delegate]; } #ifdef OF_HAVE_BLOCKS - (void)asyncSendData: (OFData *)data - receiver: (const of_socket_address_t *)receiver - block: (of_datagram_socket_async_send_data_block_t)block + receiver: (const OFSocketAddress *)receiver + block: (OFDatagramSocketAsyncSendDataBlock)block { [self asyncSendData: data receiver: receiver - runLoopMode: of_run_loop_mode_default + runLoopMode: OFDefaultRunLoopMode block: block]; } - (void)asyncSendData: (OFData *)data - receiver: (const of_socket_address_t *)receiver - runLoopMode: (of_run_loop_mode_t)runLoopMode - block: (of_datagram_socket_async_send_data_block_t)block + receiver: (const OFSocketAddress *)receiver + runLoopMode: (OFRunLoopMode)runLoopMode + block: (OFDatagramSocketAsyncSendDataBlock)block { [OFRunLoop of_addAsyncSendForDatagramSocket: self data: data receiver: receiver mode: runLoopMode @@ -352,19 +358,19 @@ #endif - (void)cancelAsyncRequests { [OFRunLoop of_cancelAsyncRequestsForObject: self - mode: of_run_loop_mode_default]; + mode: OFDefaultRunLoopMode]; } - (int)fileDescriptorForReading { #ifndef OF_WINDOWS return _socket; #else - if (_socket == INVALID_SOCKET) + if (_socket == OFInvalidSocketHandle) return -1; if (_socket > INT_MAX) @throw [OFOutOfRangeException exception]; @@ -375,11 +381,11 @@ - (int)fileDescriptorForWriting { #ifndef OF_WINDOWS return _socket; #else - if (_socket == INVALID_SOCKET) + if (_socket == OFInvalidSocketHandle) return -1; if (_socket > INT_MAX) @throw [OFOutOfRangeException exception]; @@ -387,12 +393,12 @@ #endif } - (void)close { - if (_socket == INVALID_SOCKET) + if (_socket == OFInvalidSocketHandle) @throw [OFNotOpenException exceptionWithObject: self]; closesocket(_socket); - _socket = INVALID_SOCKET; + _socket = OFInvalidSocketHandle; } @end Index: src/OFDate.h ================================================================== --- src/OFDate.h +++ src/OFDate.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -33,11 +31,11 @@ OF_SUBCLASSING_RESTRICTED #endif @interface OFDate: OFObject { - of_time_interval_t _seconds; + OFTimeInterval _seconds; } #ifdef OF_HAVE_CLASS_PROPERTIES @property (class, readonly, nonatomic) OFDate *distantFuture; @property (class, readonly, nonatomic) OFDate *distantPast; @@ -124,16 +122,16 @@ @property (readonly, nonatomic) unsigned short localDayOfYear; /** * @brief The seconds since 1970-01-01T00:00:00Z. */ -@property (readonly, nonatomic) of_time_interval_t timeIntervalSince1970; +@property (readonly, nonatomic) OFTimeInterval timeIntervalSince1970; /** * @brief The seconds the date is in the future. */ -@property (readonly, nonatomic) of_time_interval_t timeIntervalSinceNow; +@property (readonly, nonatomic) OFTimeInterval timeIntervalSinceNow; /** * @brief Creates a new OFDate with the current date and time. * * @return A new, autoreleased OFDate with the current date and time @@ -145,19 +143,19 @@ * 1970-01-01T00:00:00Z. * * @param seconds The seconds since 1970-01-01T00:00:00Z * @return A new, autoreleased OFDate with the specified date and time */ -+ (instancetype)dateWithTimeIntervalSince1970: (of_time_interval_t)seconds; ++ (instancetype)dateWithTimeIntervalSince1970: (OFTimeInterval)seconds; /** * @brief Creates a new OFDate with the specified date and time since now. * * @param seconds The seconds since now * @return A new, autoreleased OFDate with the specified date and time */ -+ (instancetype)dateWithTimeIntervalSinceNow: (of_time_interval_t)seconds; ++ (instancetype)dateWithTimeIntervalSinceNow: (OFTimeInterval)seconds; /** * @brief Creates a new OFDate with the specified string in the specified * format. * @@ -217,21 +215,21 @@ * time since 1970-01-01T00:00:00Z. * * @param seconds The seconds since 1970-01-01T00:00:00Z * @return An initialized OFDate with the specified date and time */ -- (instancetype)initWithTimeIntervalSince1970: (of_time_interval_t)seconds +- (instancetype)initWithTimeIntervalSince1970: (OFTimeInterval)seconds OF_DESIGNATED_INITIALIZER; /** * @brief Initializes an already allocated OFDate with the specified date and * time since now. * * @param seconds The seconds since now * @return An initialized OFDate with the specified date and time */ -- (instancetype)initWithTimeIntervalSinceNow: (of_time_interval_t)seconds; +- (instancetype)initWithTimeIntervalSinceNow: (OFTimeInterval)seconds; /** * @brief Initializes an already allocated OFDate with the specified string in * the specified format. * @@ -267,10 +265,18 @@ * @return An initialized OFDate with the specified date and time */ - (instancetype)initWithLocalDateString: (OFString *)string format: (OFString *)format; +/** + * @brief Compares the date to another date. + * + * @param date The date to compare the date to + * @return The result of the comparison + */ +- (OFComparisonResult)compare: (OFDate *)date; + /** * @brief Creates a string of the date with the specified format. * * See the man page for `strftime` for information on the format. * @@ -313,17 +319,17 @@ * @brief Returns the seconds the receiver is after the date. * * @param otherDate Date date to generate the difference with receiver * @return The seconds the receiver is after the date. */ -- (of_time_interval_t)timeIntervalSinceDate: (OFDate *)otherDate; +- (OFTimeInterval)timeIntervalSinceDate: (OFDate *)otherDate; /** * @brief Creates a new date with the specified time interval added. * * @param seconds The seconds after the date * @return A new, autoreleased OFDate */ -- (OFDate *)dateByAddingTimeInterval: (of_time_interval_t)seconds; +- (OFDate *)dateByAddingTimeInterval: (OFTimeInterval)seconds; @end OF_ASSUME_NONNULL_END Index: src/OFDate.m ================================================================== --- src/OFDate.m +++ src/OFDate.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -30,10 +28,11 @@ #import "OFDictionary.h" #import "OFMessagePackExtension.h" #ifdef OF_HAVE_THREADS # import "OFMutex.h" #endif +#import "OFStrPTime.h" #import "OFString.h" #import "OFSystemInfo.h" #import "OFXMLElement.h" #import "OFInitializationFailedException.h" @@ -40,14 +39,12 @@ #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFOutOfMemoryException.h" #import "OFOutOfRangeException.h" -#import "of_strptime.h" - -#ifdef OF_AMIGAOS_M68K -/* amiga-gcc does not have trunc() */ +#if defined(OF_AMIGAOS_M68K) || defined(OF_MINT) +/* amiga-gcc and freemint-gcc do not have trunc() */ # define trunc(x) ((int64_t)(x)) #endif @interface OFDate () + (instancetype)of_alloc; @@ -91,36 +88,42 @@ { distantPast = [[OFDateSingleton alloc] initWithTimeIntervalSince1970: -62167219200.0]; } -static of_time_interval_t +static OFTimeInterval now(void) { struct timeval tv; - of_time_interval_t seconds; + OFTimeInterval seconds; - OF_ENSURE(gettimeofday(&tv, NULL) == 0); + OFEnsure(gettimeofday(&tv, NULL) == 0); seconds = tv.tv_sec; - seconds += (of_time_interval_t)tv.tv_usec / 1000000; + seconds += (OFTimeInterval)tv.tv_usec / 1000000; return seconds; } #if (!defined(HAVE_GMTIME_R) || !defined(HAVE_LOCALTIME_R)) && \ defined(OF_HAVE_THREADS) static OFMutex *mutex; + +static void +releaseMutex(void) +{ + [mutex release]; +} #endif #ifdef OF_WINDOWS -static __time64_t (*func__mktime64)(struct tm *); +static __time64_t (*_mktime64FuncPtr)(struct tm *); #endif #ifdef HAVE_GMTIME_R # define GMTIME_RET(field) \ - of_time_interval_t timeInterval = self.timeIntervalSince1970; \ + OFTimeInterval timeInterval = self.timeIntervalSince1970; \ time_t seconds = (time_t)timeInterval; \ struct tm tm; \ \ if (seconds != trunc(timeInterval)) \ @throw [OFOutOfRangeException exception]; \ @@ -128,11 +131,11 @@ if (gmtime_r(&seconds, &tm) == NULL) \ @throw [OFOutOfRangeException exception]; \ \ return tm.field; # define LOCALTIME_RET(field) \ - of_time_interval_t timeInterval = self.timeIntervalSince1970; \ + OFTimeInterval timeInterval = self.timeIntervalSince1970; \ time_t seconds = (time_t)timeInterval; \ struct tm tm; \ \ if (seconds != trunc(timeInterval)) \ @throw [OFOutOfRangeException exception]; \ @@ -142,11 +145,11 @@ \ return tm.field; #else # ifdef OF_HAVE_THREADS # define GMTIME_RET(field) \ - of_time_interval_t timeInterval = self.timeIntervalSince1970; \ + OFTimeInterval timeInterval = self.timeIntervalSince1970; \ time_t seconds = (time_t)timeInterval; \ struct tm *tm; \ \ if (seconds != trunc(timeInterval)) \ @throw [OFOutOfRangeException exception]; \ @@ -160,11 +163,11 @@ return tm->field; \ } @finally { \ [mutex unlock]; \ } # define LOCALTIME_RET(field) \ - of_time_interval_t timeInterval = self.timeIntervalSince1970; \ + OFTimeInterval timeInterval = self.timeIntervalSince1970; \ time_t seconds = (time_t)timeInterval; \ struct tm *tm; \ \ if (seconds != trunc(timeInterval)) \ @throw [OFOutOfRangeException exception]; \ @@ -179,11 +182,11 @@ } @finally { \ [mutex unlock]; \ } # else # define GMTIME_RET(field) \ - of_time_interval_t timeInterval = self.timeIntervalSince1970; \ + OFTimeInterval timeInterval = self.timeIntervalSince1970; \ time_t seconds = (time_t)timeInterval; \ struct tm *tm; \ \ if (seconds != trunc(timeInterval)) \ @throw [OFOutOfRangeException exception]; \ @@ -191,11 +194,11 @@ if ((tm = gmtime(&seconds)) == NULL) \ @throw [OFOutOfRangeException exception]; \ \ return tm->field; # define LOCALTIME_RET(field) \ - of_time_interval_t timeInterval = self.timeIntervalSince1970; \ + OFTimeInterval timeInterval = self.timeIntervalSince1970; \ time_t seconds = (time_t)timeInterval; \ struct tm *tm; \ \ if (seconds != trunc(timeInterval)) \ @throw [OFOutOfRangeException exception]; \ @@ -271,11 +274,11 @@ { } - (unsigned int)retainCount { - return OF_RETAIN_COUNT_MAX; + return OFMaxRetainCount; } @end @implementation OFDatePlaceholder #ifdef __clang__ @@ -282,24 +285,24 @@ /* We intentionally don't call into super, so silence the warning. */ # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wunknown-pragmas" # pragma clang diagnostic ignored "-Wobjc-designated-initializers" #endif -- (instancetype)initWithTimeIntervalSince1970: (of_time_interval_t)seconds +- (instancetype)initWithTimeIntervalSince1970: (OFTimeInterval)seconds { #if defined(OF_OBJFW_RUNTIME) && UINTPTR_MAX == UINT64_MAX uint64_t value; #endif if (seconds == 0) { - static of_once_t once = OF_ONCE_INIT; - of_once(&once, initZeroDate); + static OFOnceControl once = OFOnceControlInitValue; + OFOnce(&once, initZeroDate); return (id)zeroDate; } #if defined(OF_OBJFW_RUNTIME) && UINTPTR_MAX == UINT64_MAX - value = OF_BSWAP64_IF_LE(OF_DOUBLE_TO_INT_RAW(OF_BSWAP_DOUBLE_IF_LE( + value = OFFromBigEndian64(OFDoubleToRawUInt64(OFToBigEndianDouble( seconds))); /* Almost all dates fall into this range. */ if (value & (UINT64_C(4) << 60)) { id ret = objc_createTaggedPointer(dateTag, @@ -317,17 +320,17 @@ #endif @end #if defined(OF_OBJFW_RUNTIME) && UINTPTR_MAX == UINT64_MAX @implementation OFTaggedPointerDate -- (of_time_interval_t)timeIntervalSince1970 +- (OFTimeInterval)timeIntervalSince1970 { uint64_t value = (uint64_t)object_getTaggedPointerValue(self); value |= UINT64_C(4) << 60; - return OF_BSWAP_DOUBLE_IF_LE(OF_INT_TO_DOUBLE_RAW(OF_BSWAP64_IF_LE( + return OFFromBigEndianDouble(OFRawUInt64ToDouble(OFToBigEndian64( value))); } @end #endif @@ -344,15 +347,16 @@ placeholder.isa = [OFDatePlaceholder class]; #if (!defined(HAVE_GMTIME_R) || !defined(HAVE_LOCALTIME_R)) && \ defined(OF_HAVE_THREADS) mutex = [[OFMutex alloc] init]; + atexit(releaseMutex); #endif #ifdef OF_WINDOWS if ((module = LoadLibrary("msvcrt.dll")) != NULL) - func__mktime64 = (__time64_t (*)(struct tm *)) + _mktime64FuncPtr = (__time64_t (*)(struct tm *)) GetProcAddress(module, "_mktime64"); #endif #if defined(OF_OBJFW_RUNTIME) && UINTPTR_MAX == UINT64_MAX dateTag = objc_registerTaggedPointerClass([OFTaggedPointerDate class]); @@ -375,17 +379,17 @@ + (instancetype)date { return [[[self alloc] init] autorelease]; } -+ (instancetype)dateWithTimeIntervalSince1970: (of_time_interval_t)seconds ++ (instancetype)dateWithTimeIntervalSince1970: (OFTimeInterval)seconds { return [[[self alloc] initWithTimeIntervalSince1970: seconds] autorelease]; } -+ (instancetype)dateWithTimeIntervalSinceNow: (of_time_interval_t)seconds ++ (instancetype)dateWithTimeIntervalSinceNow: (OFTimeInterval)seconds { return [[[self alloc] initWithTimeIntervalSinceNow: seconds] autorelease]; } @@ -403,37 +407,37 @@ format: format] autorelease]; } + (instancetype)distantFuture { - static of_once_t once = OF_ONCE_INIT; - of_once(&once, initDistantFuture); + static OFOnceControl once = OFOnceControlInitValue; + OFOnce(&once, initDistantFuture); return distantFuture; } + (instancetype)distantPast { - static of_once_t once = OF_ONCE_INIT; - of_once(&once, initDistantPast); + static OFOnceControl once = OFOnceControlInitValue; + OFOnce(&once, initDistantPast); return distantPast; } - (instancetype)init { return [self initWithTimeIntervalSince1970: now()]; } -- (instancetype)initWithTimeIntervalSince1970: (of_time_interval_t)seconds +- (instancetype)initWithTimeIntervalSince1970: (OFTimeInterval)seconds { self = [super init]; _seconds = seconds; return self; } -- (instancetype)initWithTimeIntervalSinceNow: (of_time_interval_t)seconds +- (instancetype)initWithTimeIntervalSinceNow: (OFTimeInterval)seconds { return [self initWithTimeIntervalSince1970: now() + seconds]; } - (instancetype)initWithDateString: (OFString *)string @@ -442,11 +446,11 @@ void *pool = objc_autoreleasePoolPush(); const char *UTF8String = string.UTF8String; struct tm tm = { .tm_isdst = -1 }; short tz = 0; - if (of_strptime(UTF8String, format.UTF8String, &tm, &tz) != + if (OFStrPTime(UTF8String, format.UTF8String, &tm, &tz) != UTF8String + string.UTF8StringLength) @throw [OFInvalidFormatException exception]; objc_autoreleasePoolPop(pool); @@ -458,25 +462,25 @@ { void *pool = objc_autoreleasePoolPush(); const char *UTF8String = string.UTF8String; struct tm tm = { .tm_isdst = -1 }; /* - * of_strptime() can never set this to SHRT_MAX, no matter what is + * OFStrPTime() can never set this to SHRT_MAX, no matter what is * passed to it, so this is a safe way to figure out if the date * contains a time zone. */ short tz = SHRT_MAX; - of_time_interval_t seconds; + OFTimeInterval seconds; - if (of_strptime(UTF8String, format.UTF8String, &tm, &tz) != + if (OFStrPTime(UTF8String, format.UTF8String, &tm, &tz) != UTF8String + string.UTF8StringLength) @throw [OFInvalidFormatException exception]; if (tz == SHRT_MAX) { #ifdef OF_WINDOWS - if (func__mktime64 != NULL) { - if ((seconds = func__mktime64(&tm)) == -1) + if (_mktime64FuncPtr != NULL) { + if ((seconds = _mktime64FuncPtr(&tm)) == -1) @throw [OFInvalidFormatException exception]; } else { #endif if ((seconds = mktime(&tm)) == -1) @throw [OFInvalidFormatException exception]; @@ -491,27 +495,27 @@ return [self initWithTimeIntervalSince1970: seconds]; } - (instancetype)initWithSerialization: (OFXMLElement *)element { - of_time_interval_t seconds; + OFTimeInterval seconds; @try { void *pool = objc_autoreleasePoolPush(); unsigned long long value; if (![element.name isEqual: @"OFDate"] || - ![element.namespace isEqual: OF_SERIALIZATION_NS]) + ![element.namespace isEqual: OFSerializationNS]) @throw [OFInvalidArgumentException exception]; value = [element unsignedLongLongValueWithBase: 16]; if (value > UINT64_MAX) @throw [OFOutOfRangeException exception]; - seconds = OF_BSWAP_DOUBLE_IF_LE(OF_INT_TO_DOUBLE_RAW( - OF_BSWAP64_IF_LE(value))); + seconds = OFFromBigEndianDouble(OFRawUInt64ToDouble( + OFToBigEndian64(value))); objc_autoreleasePoolPop(pool); } @catch (id e) { [self release]; @throw e; @@ -538,45 +542,41 @@ return true; } - (unsigned long)hash { - uint32_t hash; + unsigned long hash; double tmp; - OF_HASH_INIT(hash); + OFHashInit(&hash); - tmp = OF_BSWAP_DOUBLE_IF_BE(self.timeIntervalSince1970); + tmp = OFToLittleEndianDouble(self.timeIntervalSince1970); for (size_t i = 0; i < sizeof(double); i++) - OF_HASH_ADD(hash, ((char *)&tmp)[i]); + OFHashAdd(&hash, ((char *)&tmp)[i]); - OF_HASH_FINALIZE(hash); + OFHashFinalize(&hash); return hash; } - (id)copy { return [self retain]; } -- (of_comparison_result_t)compare: (id )object +- (OFComparisonResult)compare: (OFDate *)date { - OFDate *otherDate; - - if (![(id)object isKindOfClass: [OFDate class]]) + if (![date isKindOfClass: [OFDate class]]) @throw [OFInvalidArgumentException exception]; - otherDate = (OFDate *)object; - - if (self.timeIntervalSince1970 < otherDate.timeIntervalSince1970) - return OF_ORDERED_ASCENDING; - if (self.timeIntervalSince1970 > otherDate.timeIntervalSince1970) - return OF_ORDERED_DESCENDING; - - return OF_ORDERED_SAME; + if (self.timeIntervalSince1970 < date.timeIntervalSince1970) + return OFOrderedAscending; + if (self.timeIntervalSince1970 > date.timeIntervalSince1970) + return OFOrderedDescending; + + return OFOrderedSame; } - (OFString *)description { return [self dateStringWithFormat: @"%Y-%m-%dT%H:%M:%SZ"]; @@ -586,14 +586,14 @@ { void *pool = objc_autoreleasePoolPush(); OFXMLElement *element; element = [OFXMLElement elementWithName: @"OFDate" - namespace: OF_SERIALIZATION_NS]; + namespace: OFSerializationNS]; element.stringValue = [OFString stringWithFormat: @"%016" PRIx64, - OF_BSWAP64_IF_LE(OF_DOUBLE_TO_INT_RAW(OF_BSWAP_DOUBLE_IF_LE( + OFFromBigEndian64(OFDoubleToRawUInt64(OFToBigEndianDouble( self.timeIntervalSince1970)))]; [element retain]; objc_autoreleasePoolPop(pool); @@ -602,11 +602,11 @@ } - (OFData *)messagePackRepresentation { void *pool = objc_autoreleasePoolPush(); - of_time_interval_t timeInterval = self.timeIntervalSince1970; + OFTimeInterval timeInterval = self.timeIntervalSince1970; int64_t seconds = (int64_t)timeInterval; uint32_t nanoseconds = (uint32_t)((timeInterval - trunc(timeInterval)) * 1000000000); OFData *ret; @@ -613,11 +613,11 @@ if (seconds >= 0 && seconds < 0x400000000) { if (seconds <= UINT32_MAX && nanoseconds == 0) { uint32_t seconds32 = (uint32_t)seconds; OFData *data; - seconds32 = OF_BSWAP32_IF_LE(seconds32); + seconds32 = OFToBigEndian32(seconds32); data = [OFData dataWithItems: &seconds32 count: sizeof(seconds32)]; ret = [[OFMessagePackExtension extensionWithType: -1 @@ -625,11 +625,11 @@ } else { uint64_t combined = ((uint64_t)nanoseconds << 34) | (uint64_t)seconds; OFData *data; - combined = OF_BSWAP64_IF_LE(combined); + combined = OFToBigEndian64(combined); data = [OFData dataWithItems: &combined count: sizeof(combined)]; ret = [[OFMessagePackExtension extensionWithType: -1 @@ -636,17 +636,14 @@ data: data] messagePackRepresentation]; } } else { OFMutableData *data = [OFMutableData dataWithCapacity: 12]; - seconds = OF_BSWAP64_IF_LE(seconds); - nanoseconds = OF_BSWAP32_IF_LE(nanoseconds); - - [data addItems: &nanoseconds - count: sizeof(nanoseconds)]; - [data addItems: &seconds - count: sizeof(seconds)]; + nanoseconds = OFToBigEndian32(nanoseconds); + [data addItems: &nanoseconds count: sizeof(nanoseconds)]; + seconds = OFToBigEndian64(seconds); + [data addItems: &seconds count: sizeof(seconds)]; ret = [[OFMessagePackExtension extensionWithType: -1 data: data] messagePackRepresentation]; } @@ -658,11 +655,11 @@ return [ret autorelease]; } - (unsigned long)microsecond { - of_time_interval_t timeInterval = self.timeIntervalSince1970; + OFTimeInterval timeInterval = self.timeIntervalSince1970; return (unsigned long)((timeInterval - trunc(timeInterval)) * 1000000); } - (unsigned char)second @@ -741,11 +738,11 @@ } - (OFString *)dateStringWithFormat: (OFConstantString *)format { OFString *ret; - of_time_interval_t timeInterval = self.timeIntervalSince1970; + OFTimeInterval timeInterval = self.timeIntervalSince1970; time_t seconds = (time_t)timeInterval; struct tm tm; size_t pageSize; #ifndef OF_WINDOWS char *buffer; @@ -777,11 +774,11 @@ } # endif #endif pageSize = [OFSystemInfo pageSize]; - buffer = of_malloc(1, pageSize); + buffer = OFAllocMemory(1, pageSize); @try { #ifndef OF_WINDOWS if (strftime(buffer, pageSize, format.UTF8String, &tm) == 0) @throw [OFOutOfRangeException exception]; @@ -792,20 +789,20 @@ @throw [OFOutOfRangeException exception]; ret = [OFString stringWithUTF16String: buffer]; #endif } @finally { - of_free(buffer); + OFFreeMemory(buffer); } return ret; } - (OFString *)localDateStringWithFormat: (OFConstantString *)format { OFString *ret; - of_time_interval_t timeInterval = self.timeIntervalSince1970; + OFTimeInterval timeInterval = self.timeIntervalSince1970; time_t seconds = (time_t)timeInterval; struct tm tm; size_t pageSize; #ifndef OF_WINDOWS char *buffer; @@ -837,11 +834,11 @@ } # endif #endif pageSize = [OFSystemInfo pageSize]; - buffer = of_malloc(1, pageSize); + buffer = OFAllocMemory(1, pageSize); @try { #ifndef OF_WINDOWS if (strftime(buffer, pageSize, format.UTF8String, &tm) == 0) @throw [OFOutOfRangeException exception]; @@ -852,11 +849,11 @@ @throw [OFOutOfRangeException exception]; ret = [OFString stringWithUTF16String: buffer]; #endif } @finally { - of_free(buffer); + OFFreeMemory(buffer); } return ret; } @@ -863,11 +860,11 @@ - (OFDate *)earlierDate: (OFDate *)otherDate { if (otherDate == nil) return self; - if ([self compare: otherDate] == OF_ORDERED_DESCENDING) + if ([self compare: otherDate] == OFOrderedDescending) return otherDate; return self; } @@ -874,40 +871,40 @@ - (OFDate *)laterDate: (OFDate *)otherDate { if (otherDate == nil) return self; - if ([self compare: otherDate] == OF_ORDERED_ASCENDING) + if ([self compare: otherDate] == OFOrderedAscending) return otherDate; return self; } -- (of_time_interval_t)timeIntervalSince1970 +- (OFTimeInterval)timeIntervalSince1970 { return _seconds; } -- (of_time_interval_t)timeIntervalSinceDate: (OFDate *)otherDate +- (OFTimeInterval)timeIntervalSinceDate: (OFDate *)otherDate { return self.timeIntervalSince1970 - otherDate.timeIntervalSince1970; } -- (of_time_interval_t)timeIntervalSinceNow +- (OFTimeInterval)timeIntervalSinceNow { struct timeval t; - of_time_interval_t seconds; + OFTimeInterval seconds; - OF_ENSURE(gettimeofday(&t, NULL) == 0); + OFEnsure(gettimeofday(&t, NULL) == 0); seconds = t.tv_sec; - seconds += (of_time_interval_t)t.tv_usec / 1000000; + seconds += (OFTimeInterval)t.tv_usec / 1000000; return self.timeIntervalSince1970 - seconds; } -- (OFDate *)dateByAddingTimeInterval: (of_time_interval_t)seconds +- (OFDate *)dateByAddingTimeInterval: (OFTimeInterval)seconds { return [OFDate dateWithTimeIntervalSince1970: self.timeIntervalSince1970 + seconds]; } @end Index: src/OFDictionary.h ================================================================== --- src/OFDictionary.h +++ src/OFDictionary.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -34,14 +32,37 @@ OF_ASSUME_NONNULL_BEGIN @class OFArray OF_GENERIC(ObjectType); #ifdef OF_HAVE_BLOCKS -typedef void (^of_dictionary_enumeration_block_t)(id key, id object, - bool *stop); -typedef bool (^of_dictionary_filter_block_t)(id key, id object); -typedef id _Nonnull (^of_dictionary_map_block_t)(id key, id object); +/** + * @brief A block for enumerating an OFDictionary. + * + * @param key The current key + * @param object The object for the current key + * @param stop A pointer to a variable that can be set to true to stop the + * enumeration. + */ +typedef void (^OFDictionaryEnumerationBlock)(id key, id object, bool *stop); + +/** + * @brief A block for filtering an OFDictionary. + * + * @param key The key to inspect + * @param object The object for the key to inspect + * @return Whether the object should be in the filtered dictionary. + */ +typedef bool (^OFDictionaryFilterBlock)(id key, id object); + +/** + * @brief A block for mapping keys to objects in an OFDictionary. + * + * @param key The key to map + * @param object The current object for the key + * @return The object to map the key to + */ +typedef id _Nonnull (^OFDictionaryMapBlock)(id key, id object); #endif /** * @class OFDictionary OFDictionary.h ObjFW/OFDictionary.h * @@ -98,23 +119,21 @@ * * @param key The key * @param object The object * @return A new autoreleased OFDictionary */ -+ (instancetype)dictionaryWithObject: (ObjectType)object - forKey: (KeyType)key; ++ (instancetype)dictionaryWithObject: (ObjectType)object forKey: (KeyType)key; /** * @brief Creates a new OFDictionary with the specified keys and objects. * * @param keys An array of keys * @param objects An array of objects * @return A new autoreleased OFDictionary */ -+ (instancetype) - dictionaryWithObjects: (OFArray OF_GENERIC(ObjectType) *)objects - forKeys: (OFArray OF_GENERIC(KeyType) *)keys; ++ (instancetype)dictionaryWithObjects: (OFArray OF_GENERIC(ObjectType) *)objects + forKeys: (OFArray OF_GENERIC(KeyType) *)keys; /** * @brief Creates a new OFDictionary with the specified keys and objects. * * @param keys An array of keys @@ -152,12 +171,11 @@ * * @param key The key * @param object The object * @return An initialized OFDictionary */ -- (instancetype)initWithObject: (ObjectType)object - forKey: (KeyType)key; +- (instancetype)initWithObject: (ObjectType)object forKey: (KeyType)key; /** * @brief Initializes an already allocated OFDictionary with the specified keys * and objects. * @@ -196,12 +214,11 @@ * * @param firstKey The first key * @param arguments A va_list of the other arguments * @return An initialized OFDictionary */ -- (instancetype)initWithKey: (KeyType)firstKey - arguments: (va_list)arguments; +- (instancetype)initWithKey: (KeyType)firstKey arguments: (va_list)arguments; /** * @brief Returns the object for the given key or `nil` if the key was not * found. * @@ -234,12 +251,11 @@ * dictionary is immutable, an @ref OFUndefinedKeyException is thrown. * * @param key The key to set * @param value The value to set the key to */ -- (void)setValue: (nullable id)value - forKey: (OFString *)key; +- (void)setValue: (nullable id)value forKey: (OFString *)key; /** * @brief Checks whether the dictionary contains an object equal to the * specified object. * @@ -276,33 +292,32 @@ /** * @brief Executes a block for each key / object pair. * * @param block The block to execute for each key / object pair. */ -- (void)enumerateKeysAndObjectsUsingBlock: - (of_dictionary_enumeration_block_t)block; +- (void)enumerateKeysAndObjectsUsingBlock: (OFDictionaryEnumerationBlock)block; /** * @brief Creates a new dictionary, mapping each object using the specified * block. * * @param block A block which maps an object for each object * @return A new autoreleased OFDictionary */ -- (OFDictionary OF_GENERIC(KeyType, id) *)mappedDictionaryUsingBlock: - (of_dictionary_map_block_t)block; +- (OFDictionary OF_GENERIC(KeyType, id) *) + mappedDictionaryUsingBlock: (OFDictionaryMapBlock)block; /** * @brief Creates a new dictionary, only containing the objects for which the * block returns true. * * @param block A block which determines if the object should be in the new * dictionary * @return A new autoreleased OFDictionary */ -- (OFDictionary OF_GENERIC(KeyType, ObjectType) *)filteredDictionaryUsingBlock: - (of_dictionary_filter_block_t)block; +- (OFDictionary OF_GENERIC(KeyType, ObjectType) *) + filteredDictionaryUsingBlock: (OFDictionaryFilterBlock)block; #endif #if !defined(OF_HAVE_GENERICS) && !defined(DOXYGEN) # undef KeyType # undef ObjectType #endif Index: src/OFDictionary.m ================================================================== --- src/OFDictionary.m +++ src/OFDictionary.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -39,12 +37,13 @@ } placeholder; static OFCharacterSet *URLQueryPartAllowedCharacterSet = nil; @interface OFDictionary () -- (OFString *)of_JSONRepresentationWithOptions: (int)options - depth: (size_t)depth; +- (OFString *) + of_JSONRepresentationWithOptions: (OFJSONRepresentationOptions)options + depth: (size_t)depth; @end @interface OFDictionaryPlaceholder: OFDictionary @end @@ -73,19 +72,17 @@ { return (id)[[OFMapTableDictionary alloc] initWithDictionary: dictionary]; } -- (instancetype)initWithObject: (id)object - forKey: (id)key +- (instancetype)initWithObject: (id)object forKey: (id)key { return (id)[[OFMapTableDictionary alloc] initWithObject: object forKey: key]; } -- (instancetype)initWithObjects: (OFArray *)objects - forKeys: (OFArray *)keys +- (instancetype)initWithObjects: (OFArray *)objects forKeys: (OFArray *)keys { return (id)[[OFMapTableDictionary alloc] initWithObjects: objects forKeys: keys]; } @@ -173,16 +170,16 @@ { } - (unsigned int)retainCount { - return OF_RETAIN_COUNT_MAX; + return OFMaxRetainCount; } -- (bool)characterIsMember: (of_unichar_t)character +- (bool)characterIsMember: (OFUnichar)character { - if (character < CHAR_MAX && of_ascii_isalnum(character)) + if (character < CHAR_MAX && OFASCIIIsAlnum(character)) return true; switch (character) { case '-': case '.': @@ -228,15 +225,13 @@ { return [[(OFDictionary *)[self alloc] initWithDictionary: dictionary] autorelease]; } -+ (instancetype)dictionaryWithObject: (id)object - forKey: (id)key ++ (instancetype)dictionaryWithObject: (id)object forKey: (id)key { - return [[[self alloc] initWithObject: object - forKey: key] autorelease]; + return [[[self alloc] initWithObject: object forKey: key] autorelease]; } + (instancetype)dictionaryWithObjects: (OFArray *)objects forKeys: (OFArray *)keys { @@ -244,11 +239,11 @@ forKeys: keys] autorelease]; } + (instancetype)dictionaryWithObjects: (id const *)objects forKeys: (id const *)keys - count: (size_t)count + count: (size_t)count { return [[[self alloc] initWithObjects: objects forKeys: keys count: count] autorelease]; } @@ -285,21 +280,19 @@ - (instancetype)initWithDictionary: (OFDictionary *)dictionary { OF_INVALID_INIT_METHOD } -- (instancetype)initWithObject: (id)object - forKey: (id)key +- (instancetype)initWithObject: (id)object forKey: (id)key { if (key == nil || object == nil) @throw [OFInvalidArgumentException exception]; return [self initWithKeysAndObjects: key, object, nil]; } -- (instancetype)initWithObjects: (OFArray *)objects_ - forKeys: (OFArray *)keys_ +- (instancetype)initWithObjects: (OFArray *)objects_ forKeys: (OFArray *)keys_ { id const *objects, *keys; size_t count; @try { @@ -313,13 +306,11 @@ } @catch (id e) { [self release]; @throw e; } - return [self initWithObjects: objects - forKeys: keys - count: count]; + return [self initWithObjects: objects forKeys: keys count: count]; } - (instancetype)initWithObjects: (id const *)objects forKeys: (id const *)keys count: (size_t)count @@ -331,19 +322,17 @@ { id ret; va_list arguments; va_start(arguments, firstKey); - ret = [self initWithKey: firstKey - arguments: arguments]; + ret = [self initWithKey: firstKey arguments: arguments]; va_end(arguments); return ret; } -- (instancetype)initWithKey: (id)firstKey - arguments: (va_list)arguments +- (instancetype)initWithKey: (id)firstKey arguments: (va_list)arguments { OF_INVALID_INIT_METHOD } - (instancetype)initWithSerialization: (OFXMLElement *)element @@ -367,20 +356,18 @@ return [super valueForKey: @"count"]; return [self objectForKey: key]; } -- (void)setValue: (id)value - forKey: (OFString *)key +- (void)setValue: (id)value forKey: (OFString *)key { if (![self isKindOfClass: [OFMutableDictionary class]]) @throw [OFUndefinedKeyException exceptionWithObject: self key: key value: value]; - [(OFMutableDictionary *)self setObject: value - forKey: key]; + [(OFMutableDictionary *)self setObject: value forKey: key]; } - (size_t)count { OF_UNRECOGNIZED_SELECTOR @@ -519,11 +506,11 @@ { return [[[OFDictionaryObjectEnumerator alloc] initWithDictionary: self] autorelease]; } -- (int)countByEnumeratingWithState: (of_fast_enumeration_state_t *)state +- (int)countByEnumeratingWithState: (OFFastEnumerationState *)state objects: (id *)objects count: (int)count { OFEnumerator *enumerator; int i; @@ -549,12 +536,11 @@ return i; } #ifdef OF_HAVE_BLOCKS -- (void)enumerateKeysAndObjectsUsingBlock: - (of_dictionary_enumeration_block_t)block +- (void)enumerateKeysAndObjectsUsingBlock: (OFDictionaryEnumerationBlock)block { bool stop = false; for (id key in self) { block(key, [self objectForKey: key], &stop); @@ -562,35 +548,32 @@ if (stop) break; } } -- (OFDictionary *)mappedDictionaryUsingBlock: (of_dictionary_map_block_t)block +- (OFDictionary *)mappedDictionaryUsingBlock: (OFDictionaryMapBlock)block { OFMutableDictionary *new = [OFMutableDictionary dictionary]; [self enumerateKeysAndObjectsUsingBlock: ^ (id key, id object, bool *stop) { - [new setObject: block(key, object) - forKey: key]; + [new setObject: block(key, object) forKey: key]; }]; [new makeImmutable]; return new; } -- (OFDictionary *)filteredDictionaryUsingBlock: - (of_dictionary_filter_block_t)block +- (OFDictionary *)filteredDictionaryUsingBlock: (OFDictionaryFilterBlock)block { OFMutableDictionary *new = [OFMutableDictionary dictionary]; [self enumerateKeysAndObjectsUsingBlock: ^ (id key, id object, bool *stop) { if (block(key, object)) - [new setObject: object - forKey: key]; + [new setObject: object forKey: key]; }]; [new makeImmutable]; return new; @@ -644,12 +627,11 @@ if (++i < count) [ret appendString: @";\n"]; objc_autoreleasePoolPop(pool2); } - [ret replaceOccurrencesOfString: @"\n" - withString: @"\n\t"]; + [ret replaceOccurrencesOfString: @"\n" withString: @"\n\t"]; [ret appendString: @";\n}"]; [ret makeImmutable]; objc_autoreleasePoolPop(pool); @@ -696,14 +678,14 @@ OFEnumerator *keyEnumerator, *objectEnumerator; id key, object; if ([self isKindOfClass: [OFMutableDictionary class]]) element = [OFXMLElement elementWithName: @"OFMutableDictionary" - namespace: OF_SERIALIZATION_NS]; + namespace: OFSerializationNS]; else element = [OFXMLElement elementWithName: @"OFDictionary" - namespace: OF_SERIALIZATION_NS]; + namespace: OFSerializationNS]; keyEnumerator = [self keyEnumerator]; objectEnumerator = [self objectEnumerator]; while ((key = [keyEnumerator nextObject]) != nil && (object = [objectEnumerator nextObject]) != nil) { @@ -710,16 +692,16 @@ void *pool2 = objc_autoreleasePoolPush(); OFXMLElement *keyElement, *objectElement; keyElement = [OFXMLElement elementWithName: @"key" - namespace: OF_SERIALIZATION_NS]; + namespace: OFSerializationNS]; [keyElement addChild: key.XMLElementBySerializing]; objectElement = [OFXMLElement elementWithName: @"object" - namespace: OF_SERIALIZATION_NS]; + namespace: OFSerializationNS]; [objectElement addChild: object.XMLElementBySerializing]; [element addChild: keyElement]; [element addChild: objectElement]; @@ -733,31 +715,31 @@ return [element autorelease]; } - (OFString *)JSONRepresentation { - return [self of_JSONRepresentationWithOptions: 0 - depth: 0]; -} - -- (OFString *)JSONRepresentationWithOptions: (int)options -{ - return [self of_JSONRepresentationWithOptions: options - depth: 0]; + return [self of_JSONRepresentationWithOptions: 0 depth: 0]; +} + +- (OFString *)JSONRepresentationWithOptions: + (OFJSONRepresentationOptions)options +{ + return [self of_JSONRepresentationWithOptions: options depth: 0]; } -- (OFString *)of_JSONRepresentationWithOptions: (int)options - depth: (size_t)depth +- (OFString *) + of_JSONRepresentationWithOptions: (OFJSONRepresentationOptions)options + depth: (size_t)depth { OFMutableString *JSON = [OFMutableString stringWithString: @"{"]; void *pool = objc_autoreleasePoolPush(); OFEnumerator *keyEnumerator = [self keyEnumerator]; OFEnumerator *objectEnumerator = [self objectEnumerator]; size_t i, count = self.count; id key, object; - if (options & OF_JSON_REPRESENTATION_PRETTY) { + if (options & OFJSONRepresentationOptionPretty) { OFMutableString *indentation = [OFMutableString string]; for (i = 0; i < depth; i++) [indentation appendString: @"\t"]; @@ -766,11 +748,11 @@ i = 0; while ((key = [keyEnumerator nextObject]) != nil && (object = [objectEnumerator nextObject]) != nil) { void *pool2 = objc_autoreleasePoolPush(); int identifierOptions = - options | OF_JSON_REPRESENTATION_IDENTIFIER; + options | OFJSONRepresentationOptionIsIdentifier; if (![key isKindOfClass: [OFString class]]) @throw [OFInvalidArgumentException exception]; [JSON appendString: indentation]; @@ -796,11 +778,11 @@ i = 0; while ((key = [keyEnumerator nextObject]) != nil && (object = [objectEnumerator nextObject]) != nil) { void *pool2 = objc_autoreleasePoolPush(); int identifierOptions = - options | OF_JSON_REPRESENTATION_IDENTIFIER; + options | OFJSONRepresentationOptionIsIdentifier; if (![key isKindOfClass: [OFString class]]) @throw [OFInvalidArgumentException exception]; [JSON appendString: [key @@ -840,22 +822,20 @@ if (count <= 15) { uint8_t tmp = 0x80 | ((uint8_t)count & 0xF); [data addItem: &tmp]; } else if (count <= UINT16_MAX) { uint8_t type = 0xDE; - uint16_t tmp = OF_BSWAP16_IF_LE((uint16_t)count); + uint16_t tmp = OFToBigEndian16((uint16_t)count); [data addItem: &type]; - [data addItems: &tmp - count: sizeof(tmp)]; + [data addItems: &tmp count: sizeof(tmp)]; } else if (count <= UINT32_MAX) { uint8_t type = 0xDF; - uint32_t tmp = OF_BSWAP32_IF_LE((uint32_t)count); + uint32_t tmp = OFToBigEndian32((uint32_t)count); [data addItem: &type]; - [data addItems: &tmp - count: sizeof(tmp)]; + [data addItems: &tmp count: sizeof(tmp)]; } else @throw [OFOutOfRangeException exception]; pool = objc_autoreleasePoolPush(); @@ -868,16 +848,14 @@ OFData *child; i++; child = key.messagePackRepresentation; - [data addItems: child.items - count: child.count]; + [data addItems: child.items count: child.count]; child = object.messagePackRepresentation; - [data addItems: child.items - count: child.count]; + [data addItems: child.items count: child.count]; objc_autoreleasePoolPop(pool2); } assert(i == count); DELETED src/OFDimensionValue.h Index: src/OFDimensionValue.h ================================================================== --- src/OFDimensionValue.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "OFValue.h" - -OF_ASSUME_NONNULL_BEGIN - -@interface OFDimensionValue: OFValue -{ - of_dimension_t _dimension; -} -@end - -OF_ASSUME_NONNULL_END DELETED src/OFDimensionValue.m Index: src/OFDimensionValue.m ================================================================== --- src/OFDimensionValue.m +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "OFDimensionValue.h" -#import "OFMethodSignature.h" -#import "OFString.h" - -#import "OFOutOfRangeException.h" - -@implementation OFDimensionValue -@synthesize dimensionValue = _dimension; - -- (instancetype)initWithDimension: (of_dimension_t)dimension -{ - self = [super init]; - - _dimension = dimension; - - return self; -} - -- (const char *)objCType -{ - return @encode(of_dimension_t); -} - -- (void)getValue: (void *)value - size: (size_t)size -{ - if (size != sizeof(_dimension)) - @throw [OFOutOfRangeException exception]; - - memcpy(value, &_dimension, sizeof(_dimension)); -} - -- (OFString *)description -{ - return [OFString stringWithFormat: - @"", - _dimension.width, _dimension.height]; -} -@end Index: src/OFEnumerator.h ================================================================== --- src/OFEnumerator.h +++ src/OFEnumerator.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -21,15 +19,19 @@ @class OFArray OF_GENERIC(ObjectType); @class OFEnumerator OF_GENERIC(ObjectType); /** - * @protocol OFEnumerating OFEnumerator.h ObjFW/OFEnumerator.h + * @protocol OFEnumeration OFEnumerator.h ObjFW/OFEnumerator.h * * @brief A protocol for getting an enumerator for the object. + * + * If the class conforming to OFEnumeration is using lightweight generics, the + * only method, @ref objectEnumerator, should be overridden to use lightweight + * generics. */ -@protocol OFEnumerating +@protocol OFEnumeration /** * @brief Returns an OFEnumerator to enumerate through all objects of the * collection. * * @return An OFEnumerator to enumerate through all objects of the collection @@ -42,26 +44,26 @@ * * We need this bad check to see if we already imported Cocoa, which defines * this as well. */ /** - * @struct of_fast_enumeration_state_t OFEnumerator.h ObjFW/OFEnumerator.h + * @struct OFFastEnumerationState OFEnumerator.h ObjFW/OFEnumerator.h * * @brief State information for fast enumerations. */ -#define of_fast_enumeration_state_t NSFastEnumerationState -#ifndef NSINTEGER_DEFINED typedef struct { /** Arbitrary state information for the enumeration */ unsigned long state; /** Pointer to a C array of objects to return */ id __unsafe_unretained _Nullable *_Nullable itemsPtr; /** Arbitrary state information to detect mutations */ unsigned long *_Nullable mutationsPtr; /** Additional arbitrary state information */ unsigned long extra[5]; -} of_fast_enumeration_state_t; +} OFFastEnumerationState; +#ifndef NSINTEGER_DEFINED +typedef OFFastEnumerationState NSFastEnumerationState; #endif /** * @protocol OFFastEnumeration OFEnumerator.h ObjFW/OFEnumerator.h * @@ -79,11 +81,11 @@ * @param objects A pointer to an array where to put the objects * @param count The number of objects that can be stored at objects * @return The number of objects returned in objects or 0 when the enumeration * finished. */ -- (int)countByEnumeratingWithState: (of_fast_enumeration_state_t *)state +- (int)countByEnumeratingWithState: (OFFastEnumerationState *)state objects: (id __unsafe_unretained _Nonnull *_Nonnull) objects count: (int)count; @end Index: src/OFEnumerator.m ================================================================== --- src/OFEnumerator.m +++ src/OFEnumerator.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -57,11 +55,11 @@ objc_autoreleasePoolPop(pool); return ret; } -- (int)countByEnumeratingWithState: (of_fast_enumeration_state_t *)state +- (int)countByEnumeratingWithState: (OFFastEnumerationState *)state objects: (id *)objects count: (int)count { int i; Index: src/OFEpollKernelEventObserver.h ================================================================== --- src/OFEpollKernelEventObserver.h +++ src/OFEpollKernelEventObserver.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFEpollKernelEventObserver.m ================================================================== --- src/OFEpollKernelEventObserver.m +++ src/OFEpollKernelEventObserver.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -33,13 +31,13 @@ #import "OFNull.h" #import "OFInitializationFailedException.h" #import "OFObserveFailedException.h" -#define EVENTLIST_SIZE 64 +#define eventListSize 64 -static const of_map_table_functions_t mapFunctions = { NULL }; +static const OFMapTableFunctions mapFunctions = { NULL }; @implementation OFEpollKernelEventObserver - (instancetype)init { self = [super init]; @@ -187,20 +185,20 @@ events: EPOLLOUT]; [super removeObjectForWriting: object]; } -- (void)observeForTimeInterval: (of_time_interval_t)timeInterval +- (void)observeForTimeInterval: (OFTimeInterval)timeInterval { OFNull *nullObject = [OFNull null]; - struct epoll_event eventList[EVENTLIST_SIZE]; + struct epoll_event eventList[eventListSize]; int events; if ([self of_processReadBuffers]) return; - events = epoll_wait(_epfd, eventList, EVENTLIST_SIZE, + events = epoll_wait(_epfd, eventList, eventListSize, (timeInterval != -1 ? timeInterval * 1000 : -1)); if (events < 0) @throw [OFObserveFailedException exceptionWithObserver: self errNo: errno]; @@ -209,11 +207,11 @@ if (eventList[i].events & EPOLLIN) { void *pool = objc_autoreleasePoolPush(); if (eventList[i].data.ptr == nullObject) { char buffer; - OF_ENSURE(read(_cancelFD[0], &buffer, 1) == 1); + OFEnsure(read(_cancelFD[0], &buffer, 1) == 1); continue; } if ([_delegate respondsToSelector: @selector(objectIsReadyForReading:)]) Index: src/OFFile.h ================================================================== --- src/OFFile.h +++ src/OFFile.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -18,15 +16,15 @@ #import "OFSeekableStream.h" #import "OFKernelEventObserver.h" #ifndef OF_AMIGAOS # define OF_FILE_HANDLE_IS_FD -# define OF_INVALID_FILE_HANDLE (-1) -typedef int of_file_handle_t; +typedef int OFFileHandle; +static const OFFileHandle OFInvalidFileHandle = -1; #else -# define OF_INVALID_FILE_HANDLE NULL -typedef struct of_file_handle *of_file_handle_t; +typedef struct _OFFileHandle *OFFileHandle; +static const OFFileHandle OFInvalidFileHandle = NULL; #endif OF_ASSUME_NONNULL_BEGIN @class OFURL; @@ -40,11 +38,11 @@ @interface OFFile: OFSeekableStream #ifdef OF_FILE_HANDLE_IS_FD #endif { - of_file_handle_t _handle; + OFFileHandle _handle; bool _atEndOfStream; } /** * @brief Creates a new OFFile with the specified path and mode. @@ -63,45 +61,21 @@ * `w+x` | Read-write, create or fail, exclusive * `a` | Write-only, create or append * `a+` | Read-write, create or append * @return A new autoreleased OFFile */ -+ (instancetype)fileWithPath: (OFString *)path - mode: (OFString *)mode; - -/** - * @brief Creates a new OFFile with the specified URL and mode. - * - * @param URL The URL to the file to open - * @param mode The mode in which the file should be opened.@n - * Possible modes are: - * 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 - * @return A new autoreleased OFFile - */ -+ (instancetype)fileWithURL: (OFURL *)URL - mode: (OFString *)mode; ++ (instancetype)fileWithPath: (OFString *)path mode: (OFString *)mode; /** * @brief Creates a new OFFile with the specified native file handle. * * @param handle A native file handle. If OF_FILE_HANDLE_IS_FD is defined, this * is a file descriptor. The handle is closed when the OFFile * object is deallocated! * @return A new autoreleased OFFile */ -+ (instancetype)fileWithHandle: (of_file_handle_t)handle; - -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)fileWithHandle: (OFFileHandle)handle; /** * @brief Initializes an already allocated OFFile. * * @param path The path to the file to open as a string @@ -121,46 +95,21 @@ * `ab` | write-only, create, append, binary * `a+` | read-write, create, append * `ab+` or `a+b` | read-write, create, append, binary * @return An initialized OFFile */ -- (instancetype)initWithPath: (OFString *)path - mode: (OFString *)mode; - -/** - * @brief Initializes an already allocated OFFile. - * - * @param URL The URL to the file to open - * @param mode The mode in which the file should be opened.@n - * Possible modes are: - * Mode | Description - * ---------------|------------------------------------- - * `r` | read-only - * `rb` | read-only, binary - * `r+` | read-write - * `rb+` or `r+b` | read-write, binary - * `w` | write-only, create, truncate - * `wb` | write-only, create, truncate, binary - * `w` | read-write, create, truncate - * `wb+` or `w+b` | read-write, create, truncate, binary - * `a` | write-only, create, append - * `ab` | write-only, create, append, binary - * `a+` | read-write, create, append - * `ab+` or `a+b` | read-write, create, append, binary - * @return An initialized OFFile - */ -- (instancetype)initWithURL: (OFURL *)URL - mode: (OFString *)mode; +- (instancetype)initWithPath: (OFString *)path mode: (OFString *)mode; /** * @brief Initializes an already allocated OFFile. * * @param handle A native file handle. If OF_FILE_HANDLE_IS_FD is defined, this * is a file descriptor. The handle is closed when the OFFile * object is deallocated! * @return An initialized OFFile */ -- (instancetype)initWithHandle: (of_file_handle_t)handle - OF_DESIGNATED_INITIALIZER; +- (instancetype)initWithHandle: (OFFileHandle)handle OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/OFFile.m ================================================================== --- src/OFFile.m +++ src/OFFile.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -14,10 +12,12 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #include "config.h" + +#define _LARGEFILE64_SOURCE #include #include #ifdef HAVE_FCNTL_H @@ -77,35 +77,39 @@ #endif #ifndef OF_AMIGAOS # define closeHandle(h) close(h) #else -static struct of_file_handle { - of_file_handle_t previous, next; +static struct _OFFileHandle { + struct _OFFileHandle *previous, *next; BPTR handle; bool append; } *firstHandle = NULL; static void -closeHandle(of_file_handle_t handle) +closeHandle(OFFileHandle handle) { Close(handle->handle); + + Forbid(); if (handle->previous != NULL) handle->previous->next = handle->next; if (handle->next != NULL) handle->next->previous = handle->previous; if (firstHandle == handle) firstHandle = handle->next; - of_free(handle); + Permit(); + + OFFreeMemory(handle); } OF_DESTRUCTOR() { - for (of_file_handle_t iter = firstHandle; iter != NULL; + for (OFFileHandle iter = firstHandle; iter != NULL; iter = iter->next) Close(iter->handle); } #endif @@ -180,38 +184,23 @@ @throw [OFInitializationFailedException exceptionWithClass: self]; #endif } -+ (instancetype)fileWithPath: (OFString *)path - mode: (OFString *)mode -{ - return [[[self alloc] initWithPath: path - mode: mode] autorelease]; -} - -+ (instancetype)fileWithURL: (OFURL *)URL - mode: (OFString *)mode -{ - return [[[self alloc] initWithURL: URL - mode: mode] autorelease]; -} - -+ (instancetype)fileWithHandle: (of_file_handle_t)handle ++ (instancetype)fileWithPath: (OFString *)path mode: (OFString *)mode +{ + return [[[self alloc] initWithPath: path mode: mode] autorelease]; +} + ++ (instancetype)fileWithHandle: (OFFileHandle)handle { return [[[self alloc] initWithHandle: handle] autorelease]; } -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - -- (instancetype)initWithPath: (OFString *)path - mode: (OFString *)mode -{ - of_file_handle_t handle; +- (instancetype)initWithPath: (OFString *)path mode: (OFString *)mode +{ + OFFileHandle handle; @try { void *pool = objc_autoreleasePoolPush(); int flags; @@ -241,11 +230,11 @@ @throw [OFOpenItemFailedException exceptionWithPath: path mode: mode errNo: errno]; #else - handle = of_malloc(1, sizeof(*handle)); + handle = OFAllocMemory(1, sizeof(*handle)); @try { if ((flags = parseMode(mode.UTF8String, &handle->append)) == -1) @throw [OFInvalidArgumentException exception]; @@ -294,20 +283,24 @@ exceptionWithPath: path mode: mode errNo: EIO]; } } + + Forbid(); handle->previous = NULL; handle->next = firstHandle; if (firstHandle != NULL) firstHandle->previous = handle; firstHandle = handle; + + Permit(); } @catch (id e) { - of_free(handle); + OFFreeMemory(handle); @throw e; } #endif objc_autoreleasePoolPop(pool); @@ -324,54 +317,37 @@ } return self; } -- (instancetype)initWithURL: (OFURL *)URL - mode: (OFString *)mode -{ - void *pool = objc_autoreleasePoolPush(); - OFString *fileSystemRepresentation; - - @try { - fileSystemRepresentation = URL.fileSystemRepresentation; - } @catch (id e) { - [self release]; - @throw e; - } - - self = [self initWithPath: fileSystemRepresentation - mode: mode]; - - objc_autoreleasePoolPop(pool); - - return self; -} - -- (instancetype)initWithHandle: (of_file_handle_t)handle +- (instancetype)initWithHandle: (OFFileHandle)handle { self = [super init]; _handle = handle; return self; } + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} - (bool)lowlevelIsAtEndOfStream { - if (_handle == OF_INVALID_FILE_HANDLE) + if (_handle == OFInvalidFileHandle) @throw [OFNotOpenException exceptionWithObject: self]; return _atEndOfStream; } -- (size_t)lowlevelReadIntoBuffer: (void *)buffer - length: (size_t)length +- (size_t)lowlevelReadIntoBuffer: (void *)buffer length: (size_t)length { ssize_t ret; - if (_handle == OF_INVALID_FILE_HANDLE) + if (_handle == OFInvalidFileHandle) @throw [OFNotOpenException exceptionWithObject: self]; #if defined(OF_WINDOWS) if (length > UINT_MAX) @throw [OFOutOfRangeException exception]; @@ -399,14 +375,13 @@ _atEndOfStream = true; return ret; } -- (size_t)lowlevelWriteBuffer: (const void *)buffer - length: (size_t)length +- (size_t)lowlevelWriteBuffer: (const void *)buffer length: (size_t)length { - if (_handle == OF_INVALID_FILE_HANDLE) + if (_handle == OFInvalidFileHandle) @throw [OFNotOpenException exceptionWithObject: self]; #if defined(OF_WINDOWS) int bytesWritten; @@ -458,16 +433,15 @@ #endif return (size_t)bytesWritten; } -- (of_offset_t)lowlevelSeekToOffset: (of_offset_t)offset - whence: (int)whence +- (OFFileOffset)lowlevelSeekToOffset: (OFFileOffset)offset whence: (int)whence { - of_offset_t ret; + OFFileOffset ret; - if (_handle == OF_INVALID_FILE_HANDLE) + if (_handle == OFInvalidFileHandle) @throw [OFNotOpenException exceptionWithObject: self]; #ifndef OF_AMIGAOS # if defined(OF_WINDOWS) ret = _lseeki64(_handle, offset, whence); @@ -533,22 +507,22 @@ } #endif - (void)close { - if (_handle == OF_INVALID_FILE_HANDLE) + if (_handle == OFInvalidFileHandle) @throw [OFNotOpenException exceptionWithObject: self]; closeHandle(_handle); - _handle = OF_INVALID_FILE_HANDLE; + _handle = OFInvalidFileHandle; [super close]; } - (void)dealloc { - if (_handle != OF_INVALID_FILE_HANDLE) + if (_handle != OFInvalidFileHandle) [self close]; [super dealloc]; } @end Index: src/OFFileManager.h ================================================================== --- src/OFFileManager.h +++ src/OFFileManager.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -46,57 +44,57 @@ /** * @brief A key for a file attribute in the file attributes dictionary. * * Possible keys for file URLs are: * - * * @ref of_file_attribute_key_size - * * @ref of_file_attribute_key_type - * * @ref of_file_attribute_key_posix_permissions - * * @ref of_file_attribute_key_posix_uid - * * @ref of_file_attribute_key_posix_gid - * * @ref of_file_attribute_key_owner - * * @ref of_file_attribute_key_group - * * @ref of_file_attribute_key_last_access_date - * * @ref of_file_attribute_key_modification_date - * * @ref of_file_attribute_key_status_change_date - * * @ref of_file_attribute_key_creation_date - * * @ref of_file_attribute_key_symbolic_link_destination + * * @ref OFFileSize + * * @ref OFFileType + * * @ref OFFilePOSIXPermissions + * * @ref OFFileOwnerAccountID + * * @ref OFFileGroupOwnerAccountID + * * @ref OFFileOwnerAccountName + * * @ref OFFileGroupOwnerAccountName + * * @ref OFFileLastAccessDate + * * @ref OFFileModificationDate + * * @ref OFFileStatusChangeDate + * * @ref OFFileCreationDate + * * @ref OFFileSymbolicLinkDestination * * Other URL schemes might not have all keys and might have keys not listed. */ -typedef OFConstantString *of_file_attribute_key_t; +typedef OFConstantString *OFFileAttributeKey; /** * @brief The type of a file. * * Possibles values for file URLs are: * - * * @ref of_file_type_regular - * * @ref of_file_type_directory - * * @ref of_file_type_symbolic_link - * * @ref of_file_type_fifo - * * @ref of_file_type_character_special - * * @ref of_file_type_block_special - * * @ref of_file_type_socket + * * @ref OFFileTypeRegular + * * @ref OFFileTypeDirectory + * * @ref OFFileTypeSymbolicLink + * * @ref OFFileTypeFIFO + * * @ref OFFileTypeCharacterSpecial + * * @ref OFFileTypeBlockSpecial + * * @ref OFFileTypeSocket + * * @ref OFFileTypeUnknown * * Other URL schemes might not have all types and might have types not listed. */ -typedef OFConstantString *of_file_type_t; - -/** - * @brief A dictionary mapping keys of type @ref of_file_attribute_key_t - * to their attribute values. - */ -typedef OFDictionary OF_GENERIC(of_file_attribute_key_t, id) - *of_file_attributes_t; - -/** - * @brief A mutable dictionary mapping keys of type - * @ref of_file_attribute_key_t to their attribute values. - */ -typedef OFMutableDictionary OF_GENERIC(of_file_attribute_key_t, id) - *of_mutable_file_attributes_t; +typedef OFConstantString *OFFileAttributeType; + +/** + * @brief A dictionary mapping keys of type @ref OFFileAttributeKey to their + * attribute values. + */ +typedef OFDictionary OF_GENERIC(OFFileAttributeKey, id) *OFFileAttributes; + +/** + * @brief A mutable dictionary mapping keys of type @ref OFFileAttributeKey to + * their attribute values. + */ +typedef OFMutableDictionary OF_GENERIC(OFFileAttributeKey, id) + *OFMutableFileAttributes; #ifdef __cplusplus extern "C" { #endif /** @@ -103,137 +101,145 @@ * @brief The size of the file as an @ref OFNumber. * * For convenience, a category on @ref OFDictionary is provided to access this * via @ref OFDictionary#fileSize. */ -extern const of_file_attribute_key_t of_file_attribute_key_size; +extern const OFFileAttributeKey OFFileSize; /** * @brief The type of the file. * - * The corresponding value is of type @ref of_file_type_t. + * The corresponding value is of type @ref OFFileAttributeType. * * For convenience, a category on @ref OFDictionary is provided to access this * via @ref OFDictionary#fileType. */ -extern const of_file_attribute_key_t of_file_attribute_key_type; +extern const OFFileAttributeKey OFFileType; /** * @brief The POSIX permissions of the file as an @ref OFNumber. * * For convenience, a category on @ref OFDictionary is provided to access this * via @ref OFDictionary#filePOSIXPermissions. */ -extern const of_file_attribute_key_t of_file_attribute_key_posix_permissions; - -/** - * @brief The POSIX UID of the file as an @ref OFNumber. - * - * For convenience, a category on @ref OFDictionary is provided to access this - * via @ref OFDictionary#filePOSIXUID. - */ -extern const of_file_attribute_key_t of_file_attribute_key_posix_uid; - -/** - * @brief The POSIX GID of the file as an @ref OFNumber. - * - * For convenience, a category on @ref OFDictionary is provided to access this - * via @ref OFDictionary#filePOSIXGID. - */ -extern const of_file_attribute_key_t of_file_attribute_key_posix_gid; - -/** - * @brief The owner of the file as an OFString. - * - * For convenience, a category on @ref OFDictionary is provided to access this - * via @ref OFDictionary#fileOwner. - */ -extern const of_file_attribute_key_t of_file_attribute_key_owner; - -/** - * @brief The group of the file as an OFString. - * - * For convenience, a category on @ref OFDictionary is provided to access this - * via @ref OFDictionary#fileGroup. - */ -extern const of_file_attribute_key_t of_file_attribute_key_group; +extern const OFFileAttributeKey OFFilePOSIXPermissions; + +/** + * @brief The account ID of the owner of the file as an @ref OFNumber. + * + * For convenience, a category on @ref OFDictionary is provided to access this + * via @ref OFDictionary#fileOwnerAccountID. + */ +extern const OFFileAttributeKey OFFileOwnerAccountID; + +/** + * @brief The account ID of the group owner of the file as an @ref OFNumber. + * + * For convenience, a category on @ref OFDictionary is provided to access this + * via @ref OFDictionary#fileGroupOwnerAccountID. + */ +extern const OFFileAttributeKey OFFileGroupOwnerAccountID; + +/** + * @brief The account name of the owner of the file as an OFString. + * + * For convenience, a category on @ref OFDictionary is provided to access this + * via @ref OFDictionary#fileOwnerAccountName. + */ +extern const OFFileAttributeKey OFFileOwnerAccountName; + +/** + * @brief The account name of the group owner of the file as an OFString. + * + * For convenience, a category on @ref OFDictionary is provided to access this + * via @ref OFDictionary#fileGroupOwnerAccountName. + */ +extern const OFFileAttributeKey OFFileGroupOwnerAccountName; /** * @brief The last access date of the file as an @ref OFDate. * * For convenience, a category on @ref OFDictionary is provided to access this * via @ref OFDictionary#fileLastAccessDate. */ -extern const of_file_attribute_key_t of_file_attribute_key_last_access_date; +extern const OFFileAttributeKey OFFileLastAccessDate; /** * @brief The last modification date of the file as an @ref OFDate. * * For convenience, a category on @ref OFDictionary is provided to access this * via @ref OFDictionary#fileModificationDate. */ -extern const of_file_attribute_key_t of_file_attribute_key_modification_date; +extern const OFFileAttributeKey OFFileModificationDate; /** * @brief The last status change date of the file as an @ref OFDate. * * For convenience, a category on @ref OFDictionary is provided to access this * via @ref OFDictionary#fileStatusChangeDate. */ -extern const of_file_attribute_key_t of_file_attribute_key_status_change_date; +extern const OFFileAttributeKey OFFileStatusChangeDate; /** * @brief The creation date of the file as an @ref OFDate. * * For convenience, a category on @ref OFDictionary is provided to access this * via @ref OFDictionary#fileCreationDate. */ -extern const of_file_attribute_key_t of_file_attribute_key_creation_date; +extern const OFFileAttributeKey OFFileCreationDate; /** * @brief The destination of a symbolic link as an OFString. * * For convenience, a category on @ref OFDictionary is provided to access this * via @ref OFDictionary#fileSymbolicLinkDestination. */ -extern const of_file_attribute_key_t - of_file_attribute_key_symbolic_link_destination; +extern const OFFileAttributeKey OFFileSymbolicLinkDestination; /** * @brief A regular file. */ -extern const of_file_type_t of_file_type_regular; +extern const OFFileAttributeType OFFileTypeRegular; /** * @brief A directory. */ -extern const of_file_type_t of_file_type_directory; +extern const OFFileAttributeType OFFileTypeDirectory; /** * @brief A symbolic link. */ -extern const of_file_type_t of_file_type_symbolic_link; +extern const OFFileAttributeType OFFileTypeSymbolicLink; /** * @brief A FIFO. */ -extern const of_file_type_t of_file_type_fifo; +extern const OFFileAttributeType OFFileTypeFIFO; /** * @brief A character special file. */ -extern const of_file_type_t of_file_type_character_special; +extern const OFFileAttributeType OFFileTypeCharacterSpecial; /** * @brief A block special file. */ -extern const of_file_type_t of_file_type_block_special; +extern const OFFileAttributeType OFFileTypeBlockSpecial; /** * @brief A socket. */ -extern const of_file_type_t of_file_type_socket; +extern const OFFileAttributeType OFFileTypeSocket; + +/** + * @brief An unknown file type. + * + * This is different from not having an @ref OFFileType at all in that it means + * that retrieving file types is supported, but the particular file type is + * unknown. + */ +extern const OFFileAttributeType OFFileTypeUnknown; #ifdef __cplusplus } #endif /** @@ -271,23 +277,23 @@ /** * @brief Returns the attributes for the item at the specified path. * * @param path The path to return the attributes for * @return A dictionary of attributes for the specified path, with the keys of - * type @ref of_file_attribute_key_t + * type @ref OFFileAttributeKey */ -- (of_file_attributes_t)attributesOfItemAtPath: (OFString *)path; +- (OFFileAttributes)attributesOfItemAtPath: (OFString *)path; #endif /** * @brief Returns the attributes for the item at the specified URL. * * @param URL The URL to return the attributes for * @return A dictionary of attributes for the specified URL, with the keys of - * type @ref of_file_attribute_key_t + * type @ref OFFileAttributeKey */ -- (of_file_attributes_t)attributesOfItemAtURL: (OFURL *)URL; +- (OFFileAttributes)attributesOfItemAtURL: (OFURL *)URL; #ifdef OF_HAVE_FILES /** * @brief Sets the attributes for the item at the specified path. * @@ -294,11 +300,11 @@ * All attributes not part of the dictionary are left unchanged. * * @param attributes The attributes to set for the specified path * @param path The path of the item to set the attributes for */ -- (void)setAttributes: (of_file_attributes_t)attributes +- (void)setAttributes: (OFFileAttributes)attributes ofItemAtPath: (OFString *)path; #endif /** * @brief Sets the attributes for the item at the specified URL. @@ -306,12 +312,11 @@ * All attributes not part of the dictionary are left unchanged. * * @param attributes The attributes to set for the specified URL * @param URL The URL of the item to set the attributes for */ -- (void)setAttributes: (of_file_attributes_t)attributes - ofItemAtURL: (OFURL *)URL; +- (void)setAttributes: (OFFileAttributes)attributes ofItemAtURL: (OFURL *)URL; #ifdef OF_HAVE_FILES /** * @brief Checks whether a file exists at the specified path. * @@ -376,12 +381,11 @@ * @brief Creates a directory at the specified URL. * * @param URL The URL of the directory to create * @param createParents Whether to create the parents of the directory */ -- (void)createDirectoryAtURL: (OFURL *)URL - createParents: (bool)createParents; +- (void)createDirectoryAtURL: (OFURL *)URL createParents: (bool)createParents; #ifdef OF_HAVE_FILES /** * @brief Returns an array with the items in the specified directory. * @@ -392,20 +396,32 @@ */ - (OFArray OF_GENERIC(OFString *) *)contentsOfDirectoryAtPath: (OFString *)path; #endif /** - * @brief Returns an array with the items in the specified directory. + * @brief Returns an array with the URLs of the items in the specified + * directory. * * @note `.` and `..` are not part of the returned array. * * @param URL The URL to the directory whose items should be returned - * @return An array of OFString with the items in the specified directory + * @return An array with the URLs of the items in the specified directory */ -- (OFArray OF_GENERIC(OFString *) *)contentsOfDirectoryAtURL: (OFURL *)URL; +- (OFArray OF_GENERIC(OFURL *) *)contentsOfDirectoryAtURL: (OFURL *)URL; #ifdef OF_HAVE_FILES +/** + * @brief Returns an array with all subpaths of the specified directory. + * + * @note `.` and `..` (of the directory itself or any subdirectory) are not + * part of the returned array. + * + * @param path The path to the directory whose subpaths should be returned + * @return An array of OFString with the subpaths of the specified directory + */ +- (OFArray OF_GENERIC(OFString *) *)subpathsOfDirectoryAtPath: (OFString *)path; + /** * @brief Changes the current working directory. * * @param path The new directory to change to */ @@ -429,12 +445,11 @@ * directory. * * @param source The file, directory or symbolic link to copy * @param destination The destination path */ -- (void)copyItemAtPath: (OFString *)source - toPath: (OFString *)destination; +- (void)copyItemAtPath: (OFString *)source toPath: (OFString *)destination; #endif /** * @brief Copies a file, directory or symbolic link (if supported by the OS). * @@ -446,12 +461,11 @@ * directory. * * @param source The file, directory or symbolic link to copy * @param destination The destination URL */ -- (void)copyItemAtURL: (OFURL *)source - toURL: (OFURL *)destination; +- (void)copyItemAtURL: (OFURL *)source toURL: (OFURL *)destination; #ifdef OF_HAVE_FILES /** * @brief Moves an item. * @@ -463,12 +477,11 @@ * removed using @ref removeItemAtPath:. * * @param source The item to rename * @param destination The new name for the item */ -- (void)moveItemAtPath: (OFString *)source - toPath: (OFString *)destination; +- (void)moveItemAtPath: (OFString *)source toPath: (OFString *)destination; #endif /** * @brief Moves an item. * @@ -480,12 +493,11 @@ * @ref copyItemAtURL:toURL: and the source removed using @ref removeItemAtURL:. * * @param source The item to rename * @param destination The new name for the item */ -- (void)moveItemAtURL: (OFURL *)source - toURL: (OFURL *)destination; +- (void)moveItemAtURL: (OFURL *)source toURL: (OFURL *)destination; #ifdef OF_HAVE_FILES /** * @brief Removes the item at the specified path. * @@ -515,12 +527,11 @@ * This method is not available on some systems. * * @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 */ -- (void)linkItemAtPath: (OFString *)source - toPath: (OFString *)destination; +- (void)linkItemAtPath: (OFString *)source toPath: (OFString *)destination; #endif /** * @brief Creates a hard link for the specified item. * @@ -530,12 +541,11 @@ * This method is not available for all URLs. * * @param source The URL to the item for which a link should be created * @param destination The URL to the item which should link to the source */ -- (void)linkItemAtURL: (OFURL *)source - toURL: (OFURL *)destination; +- (void)linkItemAtURL: (OFURL *)source toURL: (OFURL *)destination; #ifdef OF_FILE_MANAGER_SUPPORTS_SYMLINKS /** * @brief Creates a symbolic link for an item. * @@ -572,95 +582,90 @@ withDestinationPath: (OFString *)target; @end @interface OFDictionary (FileAttributes) /** - * @brief The @ref of_file_attribute_key_size key from the dictionary. + * @brief The @ref OFFileSize key from the dictionary. * * Raises an @ref OFUndefinedKeyException if the key is missing. */ @property (readonly, nonatomic) unsigned long long fileSize; /** - * @brief The @ref of_file_attribute_key_type key from the dictionary. + * @brief The @ref OFFileType key from the dictionary. * * Raises an @ref OFUndefinedKeyException if the key is missing. */ -@property (readonly, nonatomic) of_file_type_t fileType; +@property (readonly, nonatomic) OFFileAttributeType fileType; /** - * @brief The @ref of_file_attribute_key_posix_permissions key from the - * dictionary. + * @brief The @ref OFFilePOSIXPermissions key from the dictionary. * * Raises an @ref OFUndefinedKeyException if the key is missing. */ @property (readonly, nonatomic) unsigned long filePOSIXPermissions; /** - * @brief The @ref of_file_attribute_key_posix_uid key from the dictionary. - * - * Raises an @ref OFUndefinedKeyException if the key is missing. - */ -@property (readonly, nonatomic) unsigned long filePOSIXUID; - -/** - * @brief The @ref of_file_attribute_key_posix_gid key from the dictionary. - * - * Raises an @ref OFUndefinedKeyException if the key is missing. - */ -@property (readonly, nonatomic) unsigned long filePOSIXGID; - -/** - * @brief The @ref of_file_attribute_key_owner key from the dictionary. - * - * Raises an @ref OFUndefinedKeyException if the key is missing. - */ -@property (readonly, nonatomic) OFString *fileOwner; - -/** - * @brief The @ref of_file_attribute_key_group key from the dictionary. - * - * Raises an @ref OFUndefinedKeyException if the key is missing. - */ -@property (readonly, nonatomic) OFString *fileGroup; - -/** - * @brief The @ref of_file_attribute_key_last_access_date key from the - * dictionary. + * @brief The @ref OFFileOwnerAccountID key from the dictionary. + * + * Raises an @ref OFUndefinedKeyException if the key is missing. + */ +@property (readonly, nonatomic) unsigned long fileOwnerAccountID; + +/** + * @brief The @ref OFFileGroupOwnerAccountID key from the dictionary. + * + * Raises an @ref OFUndefinedKeyException if the key is missing. + */ +@property (readonly, nonatomic) unsigned long fileGroupOwnerAccountID; + +/** + * @brief The @ref OFFileOwnerAccountName key from the dictionary. + * + * Raises an @ref OFUndefinedKeyException if the key is missing. + */ +@property (readonly, nonatomic) OFString *fileOwnerAccountName; + +/** + * @brief The @ref OFFileGroupOwnerAccountName key from the dictionary. + * + * Raises an @ref OFUndefinedKeyException if the key is missing. + */ +@property (readonly, nonatomic) OFString *fileGroupOwnerAccountName; + +/** + * @brief The @ref OFFileLastAccessDate key from the dictionary. * * Raises an @ref OFUndefinedKeyException if the key is missing. */ @property (readonly, nonatomic) OFDate *fileLastAccessDate; /** - * @brief The @ref of_file_attribute_key_modification_date key from the - * dictionary. + * @brief The @ref OFFileModificationDate key from the dictionary. * * Raises an @ref OFUndefinedKeyException if the key is missing. */ @property (readonly, nonatomic) OFDate *fileModificationDate; /** - * @brief The @ref of_file_attribute_key_status_change_date key from the - * dictionary. + * @brief The @ref OFFileStatusChangeDate key from the dictionary. * * Raises an @ref OFUndefinedKeyException if the key is missing. */ @property (readonly, nonatomic) OFDate *fileStatusChangeDate; /** - * @brief The @ref of_file_attribute_key_creation_date key from the dictionary. + * @brief The @ref OFFileCreationDate key from the dictionary. * * Raises an @ref OFUndefinedKeyException if the key is missing. */ @property (readonly, nonatomic) OFDate *fileCreationDate; /** - * @brief The @ref of_file_attribute_key_symbolic_link_destination key from the - * dictionary. + * @brief The @ref OFFileSymbolicLinkDestination key from the dictionary. * * Raises an @ref OFUndefinedKeyException if the key is missing. */ @property (readonly, nonatomic) OFString *fileSymbolicLinkDestination; @end OF_ASSUME_NONNULL_END Index: src/OFFileManager.m ================================================================== --- src/OFFileManager.m +++ src/OFFileManager.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -67,51 +65,23 @@ #ifdef OF_AMIGAOS # include # include #endif + +#ifdef OF_MINT +# include +#endif @interface OFDefaultFileManager: OFFileManager @end -const of_file_attribute_key_t of_file_attribute_key_size = - @"of_file_attribute_key_size"; -const of_file_attribute_key_t of_file_attribute_key_type = - @"of_file_attribute_key_type"; -const of_file_attribute_key_t of_file_attribute_key_posix_permissions = - @"of_file_attribute_key_posix_permissions"; -const of_file_attribute_key_t of_file_attribute_key_posix_uid = - @"of_file_attribute_key_posix_uid"; -const of_file_attribute_key_t of_file_attribute_key_posix_gid = - @"of_file_attribute_key_posix_gid"; -const of_file_attribute_key_t of_file_attribute_key_owner = - @"of_file_attribute_key_owner"; -const of_file_attribute_key_t of_file_attribute_key_group = - @"of_file_attribute_key_group"; -const of_file_attribute_key_t of_file_attribute_key_last_access_date = - @"of_file_attribute_key_last_access_date"; -const of_file_attribute_key_t of_file_attribute_key_modification_date = - @"of_file_attribute_key_modification_date"; -const of_file_attribute_key_t of_file_attribute_key_status_change_date = - @"of_file_attribute_key_status_change_date"; -const of_file_attribute_key_t of_file_attribute_key_creation_date = - @"of_file_attribute_key_creation_date"; -const of_file_attribute_key_t of_file_attribute_key_symbolic_link_destination = - @"of_file_attribute_key_symbolic_link_destination"; - -const of_file_type_t of_file_type_regular = @"of_file_type_regular"; -const of_file_type_t of_file_type_directory = @"of_file_type_directory"; -const of_file_type_t of_file_type_symbolic_link = @"of_file_type_symbolic_link"; -const of_file_type_t of_file_type_fifo = @"of_file_type_fifo"; -const of_file_type_t of_file_type_character_special = - @"of_file_type_character_special"; -const of_file_type_t of_file_type_block_special = @"of_file_type_block_special"; -const of_file_type_t of_file_type_socket = @"of_file_type_socket"; - #ifdef OF_AMIGAOS4 # define CurrentDir(lock) SetCurrentDir(lock) #endif + +#include "OFFileManagerConstants.inc" static OFFileManager *defaultManager; #ifdef OF_AMIGAOS static bool dirChanged = false; @@ -123,12 +93,11 @@ UnLock(CurrentDir(originalDirLock)); } #endif static id -attributeForKeyOrException(of_file_attributes_t attributes, - of_file_attribute_key_t key) +attributeForKeyOrException(OFFileAttributes attributes, OFFileAttributeKey key) { id object = [attributes objectForKey: key]; if (object == nil) @throw [OFUndefinedKeyException exceptionWithObject: attributes @@ -231,11 +200,11 @@ objc_autoreleasePoolPop(pool); return [ret autorelease]; } #endif -- (of_file_attributes_t)attributesOfItemAtURL: (OFURL *)URL +- (OFFileAttributes)attributesOfItemAtURL: (OFURL *)URL { OFURLHandler *URLHandler; if (URL == nil) @throw [OFInvalidArgumentException exception]; @@ -245,14 +214,14 @@ return [URLHandler attributesOfItemAtURL: URL]; } #ifdef OF_HAVE_FILES -- (of_file_attributes_t)attributesOfItemAtPath: (OFString *)path +- (OFFileAttributes)attributesOfItemAtPath: (OFString *)path { void *pool = objc_autoreleasePoolPush(); - of_file_attributes_t ret; + OFFileAttributes ret; ret = [self attributesOfItemAtURL: [OFURL fileURLWithPath: path]]; [ret retain]; @@ -260,34 +229,30 @@ return [ret autorelease]; } #endif -- (void)setAttributes: (of_file_attributes_t)attributes - ofItemAtURL: (OFURL *)URL +- (void)setAttributes: (OFFileAttributes)attributes ofItemAtURL: (OFURL *)URL { OFURLHandler *URLHandler; if (URL == nil) @throw [OFInvalidArgumentException exception]; if ((URLHandler = [OFURLHandler handlerForURL: URL]) == nil) @throw [OFUnsupportedProtocolException exceptionWithURL: URL]; - [URLHandler setAttributes: attributes - ofItemAtURL: URL]; + [URLHandler setAttributes: attributes ofItemAtURL: URL]; } #ifdef OF_HAVE_FILES -- (void)setAttributes: (of_file_attributes_t)attributes +- (void)setAttributes: (OFFileAttributes)attributes ofItemAtPath: (OFString *)path { void *pool = objc_autoreleasePoolPush(); - [self setAttributes: attributes ofItemAtURL: [OFURL fileURLWithPath: path]]; - objc_autoreleasePoolPop(pool); } #endif - (bool)fileExistsAtURL: (OFURL *)URL @@ -459,11 +424,11 @@ objc_autoreleasePoolPop(pool); } #endif -- (OFArray OF_GENERIC(OFString *) *)contentsOfDirectoryAtURL: (OFURL *)URL +- (OFArray OF_GENERIC(OFURL *) *)contentsOfDirectoryAtURL: (OFURL *)URL { OFURLHandler *URLHandler; if (URL == nil) @throw [OFInvalidArgumentException exception]; @@ -476,14 +441,50 @@ #ifdef OF_HAVE_FILES - (OFArray OF_GENERIC(OFString *) *)contentsOfDirectoryAtPath: (OFString *)path { void *pool = objc_autoreleasePoolPush(); - OFArray OF_GENERIC(OFString *) *ret; + OFArray OF_GENERIC(OFURL *) *URLs; + OFMutableArray OF_GENERIC(OFString *) *ret; - ret = [self contentsOfDirectoryAtURL: [OFURL fileURLWithPath: path]]; + URLs = [self contentsOfDirectoryAtURL: [OFURL fileURLWithPath: path]]; + ret = [OFMutableArray arrayWithCapacity: URLs.count]; + for (OFURL *URL in URLs) + [ret addObject: URL.lastPathComponent]; + + [ret makeImmutable]; + [ret retain]; + + objc_autoreleasePoolPop(pool); + + return [ret autorelease]; +} + +- (OFArray OF_GENERIC(OFString *) *)subpathsOfDirectoryAtPath: (OFString *)path +{ + void *pool = objc_autoreleasePoolPush(); + OFMutableArray OF_GENERIC(OFString *) *ret = + [OFMutableArray arrayWithObject: path]; + + for (OFString *subpath in [self contentsOfDirectoryAtPath: path]) { + void *pool2 = objc_autoreleasePoolPush(); + OFString *fullSubpath = + [path stringByAppendingPathComponent: subpath]; + OFFileAttributes attributes = + [self attributesOfItemAtPath: fullSubpath]; + + if ([attributes.fileType isEqual: OFFileTypeDirectory]) + [ret addObjectsFromArray: + [self subpathsOfDirectoryAtPath: fullSubpath]]; + else + [ret addObject: fullSubpath]; + + objc_autoreleasePoolPop(pool2); + } + + [ret makeImmutable]; [ret retain]; objc_autoreleasePoolPop(pool); return [ret autorelease]; @@ -552,12 +553,11 @@ [self changeCurrentDirectoryPath: URL.fileSystemRepresentation]; objc_autoreleasePoolPop(pool); } -- (void)copyItemAtPath: (OFString *)source - toPath: (OFString *)destination +- (void)copyItemAtPath: (OFString *)source toPath: (OFString *)destination { void *pool = objc_autoreleasePoolPush(); [self copyItemAtURL: [OFURL fileURLWithPath: source] toURL: [OFURL fileURLWithPath: destination]]; @@ -564,17 +564,16 @@ objc_autoreleasePoolPop(pool); } #endif -- (void)copyItemAtURL: (OFURL *)source - toURL: (OFURL *)destination +- (void)copyItemAtURL: (OFURL *)source toURL: (OFURL *)destination { void *pool; OFURLHandler *URLHandler; - of_file_attributes_t attributes; - of_file_type_t type; + OFFileAttributes attributes; + OFFileAttributeType type; if (source == nil || destination == nil) @throw [OFInvalidArgumentException exception]; pool = objc_autoreleasePoolPush(); @@ -581,12 +580,11 @@ if ((URLHandler = [OFURLHandler handlerForURL: source]) == nil) @throw [OFUnsupportedProtocolException exceptionWithURL: source]; - if ([URLHandler copyItemAtURL: source - toURL: destination]) + if ([URLHandler copyItemAtURL: source toURL: destination]) return; if ([self fileExistsAtURL: destination]) @throw [OFCopyItemFailedException exceptionWithSourceURL: source @@ -602,22 +600,21 @@ errNo: e.errNo]; } type = attributes.fileType; - if ([type isEqual: of_file_type_directory]) { - OFArray *contents; + if ([type isEqual: OFFileTypeDirectory]) { + OFArray OF_GENERIC(OFURL *) *contents; @try { [self createDirectoryAtURL: destination]; @try { - of_file_attribute_key_t key = - of_file_attribute_key_posix_permissions; + OFFileAttributeKey key = OFFilePOSIXPermissions; OFNumber *permissions = [attributes objectForKey: key]; - of_file_attributes_t destinationAttributes; + OFFileAttributes destinationAttributes; if (permissions != nil) { destinationAttributes = [OFDictionary dictionaryWithObject: permissions forKey: key]; @@ -643,31 +640,27 @@ errNo: [e errNo]]; @throw e; } - for (OFString *item in contents) { + for (OFURL *item in contents) { void *pool2 = objc_autoreleasePoolPush(); - OFURL *sourceURL, *destinationURL; - - sourceURL = - [source URLByAppendingPathComponent: item]; - destinationURL = - [destination URLByAppendingPathComponent: item]; - - [self copyItemAtURL: sourceURL - toURL: destinationURL]; + OFURL *destinationURL = [destination + URLByAppendingPathComponent: + item.lastPathComponent]; + + [self copyItemAtURL: item toURL: destinationURL]; objc_autoreleasePoolPop(pool2); } - } else if ([type isEqual: of_file_type_regular]) { + } else if ([type isEqual: OFFileTypeRegular]) { size_t pageSize = [OFSystemInfo pageSize]; OFStream *sourceStream = nil; OFStream *destinationStream = nil; char *buffer; - buffer = of_malloc(1, pageSize); + buffer = OFAllocMemory(1, pageSize); @try { sourceStream = [[OFURLHandler handlerForURL: source] openItemAtURL: source mode: @"r"]; destinationStream = [[OFURLHandler handlerForURL: @@ -683,15 +676,14 @@ [destinationStream writeBuffer: buffer length: length]; } @try { - of_file_attribute_key_t key = - of_file_attribute_key_posix_permissions; + OFFileAttributeKey key = OFFilePOSIXPermissions; OFNumber *permissions = [attributes objectForKey: key]; - of_file_attributes_t destinationAttributes; + OFFileAttributes destinationAttributes; if (permissions != nil) { destinationAttributes = [OFDictionary dictionaryWithObject: permissions forKey: key]; @@ -716,13 +708,13 @@ @throw e; } @finally { [sourceStream close]; [destinationStream close]; - of_free(buffer); + OFFreeMemory(buffer); } - } else if ([type isEqual: of_file_type_symbolic_link]) { + } else if ([type isEqual: OFFileTypeSymbolicLink]) { @try { OFString *linkDestination = attributes.fileSymbolicLinkDestination; [self createSymbolicLinkAtURL: destination @@ -750,24 +742,20 @@ objc_autoreleasePoolPop(pool); } #ifdef OF_HAVE_FILES -- (void)moveItemAtPath: (OFString *)source - toPath: (OFString *)destination +- (void)moveItemAtPath: (OFString *)source toPath: (OFString *)destination { void *pool = objc_autoreleasePoolPush(); - [self moveItemAtURL: [OFURL fileURLWithPath: source] toURL: [OFURL fileURLWithPath: destination]]; - objc_autoreleasePoolPop(pool); } #endif -- (void)moveItemAtURL: (OFURL *)source - toURL: (OFURL *)destination +- (void)moveItemAtURL: (OFURL *)source toURL: (OFURL *)destination { void *pool; OFURLHandler *URLHandler; if (source == nil || destination == nil) @@ -778,12 +766,11 @@ if ((URLHandler = [OFURLHandler handlerForURL: source]) == nil) @throw [OFUnsupportedProtocolException exceptionWithURL: source]; @try { - if ([URLHandler moveItemAtURL: source - toURL: destination]) + if ([URLHandler moveItemAtURL: source toURL: destination]) return; } @catch (OFMoveItemFailedException *e) { if (e.errNo != EXDEV) @throw e; } @@ -793,12 +780,11 @@ exceptionWithSourceURL: source destinationURL: destination errNo: EEXIST]; @try { - [self copyItemAtURL: source - toURL: destination]; + [self copyItemAtURL: source toURL: destination]; } @catch (OFCopyItemFailedException *e) { [self removeItemAtURL: destination]; @throw [OFMoveItemFailedException exceptionWithSourceURL: source @@ -833,19 +819,16 @@ #ifdef OF_HAVE_FILES - (void)removeItemAtPath: (OFString *)path { void *pool = objc_autoreleasePoolPush(); - [self removeItemAtURL: [OFURL fileURLWithPath: path]]; - objc_autoreleasePoolPop(pool); } #endif -- (void)linkItemAtURL: (OFURL *)source - toURL: (OFURL *)destination +- (void)linkItemAtURL: (OFURL *)source toURL: (OFURL *)destination { void *pool = objc_autoreleasePoolPush(); OFURLHandler *URLHandler; if (source == nil || destination == nil) @@ -858,25 +841,21 @@ if (URLHandler == nil) @throw [OFUnsupportedProtocolException exceptionWithURL: source]; - [URLHandler linkItemAtURL: source - toURL: destination]; + [URLHandler linkItemAtURL: source toURL: destination]; objc_autoreleasePoolPop(pool); } #ifdef OF_FILE_MANAGER_SUPPORTS_LINKS -- (void)linkItemAtPath: (OFString *)source - toPath: (OFString *)destination +- (void)linkItemAtPath: (OFString *)source toPath: (OFString *)destination { void *pool = objc_autoreleasePoolPush(); - [self linkItemAtURL: [OFURL fileURLWithPath: source] toURL: [OFURL fileURLWithPath: destination]]; - objc_autoreleasePoolPop(pool); } #endif - (void)createSymbolicLinkAtURL: (OFURL *)URL @@ -891,25 +870,22 @@ URLHandler = [OFURLHandler handlerForURL: URL]; if (URLHandler == nil) @throw [OFUnsupportedProtocolException exceptionWithURL: URL]; - [URLHandler createSymbolicLinkAtURL: URL - withDestinationPath: target]; + [URLHandler createSymbolicLinkAtURL: URL withDestinationPath: target]; objc_autoreleasePoolPop(pool); } #ifdef OF_FILE_MANAGER_SUPPORTS_SYMLINKS - (void)createSymbolicLinkAtPath: (OFString *)path withDestinationPath: (OFString *)target { void *pool = objc_autoreleasePoolPush(); - [self createSymbolicLinkAtURL: [OFURL fileURLWithPath: path] withDestinationPath: target]; - objc_autoreleasePoolPop(pool); } #endif @end @@ -928,79 +904,74 @@ { } - (unsigned int)retainCount { - return OF_RETAIN_COUNT_MAX; + return OFMaxRetainCount; } @end @implementation OFDictionary (FileAttributes) - (unsigned long long)fileSize { - return [attributeForKeyOrException(self, of_file_attribute_key_size) + return [attributeForKeyOrException(self, OFFileSize) unsignedLongLongValue]; } -- (of_file_type_t)fileType +- (OFFileAttributeType)fileType { - return attributeForKeyOrException(self, of_file_attribute_key_type); + return attributeForKeyOrException(self, OFFileType); } - (unsigned long)filePOSIXPermissions { return [attributeForKeyOrException(self, - of_file_attribute_key_posix_permissions) unsignedLongValue]; -} - -- (unsigned long)filePOSIXUID -{ - return [attributeForKeyOrException(self, - of_file_attribute_key_posix_uid) unsignedLongValue]; -} - -- (unsigned long)filePOSIXGID -{ - return [attributeForKeyOrException(self, - of_file_attribute_key_posix_gid) unsignedLongValue]; -} - -- (OFString *)fileOwner -{ - return attributeForKeyOrException(self, of_file_attribute_key_owner); -} - -- (OFString *)fileGroup -{ - return attributeForKeyOrException(self, of_file_attribute_key_group); + OFFilePOSIXPermissions) unsignedLongValue]; +} + +- (unsigned long)fileOwnerAccountID +{ + return [attributeForKeyOrException(self, + OFFileOwnerAccountID) unsignedLongValue]; +} + +- (unsigned long)fileGroupOwnerAccountID +{ + return [attributeForKeyOrException(self, + OFFileGroupOwnerAccountID) unsignedLongValue]; +} + +- (OFString *)fileOwnerAccountName +{ + return attributeForKeyOrException(self, OFFileOwnerAccountName); +} + +- (OFString *)fileGroupOwnerAccountName +{ + return attributeForKeyOrException(self, OFFileGroupOwnerAccountName); } - (OFDate *)fileLastAccessDate { - return attributeForKeyOrException(self, - of_file_attribute_key_last_access_date); + return attributeForKeyOrException(self, OFFileLastAccessDate); } - (OFDate *)fileModificationDate { - return attributeForKeyOrException(self, - of_file_attribute_key_modification_date); + return attributeForKeyOrException(self, OFFileModificationDate); } - (OFDate *)fileStatusChangeDate { - return attributeForKeyOrException(self, - of_file_attribute_key_status_change_date); + return attributeForKeyOrException(self, OFFileStatusChangeDate); } - (OFDate *)fileCreationDate { - return attributeForKeyOrException(self, - of_file_attribute_key_creation_date); + return attributeForKeyOrException(self, OFFileCreationDate); } - (OFString *)fileSymbolicLinkDestination { - return attributeForKeyOrException(self, - of_file_attribute_key_symbolic_link_destination); + return attributeForKeyOrException(self, OFFileSymbolicLinkDestination); } @end ADDED src/OFFileManagerConstants.inc Index: src/OFFileManagerConstants.inc ================================================================== --- /dev/null +++ src/OFFileManagerConstants.inc @@ -0,0 +1,40 @@ +/* + * 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. + */ + +const OFFileAttributeKey OFFileSize = @"OFFileSize"; +const OFFileAttributeKey OFFileType = @"OFFileType"; +const OFFileAttributeKey OFFilePOSIXPermissions = @"OFFilePOSIXPermissions"; +const OFFileAttributeKey OFFileOwnerAccountID = @"OFFileOwnerAccountID"; +const OFFileAttributeKey OFFileGroupOwnerAccountID = + @"OFFileGroupOwnerAccountID"; +const OFFileAttributeKey OFFileOwnerAccountName = @"OFFileOwnerAccountName"; +const OFFileAttributeKey OFFileGroupOwnerAccountName = + @"OFFileGroupOwnerAccountName"; +const OFFileAttributeKey OFFileLastAccessDate = @"OFFileLastAccessDate"; +const OFFileAttributeKey OFFileModificationDate = @"OFFileModificationDate"; +const OFFileAttributeKey OFFileStatusChangeDate = @"OFFileStatusChangeDate"; +const OFFileAttributeKey OFFileCreationDate = @"OFFileCreationDate"; +const OFFileAttributeKey OFFileSymbolicLinkDestination = + @"OFFileSymbolicLinkDestination"; + +const OFFileAttributeType OFFileTypeRegular = @"OFFileTypeRegular"; +const OFFileAttributeType OFFileTypeDirectory = @"OFFileTypeDirectory"; +const OFFileAttributeType OFFileTypeSymbolicLink = @"OFFileTypeSymbolicLink"; +const OFFileAttributeType OFFileTypeFIFO = @"OFFileTypeFIFO"; +const OFFileAttributeType OFFileTypeCharacterSpecial = + @"OFFileTypeCharacterSpecial"; +const OFFileAttributeType OFFileTypeBlockSpecial = @"OFFileTypeBlockSpecial"; +const OFFileAttributeType OFFileTypeSocket = @"OFFileTypeSocket"; +const OFFileAttributeType OFFileTypeUnknown = @"OFFileTypeUnknown"; Index: src/OFFileURLHandler.h ================================================================== --- src/OFFileURLHandler.h +++ src/OFFileURLHandler.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFFileURLHandler.m ================================================================== --- src/OFFileURLHandler.m +++ src/OFFileURLHandler.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -14,10 +12,12 @@ * 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 @@ -83,124 +83,122 @@ # ifdef OF_AMIGAOS4 # define DeleteFile(path) Delete(path) # endif #endif -#if defined(OF_WINDOWS) || (defined(OF_AMIGAOS) && !defined(OF_MORPHOS)) +#if defined(OF_WINDOWS) || defined(OF_AMIGAOS) typedef struct { - of_offset_t st_size; + OFFileOffset st_size; unsigned int st_mode; - of_time_interval_t st_atime, st_mtime, st_ctime; + OFTimeInterval st_atime, st_mtime, st_ctime; # ifdef OF_WINDOWS # define HAVE_STRUCT_STAT_ST_BIRTHTIME - of_time_interval_t st_birthtime; + OFTimeInterval st_birthtime; DWORD fileAttributes; # endif -} of_stat_t; +} Stat; #elif defined(HAVE_STAT64) -typedef struct stat64 of_stat_t; +typedef struct stat64 Stat; #else -typedef struct stat of_stat_t; +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 (*func__wutime64)(const wchar_t *, struct __utimbuf64 *); -static WINAPI BOOLEAN (*func_CreateSymbolicLinkW)(LPCWSTR, LPCWSTR, DWORD); -static WINAPI BOOLEAN (*func_CreateHardLinkW)(LPCWSTR, LPCWSTR, +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 of_time_interval_t +static OFTimeInterval filetimeToTimeInterval(const FILETIME *filetime) { return (double)((int64_t)filetime->dwHighDateTime << 32 | filetime->dwLowDateTime) / 10000000.0 - 11644473600.0; } -static void -setErrno(void) +static int +retrieveError(void) { switch (GetLastError()) { case ERROR_FILE_NOT_FOUND: case ERROR_PATH_NOT_FOUND: case ERROR_NO_MORE_FILES: - errno = ENOENT; - return; + return ENOENT; case ERROR_ACCESS_DENIED: - errno = EACCES; - return; + return EACCES; case ERROR_DIRECTORY: - errno = ENOTDIR; - return; + return ENOTDIR; case ERROR_NOT_READY: - errno = EBUSY; - return; + return EBUSY; + default: + return EIO; } - - errno = 0; } #endif #ifdef OF_AMIGAOS -static void -setErrno(void) +static int +retrieveError(void) { switch (IoErr()) { case ERROR_DELETE_PROTECTED: case ERROR_READ_PROTECTED: case ERROR_WRITE_PROTECTED: - errno = EACCES; - break; + return EACCES; case ERROR_DISK_NOT_VALIDATED: case ERROR_OBJECT_IN_USE: - errno = EBUSY; - break; + return EBUSY; case ERROR_OBJECT_EXISTS: - errno = EEXIST; - break; + return EEXIST; case ERROR_DIR_NOT_FOUND: case ERROR_NO_MORE_ENTRIES: case ERROR_OBJECT_NOT_FOUND: - errno = ENOENT; - break; + return ENOENT; case ERROR_NO_FREE_STORE: - errno = ENOMEM; - break; + return ENOMEM; case ERROR_DISK_FULL: - errno = ENOSPC; - break; + return ENOSPC; case ERROR_DIRECTORY_NOT_EMPTY: - errno = ENOTEMPTY; - break; + return ENOTEMPTY; case ERROR_DISK_WRITE_PROTECTED: - errno = EROFS; - break; + return EROFS; case ERROR_RENAME_ACROSS_DEVICES: - errno = EXDEV; - break; + return EXDEV; default: - errno = 0; - break; + return EIO; } } #endif static int -of_stat(OFString *path, of_stat_t *buffer) +statWrapper(OFString *path, Stat *buffer) { #if defined(OF_WINDOWS) WIN32_FILE_ATTRIBUTE_DATA data; bool success; @@ -210,14 +208,12 @@ else success = GetFileAttributesExA( [path cStringWithEncoding: [OFLocale encoding]], GetFileExInfoStandard, &data); - if (!success) { - setErrno(); - return -1; - } + if (!success) + return retrieveError(); buffer->st_size = (uint64_t)data.nFileSizeHigh << 32 | data.nFileSizeLow; if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) @@ -229,22 +225,18 @@ */ WIN32_FIND_DATAW findData; HANDLE findHandle; if ((findHandle = FindFirstFileW(path.UTF16String, - &findData)) == INVALID_HANDLE_VALUE) { - setErrno(); - return -1; - } + &findData)) == INVALID_HANDLE_VALUE) + return retrieveError(); @try { if (!(findData.dwFileAttributes & - FILE_ATTRIBUTE_REPARSE_POINT)) { + FILE_ATTRIBUTE_REPARSE_POINT)) /* Race? Indicate to try again. */ - errno = EAGAIN; - return -1; - } + return EAGAIN; buffer->st_mode = (findData.dwReserved0 == IO_REPARSE_TAG_SYMLINK ? S_IFLNK : S_IFREG); } @finally { @@ -261,45 +253,49 @@ buffer->st_ctime = buffer->st_birthtime = filetimeToTimeInterval(&data.ftCreationTime); buffer->fileAttributes = data.dwFileAttributes; return 0; -#elif defined(OF_AMIGAOS) && !defined(OF_MORPHOS) +#elif defined(OF_AMIGAOS) BPTR lock; # ifdef OF_AMIGAOS4 struct ExamineData *ed; # else struct FileInfoBlock fib; # endif - of_time_interval_t timeInterval; + OFTimeInterval timeInterval; struct Locale *locale; struct DateStamp *date; if ((lock = Lock([path cStringWithEncoding: [OFLocale encoding]], - SHARED_LOCK)) == 0) { - setErrno(); - return -1; - } + SHARED_LOCK)) == 0) + return retrieveError(); -# ifdef OF_AMIGAOS4 +# 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 = retrieveError(); UnLock(lock); - - errno = 0; - return -1; + return error; } UnLock(lock); -# ifdef OF_AMIGAOS4 +# if defined(OF_MORPHOS) + buffer->st_size = fib.fib_Size64; +# elif defined(OF_AMIGAOS4) buffer->st_size = ed->FileSize; - buffer->st_mode = (EXD_IS_DIRECTORY(ed) ? S_IFDIR : S_IFREG); # 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 */ @@ -317,131 +313,140 @@ # else date = &fib.fib_Date; # endif timeInterval += date->ds_Days * 86400.0; timeInterval += date->ds_Minute * 60.0; - timeInterval += date->ds_Tick / (of_time_interval_t)TICKS_PER_SECOND; + 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) - return stat64([path cStringWithEncoding: [OFLocale encoding]], buffer); + if (stat64([path cStringWithEncoding: [OFLocale encoding]], + buffer) != 0) + return errno; + + return 0; #else - return stat([path cStringWithEncoding: [OFLocale encoding]], buffer); + if (stat([path cStringWithEncoding: [OFLocale encoding]], buffer) != 0) + return errno; + + return 0; #endif } static int -of_lstat(OFString *path, of_stat_t *buffer) +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 - return lstat64([path cStringWithEncoding: [OFLocale encoding]], buffer); + if (lstat64([path cStringWithEncoding: [OFLocale encoding]], + buffer) != 0) + return errno; # else - return lstat([path cStringWithEncoding: [OFLocale encoding]], buffer); + if (lstat([path cStringWithEncoding: [OFLocale encoding]], buffer) != 0) + return errno; # endif + + return 0; #else - return of_stat(path, buffer); + return statWrapper(path, buffer); #endif } static void -setTypeAttribute(of_mutable_file_attributes_t attributes, of_stat_t *s) +setTypeAttribute(OFMutableFileAttributes attributes, Stat *s) { if (S_ISREG(s->st_mode)) - [attributes setObject: of_file_type_regular - forKey: of_file_attribute_key_type]; + [attributes setObject: OFFileTypeRegular forKey: OFFileType]; else if (S_ISDIR(s->st_mode)) - [attributes setObject: of_file_type_directory - forKey: of_file_attribute_key_type]; + [attributes setObject: OFFileTypeDirectory forKey: OFFileType]; #ifdef S_ISLNK else if (S_ISLNK(s->st_mode)) - [attributes setObject: of_file_type_symbolic_link - forKey: of_file_attribute_key_type]; + [attributes setObject: OFFileTypeSymbolicLink + forKey: OFFileType]; #endif #ifdef S_ISFIFO else if (S_ISFIFO(s->st_mode)) - [attributes setObject: of_file_type_fifo - forKey: of_file_attribute_key_type]; + [attributes setObject: OFFileTypeFIFO forKey: OFFileType]; #endif #ifdef S_ISCHR else if (S_ISCHR(s->st_mode)) - [attributes setObject: of_file_type_character_special - forKey: of_file_attribute_key_type]; + [attributes setObject: OFFileTypeCharacterSpecial + forKey: OFFileType]; #endif #ifdef S_ISBLK else if (S_ISBLK(s->st_mode)) - [attributes setObject: of_file_type_block_special - forKey: of_file_attribute_key_type]; + [attributes setObject: OFFileTypeBlockSpecial + forKey: OFFileType]; #endif #ifdef S_ISSOCK else if (S_ISSOCK(s->st_mode)) - [attributes setObject: of_file_type_socket - forKey: of_file_attribute_key_type]; + [attributes setObject: OFFileTypeSocket forKey: OFFileType]; #endif + else + [attributes setObject: OFFileTypeUnknown forKey: OFFileType]; } static void -setDateAttributes(of_mutable_file_attributes_t attributes, of_stat_t *s) +setDateAttributes(OFMutableFileAttributes attributes, Stat *s) { /* FIXME: We could be more precise on some OSes */ [attributes setObject: [OFDate dateWithTimeIntervalSince1970: s->st_atime] - forKey: of_file_attribute_key_last_access_date]; + forKey: OFFileLastAccessDate]; [attributes setObject: [OFDate dateWithTimeIntervalSince1970: s->st_mtime] - forKey: of_file_attribute_key_modification_date]; + forKey: OFFileModificationDate]; [attributes setObject: [OFDate dateWithTimeIntervalSince1970: s->st_ctime] - forKey: of_file_attribute_key_status_change_date]; + forKey: OFFileStatusChangeDate]; #ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME [attributes setObject: [OFDate dateWithTimeIntervalSince1970: s->st_birthtime] - forKey: of_file_attribute_key_creation_date]; + forKey: OFFileCreationDate]; #endif } static void -setOwnerAndGroupAttributes(of_mutable_file_attributes_t attributes, - of_stat_t *s) +setOwnerAndGroupAttributes(OFMutableFileAttributes attributes, Stat *s) { #ifdef OF_FILE_MANAGER_SUPPORTS_OWNER [attributes setObject: [NSNumber numberWithUnsignedLong: s->st_uid] - forKey: of_file_attribute_key_posix_uid]; + forKey: OFFileOwnerAccountID]; [attributes setObject: [NSNumber numberWithUnsignedLong: s->st_gid] - forKey: of_file_attribute_key_posix_gid]; + forKey: OFFileGroupOwnerAccountID]; # ifdef OF_HAVE_THREADS [passwdMutex lock]; @try { # endif - of_string_encoding_t encoding = [OFLocale encoding]; + 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: of_file_attribute_key_owner]; + forKey: OFFileOwnerAccountName]; } if (group_ != NULL) { OFString *group = [OFString stringWithCString: group_->gr_name encoding: encoding]; [attributes setObject: group - forKey: of_file_attribute_key_group]; + forKey: OFFileGroupOwnerAccountName]; } # ifdef OF_HAVE_THREADS } @finally { [passwdMutex unlock]; } @@ -449,20 +454,19 @@ #endif } #ifdef OF_FILE_MANAGER_SUPPORTS_SYMLINKS static void -setSymbolicLinkDestinationAttribute(of_mutable_file_attributes_t attributes, +setSymbolicLinkDestinationAttribute(OFMutableFileAttributes attributes, OFURL *URL) { OFString *path = URL.fileSystemRepresentation; # ifndef OF_WINDOWS - of_string_encoding_t encoding = [OFLocale encoding]; + OFStringEncoding encoding = [OFLocale encoding]; char destinationC[PATH_MAX]; ssize_t length; OFString *destination; - of_file_attribute_key_t key; length = readlink([path cStringWithEncoding: encoding], destinationC, PATH_MAX); if (length < 0) @@ -472,47 +476,45 @@ destination = [OFString stringWithCString: destinationC encoding: encoding length: length]; - key = of_file_attribute_key_symbolic_link_destination; [attributes setObject: destination - forKey: key]; + forKey: OFFileSymbolicLinkDestination]; # else HANDLE handle; OFString *destination; - if (func_CreateSymbolicLinkW == NULL) + 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 [OFRetrieveItemAttributesFailedException exceptionWithURL: URL - errNo: 0]; + errNo: retrieveError()]; @try { union { char bytes[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; REPARSE_DATA_BUFFER data; } buffer; DWORD size; wchar_t *tmp; - of_file_attribute_key_t key; if (!DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, NULL, 0, buffer.bytes, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &size, NULL)) @throw [OFRetrieveItemAttributesFailedException exceptionWithURL: URL - errNo: 0]; + errNo: retrieveError()]; if (buffer.data.ReparseTag != IO_REPARSE_TAG_SYMLINK) @throw [OFRetrieveItemAttributesFailedException exceptionWithURL: URL - errNo: 0]; + errNo: retrieveError()]; # define slrb buffer.data.SymbolicLinkReparseBuffer tmp = slrb.PathBuffer + (slrb.SubstituteNameOffset / sizeof(wchar_t)); @@ -519,15 +521,14 @@ destination = [OFString stringWithUTF16String: tmp length: slrb.SubstituteNameLength / sizeof(wchar_t)]; - [attributes setObject: of_file_type_symbolic_link - forKey: of_file_attribute_key_type]; - key = of_file_attribute_key_symbolic_link_destination; + [attributes setObject: OFFileTypeSymbolicLink + forKey: OFFileType]; [attributes setObject: destination - forKey: key]; + forKey: OFFileSymbolicLinkDestination]; # undef slrb } @finally { CloseHandle(handle); } # endif @@ -544,25 +545,27 @@ if (self != [OFFileURLHandler 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) - func__wutime64 = (int (*)(const wchar_t *, + _wutime64FuncPtr = (int (*)(const wchar_t *, struct __utimbuf64 *))GetProcAddress(module, "_wutime64"); if ((module = LoadLibrary("kernel32.dll")) != NULL) { - func_CreateSymbolicLinkW = + createSymbolicLinkWFuncPtr = (WINAPI BOOLEAN (*)(LPCWSTR, LPCWSTR, DWORD)) GetProcAddress(module, "CreateSymbolicLinkW"); - func_CreateHardLinkW = + createHardLinkWFuncPtr = (WINAPI BOOLEAN (*)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES)) GetProcAddress(module, "CreateHardLinkW"); } #endif @@ -574,20 +577,19 @@ [OFFile class]; } + (bool)of_directoryExistsAtPath: (OFString *)path { - of_stat_t s; + Stat s; - if (of_stat(path, &s) == -1) + if (statWrapper(path, &s) != 0) return false; return S_ISDIR(s.st_mode); } -- (OFStream *)openItemAtURL: (OFURL *)URL - mode: (OFString *)mode +- (OFStream *)openItemAtURL: (OFURL *)URL mode: (OFString *)mode { void *pool = objc_autoreleasePoolPush(); OFFile *file = [[OFFile alloc] initWithPath: URL.fileSystemRepresentation mode: mode]; @@ -595,40 +597,41 @@ objc_autoreleasePoolPop(pool); return [file autorelease]; } -- (of_file_attributes_t)attributesOfItemAtURL: (OFURL *)URL +- (OFFileAttributes)attributesOfItemAtURL: (OFURL *)URL { - of_mutable_file_attributes_t ret = [OFMutableDictionary dictionary]; + OFMutableFileAttributes ret = [OFMutableDictionary dictionary]; void *pool = objc_autoreleasePoolPush(); OFString *path; - of_stat_t s; + int error; + Stat s; if (URL == nil) @throw [OFInvalidArgumentException exception]; if (![[URL scheme] isEqual: _scheme]) @throw [OFInvalidArgumentException exception]; path = URL.fileSystemRepresentation; - if (of_lstat(path, &s) == -1) + if ((error = lstatWrapper(path, &s)) != 0) @throw [OFRetrieveItemAttributesFailedException exceptionWithURL: URL - errNo: errno]; + errNo: error]; if (s.st_size < 0) @throw [OFOutOfRangeException exception]; [ret setObject: [NSNumber numberWithUnsignedLongLong: s.st_size] - forKey: of_file_attribute_key_size]; + forKey: OFFileSize]; setTypeAttribute(ret, &s); [ret setObject: [NSNumber numberWithUnsignedLong: s.st_mode] - forKey: of_file_attribute_key_posix_permissions]; + forKey: OFFilePOSIXPermissions]; setOwnerAndGroupAttributes(ret, &s); setDateAttributes(ret, &s); #ifdef OF_FILE_MANAGER_SUPPORTS_SYMLINKS @@ -642,32 +645,31 @@ } - (void)of_setLastAccessDate: (OFDate *)lastAccessDate andModificationDate: (OFDate *)modificationDate ofItemAtURL: (OFURL *)URL - attributes: (of_file_attributes_t)attributes OF_DIRECT + attributes: (OFFileAttributes)attributes OF_DIRECT { OFString *path = URL.fileSystemRepresentation; - of_file_attribute_key_t attributeKey = (modificationDate != nil - ? of_file_attribute_key_modification_date - : of_file_attribute_key_last_access_date); + OFFileAttributeKey attributeKey = (modificationDate != nil + ? OFFileModificationDate : OFFileLastAccessDate); if (lastAccessDate == nil) lastAccessDate = modificationDate; if (modificationDate == nil) modificationDate = lastAccessDate; #if defined(OF_WINDOWS) - if (func__wutime64 != NULL) { + if (_wutime64FuncPtr != NULL) { struct __utimbuf64 times = { .actime = (__time64_t)lastAccessDate.timeIntervalSince1970, .modtime = (__time64_t)modificationDate.timeIntervalSince1970 }; - if (func__wutime64([path UTF16String], ×) != 0) + if (_wutime64FuncPtr([path UTF16String], ×) != 0) @throw [OFSetItemAttributesFailedException exceptionWithURL: URL attributes: attributes failedAttribute: attributeKey errNo: errno]; @@ -693,11 +695,11 @@ failedAttribute: attributeKey errNo: errno]; } #elif defined(OF_AMIGAOS) /* AmigaOS does not support access time. */ - of_time_interval_t modificationTime = + OFTimeInterval modificationTime = modificationDate.timeIntervalSince1970; struct Locale *locale; struct DateStamp date; modificationTime -= 252460800; /* 1978-01-01 */ @@ -716,35 +718,36 @@ 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) { - setErrno(); - + &date) != 0) +# endif @throw [OFSetItemAttributesFailedException exceptionWithURL: URL attributes: attributes failedAttribute: attributeKey - errNo: errno]; - } + errNo: retrieveError()]; #else - of_time_interval_t lastAccessTime = - lastAccessDate.timeIntervalSince1970; - of_time_interval_t modificationTime = + 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) * 1000) + (int)((lastAccessTime - times[0].tv_sec) * 1000000) }, { .tv_sec = (time_t)modificationTime, - .tv_usec = - (int)((modificationTime - times[1].tv_sec) * 1000) + .tv_usec = (int)((modificationTime - times[1].tv_sec) * + 1000000) }, }; if (utimes([path cStringWithEncoding: [OFLocale encoding]], times) != 0) @throw [OFSetItemAttributesFailedException @@ -755,11 +758,11 @@ #endif } - (void)of_setPOSIXPermissions: (OFNumber *)permissions ofItemAtURL: (OFURL *)URL - attributes: (of_file_attributes_t)attributes OF_DIRECT + attributes: (OFFileAttributes)attributes OF_DIRECT { #ifdef OF_FILE_MANAGER_SUPPORTS_PERMISSIONS mode_t mode = (mode_t)permissions.unsignedLongValue; OFString *path = URL.fileSystemRepresentation; int status; @@ -774,28 +777,28 @@ if (status != 0) @throw [OFSetItemAttributesFailedException exceptionWithURL: URL attributes: attributes - failedAttribute: of_file_attribute_key_posix_permissions + failedAttribute: OFFilePOSIXPermissions errNo: errno]; #else OF_UNRECOGNIZED_SELECTOR #endif } -- (void)of_setOwner: (OFString *)owner - andGroup: (OFString *)group - ofItemAtURL: (OFURL *)URL - attributeKey: (of_file_attribute_key_t)attributeKey - attributes: (of_file_attributes_t)attributes OF_DIRECT +- (void)of_setOwnerAccountName: (OFString *)owner + andGroupOwnerAccountName: (OFString *)group + ofItemAtURL: (OFURL *)URL + attributeKey: (OFFileAttributeKey)attributeKey + attributes: (OFFileAttributes)attributes OF_DIRECT { #ifdef OF_FILE_MANAGER_SUPPORTS_OWNER OFString *path = URL.fileSystemRepresentation; uid_t uid = -1; gid_t gid = -1; - of_string_encoding_t encoding; + OFStringEncoding encoding; if (owner == nil && group == nil) @throw [OFInvalidArgumentException exception]; encoding = [OFLocale encoding]; @@ -846,17 +849,16 @@ #else OF_UNRECOGNIZED_SELECTOR #endif } -- (void)setAttributes: (of_file_attributes_t)attributes - ofItemAtURL: (OFURL *)URL +- (void)setAttributes: (OFFileAttributes)attributes ofItemAtURL: (OFURL *)URL { void *pool = objc_autoreleasePoolPush(); - OFEnumerator OF_GENERIC(of_file_attribute_key_t) *keyEnumerator; + OFEnumerator OF_GENERIC(OFFileAttributeKey) *keyEnumerator; OFEnumerator *objectEnumerator; - of_file_attribute_key_t key; + OFFileAttributeKey key; id object; OFDate *lastAccessDate, *modificationDate; if (URL == nil) @throw [OFInvalidArgumentException exception]; @@ -867,39 +869,37 @@ keyEnumerator = [attributes keyEnumerator]; objectEnumerator = [attributes objectEnumerator]; while ((key = [keyEnumerator nextObject]) != nil && (object = [objectEnumerator nextObject]) != nil) { - if ([key isEqual: of_file_attribute_key_modification_date] || - [key isEqual: of_file_attribute_key_last_access_date]) + if ([key isEqual: OFFileModificationDate] || + [key isEqual: OFFileLastAccessDate]) continue; - else if ([key isEqual: of_file_attribute_key_posix_permissions]) + else if ([key isEqual: OFFilePOSIXPermissions]) [self of_setPOSIXPermissions: object ofItemAtURL: URL attributes: attributes]; - else if ([key isEqual: of_file_attribute_key_owner]) - [self of_setOwner: object - andGroup: nil - ofItemAtURL: URL - attributeKey: key - attributes: attributes]; - else if ([key isEqual: of_file_attribute_key_group]) - [self of_setOwner: nil - andGroup: object - ofItemAtURL: URL - attributeKey: key - attributes: attributes]; + else if ([key isEqual: OFFileOwnerAccountName]) + [self of_setOwnerAccountName: object + andGroupOwnerAccountName: nil + ofItemAtURL: URL + attributeKey: key + attributes: attributes]; + else if ([key isEqual: OFFileGroupOwnerAccountName]) + [self of_setOwnerAccountName: nil + andGroupOwnerAccountName: object + ofItemAtURL: URL + attributeKey: key + attributes: attributes]; else @throw [OFNotImplementedException exceptionWithSelector: _cmd object: self]; } - lastAccessDate = [attributes - objectForKey: of_file_attribute_key_last_access_date]; - modificationDate = [attributes - objectForKey: of_file_attribute_key_modification_date]; + lastAccessDate = [attributes objectForKey: OFFileLastAccessDate]; + modificationDate = [attributes objectForKey: OFFileModificationDate]; if (lastAccessDate != nil || modificationDate != nil) [self of_setLastAccessDate: lastAccessDate andModificationDate: modificationDate ofItemAtURL: URL @@ -909,20 +909,20 @@ } - (bool)fileExistsAtURL: (OFURL *)URL { void *pool = objc_autoreleasePoolPush(); - of_stat_t s; + Stat s; bool ret; if (URL == nil) @throw [OFInvalidArgumentException exception]; if (![URL.scheme isEqual: _scheme]) @throw [OFInvalidArgumentException exception]; - if (of_stat(URL.fileSystemRepresentation, &s) == -1) { + if (statWrapper(URL.fileSystemRepresentation, &s) != 0) { objc_autoreleasePoolPop(pool); return false; } ret = S_ISREG(s.st_mode); @@ -933,20 +933,20 @@ } - (bool)directoryExistsAtURL: (OFURL *)URL { void *pool = objc_autoreleasePoolPush(); - of_stat_t s; + Stat s; bool ret; if (URL == nil) @throw [OFInvalidArgumentException exception]; if (![URL.scheme isEqual: _scheme]) @throw [OFInvalidArgumentException exception]; - if (of_stat(URL.fileSystemRepresentation, &s) == -1) { + if (statWrapper(URL.fileSystemRepresentation, &s) != 0) { objc_autoreleasePoolPop(pool); return false; } ret = S_ISDIR(s.st_mode); @@ -984,17 +984,14 @@ errNo: errno]; #elif defined(OF_AMIGAOS) BPTR lock; if ((lock = CreateDir( - [path cStringWithEncoding: [OFLocale encoding]])) == 0) { - setErrno(); - + [path cStringWithEncoding: [OFLocale encoding]])) == 0) @throw [OFCreateDirectoryFailedException exceptionWithURL: URL - errNo: errno]; - } + errNo: retrieveError()]; UnLock(lock); #else if (mkdir([path cStringWithEncoding: [OFLocale encoding]], 0777) != 0) @throw [OFCreateDirectoryFailedException @@ -1003,13 +1000,13 @@ #endif objc_autoreleasePoolPop(pool); } -- (OFArray OF_GENERIC(OFString *) *)contentsOfDirectoryAtURL: (OFURL *)URL +- (OFArray OF_GENERIC(OFURL *) *)contentsOfDirectoryAtURL: (OFURL *)URL { - OFMutableArray *files = [OFMutableArray array]; + OFMutableArray *URLs = [OFMutableArray array]; void *pool = objc_autoreleasePoolPush(); OFString *path; if (URL == nil) @throw [OFInvalidArgumentException exception]; @@ -1026,21 +1023,15 @@ if ([OFSystemInfo isWindowsNT]) { WIN32_FIND_DATAW fd; if ((handle = FindFirstFileW(path.UTF16String, - &fd)) == INVALID_HANDLE_VALUE) { - int errNo = 0; - - if (GetLastError() == ERROR_FILE_NOT_FOUND) - errNo = ENOENT; - + &fd)) == INVALID_HANDLE_VALUE) @throw [OFOpenItemFailedException exceptionWithURL: URL mode: nil - errNo: errNo]; - } + errNo: retrieveError()]; @try { do { OFString *file; @@ -1049,41 +1040,36 @@ continue; file = [[OFString alloc] initWithUTF16String: fd.cFileName]; @try { - [files addObject: file]; + [URLs addObject: [URL + URLByAppendingPathComponent: file]]; } @finally { [file release]; } } while (FindNextFileW(handle, &fd)); if (GetLastError() != ERROR_NO_MORE_FILES) @throw [OFReadFailedException exceptionWithObject: self requestedLength: 0 - errNo: EIO]; + errNo: retrieveError()]; } @finally { FindClose(handle); } } else { - of_string_encoding_t encoding = [OFLocale encoding]; + OFStringEncoding encoding = [OFLocale encoding]; WIN32_FIND_DATA fd; if ((handle = FindFirstFileA( [path cStringWithEncoding: encoding], &fd)) == - INVALID_HANDLE_VALUE) { - int errNo = 0; - - if (GetLastError() == ERROR_FILE_NOT_FOUND) - errNo = ENOENT; - + INVALID_HANDLE_VALUE) @throw [OFOpenItemFailedException exceptionWithURL: URL mode: nil - errNo: errNo]; - } + errNo: retrieveError()]; @try { do { OFString *file; @@ -1093,37 +1079,36 @@ file = [[OFString alloc] initWithCString: fd.cFileName encoding: encoding]; @try { - [files addObject: file]; + [URLs addObject: [URL + URLByAppendingPathComponent: file]]; } @finally { [file release]; } } while (FindNextFileA(handle, &fd)); if (GetLastError() != ERROR_NO_MORE_FILES) @throw [OFReadFailedException exceptionWithObject: self requestedLength: 0 - errNo: EIO]; + errNo: retrieveError()]; } @finally { FindClose(handle); } } #elif defined(OF_AMIGAOS) - of_string_encoding_t encoding = [OFLocale encoding]; + OFStringEncoding encoding = [OFLocale encoding]; BPTR lock; if ((lock = Lock([path cStringWithEncoding: encoding], - SHARED_LOCK)) == 0) { - setErrno(); - - @throw [OFOpenItemFailedException exceptionWithURL: URL - mode: nil - errNo: errno]; - } + SHARED_LOCK)) == 0) + @throw [OFOpenItemFailedException + exceptionWithURL: URL + mode: nil + errNo: retrieveError()]; @try { # ifdef OF_AMIGAOS4 struct ExamineData *ed; APTR context; @@ -1132,20 +1117,21 @@ EX_DoCurrentDir, TRUE, EX_DataFields, EXF_NAME, TAG_END)) == NULL) @throw [OFOpenItemFailedException exceptionWithURL: URL mode: nil - errNo: 0]; + errNo: retrieveError()]; @try { while ((ed = ExamineDir(context)) != NULL) { OFString *file = [[OFString alloc] initWithCString: ed->Name encoding: encoding]; @try { - [files addObject: file]; + [URLs addObject: [URL + URLByAppendingPathComponent: file]]; } @finally { [file release]; } } } @finally { @@ -1156,19 +1142,19 @@ if (!Examine(lock, &fib)) @throw [OFOpenItemFailedException exceptionWithURL: URL mode: nil - errNo: 0]; + errNo: retrieveError()]; while (ExNext(lock, &fib)) { OFString *file = [[OFString alloc] initWithCString: fib.fib_FileName encoding: encoding]; - @try { - [files addObject: file]; + [URLs addObject: + [URL URLByAppendingPathComponent: file]]; } @finally { [file release]; } } # endif @@ -1175,18 +1161,17 @@ if (IoErr() != ERROR_NO_MORE_ENTRIES) @throw [OFReadFailedException exceptionWithObject: self requestedLength: 0 - errNo: EIO]; + errNo: retrieveError()]; } @finally { UnLock(lock); } #else - of_string_encoding_t encoding = [OFLocale encoding]; + OFStringEncoding encoding = [OFLocale encoding]; DIR *dir; - if ((dir = opendir([path cStringWithEncoding: encoding])) == NULL) @throw [OFOpenItemFailedException exceptionWithURL: URL mode: nil errNo: errno]; @@ -1234,11 +1219,12 @@ continue; file = [[OFString alloc] initWithCString: dirent->d_name encoding: encoding]; @try { - [files addObject: file]; + [URLs addObject: + [URL URLByAppendingPathComponent: file]]; } @finally { [file release]; } } } @finally { @@ -1247,37 +1233,38 @@ [readdirMutex unlock]; # endif } #endif - [files makeImmutable]; + [URLs makeImmutable]; objc_autoreleasePoolPop(pool); - return files; + return URLs; } - (void)removeItemAtURL: (OFURL *)URL { void *pool = objc_autoreleasePoolPush(); OFString *path; - of_stat_t s; + int error; + Stat s; if (URL == nil) @throw [OFInvalidArgumentException exception]; if (![URL.scheme isEqual: _scheme]) @throw [OFInvalidArgumentException exception]; path = URL.fileSystemRepresentation; - if (of_lstat(path, &s) != 0) + if ((error = lstatWrapper(path, &s)) != 0) @throw [OFRemoveItemFailedException exceptionWithURL: URL - errNo: errno]; + errNo: error]; if (S_ISDIR(s.st_mode)) { - OFArray *contents; + OFArray OF_GENERIC(OFURL *) *contents; @try { contents = [self contentsOfDirectoryAtURL: URL]; } @catch (id e) { /* @@ -1293,15 +1280,14 @@ errNo: [e errNo]]; @throw e; } - for (OFString *item in contents) { + for (OFURL *item in contents) { void *pool2 = objc_autoreleasePoolPush(); - [self removeItemAtURL: [OFURL fileURLWithPath: - [path stringByAppendingPathComponent: item]]]; + [self removeItemAtURL: item]; objc_autoreleasePoolPop(pool2); } #ifndef OF_AMIGAOS @@ -1336,24 +1322,21 @@ errNo: errno]; #endif } #ifdef OF_AMIGAOS - if (!DeleteFile([path cStringWithEncoding: [OFLocale encoding]])) { - setErrno(); - - @throw [OFRemoveItemFailedException exceptionWithURL: URL - errNo: errno]; - } + if (!DeleteFile([path cStringWithEncoding: [OFLocale encoding]])) + @throw [OFRemoveItemFailedException + exceptionWithURL: URL + errNo: retrieveError()]; #endif objc_autoreleasePoolPop(pool); } #ifdef OF_FILE_MANAGER_SUPPORTS_LINKS -- (void)linkItemAtURL: (OFURL *)source - toURL: (OFURL *)destination +- (void)linkItemAtURL: (OFURL *)source toURL: (OFURL *)destination { void *pool = objc_autoreleasePoolPush(); OFString *sourcePath, *destinationPath; if (source == nil || destination == nil) @@ -1365,29 +1348,29 @@ sourcePath = source.fileSystemRepresentation; destinationPath = destination.fileSystemRepresentation; # ifndef OF_WINDOWS - of_string_encoding_t encoding = [OFLocale encoding]; + OFStringEncoding encoding = [OFLocale encoding]; if (link([sourcePath cStringWithEncoding: encoding], [destinationPath cStringWithEncoding: encoding]) != 0) @throw [OFLinkFailedException exceptionWithSourceURL: source destinationURL: destination errNo: errno]; # else - if (func_CreateHardLinkW == NULL) + if (createHardLinkWFuncPtr == NULL) @throw [OFNotImplementedException exceptionWithSelector: _cmd object: self]; - if (!func_CreateHardLinkW(destinationPath.UTF16String, + if (!createHardLinkWFuncPtr(destinationPath.UTF16String, sourcePath.UTF16String, NULL)) @throw [OFLinkFailedException exceptionWithSourceURL: source destinationURL: destination - errNo: 0]; + errNo: retrieveError()]; # endif objc_autoreleasePoolPop(pool); } #endif @@ -1406,36 +1389,36 @@ @throw [OFInvalidArgumentException exception]; path = URL.fileSystemRepresentation; # ifndef OF_WINDOWS - of_string_encoding_t encoding = [OFLocale encoding]; + OFStringEncoding encoding = [OFLocale encoding]; if (symlink([target cStringWithEncoding: encoding], [path cStringWithEncoding: encoding]) != 0) @throw [OFCreateSymbolicLinkFailedException exceptionWithURL: URL target: target errNo: errno]; # else - if (func_CreateSymbolicLinkW == NULL) + if (createSymbolicLinkWFuncPtr == NULL) @throw [OFNotImplementedException exceptionWithSelector: _cmd object: self]; - if (!func_CreateSymbolicLinkW(path.UTF16String, target.UTF16String, 0)) + if (!createSymbolicLinkWFuncPtr(path.UTF16String, target.UTF16String, + 0)) @throw [OFCreateSymbolicLinkFailedException exceptionWithURL: URL target: target - errNo: 0]; + errNo: retrieveError()]; # endif objc_autoreleasePoolPop(pool); } #endif -- (bool)moveItemAtURL: (OFURL *)source - toURL: (OFURL *)destination +- (bool)moveItemAtURL: (OFURL *)source toURL: (OFURL *)destination { void *pool; if (![source.scheme isEqual: _scheme] || ![destination.scheme isEqual: _scheme]) @@ -1448,33 +1431,30 @@ errNo: EEXIST]; pool = objc_autoreleasePoolPush(); #ifdef OF_AMIGAOS - of_string_encoding_t encoding = [OFLocale encoding]; + OFStringEncoding encoding = [OFLocale encoding]; if (!Rename([source.fileSystemRepresentation cStringWithEncoding: encoding], [destination.fileSystemRepresentation - cStringWithEncoding: encoding])) { - setErrno(); - + cStringWithEncoding: encoding])) @throw [OFMoveItemFailedException exceptionWithSourceURL: source destinationURL: destination - errNo: errno]; - } + errNo: retrieveError()]; #else int status; # ifdef OF_WINDOWS if ([OFSystemInfo isWindowsNT]) status = _wrename(source.fileSystemRepresentation.UTF16String, destination.fileSystemRepresentation.UTF16String); else { # endif - of_string_encoding_t encoding = [OFLocale encoding]; + OFStringEncoding encoding = [OFLocale encoding]; status = rename([source.fileSystemRepresentation cStringWithEncoding: encoding], [destination.fileSystemRepresentation cStringWithEncoding: encoding]); Index: src/OFGZIPStream.h ================================================================== --- src/OFGZIPStream.h +++ src/OFGZIPStream.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -20,10 +18,31 @@ @class OFInflateStream; OF_ASSUME_NONNULL_BEGIN +/** + * @brief The operating system on which compressed the data. + */ +typedef enum { + OFGZIPStreamOperatingSystemFAT = 0, + OFGZIPStreamOperatingSystemAmiga = 1, + OFGZIPStreamOperatingSystemVMS = 2, + OFGZIPStreamOperatingSystemUNIX = 3, + OFGZIPStreamOperatingSystemVM_CMS = 4, + OFGZIPStreamOperatingSystemAtariTOS = 5, + OFGZIPStreamOperatingSystemHPFS = 6, + OFGZIPStreamOperatingSystemMacintosh = 7, + OFGZIPStreamOperatingSystemZSystem = 8, + OFGZIPStreamOperatingSystemCPM = 9, + OFGZIPStreamOperatingSystemTOPS20 = 10, + OFGZIPStreamOperatingSystemNTFS = 11, + OFGZIPStreamOperatingSystemQDO = 12, + OFGZIPStreamOperatingSystemAcornRISCOS = 13, + OFGZIPStreamOperatingSystemUnknown = 255 +} OFGZIPStreamOperatingSystem; + /** * @class OFGZIPStream OFGZIPStream.h ObjFW/OFGZIPStream.h * * @brief A class that handles GZIP compression and decompression transparently * for an underlying stream. @@ -31,52 +50,36 @@ OF_SUBCLASSING_RESTRICTED @interface OFGZIPStream: OFStream { OFStream *_stream; OFInflateStream *_Nullable _inflateStream; - enum of_gzip_stream_state { - OF_GZIP_STREAM_ID1, - OF_GZIP_STREAM_ID2, - OF_GZIP_STREAM_COMPRESSION_METHOD, - OF_GZIP_STREAM_FLAGS, - OF_GZIP_STREAM_MODIFICATION_TIME, - OF_GZIP_STREAM_EXTRA_FLAGS, - OF_GZIP_STREAM_OPERATING_SYSTEM, - OF_GZIP_STREAM_EXTRA_LENGTH, - OF_GZIP_STREAM_EXTRA, - OF_GZIP_STREAM_NAME, - OF_GZIP_STREAM_COMMENT, - OF_GZIP_STREAM_HEADER_CRC16, - OF_GZIP_STREAM_DATA, - OF_GZIP_STREAM_CRC32, - OF_GZIP_STREAM_UNCOMPRESSED_SIZE + enum { + OFGZIPStreamStateID1, + OFGZIPStreamStateID2, + OFGZIPStreamStateCompressionMethod, + OFGZIPStreamStateFlags, + OFGZIPStreamStateModificationDate, + OFGZIPStreamStateExtraFlags, + OFGZIPStreamStateOperatingSystem, + OFGZIPStreamStateExtraLength, + OFGZIPStreamStateExtra, + OFGZIPStreamStateName, + OFGZIPStreamStateComment, + OFGZIPStreamStateHeaderCRC16, + OFGZIPStreamStateData, + OFGZIPStreamStateCRC32, + OFGZIPStreamStateUncompressedSize } _state; - enum of_gzip_stream_flags { - OF_GZIP_STREAM_FLAG_TEXT = 0x01, - OF_GZIP_STREAM_FLAG_HEADER_CRC16 = 0x02, - OF_GZIP_STREAM_FLAG_EXTRA = 0x04, - OF_GZIP_STREAM_FLAG_NAME = 0x08, - OF_GZIP_STREAM_FLAG_COMMENT = 0x10 + enum { + OFGZIPStreamFlagText = 0x01, + OFGZIPStreamFlagHeaderCRC16 = 0x02, + OFGZIPStreamFlagExtra = 0x04, + OFGZIPStreamFlagName = 0x08, + OFGZIPStreamFlagComment = 0x10 } _flags; uint8_t _extraFlags; - enum of_gzip_stream_operating_system { - OF_GZIP_STREAM_OPERATING_SYSTEM_FAT = 0, - OF_GZIP_STREAM_OPERATING_SYSTEM_AMIGA = 1, - OF_GZIP_STREAM_OPERATING_SYSTEM_VMS = 2, - OF_GZIP_STREAM_OPERATING_SYSTEM_UNIX = 3, - OF_GZIP_STREAM_OPERATING_SYSTEM_VM_CMS = 4, - OF_GZIP_STREAM_OPERATING_SYSTEM_ATARI_TOS = 5, - OF_GZIP_STREAM_OPERATING_SYSTEM_HPFS = 6, - OF_GZIP_STREAM_OPERATING_SYSTEM_MACINTOSH = 7, - OF_GZIP_STREAM_OPERATING_SYSTEM_Z_SYSTEM = 8, - OF_GZIP_STREAM_OPERATING_SYSTEM_CP_M = 9, - OF_GZIP_STREAM_OPERATING_SYSTEM_TOPS_20 = 10, - OF_GZIP_STREAM_OPERATING_SYSTEM_NTFS = 11, - OF_GZIP_STREAM_OPERATING_SYSTEM_QDO = 12, - OF_GZIP_STREAM_OPERATING_SYSTEM_ACORN_RISC_OS = 13, - OF_GZIP_STREAM_OPERATING_SYSTEM_UNKNOWN = 255 - } _operatingSystemMadeOn; + OFGZIPStreamOperatingSystem _operatingSystemMadeOn; size_t _bytesRead; uint8_t _buffer[4]; OFDate *_Nullable _modificationDate; uint16_t _extraLength; uint32_t _CRC32, _uncompressedSize; @@ -87,11 +90,11 @@ * * This property is only guaranteed to be available once @ref atEndOfStream is * true. */ @property (readonly, nonatomic) - enum of_gzip_stream_operating_system operatingSystemMadeOn; + OFGZIPStreamOperatingSystem operatingSystemMadeOn; /** * @brief The modification date of the original file. * * This property is only guaranteed to be available once @ref atEndOfStream is @@ -105,12 +108,11 @@ * @param stream The underlying stream for the OFGZIPStream * @param mode The mode for the OFGZIPStream. Valid modes are "r" for reading * and "w" for writing. * @return A new, autoreleased OFGZIPStream */ -+ (instancetype)streamWithStream: (OFStream *)stream - mode: (OFString *)mode; ++ (instancetype)streamWithStream: (OFStream *)stream mode: (OFString *)mode; - (instancetype)init OF_UNAVAILABLE; /** * @brief Initializes an already allocated OFGZIPStream with the specified Index: src/OFGZIPStream.m ================================================================== --- src/OFGZIPStream.m +++ src/OFGZIPStream.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -16,14 +14,13 @@ */ #include "config.h" #import "OFGZIPStream.h" -#import "OFInflateStream.h" +#import "OFCRC32.h" #import "OFDate.h" - -#import "crc32.h" +#import "OFInflateStream.h" #import "OFChecksumMismatchException.h" #import "OFInvalidFormatException.h" #import "OFNotImplementedException.h" #import "OFNotOpenException.h" @@ -31,24 +28,21 @@ @implementation OFGZIPStream @synthesize operatingSystemMadeOn = _operatingSystemMadeOn; @synthesize modificationDate = _modificationDate; -+ (instancetype)streamWithStream: (OFStream *)stream - mode: (OFString *)mode ++ (instancetype)streamWithStream: (OFStream *)stream mode: (OFString *)mode { - return [[[self alloc] initWithStream: stream - mode: mode] autorelease]; + return [[[self alloc] initWithStream: stream mode: mode] autorelease]; } - (instancetype)init { OF_INVALID_INIT_METHOD } -- (instancetype)initWithStream: (OFStream *)stream - mode: (OFString *)mode +- (instancetype)initWithStream: (OFStream *)stream mode: (OFString *)mode { self = [super init]; @try { if (![mode isEqual: @"r"]) @@ -55,12 +49,11 @@ @throw [OFNotImplementedException exceptionWithSelector: _cmd object: nil]; _stream = [stream retain]; - _operatingSystemMadeOn = - OF_GZIP_STREAM_OPERATING_SYSTEM_UNKNOWN; + _operatingSystemMadeOn = OFGZIPStreamOperatingSystemUnknown; _CRC32 = ~0; } @catch (id e) { [self release]; @throw e; } @@ -77,52 +70,49 @@ [_modificationDate release]; [super dealloc]; } -- (size_t)lowlevelReadIntoBuffer: (void *)buffer - length: (size_t)length +- (size_t)lowlevelReadIntoBuffer: (void *)buffer length: (size_t)length { if (_stream == nil) @throw [OFNotOpenException exceptionWithObject: self]; for (;;) { uint8_t byte; uint32_t CRC32, uncompressedSize; if (_stream.atEndOfStream) { - if (_state != OF_GZIP_STREAM_ID1) + if (_state != OFGZIPStreamStateID1) @throw [OFTruncatedDataException exception]; return 0; } switch (_state) { - case OF_GZIP_STREAM_ID1: - case OF_GZIP_STREAM_ID2: - case OF_GZIP_STREAM_COMPRESSION_METHOD: - if ([_stream readIntoBuffer: &byte - length: 1] < 1) + case OFGZIPStreamStateID1: + case OFGZIPStreamStateID2: + case OFGZIPStreamStateCompressionMethod: + if ([_stream readIntoBuffer: &byte length: 1] < 1) return 0; - if ((_state == OF_GZIP_STREAM_ID1 && byte != 0x1F) || - (_state == OF_GZIP_STREAM_ID2 && byte != 0x8B) || - (_state == OF_GZIP_STREAM_COMPRESSION_METHOD && + if ((_state == OFGZIPStreamStateID1 && byte != 0x1F) || + (_state == OFGZIPStreamStateID2 && byte != 0x8B) || + (_state == OFGZIPStreamStateCompressionMethod && byte != 8)) @throw [OFInvalidFormatException exception]; _state++; break; - case OF_GZIP_STREAM_FLAGS: - if ([_stream readIntoBuffer: &byte - length: 1] < 1) + case OFGZIPStreamStateFlags: + if ([_stream readIntoBuffer: &byte length: 1] < 1) return 0; _flags = byte; _state++; break; - case OF_GZIP_STREAM_MODIFICATION_TIME: + case OFGZIPStreamStateModificationDate: _bytesRead += [_stream readIntoBuffer: _buffer + _bytesRead length: 4 - _bytesRead]; if (_bytesRead < 4) @@ -137,28 +127,26 @@ (_buffer[1] << 8) | _buffer[0]]; _bytesRead = 0; _state++; break; - case OF_GZIP_STREAM_EXTRA_FLAGS: - if ([_stream readIntoBuffer: &byte - length: 1] < 1) + case OFGZIPStreamStateExtraFlags: + if ([_stream readIntoBuffer: &byte length: 1] < 1) return 0; _extraFlags = byte; _state++; break; - case OF_GZIP_STREAM_OPERATING_SYSTEM: - if ([_stream readIntoBuffer: &byte - length: 1] < 1) + case OFGZIPStreamStateOperatingSystem: + if ([_stream readIntoBuffer: &byte length: 1] < 1) return 0; _operatingSystemMadeOn = byte; _state++; break; - case OF_GZIP_STREAM_EXTRA_LENGTH: - if (!(_flags & OF_GZIP_STREAM_FLAG_EXTRA)) { + case OFGZIPStreamStateExtraLength: + if (!(_flags & OFGZIPStreamFlagExtra)) { _state += 2; break; } _bytesRead += [_stream @@ -170,11 +158,11 @@ _extraLength = (_buffer[1] << 8) | _buffer[0]; _bytesRead = 0; _state++; break; - case OF_GZIP_STREAM_EXTRA: + case OFGZIPStreamStateExtra: { char tmp[512]; size_t toRead = _extraLength - _bytesRead; if (toRead > 512) @@ -188,12 +176,12 @@ return 0; _bytesRead = 0; _state++; break; - case OF_GZIP_STREAM_NAME: - if (!(_flags & OF_GZIP_STREAM_FLAG_NAME)) { + case OFGZIPStreamStateName: + if (!(_flags & OFGZIPStreamFlagName)) { _state++; break; } do { @@ -202,12 +190,12 @@ return 0; } while (byte != 0); _state++; break; - case OF_GZIP_STREAM_COMMENT: - if (!(_flags & OF_GZIP_STREAM_FLAG_COMMENT)) { + case OFGZIPStreamStateComment: + if (!(_flags & OFGZIPStreamFlagComment)) { _state++; break; } do { @@ -216,12 +204,12 @@ return 0; } while (byte != 0); _state++; break; - case OF_GZIP_STREAM_HEADER_CRC16: - if (!(_flags & OF_GZIP_STREAM_FLAG_HEADER_CRC16)) { + case OFGZIPStreamStateHeaderCRC16: + if (!(_flags & OFGZIPStreamFlagHeaderCRC16)) { _state++; break; } _bytesRead += [_stream @@ -238,21 +226,21 @@ */ _bytesRead = 0; _state++; break; - case OF_GZIP_STREAM_DATA: + case OFGZIPStreamStateData: if (_inflateStream == nil) _inflateStream = [[OFInflateStream alloc] initWithStream: _stream]; if (!_inflateStream.atEndOfStream) { size_t bytesRead = [_inflateStream readIntoBuffer: buffer length: length]; - _CRC32 = of_crc32(_CRC32, buffer, bytesRead); + _CRC32 = OFCRC32(_CRC32, buffer, bytesRead); _uncompressedSize += bytesRead; return bytesRead; } @@ -259,11 +247,11 @@ [_inflateStream release]; _inflateStream = nil; _state++; break; - case OF_GZIP_STREAM_CRC32: + case OFGZIPStreamStateCRC32: _bytesRead += [_stream readIntoBuffer: _buffer length: 4 - _bytesRead]; if (_bytesRead < 4) return 0; @@ -283,11 +271,11 @@ _bytesRead = 0; _CRC32 = ~0; _state++; break; - case OF_GZIP_STREAM_UNCOMPRESSED_SIZE: + case OFGZIPStreamStateUncompressedSize: _bytesRead += [_stream readIntoBuffer: _buffer length: 4 - _bytesRead]; uncompressedSize = ((uint32_t)_buffer[3] << 24) | (_buffer[2] << 16) | (_buffer[1] << 8) | _buffer[0]; @@ -302,11 +290,11 @@ expectedChecksum: expected]; } _bytesRead = 0; _uncompressedSize = 0; - _state = OF_GZIP_STREAM_ID1; + _state = OFGZIPStreamStateID1; break; } } } @@ -318,11 +306,11 @@ return _stream.atEndOfStream; } - (bool)hasDataInReadBuffer { - if (_state == OF_GZIP_STREAM_DATA) + if (_state == OFGZIPStreamStateData) return (super.hasDataInReadBuffer || _inflateStream.hasDataInReadBuffer); return (super.hasDataInReadBuffer || _stream.hasDataInReadBuffer); } Index: src/OFHMAC.h ================================================================== --- src/OFHMAC.h +++ src/OFHMAC.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -14,11 +12,11 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #import "OFObject.h" -#import "OFCryptoHash.h" +#import "OFCryptographicHash.h" OF_ASSUME_NONNULL_BEGIN /** * @class OFHMAC OFHMAC.h ObjFW/OFHMAC.h @@ -26,21 +24,21 @@ * @brief A class which provides methods to calculate an HMAC. */ OF_SUBCLASSING_RESTRICTED @interface OFHMAC: OFObject { - Class _hashClass; + Class _hashClass; bool _allowsSwappableMemory; - id _Nullable _outerHash, _innerHash; - id _Nullable _outerHashCopy, _innerHashCopy; + id _Nullable _outerHash, _innerHash; + id _Nullable _outerHashCopy, _innerHashCopy; bool _calculated; } /** * @brief The class for the cryptographic hash used by the HMAC. */ -@property (readonly, nonatomic) Class hashClass; +@property (readonly, nonatomic) Class hashClass; /** * @brief Whether data may be stored in swappable memory. */ @property (readonly, nonatomic) bool allowsSwappableMemory; @@ -64,11 +62,11 @@ * * @param hashClass The class of the hashing algorithm * @param allowsSwappableMemory Whether data may be stored in swappable memory * @return A new, autoreleased OFHMAC */ -+ (instancetype)HMACWithHashClass: (Class )hashClass ++ (instancetype)HMACWithHashClass: (Class )hashClass allowsSwappableMemory: (bool)allowsSwappableMemory; - (instancetype)init OF_UNAVAILABLE; /** @@ -77,11 +75,11 @@ * * @param hashClass The class of the hashing algorithm * @param allowsSwappableMemory Whether data may be stored in swappable memory * @return An initialized OFHMAC */ -- (instancetype)initWithHashClass: (Class )hashClass +- (instancetype)initWithHashClass: (Class )hashClass allowsSwappableMemory: (bool)allowsSwappableMemory OF_DESIGNATED_INITIALIZER; /** * @brief Sets the key for the HMAC. @@ -93,21 +91,24 @@ * it yourself before calling @ref setKey:length:! * * @param key The key for the HMAC * @param length The length of the key for the HMAC */ -- (void)setKey: (const void *)key - length: (size_t)length; +- (void)setKey: (const void *)key length: (size_t)length; /** * @brief Adds a buffer to the HMAC to be calculated. * * @param buffer The buffer which should be included into the calculation * @param length The length of the buffer */ -- (void)updateWithBuffer: (const void *)buffer - length: (size_t)length; +- (void)updateWithBuffer: (const void *)buffer length: (size_t)length; + +/** + * @brief Performs the final calculation of the HMAC. + */ +- (void)calculate; /** * @brief Resets the HMAC so that it can be calculated for a new message. * * @note This does not reset the key so that a new HMAC with the same key can Index: src/OFHMAC.m ================================================================== --- src/OFHMAC.m +++ src/OFHMAC.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -19,17 +17,18 @@ #import "OFHMAC.h" #import "OFSecureData.h" #import "OFHashAlreadyCalculatedException.h" +#import "OFHashNotCalculatedException.h" #import "OFInvalidArgumentException.h" @implementation OFHMAC @synthesize hashClass = _hashClass; @synthesize allowsSwappableMemory = _allowsSwappableMemory; -+ (instancetype)HMACWithHashClass: (Class )class ++ (instancetype)HMACWithHashClass: (Class )class allowsSwappableMemory: (bool)allowsSwappableMemory { return [[[self alloc] initWithHashClass: class allowsSwappableMemory: allowsSwappableMemory] autorelease]; @@ -38,11 +37,11 @@ - (instancetype)init { OF_INVALID_INIT_METHOD } -- (instancetype)initWithHashClass: (Class )class +- (instancetype)initWithHashClass: (Class )class allowsSwappableMemory: (bool)allowsSwappableMemory { self = [super init]; _hashClass = class; @@ -59,12 +58,11 @@ [_innerHashCopy release]; [super dealloc]; } -- (void)setKey: (const void *)key - length: (size_t)length +- (void)setKey: (const void *)key length: (size_t)length { void *pool = objc_autoreleasePoolPush(); size_t blockSize = [_hashClass blockSize]; OFSecureData *outerKeyPad = [OFSecureData dataWithCount: blockSize @@ -81,16 +79,15 @@ [_innerHashCopy release]; _outerHash = _innerHash = _outerHashCopy = _innerHashCopy = nil; @try { if (length > blockSize) { - id hash = [_hashClass - cryptoHashWithAllowsSwappableMemory: + id hash = [_hashClass + hashWithAllowsSwappableMemory: _allowsSwappableMemory]; - - [hash updateWithBuffer: key - length: length]; + [hash updateWithBuffer: key length: length]; + [hash calculate]; length = hash.digestSize; if OF_UNLIKELY (length > blockSize) length = blockSize; @@ -107,13 +104,13 @@ for (size_t i = 0; i < blockSize; i++) { outerKeyPadItems[i] ^= 0x5C; innerKeyPadItems[i] ^= 0x36; } - _outerHash = [[_hashClass cryptoHashWithAllowsSwappableMemory: + _outerHash = [[_hashClass hashWithAllowsSwappableMemory: _allowsSwappableMemory] retain]; - _innerHash = [[_hashClass cryptoHashWithAllowsSwappableMemory: + _innerHash = [[_hashClass hashWithAllowsSwappableMemory: _allowsSwappableMemory] retain]; [_outerHash updateWithBuffer: outerKeyPadItems length: blockSize]; [_innerHash updateWithBuffer: innerKeyPadItems @@ -131,35 +128,42 @@ _innerHashCopy = [_innerHash copy]; _calculated = false; } -- (void)updateWithBuffer: (const void *)buffer - length: (size_t)length +- (void)updateWithBuffer: (const void *)buffer length: (size_t)length { if (_innerHash == nil) @throw [OFInvalidArgumentException exception]; if (_calculated) @throw [OFHashAlreadyCalculatedException exceptionWithObject: self]; - [_innerHash updateWithBuffer: buffer - length: length]; + [_innerHash updateWithBuffer: buffer length: length]; +} + +- (void)calculate +{ + if (_calculated) + @throw [OFHashAlreadyCalculatedException + exceptionWithObject: self]; + + if (_outerHash == nil || _innerHash == nil) + @throw [OFInvalidArgumentException exception]; + + [_innerHash calculate]; + [_outerHash updateWithBuffer: _innerHash.digest + length: _innerHash.digestSize]; + [_outerHash calculate]; + _calculated = true; } - (const unsigned char *)digest { - if (_outerHash == nil || _innerHash == nil) - @throw [OFInvalidArgumentException exception]; - - if (_calculated) - return _outerHash.digest; - - [_outerHash updateWithBuffer: _innerHash.digest - length: _innerHash.digestSize]; - _calculated = true; + if (!_calculated) + @throw [OFHashNotCalculatedException exceptionWithObject: self]; return _outerHash.digest; } - (size_t)digestSize Index: src/OFHTTPClient.h ================================================================== --- src/OFHTTPClient.h +++ src/OFHTTPClient.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -27,10 +25,11 @@ @class OFHTTPClient; @class OFHTTPRequest; @class OFHTTPResponse; @class OFStream; @class OFTCPSocket; +@class OFTLSStream; @class OFURL; /** * @protocol OFHTTPClientDelegate OFHTTPClient.h ObjFW/OFHTTPClient.h * @@ -50,24 +49,36 @@ response: (nullable OFHTTPResponse *)response exception: (nullable id)exception; @optional /** - * @brief A callback which is called when an OFHTTPClient creates a socket. - * - * This is useful if the connection is using HTTPS and the server requires a - * client certificate. This callback can then be used to tell the TLS socket - * about the certificate. Another use case is to tell the socket about a SOCKS5 - * proxy it should use for this connection. - * - * @param client The OFHTTPClient that created a socket - * @param socket The socket created by the OFHTTPClient - * @param request The request for which the socket was created - */ -- (void)client: (OFHTTPClient *)client - didCreateSocket: (OFTCPSocket *)socket - request: (OFHTTPRequest *)request; + * @brief A callback which is called when an OFHTTPClient creates a TCP socket. + * + * This can be used to tell the socket about a SOCKS5 proxy it should use for + * this connection. + * + * @param client The OFHTTPClient that created a TCP socket + * @param TCPSocket The socket created by the OFHTTPClient + * @param request The request for which the TCP socket was created + */ +- (void)client: (OFHTTPClient *)client + didCreateTCPSocket: (OFTCPSocket *)TCPSocket + request: (OFHTTPRequest *)request; + +/** + * @brief A callback which is called when an OFHTTPClient creates a TLS stream. + * + * This can be used to tell the TLS stream about a client certificate it should + * use before performing the TLS handshake. + * + * @param client The OFHTTPClient that created a TLS stream + * @param TLSStream The TLS stream created by the OFHTTPClient + * @param request The request for which the TLS stream was created + */ +- (void)client: (OFHTTPClient *)client + didCreateTLSStream: (OFTLSStream *)TLSStream + request: (OFHTTPRequest *)request; /** * @brief A callback which is called when an OFHTTPClient wants to send the * body for a request. * @@ -136,11 +147,11 @@ #ifdef OF_HTTPCLIENT_M @public #endif OFObject *_Nullable _delegate; bool _allowsInsecureRedirects, _inProgress; - OFTCPSocket *_Nullable _socket; + OFStream *_Nullable _stream; OFURL *_Nullable _lastURL; bool _lastWasHEAD; OFHTTPResponse *_Nullable _lastResponse; } Index: src/OFHTTPClient.m ================================================================== --- src/OFHTTPClient.m +++ src/OFHTTPClient.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -30,10 +28,11 @@ #import "OFKernelEventObserver.h" #import "OFNumber.h" #import "OFRunLoop.h" #import "OFString.h" #import "OFTCPSocket.h" +#import "OFTLSStream.h" #import "OFURL.h" #import "OFAlreadyConnectedException.h" #import "OFHTTPRequestFailedException.h" #import "OFInvalidArgumentException.h" @@ -47,16 +46,15 @@ #import "OFTruncatedDataException.h" #import "OFUnsupportedProtocolException.h" #import "OFUnsupportedVersionException.h" #import "OFWriteFailedException.h" -#import "socket_helpers.h" - -#define REDIRECTS_DEFAULT 10 +static const unsigned int defaultRedirects = 10; OF_DIRECT_MEMBERS -@interface OFHTTPClientRequestHandler: OFObject +@interface OFHTTPClientRequestHandler: OFObject { @public OFHTTPClient *_client; OFHTTPRequest *_request; unsigned int _redirects; @@ -75,32 +73,32 @@ OF_DIRECT_MEMBERS @interface OFHTTPClientRequestBodyStream: OFStream { OFHTTPClientRequestHandler *_handler; - OFTCPSocket *_socket; + OFStream *_stream; bool _chunked; unsigned long long _toWrite; bool _atEndOfStream; } - (instancetype)initWithHandler: (OFHTTPClientRequestHandler *)handler - socket: (OFTCPSocket *)sock; + stream: (OFStream *)stream; @end OF_DIRECT_MEMBERS @interface OFHTTPClientResponse: OFHTTPResponse { - OFTCPSocket *_socket; + OFStream *_stream; bool _hasContentLength, _chunked, _keepAlive; bool _atEndOfStream, _setAtEndOfStream; long long _toRead; } @property (nonatomic, setter=of_setKeepAlive:) bool of_keepAlive; -- (instancetype)initWithSocket: (OFTCPSocket *)sock; +- (instancetype)initWithStream: (OFStream *)stream; @end OF_DIRECT_MEMBERS @interface OFHTTPClientSyncPerformer: OFObject { @@ -116,11 +114,11 @@ static OFString * constructRequestString(OFHTTPRequest *request) { void *pool = objc_autoreleasePoolPush(); - of_http_request_method_t method = request.method; + OFHTTPRequestMethod method = request.method; OFURL *URL = request.URL; OFString *path; OFString *user = URL.user, *password = URL.password; OFMutableString *requestString; OFMutableDictionary OF_GENERIC(OFString *, OFString *) *headers; @@ -132,11 +130,11 @@ path = URL.URLEncodedPath; else path = @"/"; requestString = [OFMutableString stringWithFormat: - @"%s %@", of_http_request_method_to_string(method), path]; + @"%s %@", OFHTTPRequestMethodName(method), path]; if (URL.query != nil) { [requestString appendString: @"?"]; [requestString appendString: URL.URLEncodedQuery]; } @@ -154,15 +152,13 @@ if (port != nil) { OFString *host = [OFString stringWithFormat: @"%@:%@", URL.URLEncodedHost, port]; - [headers setObject: host - forKey: @"Host"]; + [headers setObject: host forKey: @"Host"]; } else - [headers setObject: [URL URLEncodedHost] - forKey: @"Host"]; + [headers setObject: URL.URLEncodedHost forKey: @"Host"]; } if ((user.length > 0 || password.length > 0) && [headers objectForKey: @"Authorization"] == nil) { OFMutableData *authorizationData = [OFMutableData data]; @@ -175,12 +171,11 @@ count: password.UTF8StringLength]; authorization = [OFString stringWithFormat: @"Basic %@", authorizationData.stringByBase64Encoding]; - [headers setObject: authorization - forKey: @"Authorization"]; + [headers setObject: authorization forKey: @"Authorization"]; } if ([headers objectForKey: @"User-Agent"] == nil) [headers setObject: @"Something using ObjFW " @"" @@ -187,12 +182,11 @@ forKey: @"User-Agent"]; if (request.protocolVersion.major == 1 && request.protocolVersion.minor == 0 && [headers objectForKey: @"Connection"] == nil) - [headers setObject: @"keep-alive" - forKey: @"Connection"]; + [headers setObject: @"keep-alive" forKey: @"Connection"]; hasContentLength = ([headers objectForKey: @"Content-Length"] != nil); chunked = [[headers objectForKey: @"Transfer-Encoding"] isEqual: @"chunked"]; @@ -223,37 +217,36 @@ { unsigned char *str = (unsigned char *)str_; bool firstLetter = true; while (*str != '\0') { - if (!of_ascii_isalpha(*str)) { + if (!OFASCIIIsAlpha(*str)) { firstLetter = true; str++; continue; } *str = (firstLetter - ? of_ascii_toupper(*str) - : of_ascii_tolower(*str)); + ? OFASCIIToUpper(*str) : OFASCIIToLower(*str)); firstLetter = false; str++; } } static bool -defaultShouldFollow(of_http_request_method_t method, short statusCode) +defaultShouldFollow(OFHTTPRequestMethod method, short statusCode) { bool follow; /* * 301, 302 and 307 should only redirect with user confirmation if the * request method is not GET or HEAD. Asking the delegate and getting * true returned is considered user confirmation. */ - if (method == OF_HTTP_REQUEST_METHOD_GET || - method == OF_HTTP_REQUEST_METHOD_HEAD) + if (method == OFHTTPRequestMethodGet || + method == OFHTTPRequestMethodHead) follow = true; /* 303 should always be redirected and converted to a GET request. */ else if (statusCode == 303) follow = true; else @@ -301,20 +294,20 @@ didPerformRequest: _request response: nil exception: exception]; } -- (void)createResponseWithSocketOrThrow: (OFTCPSocket *)sock +- (void)createResponseWithStreamOrThrow: (OFStream *)stream { OFURL *URL = _request.URL; OFHTTPClientResponse *response; OFString *connectionHeader; bool keepAlive; OFString *location; id exception; - response = [[[OFHTTPClientResponse alloc] initWithSocket: sock] + response = [[[OFHTTPClientResponse alloc] initWithStream: stream] autorelease]; response.protocolVersionString = _version; response.statusCode = _status; response.headers = _serverHeaders; @@ -325,22 +318,22 @@ else keepAlive = true; } else { if (connectionHeader != nil) keepAlive = ([connectionHeader caseInsensitiveCompare: - @"keep-alive"] == OF_ORDERED_SAME); + @"keep-alive"] == OFOrderedSame); else keepAlive = false; } if (keepAlive) { response.of_keepAlive = true; - _client->_socket = [sock retain]; + _client->_stream = [stream retain]; _client->_lastURL = [URL copy]; _client->_lastWasHEAD = - (_request.method == OF_HTTP_REQUEST_METHOD_HEAD); + (_request.method == OFHTTPRequestMethodHead); _client->_lastResponse = [response retain]; } if (_redirects > 0 && (_status == 301 || _status == 302 || _status == 303 || _status == 307) && @@ -352,20 +345,20 @@ newURL = [OFURL URLWithString: location relativeToURL: URL]; newURLScheme = newURL.scheme; if ([newURLScheme caseInsensitiveCompare: @"http"] != - OF_ORDERED_SAME && + OFOrderedSame && [newURLScheme caseInsensitiveCompare: @"https"] != - OF_ORDERED_SAME) + OFOrderedSame) follow = false; if (!_client->_allowsInsecureRedirects && [URL.scheme caseInsensitiveCompare: @"https"] == - OF_ORDERED_SAME && + OFOrderedSame && [newURLScheme caseInsensitiveCompare: @"http"] == - OF_ORDERED_SAME) + OFOrderedSame) follow = false; if (follow && [_client->_delegate respondsToSelector: @selector( client:shouldFollowRedirect:statusCode:request:response:)]) follow = [_client->_delegate client: _client @@ -405,11 +398,11 @@ if ([key hasPrefix: @"Content-"] || [key hasPrefix: @"Transfer-"]) [newHeaders removeObjectForKey: key]; - newRequest.method = OF_HTTP_REQUEST_METHOD_GET; + newRequest.method = OFHTTPRequestMethodGet; } newRequest.URL = newURL; newRequest.headers = newHeaders; @@ -437,14 +430,14 @@ withObject: response withObject: exception afterDelay: 0]; } -- (void)createResponseWithSocket: (OFTCPSocket *)sock +- (void)createResponseWithStream: (OFStream *)stream { @try { - [self createResponseWithSocketOrThrow: sock]; + [self createResponseWithStreamOrThrow: stream]; } @catch (id e) { [self raiseException: e]; } } @@ -464,27 +457,26 @@ if (![line hasPrefix: @"HTTP/"] || line.length < 9 || [line characterAtIndex: 8] != ' ') @throw [OFInvalidServerReplyException exception]; - _version = [[line substringWithRange: of_range(5, 3)] copy]; + _version = [[line substringWithRange: OFRangeMake(5, 3)] copy]; if (![_version isEqual: @"1.0"] && ![_version isEqual: @"1.1"]) @throw [OFUnsupportedVersionException exceptionWithVersion: _version]; - status = [line substringWithRange: of_range(9, 3)].longLongValue; + status = [line substringWithRange: OFRangeMake(9, 3)].longLongValue; if (status < 0 || status > 599) @throw [OFInvalidServerReplyException exception]; _status = (short)status; return true; } -- (bool)handleServerHeader: (OFString *)line - socket: (OFTCPSocket *)sock +- (bool)handleServerHeader: (OFString *)line stream: (OFStream *)stream { OFString *key, *value, *old; const char *lineC, *tmp; char *keyC; @@ -499,14 +491,14 @@ [_client->_delegate client: _client didReceiveHeaders: _serverHeaders statusCode: _status request: _request]; - sock.delegate = nil; + stream.delegate = nil; - [self performSelector: @selector(createResponseWithSocket:) - withObject: sock + [self performSelector: @selector(createResponseWithStream:) + withObject: stream afterDelay: 0]; return false; } @@ -513,20 +505,20 @@ lineC = line.UTF8String; if ((tmp = strchr(lineC, ':')) == NULL) @throw [OFInvalidServerReplyException exception]; - keyC = of_malloc(1, tmp - lineC + 1); + keyC = OFAllocMemory(tmp - lineC + 1, 1); memcpy(keyC, lineC, tmp - lineC); keyC[tmp - lineC] = '\0'; normalizeKey(keyC); @try { key = [OFString stringWithUTF8StringNoCopy: keyC freeWhenDone: true]; } @catch (id e) { - of_free(keyC); + OFFreeMemory(keyC); @throw e; } do { tmp++; @@ -536,17 +528,16 @@ old = [_serverHeaders objectForKey: key]; if (old != nil) value = [old stringByAppendingFormat: @",%@", value]; - [_serverHeaders setObject: value - forKey: key]; + [_serverHeaders setObject: value forKey: key]; return true; } -- (bool)stream: (OFStream *)sock +- (bool)stream: (OFStream *)stream didReadLine: (OFString *)line exception: (id)exception { bool ret; @@ -562,12 +553,11 @@ @try { if (_firstLine) { _firstLine = false; ret = [self handleFirstLine: line]; } else - ret = [self handleServerHeader: line - socket: (OFTCPSocket *)sock]; + ret = [self handleServerHeader: line stream: stream]; } @catch (id e) { [self raiseException: e]; ret = false; } @@ -574,11 +564,11 @@ return ret; } - (OFString *)stream: (OFStream *)stream didWriteString: (OFString *)string - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding bytesWritten: (size_t)bytesWritten exception: (id)exception { OFDictionary OF_GENERIC(OFString *, OFString *) *headers; bool chunked; @@ -604,12 +594,11 @@ if (chunked || [headers objectForKey: @"Content-Length"] != nil) { stream.delegate = nil; OFStream *requestBody = [[[OFHTTPClientRequestBodyStream alloc] - initWithHandler: self - socket: (OFTCPSocket *)stream] autorelease]; + initWithHandler: self stream: stream] autorelease]; if ([_client->_delegate respondsToSelector: @selector(client:wantsRequestBody:request:)]) [_client->_delegate client: _client wantsRequestBody: requestBody @@ -618,23 +607,23 @@ [stream asyncReadLine]; return nil; } -- (void)handleSocket: (OFTCPSocket *)sock +- (void)handleStream: (OFStream *)stream { /* * As a work around for a bug with split packets in lighttpd when using * HTTPS, we construct the complete request in a buffer string and then * send it all at once. * - * We do not use the socket's write buffer in case we need to resend + * We do not use the streams's write buffer in case we need to resend * the entire request (e.g. in case a keep-alive connection timed out). */ @try { - [sock asyncWriteString: constructRequestString(_request)]; + [stream asyncWriteString: constructRequestString(_request)]; } @catch (id e) { [self raiseException: e]; return; } } @@ -642,58 +631,95 @@ - (void)socket: (OFTCPSocket *)sock didConnectToHost: (OFString *)host port: (uint16_t)port exception: (id)exception { - sock.delegate = self; + if (exception != nil) { + [self raiseException: exception]; + return; + } + sock.canBlock = false; + + if ([_client->_delegate respondsToSelector: + @selector(client:didCreateTCPSocket:request:)]) + [_client->_delegate client: _client + didCreateTCPSocket: sock + request: _request]; + + if ([_request.URL.scheme caseInsensitiveCompare: @"https"] == + OFOrderedSame) { + OFTLSStream *stream; + @try { + stream = [OFTLSStream streamWithStream: sock]; + } @catch (OFNotImplementedException *e) { + [self raiseException: + [OFUnsupportedProtocolException + exceptionWithURL: _request.URL]]; + return; + } + + if ([_client->_delegate respondsToSelector: + @selector(client:didCreateTLSStream:request:)]) + [_client->_delegate client: _client + didCreateTLSStream: stream + request: _request]; + + stream.delegate = self; + [stream asyncPerformClientHandshakeWithHost: _request.URL.host]; + } else { + sock.delegate = self; + [self performSelector: @selector(handleStream:) + withObject: sock + afterDelay: 0]; + } +} + +- (void)stream: (OFTLSStream *)stream + didPerformClientHandshakeWithHost: (OFString *)host + exception: (id)exception +{ if (exception != nil) { [self raiseException: exception]; return; } - if ([_client->_delegate respondsToSelector: - @selector(client:didCreateSocket:request:)]) - [_client->_delegate client: _client - didCreateSocket: sock - request: _request]; - - [self performSelector: @selector(handleSocket:) - withObject: sock + [self performSelector: @selector(handleStream:) + withObject: stream afterDelay: 0]; } - (void)start { OFURL *URL = _request.URL; - OFTCPSocket *sock; + OFStream *stream; /* Can we reuse the last socket? */ - if (_client->_socket != nil && !_client->_socket.atEndOfStream && + if (_client->_stream != nil && !_client->_stream.atEndOfStream && [_client->_lastURL.scheme isEqual: URL.scheme] && [_client->_lastURL.host isEqual: URL.host] && (_client->_lastURL.port == URL.port || [_client->_lastURL.port isEqual: URL.port]) && (_client->_lastWasHEAD || _client->_lastResponse.atEndOfStream)) { /* - * Set _socket to nil, so that in case of an error it won't be - * reused. If everything is successful, we set _socket again + * 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. */ - sock = [_client->_socket autorelease]; - _client->_socket = nil; + stream = [_client->_stream autorelease]; + _client->_stream = nil; [_client->_lastURL release]; _client->_lastURL = nil; [_client->_lastResponse release]; _client->_lastResponse = nil; - sock.delegate = self; + stream.delegate = self; - [self performSelector: @selector(handleSocket:) - withObject: sock + [self performSelector: @selector(handleStream:) + withObject: stream afterDelay: 0]; } else [self closeAndReconnect]; } @@ -704,49 +730,43 @@ OFTCPSocket *sock; uint16_t port; OFNumber *URLPort; [_client close]; + + sock = [OFTCPSocket socket]; if ([URL.scheme caseInsensitiveCompare: @"https"] == - OF_ORDERED_SAME) { - if (of_tls_socket_class == Nil) - @throw [OFUnsupportedProtocolException - exceptionWithURL: URL]; - - sock = [[[of_tls_socket_class alloc] init] autorelease]; + OFOrderedSame) port = 443; - } else { - sock = [OFTCPSocket socket]; + else port = 80; - } URLPort = URL.port; if (URLPort != nil) port = URLPort.unsignedShortValue; sock.delegate = self; - [sock asyncConnectToHost: URL.host - port: port]; + [sock asyncConnectToHost: URL.host port: port]; } @catch (id e) { [self raiseException: e]; } } @end @implementation OFHTTPClientRequestBodyStream - (instancetype)initWithHandler: (OFHTTPClientRequestHandler *)handler - socket: (OFTCPSocket *)sock + stream: (OFStream *)stream { self = [super init]; @try { OFDictionary OF_GENERIC(OFString *, OFString *) *headers; OFString *transferEncoding, *contentLengthString; _handler = [handler retain]; - _socket = [sock retain]; + _stream = [stream retain]; headers = _handler->_request.headers; transferEncoding = [headers objectForKey: @"Transfer-Encoding"]; _chunked = [transferEncoding isEqual: @"chunked"]; @@ -768,25 +788,23 @@ return self; } - (void)dealloc { - if (_socket != nil) + if (_stream != nil) [self close]; [_handler release]; [super dealloc]; } -- (size_t)lowlevelWriteBuffer: (const void *)buffer - length: (size_t)length +- (size_t)lowlevelWriteBuffer: (const void *)buffer length: (size_t)length { - size_t requestedLength = length; - size_t ret; + /* TODO: Use non-blocking writes */ - if (_socket == nil) + if (_stream == nil) @throw [OFNotOpenException exceptionWithObject: self]; /* * We must not send a chunk of size 0, as that would end the body. We * always ignore writing 0 bytes to still allow writing 0 bytes after @@ -794,91 +812,80 @@ */ if (length == 0) return 0; if (_atEndOfStream) - @throw [OFWriteFailedException - exceptionWithObject: self - requestedLength: requestedLength - bytesWritten: 0 - errNo: 0]; + @throw [OFWriteFailedException exceptionWithObject: self + requestedLength: length + bytesWritten: 0 + errNo: ENOTCONN]; if (_chunked) - [_socket writeFormat: @"%zX\r\n", length]; + [_stream writeFormat: @"%zX\r\n", length]; else if (length > _toWrite) - length = (size_t)_toWrite; + @throw [OFOutOfRangeException exception]; - ret = [_socket writeBuffer: buffer - length: length]; + [_stream writeBuffer: buffer length: length]; if (_chunked) - [_socket writeString: @"\r\n"]; - - if (ret > length) - @throw [OFOutOfRangeException exception]; + [_stream writeString: @"\r\n"]; if (!_chunked) { - _toWrite -= ret; + _toWrite -= length; if (_toWrite == 0) _atEndOfStream = true; } - if (requestedLength > length) - @throw [OFWriteFailedException - exceptionWithObject: self - requestedLength: requestedLength - bytesWritten: ret - errNo: 0]; - - return ret; + return length; } - (bool)lowlevelIsAtEndOfStream { return _atEndOfStream; } - (void)close { - if (_socket == nil) + if (_stream == nil) @throw [OFNotOpenException exceptionWithObject: self]; if (_chunked) - [_socket writeString: @"0\r\n\r\n"]; + [_stream writeString: @"0\r\n\r\n"]; else if (_toWrite > 0) @throw [OFTruncatedDataException exception]; - _socket.delegate = _handler; - [_socket asyncReadLine]; + _stream.delegate = _handler; + [_stream asyncReadLine]; - [_socket release]; - _socket = nil; + [_stream release]; + _stream = nil; [super close]; } - (int)fileDescriptorForWriting { - return _socket.fileDescriptorForWriting; + return ((OFStream *)_stream) + .fileDescriptorForWriting; } @end @implementation OFHTTPClientResponse @synthesize of_keepAlive = _keepAlive; -- (instancetype)initWithSocket: (OFTCPSocket *)sock +- (instancetype)initWithStream: (OFStream *)stream { self = [super init]; - _socket = [sock retain]; + _stream = [stream retain]; return self; } - (void)dealloc { - if (_socket != nil) + if (_stream != nil) [self close]; [super dealloc]; } @@ -910,36 +917,32 @@ @throw [OFInvalidServerReplyException exception]; } } } -- (size_t)lowlevelReadIntoBuffer: (void *)buffer - length: (size_t)length +- (size_t)lowlevelReadIntoBuffer: (void *)buffer length: (size_t)length { - if (_socket == nil) + if (_stream == nil) @throw [OFNotOpenException exceptionWithObject: self]; if (_atEndOfStream) return 0; if (!_hasContentLength && !_chunked) - return [_socket readIntoBuffer: buffer - length: length]; + return [_stream readIntoBuffer: buffer length: length]; - if (_socket.atEndOfStream) + if (_stream.atEndOfStream) @throw [OFTruncatedDataException exception]; /* Content-Length */ if (!_chunked) { size_t ret; if (length > (unsigned long long)_toRead) length = (size_t)_toRead; - ret = [_socket readIntoBuffer: buffer - length: length]; - + ret = [_stream readIntoBuffer: buffer length: length]; if (ret > length) @throw [OFOutOfRangeException exception]; _toRead -= ret; @@ -951,12 +954,11 @@ /* Chunked */ if (_toRead == -2) { char tmp[2]; - switch ([_socket readIntoBuffer: tmp - length: 2]) { + switch ([_stream readIntoBuffer: tmp length: 2]) { case 2: _toRead++; if (tmp[1] != '\n') @throw [OFInvalidServerReplyException exception]; @@ -972,12 +974,11 @@ return 0; } else if (_toRead == -1) { char tmp; - if ([_socket readIntoBuffer: &tmp - length: 1] == 1) { + if ([_stream readIntoBuffer: &tmp length: 1] == 1) { _toRead++; if (tmp != '\n') @throw [OFInvalidServerReplyException exception]; } @@ -988,15 +989,13 @@ return 0; } else if (_toRead > 0) { if (length > (unsigned long long)_toRead) length = (size_t)_toRead; - length = [_socket readIntoBuffer: buffer - length: length]; + length = [_stream readIntoBuffer: buffer length: length]; _toRead -= length; - if (_toRead == 0) _toRead = -2; return length; } else { @@ -1003,28 +1002,28 @@ void *pool = objc_autoreleasePoolPush(); OFString *line; size_t pos; @try { - line = [_socket tryReadLine]; + line = [_stream tryReadLine]; } @catch (OFInvalidEncodingException *e) { @throw [OFInvalidServerReplyException exception]; } if (line == nil) return 0; pos = [line rangeOfString: @";"].location; - if (pos != OF_NOT_FOUND) + if (pos != OFNotFound) line = [line substringToIndex: pos]; if (line.length < 1) { /* - * We have read the empty string because the socket is + * We have read the empty string because the stream is * at end of stream. */ - if (_socket.atEndOfStream && pos == OF_NOT_FOUND) + if (_stream.atEndOfStream && pos == OFNotFound) @throw [OFTruncatedDataException exception]; else @throw [OFInvalidServerReplyException exception]; } @@ -1055,41 +1054,42 @@ - (bool)lowlevelIsAtEndOfStream { if (_atEndOfStream) return true; - if (_socket == nil) + if (_stream == nil) @throw [OFNotOpenException exceptionWithObject: self]; if (!_hasContentLength && !_chunked) - return _socket.atEndOfStream; + return _stream.atEndOfStream; return _atEndOfStream; } - (int)fileDescriptorForReading { - if (_socket == nil) + if (_stream == nil) return -1; - return _socket.fileDescriptorForReading; + return ((OFStream *)_stream) + .fileDescriptorForReading; } - (bool)hasDataInReadBuffer { - return (super.hasDataInReadBuffer || _socket.hasDataInReadBuffer); + return (super.hasDataInReadBuffer || _stream.hasDataInReadBuffer); } - (void)close { - if (_socket == nil) + if (_stream == nil) @throw [OFNotOpenException exceptionWithObject: self]; _atEndOfStream = false; - [_socket release]; - _socket = nil; + [_stream release]; + _stream = nil; [super close]; } @end @@ -1120,15 +1120,12 @@ } - (OFHTTPResponse *)performRequest: (OFHTTPRequest *)request redirects: (unsigned int)redirects { - [_client asyncPerformRequest: request - redirects: redirects]; - + [_client asyncPerformRequest: request redirects: redirects]; [[OFRunLoop currentRunLoop] run]; - return _response; } - (void)client: (OFHTTPClient *)client didPerformRequest: (OFHTTPRequest *)request @@ -1155,19 +1152,30 @@ didPerformRequest: request response: response exception: nil]; } -- (void)client: (OFHTTPClient *)client - didCreateSocket: (OFTCPSocket *)sock - request: (OFHTTPRequest *)request +- (void)client: (OFHTTPClient *)client + didCreateTCPSocket: (OFTCPSocket *)TCPSocket + request: (OFHTTPRequest *)request +{ + if ([_delegate respondsToSelector: + @selector(client:didCreateTCPSocket:request:)]) + [_delegate client: client + didCreateTCPSocket: TCPSocket + request: request]; +} + +- (void)client: (OFHTTPClient *)client + didCreateTLSStream: (OFTLSStream *)TLSStream + request: (OFHTTPRequest *)request { if ([_delegate respondsToSelector: - @selector(client:didCreateSocket:request:)]) - [_delegate client: client - didCreateSocket: sock - request: request]; + @selector(client:didCreateTLSStream:request:)]) + [_delegate client: client + didCreateTLSStream: TLSStream + request: request]; } - (void)client: (OFHTTPClient *)client wantsRequestBody: (OFStream *)body request: (OFHTTPRequest *)request @@ -1226,12 +1234,11 @@ [super dealloc]; } - (OFHTTPResponse *)performRequest: (OFHTTPRequest *)request { - return [self performRequest: request - redirects: REDIRECTS_DEFAULT]; + return [self performRequest: request redirects: defaultRedirects]; } - (OFHTTPResponse *)performRequest: (OFHTTPRequest *)request redirects: (unsigned int)redirects { @@ -1249,23 +1256,22 @@ return [response autorelease]; } - (void)asyncPerformRequest: (OFHTTPRequest *)request { - [self asyncPerformRequest: request - redirects: REDIRECTS_DEFAULT]; + [self asyncPerformRequest: request redirects: defaultRedirects]; } - (void)asyncPerformRequest: (OFHTTPRequest *)request redirects: (unsigned int)redirects { void *pool = objc_autoreleasePoolPush(); OFURL *URL = request.URL; OFString *scheme = URL.scheme; - if ([scheme caseInsensitiveCompare: @"http"] != OF_ORDERED_SAME && - [scheme caseInsensitiveCompare: @"https"] != OF_ORDERED_SAME) + if ([scheme caseInsensitiveCompare: @"http"] != OFOrderedSame && + [scheme caseInsensitiveCompare: @"https"] != OFOrderedSame) @throw [OFUnsupportedProtocolException exceptionWithURL: URL]; if (_inProgress) /* TODO: Find a better exception */ @throw [OFAlreadyConnectedException exception]; @@ -1280,15 +1286,15 @@ objc_autoreleasePoolPop(pool); } - (void)close { - [_socket release]; - _socket = nil; + [_stream release]; + _stream = nil; [_lastURL release]; _lastURL = nil; [_lastResponse release]; _lastResponse = nil; } @end Index: src/OFHTTPCookie.h ================================================================== --- src/OFHTTPCookie.h +++ src/OFHTTPCookie.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFHTTPCookie.m ================================================================== --- src/OFHTTPCookie.m +++ src/OFHTTPCookie.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -68,117 +66,117 @@ { OFMutableArray OF_GENERIC(OFHTTPCookie *) *ret = [OFMutableArray array]; void *pool = objc_autoreleasePoolPush(); OFString *string = [headerFields objectForKey: @"Set-Cookie"]; OFString *domain = URL.host; - const of_unichar_t *characters = string.characters; - size_t length = string.length, last = 0; - enum { - STATE_PRE_NAME, - STATE_NAME, - STATE_EXPECT_VALUE, - STATE_VALUE, - STATE_QUOTED_VALUE, - STATE_POST_QUOTED_VALUE, - STATE_PRE_ATTR_NAME, - STATE_ATTR_NAME, - STATE_ATTR_VALUE - } state = STATE_PRE_NAME; - OFString *name = nil, *value = nil; - - for (size_t i = 0; i < length; i++) { - switch (state) { - case STATE_PRE_NAME: - if (characters[i] != ' ') { - state = STATE_NAME; - last = i; - i--; - } - break; - case STATE_NAME: - if (characters[i] == '=') { - name = [string substringWithRange: - of_range(last, i - last)]; - state = STATE_EXPECT_VALUE; - } - break; - case STATE_EXPECT_VALUE: - if (characters[i] == '"') { - state = STATE_QUOTED_VALUE; - last = i + 1; - } else { - state = STATE_VALUE; - last = i; - } - - i--; - break; - case STATE_VALUE: - if (characters[i] == ';' || characters[i] == ',') { - value = [string substringWithRange: - of_range(last, i - last)]; - - [ret addObject: - [OFHTTPCookie cookieWithName: name - value: value - domain: domain]]; - - state = (characters[i] == ';' - ? STATE_PRE_ATTR_NAME : STATE_PRE_NAME); - } - break; - case STATE_QUOTED_VALUE: - if (characters[i] == '"') { - value = [string substringWithRange: - of_range(last, i - last)]; - [ret addObject: - [OFHTTPCookie cookieWithName: name - value: value - domain: domain]]; - - state = STATE_POST_QUOTED_VALUE; - } - break; - case STATE_POST_QUOTED_VALUE: - if (characters[i] == ';') - state = STATE_PRE_ATTR_NAME; - else if (characters[i] == ',') - state = STATE_PRE_NAME; - else - @throw [OFInvalidFormatException exception]; - - break; - case STATE_PRE_ATTR_NAME: - if (characters[i] != ' ') { - state = STATE_ATTR_NAME; - last = i; - i--; - } - break; - case STATE_ATTR_NAME: - if (characters[i] == '=') { - name = [string substringWithRange: - of_range(last, i - last)]; - - state = STATE_ATTR_VALUE; - last = i + 1; - } else if (characters[i] == ';' || - characters[i] == ',') { - name = [string substringWithRange: - of_range(last, i - last)]; - - handleAttribute(ret.lastObject, name, nil); - - state = (characters[i] == ';' - ? STATE_PRE_ATTR_NAME : STATE_PRE_NAME); - } - - break; - case STATE_ATTR_VALUE: - if (characters[i] == ';' || characters[i] == ',') { - value = [string substringWithRange: - of_range(last, i - last)]; + const OFUnichar *characters = string.characters; + size_t length = string.length, last = 0; + enum { + statePreName, + stateName, + stateExpectValue, + stateValue, + stateQuotedValue, + statePostQuotedValue, + statePreAttrName, + stateAttrName, + stateAttrValue + } state = statePreName; + OFString *name = nil, *value = nil; + + for (size_t i = 0; i < length; i++) { + switch (state) { + case statePreName: + if (characters[i] != ' ') { + state = stateName; + last = i; + i--; + } + break; + case stateName: + if (characters[i] == '=') { + name = [string substringWithRange: + OFRangeMake(last, i - last)]; + state = stateExpectValue; + } + break; + case stateExpectValue: + if (characters[i] == '"') { + state = stateQuotedValue; + last = i + 1; + } else { + state = stateValue; + last = i; + } + + i--; + break; + case stateValue: + if (characters[i] == ';' || characters[i] == ',') { + value = [string substringWithRange: + OFRangeMake(last, i - last)]; + + [ret addObject: + [OFHTTPCookie cookieWithName: name + value: value + domain: domain]]; + + state = (characters[i] == ';' + ? statePreAttrName : statePreName); + } + break; + case stateQuotedValue: + if (characters[i] == '"') { + value = [string substringWithRange: + OFRangeMake(last, i - last)]; + [ret addObject: + [OFHTTPCookie cookieWithName: name + value: value + domain: domain]]; + + state = statePostQuotedValue; + } + break; + case statePostQuotedValue: + if (characters[i] == ';') + state = statePreAttrName; + else if (characters[i] == ',') + state = statePreName; + else + @throw [OFInvalidFormatException exception]; + + break; + case statePreAttrName: + if (characters[i] != ' ') { + state = stateAttrName; + last = i; + i--; + } + break; + case stateAttrName: + if (characters[i] == '=') { + name = [string substringWithRange: + OFRangeMake(last, i - last)]; + + state = stateAttrValue; + last = i + 1; + } else if (characters[i] == ';' || + characters[i] == ',') { + name = [string substringWithRange: + OFRangeMake(last, i - last)]; + + handleAttribute(ret.lastObject, name, nil); + + state = (characters[i] == ';' + ? statePreAttrName : statePreName); + } + + break; + case stateAttrValue: + if (characters[i] == ';' || characters[i] == ',') { + value = [string substringWithRange: + OFRangeMake(last, i - last)]; /* * Expires often contains a comma, even though * the comma is used as a separator for * concatenating headers as per RFC 2616, @@ -185,11 +183,11 @@ * meaning RFC 6265 contradicts RFC 2616. * Solve this by special casing this. */ if (characters[i] == ',' && [name caseInsensitiveCompare: @"expires"] == - OF_ORDERED_SAME && value.length == 3 && + OFOrderedSame && value.length == 3 && ([value isEqual: @"Mon"] || [value isEqual: @"Tue"] || [value isEqual: @"Wed"] || [value isEqual: @"Thu"] || [value isEqual: @"Fri"] || @@ -198,49 +196,49 @@ break; handleAttribute(ret.lastObject, name, value); state = (characters[i] == ';' - ? STATE_PRE_ATTR_NAME : STATE_PRE_NAME); + ? statePreAttrName : statePreName); } break; } } switch (state) { - case STATE_PRE_NAME: - case STATE_POST_QUOTED_VALUE: - case STATE_PRE_ATTR_NAME: + case statePreName: + case statePostQuotedValue: + case statePreAttrName: break; - case STATE_NAME: - case STATE_QUOTED_VALUE: + case stateName: + case stateQuotedValue: @throw [OFInvalidFormatException exception]; break; - case STATE_VALUE: + case stateValue: value = [string substringWithRange: - of_range(last, length - last)]; + OFRangeMake(last, length - last)]; [ret addObject: [OFHTTPCookie cookieWithName: name value: value domain: domain]]; break; /* We end up here if the cookie is just foo= */ - case STATE_EXPECT_VALUE: + case stateExpectValue: [ret addObject: [OFHTTPCookie cookieWithName: name value: @"" domain: domain]]; break; - case STATE_ATTR_NAME: + case stateAttrName: if (last != length) { name = [string substringWithRange: - of_range(last, length - last)]; + OFRangeMake(last, length - last)]; handleAttribute(ret.lastObject, name, nil); } break; - case STATE_ATTR_VALUE: + case stateAttrValue: value = [string substringWithRange: - of_range(last, length - last)]; + OFRangeMake(last, length - last)]; handleAttribute(ret.lastObject, name, value); break; } @@ -363,22 +361,22 @@ return true; } - (unsigned long)hash { - uint32_t hash; - - OF_HASH_INIT(hash); - OF_HASH_ADD_HASH(hash, _name.hash); - OF_HASH_ADD_HASH(hash, _value.hash); - OF_HASH_ADD_HASH(hash, _domain.hash); - OF_HASH_ADD_HASH(hash, _path.hash); - OF_HASH_ADD_HASH(hash, _expires.hash); - OF_HASH_ADD(hash, _secure); - OF_HASH_ADD(hash, _HTTPOnly); - OF_HASH_ADD_HASH(hash, _extensions.hash); - OF_HASH_FINALIZE(hash); + unsigned long hash; + + OFHashInit(&hash); + OFHashAddHash(&hash, _name.hash); + OFHashAddHash(&hash, _value.hash); + OFHashAddHash(&hash, _domain.hash); + OFHashAddHash(&hash, _path.hash); + OFHashAddHash(&hash, _expires.hash); + OFHashAdd(&hash, _secure); + OFHashAdd(&hash, _HTTPOnly); + OFHashAddHash(&hash, _extensions.hash); + OFHashFinalize(&hash); return hash; } - (id)copy Index: src/OFHTTPCookieManager.h ================================================================== --- src/OFHTTPCookieManager.h +++ src/OFHTTPCookieManager.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -54,12 +52,11 @@ * If you do not want this, pass a copy! * * @param cookie The cookie to add to the manager * @param URL The URL for which the cookie should be added */ -- (void)addCookie: (OFHTTPCookie *)cookie - forURL: (OFURL *)URL; +- (void)addCookie: (OFHTTPCookie *)cookie forURL: (OFURL *)URL; /** * @brief Adds the specified cookies for the specified URL. * * @warning This modifies the cookies (e.g. it sets the domain if it is unset)! Index: src/OFHTTPCookieManager.m ================================================================== --- src/OFHTTPCookieManager.m +++ src/OFHTTPCookieManager.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -53,22 +51,21 @@ - (OFArray OF_GENERIC(OFHTTPCookie *) *)cookies { return [[_cookies copy] autorelease]; } -- (void)addCookie: (OFHTTPCookie *)cookie - forURL: (OFURL *)URL +- (void)addCookie: (OFHTTPCookie *)cookie forURL: (OFURL *)URL { void *pool = objc_autoreleasePoolPush(); OFString *cookieDomain, *URLHost; size_t i; if (![cookie.path hasPrefix: @"/"]) cookie.path = @"/"; if (cookie.secure && - [URL.scheme caseInsensitiveCompare: @"https"] != OF_ORDERED_SAME) { + [URL.scheme caseInsensitiveCompare: @"https"] != OFOrderedSame) { objc_autoreleasePoolPop(pool); return; } cookieDomain = cookie.domain.lowercaseString; @@ -87,13 +84,11 @@ i = 0; for (OFHTTPCookie *iter in _cookies) { if ([iter.name isEqual: cookie.name] && [iter.domain isEqual: cookie.domain] && [iter.path isEqual: cookie.path]) { - [_cookies replaceObjectAtIndex: i - withObject: cookie]; - + [_cookies replaceObjectAtIndex: i withObject: cookie]; objc_autoreleasePoolPop(pool); return; } i++; @@ -106,12 +101,11 @@ - (void)addCookies: (OFArray OF_GENERIC(OFHTTPCookie *) *)cookies forURL: (OFURL *)URL { for (OFHTTPCookie *cookie in cookies) - [self addCookie: cookie - forURL: URL]; + [self addCookie: cookie forURL: URL]; } - (OFArray OF_GENERIC(OFHTTPCookie *) *)cookiesForURL: (OFURL *)URL { OFMutableArray *ret = [OFMutableArray array]; @@ -125,11 +119,11 @@ expires = cookie.expires; if (expires != nil && expires.timeIntervalSinceNow <= 0) continue; if (cookie.secure && [URL.scheme caseInsensitiveCompare: - @"https"] != OF_ORDERED_SAME) + @"https"] != OFOrderedSame) continue; pool = objc_autoreleasePoolPush(); cookieDomain = cookie.domain.lowercaseString; Index: src/OFHTTPRequest.h ================================================================== --- src/OFHTTPRequest.h +++ src/OFHTTPRequest.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -14,14 +12,13 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #import "OFObject.h" +#import "OFSocket.h" #import "OFString.h" -#import "socket.h" - OF_ASSUME_NONNULL_BEGIN @class OFURL; @class OFDictionary OF_GENERIC(KeyType, ObjectType); @class OFData; @@ -32,54 +29,51 @@ /** * @brief The type of an HTTP request. */ typedef enum { /** OPTIONS */ - OF_HTTP_REQUEST_METHOD_OPTIONS, + OFHTTPRequestMethodOptions, /** GET */ - OF_HTTP_REQUEST_METHOD_GET, + OFHTTPRequestMethodGet, /** HEAD */ - OF_HTTP_REQUEST_METHOD_HEAD, + OFHTTPRequestMethodHead, /** POST */ - OF_HTTP_REQUEST_METHOD_POST, + OFHTTPRequestMethodPost, /** PUT */ - OF_HTTP_REQUEST_METHOD_PUT, + OFHTTPRequestMethodPut, /** DELETE */ - OF_HTTP_REQUEST_METHOD_DELETE, + OFHTTPRequestMethodDelete, /** TRACE */ - OF_HTTP_REQUEST_METHOD_TRACE, + OFHTTPRequestMethodTrace, /** CONNECT */ - OF_HTTP_REQUEST_METHOD_CONNECT -} of_http_request_method_t; + OFHTTPRequestMethodConnect +} OFHTTPRequestMethod; /** - * @struct of_http_request_protocol_version_t \ - * OFHTTPRequest.h ObjFW/OFHTTPRequest.h + * @struct OFHTTPRequestProtocolVersion OFHTTPRequest.h ObjFW/OFHTTPRequest.h * * @brief The HTTP version of the HTTP request. */ -struct OF_BOXABLE of_http_request_protocol_version_t { +typedef struct OF_BOXABLE { /** The major of the HTTP version */ unsigned char major; /** The minor of the HTTP version */ unsigned char minor; -}; -typedef struct of_http_request_protocol_version_t - of_http_request_protocol_version_t; +} OFHTTPRequestProtocolVersion; /** * @class OFHTTPRequest OFHTTPRequest.h ObjFW/OFHTTPRequest.h * * @brief A class for storing HTTP requests. */ @interface OFHTTPRequest: OFObject { OFURL *_URL; - of_http_request_method_t _method; - of_http_request_protocol_version_t _protocolVersion; + OFHTTPRequestMethod _method; + OFHTTPRequestProtocolVersion _protocolVersion; OFDictionary OF_GENERIC(OFString *, OFString *) *_Nullable _headers; - of_socket_address_t _remoteAddress; + OFSocketAddress _remoteAddress; bool _hasRemoteAddress; OF_RESERVE_IVARS(OFHTTPRequest, 4) } /** @@ -88,21 +82,21 @@ @property (copy, nonatomic) OFURL *URL; /** * @brief The protocol version of the HTTP request. */ -@property (nonatomic) of_http_request_protocol_version_t protocolVersion; +@property (nonatomic) OFHTTPRequestProtocolVersion protocolVersion; /** * @brief The protocol version of the HTTP request as a string. */ @property (copy, nonatomic) OFString *protocolVersionString; /** * @brief The request method of the HTTP request. */ -@property (nonatomic) of_http_request_method_t method; +@property (nonatomic) OFHTTPRequestMethod method; /** * @brief The headers for the HTTP request. */ @property OF_NULLABLE_PROPERTY (copy, nonatomic) @@ -111,19 +105,11 @@ /** * @brief The remote address from which the request originates. * * @note The setter creates a copy of the remote address. */ -@property OF_NULLABLE_PROPERTY (nonatomic) - const of_socket_address_t *remoteAddress; - -/** - * @brief Creates a new OFHTTPRequest. - * - * @return A new, autoreleased OFHTTPRequest - */ -+ (instancetype)request; +@property OF_NULLABLE_PROPERTY (nonatomic) const OFSocketAddress *remoteAddress; /** * @brief Creates a new OFHTTPRequest with the specified URL. * * @param URL The URL for the request @@ -136,10 +122,12 @@ * * @param URL The URL for the request * @return An initialized OFHTTPRequest */ - (instancetype)initWithURL: (OFURL *)URL; + +- (instancetype)init OF_UNAVAILABLE; @end #ifdef __cplusplus extern "C" { #endif @@ -147,21 +135,20 @@ * @brief Returns a C string describing the specified request method. * * @param method The request method which should be described as a C string * @return A C string describing the specified request method */ -extern const char *_Nullable of_http_request_method_to_string( - of_http_request_method_t method); +extern const char *_Nullable OFHTTPRequestMethodName( + OFHTTPRequestMethod method); /** * @brief Returns the request method for the specified string. * * @param string The string for which the request method should be returned * @return The request method for the specified string */ -extern of_http_request_method_t of_http_request_method_from_string( - OFString *string); +extern OFHTTPRequestMethod OFHTTPRequestMethodParseName(OFString *string); #ifdef __cplusplus } #endif OF_ASSUME_NONNULL_END Index: src/OFHTTPRequest.m ================================================================== --- src/OFHTTPRequest.m +++ src/OFHTTPRequest.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -30,127 +28,118 @@ #import "OFInvalidFormatException.h" #import "OFOutOfRangeException.h" #import "OFUnsupportedVersionException.h" const char * -of_http_request_method_to_string(of_http_request_method_t method) +OFHTTPRequestMethodName(OFHTTPRequestMethod method) { switch (method) { - case OF_HTTP_REQUEST_METHOD_OPTIONS: + case OFHTTPRequestMethodOptions: return "OPTIONS"; - case OF_HTTP_REQUEST_METHOD_GET: + case OFHTTPRequestMethodGet: return "GET"; - case OF_HTTP_REQUEST_METHOD_HEAD: + case OFHTTPRequestMethodHead: return "HEAD"; - case OF_HTTP_REQUEST_METHOD_POST: + case OFHTTPRequestMethodPost: return "POST"; - case OF_HTTP_REQUEST_METHOD_PUT: + case OFHTTPRequestMethodPut: return "PUT"; - case OF_HTTP_REQUEST_METHOD_DELETE: + case OFHTTPRequestMethodDelete: return "DELETE"; - case OF_HTTP_REQUEST_METHOD_TRACE: + case OFHTTPRequestMethodTrace: return "TRACE"; - case OF_HTTP_REQUEST_METHOD_CONNECT: + case OFHTTPRequestMethodConnect: return "CONNECT"; } return NULL; } -of_http_request_method_t -of_http_request_method_from_string(OFString *string) +OFHTTPRequestMethod +OFHTTPRequestMethodParseName(OFString *string) { if ([string isEqual: @"OPTIONS"]) - return OF_HTTP_REQUEST_METHOD_OPTIONS; + return OFHTTPRequestMethodOptions; if ([string isEqual: @"GET"]) - return OF_HTTP_REQUEST_METHOD_GET; + return OFHTTPRequestMethodGet; if ([string isEqual: @"HEAD"]) - return OF_HTTP_REQUEST_METHOD_HEAD; + return OFHTTPRequestMethodHead; if ([string isEqual: @"POST"]) - return OF_HTTP_REQUEST_METHOD_POST; + return OFHTTPRequestMethodPost; if ([string isEqual: @"PUT"]) - return OF_HTTP_REQUEST_METHOD_PUT; + return OFHTTPRequestMethodPut; if ([string isEqual: @"DELETE"]) - return OF_HTTP_REQUEST_METHOD_DELETE; + return OFHTTPRequestMethodDelete; if ([string isEqual: @"TRACE"]) - return OF_HTTP_REQUEST_METHOD_TRACE; + return OFHTTPRequestMethodTrace; if ([string isEqual: @"CONNECT"]) - return OF_HTTP_REQUEST_METHOD_CONNECT; + return OFHTTPRequestMethodConnect; @throw [OFInvalidArgumentException exception]; } @implementation OFHTTPRequest @synthesize URL = _URL, method = _method, headers = _headers; -+ (instancetype)request -{ - return [[[self alloc] init] autorelease]; -} - + (instancetype)requestWithURL: (OFURL *)URL { return [[[self alloc] initWithURL: URL] autorelease]; } -- (instancetype)init +- (instancetype)initWithURL: (OFURL *)URL { self = [super init]; - _method = OF_HTTP_REQUEST_METHOD_GET; - _protocolVersion.major = 1; - _protocolVersion.minor = 1; - - return self; -} - -- (instancetype)initWithURL: (OFURL *)URL -{ - self = [self init]; - @try { _URL = [URL copy]; + _method = OFHTTPRequestMethodGet; + _protocolVersion.major = 1; + _protocolVersion.minor = 1; } @catch (id e) { [self release]; @throw e; } return self; } + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} - (void)dealloc { [_URL release]; [_headers release]; [super dealloc]; } -- (void)setRemoteAddress: (const of_socket_address_t *)remoteAddress +- (void)setRemoteAddress: (const OFSocketAddress *)remoteAddress { _hasRemoteAddress = (remoteAddress != NULL); if (_hasRemoteAddress) _remoteAddress = *remoteAddress; } -- (const of_socket_address_t *)remoteAddress +- (const OFSocketAddress *)remoteAddress { if (_hasRemoteAddress) return &_remoteAddress; return NULL; } - (id)copy { - OFHTTPRequest *copy = [[OFHTTPRequest alloc] init]; + OFHTTPRequest *copy = [[OFHTTPRequest alloc] initWithURL: _URL]; @try { copy->_method = _method; copy->_protocolVersion = _protocolVersion; - copy.URL = _URL; copy.headers = _headers; copy.remoteAddress = self.remoteAddress; } @catch (id e) { [copy release]; @throw e; @@ -177,36 +166,36 @@ ![request->_URL isEqual: _URL] || ![request->_headers isEqual: _headers]) return false; if (request.remoteAddress != self.remoteAddress && - !of_socket_address_equal(request.remoteAddress, self.remoteAddress)) + !OFSocketAddressEqual(request.remoteAddress, self.remoteAddress)) return false; return true; } - (unsigned long)hash { - uint32_t hash; - - OF_HASH_INIT(hash); - - OF_HASH_ADD(hash, _method); - OF_HASH_ADD(hash, _protocolVersion.major); - OF_HASH_ADD(hash, _protocolVersion.minor); - OF_HASH_ADD_HASH(hash, _URL.hash); - OF_HASH_ADD_HASH(hash, _headers.hash); + unsigned long hash; + + OFHashInit(&hash); + + OFHashAdd(&hash, _method); + OFHashAdd(&hash, _protocolVersion.major); + OFHashAdd(&hash, _protocolVersion.minor); + OFHashAddHash(&hash, _URL.hash); + OFHashAddHash(&hash, _headers.hash); if (_hasRemoteAddress) - OF_HASH_ADD_HASH(hash, of_socket_address_hash(&_remoteAddress)); + OFHashAddHash(&hash, OFSocketAddressHash(&_remoteAddress)); - OF_HASH_FINALIZE(hash); + OFHashFinalize(&hash); return hash; } -- (void)setProtocolVersion: (of_http_request_protocol_version_t)protocolVersion +- (void)setProtocolVersion: (OFHTTPRequestProtocolVersion)protocolVersion { if (protocolVersion.major != 1 || protocolVersion.minor > 1) @throw [OFUnsupportedVersionException exceptionWithVersion: [OFString stringWithFormat: @"%hhu.%hhu", protocolVersion.major, @@ -213,21 +202,21 @@ protocolVersion.minor]]; _protocolVersion = protocolVersion; } -- (of_http_request_protocol_version_t)protocolVersion +- (OFHTTPRequestProtocolVersion)protocolVersion { return _protocolVersion; } - (void)setProtocolVersionString: (OFString *)string { void *pool = objc_autoreleasePoolPush(); OFArray *components = [string componentsSeparatedByString: @"."]; unsigned long long major, minor; - of_http_request_protocol_version_t protocolVersion; + OFHTTPRequestProtocolVersion protocolVersion; if (components.count != 2) @throw [OFInvalidFormatException exception]; major = [components.firstObject unsignedLongLongValue]; @@ -252,20 +241,19 @@ } - (OFString *)description { void *pool = objc_autoreleasePoolPush(); - const char *method = of_http_request_method_to_string(_method); + const char *method = OFHTTPRequestMethodName(_method); OFString *indentedHeaders, *remoteAddress, *ret; indentedHeaders = [_headers.description stringByReplacingOccurrencesOfString: @"\n" withString: @"\n\t"]; if (_hasRemoteAddress) - remoteAddress = - of_socket_address_ip_string(&_remoteAddress, NULL); + remoteAddress = OFSocketAddressString(&_remoteAddress); else remoteAddress = nil; ret = [[OFString alloc] initWithFormat: @"<%@:\n\tURL = %@\n" Index: src/OFHTTPResponse.h ================================================================== --- src/OFHTTPResponse.h +++ src/OFHTTPResponse.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -24,53 +22,56 @@ @class OFArray OF_GENERIC(ObjectType); /** * @class OFHTTPResponse OFHTTPResponse.h ObjFW/OFHTTPResponse.h * - * @brief A class for representing an HTTP request reply as a stream. + * @brief A class for representing an HTTP request response as a stream. */ @interface OFHTTPResponse: OFStream { - of_http_request_protocol_version_t _protocolVersion; + OFHTTPRequestProtocolVersion _protocolVersion; short _statusCode; OFDictionary OF_GENERIC(OFString *, OFString *) *_headers; OF_RESERVE_IVARS(OFHTTPResponse, 4) } /** - * @brief The protocol version of the HTTP request reply. + * @brief The protocol version of the HTTP request response. */ -@property (nonatomic) of_http_request_protocol_version_t protocolVersion; +@property (nonatomic) OFHTTPRequestProtocolVersion protocolVersion; /** - * @brief The protocol version of the HTTP request reply as a string. + * @brief The protocol version of the HTTP request response as a string. */ @property (copy, nonatomic) OFString *protocolVersionString; /** - * @brief The status code of the reply to the HTTP request. + * @brief The status code of the response to the HTTP request. */ @property (nonatomic) short statusCode; /** - * @brief The headers of the reply to the HTTP request. + * @brief The headers of the response to the HTTP request. */ @property (copy, nonatomic) OFDictionary OF_GENERIC(OFString *, OFString *) *headers; /** - * @brief The reply as a string, trying to detect the encoding. + * @brief Read the response as a string, trying to detect the encoding and + * falling back to the specified encoding if not detectable. + * + * @return The response as a string */ -@property (readonly, nonatomic) OFString *string; +- (OFString *)readString; /** - * @brief Returns the reply as a string, trying to detect the encoding and + * @brief Rread the response as a string, trying to detect the encoding and * falling back to the specified encoding if not detectable. * - * @return The reply as a string + * @return The response as a string */ -- (OFString *)stringWithEncoding: (of_string_encoding_t)encoding; +- (OFString *)readStringWithEncoding: (OFStringEncoding)encoding; @end #ifdef __cplusplus extern "C" { #endif @@ -78,11 +79,11 @@ * @brief Returns a description string for the specified HTTP status code. * * @param code The HTTP status code to return a description string for * @return A description string for the specified HTTP status code */ -extern OFString *_Nonnull of_http_status_code_to_string(short code); +extern OFString *_Nonnull OFHTTPStatusCodeString(short code); #ifdef __cplusplus } #endif OF_ASSUME_NONNULL_END Index: src/OFHTTPResponse.m ================================================================== --- src/OFHTTPResponse.m +++ src/OFHTTPResponse.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -28,11 +26,11 @@ #import "OFOutOfRangeException.h" #import "OFTruncatedDataException.h" #import "OFUnsupportedVersionException.h" OFString * -of_http_status_code_to_string(short code) +OFHTTPStatusCodeString(short code) { switch (code) { case 100: return @"Continue"; case 101: @@ -116,64 +114,64 @@ default: return @"(unknown)"; } } -static of_string_encoding_t +static OFStringEncoding encodingForContentType(OFString *contentType) { const char *UTF8String = contentType.UTF8String; size_t last, length = contentType.UTF8StringLength; enum { - STATE_TYPE, - STATE_BEFORE_PARAM_NAME, - STATE_PARAM_NAME, - STATE_PARAM_VALUE_OR_QUOTE, - STATE_PARAM_VALUE, - STATE_PARAM_QUOTED_VALUE, - STATE_AFTER_PARAM_VALUE - } state = STATE_TYPE; + stateType, + stateBeforeParamName, + stateParamName, + stateParamValueOrQuote, + stateParamValue, + stateParamQuotedValue, + stateAfterParamValue + } state = stateType; OFString *name = nil, *value = nil, *charset = nil; - of_string_encoding_t ret; + OFStringEncoding ret; last = 0; for (size_t i = 0; i < length; i++) { switch (state) { - case STATE_TYPE: + case stateType: if (UTF8String[i] == ';') { - state = STATE_BEFORE_PARAM_NAME; + state = stateBeforeParamName; last = i + 1; } break; - case STATE_BEFORE_PARAM_NAME: + case stateBeforeParamName: if (UTF8String[i] == ' ') last = i + 1; else { - state = STATE_PARAM_NAME; + state = stateParamName; i--; } break; - case STATE_PARAM_NAME: + case stateParamName: if (UTF8String[i] == '=') { name = [OFString stringWithUTF8String: UTF8String + last length: i - last]; - state = STATE_PARAM_VALUE_OR_QUOTE; + state = stateParamValueOrQuote; last = i + 1; } break; - case STATE_PARAM_VALUE_OR_QUOTE: + case stateParamValueOrQuote: if (UTF8String[i] == '"') { - state = STATE_PARAM_QUOTED_VALUE; + state = stateParamQuotedValue; last = i + 1; } else { - state = STATE_PARAM_VALUE; + state = stateParamValue; i--; } break; - case STATE_PARAM_VALUE: + case stateParamValue: if (UTF8String[i] == ';') { value = [OFString stringWithUTF8String: UTF8String + last length: i - last]; value = @@ -180,48 +178,48 @@ value.stringByDeletingTrailingWhitespaces; if ([name isEqual: @"charset"]) charset = value; - state = STATE_BEFORE_PARAM_NAME; + state = stateBeforeParamName; last = i + 1; } break; - case STATE_PARAM_QUOTED_VALUE: + case stateParamQuotedValue: if (UTF8String[i] == '"') { value = [OFString stringWithUTF8String: UTF8String + last length: i - last]; if ([name isEqual: @"charset"]) charset = value; - state = STATE_AFTER_PARAM_VALUE; + state = stateAfterParamValue; } break; - case STATE_AFTER_PARAM_VALUE: + case stateAfterParamValue: if (UTF8String[i] == ';') { - state = STATE_BEFORE_PARAM_NAME; + state = stateBeforeParamName; last = i + 1; } else if (UTF8String[i] != ' ') - return OF_STRING_ENCODING_AUTODETECT; + return OFStringEncodingAutodetect; break; } } - if (state == STATE_PARAM_VALUE) { + if (state == stateParamValue) { value = [OFString stringWithUTF8String: UTF8String + last length: length - last]; value = value.stringByDeletingTrailingWhitespaces; if ([name isEqual: @"charset"]) charset = value; } @try { - ret = of_string_parse_encoding(charset); + ret = OFStringEncodingParseName(charset); } @catch (OFInvalidArgumentException *e) { - ret = OF_STRING_ENCODING_AUTODETECT; + ret = OFStringEncodingAutodetect; } return ret; } @@ -249,11 +247,11 @@ [_headers release]; [super dealloc]; } -- (void)setProtocolVersion: (of_http_request_protocol_version_t)protocolVersion +- (void)setProtocolVersion: (OFHTTPRequestProtocolVersion)protocolVersion { if (protocolVersion.major != 1 || protocolVersion.minor > 1) @throw [OFUnsupportedVersionException exceptionWithVersion: [OFString stringWithFormat: @"%hhu.%hhu", protocolVersion.major, @@ -260,21 +258,21 @@ protocolVersion.minor]]; _protocolVersion = protocolVersion; } -- (of_http_request_protocol_version_t)protocolVersion +- (OFHTTPRequestProtocolVersion)protocolVersion { return _protocolVersion; } - (void)setProtocolVersionString: (OFString *)string { void *pool = objc_autoreleasePoolPush(); OFArray *components = [string componentsSeparatedByString: @"."]; unsigned long long major, minor; - of_http_request_protocol_version_t protocolVersion; + OFHTTPRequestProtocolVersion protocolVersion; if (components.count != 2) @throw [OFInvalidFormatException exception]; major = [components.firstObject unsignedLongLongValue]; @@ -296,27 +294,27 @@ return [OFString stringWithFormat: @"%hhu.%hhu", _protocolVersion.major, _protocolVersion.minor]; } -- (OFString *)string +- (OFString *)readString { - return [self stringWithEncoding: OF_STRING_ENCODING_AUTODETECT]; + return [self readStringWithEncoding: OFStringEncodingAutodetect]; } -- (OFString *)stringWithEncoding: (of_string_encoding_t)encoding +- (OFString *)readStringWithEncoding: (OFStringEncoding)encoding { void *pool = objc_autoreleasePoolPush(); OFString *contentType, *contentLengthString, *ret; OFData *data; - if (encoding == OF_STRING_ENCODING_AUTODETECT && + if (encoding == OFStringEncodingAutodetect && (contentType = [_headers objectForKey: @"Content-Type"]) != nil) encoding = encodingForContentType(contentType); - if (encoding == OF_STRING_ENCODING_AUTODETECT) - encoding = OF_STRING_ENCODING_UTF_8; + if (encoding == OFStringEncodingAutodetect) + encoding = OFStringEncodingUTF8; data = [self readDataUntilEndOfStream]; contentLengthString = [_headers objectForKey: @"Content-Length"]; if (contentLengthString != nil) { Index: src/OFHTTPServer.h ================================================================== --- src/OFHTTPServer.h +++ src/OFHTTPServer.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -64,11 +62,12 @@ */ - (bool)server: (OFHTTPServer *)server didReceiveExceptionOnListeningSocket: (id)exception; /** - * @brief This method is called when a client socket encountered an exception. + * @brief This method is called when a socket for a client encountered an + * exception. * * This can happen when the OFHTTPServer tries to properly close the * connection. If no headers have been sent yet, it will send headers, and if * chunked transfer encoding was used, it will send a chunk of size 0. However, * if the other end already closed the connection before that, this will raise @@ -93,13 +92,10 @@ OF_SUBCLASSING_RESTRICTED @interface OFHTTPServer: OFObject { OFString *_Nullable _host; uint16_t _port; - bool _usesTLS; - OFString *_Nullable _certificateFile, *_Nullable _privateKeyFile; - const char *_Nullable _privateKeyPassphrase; id _Nullable _delegate; OFString *_Nullable _name; OFTCPSocket *_Nullable _listeningSocket; #ifdef OF_HAVE_THREADS size_t _numberOfThreads, _nextThreadIndex; @@ -121,46 +117,10 @@ * Setting this after @ref start has been called raises an * @ref OFAlreadyConnectedException. */ @property (nonatomic) uint16_t port; -/** - * @brief Whether the HTTP server uses TLS. - * - * Setting this after @ref start has been called raises an - * @ref OFAlreadyConnectedException. - */ -@property (nonatomic) bool usesTLS; - -/** - * @brief The path to the X.509 certificate file to use for TLS. - * - * Setting this after @ref start has been called raises an - * @ref OFAlreadyConnectedException. - */ -@property OF_NULLABLE_PROPERTY (copy, nonatomic) OFString *certificateFile; - -/** - * @brief The path to the PKCS#8 private key file to use for TLS. - * - * Setting this after @ref start has been called raises an - * @ref OFAlreadyConnectedException. - */ -@property OF_NULLABLE_PROPERTY (copy, nonatomic) OFString *privateKeyFile; - -/** - * @brief The passphrase to decrypt the PKCS#8 private key file for TLS. - * - * @warning You have to ensure that this is in secure memory protected from - * swapping! This is also the reason why this is not an OFString. - * - * Setting this after @ref start has been called raises an - * @ref OFAlreadyConnectedException. - */ -@property OF_NULLABLE_PROPERTY (assign, nonatomic) - const char *privateKeyPassphrase; - /** * @brief The delegate for the HTTP server. */ @property OF_NULLABLE_PROPERTY (assign, nonatomic) id delegate; Index: src/OFHTTPServer.m ================================================================== --- src/OFHTTPServer.m +++ src/OFHTTPServer.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -15,10 +13,11 @@ * file. */ #include "config.h" +#include #include #include #import "OFHTTPServer.h" #import "OFArray.h" @@ -26,12 +25,12 @@ #import "OFDate.h" #import "OFDictionary.h" #import "OFHTTPRequest.h" #import "OFHTTPResponse.h" #import "OFNumber.h" +#import "OFSocket+Private.h" #import "OFTCPSocket.h" -#import "OFTLSSocket.h" #import "OFThread.h" #import "OFTimer.h" #import "OFURL.h" #import "OFAlreadyConnectedException.h" @@ -43,14 +42,10 @@ #import "OFOutOfRangeException.h" #import "OFTruncatedDataException.h" #import "OFUnsupportedProtocolException.h" #import "OFWriteFailedException.h" -#import "socket_helpers.h" - -#define BUFFER_SIZE 1024 - /* * FIXME: Key normalization replaces headers like "DNT" with "Dnt". * FIXME: Errors are not reported to the user. */ @@ -77,16 +72,16 @@ @public OFStreamSocket *_socket; OFHTTPServer *_server; OFTimer *_timer; enum { - AWAITING_PROLOG, - PARSING_HEADERS, - SEND_RESPONSE + stateAwaitingProlog, + stateParsingHeaders, + stateSendResponse } _state; uint8_t _HTTPMinorVersion; - of_http_request_method_t _method; + OFHTTPRequestMethod _method; OFString *_host, *_path; uint16_t _port; OFMutableDictionary *_headers; size_t _contentLength; OFStream *_requestBody; @@ -119,38 +114,41 @@ @interface OFHTTPServerThread: OFThread - (void)stop; @end #endif -static OF_INLINE OFString * +static OFString * normalizedKey(OFString *key) { - char *cString = of_strdup(key.UTF8String); + char *cString = OFStrDup(key.UTF8String); unsigned char *tmp = (unsigned char *)cString; bool firstLetter = true; - - if (cString == NULL) - @throw [OFOutOfMemoryException - exceptionWithRequestedSize: strlen(key.UTF8String)]; + OFString *ret; while (*tmp != '\0') { - if (!of_ascii_isalpha(*tmp)) { + if (!OFASCIIIsAlpha(*tmp)) { firstLetter = true; tmp++; continue; } *tmp = (firstLetter - ? of_ascii_toupper(*tmp) - : of_ascii_tolower(*tmp)); + ? OFASCIIToUpper(*tmp) : OFASCIIToLower(*tmp)); firstLetter = false; tmp++; } - return [OFString stringWithUTF8StringNoCopy: cString - freeWhenDone: true]; + @try { + ret = [OFString stringWithUTF8StringNoCopy: cString + freeWhenDone: true]; + } @catch (id e) { + OFFreeMemory(cString); + @throw e; + } + + return ret; } @implementation OFHTTPServerResponse - (instancetype)initWithSocket: (OFStreamSocket *)sock server: (OFHTTPServer *)server @@ -184,28 +182,25 @@ OFEnumerator *keyEnumerator, *valueEnumerator; OFString *key, *value; [_socket writeFormat: @"HTTP/%@ %hd %@\r\n", self.protocolVersionString, _statusCode, - of_http_status_code_to_string(_statusCode)]; + OFHTTPStatusCodeString(_statusCode)]; headers = [[_headers mutableCopy] autorelease]; if ([headers objectForKey: @"Date"] == nil) { OFString *date = [[OFDate date] dateStringWithFormat: @"%a, %d %b %Y %H:%M:%S GMT"]; - - [headers setObject: date - forKey: @"Date"]; + [headers setObject: date forKey: @"Date"]; } if ([headers objectForKey: @"Server"] == nil) { OFString *name = _server.name; if (name != nil) - [headers setObject: name - forKey: @"Server"]; + [headers setObject: name forKey: @"Server"]; } keyEnumerator = [headers keyEnumerator]; valueEnumerator = [headers objectEnumerator]; while ((key = [keyEnumerator nextObject]) != nil && @@ -219,12 +214,11 @@ isEqual: @"chunked"]; objc_autoreleasePoolPop(pool); } -- (size_t)lowlevelWriteBuffer: (const void *)buffer - length: (size_t)length +- (size_t)lowlevelWriteBuffer: (const void *)buffer length: (size_t)length { /* TODO: Use non-blocking writes */ void *pool; @@ -232,20 +226,28 @@ @throw [OFNotOpenException exceptionWithObject: self]; if (!_headersSent) [self of_sendHeaders]; - if (!_chunked) - return [_socket writeBuffer: buffer - length: length]; + if (!_chunked) { + @try { + [_socket writeBuffer: buffer length: length]; + } @catch (OFWriteFailedException *e) { + if (e.errNo == EWOULDBLOCK || e.errNo == EAGAIN) + return e.bytesWritten; + + @throw e; + } + + return length; + } pool = objc_autoreleasePoolPush(); [_socket writeString: [OFString stringWithFormat: @"%zX\r\n", length]]; objc_autoreleasePoolPop(pool); - [_socket writeBuffer: buffer - length: length]; + [_socket writeBuffer: buffer length: length]; [_socket writeString: @"\r\n"]; return length; } @@ -299,11 +301,11 @@ scheduledTimerWithTimeInterval: 10 target: _socket selector: @selector( cancelAsyncRequests) repeats: false] retain]; - _state = AWAITING_PROLOG; + _state = stateAwaitingProlog; } @catch (id e) { [self release]; @throw e; } @@ -333,22 +335,22 @@ if (line == nil || exception != nil) return false; @try { switch (_state) { - case AWAITING_PROLOG: + case stateAwaitingProlog: return [self parseProlog: line]; - case PARSING_HEADERS: + case stateParsingHeaders: return [self parseHeaders: line]; default: return false; } } @catch (OFWriteFailedException *e) { return false; } - OF_ENSURE(0); + OFEnsure(0); } - (bool)parseProlog: (OFString *)line { OFString *method; @@ -355,12 +357,12 @@ OFMutableString *path; size_t pos; @try { OFString *version = [line - substringWithRange: of_range(line.length - 9, 9)]; - of_unichar_t tmp; + substringWithRange: OFRangeMake(line.length - 9, 9)]; + OFUnichar tmp; if (![version hasPrefix: @" HTTP/1."]) return [self sendErrorAndClose: 505]; tmp = [version characterAtIndex: 8]; @@ -371,22 +373,22 @@ } @catch (OFOutOfRangeException *e) { return [self sendErrorAndClose: 400]; } pos = [line rangeOfString: @" "].location; - if (pos == OF_NOT_FOUND) + if (pos == OFNotFound) return [self sendErrorAndClose: 400]; method = [line substringToIndex: pos]; @try { - _method = of_http_request_method_from_string(method); + _method = OFHTTPRequestMethodParseName(method); } @catch (OFInvalidArgumentException *e) { return [self sendErrorAndClose: 405]; } @try { - of_range_t range = of_range(pos + 1, line.length - pos - 10); + OFRange range = OFRangeMake(pos + 1, line.length - pos - 10); path = [[[line substringWithRange: range] mutableCopy] autorelease]; } @catch (OFOutOfRangeException *e) { return [self sendErrorAndClose: 400]; @@ -398,11 +400,11 @@ if (![path hasPrefix: @"/"]) return [self sendErrorAndClose: 400]; _headers = [[OFMutableDictionary alloc] init]; _path = [path copy]; - _state = PARSING_HEADERS; + _state = stateParsingHeaders; return true; } - (bool)parseHeaders: (OFString *)line @@ -440,18 +442,18 @@ [_timer invalidate]; [_timer release]; _timer = nil; } - _state = SEND_RESPONSE; + _state = stateSendResponse; [self createResponse]; return false; } pos = [line rangeOfString: @":"].location; - if (pos == OF_NOT_FOUND) + if (pos == OFNotFound) return [self sendErrorAndClose: 400]; key = [line substringToIndex: pos]; value = [line substringFromIndex: pos + 1]; @@ -460,19 +462,17 @@ old = [_headers objectForKey: key]; if (old != nil) value = [old stringByAppendingFormat: @",%@", value]; - [_headers setObject: value - forKey: key]; + [_headers setObject: value forKey: key]; if ([key isEqual: @"Host"]) { - pos = [value - rangeOfString: @":" - options: OF_STRING_SEARCH_BACKWARDS].location; + pos = [value rangeOfString: @":" + options: OFStringSearchBackwards].location; - if (pos != OF_NOT_FOUND) { + if (pos != OFNotFound) { [_host release]; _host = [[value substringToIndex: pos] retain]; @try { unsigned long long portTmp = @@ -498,19 +498,16 @@ - (bool)sendErrorAndClose: (short)statusCode { OFString *date = [[OFDate date] dateStringWithFormat: @"%a, %d %b %Y %H:%M:%S GMT"]; - [_socket writeFormat: @"HTTP/1.1 %hd %@\r\n" @"Date: %@\r\n" @"Server: %@\r\n" @"\r\n", - statusCode, - of_http_status_code_to_string(statusCode), + statusCode, OFHTTPStatusCodeString(statusCode), date, _server.name]; - return false; } - (void)createResponse { @@ -539,27 +536,34 @@ URL.scheme = @"http"; URL.host = _host; if (_port != 80) URL.port = [OFNumber numberWithUnsignedShort: _port]; - if ((pos = [_path rangeOfString: @"?"].location) != OF_NOT_FOUND) { - OFString *path, *query; - - path = [_path substringToIndex: pos]; - query = [_path substringFromIndex: pos + 1]; - - URL.URLEncodedPath = path; - URL.URLEncodedQuery = query; - } else - URL.URLEncodedPath = _path; + @try { + if ((pos = [_path rangeOfString: @"?"].location) != + OFNotFound) { + OFString *path, *query; + + path = [_path substringToIndex: pos]; + query = [_path substringFromIndex: pos + 1]; + + URL.URLEncodedPath = path; + URL.URLEncodedQuery = query; + } else + URL.URLEncodedPath = _path; + } @catch (OFInvalidFormatException *e) { + objc_autoreleasePoolPop(pool); + [self sendErrorAndClose: 400]; + return; + } [URL makeImmutable]; request = [OFHTTPRequest requestWithURL: URL]; request.method = _method; request.protocolVersion = - (of_http_request_protocol_version_t){ 1, _HTTPMinorVersion }; + (OFHTTPRequestProtocolVersion){ 1, _HTTPMinorVersion }; request.headers = _headers; request.remoteAddress = _socket.remoteAddress; response = [[[OFHTTPServerResponse alloc] initWithSocket: _socket @@ -611,12 +615,11 @@ - (bool)lowlevelIsAtEndOfStream { return _atEndOfStream; } -- (size_t)lowlevelReadIntoBuffer: (void *)buffer - length: (size_t)length +- (size_t)lowlevelReadIntoBuffer: (void *)buffer length: (size_t)length { if (_socket == nil) @throw [OFNotOpenException exceptionWithObject: self]; if (_atEndOfStream) @@ -630,12 +633,11 @@ size_t ret; if (length > (unsigned long long)_toRead) length = (size_t)_toRead; - ret = [_socket readIntoBuffer: buffer - length: length]; + ret = [_socket readIntoBuffer: buffer length: length]; _toRead -= ret; if (_toRead == 0) _atEndOfStream = true; @@ -645,12 +647,11 @@ /* Chunked */ if (_toRead == -2) { char tmp[2]; - switch ([_socket readIntoBuffer: tmp - length: 2]) { + switch ([_socket readIntoBuffer: tmp length: 2]) { case 2: _toRead++; if (tmp[1] != '\n') @throw [OFInvalidFormatException exception]; case 1: @@ -664,12 +665,11 @@ return 0; } else if (_toRead == -1) { char tmp; - if ([_socket readIntoBuffer: &tmp - length: 1] == 1) { + if ([_socket readIntoBuffer: &tmp length: 1] == 1) { _toRead++; if (tmp != '\n') @throw [OFInvalidFormatException exception]; } @@ -679,15 +679,13 @@ return 0; } else if (_toRead > 0) { if (length > (unsigned long long)_toRead) length = (size_t)_toRead; - length = [_socket readIntoBuffer: buffer - length: length]; + length = [_socket readIntoBuffer: buffer length: length]; _toRead -= length; - if (_toRead == 0) _toRead = -2; return length; } else { @@ -704,19 +702,19 @@ if (line == nil) return 0; pos = [line rangeOfString: @";"].location; - if (pos != OF_NOT_FOUND) + if (pos != OFNotFound) line = [line substringToIndex: pos]; if (line.length < 1) { /* * We have read the empty string because the socket is * at end of stream. */ - if (_socket.atEndOfStream && pos == OF_NOT_FOUND) + if (_socket.atEndOfStream && pos == OFNotFound) @throw [OFTruncatedDataException exception]; else @throw [OFInvalidFormatException exception]; } @@ -828,70 +826,10 @@ - (uint16_t)port { return _port; } -- (void)setUsesTLS: (bool)usesTLS -{ - if (_listeningSocket != nil) - @throw [OFAlreadyConnectedException exception]; - - _usesTLS = usesTLS; -} - -- (bool)usesTLS -{ - return _usesTLS; -} - -- (void)setCertificateFile: (OFString *)certificateFile -{ - OFString *old; - - if (_listeningSocket != nil) - @throw [OFAlreadyConnectedException exception]; - - old = _certificateFile; - _certificateFile = [certificateFile copy]; - [old release]; -} - -- (OFString *)certificateFile -{ - return _certificateFile; -} - -- (void)setPrivateKeyFile: (OFString *)privateKeyFile -{ - OFString *old; - - if (_listeningSocket != nil) - @throw [OFAlreadyConnectedException exception]; - - old = _privateKeyFile; - _privateKeyFile = [privateKeyFile copy]; - [old release]; -} - -- (OFString *)privateKeyFile -{ - return _privateKeyFile; -} - -- (void)setPrivateKeyPassphrase: (const char *)privateKeyPassphrase -{ - if (_listeningSocket != nil) - @throw [OFAlreadyConnectedException exception]; - - _privateKeyPassphrase = privateKeyPassphrase; -} - -- (const char *)privateKeyPassphrase -{ - return _privateKeyPassphrase; -} - #ifdef OF_HAVE_THREADS - (void)setNumberOfThreads: (size_t)numberOfThreads { if (numberOfThreads == 0) @throw [OFInvalidArgumentException exception]; @@ -916,27 +854,12 @@ @throw [OFInvalidArgumentException exception]; if (_listeningSocket != nil) @throw [OFAlreadyConnectedException exception]; - if (_usesTLS) { - OFTCPSocket *TLSSocket; - - if (of_tls_socket_class == Nil) - @throw [OFUnsupportedProtocolException exception]; - - TLSSocket = [[of_tls_socket_class alloc] init]; - _listeningSocket = TLSSocket; - - TLSSocket.certificateFile = _certificateFile; - TLSSocket.privateKeyFile = _privateKeyFile; - TLSSocket.privateKeyPassphrase = _privateKeyPassphrase; - } else - _listeningSocket = [[OFTCPSocket alloc] init]; - - _port = [_listeningSocket bindToHost: _host - port: _port]; + _listeningSocket = [[OFTCPSocket alloc] init]; + _port = [_listeningSocket bindToHost: _host port: _port]; [_listeningSocket listen]; #ifdef OF_HAVE_THREADS if (_numberOfThreads > 1) { OFMutableArray *threads = @@ -994,11 +917,11 @@ if (exception != nil) { if (![_delegate respondsToSelector: @selector(server:didReceiveExceptionOnListeningSocket:)]) return false; - return [_delegate server: self + return [_delegate server: self didReceiveExceptionOnListeningSocket: exception]; } #ifdef OF_HAVE_THREADS if (_numberOfThreads > 1) { Index: src/OFHTTPURLHandler.h ================================================================== --- src/OFHTTPURLHandler.h +++ src/OFHTTPURLHandler.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFHTTPURLHandler.m ================================================================== --- src/OFHTTPURLHandler.m +++ src/OFHTTPURLHandler.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFHostAddressResolver.h ================================================================== --- src/OFHostAddressResolver.h +++ src/OFHostAddressResolver.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -16,12 +14,11 @@ */ #import "OFObject.h" #import "OFDNSResolver.h" #import "OFRunLoop.h" - -#import "socket.h" +#import "OFSocket.h" OF_ASSUME_NONNULL_BEGIN @class OFDNSResolverSettings; @class OFDNSResourceRecord; @@ -30,27 +27,27 @@ @class OFString; @interface OFHostAddressResolver: OFObject { OFString *_host; - of_socket_address_family_t _addressFamily; + OFSocketAddressFamily _addressFamily; OFDNSResolver *_resolver; OFDNSResolverSettings *_settings; - of_run_loop_mode_t _Nullable _runLoopMode; + OFRunLoopMode _Nullable _runLoopMode; id _Nullable _delegate; bool _isFQDN; size_t _searchDomainIndex; unsigned int _numExpectedResponses; OFMutableData *_addresses; } - (instancetype)initWithHost: (OFString *)host - addressFamily: (of_socket_address_family_t)addressFamily + addressFamily: (OFSocketAddressFamily)addressFamily resolver: (OFDNSResolver *)resolver settings: (OFDNSResolverSettings *)settings - runLoopMode: (nullable of_run_loop_mode_t)runLoopMode + runLoopMode: (nullable OFRunLoopMode)runLoopMode delegate: (nullable id )delegate; - (void)asyncResolve; - (OFData *)resolve; @end OF_ASSUME_NONNULL_END Index: src/OFHostAddressResolver.m ================================================================== --- src/OFHostAddressResolver.m +++ src/OFHostAddressResolver.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -40,12 +38,12 @@ OFData *_addresses; id _exception; } @end -static const of_run_loop_mode_t resolveRunLoopMode = - @"of_host_address_resolver_resolve_mode"; +static const OFRunLoopMode resolveRunLoopMode = + @"OFHostAddressResolverResolveRunLoopMode"; static bool isFQDN(OFString *host, unsigned int minNumberOfDotsInAbsoluteName) { const char *UTF8String; @@ -66,24 +64,23 @@ return (dots >= minNumberOfDotsInAbsoluteName); } static bool addressForRecord(OF_KINDOF(OFDNSResourceRecord *) record, - const of_socket_address_t **address, - of_socket_address_family_t addressFamily) + const OFSocketAddress **address, OFSocketAddressFamily addressFamily) { switch ([record recordType]) { #ifdef OF_HAVE_IPV6 - case OF_DNS_RECORD_TYPE_AAAA: - if (addressFamily != OF_SOCKET_ADDRESS_FAMILY_IPV6 && - addressFamily != OF_SOCKET_ADDRESS_FAMILY_ANY) + case OFDNSRecordTypeAAAA: + if (addressFamily != OFSocketAddressFamilyIPv6 && + addressFamily != OFSocketAddressFamilyAny) return false; break; #endif - case OF_DNS_RECORD_TYPE_A: - if (addressFamily != OF_SOCKET_ADDRESS_FAMILY_IPV4 && - addressFamily != OF_SOCKET_ADDRESS_FAMILY_ANY) + case OFDNSRecordTypeA: + if (addressFamily != OFSocketAddressFamilyIPv4 && + addressFamily != OFSocketAddressFamilyAny) return false; break; default: return false; } @@ -91,11 +88,11 @@ *address = [record address]; return true; } static void -callDelegateInMode(of_run_loop_mode_t runLoopMode, +callDelegateInMode(OFRunLoopMode runLoopMode, id delegate, OFDNSResolver *resolver, OFString *host, OFData *addresses, id exception) { SEL selector = @selector(resolver:didResolveHost:addresses:exception:); @@ -114,14 +111,14 @@ } } @implementation OFHostAddressResolver: OFObject - (instancetype)initWithHost: (OFString *)host - addressFamily: (of_socket_address_family_t)addressFamily + addressFamily: (OFSocketAddressFamily)addressFamily resolver: (OFDNSResolver *)resolver settings: (OFDNSResolverSettings *)settings - runLoopMode: (of_run_loop_mode_t)runLoopMode + runLoopMode: (OFRunLoopMode)runLoopMode delegate: (id )delegate { self = [super init]; @try { @@ -163,29 +160,29 @@ _host, searchDomain]; } else domainName = _host; #ifdef OF_HAVE_IPV6 - if (_addressFamily == OF_SOCKET_ADDRESS_FAMILY_IPV6 || - _addressFamily == OF_SOCKET_ADDRESS_FAMILY_ANY) { + if (_addressFamily == OFSocketAddressFamilyIPv6 || + _addressFamily == OFSocketAddressFamilyAny) { OFDNSQuery *query = [OFDNSQuery queryWithDomainName: domainName - DNSClass: OF_DNS_CLASS_IN - recordType: OF_DNS_RECORD_TYPE_AAAA]; + DNSClass: OFDNSClassIN + recordType: OFDNSRecordTypeAAAA]; _numExpectedResponses++; [_resolver asyncPerformQuery: query runLoopMode: _runLoopMode delegate: self]; } #endif - if (_addressFamily == OF_SOCKET_ADDRESS_FAMILY_IPV4 || - _addressFamily == OF_SOCKET_ADDRESS_FAMILY_ANY) { + if (_addressFamily == OFSocketAddressFamilyIPv4 || + _addressFamily == OFSocketAddressFamilyAny) { OFDNSQuery *query = [OFDNSQuery queryWithDomainName: domainName - DNSClass: OF_DNS_CLASS_IN - recordType: OF_DNS_RECORD_TYPE_A]; + DNSClass: OFDNSClassIN + recordType: OFDNSRecordTypeA]; _numExpectedResponses++; [_resolver asyncPerformQuery: query runLoopMode: _runLoopMode delegate: self]; } @@ -197,37 +194,37 @@ exception: (id)exception { _numExpectedResponses--; if ([exception isKindOfClass: [OFDNSQueryFailedException class]] && - [exception error] == OF_DNS_RESOLVER_ERROR_SERVER_NAME_ERROR && + [exception errorCode] == OFDNSResolverErrorCodeServerNameError && !_isFQDN && _numExpectedResponses == 0 && _addresses.count == 0 && _searchDomainIndex + 1 < _settings->_searchDomains.count) { _searchDomainIndex++; [self sendQueries]; return; } for (OF_KINDOF(OFDNSResourceRecord *) record in [response.answerRecords objectForKey: query.domainName]) { - const of_socket_address_t *address = NULL; + const OFSocketAddress *address = NULL; OFDNSQuery *CNAMEQuery; - if ([record DNSClass] != OF_DNS_CLASS_IN) + if ([record DNSClass] != OFDNSClassIN) continue; if (addressForRecord(record, &address, _addressFamily)) { [_addresses addItem: address]; continue; } - if ([record recordType] != OF_DNS_RECORD_TYPE_CNAME) + if ([record recordType] != OFDNSRecordTypeCNAME) continue; /* FIXME: Check if it's already in answers */ CNAMEQuery = [OFDNSQuery queryWithDomainName: [record alias] - DNSClass: OF_DNS_CLASS_IN + DNSClass: OFDNSClassIN recordType: query.recordType]; _numExpectedResponses++; [_resolver asyncPerformQuery: CNAMEQuery runLoopMode: _runLoopMode delegate: self]; @@ -245,17 +242,17 @@ if ([exception isKindOfClass: [OFDNSQueryFailedException class]]) exception = [OFResolveHostFailedException exceptionWithHost: _host addressFamily: _addressFamily - error: [exception error]]; + errorCode: [exception errorCode]]; if (exception == nil) exception = [OFResolveHostFailedException exceptionWithHost: _host addressFamily: _addressFamily - error: OF_DNS_RESOLVER_ERROR_NO_RESULT]; + errorCode: OFDNSResolverErrorCodeNoResult]; } else exception = nil; if ([_delegate respondsToSelector: @selector(resolver:didResolveHost:addresses:exception:)]) @@ -269,20 +266,19 @@ { void *pool = objc_autoreleasePoolPush(); OFArray OF_GENERIC(OFString *) *aliases; @try { - of_socket_address_t address = - of_socket_address_parse_ip(_host, 0); + OFSocketAddress address = OFSocketAddressParseIP(_host, 0); OFData *addresses = nil; id exception = nil; if (_addressFamily == address.family || - _addressFamily == OF_SOCKET_ADDRESS_FAMILY_ANY) + _addressFamily == OFSocketAddressFamilyAny) addresses = [OFData dataWithItems: &address - itemSize: sizeof(address) - count: 1]; + count: 1 + itemSize: sizeof(address)]; else exception = [OFInvalidArgumentException exception]; callDelegateInMode(_runLoopMode, _delegate, _resolver, _host, addresses, exception); @@ -292,24 +288,24 @@ } @catch (OFInvalidFormatException *e) { } if ((aliases = [_settings->_staticHosts objectForKey: _host]) != nil) { OFMutableData *addresses = [OFMutableData - dataWithItemSize: sizeof(of_socket_address_t)]; + dataWithItemSize: sizeof(OFSocketAddress)]; id exception = nil; for (OFString *alias in aliases) { - of_socket_address_t address; + OFSocketAddress address; @try { - address = of_socket_address_parse_ip(alias, 0); + address = OFSocketAddressParseIP(alias, 0); } @catch (OFInvalidFormatException *e) { continue; } if (_addressFamily != address.family && - _addressFamily != OF_SOCKET_ADDRESS_FAMILY_ANY) + _addressFamily != OFSocketAddressFamilyAny) continue; [addresses addItem: &address]; } @@ -318,11 +314,11 @@ if (addresses.count == 0) { addresses = nil; exception = [OFResolveHostFailedException exceptionWithHost: _host addressFamily: _addressFamily - error: OF_DNS_RESOLVER_ERROR_NO_RESULT]; + errorCode: OFDNSResolverErrorCodeNoResult]; } callDelegateInMode(_runLoopMode, _delegate, _resolver, _host, addresses, exception); @@ -330,11 +326,11 @@ return; } _isFQDN = isFQDN(_host, _settings->_minNumberOfDotsInAbsoluteName); _addresses = [[OFMutableData alloc] - initWithItemSize: sizeof(of_socket_address_t)]; + initWithItemSize: sizeof(OFSocketAddress)]; [self sendQueries]; objc_autoreleasePoolPop(pool); } @@ -351,24 +347,20 @@ _delegate = [delegate retain]; [self asyncResolve]; while (!delegate->_done) - [runLoop runMode: resolveRunLoopMode - beforeDate: nil]; + [runLoop runMode: resolveRunLoopMode beforeDate: nil]; /* Cleanup */ - [runLoop runMode: resolveRunLoopMode - beforeDate: [OFDate date]]; + [runLoop runMode: resolveRunLoopMode beforeDate: [OFDate date]]; if (delegate->_exception != nil) @throw delegate->_exception; ret = [delegate->_addresses copy]; - objc_autoreleasePoolPop(pool); - return [ret autorelease]; } @end @implementation OFHostAddressResolverDelegate ADDED src/OFHuffmanTree.h Index: src/OFHuffmanTree.h ================================================================== --- /dev/null +++ src/OFHuffmanTree.h @@ -0,0 +1,66 @@ +/* + * 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 +#include + +#import "macros.h" + +#import "OFInvalidFormatException.h" + +OF_ASSUME_NONNULL_BEGIN + +typedef struct _OFHuffmanTree { + struct _OFHuffmanTree *_Nullable leaves[2]; + uint16_t value; +} *OFHuffmanTree; + +/* Inlined for performance. */ +static OF_INLINE bool +OFHuffmanTreeWalk(id _Nullable stream, + bool (*bitReader)(id _Nullable, uint16_t *_Nonnull, uint8_t), + OFHuffmanTree _Nonnull *_Nonnull tree, uint16_t *_Nonnull value) +{ + OFHuffmanTree iter = *tree; + uint16_t bits; + + while (iter->value == 0xFFFF) { + if OF_UNLIKELY (!bitReader(stream, &bits, 1)) { + *tree = iter; + return false; + } + + if OF_UNLIKELY (iter->leaves[bits] == NULL) + @throw [OFInvalidFormatException exception]; + + iter = iter->leaves[bits]; + } + + *value = iter->value; + return true; +} + +#ifdef __cplusplus +extern "C" { +#endif +extern OFHuffmanTree _Nonnull OFHuffmanTreeNew(uint8_t lengths[_Nonnull], + uint16_t count); +extern OFHuffmanTree _Nonnull OFHuffmanTreeNewSingle(uint16_t value); +extern void OFHuffmanTreeFree(OFHuffmanTree _Nonnull tree); +#ifdef __cplusplus +} +#endif + +OF_ASSUME_NONNULL_END ADDED src/OFHuffmanTree.m Index: src/OFHuffmanTree.m ================================================================== --- /dev/null +++ src/OFHuffmanTree.m @@ -0,0 +1,129 @@ +/* + * 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 "OFHuffmanTree.h" + +#import "OFInvalidFormatException.h" +#import "OFOutOfMemoryException.h" + +static OFHuffmanTree +newTree(void) +{ + OFHuffmanTree tree; + + tree = OFAllocMemory(1, sizeof(*tree)); + tree->leaves[0] = tree->leaves[1] = NULL; + tree->value = 0xFFFF; + + return tree; +} + +static void +treeInsert(OFHuffmanTree tree, uint16_t code, uint8_t length, uint16_t value) +{ + while (length > 0) { + uint8_t bit; + + length--; + bit = (code & (1u << length)) >> length; + + if (tree->leaves[bit] == NULL) + tree->leaves[bit] = newTree(); + + tree = tree->leaves[bit]; + } + + tree->value = value; +} + +OFHuffmanTree +OFHuffmanTreeNew(uint8_t lengths[], uint16_t count) +{ + OFHuffmanTree tree; + uint16_t *lengthCount = NULL; + uint16_t code, maxCode = 0, *nextCode = NULL; + uint_fast8_t maxBit = 0; + + @try { + for (uint16_t i = 0; i < count; i++) { + uint_fast8_t length = lengths[i]; + + if OF_UNLIKELY (length > maxBit) { + lengthCount = OFResizeMemory(lengthCount, + length + 1, sizeof(uint16_t)); + nextCode = OFResizeMemory(nextCode, + length + 1, sizeof(uint16_t)); + + for (uint_fast8_t j = maxBit + 1; j <= length; + j++) { + lengthCount[j] = 0; + nextCode[j] = 0; + } + + maxBit = length; + } + + if (length > 0) { + lengthCount[length]++; + maxCode = i; + } + } + + code = 0; + for (size_t i = 1; i <= maxBit; i++) { + code = (code + lengthCount[i - 1]) << 1; + nextCode[i] = code; + } + + tree = newTree(); + + for (uint16_t i = 0; i <= maxCode; i++) { + uint8_t length = lengths[i]; + + if (length > 0) + treeInsert(tree, nextCode[length]++, length, i); + } + } @finally { + OFFreeMemory(lengthCount); + OFFreeMemory(nextCode); + } + + return tree; +} + +OFHuffmanTree +OFHuffmanTreeNewSingle(uint16_t value) +{ + OFHuffmanTree tree = newTree(); + + tree->value = value; + + return tree; +} + +void +OFHuffmanTreeFree(OFHuffmanTree tree) +{ + for (uint_fast8_t i = 0; i < 2; i++) + if OF_LIKELY (tree->leaves[i] != NULL) + OFHuffmanTreeFree(tree->leaves[i]); + + OFFreeMemory(tree); +} Index: src/OFINICategory+Private.h ================================================================== --- src/OFINICategory+Private.h +++ src/OFINICategory+Private.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -25,10 +23,10 @@ OF_DIRECT_MEMBERS @interface OFINICategory () - (instancetype)of_initWithName: (OFString *)name OF_METHOD_FAMILY(init); - (void)of_parseLine: (OFString *)line; - (bool)of_writeToStream: (OFStream *)stream - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding first: (bool)first; @end OF_ASSUME_NONNULL_END Index: src/OFINICategory.h ================================================================== --- src/OFINICategory.h +++ src/OFINICategory.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -41,191 +39,183 @@ @property (copy, nonatomic) OFString *name; - (instancetype)init OF_UNAVAILABLE; /** - * @brief Returns the string value for the specified key, or `nil` if it does - * not exist. - * - * If the specified key is a multi-key (see @ref arrayForKey:), the value of - * the first key/value pair found is returned. - * - * @param key The key for which the string value should be returned - * @return The string value for the specified key, or `nil` if it does not exist + * @brief Returns the string for the specified key, or `nil` if it does not + * exist. + * + * If the specified key is a multi-key (see @ref stringArrayForKey:), the value + * of the first key/value pair found is returned. + * + * @param key The key for which the string should be returned + * @return The string for the specified key, or `nil` if it does not exist */ - (nullable OFString *)stringForKey: (OFString *)key; /** - * @brief Returns the string value for the specified key or the specified - * default value if it does not exist. + * @brief Returns the string for the specified key or the specified default + * value if it does not exist. * - * If the specified key is a multi-key (see @ref arrayForKey:), the value of - * the first key/value pair found is returned. + * If the specified key is a multi-key (see @ref stringArrayForKey:), the value + * of the first key/value pair found is returned. * - * @param key The key for which the string value should be returned + * @param key The key for which the string should be returned * @param defaultValue The value to return if the key does not exist - * @return The string value for the specified key or the specified default - * value if it does not exist + * @return The string for the specified key or the specified default value if + * it does not exist */ - (nullable OFString *)stringForKey: (OFString *)key defaultValue: (nullable OFString *)defaultValue; /** - * @brief Returns the integer value for the specified key or the specified - * default value if it does not exist. - * - * If the specified key is a multi-key (see @ref arrayForKey:), the value of - * the first key/value pair found is returned. - * - * @param key The key for which the integer value should be returned - * @param defaultValue The value to return if the key does not exist - * @return The integer value for the specified key or the specified default - * value if it does not exist - */ -- (long long)integerForKey: (OFString *)key - defaultValue: (long long)defaultValue; - -/** - * @brief Returns the bool value for the specified key or the specified default - * value if it does not exist. - * - * If the specified key is a multi-key (see @ref arrayForKey:), the value of - * the first key/value pair found is returned. - * - * @param key The key for which the bool value should be returned - * @param defaultValue The value to return if the key does not exist - * @return The bool value for the specified key or the specified default value - * if it does not exist - */ -- (bool)boolForKey: (OFString *)key - defaultValue: (bool)defaultValue; - -/** - * @brief Returns the float value for the specified key or the specified - * default value if it does not exist. - * - * If the specified key is a multi-key (see @ref arrayForKey:), the value of - * the first key/value pair found is returned. - * - * @param key The key for which the float value should be returned - * @param defaultValue The value to return if the key does not exist - * @return The float value for the specified key or the specified default value - * if it does not exist - */ -- (float)floatForKey: (OFString *)key - defaultValue: (float)defaultValue; - -/** - * @brief Returns the double value for the specified key or the specified - * default value if it does not exist. - * - * If the specified key is a multi-key (see @ref arrayForKey:), the value of - * the first key/value pair found is returned. - * - * @param key The key for which the double value should be returned - * @param defaultValue The value to return if the key does not exist - * @return The double value for the specified key or the specified default - * value if it does not exist - */ -- (double)doubleForKey: (OFString *)key - defaultValue: (double)defaultValue; - -/** - * @brief Returns an array of string values for the specified multi-key, or an - * empty array if the key does not exist. + * @brief Returns the long long for the specified key or the specified default + * value if it does not exist. + * + * If the specified key is a multi-key (see @ref stringArrayForKey:), the value + * of the first key/value pair found is returned. + * + * @param key The key for which the long long should be returned + * @param defaultValue The value to return if the key does not exist + * @return The long long for the specified key or the specified default value + * if it does not exist + */ +- (long long)longLongForKey: (OFString *)key + defaultValue: (long long)defaultValue; + +/** + * @brief Returns the bool for the specified key or the specified default value + * if it does not exist. + * + * If the specified key is a multi-key (see @ref stringArrayForKey:), the value + * of the first key/value pair found is returned. + * + * @param key The key for which the bool should be returned + * @param defaultValue The value to return if the key does not exist + * @return The bool for the specified key or the specified default value if it + * does not exist + */ +- (bool)boolForKey: (OFString *)key defaultValue: (bool)defaultValue; + +/** + * @brief Returns the float for the specified key or the specified default + * value if it does not exist. + * + * If the specified key is a multi-key (see @ref stringArrayForKey:), the value + * of the first key/value pair found is returned. + * + * @param key The key for which the float should be returned + * @param defaultValue The value to return if the key does not exist + * @return The float for the specified key or the specified default value if it + * does not exist + */ +- (float)floatForKey: (OFString *)key defaultValue: (float)defaultValue; + +/** + * @brief Returns the double for the specified key or the specified default + * value if it does not exist. + * + * If the specified key is a multi-key (see @ref stringArrayForKey:), the value + * of the first key/value pair found is returned. + * + * @param key The key for which the double should be returned + * @param defaultValue The value to return if the key does not exist + * @return The double for the specified key or the specified default value if + * it does not exist + */ +- (double)doubleForKey: (OFString *)key defaultValue: (double)defaultValue; + +/** + * @brief Returns an array of strings for the specified multi-key, or an empty + * array if the key does not exist. * * A multi-key is a key which exists several times in the same category. Each * occurrence of the key/value pair adds the respective value to the array. * * @param key The multi-key for which the array should be returned * @return The array for the specified key, or an empty array if it does not * exist */ -- (OFArray OF_GENERIC(OFString *) *)arrayForKey: (OFString *)key; +- (OFArray OF_GENERIC(OFString *) *)stringArrayForKey: (OFString *)key; /** * @brief Sets the value of the specified key to the specified string. * - * If the specified key is a multi-key (see @ref arrayForKey:), the value of - * the first key/value pair found is changed. + * If the specified key is a multi-key (see @ref stringArrayForKey:), the value + * of the first key/value pair found is changed. * - * @param string The string to which the value of the key should be set + * @param string The string to which the key should be set * @param key The key for which the new value should be set */ -- (void)setString: (OFString *)string - forKey: (OFString *)key; +- (void)setString: (OFString *)string forKey: (OFString *)key; /** - * @brief Sets the value of the specified key to the specified integer. + * @brief Sets the value of the specified key to the specified long long. * - * If the specified key is a multi-key (see @ref arrayForKey:), the value of - * the first key/value pair found is changed. + * If the specified key is a multi-key (see @ref stringArrayForKey:), the value + * of the first key/value pair found is changed. * - * @param integer The integer to which the value of the key should be set + * @param longLong The long long to which the key should be set * @param key The key for which the new value should be set */ -- (void)setInteger: (long long)integer - forKey: (OFString *)key; +- (void)setLongLong: (long long)longLong forKey: (OFString *)key; /** * @brief Sets the value of the specified key to the specified bool. * - * If the specified key is a multi-key (see @ref arrayForKey:), the value of - * the first key/value pair found is changed. + * If the specified key is a multi-key (see @ref stringArrayForKey:), the value + * of the first key/value pair found is changed. * - * @param bool_ The bool to which the value of the key should be set + * @param bool_ The bool to which the key should be set * @param key The key for which the new value should be set */ -- (void)setBool: (bool)bool_ - forKey: (OFString *)key; +- (void)setBool: (bool)bool_ forKey: (OFString *)key; /** * @brief Sets the value of the specified key to the specified float. * - * If the specified key is a multi-key (see @ref arrayForKey:), the value of - * the first key/value pair found is changed. + * If the specified key is a multi-key (see @ref stringArrayForKey:), the value + * of the first key/value pair found is changed. * - * @param float_ The float to which the value of the key should be set + * @param float_ The float to which the key should be set * @param key The key for which the new value should be set */ -- (void)setFloat: (float)float_ - forKey: (OFString *)key; +- (void)setFloat: (float)float_ forKey: (OFString *)key; /** * @brief Sets the value of the specified key to the specified double. * - * If the specified key is a multi-key (see @ref arrayForKey:), the value of - * the first key/value pair found is changed. + * If the specified key is a multi-key (see @ref stringArrayForKey:), the value + * of the first key/value pair found is changed. * - * @param double_ The double to which the value of the key should be set + * @param double_ The double to which the key should be set * @param key The key for which the new value should be set */ -- (void)setDouble: (double)double_ - forKey: (OFString *)key; +- (void)setDouble: (double)double_ forKey: (OFString *)key; /** * @brief Sets the specified multi-key to the specified array of strings. * * It replaces the first occurrence of the multi-key with several key/value * pairs and removes all following occurrences. If the multi-key does not exist * yet, it is appended to the section. * - * See also @ref arrayForKey: for more information about multi-keys. + * See also @ref stringArrayForKey: for more information about multi-keys. * * @param array The array of strings to which the multi-key should be set * @param key The multi-key for which the new values should be set */ -- (void)setArray: (OFArray OF_GENERIC(OFString *) *)array - forKey: (OFString *)key; +- (void)setStringArray: (OFArray OF_GENERIC(OFString *) *)array + forKey: (OFString *)key; /** * @brief Removes the value for the specified key * - * If the specified key is a multi-key (see @ref arrayForKey:), all key/value - * pairs matching the specified key are removed. + * If the specified key is a multi-key (see @ref stringArrayForKey:), all + * key/value pairs matching the specified key are removed. * * @param key The key of the value to remove */ - (void)removeValueForKey: (OFString *)key; @end OF_ASSUME_NONNULL_END Index: src/OFINICategory.m ================================================================== --- src/OFINICategory.m +++ src/OFINICategory.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -52,20 +50,15 @@ ![string containsString: @"\""]) return string; mutableString = [[string mutableCopy] autorelease]; - [mutableString replaceOccurrencesOfString: @"\\" - withString: @"\\\\"]; - [mutableString replaceOccurrencesOfString: @"\f" - withString: @"\\f"]; - [mutableString replaceOccurrencesOfString: @"\r" - withString: @"\\r"]; - [mutableString replaceOccurrencesOfString: @"\n" - withString: @"\\n"]; - [mutableString replaceOccurrencesOfString: @"\"" - withString: @"\\\""]; + [mutableString replaceOccurrencesOfString: @"\\" withString: @"\\\\"]; + [mutableString replaceOccurrencesOfString: @"\f" withString: @"\\f"]; + [mutableString replaceOccurrencesOfString: @"\r" withString: @"\\r"]; + [mutableString replaceOccurrencesOfString: @"\n" withString: @"\\n"]; + [mutableString replaceOccurrencesOfString: @"\"" withString: @"\\\""]; [mutableString prependString: @"\""]; [mutableString appendString: @"\""]; [mutableString makeImmutable]; @@ -79,23 +72,18 @@ OFMutableString *mutableString; if (![string hasPrefix: @"\""] || ![string hasSuffix: @"\""]) return string; - string = [string substringWithRange: of_range(1, string.length - 2)]; + string = [string substringWithRange: OFRangeMake(1, string.length - 2)]; mutableString = [[string mutableCopy] autorelease]; - [mutableString replaceOccurrencesOfString: @"\\f" - withString: @"\f"]; - [mutableString replaceOccurrencesOfString: @"\\r" - withString: @"\r"]; - [mutableString replaceOccurrencesOfString: @"\\n" - withString: @"\n"]; - [mutableString replaceOccurrencesOfString: @"\\\"" - withString: @"\""]; - [mutableString replaceOccurrencesOfString: @"\\\\" - withString: @"\\"]; + [mutableString replaceOccurrencesOfString: @"\\f" withString: @"\f"]; + [mutableString replaceOccurrencesOfString: @"\\r" withString: @"\r"]; + [mutableString replaceOccurrencesOfString: @"\\n" withString: @"\n"]; + [mutableString replaceOccurrencesOfString: @"\\\"" withString: @"\""]; + [mutableString replaceOccurrencesOfString: @"\\\\" withString: @"\\"]; [mutableString makeImmutable]; return mutableString; } @@ -106,19 +94,29 @@ [_key release]; [_value release]; [super dealloc]; } + +- (OFString *)description +{ + return [OFString stringWithFormat: @"%@ = %@", _key, _value]; +} @end @implementation OFINICategoryComment - (void)dealloc { [_comment release]; [super dealloc]; } + +- (OFString *)description +{ + return [[_comment copy] autorelease]; +} @end @implementation OFINICategory @synthesize name = _name; @@ -156,11 +154,11 @@ OFINICategoryPair *pair = [[[OFINICategoryPair alloc] init] autorelease]; OFString *key, *value; size_t pos; - if ((pos = [line rangeOfString: @"="].location) == OF_NOT_FOUND) + if ((pos = [line rangeOfString: @"="].location) == OFNotFound) @throw [OFInvalidFormatException exception]; key = unescapeString([line substringToIndex: pos] .stringByDeletingEnclosingWhitespaces); value = unescapeString([line substringFromIndex: pos + 1] @@ -180,12 +178,11 @@ } } - (OFString *)stringForKey: (OFString *)key { - return [self stringForKey: key - defaultValue: nil]; + return [self stringForKey: key defaultValue: nil]; } - (OFString *)stringForKey: (OFString *)key defaultValue: (OFString *)defaultValue { @@ -202,16 +199,15 @@ } return defaultValue; } -- (long long)integerForKey: (OFString *)key - defaultValue: (long long)defaultValue +- (long long)longLongForKey: (OFString *)key + defaultValue: (long long)defaultValue { void *pool = objc_autoreleasePoolPush(); - OFString *value = [self stringForKey: key - defaultValue: nil]; + OFString *value = [self stringForKey: key defaultValue: nil]; long long ret; if (value != nil) ret = [value longLongValueWithBase: 0]; else @@ -220,16 +216,14 @@ objc_autoreleasePoolPop(pool); return ret; } -- (bool)boolForKey: (OFString *)key - defaultValue: (bool)defaultValue +- (bool)boolForKey: (OFString *)key defaultValue: (bool)defaultValue { void *pool = objc_autoreleasePoolPush(); - OFString *value = [self stringForKey: key - defaultValue: nil]; + OFString *value = [self stringForKey: key defaultValue: nil]; bool ret; if (value != nil) { if ([value isEqual: @"true"]) ret = true; @@ -243,16 +237,14 @@ objc_autoreleasePoolPop(pool); return ret; } -- (float)floatForKey: (OFString *)key - defaultValue: (float)defaultValue +- (float)floatForKey: (OFString *)key defaultValue: (float)defaultValue { void *pool = objc_autoreleasePoolPush(); - OFString *value = [self stringForKey: key - defaultValue: nil]; + OFString *value = [self stringForKey: key defaultValue: nil]; float ret; if (value != nil) ret = value.floatValue; else @@ -261,16 +253,14 @@ objc_autoreleasePoolPop(pool); return ret; } -- (double)doubleForKey: (OFString *)key - defaultValue: (double)defaultValue +- (double)doubleForKey: (OFString *)key defaultValue: (double)defaultValue { void *pool = objc_autoreleasePoolPush(); - OFString *value = [self stringForKey: key - defaultValue: nil]; + OFString *value = [self stringForKey: key defaultValue: nil]; double ret; if (value != nil) ret = value.doubleValue; else @@ -279,11 +269,11 @@ objc_autoreleasePoolPop(pool); return ret; } -- (OFArray *)arrayForKey: (OFString *)key +- (OFArray OF_GENERIC(OFString *) *)stringArrayForKey: (OFString *)key { OFMutableArray *ret = [OFMutableArray array]; void *pool = objc_autoreleasePoolPush(); for (id line in _lines) { @@ -303,12 +293,11 @@ [ret makeImmutable]; return ret; } -- (void)setString: (OFString *)string - forKey: (OFString *)key +- (void)setString: (OFString *)string forKey: (OFString *)key { void *pool = objc_autoreleasePoolPush(); OFINICategoryPair *pair; for (id line in _lines) { @@ -344,52 +333,47 @@ } objc_autoreleasePoolPop(pool); } -- (void)setInteger: (long long)integer - forKey: (OFString *)key +- (void)setLongLong: (long long)longLong forKey: (OFString *)key { void *pool = objc_autoreleasePoolPush(); - [self setString: [OFString stringWithFormat: @"%lld", integer] + [self setString: [OFString stringWithFormat: @"%lld", longLong] forKey: key]; objc_autoreleasePoolPop(pool); } -- (void)setBool: (bool)bool_ - forKey: (OFString *)key +- (void)setBool: (bool)bool_ forKey: (OFString *)key { - [self setString: (bool_ ? @"true" : @"false") - forKey: key]; + [self setString: (bool_ ? @"true" : @"false") forKey: key]; } -- (void)setFloat: (float)float_ - forKey: (OFString *)key +- (void)setFloat: (float)float_ forKey: (OFString *)key { void *pool = objc_autoreleasePoolPush(); [self setString: [OFString stringWithFormat: @"%g", float_] forKey: key]; objc_autoreleasePoolPop(pool); } -- (void)setDouble: (double)double_ - forKey: (OFString *)key +- (void)setDouble: (double)double_ forKey: (OFString *)key { void *pool = objc_autoreleasePoolPush(); [self setString: [OFString stringWithFormat: @"%g", double_] forKey: key]; objc_autoreleasePoolPop(pool); } -- (void)setArray: (OFArray *)array - forKey: (OFString *)key +- (void)setStringArray: (OFArray OF_GENERIC(OFString *) *)array + forKey: (OFString *)key { void *pool; OFMutableArray *pairs; id const *lines; size_t count; @@ -402,19 +386,19 @@ pool = objc_autoreleasePoolPush(); pairs = [OFMutableArray arrayWithCapacity: array.count]; - for (id object in array) { + for (OFString *string in array) { OFINICategoryPair *pair; - if (![object isKindOfClass: [OFString class]]) + if (![string isKindOfClass: [OFString class]]) @throw [OFInvalidArgumentException exception]; pair = [[[OFINICategoryPair alloc] init] autorelease]; pair->_key = [key copy]; - pair->_value = [object copy]; + pair->_value = [string copy]; [pairs addObject: pair]; } lines = _lines.objects; @@ -482,11 +466,11 @@ objc_autoreleasePoolPop(pool); } - (bool)of_writeToStream: (OFStream *)stream - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding first: (bool)first { if (_lines.count == 0) return false; @@ -503,15 +487,19 @@ OFINICategoryPair *pair = line; OFString *key = escapeString(pair->_key); OFString *value = escapeString(pair->_value); OFString *tmp = [OFString stringWithFormat: @"%@=%@\r\n", key, value]; - - [stream writeString: tmp - encoding: encoding]; + [stream writeString: tmp encoding: encoding]; } else @throw [OFInvalidArgumentException exception]; } return true; } + +- (OFString *)description +{ + return [OFString stringWithFormat: @"<%@ \"%@\": %@>", + self.class, _name, _lines]; +} @end Index: src/OFINIFile.h ================================================================== --- src/OFINIFile.h +++ src/OFINIFile.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -32,10 +30,15 @@ @interface OFINIFile: OFObject { OFMutableArray OF_GENERIC(OFINICategory *) *_categories; } +/** + * @brief All categories in the INI file. + */ +@property (readonly, nonatomic) OFArray OF_GENERIC(OFINICategory *) *categories; + /** * @brief Creates a new OFINIFile with the contents of the specified file. * * @param path The path to the file whose contents the OFINIFile should contain * @@ -51,11 +54,11 @@ * @param encoding The encoding of the specified file * * @return A new, autoreleased OFINIFile with the contents of the specified file */ + (instancetype)fileWithPath: (OFString *)path - encoding: (of_string_encoding_t)encoding; + encoding: (OFStringEncoding)encoding; - (instancetype)init OF_UNAVAILABLE; /** * @brief Initializes an already allocated OFINIFile with the contents of the @@ -75,11 +78,11 @@ * @param encoding The encoding of the specified file * * @return An initialized OFINIFile with the contents of the specified file */ - (instancetype)initWithPath: (OFString *)path - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding OF_DESIGNATED_INITIALIZER; /** * @brief Returns an @ref OFINICategory for the category with the specified * name. @@ -103,10 +106,9 @@ * encoding. * * @param path The path of the file to write to * @param encoding The encoding to use */ -- (void)writeToFile: (OFString *)path - encoding: (of_string_encoding_t)encoding; +- (void)writeToFile: (OFString *)path encoding: (OFStringEncoding)encoding; @end OF_ASSUME_NONNULL_END Index: src/OFINIFile.m ================================================================== --- src/OFINIFile.m +++ src/OFINIFile.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -29,35 +27,36 @@ #import "OFInvalidFormatException.h" #import "OFOpenItemFailedException.h" OF_DIRECT_MEMBERS @interface OFINIFile () -- (void)of_parseFile: (OFString *)path - encoding: (of_string_encoding_t)encoding; +- (void)of_parseFile: (OFString *)path encoding: (OFStringEncoding)encoding; @end static bool isWhitespaceLine(OFString *line) { const char *cString = line.UTF8String; size_t length = line.UTF8StringLength; for (size_t i = 0; i < length; i++) - if (!of_ascii_isspace(cString[i])) + if (!OFASCIIIsSpace(cString[i])) return false; return true; } @implementation OFINIFile +@synthesize categories = _categories; + + (instancetype)fileWithPath: (OFString *)path { return [[[self alloc] initWithPath: path] autorelease]; } + (instancetype)fileWithPath: (OFString *)path - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding { return [[[self alloc] initWithPath: path encoding: encoding] autorelease]; } @@ -66,24 +65,22 @@ OF_INVALID_INIT_METHOD } - (instancetype)initWithPath: (OFString *)path { - return [self initWithPath: path - encoding: OF_STRING_ENCODING_UTF_8]; + return [self initWithPath: path encoding: OFStringEncodingUTF8]; } - (instancetype)initWithPath: (OFString *)path - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding { self = [super init]; @try { _categories = [[OFMutableArray alloc] init]; - [self of_parseFile: path - encoding: encoding]; + [self of_parseFile: path encoding: encoding]; } @catch (id e) { [self release]; @throw e; } @@ -112,21 +109,19 @@ objc_autoreleasePoolPop(pool); return category; } -- (void)of_parseFile: (OFString *)path - encoding: (of_string_encoding_t)encoding +- (void)of_parseFile: (OFString *)path encoding: (OFStringEncoding)encoding { void *pool = objc_autoreleasePoolPush(); OFFile *file; OFINICategory *category = nil; OFString *line; @try { - file = [OFFile fileWithPath: path - mode: @"r"]; + file = [OFFile fileWithPath: path mode: @"r"]; } @catch (OFOpenItemFailedException *e) { /* Handle missing file like an empty file */ if (e.errNo == ENOENT) return; @@ -142,12 +137,11 @@ if (![line hasSuffix: @"]"]) @throw [OFInvalidFormatException exception]; categoryName = [line substringWithRange: - of_range(1, line.length - 2)]; - + OFRangeMake(1, line.length - 2)]; category = [[[OFINICategory alloc] of_initWithName: categoryName] autorelease]; [_categories addObject: category]; } else { if (category == nil) @@ -160,20 +154,17 @@ objc_autoreleasePoolPop(pool); } - (void)writeToFile: (OFString *)path { - [self writeToFile: path - encoding: OF_STRING_ENCODING_UTF_8]; + [self writeToFile: path encoding: OFStringEncodingUTF8]; } -- (void)writeToFile: (OFString *)path - encoding: (of_string_encoding_t)encoding +- (void)writeToFile: (OFString *)path encoding: (OFStringEncoding)encoding { void *pool = objc_autoreleasePoolPush(); - OFFile *file = [OFFile fileWithPath: path - mode: @"w"]; + OFFile *file = [OFFile fileWithPath: path mode: @"w"]; bool first = true; for (OFINICategory *category in _categories) if ([category of_writeToStream: file encoding: encoding @@ -180,6 +171,12 @@ first: first]) first = false; objc_autoreleasePoolPop(pool); } + +- (OFString *)description +{ + return [OFString stringWithFormat: @"<%@: %@>", + self.class, _categories]; +} @end Index: src/OFINIFileSettings.h ================================================================== --- src/OFINIFileSettings.h +++ src/OFINIFileSettings.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFINIFileSettings.m ================================================================== --- src/OFINIFileSettings.m +++ src/OFINIFileSettings.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -57,114 +55,87 @@ - (void)of_getCategory: (OFString **)category andKey: (OFString **)key forPath: (OFString *)path OF_DIRECT { size_t pos = [path rangeOfString: @"." - options: OF_STRING_SEARCH_BACKWARDS].location; + options: OFStringSearchBackwards].location; - if (pos == OF_NOT_FOUND) { + if (pos == OFNotFound) { *category = @""; *key = path; return; } *category = [path substringToIndex: pos]; *key = [path substringFromIndex: pos + 1]; } -- (void)setString: (OFString *)string - forPath: (OFString *)path -{ - void *pool = objc_autoreleasePoolPush(); - OFString *category, *key; - - [self of_getCategory: &category - andKey: &key - forPath: path]; - - [[_INIFile categoryForName: category] setString: string - forKey: key]; - - objc_autoreleasePoolPop(pool); -} - -- (void)setInteger: (long long)integer - forPath: (OFString *)path -{ - void *pool = objc_autoreleasePoolPush(); - OFString *category, *key; - - [self of_getCategory: &category - andKey: &key - forPath: path]; - - [[_INIFile categoryForName: category] setInteger: integer - forKey: key]; - - objc_autoreleasePoolPop(pool); -} - -- (void)setBool: (bool)bool_ - forPath: (OFString *)path -{ - void *pool = objc_autoreleasePoolPush(); - OFString *category, *key; - - [self of_getCategory: &category - andKey: &key - forPath: path]; - - [[_INIFile categoryForName: category] setBool: bool_ - forKey: key]; - - objc_autoreleasePoolPop(pool); -} - -- (void)setFloat: (float)float_ - forPath: (OFString *)path -{ - void *pool = objc_autoreleasePoolPush(); - OFString *category, *key; - - [self of_getCategory: &category - andKey: &key - forPath: path]; - - [[_INIFile categoryForName: category] setFloat: float_ - forKey: key]; - - objc_autoreleasePoolPop(pool); -} - -- (void)setDouble: (double)double_ - forPath: (OFString *)path -{ - void *pool = objc_autoreleasePoolPush(); - OFString *category, *key; - - [self of_getCategory: &category - andKey: &key - forPath: path]; - - [[_INIFile categoryForName: category] setDouble: double_ - forKey: key]; - - objc_autoreleasePoolPop(pool); -} - -- (void)setArray: (OFArray *)array - forPath: (OFString *)path -{ - void *pool = objc_autoreleasePoolPush(); - OFString *category, *key; - - [self of_getCategory: &category - andKey: &key - forPath: path]; - - [[_INIFile categoryForName: category] setArray: array - forKey: key]; +- (void)setString: (OFString *)string forPath: (OFString *)path +{ + void *pool = objc_autoreleasePoolPush(); + OFString *category, *key; + + [self of_getCategory: &category andKey: &key forPath: path]; + [[_INIFile categoryForName: category] setString: string forKey: key]; + + objc_autoreleasePoolPop(pool); +} + +- (void)setLongLong: (long long)longLong forPath: (OFString *)path +{ + void *pool = objc_autoreleasePoolPush(); + OFString *category, *key; + + [self of_getCategory: &category andKey: &key forPath: path]; + [[_INIFile categoryForName: category] setLongLong: longLong + forKey: key]; + + objc_autoreleasePoolPop(pool); +} + +- (void)setBool: (bool)bool_ forPath: (OFString *)path +{ + void *pool = objc_autoreleasePoolPush(); + OFString *category, *key; + + [self of_getCategory: &category andKey: &key forPath: path]; + [[_INIFile categoryForName: category] setBool: bool_ forKey: key]; + + objc_autoreleasePoolPop(pool); +} + +- (void)setFloat: (float)float_ forPath: (OFString *)path +{ + void *pool = objc_autoreleasePoolPush(); + OFString *category, *key; + + [self of_getCategory: &category andKey: &key forPath: path]; + [[_INIFile categoryForName: category] setFloat: float_ forKey: key]; + + objc_autoreleasePoolPop(pool); +} + +- (void)setDouble: (double)double_ forPath: (OFString *)path +{ + void *pool = objc_autoreleasePoolPush(); + OFString *category, *key; + + [self of_getCategory: &category andKey: &key forPath: path]; + [[_INIFile categoryForName: category] setDouble: double_ forKey: key]; + + objc_autoreleasePoolPop(pool); +} + +- (void)setStringArray: (OFArray OF_GENERIC(OFString *) *)array + forPath: (OFString *)path +{ + void *pool = objc_autoreleasePoolPush(); + OFString *category, *key; + + [self of_getCategory: &category andKey: &key forPath: path]; + [[_INIFile categoryForName: category] setStringArray: array + forKey: key]; objc_autoreleasePoolPop(pool); } - (OFString *)stringForPath: (OFString *)path @@ -171,110 +142,89 @@ defaultValue: (OFString *)defaultValue { void *pool = objc_autoreleasePoolPush(); OFString *category, *key, *ret; - [self of_getCategory: &category - andKey: &key - forPath: path]; - + [self of_getCategory: &category andKey: &key forPath: path]; ret = [[_INIFile categoryForName: category] stringForKey: key defaultValue: defaultValue]; [ret retain]; objc_autoreleasePoolPop(pool); return [ret autorelease]; } -- (long long)integerForPath: (OFString *)path - defaultValue: (long long)defaultValue +- (long long)longLongForPath: (OFString *)path + defaultValue: (long long)defaultValue { void *pool = objc_autoreleasePoolPush(); OFString *category, *key; long long ret; - [self of_getCategory: &category - andKey: &key - forPath: path]; - + [self of_getCategory: &category andKey: &key forPath: path]; ret = [[_INIFile categoryForName: category] - integerForKey: key - defaultValue: defaultValue]; + longLongForKey: key + defaultValue: defaultValue]; objc_autoreleasePoolPop(pool); return ret; } -- (bool)boolForPath: (OFString *)path - defaultValue: (bool)defaultValue +- (bool)boolForPath: (OFString *)path defaultValue: (bool)defaultValue { void *pool = objc_autoreleasePoolPush(); OFString *category, *key; bool ret; - [self of_getCategory: &category - andKey: &key - forPath: path]; - + [self of_getCategory: &category andKey: &key forPath: path]; ret = [[_INIFile categoryForName: category] boolForKey: key defaultValue: defaultValue]; objc_autoreleasePoolPop(pool); return ret; } -- (float)floatForPath: (OFString *)path - defaultValue: (float)defaultValue +- (float)floatForPath: (OFString *)path defaultValue: (float)defaultValue { void *pool = objc_autoreleasePoolPush(); OFString *category, *key; float ret; - [self of_getCategory: &category - andKey: &key - forPath: path]; - + [self of_getCategory: &category andKey: &key forPath: path]; ret = [[_INIFile categoryForName: category] floatForKey: key defaultValue: defaultValue]; objc_autoreleasePoolPop(pool); return ret; } -- (double)doubleForPath: (OFString *)path - defaultValue: (double)defaultValue +- (double)doubleForPath: (OFString *)path defaultValue: (double)defaultValue { void *pool = objc_autoreleasePoolPush(); OFString *category, *key; double ret; - [self of_getCategory: &category - andKey: &key - forPath: path]; - + [self of_getCategory: &category andKey: &key forPath: path]; ret = [[_INIFile categoryForName: category] doubleForKey: key defaultValue: defaultValue]; objc_autoreleasePoolPop(pool); return ret; } -- (OFArray *)arrayForPath: (OFString *)path +- (OFArray OF_GENERIC(OFString *) *)stringArrayForPath: (OFString *)path { void *pool = objc_autoreleasePoolPush(); OFString *category, *key; OFArray *ret; - [self of_getCategory: &category - andKey: &key - forPath: path]; - - ret = [[_INIFile categoryForName: category] arrayForKey: key]; + [self of_getCategory: &category andKey: &key forPath: path]; + ret = [[_INIFile categoryForName: category] stringArrayForKey: key]; [ret retain]; objc_autoreleasePoolPop(pool); return [ret autorelease]; } @@ -282,14 +232,11 @@ - (void)removeValueForPath: (OFString *)path { void *pool = objc_autoreleasePoolPush(); OFString *category, *key; - [self of_getCategory: &category - andKey: &key - forPath: path]; - + [self of_getCategory: &category andKey: &key forPath: path]; [[_INIFile categoryForName: category] removeValueForKey: key]; objc_autoreleasePoolPop(pool); } Index: src/OFIPSocketAsyncConnector.h ================================================================== --- src/OFIPSocketAsyncConnector.h +++ src/OFIPSocketAsyncConnector.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -20,13 +18,13 @@ #import "OFRunLoop+Private.h" OF_ASSUME_NONNULL_BEGIN @protocol OFIPSocketAsyncConnecting -- (bool)of_createSocketForAddress: (const of_socket_address_t *)address +- (bool)of_createSocketForAddress: (const OFSocketAddress *)address errNo: (int *)errNo; -- (bool)of_connectSocketToAddress: (const of_socket_address_t *)address +- (bool)of_connectSocketToAddress: (const OFSocketAddress *)address errNo: (int *)errNo; - (void)of_closeSocket; @end @interface OFIPSocketAsyncConnector: OFObject + * 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 @@ -19,13 +17,10 @@ #include #import "OFIPSocketAsyncConnector.h" #import "OFData.h" -#ifdef OF_HAVE_SCTP -# import "OFSCTPSocket.h" -#endif #import "OFTCPSocket.h" #import "OFThread.h" #import "OFTimer.h" #import "OFConnectionFailedException.h" @@ -72,19 +67,13 @@ [_socket setCanBlock: true]; #ifdef OF_HAVE_BLOCKS if (_block != NULL) { if ([_socket isKindOfClass: [OFTCPSocket class]]) - ((of_tcp_socket_async_connect_block_t)_block)( - _exception); -# ifdef OF_HAVE_SCTP - else if ([_socket isKindOfClass: [OFSCTPSocket class]]) - ((of_sctp_socket_async_connect_block_t)_block)( - _exception); -# endif + ((OFTCPSocketAsyncConnectBlock)_block)(_exception); else - OF_ENSURE(0); + OFEnsure(0); } else { #endif if ([_delegate respondsToSelector: @selector(socket:didConnectToHost:port:exception:)]) [_delegate socket: _socket @@ -94,12 +83,11 @@ #ifdef OF_HAVE_BLOCKS } #endif } -- (void)of_socketDidConnect: (id)sock - exception: (id)exception +- (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. @@ -125,12 +113,11 @@ timerWithTimeInterval: 0 target: self selector: selector object: runLoop.currentMode repeats: false]; - [runLoop addTimer: timer - forMode: runLoop.currentMode]; + [runLoop addTimer: timer forMode: runLoop.currentMode]; } return; } @@ -143,20 +130,19 @@ port: _port socket: _socket errNo: errNo]; } -- (void)tryNextAddressWithRunLoopMode: (of_run_loop_mode_t)runLoopMode +- (void)tryNextAddressWithRunLoopMode: (OFRunLoopMode)runLoopMode { - of_socket_address_t address = *(const of_socket_address_t *) + OFSocketAddress address = *(const OFSocketAddress *) [_socketAddresses itemAtIndex: _socketAddressesIndex++]; int errNo; - of_socket_address_set_port(&address, _port); + OFSocketAddressSetPort(&address, _port); - if (![_socket of_createSocketForAddress: &address - errNo: &errNo]) { + if (![_socket of_createSocketForAddress: &address errNo: &errNo]) { if (_socketAddressesIndex >= _socketAddresses.count) { _exception = [[OFConnectionFailedException alloc] initWithHost: _host port: _port socket: _socket @@ -183,14 +169,17 @@ [_socket setCanBlock: true]; #else [_socket setCanBlock: false]; #endif - if (![_socket of_connectSocketToAddress: &address - errNo: &errNo]) { + 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 { @@ -236,28 +225,27 @@ [self tryNextAddressWithRunLoopMode: [OFRunLoop currentRunLoop].currentMode]; } -- (void)startWithRunLoopMode: (of_run_loop_mode_t)runLoopMode +- (void)startWithRunLoopMode: (OFRunLoopMode)runLoopMode { @try { - of_socket_address_t address = - of_socket_address_parse_ip(_host, _port); + OFSocketAddress address = OFSocketAddressParseIP(_host, _port); _socketAddresses = [[OFData alloc] initWithItems: &address - itemSize: sizeof(address) - count: 1]; + count: 1 + itemSize: sizeof(address)]; [self tryNextAddressWithRunLoopMode: runLoopMode]; return; } @catch (OFInvalidFormatException *e) { } [[OFThread DNSResolver] asyncResolveAddressesForHost: _host - addressFamily: OF_SOCKET_ADDRESS_FAMILY_ANY + addressFamily: OFSocketAddressFamilyAny runLoopMode: runLoopMode delegate: self]; } @end Index: src/OFIPXSocket.h ================================================================== --- src/OFIPXSocket.h +++ src/OFIPXSocket.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -32,15 +30,15 @@ /** * @class OFIPXSocket OFIPXSocket.h ObjFW/OFIPXSocket.h * * @brief A class which provides methods to create and use IPX sockets. * - * Addresses are of type @ref of_socket_address_t. You can use - * @ref of_socket_address_ipx to create an address or - * @ref of_socket_address_get_ipx_network to get the IPX network, - * @ref of_socket_address_get_ipx_node to get the IPX node and - * @ref of_socket_address_get_port to get the port (sometimes also called + * 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 * 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, @@ -72,10 +70,9 @@ * @param port The port (sometimes called socket number) to bind to. 0 means to * pick one and return it. * @param packetType The packet type to use on the socket * @return The address on which this socket can be reached */ -- (of_socket_address_t)bindToPort: (uint16_t)port - packetType: (uint8_t)packetType; +- (OFSocketAddress)bindToPort: (uint16_t)port packetType: (uint8_t)packetType; @end OF_ASSUME_NONNULL_END Index: src/OFIPXSocket.m ================================================================== --- src/OFIPXSocket.m +++ src/OFIPXSocket.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -22,88 +20,86 @@ #ifdef HAVE_FCNTL_H # include #endif #import "OFIPXSocket.h" +#import "OFSocket.h" +#import "OFSocket+Private.h" #import "OFAlreadyConnectedException.h" #import "OFBindFailedException.h" -#import "socket.h" -#import "socket_helpers.h" - @implementation OFIPXSocket @dynamic delegate; -- (of_socket_address_t)bindToPort: (uint16_t)port - packetType: (uint8_t)packetType +- (OFSocketAddress)bindToPort: (uint16_t)port packetType: (uint8_t)packetType { const unsigned char zeroNode[IPX_NODE_LEN] = { 0 }; - of_socket_address_t address; + OFSocketAddress address; int protocol = 0; #if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL_H) && defined(FD_CLOEXEC) int flags; #endif - if (_socket != INVALID_SOCKET) + if (_socket != OFInvalidSocketHandle) @throw [OFAlreadyConnectedException exceptionWithSocket: self]; - address = of_socket_address_ipx(zeroNode, 0, port); + address = OFSocketAddressMakeIPX(zeroNode, 0, port); #ifdef OF_WINDOWS protocol = NSPROTO_IPX + packetType; #else _packetType = address.sockaddr.ipx.sipx_type = packetType; #endif if ((_socket = socket(address.sockaddr.sockaddr.sa_family, - SOCK_DGRAM | SOCK_CLOEXEC, protocol)) == INVALID_SOCKET) + SOCK_DGRAM | SOCK_CLOEXEC, protocol)) == OFInvalidSocketHandle) @throw [OFBindFailedException exceptionWithPort: port packetType: packetType socket: self - errNo: of_socket_errno()]; + 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, &address.sockaddr.sockaddr, address.length) != 0) { - int errNo = of_socket_errno(); + int errNo = OFSocketErrNo(); closesocket(_socket); - _socket = INVALID_SOCKET; + _socket = OFInvalidSocketHandle; @throw [OFBindFailedException exceptionWithPort: port packetType: packetType socket: self errNo: errNo]; } memset(&address, 0, sizeof(address)); - address.family = OF_SOCKET_ADDRESS_FAMILY_IPX; + address.family = OFSocketAddressFamilyIPX; address.length = (socklen_t)sizeof(address.sockaddr); - if (of_getsockname(_socket, &address.sockaddr.sockaddr, + if (OFGetSockName(_socket, &address.sockaddr.sockaddr, &address.length) != 0) { - int errNo = of_socket_errno(); + int errNo = OFSocketErrNo(); closesocket(_socket); - _socket = INVALID_SOCKET; + _socket = OFInvalidSocketHandle; @throw [OFBindFailedException exceptionWithPort: port packetType: packetType socket: self errNo: errNo]; } if (address.sockaddr.sockaddr.sa_family != AF_IPX) { closesocket(_socket); - _socket = INVALID_SOCKET; + _socket = OFInvalidSocketHandle; @throw [OFBindFailedException exceptionWithPort: port packetType: packetType socket: self errNo: EAFNOSUPPORT]; @@ -113,21 +109,19 @@ } #ifndef OF_WINDOWS - (void)sendBuffer: (const void *)buffer length: (size_t)length - receiver: (const of_socket_address_t *)receiver + receiver: (const OFSocketAddress *)receiver { - of_socket_address_t fixedReceiver; + OFSocketAddress fixedReceiver; memcpy(&fixedReceiver, receiver, sizeof(fixedReceiver)); /* If it's not IPX, no fix-up needed - it will fail anyway. */ - if (fixedReceiver.family == OF_SOCKET_ADDRESS_FAMILY_IPX) + if (fixedReceiver.family == OFSocketAddressFamilyIPX) fixedReceiver.sockaddr.ipx.sipx_type = _packetType; - [super sendBuffer: buffer - length: length - receiver: &fixedReceiver]; + [super sendBuffer: buffer length: length receiver: &fixedReceiver]; } #endif @end Index: src/OFInflate64Stream.h ================================================================== --- src/OFInflate64Stream.h +++ src/OFInflate64Stream.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -18,11 +16,11 @@ #import "OFStream.h" #import "OFKernelEventObserver.h" OF_ASSUME_NONNULL_BEGIN -#define OF_INFLATE64_STREAM_BUFFER_SIZE 4096 +#define OFInflate64StreamBufferSize 4096 /** * @class OFInflate64Stream OFInflate64Stream.h ObjFW/OFInflate64Stream.h * * @note This class only conforms to OFReadyForReadingObserving if the @@ -33,11 +31,11 @@ */ OF_SUBCLASSING_RESTRICTED @interface OFInflate64Stream: OFStream { OFStream *_stream; - unsigned char _buffer[OF_INFLATE64_STREAM_BUFFER_SIZE]; + unsigned char _buffer[OFInflate64StreamBufferSize]; uint16_t _bufferIndex, _bufferLength; uint8_t _byte; uint8_t _bitIndex, _savedBitsLength; uint16_t _savedBits; unsigned char *_Nullable _slidingWindow; @@ -50,23 +48,23 @@ } uncompressedHeader; struct { uint16_t position, length; } uncompressed; struct { - struct of_huffman_tree *_Nullable litLenTree; - struct of_huffman_tree *_Nullable distTree; - struct of_huffman_tree *_Nullable codeLenTree; - struct of_huffman_tree *_Nullable treeIter; + struct _OFHuffmanTree *_Nullable litLenTree; + struct _OFHuffmanTree *_Nullable distTree; + struct _OFHuffmanTree *_Nullable codeLenTree; + struct _OFHuffmanTree *_Nullable treeIter; uint8_t *_Nullable lengths; uint16_t receivedCount; uint8_t value, litLenCodesCount, distCodesCount; uint8_t codeLenCodesCount; } huffmanTree; struct { - struct of_huffman_tree *_Nullable litLenTree; - struct of_huffman_tree *_Nullable distTree; - struct of_huffman_tree *_Nullable treeIter; + struct _OFHuffmanTree *_Nullable litLenTree; + struct _OFHuffmanTree *_Nullable distTree; + struct _OFHuffmanTree *_Nullable treeIter; int state; uint16_t value, length, distance, extraBits; } huffman; } _context; bool _inLastBlock, _atEndOfStream; Index: src/OFInflate64Stream.m ================================================================== --- src/OFInflate64Stream.m +++ src/OFInflate64Stream.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFInflateStream.h ================================================================== --- src/OFInflateStream.h +++ src/OFInflateStream.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -18,11 +16,11 @@ #import "OFStream.h" #import "OFKernelEventObserver.h" OF_ASSUME_NONNULL_BEGIN -#define OF_INFLATE_STREAM_BUFFER_SIZE 4096 +#define OFInflateStreamBufferSize 4096 /** * @class OFInflateStream OFInflateStream.h ObjFW/OFInflateStream.h * * @note This class only conforms to OFReadyForReadingObserving if the @@ -33,11 +31,11 @@ */ OF_SUBCLASSING_RESTRICTED @interface OFInflateStream: OFStream { OFStream *_stream; - unsigned char _buffer[OF_INFLATE_STREAM_BUFFER_SIZE]; + unsigned char _buffer[OFInflateStreamBufferSize]; uint16_t _bufferIndex, _bufferLength; uint8_t _byte; uint8_t _bitIndex, _savedBitsLength; uint16_t _savedBits; unsigned char *_Nullable _slidingWindow; @@ -50,23 +48,23 @@ } uncompressedHeader; struct { uint16_t position, length; } uncompressed; struct { - struct of_huffman_tree *_Nullable litLenTree; - struct of_huffman_tree *_Nullable distTree; - struct of_huffman_tree *_Nullable codeLenTree; - struct of_huffman_tree *_Nullable treeIter; + struct _OFHuffmanTree *_Nullable litLenTree; + struct _OFHuffmanTree *_Nullable distTree; + struct _OFHuffmanTree *_Nullable codeLenTree; + struct _OFHuffmanTree *_Nullable treeIter; uint8_t *_Nullable lengths; uint16_t receivedCount; uint8_t value, litLenCodesCount, distCodesCount; uint8_t codeLenCodesCount; } huffmanTree; struct { - struct of_huffman_tree *_Nullable litLenTree; - struct of_huffman_tree *_Nullable distTree; - struct of_huffman_tree *_Nullable treeIter; + struct _OFHuffmanTree *_Nullable litLenTree; + struct _OFHuffmanTree *_Nullable distTree; + struct _OFHuffmanTree *_Nullable treeIter; int state; uint16_t value, length, distance, extraBits; } huffman; } _context; bool _inLastBlock, _atEndOfStream; Index: src/OFInflateStream.m ================================================================== --- src/OFInflateStream.m +++ src/OFInflateStream.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -26,39 +24,38 @@ # import "OFInflateStream.h" #else # import "OFInflate64Stream.h" # define OFInflateStream OFInflate64Stream #endif - -#import "huffman_tree.h" +#import "OFHuffmanTree.h" #import "OFInitializationFailedException.h" #import "OFInvalidFormatException.h" #import "OFNotOpenException.h" #import "OFOutOfMemoryException.h" #ifndef OF_INFLATE64_STREAM_M -# define BUFFER_SIZE OF_INFLATE_STREAM_BUFFER_SIZE +# define bufferSize OFInflateStreamBufferSize #else -# define BUFFER_SIZE OF_INFLATE64_STREAM_BUFFER_SIZE +# define bufferSize OFInflate64StreamBufferSize #endif -enum state { - BLOCK_HEADER, - UNCOMPRESSED_BLOCK_HEADER, - UNCOMPRESSED_BLOCK, - HUFFMAN_TREE, - HUFFMAN_BLOCK +enum State { + stateBlockHeader, + stateUncompressedBlockHeader, + stateUncompressedBlock, + stateHuffmanTree, + stateHuffmanBlock }; -enum huffman_state { - WRITE_VALUE, - AWAIT_CODE, - AWAIT_LENGTH_EXTRA_BITS, - AWAIT_DISTANCE, - AWAIT_DISTANCE_EXTRA_BITS, - PROCESS_PAIR +enum HuffmanState { + huffmanStateWriteValue, + huffmanStateAwaitCode, + huffmanStateAwaitLengthExtraBits, + huffmanStateAwaitDistance, + huffmanStateAwaitDistanceExtraBits, + huffmanStateProcessPair }; #ifndef OF_INFLATE64_STREAM_M static const uint8_t numDistanceCodes = 30; static const uint8_t lengthCodes[29] = { @@ -100,11 +97,11 @@ }; #endif static const uint8_t codeLengthsOrder[19] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; -static struct of_huffman_tree *fixedLitLenTree, *fixedDistTree; +static OFHuffmanTree fixedLitLenTree, fixedDistTree; @implementation OFInflateStream static OF_INLINE bool tryReadBits(OFInflateStream *stream, uint16_t *bits, uint8_t count) { @@ -119,11 +116,11 @@ stream->_byte = stream->_buffer[stream->_bufferIndex++]; else { size_t length = [stream->_stream readIntoBuffer: stream->_buffer - length: BUFFER_SIZE]; + length: bufferSize]; if OF_UNLIKELY (length < 1) { stream->_savedBits = ret; stream->_savedBitsLength = i; return false; @@ -161,16 +158,16 @@ for (uint16_t i = 256; i <= 279; i++) lengths[i] = 7; for (uint16_t i = 280; i <= 287; i++) lengths[i] = 8; - fixedLitLenTree = of_huffman_tree_construct(lengths, 288); + fixedLitLenTree = OFHuffmanTreeNew(lengths, 288); for (uint16_t i = 0; i <= 31; i++) lengths[i] = 5; - fixedDistTree = of_huffman_tree_construct(lengths, 32); + fixedDistTree = OFHuffmanTreeNew(lengths, 32); } + (instancetype)streamWithStream: (OFStream *)stream { return [[[self alloc] initWithStream: stream] autorelease]; @@ -194,12 +191,11 @@ #ifdef OF_INFLATE64_STREAM_M _slidingWindowMask = 0xFFFF; #else _slidingWindowMask = 0x7FFF; #endif - _slidingWindow = [self allocZeroedMemoryWithSize: - _slidingWindowMask + 1]; + _slidingWindow = OFAllocZeroedMemory(_slidingWindowMask + 1, 1); } @catch (id e) { [self release]; @throw e; } @@ -209,20 +205,24 @@ - (void)dealloc { if (_stream != nil) [self close]; - if (_state == HUFFMAN_TREE) + OFFreeMemory(_slidingWindow); + + if (_state == stateHuffmanTree) { + OFFreeMemory(_context.huffmanTree.lengths); + if (_context.huffmanTree.codeLenTree != NULL) - of_huffman_tree_release( - _context.huffmanTree.codeLenTree); + OFHuffmanTreeFree(_context.huffmanTree.codeLenTree); + } - if (_state == HUFFMAN_TREE || _state == HUFFMAN_BLOCK) { + if (_state == stateHuffmanTree || _state == stateHuffmanBlock) { if (_context.huffman.litLenTree != fixedLitLenTree) - of_huffman_tree_release(_context.huffman.litLenTree); + OFHuffmanTreeFree(_context.huffman.litLenTree); if (_context.huffman.distTree != fixedDistTree) - of_huffman_tree_release(_context.huffman.distTree); + OFHuffmanTreeFree(_context.huffman.distTree); } [super dealloc]; } @@ -240,12 +240,12 @@ if (_atEndOfStream) return 0; start: - switch ((enum state)_state) { - case BLOCK_HEADER: + switch ((enum State)_state) { + case stateBlockHeader: if OF_UNLIKELY (_inLastBlock) { [_stream unreadFromBuffer: _buffer + _bufferIndex length: _bufferLength - _bufferIndex]; _bufferIndex = _bufferLength = 0; @@ -259,24 +259,24 @@ _inLastBlock = (bits & 1); switch (bits >> 1) { case 0: /* No compression */ - _state = UNCOMPRESSED_BLOCK_HEADER; + _state = stateUncompressedBlockHeader; _bitIndex = 8; _context.uncompressedHeader.position = 0; memset(_context.uncompressedHeader.length, 0, 4); break; case 1: /* Fixed Huffman */ - _state = HUFFMAN_BLOCK; - _context.huffman.state = AWAIT_CODE; + _state = stateHuffmanBlock; + _context.huffman.state = huffmanStateAwaitCode; _context.huffman.litLenTree = fixedLitLenTree; _context.huffman.distTree = fixedDistTree; _context.huffman.treeIter = fixedLitLenTree; break; case 2: /* Dynamic Huffman */ - _state = HUFFMAN_TREE; + _state = stateHuffmanTree; _context.huffmanTree.lengths = NULL; _context.huffmanTree.receivedCount = 0; _context.huffmanTree.value = 0xFE; _context.huffmanTree.litLenCodesCount = 0xFF; _context.huffmanTree.distCodesCount = 0xFF; @@ -285,11 +285,11 @@ default: @throw [OFInvalidFormatException exception]; } goto start; - case UNCOMPRESSED_BLOCK_HEADER: + case stateUncompressedBlockHeader: #define CTX _context.uncompressedHeader /* FIXME: This can be done more efficiently than unreading */ [_stream unreadFromBuffer: _buffer + _bufferIndex length: _bufferLength - _bufferIndex]; _bufferIndex = _bufferLength = 0; @@ -303,11 +303,11 @@ if OF_UNLIKELY ((CTX.length[0] | (CTX.length[1] << 8)) != (uint16_t)~(CTX.length[2] | (CTX.length[3] << 8))) @throw [OFInvalidFormatException exception]; - _state = UNCOMPRESSED_BLOCK; + _state = stateUncompressedBlock; /* * Do not reorder! _context.uncompressed.position and * _context.uncompressedHeader.length overlap! */ @@ -315,11 +315,11 @@ CTX.length[0] | (CTX.length[1] << 8); _context.uncompressed.position = 0; goto start; #undef CTX - case UNCOMPRESSED_BLOCK: + case stateUncompressedBlock: #define CTX _context.uncompressed if OF_UNLIKELY (length == 0) return bytesWritten; tmp = (length < (size_t)CTX.length - CTX.position @@ -341,15 +341,15 @@ length -= tmp; bytesWritten += tmp; CTX.position += tmp; if OF_UNLIKELY (CTX.position == CTX.length) - _state = BLOCK_HEADER; + _state = stateBlockHeader; goto start; #undef CTX - case HUFFMAN_TREE: + case stateHuffmanTree: #define CTX _context.huffmanTree if OF_LIKELY (CTX.value == 0xFE) { if OF_LIKELY (CTX.litLenCodesCount == 0xFF) { if OF_UNLIKELY (!tryReadBits(self, &bits, 5)) return bytesWritten; @@ -374,12 +374,11 @@ CTX.codeLenCodesCount = bits; } if OF_LIKELY (CTX.lengths == NULL) - CTX.lengths = [self - allocZeroedMemoryWithSize: 19]; + CTX.lengths = OFAllocZeroedMemory(19, 1); for (uint16_t i = CTX.receivedCount; i < CTX.codeLenCodesCount + 4; i++) { if OF_UNLIKELY (!tryReadBits(self, &bits, 3)) { CTX.receivedCount = i; @@ -387,30 +386,29 @@ } CTX.lengths[codeLengthsOrder[i]] = bits; } - CTX.codeLenTree = of_huffman_tree_construct( - CTX.lengths, 19); + CTX.codeLenTree = OFHuffmanTreeNew(CTX.lengths, 19); CTX.treeIter = CTX.codeLenTree; - [self freeMemory: CTX.lengths]; + OFFreeMemory(CTX.lengths); CTX.lengths = NULL; CTX.receivedCount = 0; CTX.value = 0xFF; } if OF_LIKELY (CTX.lengths == NULL) - CTX.lengths = [self allocMemoryWithSize: - CTX.litLenCodesCount + CTX.distCodesCount + 258]; + CTX.lengths = OFAllocMemory( + CTX.litLenCodesCount + CTX.distCodesCount + 258, 1); for (uint16_t i = CTX.receivedCount; i < CTX.litLenCodesCount + CTX.distCodesCount + 258;) { uint8_t j, count; if OF_LIKELY (CTX.value == 0xFF) { - if OF_UNLIKELY (!of_huffman_tree_walk(self, + if OF_UNLIKELY (!OFHuffmanTreeWalk(self, tryReadBits, &CTX.treeIter, &value)) { CTX.receivedCount = i; return bytesWritten; } @@ -473,38 +471,38 @@ CTX.lengths[i++] = value; CTX.value = 0xFF; } - of_huffman_tree_release(CTX.codeLenTree); + OFHuffmanTreeFree(CTX.codeLenTree); CTX.codeLenTree = NULL; - CTX.litLenTree = of_huffman_tree_construct(CTX.lengths, + CTX.litLenTree = OFHuffmanTreeNew(CTX.lengths, CTX.litLenCodesCount + 257); - CTX.distTree = of_huffman_tree_construct( + CTX.distTree = OFHuffmanTreeNew( CTX.lengths + CTX.litLenCodesCount + 257, CTX.distCodesCount + 1); - [self freeMemory: CTX.lengths]; + OFFreeMemory(CTX.lengths); /* * litLenTree and distTree are at the same location in * _context.huffman and _context.huffmanTree, thus no need to * set them. */ - _state = HUFFMAN_BLOCK; - _context.huffman.state = AWAIT_CODE; + _state = stateHuffmanBlock; + _context.huffman.state = huffmanStateAwaitCode; _context.huffman.treeIter = CTX.litLenTree; goto start; #undef CTX - case HUFFMAN_BLOCK: + case stateHuffmanBlock: #define CTX _context.huffman for (;;) { uint8_t extraBits, lengthCodeIndex; - if OF_UNLIKELY (CTX.state == WRITE_VALUE) { + if OF_UNLIKELY (CTX.state == huffmanStateWriteValue) { if OF_UNLIKELY (length == 0) return bytesWritten; buffer[bytesWritten++] = CTX.value; length--; @@ -512,28 +510,29 @@ _slidingWindow[_slidingWindowIndex] = CTX.value; _slidingWindowIndex = (_slidingWindowIndex + 1) & _slidingWindowMask; - CTX.state = AWAIT_CODE; + CTX.state = huffmanStateAwaitCode; CTX.treeIter = CTX.litLenTree; } - if OF_UNLIKELY (CTX.state == AWAIT_LENGTH_EXTRA_BITS) { + if OF_UNLIKELY (CTX.state == + huffmanStateAwaitLengthExtraBits) { if OF_UNLIKELY (!tryReadBits(self, &bits, CTX.extraBits)) return bytesWritten; CTX.length += bits; - CTX.state = AWAIT_DISTANCE; + CTX.state = huffmanStateAwaitDistance; CTX.treeIter = CTX.distTree; } /* Distance of length distance pair */ - if (CTX.state == AWAIT_DISTANCE) { - if OF_UNLIKELY (!of_huffman_tree_walk(self, + if (CTX.state == huffmanStateAwaitDistance) { + if OF_UNLIKELY (!OFHuffmanTreeWalk(self, tryReadBits, &CTX.treeIter, &value)) return bytesWritten; if OF_UNLIKELY (value >= numDistanceCodes) @throw [OFInvalidFormatException @@ -543,32 +542,34 @@ extraBits = distanceExtraBits[value]; if (extraBits > 0) { if OF_UNLIKELY (!tryReadBits(self, &bits, extraBits)) { - CTX.state = - AWAIT_DISTANCE_EXTRA_BITS; +#define HSADEB huffmanStateAwaitDistanceExtraBits + CTX.state = HSADEB; +#undef HSADEB CTX.extraBits = extraBits; return bytesWritten; } CTX.distance += bits; } - CTX.state = PROCESS_PAIR; - } else if (CTX.state == AWAIT_DISTANCE_EXTRA_BITS) { + CTX.state = huffmanStateProcessPair; + } else if (CTX.state == + huffmanStateAwaitDistanceExtraBits) { if OF_UNLIKELY (!tryReadBits(self, &bits, CTX.extraBits)) return bytesWritten; CTX.distance += bits; - CTX.state = PROCESS_PAIR; + CTX.state = huffmanStateProcessPair; } /* Length distance pair */ - if (CTX.state == PROCESS_PAIR) { + if (CTX.state == huffmanStateProcessPair) { for (uint_fast16_t j = 0; j < CTX.length; j++) { uint16_t idx; if OF_UNLIKELY (length == 0) { CTX.length -= j; @@ -587,33 +588,33 @@ _slidingWindowIndex = (_slidingWindowIndex + 1) & _slidingWindowMask; } - CTX.state = AWAIT_CODE; + CTX.state = huffmanStateAwaitCode; CTX.treeIter = CTX.litLenTree; } - if OF_UNLIKELY (!of_huffman_tree_walk(self, tryReadBits, + if OF_UNLIKELY (!OFHuffmanTreeWalk(self, tryReadBits, &CTX.treeIter, &value)) return bytesWritten; /* End of block */ if OF_UNLIKELY (value == 256) { if (CTX.litLenTree != fixedLitLenTree) - of_huffman_tree_release(CTX.litLenTree); + OFHuffmanTreeFree(CTX.litLenTree); if (CTX.distTree != fixedDistTree) - of_huffman_tree_release(CTX.distTree); + OFHuffmanTreeFree(CTX.distTree); - _state = BLOCK_HEADER; + _state = stateBlockHeader; goto start; } /* Literal byte */ if OF_LIKELY (value < 256) { if OF_UNLIKELY (length == 0) { - CTX.state = WRITE_VALUE; + CTX.state = huffmanStateWriteValue; CTX.value = value; return bytesWritten; } buffer[bytesWritten++] = value; @@ -638,19 +639,20 @@ if (extraBits > 0) { if OF_UNLIKELY (!tryReadBits(self, &bits, extraBits)) { CTX.extraBits = extraBits; - CTX.state = AWAIT_LENGTH_EXTRA_BITS; + CTX.state = + huffmanStateAwaitLengthExtraBits; return bytesWritten; } CTX.length += bits; } CTX.treeIter = CTX.distTree; - CTX.state = AWAIT_DISTANCE; + CTX.state = huffmanStateAwaitDistance; } break; #undef CTX } Index: src/OFInvertedCharacterSet.h ================================================================== --- src/OFInvertedCharacterSet.h +++ src/OFInvertedCharacterSet.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -20,12 +18,12 @@ OF_ASSUME_NONNULL_BEGIN @interface OFInvertedCharacterSet: OFCharacterSet { OFCharacterSet *_characterSet; - bool (*_characterIsMember)(id, SEL, of_unichar_t); + bool (*_characterIsMember)(id, SEL, OFUnichar); } - (instancetype)initWithCharacterSet: (OFCharacterSet *)characterSet; @end OF_ASSUME_NONNULL_END Index: src/OFInvertedCharacterSet.m ================================================================== --- src/OFInvertedCharacterSet.m +++ src/OFInvertedCharacterSet.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -32,11 +30,11 @@ { self = [super init]; @try { _characterSet = [characterSet retain]; - _characterIsMember = (bool (*)(id, SEL, of_unichar_t)) + _characterIsMember = (bool (*)(id, SEL, OFUnichar)) [_characterSet methodForSelector: @selector(characterIsMember:)]; } @catch (id e) { [self release]; @throw e; @@ -50,11 +48,11 @@ [_characterSet release]; [super dealloc]; } -- (bool)characterIsMember: (of_unichar_t)character +- (bool)characterIsMember: (OFUnichar)character { return !_characterIsMember(_characterSet, @selector(characterIsMember:), character); } Index: src/OFInvocation.h ================================================================== --- src/OFInvocation.h +++ src/OFInvocation.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -17,22 +15,10 @@ #import "OFObject.h" OF_ASSUME_NONNULL_BEGIN -#ifdef OF_APPLE_RUNTIME -# ifdef OF_X86_64 -# define OF_INVOCATION_CAN_INVOKE -# endif -#else -# ifdef OF_ELF -# ifdef OF_X86_64 -# define OF_INVOCATION_CAN_INVOKE -# endif -# endif -#endif - @class OFMethodSignature; @class OFMutableArray OF_GENERIC(ObjectType); @class OFMutableData; /** @@ -74,21 +60,19 @@ * @brief Sets the argument for the specified index. * * @param buffer The buffer in which the argument is stored * @param index The index of the argument to set */ -- (void)setArgument: (const void *)buffer - atIndex: (size_t)index; +- (void)setArgument: (const void *)buffer atIndex: (size_t)index; /** * @brief Gets the argument for the specified index. * * @param buffer The buffer in which the argument is stored * @param index The index of the argument to get */ -- (void)getArgument: (void *)buffer - atIndex: (size_t)index; +- (void)getArgument: (void *)buffer atIndex: (size_t)index; /** * @brief Sets the return value. * * @param buffer The buffer in which the return value is stored @@ -99,15 +83,8 @@ * @brief Gets the return value. * * @param buffer The buffer in which the return value is stored */ - (void)getReturnValue: (void *)buffer; - -#ifdef OF_INVOCATION_CAN_INVOKE -/** - * @brief Invokes the method. - */ -- (void)invoke; -#endif @end OF_ASSUME_NONNULL_END Index: src/OFInvocation.m ================================================================== --- src/OFInvocation.m +++ src/OFInvocation.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -22,14 +20,10 @@ #import "OFInvocation.h" #import "OFArray.h" #import "OFData.h" #import "OFMethodSignature.h" -#ifdef OF_INVOCATION_CAN_INVOKE -extern void of_invocation_invoke(OFInvocation *); -#endif - @implementation OFInvocation @synthesize methodSignature = _methodSignature; + (instancetype)invocationWithMethodSignature: (OFMethodSignature *)signature { @@ -52,20 +46,20 @@ for (size_t i = 0; i < numberOfArguments; i++) { OFMutableData *data; typeEncoding = [_methodSignature argumentTypeAtIndex: i]; - typeSize = of_sizeof_type_encoding(typeEncoding); + typeSize = OFSizeOfTypeEncoding(typeEncoding); data = [OFMutableData dataWithItemSize: typeSize capacity: 1]; [data increaseCountBy: 1]; [_arguments addObject: data]; } typeEncoding = _methodSignature.methodReturnType; - typeSize = of_sizeof_type_encoding(typeEncoding); + typeSize = OFSizeOfTypeEncoding(typeEncoding); if (typeSize > 0) { _returnValue = [[OFMutableData alloc] initWithItemSize: typeSize capacity: 1]; @@ -88,23 +82,19 @@ [_returnValue release]; [super dealloc]; } -- (void)setArgument: (const void *)buffer - atIndex: (size_t)idx +- (void)setArgument: (const void *)buffer atIndex: (size_t)idx { OFMutableData *data = [_arguments objectAtIndex: idx]; - memcpy(data.mutableItems, buffer, data.itemSize); } -- (void)getArgument: (void *)buffer - atIndex: (size_t)idx +- (void)getArgument: (void *)buffer atIndex: (size_t)idx { OFData *data = [_arguments objectAtIndex: idx]; - memcpy(buffer, data.items, data.itemSize); } - (void)setReturnValue: (const void *)buffer { @@ -113,13 +103,6 @@ - (void)getReturnValue: (void *)buffer { memcpy(buffer, _returnValue.items, _returnValue.itemSize); } - -#ifdef OF_INVOCATION_CAN_INVOKE -- (void)invoke -{ - of_invocation_invoke(self); -} -#endif @end Index: src/OFJSONRepresentation.h ================================================================== --- src/OFJSONRepresentation.h +++ src/OFJSONRepresentation.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -19,15 +17,20 @@ @class OFString; OF_ASSUME_NONNULL_BEGIN -enum { - OF_JSON_REPRESENTATION_PRETTY = 0x01, - OF_JSON_REPRESENTATION_JSON5 = 0x02, - OF_JSON_REPRESENTATION_IDENTIFIER = 0x10 -}; +/** + * @brief Options to change the behavior when creating a JSON representation. + */ +typedef enum { + /** Optimize for readability */ + OFJSONRepresentationOptionPretty = 0x01, + /** Generate JSON5 */ + OFJSONRepresentationOptionJSON5 = 0x02, + OFJSONRepresentationOptionIsIdentifier = 0x10 +} OFJSONRepresentationOptions; /** * @protocol OFJSONRepresentation * OFJSONRepresentation.h ObjFW/OFJSONRepresentation.h * @@ -45,18 +48,13 @@ @property (readonly, nonatomic) OFString *JSONRepresentation; /** * @brief Returns the JSON representation of the object as a string. * - * @param options The options to use when creating a JSON representation.@n - * Possible values are: - * Value | Description - * --------------------------------|------------------------- - * `OF_JSON_REPRESENTATION_PRETTY` | Optimize for readability - * `OF_JSON_REPRESENTATION_JSON5` | Generate JSON5 - * + * @param options The options to use when creating a JSON representation * @return The JSON representation of the object as a string */ -- (OFString *)JSONRepresentationWithOptions: (int)options; +- (OFString *)JSONRepresentationWithOptions: + (OFJSONRepresentationOptions)options; @end OF_ASSUME_NONNULL_END Index: src/OFKernelEventObserver.h ================================================================== --- src/OFKernelEventObserver.h +++ src/OFKernelEventObserver.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -14,13 +12,12 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #import "OFObject.h" - #ifdef OF_HAVE_SOCKETS -# import "socket.h" +# import "OFSocket.h" #endif #ifdef OF_AMIGAOS # include # include @@ -122,17 +119,17 @@ OFMutableArray OF_GENERIC(id ) *_readObjects; OFMutableArray OF_GENERIC(id ) *_writeObjects; id _Nullable _delegate; -#if defined(OF_HAVE_PIPE) - int _cancelFD[2]; -#elif defined(OF_AMIGAOS) +#if defined(OF_AMIGAOS) struct Task *_waitingTask; ULONG _cancelSignal; +#elif defined(OF_HAVE_PIPE) + int _cancelFD[2]; #else - of_socket_t _cancelFD[2]; + OFSocketHandle _cancelFD[2]; struct sockaddr_in _cancelAddr; #endif #ifdef OF_AMIGAOS ULONG _execSignalMask; #endif @@ -213,11 +210,11 @@ * @brief Observes all objects until an event happens on an object or the * timeout is reached. * * @param timeInterval The time to wait for an event, in seconds */ -- (void)observeForTimeInterval: (of_time_interval_t)timeInterval; +- (void)observeForTimeInterval: (OFTimeInterval)timeInterval; /** * @brief Observes all objects until an event happens on an object or the * specified date is reached. * Index: src/OFKernelEventObserver.m ================================================================== --- src/OFKernelEventObserver.m +++ src/OFKernelEventObserver.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -23,48 +21,38 @@ #import "OFKernelEventObserver.h" #import "OFArray.h" #import "OFData.h" #import "OFDate.h" -#import "OFStream.h" -#import "OFStream+Private.h" -#ifndef OF_HAVE_PIPE -# import "OFStreamSocket.h" +#ifdef HAVE_EPOLL +# import "OFEpollKernelEventObserver.h" #endif - #ifdef HAVE_KQUEUE # import "OFKqueueKernelEventObserver.h" #endif -#ifdef HAVE_EPOLL -# import "OFEpollKernelEventObserver.h" -#endif #ifdef HAVE_POLL # import "OFPollKernelEventObserver.h" #endif #ifdef HAVE_SELECT # import "OFSelectKernelEventObserver.h" #endif +#import "OFSocket.h" +#import "OFSocket+Private.h" +#import "OFStream.h" +#import "OFStream+Private.h" +#ifndef OF_HAVE_PIPE +# import "OFStreamSocket.h" +#endif #import "OFInitializationFailedException.h" #import "OFInvalidArgumentException.h" #import "OFOutOfRangeException.h" -#import "socket.h" -#import "socket_helpers.h" - #ifdef OF_AMIGAOS # include #endif -enum { - QUEUE_ADD = 0, - QUEUE_REMOVE = 1, - QUEUE_READ = 0, - QUEUE_WRITE = 2 -}; -#define QUEUE_ACTION (QUEUE_ADD | QUEUE_REMOVE) - @implementation OFKernelEventObserver @synthesize delegate = _delegate; #ifdef OF_AMIGAOS @synthesize execSignalMask = _execSignalMask; #endif @@ -72,11 +60,11 @@ + (void)initialize { if (self != [OFKernelEventObserver class]) return; - if (!of_socket_init()) + if (!OFSocketInit()) @throw [OFInitializationFailedException exceptionWithClass: self]; } + (instancetype)observer @@ -113,18 +101,18 @@ #endif _readObjects = [[OFMutableArray alloc] init]; _writeObjects = [[OFMutableArray alloc] init]; -#if defined(OF_HAVE_PIPE) +#if defined(OF_HAVE_PIPE) && !defined(OF_AMIGAOS) if (pipe(_cancelFD)) @throw [OFInitializationFailedException exceptionWithClass: self.class]; #elif !defined(OF_AMIGAOS) _cancelFD[0] = _cancelFD[1] = socket(AF_INET, SOCK_DGRAM, 0); - if (_cancelFD[0] == INVALID_SOCKET) + if (_cancelFD[0] == OFInvalidSocketHandle) @throw [OFInitializationFailedException exceptionWithClass: self.class]; _cancelAddr.sin_family = AF_INET; _cancelAddr.sin_port = 0; @@ -138,11 +126,11 @@ sizeof(_cancelAddr)) != 0) @throw [OFInitializationFailedException exceptionWithClass: self.class]; cancelAddrLen = sizeof(_cancelAddr); - if (of_getsockname(_cancelFD[0], + if (OFGetSockName(_cancelFD[0], (struct sockaddr *)&_cancelAddr, &cancelAddrLen) != 0) @throw [OFInitializationFailedException exceptionWithClass: self.class]; # else for (;;) { @@ -150,19 +138,19 @@ int ret; while (rnd < 1024) rnd = (uint16_t)rand(); - _cancelAddr.sin_port = OF_BSWAP16_IF_LE(rnd); + _cancelAddr.sin_port = OFToBigEndian16(rnd); ret = bind(_cancelFD[0], (struct sockaddr *)&_cancelAddr, sizeof(_cancelAddr)); if (ret == 0) break; - if (of_socket_errno() != EADDRINUSE) + if (OFSocketErrNo() != EADDRINUSE) @throw [OFInitializationFailedException exceptionWithClass: self.class]; } # endif #endif @@ -174,11 +162,11 @@ return self; } - (void)dealloc { -#if defined(OF_HAVE_PIPE) +#if defined(OF_HAVE_PIPE) && !defined(OF_AMIGAOS) close(_cancelFD[0]); if (_cancelFD[1] != _cancelFD[0]) close(_cancelFD[1]); #elif !defined(OF_AMIGAOS) closesocket(_cancelFD[0]); @@ -245,11 +233,11 @@ - (void)observe { [self observeForTimeInterval: -1]; } -- (void)observeForTimeInterval: (of_time_interval_t)timeInterval +- (void)observeForTimeInterval: (OFTimeInterval)timeInterval { OF_UNRECOGNIZED_SELECTOR } - (void)observeUntilDate: (OFDate *)date @@ -257,25 +245,25 @@ [self observeForTimeInterval: date.timeIntervalSinceNow]; } - (void)cancel { -#if defined(OF_HAVE_PIPE) - OF_ENSURE(write(_cancelFD[1], "", 1) > 0); -#elif defined(OF_AMIGAOS) +#if defined(OF_AMIGAOS) Forbid(); if (_waitingTask != NULL) { Signal(_waitingTask, (1ul << _cancelSignal)); _waitingTask = NULL; } Permit(); +#elif defined(OF_HAVE_PIPE) + OFEnsure(write(_cancelFD[1], "", 1) > 0); #elif defined(OF_WII) - OF_ENSURE(sendto(_cancelFD[1], "", 1, 0, + OFEnsure(sendto(_cancelFD[1], "", 1, 0, (struct sockaddr *)&_cancelAddr, 8) > 0); #else - OF_ENSURE(sendto(_cancelFD[1], (void *)"", 1, 0, + OFEnsure(sendto(_cancelFD[1], (void *)"", 1, 0, (struct sockaddr *)&_cancelAddr, sizeof(_cancelAddr)) > 0); #endif } @end Index: src/OFKeyValueCoding.h ================================================================== --- src/OFKeyValueCoding.h +++ src/OFKeyValueCoding.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -61,21 +59,19 @@ * @brief Set the value for the specified key. * * @param value The value for the specified key * @param key The key of the value to set */ -- (void)setValue: (nullable id)value - forKey: (OFString *)key; +- (void)setValue: (nullable id)value forKey: (OFString *)key; /** * @brief Set the value for the specified key path. * * @param value The value for the specified key path * @param keyPath The key path of the value to set */ -- (void)setValue: (nullable id)value - forKeyPath: (OFString *)keyPath; +- (void)setValue: (nullable id)value forKeyPath: (OFString *)keyPath; /** * @brief This is called by @ref setValue:forKey: if the specified key does not * exist. * @@ -82,12 +78,11 @@ * By default, this throws an @ref OFUndefinedKeyException. * * @param value The value for the specified undefined key * @param key The undefined key of the value to set */ -- (void)setValue: (nullable id)value - forUndefinedKey: (OFString *)key; +- (void)setValue: (nullable id)value forUndefinedKey: (OFString *)key; /** * @brief This is called by @ref setValue:forKey: if the specified key is a * scalar, but the value specified is `nil`. * Index: src/OFKqueueKernelEventObserver.h ================================================================== --- src/OFKqueueKernelEventObserver.h +++ src/OFKqueueKernelEventObserver.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFKqueueKernelEventObserver.m ================================================================== --- src/OFKqueueKernelEventObserver.m +++ src/OFKqueueKernelEventObserver.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -34,11 +32,11 @@ #import "OFInitializationFailedException.h" #import "OFObserveFailedException.h" #import "OFOutOfRangeException.h" -#define EVENTLIST_SIZE 64 +#define eventListSize 64 @implementation OFKqueueKernelEventObserver - (instancetype)init { self = [super init]; @@ -87,15 +85,15 @@ memset(&event, 0, sizeof(event)); event.ident = object.fileDescriptorForReading; event.filter = EVFILT_READ; event.flags = EV_ADD; -#ifndef OF_NETBSD - event.udata = object; -#else - event.udata = (intptr_t)object; -#endif + /* + * Ugly hack required for NetBSD: NetBSD used `intptr_t` for udata, but + * switched this to `void *` in NetBSD 10. + */ + event.udata = (__typeof__(event.udata))object; if (kevent(_kernelQueue, &event, 1, NULL, 0, NULL) != 0) @throw [OFObserveFailedException exceptionWithObserver: self errNo: errno]; @@ -108,15 +106,15 @@ memset(&event, 0, sizeof(event)); event.ident = object.fileDescriptorForWriting; event.filter = EVFILT_WRITE; event.flags = EV_ADD; -#ifndef OF_NETBSD - event.udata = object; -#else - event.udata = (intptr_t)object; -#endif + /* + * Ugly hack required for NetBSD: NetBSD used `intptr_t` for udata, but + * switched this to `void *` in NetBSD 10. + */ + event.udata = (__typeof__(event.udata))object; if (kevent(_kernelQueue, &event, 1, NULL, 0, NULL) != 0) @throw [OFObserveFailedException exceptionWithObserver: self errNo: errno]; @@ -153,23 +151,23 @@ errNo: errno]; [super removeObjectForWriting: object]; } -- (void)observeForTimeInterval: (of_time_interval_t)timeInterval +- (void)observeForTimeInterval: (OFTimeInterval)timeInterval { struct timespec timeout; - struct kevent eventList[EVENTLIST_SIZE]; + struct kevent eventList[eventListSize]; int events; if ([self of_processReadBuffers]) return; timeout.tv_sec = (time_t)timeInterval; timeout.tv_nsec = (long)((timeInterval - timeout.tv_sec) * 1000000000); - events = kevent(_kernelQueue, NULL, 0, eventList, EVENTLIST_SIZE, + events = kevent(_kernelQueue, NULL, 0, eventList, eventListSize, (timeInterval != -1 ? &timeout : NULL)); if (events < 0) @throw [OFObserveFailedException exceptionWithObserver: self errNo: errno]; @@ -184,11 +182,11 @@ if (eventList[i].ident == (uintptr_t)_cancelFD[0]) { char buffer; assert(eventList[i].filter == EVFILT_READ); - OF_ENSURE(read(_cancelFD[0], &buffer, 1) == 1); + OFEnsure(read(_cancelFD[0], &buffer, 1) == 1); continue; } pool = objc_autoreleasePoolPush(); Index: src/OFLHAArchive.h ================================================================== --- src/OFLHAArchive.h +++ src/OFLHAArchive.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -31,23 +29,19 @@ */ OF_SUBCLASSING_RESTRICTED @interface OFLHAArchive: OFObject { OFStream *_stream; - enum { - OF_LHA_ARCHIVE_MODE_READ, - OF_LHA_ARCHIVE_MODE_WRITE, - OF_LHA_ARCHIVE_MODE_APPEND - } _mode; - of_string_encoding_t _encoding; + uint_least8_t _mode; + OFStringEncoding _encoding; OFStream *_Nullable _lastReturnedStream; } /** * @brief The encoding to use for the archive. Defaults to ISO 8859-1. */ -@property (nonatomic) of_string_encoding_t encoding; +@property (nonatomic) OFStringEncoding encoding; /** * @brief A stream for reading the current entry. * * @note This is only available in read mode. @@ -65,12 +59,11 @@ * @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)archiveWithStream: (OFStream *)stream - mode: (OFString *)mode; ++ (instancetype)archiveWithStream: (OFStream *)stream mode: (OFString *)mode; #ifdef OF_HAVE_FILES /** * @brief Creates a new OFLHAArchive object with the specified file. * @@ -78,12 +71,11 @@ * @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)archiveWithPath: (OFString *)path - mode: (OFString *)mode; ++ (instancetype)archiveWithPath: (OFString *)path mode: (OFString *)mode; #endif - (instancetype)init OF_UNAVAILABLE; /** @@ -109,12 +101,11 @@ * @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)initWithPath: (OFString *)path - mode: (OFString *)mode; +- (instancetype)initWithPath: (OFString *)path mode: (OFString *)mode; #endif /** * @brief Returns the next entry from the LHA archive or `nil` if all entries * have been read. Index: src/OFLHAArchive.m ================================================================== --- src/OFLHAArchive.m +++ src/OFLHAArchive.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -14,31 +12,38 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #include "config.h" + +#include #import "OFLHAArchive.h" #import "OFLHAArchiveEntry.h" #import "OFLHAArchiveEntry+Private.h" +#import "OFCRC16.h" #ifdef OF_HAVE_FILES # import "OFFile.h" #endif #import "OFLHADecompressingStream.h" #import "OFStream.h" #import "OFSeekableStream.h" #import "OFString.h" -#import "crc16.h" - #import "OFChecksumMismatchException.h" #import "OFInvalidArgumentException.h" #import "OFNotImplementedException.h" #import "OFNotOpenException.h" #import "OFOutOfRangeException.h" #import "OFTruncatedDataException.h" #import "OFWriteFailedException.h" + +enum { + modeRead, + modeWrite, + modeAppend +}; OF_DIRECT_MEMBERS @interface OFLHAArchiveFileReadStream: OFStream { OFStream *_stream, *_decompressedStream; @@ -55,97 +60,87 @@ OF_DIRECT_MEMBERS @interface OFLHAArchiveFileWriteStream: OFStream { OFMutableLHAArchiveEntry *_entry; - of_string_encoding_t _encoding; + OFStringEncoding _encoding; OFSeekableStream *_stream; - of_offset_t _headerOffset; + OFFileOffset _headerOffset; uint32_t _bytesWritten; uint16_t _CRC16; } - (instancetype)of_initWithStream: (OFSeekableStream *)stream entry: (OFLHAArchiveEntry *)entry - encoding: (of_string_encoding_t)encoding; + encoding: (OFStringEncoding)encoding; @end @implementation OFLHAArchive @synthesize encoding = _encoding; -+ (instancetype)archiveWithStream: (OFStream *)stream - mode: (OFString *)mode ++ (instancetype)archiveWithStream: (OFStream *)stream mode: (OFString *)mode { - return [[[self alloc] initWithStream: stream - mode: mode] autorelease]; + return [[[self alloc] initWithStream: stream mode: mode] autorelease]; } #ifdef OF_HAVE_FILES -+ (instancetype)archiveWithPath: (OFString *)path - mode: (OFString *)mode ++ (instancetype)archiveWithPath: (OFString *)path mode: (OFString *)mode { - return [[[self alloc] initWithPath: path - mode: mode] autorelease]; + return [[[self alloc] initWithPath: path mode: mode] autorelease]; } #endif - (instancetype)init { OF_INVALID_INIT_METHOD } -- (instancetype)initWithStream: (OFStream *)stream - mode: (OFString *)mode +- (instancetype)initWithStream: (OFStream *)stream mode: (OFString *)mode { self = [super init]; @try { _stream = [stream retain]; if ([mode isEqual: @"r"]) - _mode = OF_LHA_ARCHIVE_MODE_READ; + _mode = modeRead; else if ([mode isEqual: @"w"]) - _mode = OF_LHA_ARCHIVE_MODE_WRITE; + _mode = modeWrite; else if ([mode isEqual: @"a"]) - _mode = OF_LHA_ARCHIVE_MODE_APPEND; + _mode = modeAppend; else @throw [OFInvalidArgumentException exception]; - if ((_mode == OF_LHA_ARCHIVE_MODE_WRITE || - _mode == OF_LHA_ARCHIVE_MODE_APPEND) && + if ((_mode == modeWrite || _mode == modeAppend) && ![_stream isKindOfClass: [OFSeekableStream class]]) @throw [OFInvalidArgumentException exception]; - if (_mode == OF_LHA_ARCHIVE_MODE_APPEND) + if (_mode == modeAppend) [(OFSeekableStream *)_stream seekToOffset: 0 whence: SEEK_END]; - _encoding = OF_STRING_ENCODING_ISO_8859_1; + _encoding = OFStringEncodingISO8859_1; } @catch (id e) { [self release]; @throw e; } return self; } #ifdef OF_HAVE_FILES -- (instancetype)initWithPath: (OFString *)path - mode: (OFString *)mode +- (instancetype)initWithPath: (OFString *)path mode: (OFString *)mode { OFFile *file; if ([mode isEqual: @"a"]) - file = [[OFFile alloc] initWithPath: path - mode: @"r+"]; + file = [[OFFile alloc] initWithPath: path mode: @"r+"]; else - file = [[OFFile alloc] initWithPath: path - mode: mode]; + file = [[OFFile alloc] initWithPath: path mode: mode]; @try { - self = [self initWithStream: file - mode: mode]; + self = [self initWithStream: file mode: mode]; } @finally { [file release]; } return self; @@ -164,11 +159,11 @@ { OFLHAArchiveEntry *entry; char header[21]; size_t headerLen; - if (_mode != OF_LHA_ARCHIVE_MODE_READ) + if (_mode != modeRead) @throw [OFInvalidArgumentException exception]; [(OFLHAArchiveFileReadStream *)_lastReturnedStream of_skip]; @try { [_lastReturnedStream close]; @@ -205,11 +200,11 @@ return entry; } - (OFStream *)streamForReadingCurrentEntry { - if (_mode != OF_LHA_ARCHIVE_MODE_READ) + if (_mode != modeRead) @throw [OFInvalidArgumentException exception]; if (_lastReturnedStream == nil) @throw [OFInvalidArgumentException exception]; @@ -219,12 +214,11 @@ - (OFStream *)streamForWritingEntry: (OFLHAArchiveEntry *)entry { OFString *compressionMethod; - if (_mode != OF_LHA_ARCHIVE_MODE_WRITE && - _mode != OF_LHA_ARCHIVE_MODE_APPEND) + if (_mode != modeWrite && _mode != modeAppend) @throw [OFInvalidArgumentException exception]; compressionMethod = entry.compressionMethod; if (![compressionMethod isEqual: @"-lh0-"] && @@ -325,12 +319,11 @@ @throw [OFNotOpenException exceptionWithObject: self]; return _atEndOfStream; } -- (size_t)lowlevelReadIntoBuffer: (void *)buffer - length: (size_t)length +- (size_t)lowlevelReadIntoBuffer: (void *)buffer length: (size_t)length { size_t ret; if (_stream == nil) @throw [OFNotOpenException exceptionWithObject: self]; @@ -342,15 +335,14 @@ @throw [OFTruncatedDataException exception]; if (length > _toRead) length = _toRead; - ret = [_decompressedStream readIntoBuffer: buffer - length: length]; + ret = [_decompressedStream readIntoBuffer: buffer length: length]; _toRead -= ret; - _CRC16 = of_crc16(_CRC16, buffer, ret); + _CRC16 = OFCRC16(_CRC16, buffer, ret); if (_toRead == 0) { _atEndOfStream = true; if (_CRC16 != _entry.CRC16) { @@ -406,23 +398,22 @@ stream = _stream; } if ([stream isKindOfClass: [OFSeekableStream class]] && - (sizeof(of_offset_t) > 4 || toRead < INT32_MAX)) - [(OFSeekableStream *)stream seekToOffset: (of_offset_t)toRead + (sizeof(OFFileOffset) > 4 || toRead < INT32_MAX)) + [(OFSeekableStream *)stream seekToOffset: (OFFileOffset)toRead whence: SEEK_CUR]; else { while (toRead > 0) { char buffer[512]; size_t min = toRead; if (min > 512) min = 512; - toRead -= [stream readIntoBuffer: buffer - length: min]; + toRead -= [stream readIntoBuffer: buffer length: min]; } } _toRead = 0; _skipped = true; @@ -446,22 +437,20 @@ @end @implementation OFLHAArchiveFileWriteStream - (instancetype)of_initWithStream: (OFSeekableStream *)stream entry: (OFLHAArchiveEntry *)entry - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding { self = [super init]; @try { _entry = [entry mutableCopy]; _encoding = encoding; - _headerOffset = [stream seekToOffset: 0 - whence: SEEK_CUR]; - [_entry of_writeToStream: stream - encoding: _encoding]; + _headerOffset = [stream seekToOffset: 0 whence: SEEK_CUR]; + [_entry of_writeToStream: stream encoding: _encoding]; /* * Retain stream last, so that -[close] called by -[dealloc] * doesn't write in case of an error. */ @@ -482,35 +471,36 @@ [_entry release]; [super dealloc]; } -- (size_t)lowlevelWriteBuffer: (const void *)buffer - length: (size_t)length +- (size_t)lowlevelWriteBuffer: (const void *)buffer length: (size_t)length { - uint32_t bytesWritten; - if (_stream == nil) @throw [OFNotOpenException exceptionWithObject: self]; if (UINT32_MAX - _bytesWritten < length) @throw [OFOutOfRangeException exception]; @try { - bytesWritten = (uint32_t)[_stream writeBuffer: buffer - length: length]; + [_stream writeBuffer: buffer length: length]; } @catch (OFWriteFailedException *e) { - _bytesWritten += e.bytesWritten; - _CRC16 = of_crc16(_CRC16, buffer, e.bytesWritten); + OFEnsure(e.bytesWritten <= length); + + _bytesWritten += (uint32_t)e.bytesWritten; + _CRC16 = OFCRC16(_CRC16, buffer, e.bytesWritten); + + if (e.errNo == EWOULDBLOCK || e.errNo == EAGAIN) + return e.bytesWritten; @throw e; } - _bytesWritten += (uint32_t)bytesWritten; - _CRC16 = of_crc16(_CRC16, buffer, bytesWritten); + _bytesWritten += (uint32_t)length; + _CRC16 = OFCRC16(_CRC16, buffer, length); - return bytesWritten; + return length; } - (bool)lowlevelIsAtEndOfStream { if (_stream == nil) @@ -525,29 +515,25 @@ .fileDescriptorForWriting; } - (void)close { - of_offset_t offset; + OFFileOffset offset; if (_stream == nil) @throw [OFNotOpenException exceptionWithObject: self]; _entry.uncompressedSize = _bytesWritten; _entry.compressedSize = _bytesWritten; _entry.CRC16 = _CRC16; - offset = [_stream seekToOffset: 0 - whence:SEEK_CUR]; - [_stream seekToOffset: _headerOffset - whence: SEEK_SET]; - [_entry of_writeToStream: _stream - encoding: _encoding]; - [_stream seekToOffset: offset - whence: SEEK_SET]; + offset = [_stream seekToOffset: 0 whence: SEEK_CUR]; + [_stream seekToOffset: _headerOffset whence: SEEK_SET]; + [_entry of_writeToStream: _stream encoding: _encoding]; + [_stream seekToOffset: offset whence: SEEK_SET]; [_stream release]; _stream = nil; [super close]; } @end Index: src/OFLHAArchiveEntry+Private.h ================================================================== --- src/OFLHAArchiveEntry+Private.h +++ src/OFLHAArchiveEntry+Private.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -21,12 +19,12 @@ OF_DIRECT_MEMBERS @interface OFLHAArchiveEntry () - (instancetype)of_initWithHeader: (char [_Nonnull 21])header stream: (OFStream *)stream - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding OF_METHOD_FAMILY(init); - (void)of_writeToStream: (OFStream *)stream - encoding: (of_string_encoding_t)encoding; + encoding: (OFStringEncoding)encoding; @end OF_ASSUME_NONNULL_END Index: src/OFLHAArchiveEntry.h ================================================================== --- src/OFLHAArchiveEntry.h +++ src/OFLHAArchiveEntry.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFLHAArchiveEntry.m ================================================================== --- src/OFLHAArchiveEntry.m +++ src/OFLHAArchiveEntry.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -20,18 +18,17 @@ #include #import "OFLHAArchiveEntry.h" #import "OFLHAArchiveEntry+Private.h" #import "OFArray.h" +#import "OFCRC16.h" #import "OFData.h" #import "OFDate.h" #import "OFNumber.h" #import "OFStream.h" #import "OFString.h" -#import "crc16.h" - #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFOutOfRangeException.h" #import "OFUnsupportedVersionException.h" @@ -55,11 +52,11 @@ format: @"%Y-%m-%d %H:%M:%S"]; } static void parseFileNameExtension(OFLHAArchiveEntry *entry, OFData *extension, - of_string_encoding_t encoding) + OFStringEncoding encoding) { [entry->_fileName release]; entry->_fileName = nil; entry->_fileName = [[OFString alloc] @@ -68,11 +65,11 @@ length: [extension count] - 1]; } static void parseDirectoryNameExtension(OFLHAArchiveEntry *entry, OFData *extension, - of_string_encoding_t encoding) + OFStringEncoding encoding) { void *pool = objc_autoreleasePoolPush(); OFMutableData *data = [[extension mutableCopy] autorelease]; char *items = data.mutableItems; size_t count = data.count; @@ -99,11 +96,11 @@ objc_autoreleasePoolPop(pool); } static void parseCommentExtension(OFLHAArchiveEntry *entry, OFData *extension, - of_string_encoding_t encoding) + OFStringEncoding encoding) { [entry->_fileComment release]; entry->_fileComment = nil; entry->_fileComment = [[OFString alloc] @@ -112,40 +109,40 @@ length: extension.count - 1]; } static void parsePermissionsExtension(OFLHAArchiveEntry *entry, OFData *extension, - of_string_encoding_t encoding) + OFStringEncoding encoding) { uint16_t mode; if (extension.count != 3) @throw [OFInvalidFormatException exception]; memcpy(&mode, (char *)extension.items + 1, 2); - mode = OF_BSWAP16_IF_BE(mode); + mode = OFFromLittleEndian16(mode); [entry->_mode release]; entry->_mode = nil; entry->_mode = [[OFNumber alloc] initWithUnsignedShort: mode]; } static void parseGIDUIDExtension(OFLHAArchiveEntry *entry, OFData *extension, - of_string_encoding_t encoding) + OFStringEncoding encoding) { uint16_t UID, GID; if (extension.count != 5) @throw [OFInvalidFormatException exception]; memcpy(&GID, (char *)extension.items + 1, 2); - GID = OF_BSWAP16_IF_BE(GID); + GID = OFFromLittleEndian16(GID); memcpy(&UID, (char *)extension.items + 3, 2); - UID = OF_BSWAP16_IF_BE(UID); + UID = OFFromLittleEndian16(UID); [entry->_GID release]; entry->_GID = nil; [entry->_UID release]; @@ -155,11 +152,11 @@ entry->_UID = [[OFNumber alloc] initWithUnsignedShort: UID]; } static void parseGroupExtension(OFLHAArchiveEntry *entry, OFData *extension, - of_string_encoding_t encoding) + OFStringEncoding encoding) { [entry->_group release]; entry->_group = nil; entry->_group = [[OFString alloc] @@ -168,11 +165,11 @@ length: extension.count - 1]; } static void parseOwnerExtension(OFLHAArchiveEntry *entry, OFData *extension, - of_string_encoding_t encoding) + OFStringEncoding encoding) { [entry->_owner release]; entry->_owner = nil; entry->_owner = [[OFString alloc] @@ -181,19 +178,19 @@ length: extension.count - 1]; } static void parseModificationDateExtension(OFLHAArchiveEntry *entry, OFData *extension, - of_string_encoding_t encoding) + OFStringEncoding encoding) { uint32_t modificationDate; if (extension.count != 5) @throw [OFInvalidFormatException exception]; memcpy(&modificationDate, (char *)extension.items + 1, 4); - modificationDate = OF_BSWAP32_IF_BE(modificationDate); + modificationDate = OFFromLittleEndian32(modificationDate); [entry->_modificationDate release]; entry->_modificationDate = nil; entry->_modificationDate = [[OFDate alloc] @@ -200,13 +197,13 @@ initWithTimeIntervalSince1970: modificationDate]; } static bool parseExtension(OFLHAArchiveEntry *entry, OFData *extension, - of_string_encoding_t encoding, bool allowFileName) + OFStringEncoding encoding, bool allowFileName) { - void (*function)(OFLHAArchiveEntry *, OFData *, of_string_encoding_t) = + void (*function)(OFLHAArchiveEntry *, OFData *, OFStringEncoding) = NULL; switch (*(char *)[extension itemAtIndex: 0]) { case 0x01: if (allowFileName) @@ -242,11 +239,11 @@ return true; } static void readExtensions(OFLHAArchiveEntry *entry, OFStream *stream, - of_string_encoding_t encoding, bool allowFileName) + OFStringEncoding encoding, bool allowFileName) { uint16_t size; while ((size = [stream readLittleEndianInt16]) > 0) { OFData *extension; @@ -267,12 +264,11 @@ } } } static void -getFileNameAndDirectoryName(OFLHAArchiveEntry *entry, - of_string_encoding_t encoding, +getFileNameAndDirectoryName(OFLHAArchiveEntry *entry, OFStringEncoding encoding, const char **fileName, size_t *fileNameLength, const char **directoryName, size_t *directoryNameLength) { OFMutableData *data; char *cString; @@ -333,30 +329,30 @@ return self; } - (instancetype)of_initWithHeader: (char [21])header stream: (OFStream *)stream - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding { self = [super init]; @try { uint32_t date; _compressionMethod = [[OFString alloc] initWithCString: header + 2 - encoding: OF_STRING_ENCODING_ASCII + encoding: OFStringEncodingASCII length: 5]; memcpy(&_compressedSize, header + 7, 4); - _compressedSize = OF_BSWAP32_IF_BE(_compressedSize); + _compressedSize = OFFromLittleEndian32(_compressedSize); memcpy(&_uncompressedSize, header + 11, 4); - _uncompressedSize = OF_BSWAP32_IF_BE(_uncompressedSize); + _uncompressedSize = OFFromLittleEndian32(_uncompressedSize); memcpy(&date, header + 15, 4); - date = OF_BSWAP32_IF_BE(date); + date = OFFromLittleEndian32(date); _headerLevel = header[20]; _extensions = [[OFMutableArray alloc] init]; switch (_headerLevel) { @@ -555,11 +551,11 @@ { return _extensions; } - (void)of_writeToStream: (OFStream *)stream - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding { void *pool = objc_autoreleasePoolPush(); OFMutableData *data = [OFMutableData dataWithCapacity: 24]; const char *fileName, *directoryName; size_t fileNameLength, directoryNameLength; @@ -566,11 +562,11 @@ uint16_t tmp16; uint32_t tmp32; size_t headerSize; if ([_compressionMethod cStringLengthWithEncoding: - OF_STRING_ENCODING_ASCII] != 5) + OFStringEncodingASCII] != 5) @throw [OFInvalidArgumentException exception]; getFileNameAndDirectoryName(self, encoding, &fileName, &fileNameLength, &directoryName, &directoryNameLength); @@ -580,116 +576,100 @@ /* Length. Filled in after we're done. */ [data increaseCountBy: 2]; [data addItems: [_compressionMethod - cStringWithEncoding: OF_STRING_ENCODING_ASCII] + cStringWithEncoding: OFStringEncodingASCII] count: 5]; - tmp32 = OF_BSWAP32_IF_BE(_compressedSize); - [data addItems: &tmp32 - count: sizeof(tmp32)]; - - tmp32 = OF_BSWAP32_IF_BE(_uncompressedSize); - [data addItems: &tmp32 - count: sizeof(tmp32)]; - - tmp32 = OF_BSWAP32_IF_BE((uint32_t)_date.timeIntervalSince1970); - [data addItems: &tmp32 - count: sizeof(tmp32)]; + tmp32 = OFToLittleEndian32(_compressedSize); + [data addItems: &tmp32 count: sizeof(tmp32)]; + + tmp32 = OFToLittleEndian32(_uncompressedSize); + [data addItems: &tmp32 count: sizeof(tmp32)]; + + tmp32 = OFToLittleEndian32((uint32_t)_date.timeIntervalSince1970); + [data addItems: &tmp32 count: sizeof(tmp32)]; /* Reserved */ [data increaseCountBy: 1]; /* Header level */ [data addItem: "\x02"]; /* CRC16 */ - tmp16 = OF_BSWAP16_IF_BE(_CRC16); - [data addItems: &tmp16 - count: sizeof(tmp16)]; + tmp16 = OFToLittleEndian16(_CRC16); + [data addItems: &tmp16 count: sizeof(tmp16)]; /* Operating system identifier */ [data addItem: "U"]; /* Common header. Contains CRC16, which is written at the end. */ - tmp16 = OF_BSWAP16_IF_BE(5); - [data addItems: &tmp16 - count: sizeof(tmp16)]; + tmp16 = OFToLittleEndian16(5); + [data addItems: &tmp16 count: sizeof(tmp16)]; [data addItem: "\x00"]; [data increaseCountBy: 2]; - tmp16 = OF_BSWAP16_IF_BE((uint16_t)fileNameLength + 3); - [data addItems: &tmp16 - count: sizeof(tmp16)]; + tmp16 = OFToLittleEndian16((uint16_t)fileNameLength + 3); + [data addItems: &tmp16 count: sizeof(tmp16)]; [data addItem: "\x01"]; - [data addItems: fileName - count: fileNameLength]; + [data addItems: fileName count: fileNameLength]; if (directoryNameLength > 0) { - tmp16 = OF_BSWAP16_IF_BE((uint16_t)directoryNameLength + 3); - [data addItems: &tmp16 - count: sizeof(tmp16)]; + tmp16 = OFToLittleEndian16((uint16_t)directoryNameLength + 3); + [data addItems: &tmp16 count: sizeof(tmp16)]; [data addItem: "\x02"]; - [data addItems: directoryName - count: directoryNameLength]; + [data addItems: directoryName count: directoryNameLength]; } if (_fileComment != nil) { size_t fileCommentLength = [_fileComment cStringLengthWithEncoding: encoding]; if (fileCommentLength > UINT16_MAX - 3) @throw [OFOutOfRangeException exception]; - tmp16 = OF_BSWAP16_IF_BE((uint16_t)fileCommentLength + 3); - [data addItems: &tmp16 - count: sizeof(tmp16)]; + tmp16 = OFToLittleEndian16((uint16_t)fileCommentLength + 3); + [data addItems: &tmp16 count: sizeof(tmp16)]; [data addItem: "\x3F"]; [data addItems: [_fileComment cStringWithEncoding: encoding] count: fileCommentLength]; } if (_mode != nil) { - tmp16 = OF_BSWAP16_IF_BE(5); - [data addItems: &tmp16 - count: sizeof(tmp16)]; + tmp16 = OFToLittleEndian16(5); + [data addItems: &tmp16 count: sizeof(tmp16)]; [data addItem: "\x50"]; - tmp16 = OF_BSWAP16_IF_BE(_mode.unsignedShortValue); - [data addItems: &tmp16 - count: sizeof(tmp16)]; + tmp16 = OFToLittleEndian16(_mode.unsignedShortValue); + [data addItems: &tmp16 count: sizeof(tmp16)]; } if (_UID != nil || _GID != nil) { if (_UID == nil || _GID == nil) @throw [OFInvalidArgumentException exception]; - tmp16 = OF_BSWAP16_IF_BE(7); - [data addItems: &tmp16 - count: sizeof(tmp16)]; + tmp16 = OFToLittleEndian16(7); + [data addItems: &tmp16 count: sizeof(tmp16)]; [data addItem: "\x51"]; - tmp16 = OF_BSWAP16_IF_BE(_GID.unsignedShortValue); - [data addItems: &tmp16 - count: sizeof(tmp16)]; + tmp16 = OFToLittleEndian16(_GID.unsignedShortValue); + [data addItems: &tmp16 count: sizeof(tmp16)]; - tmp16 = OF_BSWAP16_IF_BE(_UID.unsignedShortValue); - [data addItems: &tmp16 - count: sizeof(tmp16)]; + tmp16 = OFToLittleEndian16(_UID.unsignedShortValue); + [data addItems: &tmp16 count: sizeof(tmp16)]; } if (_group != nil) { size_t groupLength = [_group cStringLengthWithEncoding: encoding]; if (groupLength > UINT16_MAX - 3) @throw [OFOutOfRangeException exception]; - tmp16 = OF_BSWAP16_IF_BE((uint16_t)groupLength + 3); - [data addItems: &tmp16 - count: sizeof(tmp16)]; + tmp16 = OFToLittleEndian16((uint16_t)groupLength + 3); + [data addItems: &tmp16 count: sizeof(tmp16)]; [data addItem: "\x52"]; [data addItems: [_group cStringWithEncoding: encoding] count: groupLength]; } @@ -698,28 +678,25 @@ [_owner cStringLengthWithEncoding: encoding]; if (ownerLength > UINT16_MAX - 3) @throw [OFOutOfRangeException exception]; - tmp16 = OF_BSWAP16_IF_BE((uint16_t)ownerLength + 3); - [data addItems: &tmp16 - count: sizeof(tmp16)]; + tmp16 = OFToLittleEndian16((uint16_t)ownerLength + 3); + [data addItems: &tmp16 count: sizeof(tmp16)]; [data addItem: "\x53"]; [data addItems: [_owner cStringWithEncoding: encoding] count: ownerLength]; } if (_modificationDate != nil) { - tmp16 = OF_BSWAP16_IF_BE(7); - [data addItems: &tmp16 - count: sizeof(tmp16)]; + tmp16 = OFToLittleEndian16(7); + [data addItems: &tmp16 count: sizeof(tmp16)]; [data addItem: "\x54"]; - tmp32 = OF_BSWAP32_IF_BE( + tmp32 = OFToLittleEndian32( (uint32_t)_modificationDate.timeIntervalSince1970); - [data addItems: &tmp32 - count: sizeof(tmp32)]; + [data addItems: &tmp32 count: sizeof(tmp32)]; } for (OFData *extension in _extensions) { size_t extensionLength = extension.count; @@ -727,15 +704,13 @@ @throw [OFInvalidArgumentException exception]; if (extensionLength > UINT16_MAX - 2) @throw [OFOutOfRangeException exception]; - tmp16 = OF_BSWAP16_IF_BE((uint16_t)extensionLength + 2); - [data addItems: &tmp16 - count: sizeof(tmp16)]; - [data addItems: extension.items - count: extension.count]; + tmp16 = OFToLittleEndian16((uint16_t)extensionLength + 2); + [data addItems: &tmp16 count: sizeof(tmp16)]; + [data addItems: extension.items count: extension.count]; } /* Zero-length extension to terminate */ [data increaseCountBy: 2]; @@ -743,15 +718,15 @@ if (headerSize > UINT16_MAX) @throw [OFOutOfRangeException exception]; /* Now fill in the size and CRC16 for the entire header */ - tmp16 = OF_BSWAP16_IF_BE(headerSize); + tmp16 = OFToLittleEndian16(headerSize); memcpy([data mutableItemAtIndex: 0], &tmp16, sizeof(tmp16)); - tmp16 = of_crc16(0, data.items, data.count); - tmp16 = OF_BSWAP16_IF_BE(tmp16); + tmp16 = OFCRC16(0, data.items, data.count); + tmp16 = OFToLittleEndian16(tmp16); memcpy([data mutableItemAtIndex: 27], &tmp16, sizeof(tmp16)); [stream writeData: data]; objc_autoreleasePoolPop(pool); Index: src/OFLHADecompressingStream.h ================================================================== --- src/OFLHADecompressingStream.h +++ src/OFLHADecompressingStream.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -14,32 +12,35 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #import "OFStream.h" +#import "OFHuffmanTree.h" OF_ASSUME_NONNULL_BEGIN -#define OF_LHA_DECOMPRESSING_STREAM_BUFFER_SIZE 4096 +#define OFLHADecompressingStreamBufferSize 4096 OF_DIRECT_MEMBERS @interface OFLHADecompressingStream: OFStream { OFStream *_stream; uint8_t _distanceBits, _dictionaryBits; - unsigned char _buffer[OF_LHA_DECOMPRESSING_STREAM_BUFFER_SIZE]; + unsigned char _buffer[OFLHADecompressingStreamBufferSize]; uint32_t _bytesConsumed; uint16_t _bufferIndex, _bufferLength; uint8_t _byte; uint8_t _bitIndex, _savedBitsLength; uint16_t _savedBits; unsigned char *_slidingWindow; uint32_t _slidingWindowIndex, _slidingWindowMask; int _state; uint16_t _symbolsLeft; - struct of_huffman_tree *_Nullable _codeLenTree, *_Nullable _litLenTree; - struct of_huffman_tree *_Nullable _distTree, *_Nullable _treeIter; + OFHuffmanTree _Nullable _codeLenTree; + OFHuffmanTree _Nullable _litLenTree; + OFHuffmanTree _Nullable _distTree; + OFHuffmanTree _Nullable _treeIter; uint16_t _codesCount, _codesReceived; bool _currentIsExtendedLength, _skip; uint8_t *_Nullable _codesLengths; uint16_t _length; uint32_t _distance; Index: src/OFLHADecompressingStream.m ================================================================== --- src/OFLHADecompressingStream.m +++ src/OFLHADecompressingStream.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -20,30 +18,30 @@ #include #import "OFLHADecompressingStream.h" #import "OFKernelEventObserver.h" -#import "huffman_tree.h" +#import "OFHuffmanTree.h" #import "OFInvalidFormatException.h" #import "OFNotOpenException.h" -enum state { - STATE_BLOCK_HEADER, - STATE_CODE_LEN_CODES_COUNT, - STATE_CODE_LEN_TREE, - STATE_CODE_LEN_TREE_SINGLE, - STATE_LITLEN_CODES_COUNT, - STATE_LITLEN_TREE, - STATE_LITLEN_TREE_SINGLE, - STATE_DIST_CODES_COUNT, - STATE_DIST_TREE, - STATE_DIST_TREE_SINGLE, - STATE_BLOCK_LITLEN, - STATE_BLOCK_DIST_LENGTH, - STATE_BLOCK_DIST_LENGTH_EXTRA, - STATE_BLOCK_LEN_DIST_PAIR +enum State { + stateBlockHeader, + stateCodeLenCodesCount, + stateCodeLenTree, + stateCodeLenTreeSingle, + stateLitLenCodesCount, + stateLitLenTree, + stateLitLenTreeSingle, + stateDistCodesCount, + stateDistTree, + stateDistTreeSingle, + stateBlockLitLen, + stateBlockDistLength, + stateBlockDistLengthExtra, + stateBlockLenDistPair }; @implementation OFLHADecompressingStream @synthesize bytesConsumed = _bytesConsumed; @@ -60,11 +58,11 @@ stream->_bufferLength) stream->_byte = stream->_buffer[stream->_bufferIndex++]; else { const size_t bufferLength = - OF_LHA_DECOMPRESSING_STREAM_BUFFER_SIZE; + OFLHADecompressingStreamBufferSize; size_t length = [stream->_stream readIntoBuffer: stream->_buffer length: bufferLength]; stream->_bytesConsumed += (uint32_t)length; @@ -108,12 +106,11 @@ _distanceBits = distanceBits; _dictionaryBits = dictionaryBits; _slidingWindowMask = (1u << dictionaryBits) - 1; - _slidingWindow = [self allocMemoryWithSize: - _slidingWindowMask + 1]; + _slidingWindow = OFAllocMemory(_slidingWindowMask + 1, 1); memset(_slidingWindow, ' ', _slidingWindowMask + 1); } @catch (id e) { [self release]; @throw e; } @@ -124,16 +121,20 @@ - (void)dealloc { if (_stream != nil) [self close]; + OFFreeMemory(_slidingWindow); + if (_codeLenTree != NULL) - of_huffman_tree_release(_codeLenTree); + OFHuffmanTreeFree(_codeLenTree); if (_litLenTree != NULL) - of_huffman_tree_release(_litLenTree); + OFHuffmanTreeFree(_litLenTree); if (_distTree != NULL) - of_huffman_tree_release(_distTree); + OFHuffmanTreeFree(_distTree); + + OFFreeMemory(_codesLengths); [super dealloc]; } - (size_t)lowlevelReadIntoBuffer: (void *)buffer_ @@ -145,43 +146,43 @@ if (_stream == nil) @throw [OFNotOpenException exceptionWithObject: self]; if (_stream.atEndOfStream && _bufferLength - _bufferIndex == 0 && - _state == STATE_BLOCK_HEADER) + _state == stateBlockHeader) return 0; start: - switch ((enum state)_state) { - case STATE_BLOCK_HEADER: + switch ((enum State)_state) { + case stateBlockHeader: if OF_UNLIKELY (!tryReadBits(self, &bits, 16)) return bytesWritten; _symbolsLeft = bits; - _state = STATE_CODE_LEN_CODES_COUNT; + _state = stateCodeLenCodesCount; goto start; - case STATE_CODE_LEN_CODES_COUNT: + case stateCodeLenCodesCount: if OF_UNLIKELY (!tryReadBits(self, &bits, 5)) return bytesWritten; if OF_UNLIKELY (bits > 20) @throw [OFInvalidFormatException exception]; if OF_UNLIKELY (bits == 0) { - _state = STATE_CODE_LEN_TREE_SINGLE; + _state = stateCodeLenTreeSingle; goto start; } _codesCount = bits; _codesReceived = 0; - _codesLengths = [self allocZeroedMemoryWithSize: bits]; + _codesLengths = OFAllocZeroedMemory(bits, 1); _skip = true; - _state = STATE_CODE_LEN_TREE; + _state = stateCodeLenTree; goto start; - case STATE_CODE_LEN_TREE: + case stateCodeLenTree: while (_codesReceived < _codesCount) { if OF_UNLIKELY (_currentIsExtendedLength) { if OF_UNLIKELY (!tryReadBits(self, &bits, 1)) return bytesWritten; @@ -221,48 +222,48 @@ continue; } else _codesReceived++; } - _codeLenTree = of_huffman_tree_construct(_codesLengths, - _codesCount); - [self freeMemory: _codesLengths]; + _codeLenTree = OFHuffmanTreeNew(_codesLengths, _codesCount); + OFFreeMemory(_codesLengths); + _codesLengths = NULL; - _state = STATE_LITLEN_CODES_COUNT; + _state = stateLitLenCodesCount; goto start; - case STATE_CODE_LEN_TREE_SINGLE: + case stateCodeLenTreeSingle: if OF_UNLIKELY (!tryReadBits(self, &bits, 5)) return bytesWritten; - _codeLenTree = of_huffman_tree_construct_single(bits); + _codeLenTree = OFHuffmanTreeNewSingle(bits); - _state = STATE_LITLEN_CODES_COUNT; + _state = stateLitLenCodesCount; goto start; - case STATE_LITLEN_CODES_COUNT: + case stateLitLenCodesCount: if OF_UNLIKELY (!tryReadBits(self, &bits, 9)) return bytesWritten; if OF_UNLIKELY (bits > 510) @throw [OFInvalidFormatException exception]; if OF_UNLIKELY (bits == 0) { - of_huffman_tree_release(_codeLenTree); + OFHuffmanTreeFree(_codeLenTree); _codeLenTree = NULL; - _state = STATE_LITLEN_TREE_SINGLE; + _state = stateLitLenTreeSingle; goto start; } _codesCount = bits; _codesReceived = 0; - _codesLengths = [self allocZeroedMemoryWithSize: bits]; + _codesLengths = OFAllocZeroedMemory(bits, 1); _skip = false; _treeIter = _codeLenTree; - _state = STATE_LITLEN_TREE; + _state = stateLitLenTree; goto start; - case STATE_LITLEN_TREE: + case stateLitLenTree: while (_codesReceived < _codesCount) { if OF_UNLIKELY (_skip) { uint16_t skipCount; switch (_codesLengths[_codesReceived]) { @@ -282,11 +283,11 @@ return bytesWritten; skipCount = bits + 20; break; default: - OF_ENSURE(0); + OFEnsure(0); } if OF_UNLIKELY (_codesReceived + skipCount > _codesCount) @throw [OFInvalidFormatException @@ -297,12 +298,12 @@ _skip = false; continue; } - if (!of_huffman_tree_walk(self, tryReadBits, - &_treeIter, &value)) + if (!OFHuffmanTreeWalk(self, tryReadBits, &_treeIter, + &value)) return bytesWritten; _treeIter = _codeLenTree; if (value < 3) { @@ -310,47 +311,47 @@ _skip = true; } else _codesLengths[_codesReceived++] = value - 2; } - _litLenTree = of_huffman_tree_construct(_codesLengths, - _codesCount); - [self freeMemory: _codesLengths]; + _litLenTree = OFHuffmanTreeNew(_codesLengths, _codesCount); + OFFreeMemory(_codesLengths); + _codesLengths = NULL; - of_huffman_tree_release(_codeLenTree); + OFHuffmanTreeFree(_codeLenTree); _codeLenTree = NULL; - _state = STATE_DIST_CODES_COUNT; + _state = stateDistCodesCount; goto start; - case STATE_LITLEN_TREE_SINGLE: + case stateLitLenTreeSingle: if OF_UNLIKELY (!tryReadBits(self, &bits, 9)) return bytesWritten; - _litLenTree = of_huffman_tree_construct_single(bits); + _litLenTree = OFHuffmanTreeNewSingle(bits); - _state = STATE_DIST_CODES_COUNT; + _state = stateDistCodesCount; goto start; - case STATE_DIST_CODES_COUNT: + case stateDistCodesCount: if OF_UNLIKELY (!tryReadBits(self, &bits, _distanceBits)) return bytesWritten; if OF_UNLIKELY (bits > _dictionaryBits) @throw [OFInvalidFormatException exception]; if OF_UNLIKELY (bits == 0) { - _state = STATE_DIST_TREE_SINGLE; + _state = stateDistTreeSingle; goto start; } _codesCount = bits; _codesReceived = 0; - _codesLengths = [self allocZeroedMemoryWithSize: bits]; + _codesLengths = OFAllocZeroedMemory(bits, 1); _treeIter = _codeLenTree; - _state = STATE_DIST_TREE; + _state = stateDistTree; goto start; - case STATE_DIST_TREE: + case stateDistTree: while (_codesReceived < _codesCount) { if OF_UNLIKELY (_currentIsExtendedLength) { if OF_UNLIKELY (!tryReadBits(self, &bits, 1)) return bytesWritten; @@ -374,33 +375,33 @@ continue; } else _codesReceived++; } - _distTree = of_huffman_tree_construct(_codesLengths, - _codesCount); - [self freeMemory: _codesLengths]; + _distTree = OFHuffmanTreeNew(_codesLengths, _codesCount); + OFFreeMemory(_codesLengths); + _codesLengths = NULL; _treeIter = _litLenTree; - _state = STATE_BLOCK_LITLEN; + _state = stateBlockLitLen; goto start; - case STATE_DIST_TREE_SINGLE: + case stateDistTreeSingle: if OF_UNLIKELY (!tryReadBits(self, &bits, _distanceBits)) return bytesWritten; - _distTree = of_huffman_tree_construct_single(bits); + _distTree = OFHuffmanTreeNewSingle(bits); _treeIter = _litLenTree; - _state = STATE_BLOCK_LITLEN; + _state = stateBlockLitLen; goto start; - case STATE_BLOCK_LITLEN: + case stateBlockLitLen: if OF_UNLIKELY (_symbolsLeft == 0) { - of_huffman_tree_release(_litLenTree); - of_huffman_tree_release(_distTree); + OFHuffmanTreeFree(_litLenTree); + OFHuffmanTreeFree(_distTree); _litLenTree = _distTree = NULL; - _state = STATE_BLOCK_HEADER; + _state = stateBlockHeader; /* * We must return here, as there is no indication * whether this was the last block. Whoever called this * method needs to check if everything has been read @@ -421,11 +422,11 @@ } if OF_UNLIKELY (length == 0) return bytesWritten; - if OF_UNLIKELY (!of_huffman_tree_walk(self, tryReadBits, + if OF_UNLIKELY (!OFHuffmanTreeWalk(self, tryReadBits, &_treeIter, &value)) return bytesWritten; if OF_LIKELY (value < 256) { buffer[bytesWritten++] = value; @@ -438,34 +439,33 @@ _symbolsLeft--; _treeIter = _litLenTree; } else { _length = value - 253; _treeIter = _distTree; - _state = STATE_BLOCK_DIST_LENGTH; + _state = stateBlockDistLength; } goto start; - case STATE_BLOCK_DIST_LENGTH: - if OF_UNLIKELY (!of_huffman_tree_walk(self, tryReadBits, + case stateBlockDistLength: + if OF_UNLIKELY (!OFHuffmanTreeWalk(self, tryReadBits, &_treeIter, &value)) return bytesWritten; _distance = value; _state = (value < 2 - ? STATE_BLOCK_LEN_DIST_PAIR - : STATE_BLOCK_DIST_LENGTH_EXTRA); + ? stateBlockLenDistPair : stateBlockDistLengthExtra); goto start; - case STATE_BLOCK_DIST_LENGTH_EXTRA: + case stateBlockDistLengthExtra: if OF_UNLIKELY (!tryReadBits(self, &bits, _distance - 1)) return bytesWritten; _distance = bits + (1u << (_distance - 1)); - _state = STATE_BLOCK_LEN_DIST_PAIR; + _state = stateBlockLenDistPair; goto start; - case STATE_BLOCK_LEN_DIST_PAIR: + case stateBlockLenDistPair: for (uint_fast16_t i = 0; i < _length; i++) { uint32_t idx; if OF_UNLIKELY (length == 0) { _length -= i; @@ -485,11 +485,11 @@ } _symbolsLeft--; _treeIter = _litLenTree; - _state = STATE_BLOCK_LITLEN; + _state = stateBlockLitLen; goto start; } OF_UNREACHABLE } @@ -498,11 +498,11 @@ { if (_stream == nil) @throw [OFNotOpenException exceptionWithObject: self]; return (_stream.atEndOfStream && - _bufferLength - _bufferIndex == 0 && _state == STATE_BLOCK_HEADER); + _bufferLength - _bufferIndex == 0 && _state == stateBlockHeader); } - (int)fileDescriptorForReading { return ((id )_stream) Index: src/OFList.h ================================================================== --- src/OFList.h +++ src/OFList.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -20,27 +18,65 @@ #import "OFEnumerator.h" #import "OFSerialization.h" OF_ASSUME_NONNULL_BEGIN -typedef struct of_list_object_t of_list_object_t; +/** @file */ + +/* + * Make clang's -Wdocumentation shut about about using @struct on someting it + * thinks is not a struct. Doxygen requires it this way. + */ +#ifdef __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wdocumentation" +#endif /** - * @struct of_list_object_t OFList.h ObjFW/OFList.h + * @struct OFListItem OFList.h ObjFW/OFList.h + * + * @brief A list item. + * + * See @ref OFListItemNext, @ref OFListItemPrevious and @ref OFListItemObject. + */ +typedef struct _OFListItem *OFListItem; +#ifdef __clang__ +# pragma clang diagnostic pop +#endif + +#ifdef __cplusplus +extern "C" { +#endif +/*! + * @brief Returns the next list item of the list item. + * + * @param listItem The list item for which the next list item should be returned + * @return The next list item of the list item + */ +extern OFListItem _Nullable OFListItemNext(OFListItem _Nonnull listItem); + +/*! + * @brief Returns the previous list item of the list item. + * + * @param listItem The list item for which the previous list item should be + * returned + * @return The previous list item of the list item + */ +extern OFListItem _Nullable OFListItemPrevious(OFListItem _Nonnull listItem); + +/*! + * @brief Returns the object of the list item. * - * @brief A list object. + * @warning The returned object is not retained and autoreleased - this is the + * caller's responsibility! * - * A struct that contains a pointer to the next list object, the previous list - * object and the object. + * @param listItem The list item for which the object should be returned + * @return The object of the list item */ -struct of_list_object_t { - /** A pointer to the next list object in the list */ - of_list_object_t *_Nullable next; - /** A pointer to the previous list object in the list */ - of_list_object_t *_Nullable previous; - /** The object for the list object */ - id __unsafe_unretained object; -}; +extern id _Nonnull OFListItemObject(OFListItem _Nonnull listItem); +#ifdef __cplusplus +} +#endif /** * @class OFList OFList.h ObjFW/OFList.h * * @brief A class which provides easy to use double-linked lists. @@ -49,22 +85,21 @@ OFSerialization> #if !defined(OF_HAVE_GENERICS) && !defined(DOXYGEN) # define ObjectType id #endif { - of_list_object_t *_Nullable _firstListObject; - of_list_object_t *_Nullable _lastListObject; + OFListItem _Nullable _firstListItem; + OFListItem _Nullable _lastListItem; size_t _count; - unsigned long _mutations; + unsigned long _mutations; OF_RESERVE_IVARS(OFList, 4) } /** * @brief The first list object of the list. */ -@property OF_NULLABLE_PROPERTY (readonly, nonatomic) - of_list_object_t *firstListObject; +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFListItem firstListItem; /** * @brief The first object of the list or `nil`. * * @warning The returned object is *not* retained and autoreleased for @@ -73,12 +108,11 @@ @property OF_NULLABLE_PROPERTY (readonly, nonatomic) ObjectType firstObject; /** * @brief The last list object of the list. */ -@property OF_NULLABLE_PROPERTY (readonly, nonatomic) - of_list_object_t *lastListObject; +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFListItem lastListItem; /** * @brief The last object of the list or `nil`. * * @warning The returned object is *not* retained and autoreleased for @@ -95,58 +129,58 @@ /** * @brief Appends an object to the list. * * @param object The object to append - * @return An of_list_object_t, needed to identify the object inside the list. + * @return An OFListItem, needed to identify the object inside the list. * For example, if you want to remove an object from the list, you need - * its of_list_object_t. + * its OFListItem. */ -- (of_list_object_t *)appendObject: (ObjectType)object; +- (OFListItem)appendObject: (ObjectType)object; /** * @brief Prepends an object to the list. * * @param object The object to prepend - * @return An of_list_object_t, needed to identify the object inside the list. + * @return An OFListItem, needed to identify the object inside the list. * For example, if you want to remove an object from the list, you need - * its of_list_object_t. + * its OFListItem. */ -- (of_list_object_t *)prependObject: (ObjectType)object; +- (OFListItem)prependObject: (ObjectType)object; /** * @brief Inserts an object before another list object. * * @param object The object to insert - * @param listObject The of_list_object_t of the object before which it should - * be inserted - * @return An of_list_object_t, needed to identify the object inside the list. + * @param listItem The OFListItem of the object before which it should be + * inserted + * @return An OFListItem, needed to identify the object inside the list. * For example, if you want to remove an object from the list, you need - * its of_list_object_t. + * its OFListItem. */ -- (of_list_object_t *)insertObject: (ObjectType)object - beforeListObject: (of_list_object_t *)listObject; +- (OFListItem)insertObject: (ObjectType)object + beforeListItem: (OFListItem)listItem; /** * @brief Inserts an object after another list object. * * @param object The object to insert - * @param listObject The of_list_object_t of the object after which it should be + * @param listItem The OFListItem of the object after which it should be * inserted - * @return An of_list_object_t, needed to identify the object inside the list. + * @return An OFListItem, needed to identify the object inside the list. * For example, if you want to remove an object from the list, you need - * its of_list_object_t. + * its OFListItem. */ -- (of_list_object_t *)insertObject: (ObjectType)object - afterListObject: (of_list_object_t *)listObject; +- (OFListItem)insertObject: (ObjectType)object + afterListItem: (OFListItem)listItem; /** * @brief Removes the object with the specified list object from the list. * - * @param listObject The list object returned by append / prepend + * @param listItem The list object returned by append / prepend */ -- (void)removeListObject: (of_list_object_t *)listObject; +- (void)removeListItem: (OFListItem)listItem; /** * @brief Checks whether the list contains an object equal to the specified * object. * Index: src/OFList.m ================================================================== --- src/OFList.m +++ src/OFList.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -25,27 +23,49 @@ #import "OFXMLElement.h" #import "OFArray.h" #import "OFEnumerationMutationException.h" #import "OFInvalidArgumentException.h" + +struct _OFListItem { + struct _OFListItem *previous, *next; + id object; +}; OF_DIRECT_MEMBERS @interface OFListEnumerator: OFEnumerator { OFList *_list; - of_list_object_t *_Nullable _current; + OFListItem _Nullable _current; unsigned long _mutations; unsigned long *_Nullable _mutationsPtr; } - (instancetype)initWithList: (OFList *)list mutationsPointer: (unsigned long *)mutationsPtr; @end + +OFListItem +OFListItemNext(OFListItem listItem) +{ + return listItem->next; +} + +OFListItem +OFListItemPrevious(OFListItem listItem) +{ + return listItem->previous; +} + +id +OFListItemObject(OFListItem listItem) +{ + return listItem->object; +} @implementation OFList -@synthesize firstListObject = _firstListObject; -@synthesize lastListObject = _lastListObject; +@synthesize firstListItem = _firstListItem, lastListItem = _lastListItem; + (instancetype)list { return [[[self alloc] init] autorelease]; } @@ -56,15 +76,15 @@ @try { void *pool = objc_autoreleasePoolPush(); if (![element.name isEqual: self.className] || - ![element.namespace isEqual: OF_SERIALIZATION_NS]) + ![element.namespace isEqual: OFSerializationNS]) @throw [OFInvalidArgumentException exception]; for (OFXMLElement *child in - [element elementsForNamespace: OF_SERIALIZATION_NS]) { + [element elementsForNamespace: OFSerializationNS]) { void *pool2 = objc_autoreleasePoolPush(); [self appendObject: child.objectByDeserializing]; objc_autoreleasePoolPop(pool2); @@ -79,138 +99,135 @@ return self; } - (void)dealloc { - for (of_list_object_t *iter = _firstListObject; - iter != NULL; iter = iter->next) - [iter->object release]; - - [super dealloc]; -} - -- (of_list_object_t *)appendObject: (id)object -{ - of_list_object_t *listObject; - - listObject = [self allocMemoryWithSize: sizeof(of_list_object_t)]; - listObject->object = [object retain]; - listObject->next = NULL; - listObject->previous = _lastListObject; - - if (_lastListObject != NULL) - _lastListObject->next = listObject; - - _lastListObject = listObject; - - if (_firstListObject == NULL) - _firstListObject = listObject; - - _count++; - _mutations++; - - return listObject; -} - -- (of_list_object_t *)prependObject: (id)object -{ - of_list_object_t *listObject; - - listObject = [self allocMemoryWithSize: sizeof(of_list_object_t)]; - listObject->object = [object retain]; - listObject->next = _firstListObject; - listObject->previous = NULL; - - if (_firstListObject != NULL) - _firstListObject->previous = listObject; - - _firstListObject = listObject; - if (_lastListObject == NULL) - _lastListObject = listObject; - - _count++; - _mutations++; - - return listObject; -} - -- (of_list_object_t *)insertObject: (id)object - beforeListObject: (of_list_object_t *)listObject -{ - of_list_object_t *newListObject; - - newListObject = [self allocMemoryWithSize: sizeof(of_list_object_t)]; - newListObject->object = [object retain]; - newListObject->next = listObject; - newListObject->previous = listObject->previous; - - if (listObject->previous != NULL) - listObject->previous->next = newListObject; - - listObject->previous = newListObject; - - if (listObject == _firstListObject) - _firstListObject = newListObject; - - _count++; - _mutations++; - - return newListObject; -} - -- (of_list_object_t *)insertObject: (id)object - afterListObject: (of_list_object_t *)listObject -{ - of_list_object_t *newListObject; - - newListObject = [self allocMemoryWithSize: sizeof(of_list_object_t)]; - newListObject->object = [object retain]; - newListObject->next = listObject->next; - newListObject->previous = listObject; - - if (listObject->next != NULL) - listObject->next->previous = newListObject; - - listObject->next = newListObject; - - if (listObject == _lastListObject) - _lastListObject = newListObject; - - _count++; - _mutations++; - - return newListObject; -} - -- (void)removeListObject: (of_list_object_t *)listObject -{ - if (listObject->previous != NULL) - listObject->previous->next = listObject->next; - if (listObject->next != NULL) - listObject->next->previous = listObject->previous; - - if (_firstListObject == listObject) - _firstListObject = listObject->next; - if (_lastListObject == listObject) - _lastListObject = listObject->previous; - - _count--; - _mutations++; - - [listObject->object release]; - - [self freeMemory: listObject]; -} - -- (id)firstObject -{ - return (_firstListObject != NULL ? _firstListObject->object : nil); -} - -- (id)lastObject -{ - return (_lastListObject != NULL ? _lastListObject->object : nil); + OFListItem next; + + for (OFListItem iter = _firstListItem; iter != NULL; iter = next) { + [iter->object release]; + next = iter->next; + OFFreeMemory(iter); + } + + [super dealloc]; +} + +- (OFListItem)appendObject: (id)object +{ + OFListItem listItem = OFAllocMemory(1, sizeof(*listItem)); + + listItem->object = [object retain]; + listItem->next = NULL; + listItem->previous = _lastListItem; + + if (_lastListItem != NULL) + _lastListItem->next = listItem; + + _lastListItem = listItem; + + if (_firstListItem == NULL) + _firstListItem = listItem; + + _count++; + _mutations++; + + return listItem; +} + +- (OFListItem)prependObject: (id)object +{ + OFListItem listItem = OFAllocMemory(1, sizeof(*listItem)); + + listItem->object = [object retain]; + listItem->next = _firstListItem; + listItem->previous = NULL; + + if (_firstListItem != NULL) + _firstListItem->previous = listItem; + + _firstListItem = listItem; + if (_lastListItem == NULL) + _lastListItem = listItem; + + _count++; + _mutations++; + + return listItem; +} + +- (OFListItem)insertObject: (id)object beforeListItem: (OFListItem)listItem +{ + OFListItem newListItem = OFAllocMemory(1, sizeof(*newListItem)); + + newListItem->object = [object retain]; + newListItem->next = listItem; + newListItem->previous = listItem->previous; + + if (listItem->previous != NULL) + listItem->previous->next = newListItem; + + listItem->previous = newListItem; + + if (listItem == _firstListItem) + _firstListItem = newListItem; + + _count++; + _mutations++; + + return newListItem; +} + +- (OFListItem)insertObject: (id)object afterListItem: (OFListItem)listItem +{ + OFListItem newListItem = OFAllocMemory(1, sizeof(*newListItem)); + + newListItem->object = [object retain]; + newListItem->next = listItem->next; + newListItem->previous = listItem; + + if (listItem->next != NULL) + listItem->next->previous = newListItem; + + listItem->next = newListItem; + + if (listItem == _lastListItem) + _lastListItem = newListItem; + + _count++; + _mutations++; + + return newListItem; +} + +- (void)removeListItem: (OFListItem)listItem +{ + if (listItem->previous != NULL) + listItem->previous->next = listItem->next; + if (listItem->next != NULL) + listItem->next->previous = listItem->previous; + + if (_firstListItem == listItem) + _firstListItem = listItem->next; + if (_lastListItem == listItem) + _lastListItem = listItem->previous; + + _count--; + _mutations++; + + [listItem->object release]; + OFFreeMemory(listItem); +} + +- (id)firstObject +{ + return (_firstListItem != NULL ? _firstListItem->object : nil); +} + +- (id)lastObject +{ + return (_lastListItem != NULL ? _lastListItem->object : nil); } - (size_t)count { return _count; @@ -217,11 +234,11 @@ } - (bool)isEqual: (id)object { OFList *list; - of_list_object_t *iter, *iter2; + OFListItem iter, iter2; if (object == self) return true; if (![object isKindOfClass: [OFList class]]) @@ -230,11 +247,11 @@ list = object; if (list.count != _count) return false; - for (iter = _firstListObject, iter2 = list.firstListObject; + for (iter = _firstListItem, iter2 = list.firstListItem; iter != NULL && iter2 != NULL; iter = iter->next, iter2 = iter2->next) if (![iter->object isEqual: iter2->object]) return false; @@ -247,12 +264,11 @@ - (bool)containsObject: (id)object { if (_count == 0) return false; - for (of_list_object_t *iter = _firstListObject; - iter != NULL; iter = iter->next) + for (OFListItem iter = _firstListItem; iter != NULL; iter = iter->next) if ([iter->object isEqual: object]) return true; return false; } @@ -260,81 +276,74 @@ - (bool)containsObjectIdenticalTo: (id)object { if (_count == 0) return false; - for (of_list_object_t *iter = _firstListObject; - iter != NULL; iter = iter->next) + for (OFListItem iter = _firstListItem; iter != NULL; iter = iter->next) if (iter->object == object) return true; return false; } - (void)removeAllObjects { - of_list_object_t *iter, *next; + OFListItem next; _mutations++; - for (iter = _firstListObject; iter != NULL; iter = next) { + for (OFListItem iter = _firstListItem; iter != NULL; iter = next) { + [iter->object release]; next = iter->next; - - [iter->object release]; - [self freeMemory: iter]; + OFFreeMemory(iter); } - _firstListObject = _lastListObject = NULL; + _firstListItem = _lastListItem = NULL; } - (id)copy { OFList *copy = [[[self class] alloc] init]; - of_list_object_t *listObject, *previous; - - listObject = NULL; - previous = NULL; + OFListItem listItem = NULL, previous = NULL; @try { - for (of_list_object_t *iter = _firstListObject; + for (OFListItem iter = _firstListItem; iter != NULL; iter = iter->next) { - listObject = [copy allocMemoryWithSize: - sizeof(of_list_object_t)]; - listObject->object = [iter->object retain]; - listObject->next = NULL; - listObject->previous = previous; - - if (copy->_firstListObject == NULL) - copy->_firstListObject = listObject; + listItem = OFAllocMemory(1, sizeof(*listItem)); + listItem->object = [iter->object retain]; + listItem->next = NULL; + listItem->previous = previous; + + if (copy->_firstListItem == NULL) + copy->_firstListItem = listItem; if (previous != NULL) - previous->next = listObject; + previous->next = listItem; copy->_count++; - previous = listObject; + previous = listItem; } } @catch (id e) { [copy release]; @throw e; } - copy->_lastListObject = listObject; + copy->_lastListItem = listItem; return copy; } - (unsigned long)hash { - uint32_t hash; - - OF_HASH_INIT(hash); - - for (of_list_object_t *iter = _firstListObject; - iter != NULL; iter = iter->next) - OF_HASH_ADD_HASH(hash, [iter->object hash]); - - OF_HASH_FINALIZE(hash); + unsigned long hash; + + OFHashInit(&hash); + + for (OFListItem iter = _firstListItem; iter != NULL; iter = iter->next) + OFHashAddHash(&hash, [iter->object hash]); + + OFHashFinalize(&hash); return hash; } - (OFString *)description @@ -344,11 +353,11 @@ if (_count == 0) return @"[]"; ret = [OFMutableString stringWithString: @"[\n"]; - for (of_list_object_t *iter = _firstListObject; + for (OFListItem iter = _firstListItem; iter != NULL; iter = iter->next) { void *pool = objc_autoreleasePoolPush(); [ret appendString: [iter->object description]]; @@ -355,12 +364,11 @@ if (iter->next != NULL) [ret appendString: @",\n"]; objc_autoreleasePoolPop(pool); } - [ret replaceOccurrencesOfString: @"\n" - withString: @"\n\t"]; + [ret replaceOccurrencesOfString: @"\n" withString: @"\n\t"]; [ret appendString: @"\n]"]; [ret makeImmutable]; return ret; @@ -368,13 +376,13 @@ - (OFXMLElement *)XMLElementBySerializing { OFXMLElement *element = [OFXMLElement elementWithName: self.className - namespace: OF_SERIALIZATION_NS]; + namespace: OFSerializationNS]; - for (of_list_object_t *iter = _firstListObject; + for (OFListItem iter = _firstListItem; iter != NULL; iter = iter->next) { void *pool = objc_autoreleasePoolPush(); [element addChild: [iter->object XMLElementBySerializing]]; @@ -382,44 +390,44 @@ } return element; } -- (int)countByEnumeratingWithState: (of_fast_enumeration_state_t *)state +- (int)countByEnumeratingWithState: (OFFastEnumerationState *)state objects: (id *)objects count: (int)count { - of_list_object_t *listObject; + OFListItem listItem; - memcpy(&listObject, state->extra, sizeof(listObject)); + memcpy(&listItem, state->extra, sizeof(listItem)); state->itemsPtr = objects; state->mutationsPtr = &_mutations; if (state->state == 0) { - listObject = _firstListObject; + listItem = _firstListItem; state->state = 1; } for (int i = 0; i < count; i++) { - if (listObject == NULL) + if (listItem == NULL) return i; - objects[i] = listObject->object; - listObject = listObject->next; + objects[i] = listItem->object; + listItem = listItem->next; } - memcpy(state->extra, &listObject, sizeof(listObject)); + memcpy(state->extra, &listItem, sizeof(listItem)); return count; } - (OFEnumerator *)objectEnumerator { - return [[[OFListEnumerator alloc] - initWithList: self - mutationsPointer: &_mutations] autorelease]; + return [[[OFListEnumerator alloc] initWithList: self + mutationsPointer: &_mutations] + autorelease]; } @end @implementation OFListEnumerator - (instancetype)initWithList: (OFList *)list @@ -426,11 +434,11 @@ mutationsPointer: (unsigned long *)mutationsPtr { self = [super init]; _list = [list retain]; - _current = _list.firstListObject; + _current = _list.firstListItem; _mutations = *mutationsPtr; _mutationsPtr = mutationsPtr; return self; } Index: src/OFLocale.h ================================================================== --- src/OFLocale.h +++ src/OFLocale.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -45,21 +43,21 @@ */ OF_SUBCLASSING_RESTRICTED @interface OFLocale: OFObject { OFString *_Nullable _language, *_Nullable _territory; - of_string_encoding_t _encoding; + OFStringEncoding _encoding; OFString *_decimalPoint; OFMutableArray OF_GENERIC(OFDictionary OF_GENERIC(OFString *, id) *) *_localizedStrings; } #ifdef OF_HAVE_CLASS_PROPERTIES @property (class, readonly, nullable, nonatomic) OFLocale *currentLocale; @property (class, readonly, nullable, nonatomic) OFString *language; @property (class, readonly, nullable, nonatomic) OFString *territory; -@property (class, readonly, nonatomic) of_string_encoding_t encoding; +@property (class, readonly, nonatomic) OFStringEncoding encoding; @property (class, readonly, nullable, nonatomic) OFString *decimalPoint; #endif /** * @brief The language of the locale for messages. @@ -81,11 +79,11 @@ * This is useful to encode strings correctly for passing them to operating * system calls. * * If the native 8-bit encoding is unknown, UTF-8 is assumed. */ -@property (readonly, nonatomic) of_string_encoding_t encoding; +@property (readonly, nonatomic) OFStringEncoding encoding; /** * @brief The decimal point of the system's locale. */ @property (readonly, nonatomic) OFString *decimalPoint; @@ -127,11 +125,11 @@ * * If the native 8-bit encoding is unknown, UTF-8 is assumed. * * @return The native 8-bit string encoding for the locale */ -+ (of_string_encoding_t)encoding; ++ (OFStringEncoding)encoding; /** * @brief Returns the decimal point of the system's locale. * * @return The decimal point of the system's locale @@ -152,11 +150,11 @@ * * @warning This sets the locale via `setlocale()`! * * @warning You should never call this yourself, except if you do not use * @ref OFApplication. In this case, you need to allocate exactly one - * instance of OFLocale, which will be come the current locale, and + * instance of OFLocale, which will become the current locale, and * call this method. */ - (instancetype)init; #ifdef OF_HAVE_FILES Index: src/OFLocale.m ================================================================== --- src/OFLocale.m +++ src/OFLocale.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -39,18 +37,17 @@ static OFLocale *currentLocale = nil; static OFDictionary *operatorPrecedences = nil; #ifndef OF_AMIGAOS static void -parseLocale(char *locale, of_string_encoding_t *encoding, +parseLocale(char *locale, OFStringEncoding *encoding, OFString **language, OFString **territory) { - if ((locale = of_strdup(locale)) == NULL) - return; + locale = OFStrDup(locale); @try { - const of_string_encoding_t enc = OF_STRING_ENCODING_ASCII; + OFStringEncoding enc = OFStringEncodingASCII; char *tmp; /* We don't care for extras behind the @ */ if ((tmp = strrchr(locale, '@')) != NULL) *tmp = '\0'; @@ -59,11 +56,11 @@ if ((tmp = strrchr(locale, '.')) != NULL) { *tmp++ = '\0'; @try { if (encoding != NULL) - *encoding = of_string_parse_encoding( + *encoding = OFStringEncodingParseName( [OFString stringWithCString: tmp encoding: enc]); } @catch (OFInvalidArgumentException *e) { } } @@ -79,18 +76,19 @@ if (language != NULL) *language = [OFString stringWithCString: locale encoding: enc]; } @finally { - free(locale); + OFFreeMemory(locale); } } #endif static bool -evaluateCondition(OFString *condition, OFDictionary *variables) +evaluateCondition(OFString *condition_, OFDictionary *variables) { + OFMutableString *condition = [[condition_ mutableCopy] autorelease]; OFMutableArray *tokens, *operators, *stack; /* Empty condition is the fallback that's always true */ if (condition.length == 0) return true; @@ -98,25 +96,22 @@ /* * Dirty hack to allow not needing spaces after "!" or "(" and spaces * before ")". * TODO: Replace with a proper tokenizer. */ - condition = [condition stringByReplacingOccurrencesOfString: @"!" - withString: @"! "]; - condition = [condition stringByReplacingOccurrencesOfString: @"(" - withString: @"( "]; - condition = [condition stringByReplacingOccurrencesOfString: @")" - withString: @" )"]; + [condition replaceOccurrencesOfString: @"!" withString: @"! "]; + [condition replaceOccurrencesOfString: @"(" withString: @"( "]; + [condition replaceOccurrencesOfString: @")" withString: @" )"]; /* Substitute variables and convert to RPN first */ tokens = [OFMutableArray array]; operators = [OFMutableArray array]; for (OFString *token in [condition componentsSeparatedByString: @" " - options: OF_STRING_SKIP_EMPTY]) { + options: OFStringSkipEmptyComponents]) { unsigned precedence; - of_unichar_t c; + OFUnichar c; if ([token isEqual: @"("]) { [operators addObject: @"("]; continue; } @@ -199,20 +194,20 @@ else if ([token isEqual: @"!="]) var = [OFNumber numberWithBool: ![first isEqual: second]]; else if ([token isEqual: @"<"]) var = [OFNumber numberWithBool: [first - compare: second] == OF_ORDERED_ASCENDING]; + compare: second] == OFOrderedAscending]; else if ([token isEqual: @"<="]) var = [OFNumber numberWithBool: [first - compare: second] != OF_ORDERED_DESCENDING]; + compare: second] != OFOrderedDescending]; else if ([token isEqual: @">"]) var = [OFNumber numberWithBool: [first - compare: second] == OF_ORDERED_DESCENDING]; + compare: second] == OFOrderedDescending]; else if ([token isEqual: @">="]) var = [OFNumber numberWithBool: [first - compare: second] != OF_ORDERED_ASCENDING]; + compare: second] != OFOrderedAscending]; else if ([token isEqual: @"+"]) var = [OFNumber numberWithDouble: [first doubleValue] + [second doubleValue]]; else if ([token isEqual: @"%"]) var = [OFNumber numberWithLongLong: @@ -223,11 +218,11 @@ [first boolValue] && [second boolValue]]; else if ([token isEqual: @"||"]) var = [OFNumber numberWithBool: [first boolValue] || [second boolValue]]; else - OF_ENSURE(0); + OFEnsure(0); [stack replaceObjectAtIndex: stackSize - 2 withObject: var]; [stack removeLastObject]; } else if (precedence == 1) { @@ -240,11 +235,11 @@ else if ([token isEqual: @"is_real"]) var = [OFNumber numberWithBool: ([first doubleValue] != [first longLongValue])]; else - OF_ENSURE(0); + OFEnsure(0); [stack replaceObjectAtIndex: stackSize - 1 withObject: var]; } else [stack addObject: token]; @@ -353,11 +348,11 @@ + (OFString *)territory { return currentLocale.territory; } -+ (of_string_encoding_t)encoding ++ (OFStringEncoding)encoding { return currentLocale.encoding; } + (OFString *)decimalPoint @@ -382,11 +377,11 @@ if (currentLocale != nil) @throw [OFInitializationFailedException exceptionWithClass: self.class]; - _encoding = OF_STRING_ENCODING_UTF_8; + _encoding = OFStringEncodingUTF8; _decimalPoint = @"."; _localizedStrings = [[OFMutableArray alloc] init]; if ((locale = setlocale(LC_ALL, "")) != NULL) _decimalPoint = [[OFString alloc] @@ -426,21 +421,21 @@ # elif defined(OF_AMIGAOS4) if (GetVar("Charset", buffer, sizeof(buffer), 0) > 0) { # else if (0) { # endif - of_string_encoding_t ASCII = OF_STRING_ENCODING_ASCII; + OFStringEncoding ASCII = OFStringEncodingASCII; @try { - _encoding = of_string_parse_encoding( + _encoding = OFStringEncodingParseName( [OFString stringWithCString: buffer encoding: ASCII]); } @catch (OFInvalidArgumentException *e) { - _encoding = OF_STRING_ENCODING_ISO_8859_1; + _encoding = OFStringEncodingISO8859_1; } } else - _encoding = OF_STRING_ENCODING_ISO_8859_1; + _encoding = OFStringEncodingISO8859_1; /* * Get it via localeconv() instead of from the Locale struct, * to make sure we and printf etc. have the same expectations. */ @@ -459,11 +454,11 @@ @try { uint32_t territory; size_t length; territory = - OF_BSWAP32_IF_LE(locale->loc_CountryCode); + OFToBigEndian32(locale->loc_CountryCode); for (length = 0; length < 4; length++) if (((char *)&territory)[length] == 0) break; @@ -571,12 +566,11 @@ size_t last, UTF8StringLength; int state = 0; variables = [OFMutableDictionary dictionary]; while ((name = va_arg(arguments, OFConstantString *)) != nil) - [variables setObject: va_arg(arguments, id) - forKey: name]; + [variables setObject: va_arg(arguments, id) forKey: name]; for (OFDictionary *strings in _localizedStrings) { id string = [strings objectForKey: ID]; if (string == nil) Index: src/OFLocking.h ================================================================== --- src/OFLocking.h +++ src/OFLocking.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFMD5Hash.h ================================================================== --- src/OFMD5Hash.h +++ src/OFMD5Hash.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -13,11 +11,11 @@ * 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 "OFCryptoHash.h" +#import "OFCryptographicHash.h" OF_ASSUME_NONNULL_BEGIN @class OFSecureData; @@ -25,17 +23,17 @@ * @class OFMD5Hash OFMD5Hash.h ObjFW/OFMD5Hash.h * * @brief A class which provides methods to create an MD5 hash. */ OF_SUBCLASSING_RESTRICTED -@interface OFMD5Hash: OFObject +@interface OFMD5Hash: OFObject { OFSecureData *_iVarsData; - struct of_md5_hash_ivars { + struct { uint32_t state[4]; uint64_t bits; - union of_md5_hash_buffer { + union { unsigned char bytes[64]; uint32_t words[16]; } buffer; size_t bufferLength; } *_iVars; Index: src/OFMD5Hash.m ================================================================== --- src/OFMD5Hash.m +++ src/OFMD5Hash.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -21,14 +19,15 @@ #import "OFMD5Hash.h" #import "OFSecureData.h" #import "OFHashAlreadyCalculatedException.h" +#import "OFHashNotCalculatedException.h" #import "OFOutOfRangeException.h" -#define DIGEST_SIZE 16 -#define BLOCK_SIZE 64 +static const size_t digestSize = 16; +static const size_t blockSize = 64; OF_DIRECT_MEMBERS @interface OFMD5Hash () - (void)of_resetState; @end @@ -75,11 +74,11 @@ static OF_INLINE void byteSwapVectorIfBE(uint32_t *vector, uint_fast8_t length) { #ifdef OF_BIG_ENDIAN for (uint_fast8_t i = 0; i < length; i++) - vector[i] = OF_BSWAP32(vector[i]); + vector[i] = OFByteSwap32(vector[i]); #endif } static void processBlock(uint32_t *state, uint32_t *buffer) @@ -92,20 +91,21 @@ new[2] = state[2]; new[3] = state[3]; byteSwapVectorIfBE(buffer, 16); -#define LOOP_BODY(f) \ - { \ - uint32_t tmp = new[3]; \ - tmp = new[3]; \ - new[0] += f(new[1], new[2], new[3]) + \ - buffer[wordOrder[i]] + table[i]; \ - new[3] = new[2]; \ - new[2] = new[1]; \ - new[1] += OF_ROL(new[0], rotateBits[(i % 4) + (i / 16) * 4]); \ - new[0] = tmp;\ +#define LOOP_BODY(f) \ + { \ + uint32_t tmp = new[3]; \ + tmp = new[3]; \ + new[0] += f(new[1], new[2], new[3]) + \ + buffer[wordOrder[i]] + table[i]; \ + new[3] = new[2]; \ + new[2] = new[1]; \ + new[1] += OFRotateLeft(new[0], \ + rotateBits[(i % 4) + (i / 16) * 4]); \ + new[0] = tmp; \ } for (; i < 16; i++) LOOP_BODY(F) for (; i < 32; i++) @@ -127,19 +127,19 @@ @synthesize calculated = _calculated; @synthesize allowsSwappableMemory = _allowsSwappableMemory; + (size_t)digestSize { - return DIGEST_SIZE; + return digestSize; } + (size_t)blockSize { - return BLOCK_SIZE; + return blockSize; } -+ (instancetype)cryptoHashWithAllowsSwappableMemory: (bool)allowsSwappableMemory ++ (instancetype)hashWithAllowsSwappableMemory: (bool)allowsSwappableMemory { return [[[self alloc] initWithAllowsSwappableMemory: allowsSwappableMemory] autorelease]; } @@ -180,16 +180,16 @@ [super dealloc]; } - (size_t)digestSize { - return DIGEST_SIZE; + return digestSize; } - (size_t)blockSize { - return BLOCK_SIZE; + return blockSize; } - (id)copy { OFMD5Hash *copy = [[OFMD5Hash alloc] of_init]; @@ -208,12 +208,11 @@ _iVars->state[1] = 0xEFCDAB89; _iVars->state[2] = 0x98BADCFE; _iVars->state[3] = 0x10325476; } -- (void)updateWithBuffer: (const void *)buffer_ - length: (size_t)length +- (void)updateWithBuffer: (const void *)buffer_ length: (size_t)length { const unsigned char *buffer = buffer_; if (_calculated) @throw [OFHashAlreadyCalculatedException @@ -244,39 +243,46 @@ } } - (const unsigned char *)digest { + if (!_calculated) + @throw [OFHashNotCalculatedException exceptionWithObject: self]; + + return (const unsigned char *)_iVars->state; +} + +- (void)calculate +{ if (_calculated) - return (const unsigned char *)_iVars->state; + @throw [OFHashAlreadyCalculatedException + exceptionWithObject: self]; _iVars->buffer.bytes[_iVars->bufferLength] = 0x80; - of_explicit_memset(_iVars->buffer.bytes + _iVars->bufferLength + 1, 0, + OFZeroMemory(_iVars->buffer.bytes + _iVars->bufferLength + 1, 64 - _iVars->bufferLength - 1); if (_iVars->bufferLength >= 56) { processBlock(_iVars->state, _iVars->buffer.words); - of_explicit_memset(_iVars->buffer.bytes, 0, 64); + OFZeroMemory(_iVars->buffer.bytes, 64); } _iVars->buffer.words[14] = - OF_BSWAP32_IF_BE((uint32_t)(_iVars->bits & 0xFFFFFFFF)); + OFToLittleEndian32((uint32_t)(_iVars->bits & 0xFFFFFFFF)); _iVars->buffer.words[15] = - OF_BSWAP32_IF_BE((uint32_t)(_iVars->bits >> 32)); + OFToLittleEndian32((uint32_t)(_iVars->bits >> 32)); processBlock(_iVars->state, _iVars->buffer.words); - of_explicit_memset(&_iVars->buffer, 0, sizeof(_iVars->buffer)); + OFZeroMemory(&_iVars->buffer, sizeof(_iVars->buffer)); byteSwapVectorIfBE(_iVars->state, 4); _calculated = true; - - return (const unsigned char *)_iVars->state; } - (void)reset { [self of_resetState]; _iVars->bits = 0; - of_explicit_memset(&_iVars->buffer, 0, sizeof(_iVars->buffer)); + OFZeroMemory(&_iVars->buffer, sizeof(_iVars->buffer)); _iVars->bufferLength = 0; _calculated = false; } @end Index: src/OFMapTable+Private.h ================================================================== --- src/OFMapTable+Private.h +++ src/OFMapTable+Private.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFMapTable.h ================================================================== --- src/OFMapTable.h +++ src/OFMapTable.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -21,26 +19,25 @@ OF_ASSUME_NONNULL_BEGIN /** @file */ /** - * @struct of_map_table_functions_t OFMapTable.h ObjFW/OFMapTable.h + * @struct OFMapTableFunctions OFMapTable.h ObjFW/OFMapTable.h * * @brief A struct describing the functions to be used by the map table. */ -struct of_map_table_functions_t { +typedef struct { /** The function to retain keys / objects */ void *_Nullable (*_Nullable retain)(void *_Nullable object); /** The function to release keys / objects */ void (*_Nullable release)(void *_Nullable object); /** The function to hash keys */ unsigned long (*_Nullable hash)(void *_Nullable object); /** The function to compare keys / objects */ bool (*_Nullable equal)(void *_Nullable object1, void *_Nullable object2); -}; -typedef struct of_map_table_functions_t of_map_table_functions_t; +} OFMapTableFunctions; #ifdef OF_HAVE_BLOCKS /** * @brief A block for enumerating an OFMapTable. * @@ -47,21 +44,21 @@ * @param key The current key * @param object The current object * @param stop A pointer to a variable that can be set to true to stop the * enumeration */ -typedef void (^of_map_table_enumeration_block_t)(void *_Nullable key, +typedef void (^OFMapTableEnumerationBlock)(void *_Nullable key, void *_Nullable object, bool *stop); /** * @brief A block for replacing objects in an OFMapTable. * * @param key The key of the object to replace * @param object The object to replace * @return The object to replace the object with */ -typedef void *_Nullable (^of_map_table_replace_block_t)(void *_Nullable key, +typedef void *_Nullable (^OFMapTableReplaceBlock)(void *_Nullable key, void *_Nullable object); #endif @class OFMapTableEnumerator; @@ -72,26 +69,26 @@ * and objects should be retained, released, compared and hashed. */ OF_SUBCLASSING_RESTRICTED @interface OFMapTable: OFObject { - of_map_table_functions_t _keyFunctions, _objectFunctions; - struct of_map_table_bucket *_Nonnull *_Nullable _buckets; - unsigned long _count, _capacity; + OFMapTableFunctions _keyFunctions, _objectFunctions; + struct OFMapTableBucket *_Nonnull *_Nullable _buckets; + uint32_t _count, _capacity; unsigned char _rotate; unsigned long _mutations; } /** * @brief The key functions used by the map table. */ -@property (readonly, nonatomic) of_map_table_functions_t keyFunctions; +@property (readonly, nonatomic) OFMapTableFunctions keyFunctions; /** * @brief The object functions used by the map table. */ -@property (readonly, nonatomic) of_map_table_functions_t objectFunctions; +@property (readonly, nonatomic) OFMapTableFunctions objectFunctions; /** * @brief The number of objects in the map table. */ @property (readonly, nonatomic) size_t count; @@ -101,13 +98,12 @@ * * @param keyFunctions A structure of functions for handling keys * @param objectFunctions A structure of functions for handling objects * @return A new autoreleased OFMapTable */ -+ (instancetype)mapTableWithKeyFunctions: (of_map_table_functions_t)keyFunctions - objectFunctions: (of_map_table_functions_t) - objectFunctions; ++ (instancetype)mapTableWithKeyFunctions: (OFMapTableFunctions)keyFunctions + objectFunctions: (OFMapTableFunctions)objectFunctions; /** * @brief Creates a new OFMapTable with the specified key functions, object * functions and capacity. * @@ -115,13 +111,12 @@ * @param objectFunctions A structure of functions for handling objects * @param capacity A hint about the count of elements expected to be in the map * table * @return A new autoreleased OFMapTable */ -+ (instancetype)mapTableWithKeyFunctions: (of_map_table_functions_t)keyFunctions - objectFunctions: (of_map_table_functions_t) - objectFunctions ++ (instancetype)mapTableWithKeyFunctions: (OFMapTableFunctions)keyFunctions + objectFunctions: (OFMapTableFunctions)objectFunctions capacity: (size_t)capacity; - (instancetype)init OF_UNAVAILABLE; /** @@ -130,12 +125,12 @@ * * @param keyFunctions A structure of functions for handling keys * @param objectFunctions A structure of functions for handling objects * @return An initialized OFMapTable */ -- (instancetype)initWithKeyFunctions: (of_map_table_functions_t)keyFunctions - objectFunctions: (of_map_table_functions_t)objectFunctions; +- (instancetype)initWithKeyFunctions: (OFMapTableFunctions)keyFunctions + objectFunctions: (OFMapTableFunctions)objectFunctions; /** * @brief Initializes an already allocated OFMapTable with the specified key * functions, object functions and capacity. * @@ -143,12 +138,12 @@ * @param objectFunctions A structure of functions for handling objects * @param capacity A hint about the count of elements expected to be in the map * table * @return An initialized OFMapTable */ -- (instancetype)initWithKeyFunctions: (of_map_table_functions_t)keyFunctions - objectFunctions: (of_map_table_functions_t)objectFunctions +- (instancetype)initWithKeyFunctions: (OFMapTableFunctions)keyFunctions + objectFunctions: (OFMapTableFunctions)objectFunctions capacity: (size_t)capacity OF_DESIGNATED_INITIALIZER; /** * @brief Returns the object for the given key or NULL if the key was not found. @@ -162,12 +157,11 @@ * @brief Sets an object for a key. * * @param key The key to set * @param object The object to set the key to */ -- (void)setObject: (nullable void *)object - forKey: (nullable void *)key; +- (void)setObject: (nullable void *)object forKey: (nullable void *)key; /** * @brief Removes the object for the specified key from the map table. * * @param key The key whose object should be removed @@ -218,19 +212,18 @@ /** * @brief Executes a block for each key / object pair. * * @param block The block to execute for each key / object pair. */ -- (void)enumerateKeysAndObjectsUsingBlock: - (of_map_table_enumeration_block_t)block; +- (void)enumerateKeysAndObjectsUsingBlock: (OFMapTableEnumerationBlock)block; /** * @brief Replaces each object with the object returned by the block. * * @param block The block which returns a new object for each object */ -- (void)replaceObjectsUsingBlock: (of_map_table_replace_block_t)block; +- (void)replaceObjectsUsingBlock: (OFMapTableReplaceBlock)block; #endif @end /** * @class OFMapTableEnumerator OFMapTable.h ObjFW/OFMapTable.h @@ -239,13 +232,13 @@ * keys or objects. */ @interface OFMapTableEnumerator: OFObject { OFMapTable *_mapTable; - struct of_map_table_bucket *_Nonnull *_Nullable _buckets; - unsigned long _capacity, _mutations, *_Nullable _mutationsPtr; - unsigned long _position; + struct OFMapTableBucket *_Nonnull *_Nullable _buckets; + uint32_t _capacity; + unsigned long _mutations, *_Nullable _mutationsPtr, _position; } - (instancetype)init OF_UNAVAILABLE; /** Index: src/OFMapTable.m ================================================================== --- src/OFMapTable.m +++ src/OFMapTable.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -28,17 +26,19 @@ #import "OFEnumerationMutationException.h" #import "OFInvalidArgumentException.h" #import "OFOutOfRangeException.h" -#define MIN_CAPACITY 16 +extern uint32_t OFHashSeed; -struct of_map_table_bucket { +static const uint32_t minCapacity = 16; + +struct OFMapTableBucket { void *key, *object; - unsigned long hash; + uint32_t hash; }; -static struct of_map_table_bucket deleted = { 0 }; +static struct OFMapTableBucket deletedBucket = { 0 }; static void * defaultRetain(void *object) { return object; @@ -59,22 +59,15 @@ defaultEqual(void *object1, void *object2) { return (object1 == object2); } -OF_DIRECT_MEMBERS -@interface OFMapTable () -- (void)of_setObject: (void *)object - forKey: (void *)key - hash: (unsigned long)hash; -@end - OF_DIRECT_MEMBERS @interface OFMapTableEnumerator () - (instancetype)of_initWithMapTable: (OFMapTable *)mapTable - buckets: (struct of_map_table_bucket **)buckets - capacity: (unsigned long)capacity + buckets: (struct OFMapTableBucket **)buckets + capacity: (uint32_t)capacity mutationsPointer: (unsigned long *)mutationsPtr OF_METHOD_FAMILY(init); @end @interface OFMapTableKeyEnumerator: OFMapTableEnumerator @@ -84,22 +77,20 @@ @end @implementation OFMapTable @synthesize keyFunctions = _keyFunctions, objectFunctions = _objectFunctions; -+ (instancetype)mapTableWithKeyFunctions: (of_map_table_functions_t)keyFunctions - objectFunctions: (of_map_table_functions_t) - objectFunctions ++ (instancetype)mapTableWithKeyFunctions: (OFMapTableFunctions)keyFunctions + objectFunctions: (OFMapTableFunctions)objectFunctions { return [[[self alloc] initWithKeyFunctions: keyFunctions objectFunctions: objectFunctions] autorelease]; } -+ (instancetype)mapTableWithKeyFunctions: (of_map_table_functions_t)keyFunctions - objectFunctions: (of_map_table_functions_t) - objectFunctions ++ (instancetype)mapTableWithKeyFunctions: (OFMapTableFunctions)keyFunctions + objectFunctions: (OFMapTableFunctions)objectFunctions capacity: (size_t)capacity { return [[[self alloc] initWithKeyFunctions: keyFunctions objectFunctions: objectFunctions @@ -109,20 +100,20 @@ - (instancetype)init { OF_INVALID_INIT_METHOD } -- (instancetype)initWithKeyFunctions: (of_map_table_functions_t)keyFunctions - objectFunctions: (of_map_table_functions_t)objectFunctions +- (instancetype)initWithKeyFunctions: (OFMapTableFunctions)keyFunctions + objectFunctions: (OFMapTableFunctions)objectFunctions { return [self initWithKeyFunctions: keyFunctions objectFunctions: objectFunctions capacity: 0]; } -- (instancetype)initWithKeyFunctions: (of_map_table_functions_t)keyFunctions - objectFunctions: (of_map_table_functions_t)objectFunctions +- (instancetype)initWithKeyFunctions: (OFMapTableFunctions)keyFunctions + objectFunctions: (OFMapTableFunctions)objectFunctions capacity: (size_t)capacity { self = [super init]; @try { @@ -143,33 +134,32 @@ SET_DEFAULT(_objectFunctions.hash, defaultHash); SET_DEFAULT(_objectFunctions.equal, defaultEqual); #undef SET_DEFAULT - if (capacity > ULONG_MAX / sizeof(*_buckets) || - capacity > ULONG_MAX / 8) + if (capacity > UINT32_MAX / sizeof(*_buckets) || + capacity > UINT32_MAX / 8) @throw [OFOutOfRangeException exception]; for (_capacity = 1; _capacity < capacity;) { - if (_capacity > ULONG_MAX / 2) + if (_capacity > UINT32_MAX / 2) @throw [OFOutOfRangeException exception]; _capacity *= 2; } if (capacity * 8 / _capacity >= 6) - if (_capacity <= ULONG_MAX / 2) + if (_capacity <= UINT32_MAX / 2) _capacity *= 2; - if (_capacity < MIN_CAPACITY) - _capacity = MIN_CAPACITY; - - _buckets = [self allocZeroedMemoryWithSize: sizeof(*_buckets) - count: _capacity]; - - if (of_hash_seed != 0) - _rotate = of_random16() & 31; + if (_capacity < minCapacity) + _capacity = minCapacity; + + _buckets = OFAllocZeroedMemory(_capacity, sizeof(*_buckets)); + + if (OFHashSeed != 0) + _rotate = OFRandom16() & 31; } @catch (id e) { [self release]; @throw e; } @@ -176,19 +166,176 @@ return self; } - (void)dealloc { - for (unsigned long i = 0; i < _capacity; i++) { - if (_buckets[i] != NULL && _buckets[i] != &deleted) { + for (uint32_t i = 0; i < _capacity; i++) { + if (_buckets[i] != NULL && _buckets[i] != &deletedBucket) { _keyFunctions.release(_buckets[i]->key); _objectFunctions.release(_buckets[i]->object); + + OFFreeMemory(_buckets[i]); } } + + OFFreeMemory(_buckets); [super dealloc]; } + +static void +resizeForCount(OFMapTable *self, uint32_t count) +{ + uint32_t fullness, capacity; + struct OFMapTableBucket **buckets; + + if (count > UINT32_MAX / sizeof(*self->_buckets) || + count > UINT32_MAX / 8) + @throw [OFOutOfRangeException exception]; + + fullness = count * 8 / self->_capacity; + + if (fullness >= 6) { + if (self->_capacity > UINT32_MAX / 2) + return; + + capacity = self->_capacity * 2; + } else if (fullness <= 1) + capacity = self->_capacity / 2; + else + return; + + /* + * Don't downsize if we have an initial capacity or if we would fall + * below the minimum capacity. + */ + if ((capacity < self->_capacity && count > self->_count) || + capacity < minCapacity) + return; + + buckets = OFAllocZeroedMemory(capacity, sizeof(*buckets)); + + for (uint32_t i = 0; i < self->_capacity; i++) { + if (self->_buckets[i] != NULL && + self->_buckets[i] != &deletedBucket) { + uint32_t j, last; + + last = capacity; + + for (j = self->_buckets[i]->hash & (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); + + for (j = 0; j < last && + buckets[j] != NULL; j++); + } + + if (j >= last) + @throw [OFOutOfRangeException exception]; + + buckets[j] = self->_buckets[i]; + } + } + + OFFreeMemory(self->_buckets); + self->_buckets = buckets; + self->_capacity = capacity; +} + +static void +setObject(OFMapTable *restrict self, void *key, void *object, uint32_t hash) +{ + uint32_t i, last; + void *old; + + if (key == NULL || object == NULL) + @throw [OFInvalidArgumentException exception]; + + hash = OFRotateLeft(hash, self->_rotate); + last = self->_capacity; + + for (i = hash & (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)) + break; + } + + /* In case the last bucket is already used */ + if (i >= last) { + last = hash & (self->_capacity - 1); + + for (i = 0; i < last && self->_buckets[i] != NULL; i++) { + if (self->_buckets[i] == &deletedBucket) + continue; + + if (self->_keyFunctions.equal( + self->_buckets[i]->key, key)) + break; + } + } + + /* Key not in map table */ + if (i >= last || self->_buckets[i] == NULL || + self->_buckets[i] == &deletedBucket || + !self->_keyFunctions.equal(self->_buckets[i]->key, key)) { + struct OFMapTableBucket *bucket; + + resizeForCount(self, self->_count + 1); + + self->_mutations++; + last = self->_capacity; + + for (i = hash & (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); + + for (i = 0; i < last && self->_buckets[i] != NULL && + self->_buckets[i] != &deletedBucket; i++); + } + + if (i >= last) + @throw [OFOutOfRangeException exception]; + + bucket = OFAllocMemory(1, sizeof(*bucket)); + + @try { + bucket->key = self->_keyFunctions.retain(key); + } @catch (id e) { + OFFreeMemory(bucket); + @throw e; + } + + @try { + bucket->object = self->_objectFunctions.retain(object); + } @catch (id e) { + self->_keyFunctions.release(bucket->key); + OFFreeMemory(bucket); + @throw e; + } + + bucket->hash = hash; + + self->_buckets[i] = bucket; + self->_count++; + + return; + } + + old = self->_buckets[i]->object; + self->_buckets[i]->object = self->_objectFunctions.retain(object); + self->_objectFunctions.release(old); +} - (bool)isEqual: (id)object { OFMapTable *mapTable; @@ -203,12 +350,12 @@ if (mapTable->_count != _count || mapTable->_keyFunctions.equal != _keyFunctions.equal || mapTable->_objectFunctions.equal != _objectFunctions.equal) return false; - for (unsigned long i = 0; i < _capacity; i++) { - if (_buckets[i] != NULL && _buckets[i] != &deleted) { + for (uint32_t i = 0; i < _capacity; i++) { + if (_buckets[i] != NULL && _buckets[i] != &deletedBucket) { void *objectIter = [mapTable objectForKey: _buckets[i]->key]; if (!_objectFunctions.equal(objectIter, _buckets[i]->object)) @@ -222,12 +369,12 @@ - (unsigned long)hash { unsigned long hash = 0; for (unsigned long i = 0; i < _capacity; i++) { - if (_buckets[i] != NULL && _buckets[i] != &deleted) { - hash ^= OF_ROR(_buckets[i]->hash, _rotate); + if (_buckets[i] != NULL && _buckets[i] != &deletedBucket) { + hash ^= OFRotateRight(_buckets[i]->hash, _rotate); hash ^= _objectFunctions.hash(_buckets[i]->object); } } return hash; @@ -239,16 +386,16 @@ initWithKeyFunctions: _keyFunctions objectFunctions: _objectFunctions capacity: _capacity]; @try { - for (unsigned long i = 0; i < _capacity; i++) - if (_buckets[i] != NULL && _buckets[i] != &deleted) - [copy of_setObject: _buckets[i]->object - forKey: _buckets[i]->key - hash: OF_ROR(_buckets[i]->hash, - _rotate)]; + 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)); } @catch (id e) { [copy release]; @throw e; } @@ -260,20 +407,20 @@ return _count; } - (void *)objectForKey: (void *)key { - unsigned long i, hash, last; + uint32_t i, hash, last; if (key == NULL) @throw [OFInvalidArgumentException exception]; - hash = OF_ROL(_keyFunctions.hash(key), _rotate); + hash = OFRotateLeft((uint32_t)_keyFunctions.hash(key), _rotate); last = _capacity; for (i = hash & (_capacity - 1); i < last && _buckets[i] != NULL; i++) { - if (_buckets[i] == &deleted) + if (_buckets[i] == &deletedBucket) continue; if (_keyFunctions.equal(_buckets[i]->key, key)) return _buckets[i]->object; } @@ -283,200 +430,50 @@ /* In case the last bucket is already used */ last = hash & (_capacity - 1); for (i = 0; i < last && _buckets[i] != NULL; i++) { - if (_buckets[i] == &deleted) + if (_buckets[i] == &deletedBucket) continue; if (_keyFunctions.equal(_buckets[i]->key, key)) return _buckets[i]->object; } return NULL; } -- (void)of_resizeForCount: (unsigned long)count OF_DIRECT -{ - unsigned long fullness, capacity; - struct of_map_table_bucket **buckets; - - if (count > ULONG_MAX / sizeof(*_buckets) || count > ULONG_MAX / 8) - @throw [OFOutOfRangeException exception]; - - fullness = count * 8 / _capacity; - - if (fullness >= 6) { - if (_capacity > ULONG_MAX / 2) - return; - - capacity = _capacity * 2; - } else if (fullness <= 1) - capacity = _capacity / 2; - else - return; - - /* - * Don't downsize if we have an initial capacity or if we would fall - * below the minimum capacity. - */ - if ((capacity < _capacity && count > _count) || capacity < MIN_CAPACITY) - return; - - buckets = [self allocZeroedMemoryWithSize: sizeof(*buckets) - count: capacity]; - - for (unsigned long i = 0; i < _capacity; i++) { - if (_buckets[i] != NULL && _buckets[i] != &deleted) { - unsigned long j, last; - - last = capacity; - - for (j = _buckets[i]->hash & (capacity - 1); - j < last && buckets[j] != NULL; j++); - - /* In case the last bucket is already used */ - if (j >= last) { - last = _buckets[i]->hash & (capacity - 1); - - for (j = 0; j < last && - buckets[j] != NULL; j++); - } - - if (j >= last) - @throw [OFOutOfRangeException exception]; - - buckets[j] = _buckets[i]; - } - } - - [self freeMemory: _buckets]; - _buckets = buckets; - _capacity = capacity; -} - -- (void)of_setObject: (void *)object - forKey: (void *)key - hash: (unsigned long)hash -{ - unsigned long i, last; - void *old; - - if (key == NULL || object == NULL) - @throw [OFInvalidArgumentException exception]; - - hash = OF_ROL(hash, _rotate); - last = _capacity; - - for (i = hash & (_capacity - 1); i < last && _buckets[i] != NULL; i++) { - if (_buckets[i] == &deleted) - continue; - - if (_keyFunctions.equal(_buckets[i]->key, key)) - break; - } - - /* In case the last bucket is already used */ - if (i >= last) { - last = hash & (_capacity - 1); - - for (i = 0; i < last && _buckets[i] != NULL; i++) { - if (_buckets[i] == &deleted) - continue; - - if (_keyFunctions.equal(_buckets[i]->key, key)) - break; - } - } - - /* Key not in map table */ - if (i >= last || _buckets[i] == NULL || _buckets[i] == &deleted || - !_keyFunctions.equal(_buckets[i]->key, key)) { - struct of_map_table_bucket *bucket; - - [self of_resizeForCount: _count + 1]; - - _mutations++; - last = _capacity; - - for (i = hash & (_capacity - 1); i < last && - _buckets[i] != NULL && _buckets[i] != &deleted; i++); - - /* In case the last bucket is already used */ - if (i >= last) { - last = hash & (_capacity - 1); - - for (i = 0; i < last && _buckets[i] != NULL && - _buckets[i] != &deleted; i++); - } - - if (i >= last) - @throw [OFOutOfRangeException exception]; - - bucket = [self allocMemoryWithSize: sizeof(*bucket)]; - - @try { - bucket->key = _keyFunctions.retain(key); - } @catch (id e) { - [self freeMemory: bucket]; - @throw e; - } - - @try { - bucket->object = _objectFunctions.retain(object); - } @catch (id e) { - _keyFunctions.release(bucket->key); - [self freeMemory: bucket]; - @throw e; - } - - bucket->hash = hash; - - _buckets[i] = bucket; - _count++; - - return; - } - - old = _buckets[i]->object; - _buckets[i]->object = _objectFunctions.retain(object); - _objectFunctions.release(old); -} - -- (void)setObject: (void *)object - forKey: (void *)key -{ - [self of_setObject: object - forKey: key - hash: _keyFunctions.hash(key)]; +- (void)setObject: (void *)object forKey: (void *)key +{ + setObject(self, key, object, (uint32_t)_keyFunctions.hash(key)); } - (void)removeObjectForKey: (void *)key { - unsigned long i, hash, last; + uint32_t i, hash, last; if (key == NULL) @throw [OFInvalidArgumentException exception]; - hash = OF_ROL(_keyFunctions.hash(key), _rotate); + hash = OFRotateLeft((uint32_t)_keyFunctions.hash(key), _rotate); last = _capacity; for (i = hash & (_capacity - 1); i < last && _buckets[i] != NULL; i++) { - if (_buckets[i] == &deleted) + if (_buckets[i] == &deletedBucket) continue; if (_keyFunctions.equal(_buckets[i]->key, key)) { _mutations++; _keyFunctions.release(_buckets[i]->key); _objectFunctions.release(_buckets[i]->object); - [self freeMemory: _buckets[i]]; - _buckets[i] = &deleted; + OFFreeMemory(_buckets[i]); + _buckets[i] = &deletedBucket; _count--; - [self of_resizeForCount: _count]; + resizeForCount(self, _count); return; } } @@ -485,67 +482,65 @@ /* In case the last bucket is already used */ last = hash & (_capacity - 1); for (i = 0; i < last && _buckets[i] != NULL; i++) { - if (_buckets[i] == &deleted) + if (_buckets[i] == &deletedBucket) continue; if (_keyFunctions.equal(_buckets[i]->key, key)) { _keyFunctions.release(_buckets[i]->key); _objectFunctions.release(_buckets[i]->object); - [self freeMemory: _buckets[i]]; - _buckets[i] = &deleted; + OFFreeMemory(_buckets[i]); + _buckets[i] = &deletedBucket; _count--; _mutations++; - [self of_resizeForCount: _count]; + resizeForCount(self, _count); return; } } } - (void)removeAllObjects { - for (unsigned long i = 0; i < _capacity; i++) { + for (uint32_t i = 0; i < _capacity; i++) { if (_buckets[i] != NULL) { - if (_buckets[i] == &deleted) { + if (_buckets[i] == &deletedBucket) { _buckets[i] = NULL; continue; } _keyFunctions.release(_buckets[i]->key); _objectFunctions.release(_buckets[i]->object); - [self freeMemory: _buckets[i]]; + OFFreeMemory(_buckets[i]); _buckets[i] = NULL; } } _count = 0; - _capacity = MIN_CAPACITY; - _buckets = [self resizeMemory: _buckets - size: sizeof(*_buckets) - count: _capacity]; + _capacity = minCapacity; + _buckets = OFResizeMemory(_buckets, _capacity, sizeof(*_buckets)); /* * Get a new random value for _rotate, so that it is not less secure * than creating a new hash map. */ - if (of_hash_seed != 0) - _rotate = of_random16() & 31; + if (OFHashSeed != 0) + _rotate = OFRandom16() & 31; } - (bool)containsObject: (void *)object { if (object == NULL || _count == 0) return false; - for (unsigned long i = 0; i < _capacity; i++) - if (_buckets[i] != NULL && _buckets[i] != &deleted) + for (uint32_t i = 0; i < _capacity; i++) + if (_buckets[i] != NULL && _buckets[i] != &deletedBucket) if (_objectFunctions.equal(_buckets[i]->object, object)) return true; return false; } @@ -553,12 +548,12 @@ - (bool)containsObjectIdenticalTo: (void *)object { if (object == NULL || _count == 0) return false; - for (unsigned long i = 0; i < _capacity; i++) - if (_buckets[i] != NULL && _buckets[i] != &deleted) + for (uint32_t i = 0; i < _capacity; i++) + if (_buckets[i] != NULL && _buckets[i] != &deletedBucket) if (_buckets[i]->object == object) return true; return false; } @@ -579,20 +574,20 @@ buckets: _buckets capacity: _capacity mutationsPointer: &_mutations] autorelease]; } -- (int)countByEnumeratingWithState: (of_fast_enumeration_state_t *)state +- (int)countByEnumeratingWithState: (OFFastEnumerationState *)state objects: (id *)objects count: (int)count { unsigned long j = state->state; int i; for (i = 0; i < count; i++) { for (; j < _capacity && (_buckets[j] == NULL || - _buckets[j] == &deleted); j++); + _buckets[j] == &deletedBucket); j++); if (j < _capacity) { objects[i] = _buckets[j]->key; j++; } else @@ -605,36 +600,35 @@ return i; } #ifdef OF_HAVE_BLOCKS -- (void)enumerateKeysAndObjectsUsingBlock: - (of_map_table_enumeration_block_t)block +- (void)enumerateKeysAndObjectsUsingBlock: (OFMapTableEnumerationBlock)block { bool stop = false; unsigned long mutations = _mutations; for (size_t i = 0; i < _capacity && !stop; i++) { if (_mutations != mutations) @throw [OFEnumerationMutationException exceptionWithObject: self]; - if (_buckets[i] != NULL && _buckets[i] != &deleted) + if (_buckets[i] != NULL && _buckets[i] != &deletedBucket) block(_buckets[i]->key, _buckets[i]->object, &stop); } } -- (void)replaceObjectsUsingBlock: (of_map_table_replace_block_t)block +- (void)replaceObjectsUsingBlock: (OFMapTableReplaceBlock)block { unsigned long mutations = _mutations; for (size_t i = 0; i < _capacity; i++) { if (_mutations != mutations) @throw [OFEnumerationMutationException exceptionWithObject: self]; - if (_buckets[i] != NULL && _buckets[i] != &deleted) { + if (_buckets[i] != NULL && _buckets[i] != &deletedBucket) { void *new; new = block(_buckets[i]->key, _buckets[i]->object); if (new == NULL) @throw [OFInvalidArgumentException exception]; @@ -655,12 +649,12 @@ { OF_INVALID_INIT_METHOD } - (instancetype)of_initWithMapTable: (OFMapTable *)mapTable - buckets: (struct of_map_table_bucket **)buckets - capacity: (unsigned long)capacity + buckets: (struct OFMapTableBucket **)buckets + capacity: (uint32_t)capacity mutationsPointer: (unsigned long *)mutationsPtr { self = [super init]; _mapTable = [mapTable retain]; @@ -691,11 +685,11 @@ if (*_mutationsPtr != _mutations) @throw [OFEnumerationMutationException exceptionWithObject: _mapTable]; for (; _position < _capacity && (_buckets[_position] == NULL || - _buckets[_position] == &deleted); _position++); + _buckets[_position] == &deletedBucket); _position++); if (_position < _capacity) return &_buckets[_position++]->key; else return NULL; @@ -708,11 +702,11 @@ if (*_mutationsPtr != _mutations) @throw [OFEnumerationMutationException exceptionWithObject: _mapTable]; for (; _position < _capacity && (_buckets[_position] == NULL || - _buckets[_position] == &deleted); _position++); + _buckets[_position] == &deletedBucket); _position++); if (_position < _capacity) return &_buckets[_position++]->object; else return NULL; Index: src/OFMapTableDictionary.h ================================================================== --- src/OFMapTableDictionary.h +++ src/OFMapTableDictionary.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFMapTableDictionary.m ================================================================== --- src/OFMapTableDictionary.m +++ src/OFMapTableDictionary.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -59,17 +57,17 @@ equal(void *object1, void *object2) { return [(id)object1 isEqual: (id)object2]; } -static const of_map_table_functions_t keyFunctions = { +static const OFMapTableFunctions keyFunctions = { .retain = copy, .release = release, .hash = hash, .equal = equal }; -static const of_map_table_functions_t objectFunctions = { +static const OFMapTableFunctions objectFunctions = { .retain = retain, .release = release, .hash = hash, .equal = equal }; @@ -137,12 +135,11 @@ keyEnumerator = [dictionary keyEnumerator]; objectEnumerator = [dictionary objectEnumerator]; while ((key = [keyEnumerator nextObject]) != nil && (object = [objectEnumerator nextObject]) != nil) - [_mapTable setObject: object - forKey: key]; + [_mapTable setObject: object forKey: key]; objc_autoreleasePoolPop(pool); } @catch (id e) { [self release]; @throw e; @@ -149,18 +146,16 @@ } return self; } -- (instancetype)initWithObject: (id)object - forKey: (id)key +- (instancetype)initWithObject: (id)object forKey: (id)key { self = [self initWithCapacity: 1]; @try { - [_mapTable setObject: object - forKey: key]; + [_mapTable setObject: object forKey: key]; } @catch (id e) { [self release]; @throw e; } @@ -175,22 +170,20 @@ @try { size_t i; for (i = 0; i < count; i++) - [_mapTable setObject: objects[i] - forKey: keys[i]]; + [_mapTable setObject: objects[i] forKey: keys[i]]; } @catch (id e) { [self release]; @throw e; } return self; } -- (instancetype)initWithKey: (id)firstKey - arguments: (va_list)arguments +- (instancetype)initWithKey: (id)firstKey arguments: (va_list)arguments { self = [super init]; @try { va_list argumentsCopy; @@ -218,22 +211,20 @@ _mapTable = [[OFMapTable alloc] initWithKeyFunctions: keyFunctions objectFunctions: objectFunctions capacity: count]; - [_mapTable setObject: object - forKey: key]; + [_mapTable setObject: object forKey: key]; for (i = 1; i < count; i++) { key = va_arg(arguments, id); object = va_arg(arguments, id); if (key == nil || object == nil) @throw [OFInvalidArgumentException exception]; - [_mapTable setObject: object - forKey: key]; + [_mapTable setObject: object forKey: key]; } } @catch (id e) { [self release]; @throw e; } @@ -250,13 +241,13 @@ OFArray *keys, *objects; OFEnumerator *keyEnumerator, *objectEnumerator; OFXMLElement *keyElement, *objectElement; keys = [element elementsForName: @"key" - namespace: OF_SERIALIZATION_NS]; + namespace: OFSerializationNS]; objects = [element elementsForName: @"object" - namespace: OF_SERIALIZATION_NS]; + namespace: OFSerializationNS]; if (keys.count != objects.count) @throw [OFInvalidFormatException exception]; _mapTable = [[OFMapTable alloc] @@ -270,13 +261,13 @@ (objectElement = [objectEnumerator nextObject]) != nil) { void *pool2 = objc_autoreleasePoolPush(); OFXMLElement *key, *object; key = [keyElement elementsForNamespace: - OF_SERIALIZATION_NS].firstObject; + OFSerializationNS].firstObject; object = [objectElement elementsForNamespace: - OF_SERIALIZATION_NS].firstObject; + OFSerializationNS].firstObject; if (key == nil || object == nil) @throw [OFInvalidFormatException exception]; [_mapTable setObject: object.objectByDeserializing @@ -342,12 +333,11 @@ OFArray *ret; id *keys; size_t count; count = _mapTable.count; - keys = [self allocMemoryWithSize: sizeof(*keys) - count: count]; + keys = OFAllocMemory(count, sizeof(*keys)); @try { void *pool = objc_autoreleasePoolPush(); OFMapTableEnumerator *enumerator; void **keyPtr; @@ -361,14 +351,13 @@ keys[i++] = (id)*keyPtr; } objc_autoreleasePoolPop(pool); - ret = [OFArray arrayWithObjects: keys - count: count]; + ret = [OFArray arrayWithObjects: keys count: count]; } @finally { - [self freeMemory: keys]; + OFFreeMemory(keys); } return ret; } @@ -377,12 +366,11 @@ OFArray *ret; id *objects; size_t count; count = _mapTable.count; - objects = [self allocMemoryWithSize: sizeof(*objects) - count: count]; + objects = OFAllocMemory(count, sizeof(*objects)); @try { void *pool = objc_autoreleasePoolPush(); OFMapTableEnumerator *enumerator; void **objectPtr; @@ -396,14 +384,13 @@ objects[i++] = (id)*objectPtr; } objc_autoreleasePoolPop(pool); - ret = [OFArray arrayWithObjects: objects - count: count]; + ret = [OFArray arrayWithObjects: objects count: count]; } @finally { - [self freeMemory: objects]; + OFFreeMemory(objects); } return ret; } @@ -419,22 +406,21 @@ return [[[OFMapTableEnumeratorWrapper alloc] initWithEnumerator: [_mapTable objectEnumerator] object: self] autorelease]; } -- (int)countByEnumeratingWithState: (of_fast_enumeration_state_t *)state +- (int)countByEnumeratingWithState: (OFFastEnumerationState *)state objects: (id *)objects count: (int)count { return [_mapTable countByEnumeratingWithState: state objects: objects count: count]; } #ifdef OF_HAVE_BLOCKS -- (void)enumerateKeysAndObjectsUsingBlock: - (of_dictionary_enumeration_block_t)block +- (void)enumerateKeysAndObjectsUsingBlock: (OFDictionaryEnumerationBlock)block { @try { [_mapTable enumerateKeysAndObjectsUsingBlock: ^ (void *key, void *object, bool *stop) { block(key, object, stop); Index: src/OFMapTableSet.h ================================================================== --- src/OFMapTableSet.h +++ src/OFMapTableSet.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFMapTableSet.m ================================================================== --- src/OFMapTableSet.m +++ src/OFMapTableSet.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -51,17 +49,17 @@ equal(void *object1, void *object2) { return [(id)object1 isEqual: (id)object2]; } -static const of_map_table_functions_t keyFunctions = { +static const OFMapTableFunctions keyFunctions = { .retain = retain, .release = release, .hash = hash, .equal = equal }; -static const of_map_table_functions_t objectFunctions = { NULL }; +static const OFMapTableFunctions objectFunctions = { NULL }; @implementation OFMapTableSet - (instancetype)init { return [self initWithCapacity: 0]; @@ -100,12 +98,11 @@ self = [self initWithCapacity: count]; @try { for (id object in set) - [_mapTable setObject: (void *)1 - forKey: object]; + [_mapTable setObject: (void *)1 forKey: object]; } @catch (id e) { [self release]; @throw e; } @@ -128,39 +125,35 @@ self = [self initWithCapacity: count]; @try { for (id object in array) - [_mapTable setObject: (void *)1 - forKey: object]; + [_mapTable setObject: (void *)1 forKey: object]; } @catch (id e) { [self release]; @throw e; } return self; } -- (instancetype)initWithObjects: (id const *)objects - count: (size_t)count +- (instancetype)initWithObjects: (id const *)objects count: (size_t)count { self = [self initWithCapacity: count]; @try { for (size_t i = 0; i < count; i++) - [_mapTable setObject: (void *)1 - forKey: objects[i]]; + [_mapTable setObject: (void *)1 forKey: objects[i]]; } @catch (id e) { [self release]; @throw e; } return self; } -- (instancetype)initWithObject: (id)firstObject - arguments: (va_list)arguments +- (instancetype)initWithObject: (id)firstObject arguments: (va_list)arguments { self = [super init]; @try { id object; @@ -174,16 +167,14 @@ _mapTable = [[OFMapTable alloc] initWithKeyFunctions: keyFunctions objectFunctions: objectFunctions capacity: count]; - [_mapTable setObject: (void *)1 - forKey: firstObject]; + [_mapTable setObject: (void *)1 forKey: firstObject]; while ((object = va_arg(arguments, id)) != nil) - [_mapTable setObject: (void *)1 - forKey: object]; + [_mapTable setObject: (void *)1 forKey: object]; } @catch (id e) { [self release]; @throw e; } @@ -197,15 +188,15 @@ @try { void *pool = objc_autoreleasePoolPush(); if ((![element.name isEqual: @"OFSet"] && ![element.name isEqual: @"OFMutableSet"]) || - ![element.namespace isEqual: OF_SERIALIZATION_NS]) + ![element.namespace isEqual: OFSerializationNS]) @throw [OFInvalidArgumentException exception]; for (OFXMLElement *child in - [element elementsForNamespace: OF_SERIALIZATION_NS]) { + [element elementsForNamespace: OFSerializationNS]) { void *pool2 = objc_autoreleasePoolPush(); [_mapTable setObject: (void *)1 forKey: [child objectByDeserializing]]; @@ -283,21 +274,21 @@ return [[[OFMapTableEnumeratorWrapper alloc] initWithEnumerator: [_mapTable keyEnumerator] object: self] autorelease]; } -- (int)countByEnumeratingWithState: (of_fast_enumeration_state_t *)state +- (int)countByEnumeratingWithState: (OFFastEnumerationState *)state objects: (id *)objects count: (int)count { return [_mapTable countByEnumeratingWithState: state objects: objects count: count]; } #ifdef OF_HAVE_BLOCKS -- (void)enumerateObjectsUsingBlock: (of_set_enumeration_block_t)block +- (void)enumerateObjectsUsingBlock: (OFSetEnumerationBlock)block { @try { [_mapTable enumerateKeysAndObjectsUsingBlock: ^ (void *key, void *object, bool *stop) { block(key, stop); Index: src/OFMessagePackExtension.h ================================================================== --- src/OFMessagePackExtension.h +++ src/OFMessagePackExtension.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -52,12 +50,11 @@ * * @param type The MessagePack extension type * @param data The data for the extension * @return A new, autoreleased OFMessagePackRepresentation */ -+ (instancetype)extensionWithType: (int8_t)type - data: (OFData *)data; ++ (instancetype)extensionWithType: (int8_t)type data: (OFData *)data; - (instancetype)init OF_UNAVAILABLE; /** * @brief Initializes an already allocated OFMessagePackRepresentation with the Index: src/OFMessagePackExtension.m ================================================================== --- src/OFMessagePackExtension.m +++ src/OFMessagePackExtension.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -24,24 +22,21 @@ #import "OFInvalidArgumentException.h" @implementation OFMessagePackExtension @synthesize type = _type, data = _data; -+ (instancetype)extensionWithType: (int8_t)type - data: (OFData *)data ++ (instancetype)extensionWithType: (int8_t)type data: (OFData *)data { - return [[[self alloc] initWithType: type - data: data] autorelease]; + return [[[self alloc] initWithType: type data: data] autorelease]; } - (instancetype)init { OF_INVALID_INIT_METHOD } -- (instancetype)initWithType: (int8_t)type - data: (OFData *)data +- (instancetype)initWithType: (int8_t)type data: (OFData *)data { self = [super init]; @try { if (data == nil || data.itemSize != 1) @@ -123,13 +118,12 @@ ret = [OFMutableData dataWithCapacity: count + 4]; prefix = 0xC8; [ret addItem: &prefix]; - length = OF_BSWAP16_IF_LE((uint16_t)count); - [ret addItems: &length - count: 2]; + length = OFToBigEndian16((uint16_t)count); + [ret addItems: &length count: 2]; [ret addItem: &_type]; } else { uint32_t length; @@ -136,20 +130,17 @@ ret = [OFMutableData dataWithCapacity: count + 6]; prefix = 0xC9; [ret addItem: &prefix]; - length = OF_BSWAP32_IF_LE((uint32_t)count); - [ret addItems: &length - count: 4]; + length = OFToBigEndian32((uint32_t)count); + [ret addItems: &length count: 4]; [ret addItem: &_type]; } - [ret addItems: _data.items - count: _data.count]; - + [ret addItems: _data.items count: _data.count]; [ret makeImmutable]; return ret; } @@ -177,22 +168,22 @@ return true; } - (unsigned long)hash { - uint32_t hash; - - OF_HASH_INIT(hash); - - OF_HASH_ADD(hash, (uint8_t)_type); - OF_HASH_ADD_HASH(hash, _data.hash); - - OF_HASH_FINALIZE(hash); + unsigned long hash; + + OFHashInit(&hash); + + OFHashAdd(&hash, (uint8_t)_type); + OFHashAddHash(&hash, _data.hash); + + OFHashFinalize(&hash); return hash; } - (id)copy { return [self retain]; } @end Index: src/OFMessagePackRepresentation.h ================================================================== --- src/OFMessagePackRepresentation.h +++ src/OFMessagePackRepresentation.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFMethodSignature.h ================================================================== --- src/OFMethodSignature.h +++ src/OFMethodSignature.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -94,19 +92,19 @@ * @brief Returns the size for the specified type encoding. * * @param type The type encoding to return the size for * @return The size for the specified type encoding */ -extern size_t of_sizeof_type_encoding(const char *type); +extern size_t OFSizeOfTypeEncoding(const char *type); /** * @brief Returns the alignment for the specified type encoding. * * @param type The type encoding to return the alignment for * @return The alignment for the specified type encoding */ -extern size_t of_alignof_type_encoding(const char *type); +extern size_t OFAlignmentOfTypeEncoding(const char *type); #ifdef __cplusplus } #endif OF_ASSUME_NONNULL_END Index: src/OFMethodSignature.m ================================================================== --- src/OFMethodSignature.m +++ src/OFMethodSignature.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -27,43 +25,44 @@ #import "OFInvalidFormatException.h" #import "OFOutOfRangeException.h" #import "macros.h" -static size_t alignofEncoding(const char **type, size_t *length, bool inStruct); -static size_t sizeofEncoding(const char **type, size_t *length); +static size_t alignmentOfEncoding(const char **type, size_t *length, + bool inStruct); +static size_t sizeOfEncoding(const char **type, size_t *length); static size_t -alignofArray(const char **type, size_t *length) +alignmentOfArray(const char **type, size_t *length) { - size_t align; + size_t alignment; assert(*length > 0); (*type)++; (*length)--; - while (*length > 0 && of_ascii_isdigit(**type)) { + while (*length > 0 && OFASCIIIsDigit(**type)) { (*type)++; (*length)--; } - align = alignofEncoding(type, length, true); + alignment = alignmentOfEncoding(type, length, true); if (*length == 0 || **type != ']') @throw [OFInvalidFormatException exception]; (*type)++; (*length)--; - return align; + return alignment; } static size_t -alignofStruct(const char **type, size_t *length) +alignmentOfStruct(const char **type, size_t *length) { - size_t align = 0; + size_t alignment = 0; #if defined(OF_POWERPC) && defined(OF_MACOS) bool first = true; #endif assert(*length > 0); @@ -83,36 +82,36 @@ /* Skip '=' */ (*type)++; (*length)--; while (*length > 0 && **type != '}') { - size_t fieldAlign = alignofEncoding(type, length, true); + size_t fieldAlignment = alignmentOfEncoding(type, length, true); #if defined(OF_POWERPC) && defined(OF_MACOS) - if (!first && fieldAlign > 4) - fieldAlign = 4; + if (!first && fieldAlignment > 4) + fieldAlignment = 4; first = false; #endif - if (fieldAlign > align) - align = fieldAlign; + if (fieldAlignment > alignment) + alignment = fieldAlignment; } if (*length == 0 || **type != '}') @throw [OFInvalidFormatException exception]; (*type)++; (*length)--; - return align; + return alignment; } static size_t -alignofUnion(const char **type, size_t *length) +alignmentOfUnion(const char **type, size_t *length) { - size_t align = 0; + size_t alignment = 0; assert(*length > 0); (*type)++; (*length)--; @@ -129,29 +128,29 @@ /* Skip '=' */ (*type)++; (*length)--; while (*length > 0 && **type != ')') { - size_t fieldAlign = alignofEncoding(type, length, true); + size_t fieldAlignment = alignmentOfEncoding(type, length, true); - if (fieldAlign > align) - align = fieldAlign; + if (fieldAlignment > alignment) + alignment = fieldAlignment; } if (*length == 0 || **type != ')') @throw [OFInvalidFormatException exception]; (*type)++; (*length)--; - return align; + return alignment; } static size_t -alignofEncoding(const char **type, size_t *length, bool inStruct) +alignmentOfEncoding(const char **type, size_t *length, bool inStruct) { - size_t align; + size_t alignment; if (*length == 0) @throw [OFInvalidFormatException exception]; if (**type == 'r') { @@ -163,87 +162,87 @@ } switch (**type) { case 'c': case 'C': - align = OF_ALIGNOF(char); + alignment = OF_ALIGNOF(char); break; case 'i': case 'I': - align = OF_ALIGNOF(int); + alignment = OF_ALIGNOF(int); break; case 's': case 'S': - align = OF_ALIGNOF(short); + alignment = OF_ALIGNOF(short); break; case 'l': case 'L': - align = OF_ALIGNOF(long); + alignment = OF_ALIGNOF(long); break; case 'q': case 'Q': #if defined(OF_X86) && !defined(OF_WINDOWS) if (inStruct) - align = 4; + alignment = 4; else #endif - align = OF_ALIGNOF(long long); + alignment = OF_ALIGNOF(long long); break; #ifdef __SIZEOF_INT128__ case 't': case 'T': - align = __extension__ OF_ALIGNOF(__int128); + alignment = __extension__ OF_ALIGNOF(__int128); break; #endif case 'f': - align = OF_ALIGNOF(float); + alignment = OF_ALIGNOF(float); break; case 'd': #if defined(OF_X86) && !defined(OF_WINDOWS) if (inStruct) - align = 4; + alignment = 4; else #endif - align = OF_ALIGNOF(double); + alignment = OF_ALIGNOF(double); break; case 'D': #if defined(OF_X86) && !defined(OF_WINDOWS) if (inStruct) - align = 4; + alignment = 4; else #endif - align = OF_ALIGNOF(long double); + alignment = OF_ALIGNOF(long double); break; case 'B': - align = OF_ALIGNOF(_Bool); + alignment = OF_ALIGNOF(_Bool); break; case 'v': - align = 0; + alignment = 0; break; case '*': - align = OF_ALIGNOF(char *); + alignment = OF_ALIGNOF(char *); break; case '@': - align = OF_ALIGNOF(id); + alignment = OF_ALIGNOF(id); break; case '#': - align = OF_ALIGNOF(Class); + alignment = OF_ALIGNOF(Class); break; case ':': - align = OF_ALIGNOF(SEL); + alignment = OF_ALIGNOF(SEL); break; case '[': - return alignofArray(type, length); + return alignmentOfArray(type, length); case '{': - return alignofStruct(type, length); + return alignmentOfStruct(type, length); case '(': - return alignofUnion(type, length); + return alignmentOfUnion(type, length); case '^': /* Just to skip over the rest */ (*type)++; (*length)--; - alignofEncoding(type, length, false); + alignmentOfEncoding(type, length, false); return OF_ALIGNOF(void *); #ifndef __STDC_NO_COMPLEX__ case 'j': (*type)++; @@ -252,22 +251,22 @@ if (*length == 0) @throw [OFInvalidFormatException exception]; switch (**type) { case 'f': - align = OF_ALIGNOF(float _Complex); + alignment = OF_ALIGNOF(float _Complex); break; case 'd': # if defined(OF_X86) && !defined(OF_WINDOWS) if (inStruct) - align = 4; + alignment = 4; else # endif - align = OF_ALIGNOF(double _Complex); + alignment = OF_ALIGNOF(double _Complex); break; case 'D': - align = OF_ALIGNOF(long double _Complex); + alignment = OF_ALIGNOF(long double _Complex); break; default: @throw [OFInvalidFormatException exception]; } @@ -278,35 +277,35 @@ } (*type)++; (*length)--; - return align; + return alignment; } static size_t -sizeofArray(const char **type, size_t *length) +sizeOfArray(const char **type, size_t *length) { size_t count = 0; size_t size; assert(*length > 0); (*type)++; (*length)--; - while (*length > 0 && of_ascii_isdigit(**type)) { + while (*length > 0 && OFASCIIIsDigit(**type)) { count = count * 10 + **type - '0'; (*type)++; (*length)--; } if (count == 0) @throw [OFInvalidFormatException exception]; - size = sizeofEncoding(type, length); + size = sizeOfEncoding(type, length); if (*length == 0 || **type != ']') @throw [OFInvalidFormatException exception]; (*type)++; @@ -317,16 +316,16 @@ return count * size; } static size_t -sizeofStruct(const char **type, size_t *length) +sizeOfStruct(const char **type, size_t *length) { size_t size = 0; const char *typeCopy = *type; size_t lengthCopy = *length; - size_t alignment = alignofStruct(&typeCopy, &lengthCopy); + size_t alignment = alignmentOfStruct(&typeCopy, &lengthCopy); #if defined(OF_POWERPC) && defined(OF_MACOS) bool first = true; #endif assert(*length > 0); @@ -346,26 +345,28 @@ /* Skip '=' */ (*type)++; (*length)--; while (*length > 0 && **type != '}') { - size_t fieldSize, fieldAlign; + size_t fieldSize, fieldAlignment; typeCopy = *type; lengthCopy = *length; - fieldSize = sizeofEncoding(type, length); - fieldAlign = alignofEncoding(&typeCopy, &lengthCopy, true); + fieldSize = sizeOfEncoding(type, length); + fieldAlignment = alignmentOfEncoding(&typeCopy, &lengthCopy, + true); #if defined(OF_POWERPC) && defined(OF_MACOS) - if (!first && fieldAlign > 4) - fieldAlign = 4; + if (!first && fieldAlignment > 4) + fieldAlignment = 4; first = false; #endif - if (size % fieldAlign != 0) { - size_t padding = fieldAlign - (size % fieldAlign); + if (size % fieldAlignment != 0) { + size_t padding = + fieldAlignment - (size % fieldAlignment); if (SIZE_MAX - size < padding) @throw [OFOutOfRangeException exception]; size += padding; @@ -394,11 +395,11 @@ return size; } static size_t -sizeofUnion(const char **type, size_t *length) +sizeOfUnion(const char **type, size_t *length) { size_t size = 0; assert(*length > 0); @@ -417,11 +418,11 @@ /* Skip '=' */ (*type)++; (*length)--; while (*length > 0 && **type != ')') { - size_t fieldSize = sizeofEncoding(type, length); + size_t fieldSize = sizeOfEncoding(type, length); if (fieldSize > size) size = fieldSize; } @@ -433,11 +434,11 @@ return size; } static size_t -sizeofEncoding(const char **type, size_t *length) +sizeOfEncoding(const char **type, size_t *length) { size_t size; if (*length == 0) @throw [OFInvalidFormatException exception]; @@ -503,20 +504,20 @@ break; case ':': size = sizeof(SEL); break; case '[': - return sizeofArray(type, length); + return sizeOfArray(type, length); case '{': - return sizeofStruct(type, length); + return sizeOfStruct(type, length); case '(': - return sizeofUnion(type, length); + return sizeOfUnion(type, length); case '^': /* Just to skip over the rest */ (*type)++; (*length)--; - sizeofEncoding(type, length); + sizeOfEncoding(type, length); return sizeof(void *); #ifndef __STDC_NO_COMPLEX__ case 'j': (*type)++; @@ -550,26 +551,26 @@ return size; } size_t -of_sizeof_type_encoding(const char *type) +OFSizeOfTypeEncoding(const char *type) { size_t length = strlen(type); - size_t ret = sizeofEncoding(&type, &length); + size_t ret = sizeOfEncoding(&type, &length); if (length > 0) @throw [OFInvalidFormatException exception]; return ret; } size_t -of_alignof_type_encoding(const char *type) +OFAlignmentOfTypeEncoding(const char *type) { size_t length = strlen(type); - size_t ret = alignofEncoding(&type, &length, false); + size_t ret = alignmentOfEncoding(&type, &length, false); if (length > 0) @throw [OFInvalidFormatException exception]; return ret; @@ -595,21 +596,21 @@ length = strlen(types); if (length == 0) @throw [OFInvalidFormatException exception]; - _types = [self allocMemoryWithSize: length + 1]; + _types = OFAllocMemory(length + 1, 1); memcpy(_types, types, length); _typesPointers = [[OFMutableData alloc] initWithItemSize: sizeof(char *)]; _offsets = [[OFMutableData alloc] initWithItemSize: sizeof(size_t)]; last = _types; for (size_t i = 0; i < length; i++) { - if (of_ascii_isdigit(_types[i])) { + if (OFASCIIIsDigit(_types[i])) { size_t offset = _types[i] - '0'; if (last == _types + i) @throw [OFInvalidFormatException exception]; @@ -617,11 +618,11 @@ _types[i] = '\0'; [_typesPointers addItem: &last]; i++; for (; i < length && - of_ascii_isdigit(_types[i]); i++) + OFASCIIIsDigit(_types[i]); i++) offset = offset * 10 + _types[i] - '0'; [_offsets addItem: &offset]; last = _types + i; @@ -669,10 +670,11 @@ return self; } - (void)dealloc { + OFFreeMemory(_types); [_typesPointers release]; [_offsets release]; [super dealloc]; } Index: src/OFMutableAdjacentArray.h ================================================================== --- src/OFMutableAdjacentArray.h +++ src/OFMutableAdjacentArray.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFMutableAdjacentArray.m ================================================================== --- src/OFMutableAdjacentArray.m +++ src/OFMutableAdjacentArray.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -59,37 +57,32 @@ [object retain]; _mutations++; } -- (void)insertObject: (id)object - atIndex: (size_t)idx +- (void)insertObject: (id)object atIndex: (size_t)idx { if (object == nil) @throw [OFInvalidArgumentException exception]; @try { - [_array insertItem: &object - atIndex: idx]; + [_array insertItem: &object atIndex: idx]; } @catch (OFOutOfRangeException *e) { @throw [OFOutOfRangeException exception]; } [object retain]; _mutations++; } -- (void)insertObjectsFromArray: (OFArray *)array - atIndex: (size_t)idx +- (void)insertObjectsFromArray: (OFArray *)array atIndex: (size_t)idx { id const *objects = array.objects; size_t count = array.count; @try { - [_array insertItems: objects - atIndex: idx - count: count]; + [_array insertItems: objects atIndex: idx count: count]; } @catch (OFOutOfRangeException *e) { @throw [OFOutOfRangeException exception]; } for (size_t i = 0; i < count; i++) @@ -96,12 +89,11 @@ [objects[i] retain]; _mutations++; } -- (void)replaceObject: (id)oldObject - withObject: (id)newObject +- (void)replaceObject: (id)oldObject withObject: (id)newObject { id *objects; size_t count; if (oldObject == nil || newObject == nil) @@ -113,18 +105,15 @@ for (size_t i = 0; i < count; i++) { if ([objects[i] isEqual: oldObject]) { [newObject retain]; [objects[i] release]; objects[i] = newObject; - - return; } } } -- (void)replaceObjectAtIndex: (size_t)idx - withObject: (id)object +- (void)replaceObjectAtIndex: (size_t)idx withObject: (id)object { id *objects; id oldObject; if (object == nil) @@ -138,12 +127,11 @@ oldObject = objects[idx]; objects[idx] = [object retain]; [oldObject release]; } -- (void)replaceObjectIdenticalTo: (id)oldObject - withObject: (id)newObject +- (void)replaceObjectIdenticalTo: (id)oldObject withObject: (id)newObject { id *objects; size_t count; if (oldObject == nil || newObject == nil) @@ -174,18 +162,21 @@ objects = _array.items; count = _array.count; for (size_t i = 0; i < count; i++) { if ([objects[i] isEqual: object]) { - object = objects[i]; + id tmp = objects[i]; [_array removeItemAtIndex: i]; _mutations++; - [object release]; + [tmp release]; - return; + objects = _array.items; + i--; + count--; + continue; } } } - (void)removeObjectIdenticalTo: (id)object @@ -204,11 +195,14 @@ [_array removeItemAtIndex: i]; _mutations++; [object release]; - return; + objects = _array.items; + i--; + count--; + continue; } } } - (void)removeObjectAtIndex: (size_t)idx @@ -231,32 +225,31 @@ [objects[i] release]; [_array removeAllItems]; } -- (void)removeObjectsInRange: (of_range_t)range +- (void)removeObjectsInRange: (OFRange)range { id const *objects = _array.items; size_t count = _array.count; id *copy; if (range.length > SIZE_MAX - range.location || range.location >= count || range.length > count - range.location) @throw [OFOutOfRangeException exception]; - copy = [self allocMemoryWithSize: sizeof(*copy) - count: range.length]; + copy = OFAllocMemory(range.length, sizeof(*copy)); memcpy(copy, objects + range.location, range.length * sizeof(id)); @try { [_array removeItemsInRange: range]; _mutations++; for (size_t i = 0; i < range.length; i++) [copy[i] release]; } @finally { - [self freeMemory: copy]; + OFFreeMemory(copy); } } - (void)removeLastObject { @@ -273,12 +266,11 @@ _mutations++; #endif } -- (void)exchangeObjectAtIndex: (size_t)idx1 - withObjectAtIndex: (size_t)idx2 +- (void)exchangeObjectAtIndex: (size_t)idx1 withObjectAtIndex: (size_t)idx2 { id *objects = _array.mutableItems; size_t count = _array.count; id tmp; @@ -303,11 +295,11 @@ objects[i] = objects[j]; objects[j] = tmp; } } -- (int)countByEnumeratingWithState: (of_fast_enumeration_state_t *)state +- (int)countByEnumeratingWithState: (OFFastEnumerationState *)state objects: (id *)objects count: (int)count_ { size_t count = _array.count; @@ -340,11 +332,11 @@ initWithArray: self mutationsPtr: &_mutations] autorelease]; } #ifdef OF_HAVE_BLOCKS -- (void)enumerateObjectsUsingBlock: (of_array_enumeration_block_t)block +- (void)enumerateObjectsUsingBlock: (OFArrayEnumerationBlock)block { id const *objects = _array.items; size_t count = _array.count; bool stop = false; unsigned long mutations = _mutations; @@ -356,11 +348,11 @@ block(objects[i], i, &stop); } } -- (void)replaceObjectsUsingBlock: (of_array_replace_block_t)block +- (void)replaceObjectsUsingBlock: (OFArrayReplaceBlock)block { id *objects = _array.mutableItems; size_t count = _array.count; unsigned long mutations = _mutations; Index: src/OFMutableArray.h ================================================================== --- src/OFMutableArray.h +++ src/OFMutableArray.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -27,11 +25,11 @@ * * @param object The object to replace * @param index The index of the object to replace * @return The object to replace the object with */ -typedef id _Nonnull (^of_array_replace_block_t)(id object, size_t index); +typedef id _Nonnull (^OFArrayReplaceBlock)(id object, size_t index); #endif /** * @class OFMutableArray OFArray.h ObjFW/OFArray.h * @@ -82,12 +80,11 @@ * @brief Inserts an object to the OFArray at the specified index. * * @param object An object to add * @param index The index where the object should be inserted */ -- (void)insertObject: (ObjectType)object - atIndex: (size_t)index; +- (void)insertObject: (ObjectType)object atIndex: (size_t)index; /** * @brief Inserts the objects from the specified OFArray at the specified index. * * @param array An array of objects @@ -95,27 +92,25 @@ */ - (void)insertObjectsFromArray: (OFArray OF_GENERIC(ObjectType) *)array atIndex: (size_t)index; /** - * @brief Replaces the first object equivalent to the specified object with the + * @brief Replaces all objects equivalent to the specified object with the * other specified object. * * @param oldObject The object to replace * @param newObject The replacement object */ -- (void)replaceObject: (ObjectType)oldObject - withObject: (ObjectType)newObject; +- (void)replaceObject: (ObjectType)oldObject withObject: (ObjectType)newObject; /** * @brief Replaces the object at the specified index with the specified object. * * @param index The index of the object to replace * @param object The replacement object */ -- (void)replaceObjectAtIndex: (size_t)index - withObject: (ObjectType)object; +- (void)replaceObjectAtIndex: (size_t)index withObject: (ObjectType)object; /** * @brief Replaces the object at the specified index with the specified object. * * This method is the same as @ref replaceObjectAtIndex:withObject:. @@ -123,12 +118,11 @@ * This method is also used by the subscripting syntax. * * @param index The index of the object to replace * @param object The replacement object */ -- (void)setObject: (ObjectType)object - atIndexedSubscript: (size_t)index; +- (void)setObject: (ObjectType)object atIndexedSubscript: (size_t)index; /** * @brief Replaces the first object that has the same address as the specified * object with the other specified object. * @@ -137,18 +131,18 @@ */ - (void)replaceObjectIdenticalTo: (ObjectType)oldObject withObject: (ObjectType)newObject; /** - * @brief Removes the first object equivalent to the specified object. + * @brief Removes all objects equivalent to the specified object. * * @param object The object to remove */ - (void)removeObject: (ObjectType)object; /** - * @brief Removes the first object that has the same address as the specified + * @brief Removes all objects that have the same address as the specified * object. * * @param object The object to remove */ - (void)removeObjectIdenticalTo: (ObjectType)object; @@ -159,15 +153,15 @@ * @param index The index of the object to remove */ - (void)removeObjectAtIndex: (size_t)index; /** - * @brief Removes the object in the specified range. + * @brief Removes the objects in the specified range. * * @param range The range of the objects to remove */ -- (void)removeObjectsInRange: (of_range_t)range; +- (void)removeObjectsInRange: (OFRange)range; /** * @brief Removes the last object. */ - (void)removeLastObject; @@ -181,21 +175,20 @@ /** * @brief Replaces each object with the object returned by the block. * * @param block The block which returns a new object for each object */ -- (void)replaceObjectsUsingBlock: (of_array_replace_block_t)block; +- (void)replaceObjectsUsingBlock: (OFArrayReplaceBlock)block; #endif /** * @brief Exchange the objects at the specified indices. * * @param index1 The index of the first object to exchange * @param index2 The index of the second object to exchange */ -- (void)exchangeObjectAtIndex: (size_t)index1 - withObjectAtIndex: (size_t)index2; +- (void)exchangeObjectAtIndex: (size_t)index1 withObjectAtIndex: (size_t)index2; /** * @brief Sorts the array in ascending order. */ - (void)sort; @@ -203,32 +196,23 @@ /** * @brief Sorts the array using the specified selector and options. * * @param selector The selector to use to sort the array. It's signature * should be the same as that of -[compare:]. - * @param options The options to use when sorting the array.@n - * Possible values are: - * Value | Description - * ---------------------------|------------------------- - * `OF_ARRAY_SORT_DESCENDING` | Sort in descending order + * @param options The options to use when sorting the array */ -- (void)sortUsingSelector: (SEL)selector - options: (int)options; +- (void)sortUsingSelector: (SEL)selector 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 - * @param options The options to use when sorting the array.@n - * Possible values are: - * Value | Description - * ---------------------------|------------------------- - * `OF_ARRAY_SORT_DESCENDING` | Sort in descending order + * @param options The options to use when sorting the array */ -- (void)sortUsingComparator: (of_comparator_t)comparator - options: (int)options; +- (void)sortUsingComparator: (OFComparator)comparator + options: (OFArraySortOptions)options; #endif /** * @brief Reverts the order of the objects in the array. */ Index: src/OFMutableArray.m ================================================================== --- src/OFMutableArray.m +++ src/OFMutableArray.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -34,32 +32,32 @@ } placeholder; @interface OFMutableArrayPlaceholder: OFMutableArray @end -static of_comparison_result_t +static OFComparisonResult compare(id left, id right, SEL selector) { - of_comparison_result_t (*comparator)(id, SEL, id) = - (of_comparison_result_t (*)(id, SEL, id)) + 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, - int options) + OFArraySortOptions options) { - of_comparison_result_t ascending, descending; + OFComparisonResult ascending, descending; - if (options & OF_ARRAY_SORT_DESCENDING) { - ascending = OF_ORDERED_DESCENDING; - descending = OF_ORDERED_ASCENDING; + if (options & OFArraySortDescending) { + ascending = OFOrderedDescending; + descending = OFOrderedAscending; } else { - ascending = OF_ORDERED_ASCENDING; - descending = OF_ORDERED_DESCENDING; + ascending = OFOrderedAscending; + descending = OFOrderedDescending; } while (left < right) { size_t i = left; size_t j = right - 1; @@ -92,20 +90,20 @@ } #ifdef OF_HAVE_BLOCKS static void quicksortWithBlock(OFMutableArray *array, size_t left, size_t right, - of_comparator_t comparator, int options) + OFComparator comparator, OFArraySortOptions options) { - of_comparison_result_t ascending, descending; + OFComparisonResult ascending, descending; - if (options & OF_ARRAY_SORT_DESCENDING) { - ascending = OF_ORDERED_DESCENDING; - descending = OF_ORDERED_ASCENDING; + if (options & OFArraySortDescending) { + ascending = OFOrderedDescending; + descending = OFOrderedAscending; } else { - ascending = OF_ORDERED_ASCENDING; - descending = OF_ORDERED_DESCENDING; + ascending = OFOrderedAscending; + descending = OFOrderedDescending; } while (left < right) { size_t i = left; size_t j = right - 1; @@ -165,12 +163,11 @@ va_end(arguments); return ret; } -- (instancetype)initWithObject: (id)firstObject - arguments: (va_list)arguments +- (instancetype)initWithObject: (id)firstObject arguments: (va_list)arguments { return (id)[[OFMutableAdjacentArray alloc] initWithObject: firstObject arguments: arguments]; } @@ -177,12 +174,11 @@ - (instancetype)initWithArray: (OFArray *)array { return (id)[[OFMutableAdjacentArray alloc] initWithArray: array]; } -- (instancetype)initWithObjects: (id const *)objects - count: (size_t)count +- (instancetype)initWithObjects: (id const *)objects count: (size_t)count { return (id)[[OFMutableAdjacentArray alloc] initWithObjects: objects count: count]; } @@ -257,70 +253,56 @@ return [[OFArray alloc] initWithArray: self]; } - (void)addObject: (id)object { - [self insertObject: object - atIndex: self.count]; + [self insertObject: object atIndex: self.count]; } - (void)addObjectsFromArray: (OFArray *)array { - [self insertObjectsFromArray: array - atIndex: self.count]; + [self insertObjectsFromArray: array atIndex: self.count]; } -- (void)insertObject: (id)object - atIndex: (size_t)idx +- (void)insertObject: (id)object atIndex: (size_t)idx { OF_UNRECOGNIZED_SELECTOR } -- (void)insertObjectsFromArray: (OFArray *)array - atIndex: (size_t)idx +- (void)insertObjectsFromArray: (OFArray *)array atIndex: (size_t)idx { size_t i = 0; for (id object in array) - [self insertObject: object - atIndex: idx + i++]; + [self insertObject: object atIndex: idx + i++]; } -- (void)replaceObjectAtIndex: (size_t)idx - withObject: (id)object +- (void)replaceObjectAtIndex: (size_t)idx withObject: (id)object { OF_UNRECOGNIZED_SELECTOR } -- (void)setObject: (id)object - atIndexedSubscript: (size_t)idx +- (void)setObject: (id)object atIndexedSubscript: (size_t)idx { - [self replaceObjectAtIndex: idx - withObject: object]; + [self replaceObjectAtIndex: idx withObject: object]; } -- (void)replaceObject: (id)oldObject - withObject: (id)newObject +- (void)replaceObject: (id)oldObject withObject: (id)newObject { size_t count; if (oldObject == nil || newObject == nil) @throw [OFInvalidArgumentException exception]; count = self.count; - for (size_t i = 0; i < count; i++) { - if ([[self objectAtIndex: i] isEqual: oldObject]) { - [self replaceObjectAtIndex: i - withObject: newObject]; - return; - } - } + for (size_t i = 0; i < count; i++) + if ([[self objectAtIndex: i] isEqual: oldObject]) + [self replaceObjectAtIndex: i withObject: newObject]; } -- (void)replaceObjectIdenticalTo: (id)oldObject - withObject: (id)newObject +- (void)replaceObjectIdenticalTo: (id)oldObject withObject: (id)newObject { size_t count; if (oldObject == nil || newObject == nil) @throw [OFInvalidArgumentException exception]; @@ -327,12 +309,11 @@ count = self.count; for (size_t i = 0; i < count; i++) { if ([self objectAtIndex: i] == oldObject) { - [self replaceObjectAtIndex: i - withObject: newObject]; + [self replaceObjectAtIndex: i withObject: newObject]; return; } } } @@ -353,11 +334,13 @@ for (size_t i = 0; i < count; i++) { if ([[self objectAtIndex: i] isEqual: object]) { [self removeObjectAtIndex: i]; - return; + i--; + count--; + continue; } } } - (void)removeObjectIdenticalTo: (id)object @@ -371,16 +354,18 @@ for (size_t i = 0; i < count; i++) { if ([self objectAtIndex: i] == object) { [self removeObjectAtIndex: i]; - return; + i--; + count--; + continue; } } } -- (void)removeObjectsInRange: (of_range_t)range +- (void)removeObjectsInRange: (OFRange)range { for (size_t i = 0; i < range.length; i++) [self removeObjectAtIndex: range.location]; } @@ -394,52 +379,47 @@ [self removeObjectAtIndex: count - 1]; } - (void)removeAllObjects { - [self removeObjectsInRange: of_range(0, self.count)]; + [self removeObjectsInRange: OFRangeMake(0, self.count)]; } #ifdef OF_HAVE_BLOCKS -- (void)replaceObjectsUsingBlock: (of_array_replace_block_t)block +- (void)replaceObjectsUsingBlock: (OFArrayReplaceBlock)block { [self enumerateObjectsUsingBlock: ^ (id object, size_t idx, bool *stop) { id new = block(object, idx); if (new != object) - [self replaceObjectAtIndex: idx - withObject: new]; + [self replaceObjectAtIndex: idx withObject: new]; }]; } #endif -- (void)exchangeObjectAtIndex: (size_t)idx1 - withObjectAtIndex: (size_t)idx2 +- (void)exchangeObjectAtIndex: (size_t)idx1 withObjectAtIndex: (size_t)idx2 { id object1 = [self objectAtIndex: idx1]; id object2 = [self objectAtIndex: idx2]; [object1 retain]; @try { - [self replaceObjectAtIndex: idx1 - withObject: object2]; - [self replaceObjectAtIndex: idx2 - withObject: object1]; + [self replaceObjectAtIndex: idx1 withObject: object2]; + [self replaceObjectAtIndex: idx2 withObject: object1]; } @finally { [object1 release]; } } - (void)sort { - [self sortUsingSelector: @selector(compare:) - options: 0]; + [self sortUsingSelector: @selector(compare:) options: 0]; } - (void)sortUsingSelector: (SEL)selector - options: (int)options + options: (OFArraySortOptions)options { size_t count = self.count; if (count == 0 || count == 1) return; @@ -446,12 +426,12 @@ quicksort(self, 0, count - 1, selector, options); } #ifdef OF_HAVE_BLOCKS -- (void)sortUsingComparator: (of_comparator_t)comparator - options: (int)options +- (void)sortUsingComparator: (OFComparator)comparator + options: (OFArraySortOptions)options { size_t count = self.count; if (count == 0 || count == 1) return; @@ -466,13 +446,12 @@ if (count == 0 || count == 1) return; for (i = 0, j = count - 1; i < j; i++, j--) - [self exchangeObjectAtIndex: i - withObjectAtIndex: j]; + [self exchangeObjectAtIndex: i withObjectAtIndex: j]; } - (void)makeImmutable { } @end Index: src/OFMutableData.h ================================================================== --- src/OFMutableData.h +++ src/OFMutableData.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -39,11 +37,12 @@ * @warning The pointer is only valid until the OFMutableData is changed! * * Modifying the returned array directly is allowed and will change the contents * of the data. */ -@property (readonly, nonatomic) void *mutableItems OF_RETURNS_INNER_POINTER; +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) void *mutableItems + OF_RETURNS_INNER_POINTER; /** * @brief The first item of the OFMutableData or `NULL`. */ @property OF_NULLABLE_PROPERTY (readonly, nonatomic) void *mutableFirstItem @@ -86,12 +85,11 @@ * * @param itemSize The size of a single element in the OFMutableData * @param capacity The initial capacity for the OFMutableData * @return A new autoreleased OFMutableData */ -+ (instancetype)dataWithItemSize: (size_t)itemSize - capacity: (size_t)capacity; ++ (instancetype)dataWithItemSize: (size_t)itemSize capacity: (size_t)capacity; /** * @brief Initializes an already allocated OFMutableData with an item size of 1. * * @return An initialized OFMutableData @@ -124,12 +122,11 @@ * * @param itemSize The size of a single element in the OFMutableData * @param capacity The initial capacity for the OFMutableData * @return An initialized OFMutableData */ -- (instancetype)initWithItemSize: (size_t)itemSize - capacity: (size_t)capacity; +- (instancetype)initWithItemSize: (size_t)itemSize capacity: (size_t)capacity; /** * @brief Returns a specific item of the OFMutableData. * * Modifying the returned item directly is allowed and will change the contents @@ -151,21 +148,19 @@ * @brief Adds an item to the OFMutableData at the specified index. * * @param item A pointer to an arbitrary item * @param index The index where the item should be added */ -- (void)insertItem: (const void *)item - atIndex: (size_t)index; +- (void)insertItem: (const void *)item atIndex: (size_t)index; /** * @brief Adds items from a C array to the OFMutableData. * * @param items A C array containing the items to add * @param count The number of items to add */ -- (void)addItems: (const void *)items - count: (size_t)count; +- (void)addItems: (const void *)items count: (size_t)count; /** * @brief Adds items from a C array to the OFMutableData at the specified index. * * @param items A C array containing the items to add @@ -194,11 +189,11 @@ /** * @brief Removes the specified amount of items at the specified index. * * @param range The range of items to remove */ -- (void)removeItemsInRange: (of_range_t)range; +- (void)removeItemsInRange: (OFRange)range; /** * @brief Removes the last item. */ - (void)removeLastItem; Index: src/OFMutableData.m ================================================================== --- src/OFMutableData.m +++ src/OFMutableData.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -42,12 +40,11 @@ + (instancetype)dataWithCapacity: (size_t)capacity { return [[[self alloc] initWithCapacity: capacity] autorelease]; } -+ (instancetype)dataWithItemSize: (size_t)itemSize - capacity: (size_t)capacity ++ (instancetype)dataWithItemSize: (size_t)itemSize capacity: (size_t)capacity { return [[[self alloc] initWithItemSize: itemSize capacity: capacity] autorelease]; } @@ -54,10 +51,11 @@ - (instancetype)init { self = [super init]; _itemSize = 1; + _freeWhenDone = true; return self; } - (instancetype)initWithItemSize: (size_t)itemSize @@ -67,10 +65,11 @@ @try { if (itemSize == 0) @throw [OFInvalidArgumentException exception]; _itemSize = itemSize; + _freeWhenDone = true; } @catch (id e) { [self release]; @throw e; } @@ -81,56 +80,50 @@ { return [self initWithItemSize: 1 capacity: capacity]; } -- (instancetype)initWithItemSize: (size_t)itemSize - capacity: (size_t)capacity +- (instancetype)initWithItemSize: (size_t)itemSize capacity: (size_t)capacity { self = [super init]; @try { if (itemSize == 0) @throw [OFInvalidArgumentException exception]; - _items = [self allocMemoryWithSize: itemSize - count: capacity]; - + _items = OFAllocMemory(capacity, itemSize); _itemSize = itemSize; _capacity = capacity; + _freeWhenDone = true; } @catch (id e) { [self release]; @throw e; } return self; } - (instancetype)initWithItems: (const void *)items - itemSize: (size_t)itemSize count: (size_t)count + itemSize: (size_t)itemSize { - self = [super initWithItems: items - itemSize: itemSize - count: count]; + self = [super initWithItems: items count: count itemSize: itemSize]; _capacity = _count; return self; } - (instancetype)initWithItemsNoCopy: (void *)items - itemSize: (size_t)itemSize count: (size_t)count + itemSize: (size_t)itemSize freeWhenDone: (bool)freeWhenDone { - self = [self initWithItems: items - itemSize: itemSize - count: count]; + self = [self initWithItems: items count: count itemSize: itemSize]; if (freeWhenDone) - free(items); + OFFreeMemory(items); return self; } - (instancetype)initWithStringRepresentation: (OFString *)string @@ -169,56 +162,48 @@ return NULL; return _items + (_count - 1) * _itemSize; } -- (OFData *)subdataWithRange: (of_range_t)range +- (OFData *)subdataWithRange: (OFRange)range { if (range.length > SIZE_MAX - range.location || range.location + range.length > _count) @throw [OFOutOfRangeException exception]; return [OFData dataWithItems: _items + (range.location * _itemSize) - itemSize: _itemSize - count: range.length]; + count: range.length + itemSize: _itemSize]; } - (void)addItem: (const void *)item { if (SIZE_MAX - _count < 1) @throw [OFOutOfRangeException exception]; if (_count + 1 > _capacity) { - _items = [self resizeMemory: _items - size: _itemSize - count: _count + 1]; + _items = OFResizeMemory(_items, _count + 1, _itemSize); _capacity = _count + 1; } memcpy(_items + _count * _itemSize, item, _itemSize); _count++; } -- (void)insertItem: (const void *)item - atIndex: (size_t)idx +- (void)insertItem: (const void *)item atIndex: (size_t)idx { - [self insertItems: item - atIndex: idx - count: 1]; + [self insertItems: item atIndex: idx count: 1]; } -- (void)addItems: (const void *)items - count: (size_t)count +- (void)addItems: (const void *)items count: (size_t)count { if (count > SIZE_MAX - _count) @throw [OFOutOfRangeException exception]; if (_count + count > _capacity) { - _items = [self resizeMemory: _items - size: _itemSize - count: _count + count]; + _items = OFResizeMemory(_items, _count + count, _itemSize); _capacity = _count + count; } memcpy(_items + _count * _itemSize, items, count * _itemSize); _count += count; @@ -230,13 +215,11 @@ { if (count > SIZE_MAX - _count || idx > _count) @throw [OFOutOfRangeException exception]; if (_count + count > _capacity) { - _items = [self resizeMemory: _items - size: _itemSize - count: _count + count]; + _items = OFResizeMemory(_items, _count + count, _itemSize); _capacity = _count + count; } memmove(_items + (idx + count) * _itemSize, _items + idx * _itemSize, (_count - idx) * _itemSize); @@ -249,26 +232,24 @@ { if (count > SIZE_MAX - _count) @throw [OFOutOfRangeException exception]; if (_count + count > _capacity) { - _items = [self resizeMemory: _items - size: _itemSize - count: _count + count]; + _items = OFResizeMemory(_items, _count + count, _itemSize); _capacity = _count + count; } memset(_items + _count * _itemSize, '\0', count * _itemSize); _count += count; } - (void)removeItemAtIndex: (size_t)idx { - [self removeItemsInRange: of_range(idx, 1)]; + [self removeItemsInRange: OFRangeMake(idx, 1)]; } -- (void)removeItemsInRange: (of_range_t)range +- (void)removeItemsInRange: (OFRange)range { if (range.length > SIZE_MAX - range.location || range.location + range.length > _count) @throw [OFOutOfRangeException exception]; @@ -276,13 +257,11 @@ _items + (range.location + range.length) * _itemSize, (_count - range.location - range.length) * _itemSize); _count -= range.length; @try { - _items = [self resizeMemory: _items - size: _itemSize - count: _count]; + _items = OFResizeMemory(_items, _count, _itemSize); _capacity = _count; } @catch (OFOutOfMemoryException *e) { /* We don't really care, as we only made it smaller */ } } @@ -292,35 +271,41 @@ if (_count == 0) return; _count--; @try { - _items = [self resizeMemory: _items - size: _itemSize - count: _count]; + _items = OFResizeMemory(_items, _count, _itemSize); _capacity = _count; } @catch (OFOutOfMemoryException *e) { /* We don't care, as we only made it smaller */ } } - (void)removeAllItems { - [self freeMemory: _items]; - + OFFreeMemory(_items); _items = NULL; _count = 0; _capacity = 0; } - (id)copy { return [[OFData alloc] initWithItems: _items - itemSize: _itemSize - count: _count]; + count: _count + itemSize: _itemSize]; } - (void)makeImmutable { + if (_capacity != _count) { + @try { + _items = OFResizeMemory(_items, _count, _itemSize); + _capacity = _count; + } @catch (OFOutOfMemoryException *e) { + /* We don't care, as we only made it smaller */ + } + } + object_setClass(self, [OFData class]); } @end Index: src/OFMutableDictionary.h ================================================================== --- src/OFMutableDictionary.h +++ src/OFMutableDictionary.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -27,11 +25,11 @@ * * @param key The key of the object to replace * @param object The object to replace * @return The object to replace the object with */ -typedef id _Nonnull (^of_dictionary_replace_block_t)(id key, id object); +typedef id _Nonnull (^OFDictionaryReplaceBlock)(id key, id object); #endif /** * @class OFMutableDictionary OFDictionary.h ObjFW/OFDictionary.h * @@ -71,12 +69,11 @@ * A key can be any object that conforms to the OFCopying protocol. * * @param key The key to set * @param object The object to set the key to */ -- (void)setObject: (ObjectType)object - forKey: (KeyType)key; +- (void)setObject: (ObjectType)object forKey: (KeyType)key; /** * @brief Sets an object for a key. * * A key can be any object that conforms to the OFCopying protocol. @@ -85,12 +82,11 @@ * * @param key The key to set * @param object The object to set the key to. If it is nil, this is equal to * calling @ref removeObjectForKey:. */ -- (void)setObject: (nullable ObjectType)object - forKeyedSubscript: (KeyType)key; +- (void)setObject: (nullable ObjectType)object forKeyedSubscript: (KeyType)key; /** * @brief Removes the object for the specified key from the dictionary. * * @param key The key whose object should be removed @@ -114,11 +110,11 @@ /** * @brief Replaces each object with the object returned by the block. * * @param block The block which returns a new object for each object */ -- (void)replaceObjectsUsingBlock: (of_dictionary_replace_block_t)block; +- (void)replaceObjectsUsingBlock: (OFDictionaryReplaceBlock)block; #endif /** * @brief Converts the mutable dictionary to an immutable dictionary. */ Index: src/OFMutableDictionary.m ================================================================== --- src/OFMutableDictionary.m +++ src/OFMutableDictionary.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -40,19 +38,17 @@ { return (id)[[OFMutableMapTableDictionary alloc] initWithDictionary: dictionary]; } -- (instancetype)initWithObject: (id)object - forKey: (id)key +- (instancetype)initWithObject: (id)object forKey: (id)key { return (id)[[OFMutableMapTableDictionary alloc] initWithObject: object forKey: key]; } -- (instancetype)initWithObjects: (OFArray *)objects - forKeys: (OFArray *)keys +- (instancetype)initWithObjects: (OFArray *)objects forKeys: (OFArray *)keys { return (id)[[OFMutableMapTableDictionary alloc] initWithObjects: objects forKeys: keys]; } @@ -76,12 +72,11 @@ va_end(arguments); return ret; } -- (instancetype)initWithKey: (id)firstKey - arguments: (va_list)arguments +- (instancetype)initWithKey: (id)firstKey arguments: (va_list)arguments { return (id)[[OFMutableMapTableDictionary alloc] initWithKey: firstKey arguments: arguments]; } @@ -156,22 +151,19 @@ - (instancetype)initWithCapacity: (size_t)capacity { OF_INVALID_INIT_METHOD } -- (void)setObject: (id)object - forKey: (id)key +- (void)setObject: (id)object forKey: (id)key { OF_UNRECOGNIZED_SELECTOR } -- (void)setObject: (id)object - forKeyedSubscript: (id)key +- (void)setObject: (id)object forKeyedSubscript: (id)key { if (object != nil) - [self setObject: object - forKey: key]; + [self setObject: object forKey: key]; else [self removeObjectForKey: key]; } - (void)removeObjectForKey: (id)key @@ -201,30 +193,28 @@ OFEnumerator *objectEnumerator = [dictionary objectEnumerator]; id key, object; while ((key = [keyEnumerator nextObject]) != nil && (object = [objectEnumerator nextObject]) != nil) - [self setObject: object - forKey: key]; + [self setObject: object forKey: key]; objc_autoreleasePoolPop(pool); } #ifdef OF_HAVE_BLOCKS -- (void)replaceObjectsUsingBlock: (of_dictionary_replace_block_t)block +- (void)replaceObjectsUsingBlock: (OFDictionaryReplaceBlock)block { [self enumerateKeysAndObjectsUsingBlock: ^ (id key, id object, bool *stop) { id new = block(key, object); if (new != object) { - [self setObject: block(key, object) - forKey: key]; + [self setObject: block(key, object) forKey: key]; } }]; } #endif - (void)makeImmutable { } @end Index: src/OFMutableLHAArchiveEntry.h ================================================================== --- src/OFMutableLHAArchiveEntry.h +++ src/OFMutableLHAArchiveEntry.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFMutableLHAArchiveEntry.m ================================================================== --- src/OFMutableLHAArchiveEntry.m +++ src/OFMutableLHAArchiveEntry.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFMutableMapTableDictionary.h ================================================================== --- src/OFMutableMapTableDictionary.h +++ src/OFMutableMapTableDictionary.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFMutableMapTableDictionary.m ================================================================== --- src/OFMutableMapTableDictionary.m +++ src/OFMutableMapTableDictionary.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -31,15 +29,13 @@ { if (self == [OFMutableMapTableDictionary class]) [self inheritMethodsFromClass: [OFMapTableDictionary class]]; } -- (void)setObject: (id)object - forKey: (id)key +- (void)setObject: (id)object forKey: (id)key { - [_mapTable setObject: object - forKey: key]; + [_mapTable setObject: object forKey: key]; } - (void)removeObjectForKey: (id)key { [_mapTable removeObjectForKey: key]; @@ -49,11 +45,11 @@ { [_mapTable removeAllObjects]; } #ifdef OF_HAVE_BLOCKS -- (void)replaceObjectsUsingBlock: (of_dictionary_replace_block_t)block +- (void)replaceObjectsUsingBlock: (OFDictionaryReplaceBlock)block { @try { [_mapTable replaceObjectsUsingBlock: ^ void *(void *key, void *object) { return block(key, object); Index: src/OFMutableMapTableSet.h ================================================================== --- src/OFMutableMapTableSet.h +++ src/OFMutableMapTableSet.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFMutableMapTableSet.m ================================================================== --- src/OFMutableMapTableSet.m +++ src/OFMutableMapTableSet.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -28,12 +26,11 @@ [self inheritMethodsFromClass: [OFMapTableSet class]]; } - (void)addObject: (id)object { - [_mapTable setObject: (void *)1 - forKey: object]; + [_mapTable setObject: (void *)1 forKey: object]; } - (void)removeObject: (id)object { [_mapTable removeObjectForKey: object]; Index: src/OFMutablePair.h ================================================================== --- src/OFMutablePair.h +++ src/OFMutablePair.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFMutablePair.m ================================================================== --- src/OFMutablePair.m +++ src/OFMutablePair.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -37,16 +35,14 @@ } - (id)copy { OFMutablePair *copy = [self mutableCopy]; - [copy makeImmutable]; - return copy; } - (void)makeImmutable { object_setClass(self, [OFPair class]); } @end Index: src/OFMutableSet.h ================================================================== --- src/OFMutableSet.h +++ src/OFMutableSet.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFMutableSet.m ================================================================== --- src/OFMutableSet.m +++ src/OFMutableSet.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -58,19 +56,17 @@ va_end(arguments); return ret; } -- (instancetype)initWithObjects: (id const *)objects - count: (size_t)count +- (instancetype)initWithObjects: (id const *)objects count: (size_t)count { return (id)[[OFMutableMapTableSet alloc] initWithObjects: objects count: count]; } -- (instancetype)initWithObject: (id)firstObject - arguments: (va_list)arguments +- (instancetype)initWithObject: (id)firstObject arguments: (va_list)arguments { return (id)[[OFMutableMapTableSet alloc] initWithObject: firstObject arguments: arguments]; } @@ -170,13 +166,11 @@ { void *pool = objc_autoreleasePoolPush(); size_t count = self.count; id *cArray; - cArray = [self allocMemoryWithSize: sizeof(id) - count: count]; - + cArray = OFAllocMemory(count, sizeof(id)); @try { size_t i; i = 0; for (id object in self) { @@ -184,13 +178,13 @@ cArray[i++] = object; } for (i = 0; i < count; i++) if (![set containsObject: cArray[i]]) - [self removeObject: cArray[i]]; + [self removeObject: cArray[i]]; } @finally { - [self freeMemory: cArray]; + OFFreeMemory(cArray); } objc_autoreleasePoolPop(pool); } Index: src/OFMutableString.h ================================================================== --- src/OFMutableString.h +++ src/OFMutableString.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -33,12 +31,11 @@ * @brief Sets the character at the specified index. * * @param character The character to set * @param index The index where to set the character */ -- (void)setCharacter: (of_unichar_t)character - atIndex: (size_t)index; +- (void)setCharacter: (OFUnichar)character atIndex: (size_t)index; /** * @brief Appends another OFString to the OFMutableString. * * @param string An OFString to append @@ -49,12 +46,11 @@ * @brief Appends the specified characters to the OFMutableString. * * @param characters An array of characters to append * @param length The length of the array of characters */ -- (void)appendCharacters: (const of_unichar_t *)characters - length: (size_t)length; +- (void)appendCharacters: (const OFUnichar *)characters length: (size_t)length; /** * @brief Appends a UTF-8 encoded C string to the OFMutableString. * * @param UTF8String A UTF-8 encoded C string to append @@ -76,11 +72,11 @@ * * @param cString A C string to append * @param encoding The encoding of the C string */ - (void)appendCString: (const char *)cString - encoding: (of_string_encoding_t)encoding; + encoding: (OFStringEncoding)encoding; /** * @brief Appends a C string with the specified encoding and length to the * OFMutableString. * @@ -87,36 +83,35 @@ * @param cString A C string to append * @param encoding The encoding of the C string * @param cStringLength The length of the UTF-8 encoded C string */ - (void)appendCString: (const char *)cString - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding length: (size_t)cStringLength; /** * @brief Appends a formatted string to the OFMutableString. * * See `printf` for the format syntax. As an addition, `%@` is available as - * format specifier for objects, `%C` for `of_unichar_t` and `%S` for - * `const of_unichar_t *`. + * format specifier for objects, `%C` for `OFUnichar` and `%S` for + * `const OFUnichar *`. * * @param format A format string which generates the string to append */ - (void)appendFormat: (OFConstantString *)format, ...; /** * @brief Appends a formatted string to the OFMutableString. * * See printf for the format syntax. As an addition, `%@` is available as - * format specifier for objects, `%C` for `of_unichar_t` and `%S` for - * `const of_unichar_t *`. + * format specifier for objects, `%C` for `OFUnichar` and `%S` for + * `const OFUnichar *`. * * @param format A format string which generates the string to append * @param arguments The arguments used in the format string */ -- (void)appendFormat: (OFConstantString *)format - arguments: (va_list)arguments; +- (void)appendFormat: (OFConstantString *)format arguments: (va_list)arguments; /** * @brief Prepends another OFString to the OFMutableString. * * @param string An OFString to prepend @@ -151,27 +146,26 @@ * @brief Inserts a string at the specified index. * * @param string The string to insert * @param index The index */ -- (void)insertString: (OFString *)string - atIndex: (size_t)index; +- (void)insertString: (OFString *)string atIndex: (size_t)index; /** * @brief Deletes the characters at the specified range. * * @param range The range of the characters which should be removed */ -- (void)deleteCharactersInRange: (of_range_t)range; +- (void)deleteCharactersInRange: (OFRange)range; /** * @brief Replaces the characters at the specified range. * * @param range The range of the characters which should be replaced * @param replacement The string to the replace the characters with */ -- (void)replaceCharactersInRange: (of_range_t)range +- (void)replaceCharactersInRange: (OFRange)range withString: (OFString *)replacement; /** * @brief Replaces all occurrences of a string with another string. * @@ -192,11 +186,11 @@ * @param range The range in which the string should be replaced */ - (void)replaceOccurrencesOfString: (OFString *)string withString: (OFString *)replacement options: (int)options - range: (of_range_t)range; + range: (OFRange)range; /** * @brief Deletes all whitespaces at the beginning of the string. */ - (void)deleteLeadingWhitespaces; Index: src/OFMutableString.m ================================================================== --- src/OFMutableString.m +++ src/OFMutableString.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -20,17 +18,17 @@ #include #include #include #import "OFString.h" +#import "OFASPrintF.h" #import "OFMutableUTF8String.h" #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFOutOfRangeException.h" -#import "of_asprintf.h" #import "unicode.h" static struct { Class isa; } placeholder; @@ -56,18 +54,18 @@ initWithUTF8String: UTF8String length: UTF8StringLength]; } - (instancetype)initWithCString: (const char *)cString - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding { return (id)[[OFMutableUTF8String alloc] initWithCString: cString encoding: encoding]; } - (instancetype)initWithCString: (const char *)cString - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding length: (size_t)cStringLength { return (id)[[OFMutableUTF8String alloc] initWithCString: cString encoding: encoding length: cStringLength]; @@ -76,67 +74,67 @@ - (instancetype)initWithString: (OFString *)string { return (id)[[OFMutableUTF8String alloc] initWithString: string]; } -- (instancetype)initWithCharacters: (const of_unichar_t *)characters +- (instancetype)initWithCharacters: (const OFUnichar *)characters length: (size_t)length { return (id)[[OFMutableUTF8String alloc] initWithCharacters: characters length: length]; } -- (instancetype)initWithUTF16String: (const of_char16_t *)string +- (instancetype)initWithUTF16String: (const OFChar16 *)string { return (id)[[OFMutableUTF8String alloc] initWithUTF16String: string]; } -- (instancetype)initWithUTF16String: (const of_char16_t *)string +- (instancetype)initWithUTF16String: (const OFChar16 *)string length: (size_t)length { return (id)[[OFMutableUTF8String alloc] initWithUTF16String: string length: length]; } -- (instancetype)initWithUTF16String: (const of_char16_t *)string - byteOrder: (of_byte_order_t)byteOrder +- (instancetype)initWithUTF16String: (const OFChar16 *)string + byteOrder: (OFByteOrder)byteOrder { return (id)[[OFMutableUTF8String alloc] initWithUTF16String: string byteOrder: byteOrder]; } -- (instancetype)initWithUTF16String: (const of_char16_t *)string +- (instancetype)initWithUTF16String: (const OFChar16 *)string length: (size_t)length - byteOrder: (of_byte_order_t)byteOrder + byteOrder: (OFByteOrder)byteOrder { return (id)[[OFMutableUTF8String alloc] initWithUTF16String: string length: length byteOrder: byteOrder]; } -- (instancetype)initWithUTF32String: (const of_char32_t *)string +- (instancetype)initWithUTF32String: (const OFChar32 *)string { return (id)[[OFMutableUTF8String alloc] initWithUTF32String: string]; } -- (instancetype)initWithUTF32String: (const of_char32_t *)string +- (instancetype)initWithUTF32String: (const OFChar32 *)string length: (size_t)length { return (id)[[OFMutableUTF8String alloc] initWithUTF32String: string length: length]; } -- (instancetype)initWithUTF32String: (const of_char32_t *)string - byteOrder: (of_byte_order_t)byteOrder +- (instancetype)initWithUTF32String: (const OFChar32 *)string + byteOrder: (OFByteOrder)byteOrder { return (id)[[OFMutableUTF8String alloc] initWithUTF32String: string byteOrder: byteOrder]; } -- (instancetype)initWithUTF32String: (const of_char32_t *)string +- (instancetype)initWithUTF32String: (const OFChar32 *)string length: (size_t)length - byteOrder: (of_byte_order_t)byteOrder + byteOrder: (OFByteOrder)byteOrder { return (id)[[OFMutableUTF8String alloc] initWithUTF32String: string length: length byteOrder: byteOrder]; } @@ -166,32 +164,30 @@ { return (id)[[OFMutableUTF8String alloc] initWithContentsOfFile: path]; } - (instancetype)initWithContentsOfFile: (OFString *)path - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding { return (id)[[OFMutableUTF8String alloc] initWithContentsOfFile: path encoding: encoding]; } #endif -#if defined(OF_HAVE_FILES) || defined(OF_HAVE_SOCKETS) - (instancetype)initWithContentsOfURL: (OFURL *)URL { return (id)[[OFMutableUTF8String alloc] initWithContentsOfURL: URL]; } - (instancetype)initWithContentsOfURL: (OFURL *)URL - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding { return (id)[[OFMutableUTF8String alloc] initWithContentsOfURL: URL encoding: encoding]; } -#endif - (instancetype)initWithSerialization: (OFXMLElement *)element { return (id)[[OFMutableUTF8String alloc] initWithSerialization: element]; } @@ -230,24 +226,24 @@ return [super alloc]; } #ifdef OF_HAVE_UNICODE_TABLES -- (void)of_convertWithWordStartTable: (const of_unichar_t *const [])startTable - wordMiddleTable: (const of_unichar_t *const [])middleTable +- (void)of_convertWithWordStartTable: (const OFUnichar *const [])startTable + wordMiddleTable: (const OFUnichar *const [])middleTable wordStartTableSize: (size_t)startTableSize - wordMiddleTableSize: (size_t)middleTableSize OF_DIRECT + wordMiddleTableSize: (size_t)middleTableSize { void *pool = objc_autoreleasePoolPush(); - const of_unichar_t *characters = self.characters; + const OFUnichar *characters = self.characters; size_t length = self.length; bool isStart = true; for (size_t i = 0; i < length; i++) { - const of_unichar_t *const *table; + const OFUnichar *const *table; size_t tableSize; - of_unichar_t c = characters[i]; + OFUnichar c = characters[i]; if (isStart) { table = startTable; tableSize = middleTableSize; } else { @@ -254,117 +250,98 @@ table = middleTable; tableSize = middleTableSize; } if (c >> 8 < tableSize && table[c >> 8][c & 0xFF]) - [self setCharacter: table[c >> 8][c & 0xFF] - atIndex: i]; + [self setCharacter: table[c >> 8][c & 0xFF] atIndex: i]; - isStart = of_ascii_isspace(c); + isStart = OFASCIIIsSpace(c); } objc_autoreleasePoolPop(pool); } #else -- (void)of_convertWithWordStartFunction: (char (*)(char))startFunction - wordMiddleFunction: (char (*)(char))middleFunction - OF_DIRECT +static void +convert(OFMutableString *self, char (*startFunction)(char), + char (*middleFunction)(char)) { void *pool = objc_autoreleasePoolPush(); - const of_unichar_t *characters = self.characters; + const OFUnichar *characters = self.characters; size_t length = self.length; bool isStart = true; for (size_t i = 0; i < length; i++) { char (*function)(char) = (isStart ? startFunction : middleFunction); - of_unichar_t c = characters[i]; + OFUnichar c = characters[i]; if (c <= 0x7F) - [self setCharacter: (int)function(c) - atIndex: i]; + [self setCharacter: (int)function(c) atIndex: i]; - isStart = of_ascii_isspace(c); + isStart = OFASCIIIsSpace(c); } objc_autoreleasePoolPop(pool); } #endif -- (void)setCharacter: (of_unichar_t)character - atIndex: (size_t)idx +- (void)setCharacter: (OFUnichar)character atIndex: (size_t)idx { void *pool = objc_autoreleasePoolPush(); - OFString *string; - - string = [OFString stringWithCharacters: &character - length: 1]; - - [self replaceCharactersInRange: of_range(idx, 1) - withString: string]; - + OFString *string = + [OFString stringWithCharacters: &character length: 1]; + [self replaceCharactersInRange: OFRangeMake(idx, 1) withString: string]; objc_autoreleasePoolPop(pool); } - (void)appendString: (OFString *)string { - [self insertString: string - atIndex: self.length]; + [self insertString: string atIndex: self.length]; } -- (void)appendCharacters: (const of_unichar_t *)characters +- (void)appendCharacters: (const OFUnichar *)characters length: (size_t)length { void *pool = objc_autoreleasePoolPush(); - [self appendString: [OFString stringWithCharacters: characters length: length]]; - objc_autoreleasePoolPop(pool); } - (void)appendUTF8String: (const char *)UTF8String { void *pool = objc_autoreleasePoolPush(); - [self appendString: [OFString stringWithUTF8String: UTF8String]]; - objc_autoreleasePoolPop(pool); } - (void)appendUTF8String: (const char *)UTF8String length: (size_t)UTF8StringLength { void *pool = objc_autoreleasePoolPush(); - [self appendString: [OFString stringWithUTF8String: UTF8String length: UTF8StringLength]]; - objc_autoreleasePoolPop(pool); } - (void)appendCString: (const char *)cString - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding { void *pool = objc_autoreleasePoolPush(); - [self appendString: [OFString stringWithCString: cString encoding: encoding]]; - objc_autoreleasePoolPop(pool); } - (void)appendCString: (const char *)cString - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding length: (size_t)cStringLength { void *pool = objc_autoreleasePoolPush(); - [self appendString: [OFString stringWithCString: cString encoding: encoding length: cStringLength]]; - objc_autoreleasePoolPop(pool); } - (void)appendFormat: (OFConstantString *)format, ... { @@ -374,108 +351,97 @@ [self appendFormat: format arguments: arguments]; va_end(arguments); } -- (void)appendFormat: (OFConstantString *)format - arguments: (va_list)arguments +- (void)appendFormat: (OFConstantString *)format arguments: (va_list)arguments { char *UTF8String; int UTF8StringLength; if (format == nil) @throw [OFInvalidArgumentException exception]; - if ((UTF8StringLength = of_vasprintf(&UTF8String, format.UTF8String, + if ((UTF8StringLength = OFVASPrintF(&UTF8String, format.UTF8String, arguments)) == -1) @throw [OFInvalidFormatException exception]; @try { - [self appendUTF8String: UTF8String - length: UTF8StringLength]; + [self appendUTF8String: UTF8String length: UTF8StringLength]; } @finally { free(UTF8String); } } - (void)prependString: (OFString *)string { - [self insertString: string - atIndex: 0]; + [self insertString: string atIndex: 0]; } - (void)reverse { size_t i, j, length = self.length; for (i = 0, j = length - 1; i < length / 2; i++, j--) { - of_unichar_t tmp = [self characterAtIndex: j]; - [self setCharacter: [self characterAtIndex: i] - atIndex: j]; - [self setCharacter: tmp - atIndex: i]; + OFUnichar tmp = [self characterAtIndex: j]; + [self setCharacter: [self characterAtIndex: i] atIndex: j]; + [self setCharacter: tmp atIndex: i]; } } #ifdef OF_HAVE_UNICODE_TABLES - (void)uppercase { - [self of_convertWithWordStartTable: of_unicode_uppercase_table - wordMiddleTable: of_unicode_uppercase_table - wordStartTableSize: OF_UNICODE_UPPERCASE_TABLE_SIZE - wordMiddleTableSize: OF_UNICODE_UPPERCASE_TABLE_SIZE]; -} - -- (void)lowercase -{ - [self of_convertWithWordStartTable: of_unicode_lowercase_table - wordMiddleTable: of_unicode_lowercase_table - wordStartTableSize: OF_UNICODE_LOWERCASE_TABLE_SIZE - wordMiddleTableSize: OF_UNICODE_LOWERCASE_TABLE_SIZE]; -} - -- (void)capitalize -{ - [self of_convertWithWordStartTable: of_unicode_titlecase_table - wordMiddleTable: of_unicode_lowercase_table - wordStartTableSize: OF_UNICODE_TITLECASE_TABLE_SIZE - wordMiddleTableSize: OF_UNICODE_LOWERCASE_TABLE_SIZE]; -} -#else -- (void)uppercase -{ - [self of_convertWithWordStartFunction: of_ascii_toupper - wordMiddleFunction: of_ascii_toupper]; -} - -- (void)lowercase -{ - [self of_convertWithWordStartFunction: of_ascii_tolower - wordMiddleFunction: of_ascii_tolower]; -} - -- (void)capitalize -{ - [self of_convertWithWordStartFunction: of_ascii_toupper - wordMiddleFunction: of_ascii_tolower]; -} -#endif - -- (void)insertString: (OFString *)string - atIndex: (size_t)idx -{ - [self replaceCharactersInRange: of_range(idx, 0) - withString: string]; -} - -- (void)deleteCharactersInRange: (of_range_t)range -{ - [self replaceCharactersInRange: range - withString: @""]; -} - -- (void)replaceCharactersInRange: (of_range_t)range + [self of_convertWithWordStartTable: OFUnicodeUppercaseTable + wordMiddleTable: OFUnicodeUppercaseTable + wordStartTableSize: OFUnicodeUppercaseTableSize + wordMiddleTableSize: OFUnicodeUppercaseTableSize]; +} + +- (void)lowercase +{ + [self of_convertWithWordStartTable: OFUnicodeLowercaseTable + wordMiddleTable: OFUnicodeLowercaseTable + wordStartTableSize: OFUnicodeLowercaseTableSize + wordMiddleTableSize: OFUnicodeLowercaseTableSize]; +} + +- (void)capitalize +{ + [self of_convertWithWordStartTable: OFUnicodeTitlecaseTable + wordMiddleTable: OFUnicodeLowercaseTable + wordStartTableSize: OFUnicodeTitlecaseTableSize + wordMiddleTableSize: OFUnicodeLowercaseTableSize]; +} +#else +- (void)uppercase +{ + convert(self, OFASCIIToUpper, OFASCIIToUpper); +} + +- (void)lowercase +{ + convert(self, OFASCIIToLower, OFASCIIToLower); +} + +- (void)capitalize +{ + convert(self, OFASCIIToUpper, OFASCIIToLower); +} +#endif + +- (void)insertString: (OFString *)string atIndex: (size_t)idx +{ + [self replaceCharactersInRange: OFRangeMake(idx, 0) withString: string]; +} + +- (void)deleteCharactersInRange: (OFRange)range +{ + [self replaceCharactersInRange: range withString: @""]; +} + +- (void)replaceCharactersInRange: (OFRange)range withString: (OFString *)replacement { OF_UNRECOGNIZED_SELECTOR } @@ -483,21 +449,21 @@ withString: (OFString *)replacement { [self replaceOccurrencesOfString: string withString: replacement options: 0 - range: of_range(0, self.length)]; + range: OFRangeMake(0, self.length)]; } - (void)replaceOccurrencesOfString: (OFString *)string withString: (OFString *)replacement options: (int)options - range: (of_range_t)range + range: (OFRange)range { void *pool = objc_autoreleasePoolPush(), *pool2; - const of_unichar_t *characters; - const of_unichar_t *searchCharacters = string.characters; + const OFUnichar *characters; + const OFUnichar *searchCharacters = string.characters; size_t searchLength = string.length; size_t replacementLength = replacement.length; if (string == nil || replacement == nil) @throw [OFInvalidArgumentException exception]; @@ -514,14 +480,14 @@ pool2 = objc_autoreleasePoolPush(); characters = self.characters; for (size_t i = range.location; i <= range.length - searchLength; i++) { if (memcmp(characters + i, searchCharacters, - searchLength * sizeof(of_unichar_t)) != 0) + searchLength * sizeof(OFUnichar)) != 0) continue; - [self replaceCharactersInRange: of_range(i, searchLength) + [self replaceCharactersInRange: OFRangeMake(i, searchLength) withString: replacement]; range.length -= searchLength; range.length += replacementLength; @@ -537,29 +503,29 @@ } - (void)deleteLeadingWhitespaces { void *pool = objc_autoreleasePoolPush(); - const of_unichar_t *characters = self.characters; + const OFUnichar *characters = self.characters; size_t i, length = self.length; for (i = 0; i < length; i++) { - of_unichar_t c = characters[i]; + OFUnichar c = characters[i]; - if (!of_ascii_isspace(c)) + if (!OFASCIIIsSpace(c)) break; } objc_autoreleasePoolPop(pool); - [self deleteCharactersInRange: of_range(0, i)]; + [self deleteCharactersInRange: OFRangeMake(0, i)]; } - (void)deleteTrailingWhitespaces { void *pool; - const of_unichar_t *characters, *p; + const OFUnichar *characters, *p; size_t length, d; length = self.length; if (length == 0) @@ -568,19 +534,19 @@ pool = objc_autoreleasePoolPush(); characters = self.characters; d = 0; for (p = characters + length - 1; p >= characters; p--) { - if (!of_ascii_isspace(*p)) + if (!OFASCIIIsSpace(*p)) break; d++; } objc_autoreleasePoolPop(pool); - [self deleteCharactersInRange: of_range(length - d, d)]; + [self deleteCharactersInRange: OFRangeMake(length - d, d)]; } - (void)deleteEnclosingWhitespaces { [self deleteLeadingWhitespaces]; Index: src/OFMutableTarArchiveEntry.h ================================================================== --- src/OFMutableTarArchiveEntry.h +++ src/OFMutableTarArchiveEntry.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -61,13 +59,13 @@ @property (readwrite, retain, nonatomic) OFDate *modificationDate; /** * @brief The type of the archive entry. * - * See @ref of_tar_archive_entry_type_t. + * See @ref OFTarArchiveEntryType. */ -@property (readwrite, nonatomic) of_tar_archive_entry_type_t type; +@property (readwrite, nonatomic) OFTarArchiveEntryType type; /** * @brief The file name of the target (for a hard link or symbolic link). */ @property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) Index: src/OFMutableTarArchiveEntry.m ================================================================== --- src/OFMutableTarArchiveEntry.m +++ src/OFMutableTarArchiveEntry.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -66,11 +64,11 @@ OFDate *old = _modificationDate; _modificationDate = [modificationDate retain]; [old release]; } -- (void)setType: (of_tar_archive_entry_type_t)type +- (void)setType: (OFTarArchiveEntryType)type { _type = type; } - (void)setTargetFileName: (OFString *)targetFileName Index: src/OFMutableTriple.h ================================================================== --- src/OFMutableTriple.h +++ src/OFMutableTriple.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFMutableTriple.m ================================================================== --- src/OFMutableTriple.m +++ src/OFMutableTriple.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFMutableURL.h ================================================================== --- src/OFMutableURL.h +++ src/OFMutableURL.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -131,12 +129,12 @@ * * For example, a query like `key1=value1&key2=value2` would correspond to the * following dictionary: * * @{ - * @"key1": "value1", - * @"key2": "value2" + * @"key1": @"value1", + * @"key2": @"value2" * } */ @property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) OFDictionary OF_GENERIC(OFString *, OFString *) *queryDictionary; @@ -177,11 +175,11 @@ */ - (void)appendPathComponent: (OFString *)component isDirectory: (bool)isDirectory; /** - * @brief Resolves relative sub paths. + * @brief Resolves relative subpaths. */ - (void)standardizePath; /** * @brief Converts the mutable URL to an immutable URL. Index: src/OFMutableURL.m ================================================================== --- src/OFMutableURL.m +++ src/OFMutableURL.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -26,12 +24,10 @@ #import "OFNumber.h" #import "OFString.h" #import "OFInvalidFormatException.h" -extern void of_url_verify_escaped(OFString *, OFCharacterSet *); - @implementation OFMutableURL @dynamic scheme, URLEncodedScheme, host, URLEncodedHost, port, user; @dynamic URLEncodedUser, password, URLEncodedPassword, path, URLEncodedPath; @dynamic pathComponents, query, URLEncodedQuery, queryDictionary, fragment; @dynamic URLEncodedFragment; @@ -57,11 +53,11 @@ - (void)setURLEncodedScheme: (OFString *)URLEncodedScheme { OFString *old; if (URLEncodedScheme != nil) - of_url_verify_escaped(URLEncodedScheme, + OFURLVerifyIsEscaped(URLEncodedScheme, [OFCharacterSet URLSchemeAllowedCharacterSet]); old = _URLEncodedScheme; _URLEncodedScheme = [URLEncodedScheme copy]; [old release]; @@ -70,11 +66,11 @@ - (void)setHost: (OFString *)host { void *pool = objc_autoreleasePoolPush(); OFString *old = _URLEncodedHost; - if (of_url_is_ipv6_host(host)) + if (OFURLIsIPv6Host(host)) _URLEncodedHost = [[OFString alloc] initWithFormat: @"[%@]", host]; else _URLEncodedHost = [[host stringByURLEncodingWithAllowedCharacters: @@ -89,15 +85,15 @@ { OFString *old; if ([URLEncodedHost hasPrefix: @"["] && [URLEncodedHost hasSuffix: @"]"]) { - if (!of_url_is_ipv6_host([URLEncodedHost substringWithRange: - of_range(1, URLEncodedHost.length - 2)])) + if (!OFURLIsIPv6Host([URLEncodedHost substringWithRange: + OFRangeMake(1, URLEncodedHost.length - 2)])) @throw [OFInvalidFormatException exception]; } else if (URLEncodedHost != nil) - of_url_verify_escaped(URLEncodedHost, + OFURLVerifyIsEscaped(URLEncodedHost, [OFCharacterSet URLHostAllowedCharacterSet]); old = _URLEncodedHost; _URLEncodedHost = [URLEncodedHost copy]; [old release]; @@ -126,11 +122,11 @@ - (void)setURLEncodedUser: (OFString *)URLEncodedUser { OFString *old; if (URLEncodedUser != nil) - of_url_verify_escaped(URLEncodedUser, + OFURLVerifyIsEscaped(URLEncodedUser, [OFCharacterSet URLUserAllowedCharacterSet]); old = _URLEncodedUser; _URLEncodedUser = [URLEncodedUser copy]; [old release]; @@ -153,11 +149,11 @@ - (void)setURLEncodedPassword: (OFString *)URLEncodedPassword { OFString *old; if (URLEncodedPassword != nil) - of_url_verify_escaped(URLEncodedPassword, + OFURLVerifyIsEscaped(URLEncodedPassword, [OFCharacterSet URLPasswordAllowedCharacterSet]); old = _URLEncodedPassword; _URLEncodedPassword = [URLEncodedPassword copy]; [old release]; @@ -179,11 +175,11 @@ - (void)setURLEncodedPath: (OFString *)URLEncodedPath { OFString *old; if (URLEncodedPath != nil) - of_url_verify_escaped(URLEncodedPath, + OFURLVerifyIsEscaped(URLEncodedPath, [OFCharacterSet URLPathAllowedCharacterSet]); old = _URLEncodedPath; _URLEncodedPath = [URLEncodedPath copy]; [old release]; @@ -225,11 +221,11 @@ - (void)setURLEncodedQuery: (OFString *)URLEncodedQuery { OFString *old; if (URLEncodedQuery != nil) - of_url_verify_escaped(URLEncodedQuery, + OFURLVerifyIsEscaped(URLEncodedQuery, [OFCharacterSet URLQueryAllowedCharacterSet]); old = _URLEncodedQuery; _URLEncodedQuery = [URLEncodedQuery copy]; [old release]; @@ -293,11 +289,11 @@ - (void)setURLEncodedFragment: (OFString *)URLEncodedFragment { OFString *old; if (URLEncodedFragment != nil) - of_url_verify_escaped(URLEncodedFragment, + OFURLVerifyIsEscaped(URLEncodedFragment, [OFCharacterSet URLFragmentAllowedCharacterSet]); old = _URLEncodedFragment; _URLEncodedFragment = [URLEncodedFragment copy]; [old release]; @@ -312,12 +308,11 @@ return copy; } - (void)appendPathComponent: (OFString *)component { - [self appendPathComponent: component - isDirectory: false]; + [self appendPathComponent: component isDirectory: false]; #ifdef OF_HAVE_FILES if ([_URLEncodedScheme isEqual: @"file"] && ![_URLEncodedPath hasSuffix: @"/"] && [[OFFileManager defaultManager] directoryExistsAtURL: self]) { @@ -405,20 +400,19 @@ } if ([current isEqual: @".."] && parent != nil && ![parent isEqual: @".."]) { [array removeObjectsInRange: - of_range(i - 1, 2)]; + OFRangeMake(i - 1, 2)]; done = false; break; } } } - [array insertObject: @"" - atIndex: 0]; + [array insertObject: @"" atIndex: 0]; if (endsWithEmpty) [array addObject: @""]; path = [array componentsJoinedByString: @"/"]; if (path.length == 0) Index: src/OFMutableUTF8String.h ================================================================== --- src/OFMutableUTF8String.h +++ src/OFMutableUTF8String.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -20,11 +18,11 @@ OF_ASSUME_NONNULL_BEGIN @interface OFMutableUTF8String: OFMutableString { - struct of_string_utf8_ivars *restrict _s; - struct of_string_utf8_ivars _storage; + struct OFUTF8StringIvars *restrict _s; + struct OFUTF8StringIvars _storage; } @end OF_ASSUME_NONNULL_END Index: src/OFMutableUTF8String.m ================================================================== --- src/OFMutableUTF8String.m +++ src/OFMutableUTF8String.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -21,20 +19,20 @@ #include #include #include #import "OFMutableUTF8String.h" +#import "OFASPrintF.h" #import "OFString.h" #import "OFUTF8String.h" #import "OFInvalidArgumentException.h" #import "OFInvalidEncodingException.h" #import "OFInvalidFormatException.h" #import "OFOutOfMemoryException.h" #import "OFOutOfRangeException.h" -#import "of_asprintf.h" #import "unicode.h" @implementation OFMutableUTF8String + (void)initialize { @@ -43,80 +41,75 @@ } - (instancetype)initWithUTF8StringNoCopy: (char *)UTF8String freeWhenDone: (bool)freeWhenDone { - @try { - self = [self initWithUTF8String: UTF8String]; - } @finally { - if (freeWhenDone) - free(UTF8String); - } + self = [self initWithUTF8String: UTF8String]; + + if (freeWhenDone) + OFFreeMemory(UTF8String); return self; } - (instancetype)initWithUTF8StringNoCopy: (char *)UTF8String length: (size_t)UTF8StringLength freeWhenDone: (bool)freeWhenDone { - @try { - self = [self initWithUTF8String: UTF8String - length: UTF8StringLength]; - } @finally { - if (freeWhenDone) - free(UTF8String); - } + self = [self initWithUTF8String: UTF8String length: UTF8StringLength]; + + if (freeWhenDone) + OFFreeMemory(UTF8String); return self; } -- (void)of_convertWithWordStartTable: (const of_unichar_t *const[])startTable - wordMiddleTable: (const of_unichar_t *const[])middleTable +#ifdef OF_HAVE_UNICODE_TABLES +- (void)of_convertWithWordStartTable: (const OFUnichar *const [])startTable + wordMiddleTable: (const OFUnichar *const [])middleTable wordStartTableSize: (size_t)startTableSize - wordMiddleTableSize: (size_t)middleTableSize OF_DIRECT + wordMiddleTableSize: (size_t)middleTableSize { - of_unichar_t *unicodeString; + OFUnichar *unicodeString; size_t unicodeLen, newCStringLength; size_t i, j; char *newCString; bool isStart = true; if (!_s->isUTF8) { uint8_t t; - const of_unichar_t *const *table; + const OFUnichar *const *table; assert(startTableSize >= 1 && middleTableSize >= 1); - _s->hashed = false; + _s->hasHash = false; for (i = 0; i < _s->cStringLength; i++) { if (isStart) table = startTable; else table = middleTable; - isStart = of_ascii_isspace(_s->cString[i]); + isStart = OFASCIIIsSpace(_s->cString[i]); if ((t = table[0][(uint8_t)_s->cString[i]]) != 0) _s->cString[i] = t; } return; } unicodeLen = self.length; - unicodeString = [self allocMemoryWithSize: sizeof(of_unichar_t) - count: unicodeLen]; + unicodeString = OFAllocMemory(unicodeLen, sizeof(OFUnichar)); i = j = 0; newCStringLength = 0; while (i < _s->cStringLength) { - const of_unichar_t *const *table; + const OFUnichar *const *table; size_t tableSize; - of_unichar_t c; + OFUnichar c; ssize_t cLen; if (isStart) { table = startTable; tableSize = middleTableSize; @@ -123,22 +116,22 @@ } else { table = middleTable; tableSize = middleTableSize; } - cLen = of_string_utf8_decode(_s->cString + i, + cLen = OFUTF8StringDecode(_s->cString + i, _s->cStringLength - i, &c); if (cLen <= 0 || c > 0x10FFFF) { - [self freeMemory: unicodeString]; + OFFreeMemory(unicodeString); @throw [OFInvalidEncodingException exception]; } - isStart = of_ascii_isspace(c); + isStart = OFASCIIIsSpace(c); if (c >> 8 < tableSize) { - of_unichar_t tc = table[c >> 8][c & 0xFF]; + OFUnichar tc = table[c >> 8][c & 0xFF]; if (tc) c = tc; } unicodeString[j++] = c; @@ -150,90 +143,89 @@ else if (c < 0x10000) newCStringLength += 3; else if (c < 0x110000) newCStringLength += 4; else { - [self freeMemory: unicodeString]; + OFFreeMemory(unicodeString); @throw [OFInvalidEncodingException exception]; } i += cLen; } @try { - newCString = [self allocMemoryWithSize: newCStringLength + 1]; + newCString = OFAllocMemory(newCStringLength + 1, 1); } @catch (id e) { - [self freeMemory: unicodeString]; + OFFreeMemory(unicodeString); @throw e; } j = 0; for (i = 0; i < unicodeLen; i++) { size_t d; - if ((d = of_string_utf8_encode(unicodeString[i], + if ((d = OFUTF8StringEncode(unicodeString[i], newCString + j)) == 0) { - [self freeMemory: unicodeString]; - [self freeMemory: newCString]; + OFFreeMemory(unicodeString); + OFFreeMemory(newCString); @throw [OFInvalidEncodingException exception]; } j += d; } assert(j == newCStringLength); newCString[j] = 0; - [self freeMemory: unicodeString]; + OFFreeMemory(unicodeString); - [self freeMemory: _s->cString]; - _s->hashed = false; + OFFreeMemory(_s->cString); + _s->hasHash = false; _s->cString = newCString; _s->cStringLength = newCStringLength; /* * Even though cStringLength can change, length cannot, therefore no * need to change it. */ } +#endif -- (void)setCharacter: (of_unichar_t)character - atIndex: (size_t)idx +- (void)setCharacter: (OFUnichar)character atIndex: (size_t)idx { char buffer[4]; - of_unichar_t c; + OFUnichar c; size_t lenNew; ssize_t lenOld; if (_s->isUTF8) - idx = of_string_utf8_get_position(_s->cString, idx, + idx = OFUTF8StringIndexToPosition(_s->cString, idx, _s->cStringLength); if (idx >= _s->cStringLength) @throw [OFOutOfRangeException exception]; /* Shortcut if old and new character both are ASCII */ if (character < 0x80 && !(_s->cString[idx] & 0x80)) { - _s->hashed = false; + _s->hasHash = false; _s->cString[idx] = character; return; } - if ((lenNew = of_string_utf8_encode(character, buffer)) == 0) + if ((lenNew = OFUTF8StringEncode(character, buffer)) == 0) @throw [OFInvalidEncodingException exception]; - if ((lenOld = of_string_utf8_decode(_s->cString + idx, + if ((lenOld = OFUTF8StringDecode(_s->cString + idx, _s->cStringLength - idx, &c)) <= 0) @throw [OFInvalidEncodingException exception]; - _s->hashed = false; + _s->hasHash = false; if (lenNew == (size_t)lenOld) memcpy(_s->cString + idx, buffer, lenNew); else if (lenNew > (size_t)lenOld) { - _s->cString = [self resizeMemory: _s->cString - size: _s->cStringLength - - lenOld + lenNew + 1]; + _s->cString = OFResizeMemory(_s->cString, + _s->cStringLength - lenOld + lenNew + 1, 1); memmove(_s->cString + idx + lenNew, _s->cString + idx + lenOld, _s->cStringLength - idx - lenOld); memcpy(_s->cString + idx, buffer, lenNew); @@ -254,13 +246,12 @@ if (character >= 0x80) _s->isUTF8 = true; @try { - _s->cString = [self - resizeMemory: _s->cString - size: _s->cStringLength + 1]; + _s->cString = OFResizeMemory(_s->cString, + _s->cStringLength + 1, 1); } @catch (OFOutOfMemoryException *e) { /* We don't really care, as we only made it smaller */ } } } @@ -274,22 +265,21 @@ memcmp(UTF8String, "\xEF\xBB\xBF", 3) == 0) { UTF8String += 3; UTF8StringLength -= 3; } - switch (of_string_utf8_check(UTF8String, UTF8StringLength, &length)) { + switch (OFUTF8StringCheck(UTF8String, UTF8StringLength, &length)) { case 1: _s->isUTF8 = true; break; case -1: @throw [OFInvalidEncodingException exception]; } - _s->hashed = false; - _s->cString = [self resizeMemory: _s->cString - size: _s->cStringLength + - UTF8StringLength + 1]; + _s->hasHash = false; + _s->cString = OFResizeMemory(_s->cString, + _s->cStringLength + UTF8StringLength + 1, 1); memcpy(_s->cString + _s->cStringLength, UTF8String, UTF8StringLength + 1); _s->cStringLength += UTF8StringLength; _s->length += length; @@ -304,45 +294,43 @@ memcmp(UTF8String, "\xEF\xBB\xBF", 3) == 0) { UTF8String += 3; UTF8StringLength -= 3; } - switch (of_string_utf8_check(UTF8String, UTF8StringLength, &length)) { + switch (OFUTF8StringCheck(UTF8String, UTF8StringLength, &length)) { case 1: _s->isUTF8 = true; break; case -1: @throw [OFInvalidEncodingException exception]; } - _s->hashed = false; - _s->cString = [self resizeMemory: _s->cString - size: _s->cStringLength + - UTF8StringLength + 1]; + _s->hasHash = false; + _s->cString = OFResizeMemory(_s->cString, + _s->cStringLength + UTF8StringLength + 1, 1); memcpy(_s->cString + _s->cStringLength, UTF8String, UTF8StringLength); _s->cStringLength += UTF8StringLength; _s->length += length; _s->cString[_s->cStringLength] = 0; } - (void)appendCString: (const char *)cString - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding { [self appendCString: cString encoding: encoding length: strlen(cString)]; } - (void)appendCString: (const char *)cString - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding length: (size_t)cStringLength { - if (encoding == OF_STRING_ENCODING_UTF_8) - [self appendUTF8String: cString - length: cStringLength]; + if (encoding == OFStringEncodingUTF8) + [self appendUTF8String: cString length: cStringLength]; else { void *pool = objc_autoreleasePoolPush(); [self appendString: [OFString stringWithCString: cString @@ -360,14 +348,13 @@ if (string == nil) @throw [OFInvalidArgumentException exception]; UTF8StringLength = string.UTF8StringLength; - _s->hashed = false; - _s->cString = [self resizeMemory: _s->cString - size: _s->cStringLength + - UTF8StringLength + 1]; + _s->hasHash = false; + _s->cString = OFResizeMemory(_s->cString, + _s->cStringLength + UTF8StringLength + 1, 1); memcpy(_s->cString + _s->cStringLength, string.UTF8String, UTF8StringLength); _s->cStringLength += UTF8StringLength; _s->length += string.length; @@ -380,23 +367,20 @@ _s->isUTF8 = true; } else _s->isUTF8 = true; } -- (void)appendCharacters: (const of_unichar_t *)characters - length: (size_t)length +- (void)appendCharacters: (const OFUnichar *)characters length: (size_t)length { - char *tmp; + char *tmp = OFAllocMemory((length * 4) + 1, 1); - tmp = [self allocMemoryWithSize: (length * 4) + 1]; @try { size_t j = 0; bool isUTF8 = false; for (size_t i = 0; i < length; i++) { - size_t len = of_string_utf8_encode(characters[i], - tmp + j); + size_t len = OFUTF8StringEncode(characters[i], tmp + j); if (len == 0) @throw [OFInvalidEncodingException exception]; if (len > 1) @@ -405,51 +389,49 @@ j += len; } tmp[j] = '\0'; - _s->hashed = false; - _s->cString = [self resizeMemory: _s->cString - size: _s->cStringLength + j + 1]; + _s->hasHash = false; + _s->cString = OFResizeMemory(_s->cString, + _s->cStringLength + j + 1, 1); memcpy(_s->cString + _s->cStringLength, tmp, j + 1); _s->cStringLength += j; _s->length += length; if (isUTF8) _s->isUTF8 = true; } @finally { - [self freeMemory: tmp]; + OFFreeMemory(tmp); } } -- (void)appendFormat: (OFConstantString *)format - arguments: (va_list)arguments +- (void)appendFormat: (OFConstantString *)format arguments: (va_list)arguments { char *UTF8String; int UTF8StringLength; if (format == nil) @throw [OFInvalidArgumentException exception]; - if ((UTF8StringLength = of_vasprintf(&UTF8String, format.UTF8String, + if ((UTF8StringLength = OFVASPrintF(&UTF8String, format.UTF8String, arguments)) == -1) @throw [OFInvalidFormatException exception]; @try { - [self appendUTF8String: UTF8String - length: UTF8StringLength]; + [self appendUTF8String: UTF8String length: UTF8StringLength]; } @finally { free(UTF8String); } } - (void)reverse { size_t i, j; - _s->hashed = false; + _s->hasHash = false; /* We reverse all bytes and restore UTF-8 later, if necessary */ for (i = 0, j = _s->cStringLength - 1; i < _s->cStringLength / 2; i++, j--) { _s->cString[i] ^= _s->cString[j]; @@ -521,26 +503,24 @@ /* UTF-8 does not allow more than 4 bytes per character */ @throw [OFInvalidEncodingException exception]; } } -- (void)insertString: (OFString *)string - atIndex: (size_t)idx +- (void)insertString: (OFString *)string atIndex: (size_t)idx { size_t newCStringLength; if (idx > _s->length) @throw [OFOutOfRangeException exception]; if (_s->isUTF8) - idx = of_string_utf8_get_position(_s->cString, idx, + idx = OFUTF8StringIndexToPosition(_s->cString, idx, _s->cStringLength); newCStringLength = _s->cStringLength + string.UTF8StringLength; - _s->hashed = false; - _s->cString = [self resizeMemory: _s->cString - size: newCStringLength + 1]; + _s->hasHash = false; + _s->cString = OFResizeMemory(_s->cString, newCStringLength + 1, 1); memmove(_s->cString + idx + string.UTF8StringLength, _s->cString + idx, _s->cStringLength - idx); memcpy(_s->cString + idx, string.UTF8String, string.UTF8StringLength); @@ -555,41 +535,41 @@ _s->isUTF8 = true; } else _s->isUTF8 = true; } -- (void)deleteCharactersInRange: (of_range_t)range +- (void)deleteCharactersInRange: (OFRange)range { size_t start = range.location; size_t end = range.location + range.length; if (range.length > SIZE_MAX - range.location || end > _s->length) @throw [OFOutOfRangeException exception]; if (_s->isUTF8) { - start = of_string_utf8_get_position(_s->cString, start, + start = OFUTF8StringIndexToPosition(_s->cString, start, _s->cStringLength); - end = of_string_utf8_get_position(_s->cString, end, + end = OFUTF8StringIndexToPosition(_s->cString, end, _s->cStringLength); } memmove(_s->cString + start, _s->cString + end, _s->cStringLength - end); - _s->hashed = false; + _s->hasHash = false; _s->length -= range.length; _s->cStringLength -= end - start; _s->cString[_s->cStringLength] = 0; @try { - _s->cString = [self resizeMemory: _s->cString - size: _s->cStringLength + 1]; + _s->cString = OFResizeMemory(_s->cString, _s->cStringLength + 1, + 1); } @catch (OFOutOfMemoryException *e) { /* We don't really care, as we only made it smaller */ } } -- (void)replaceCharactersInRange: (of_range_t)range +- (void)replaceCharactersInRange: (OFRange)range withString: (OFString *)replacement { size_t start = range.location; size_t end = range.location + range.length; size_t newCStringLength, newLength; @@ -601,19 +581,19 @@ @throw [OFOutOfRangeException exception]; newLength = _s->length - range.length + replacement.length; if (_s->isUTF8) { - start = of_string_utf8_get_position(_s->cString, start, + start = OFUTF8StringIndexToPosition(_s->cString, start, _s->cStringLength); - end = of_string_utf8_get_position(_s->cString, end, + end = OFUTF8StringIndexToPosition(_s->cString, end, _s->cStringLength); } newCStringLength = _s->cStringLength - (end - start) + replacement.UTF8StringLength; - _s->hashed = false; + _s->hasHash = false; /* * If the new string is bigger, we need to resize it first so we can * memmove() the rest of the string to the end. * @@ -620,12 +600,12 @@ * We must not resize the string if the new string is smaller, because * then we can't memmove() the rest of the string forward as the rest is * lost due to the resize! */ if (newCStringLength > _s->cStringLength) - _s->cString = [self resizeMemory: _s->cString - size: newCStringLength + 1]; + _s->cString = OFResizeMemory(_s->cString, newCStringLength + 1, + 1); memmove(_s->cString + start + replacement.UTF8StringLength, _s->cString + end, _s->cStringLength - end); memcpy(_s->cString + start, replacement.UTF8String, replacement.UTF8StringLength); @@ -634,12 +614,12 @@ /* * If the new string is smaller, we can safely resize it now as we're * done with memmove(). */ if (newCStringLength < _s->cStringLength) - _s->cString = [self resizeMemory: _s->cString - size: newCStringLength + 1]; + _s->cString = OFResizeMemory(_s->cString, newCStringLength + 1, + 1); _s->cStringLength = newCStringLength; _s->length = newLength; if ([replacement isKindOfClass: [OFUTF8String class]] || @@ -651,11 +631,11 @@ } - (void)replaceOccurrencesOfString: (OFString *)string withString: (OFString *)replacement options: (int)options - range: (of_range_t)range + range: (OFRange)range { const char *searchString = string.UTF8String; const char *replacementString = replacement.UTF8String; size_t searchLength = string.UTF8StringLength; size_t replacementLength = replacement.UTF8StringLength; @@ -668,13 +648,13 @@ if (range.length > SIZE_MAX - range.location || range.location + range.length > self.length) @throw [OFOutOfRangeException exception]; if (_s->isUTF8) { - range.location = of_string_utf8_get_position(_s->cString, + range.location = OFUTF8StringIndexToPosition(_s->cString, range.location, _s->cStringLength); - range.length = of_string_utf8_get_position( + range.length = OFUTF8StringIndexToPosition( _s->cString + range.location, range.length, _s->cStringLength - range.location); } if (string.UTF8StringLength > range.length) @@ -688,16 +668,15 @@ for (size_t i = range.location; i <= range.length - searchLength; i++) { if (memcmp(_s->cString + i, searchString, searchLength) != 0) continue; @try { - newCString = [self resizeMemory: newCString - size: newCStringLength + - i - last + - replacementLength + 1]; + newCString = OFResizeMemory(newCString, + newCStringLength + i - last + replacementLength + 1, + 1); } @catch (id e) { - [self freeMemory: newCString]; + OFFreeMemory(newCString); @throw e; } memcpy(newCString + newCStringLength, _s->cString + last, i - last); memcpy(newCString + newCStringLength + i - last, @@ -709,24 +688,23 @@ i += searchLength - 1; last = i + 1; } @try { - newCString = [self resizeMemory: newCString - size: newCStringLength + - _s->cStringLength - last + 1]; + newCString = OFResizeMemory(newCString, + newCStringLength + _s->cStringLength - last + 1, 1); } @catch (id e) { - [self freeMemory: newCString]; + OFFreeMemory(newCString); @throw e; } memcpy(newCString + newCStringLength, _s->cString + last, _s->cStringLength - last); newCStringLength += _s->cStringLength - last; newCString[newCStringLength] = 0; - [self freeMemory: _s->cString]; - _s->hashed = false; + OFFreeMemory(_s->cString); + _s->hasHash = false; _s->cString = newCString; _s->cStringLength = newCStringLength; _s->length = newLength; if ([replacement isKindOfClass: [OFUTF8String class]] || @@ -740,23 +718,23 @@ - (void)deleteLeadingWhitespaces { size_t i; for (i = 0; i < _s->cStringLength; i++) - if (!of_ascii_isspace(_s->cString[i])) + if (!OFASCIIIsSpace(_s->cString[i])) break; - _s->hashed = false; + _s->hasHash = false; _s->cStringLength -= i; _s->length -= i; memmove(_s->cString, _s->cString + i, _s->cStringLength); _s->cString[_s->cStringLength] = '\0'; @try { - _s->cString = [self resizeMemory: _s->cString - size: _s->cStringLength + 1]; + _s->cString = OFResizeMemory(_s->cString, _s->cStringLength + 1, + 1); } @catch (OFOutOfMemoryException *e) { /* We don't really care, as we only made it smaller */ } } @@ -763,15 +741,15 @@ - (void)deleteTrailingWhitespaces { size_t d; char *p; - _s->hashed = false; + _s->hasHash = false; d = 0; for (p = _s->cString + _s->cStringLength - 1; p >= _s->cString; p--) { - if (!of_ascii_isspace(*p)) + if (!OFASCIIIsSpace(*p)) break; *p = '\0'; d++; } @@ -778,12 +756,12 @@ _s->cStringLength -= d; _s->length -= d; @try { - _s->cString = [self resizeMemory: _s->cString - size: _s->cStringLength + 1]; + _s->cString = OFResizeMemory(_s->cString, _s->cStringLength + 1, + 1); } @catch (OFOutOfMemoryException *e) { /* We don't really care, as we only made it smaller */ } } @@ -790,15 +768,15 @@ - (void)deleteEnclosingWhitespaces { size_t d, i; char *p; - _s->hashed = false; + _s->hasHash = false; d = 0; for (p = _s->cString + _s->cStringLength - 1; p >= _s->cString; p--) { - if (!of_ascii_isspace(*p)) + if (!OFASCIIIsSpace(*p)) break; *p = '\0'; d++; } @@ -805,22 +783,22 @@ _s->cStringLength -= d; _s->length -= d; for (i = 0; i < _s->cStringLength; i++) - if (!of_ascii_isspace(_s->cString[i])) + if (!OFASCIIIsSpace(_s->cString[i])) break; _s->cStringLength -= i; _s->length -= i; memmove(_s->cString, _s->cString + i, _s->cStringLength); _s->cString[_s->cStringLength] = '\0'; @try { - _s->cString = [self resizeMemory: _s->cString - size: _s->cStringLength + 1]; + _s->cString = OFResizeMemory(_s->cString, _s->cStringLength + 1, + 1); } @catch (OFOutOfMemoryException *e) { /* We don't really care, as we only made it smaller */ } } Index: src/OFMutableZIPArchiveEntry.h ================================================================== --- src/OFMutableZIPArchiveEntry.h +++ src/OFMutableZIPArchiveEntry.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -52,22 +50,24 @@ /** * @brief The version which made the entry. * * The lower 8 bits are the ZIP specification version.@n * The upper 8 bits are the attribute compatibility. - * See @ref of_zip_archive_entry_attribute_compatibility. + * See @ref OFZIPArchiveEntryAttributeCompatibility. */ -@property (readwrite, nonatomic) uint16_t versionMadeBy; +@property (readwrite, nonatomic) + OFZIPArchiveEntryAttributeCompatibility versionMadeBy; /** * @brief The minimum version required to extract the file. * * The lower 8 bits are the ZIP specification version.@n * The upper 8 bits are the attribute compatibility. - * See @ref of_zip_archive_entry_attribute_compatibility. + * See @ref OFZIPArchiveEntryAttributeCompatibility. */ -@property (readwrite, nonatomic) uint16_t minVersionNeeded; +@property (readwrite, nonatomic) + OFZIPArchiveEntryAttributeCompatibility minVersionNeeded; /** * @brief The last modification date of the entry's file. * * @note Due to limitations of the ZIP format, this has only 2 second precision. @@ -76,19 +76,20 @@ /** * @brief The compression method of the entry. * * Supported values are: - * Value | Description - * --------------------------------------------------|--------------- - * OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_NONE | No compression - * OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_DEFLATE | Deflate - * OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_DEFLATE64 | Deflate64 + * Value | Description + * --------------------------------------------|--------------- + * OFZIPArchiveEntryCompressionMethodNone | No compression + * OFZIPArchiveEntryCompressionMethodDeflate | Deflate + * OFZIPArchiveEntryCompressionMethodDeflate64 | Deflate64 * * Other values may be returned, but the file cannot be extracted then. */ -@property (readwrite, nonatomic) uint16_t compressionMethod; +@property (readwrite, nonatomic) + OFZIPArchiveEntryCompressionMethod compressionMethod; /** * @brief The compressed size of the entry's file. */ @property (readwrite, nonatomic) uint64_t compressedSize; Index: src/OFMutableZIPArchiveEntry.m ================================================================== --- src/OFMutableZIPArchiveEntry.m +++ src/OFMutableZIPArchiveEntry.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -33,13 +31,11 @@ @dynamic of_localFileHeaderOffset; - (id)copy { OFMutableZIPArchiveEntry *copy = [self mutableCopy]; - [copy makeImmutable]; - return copy; } - (void)setFileName: (OFString *)fileName { @@ -87,16 +83,18 @@ [old release]; objc_autoreleasePoolPop(pool); } -- (void)setVersionMadeBy: (uint16_t)versionMadeBy +- (void)setVersionMadeBy: + (OFZIPArchiveEntryAttributeCompatibility)versionMadeBy { _versionMadeBy = versionMadeBy; } -- (void)setMinVersionNeeded: (uint16_t)minVersionNeeded +- (void)setMinVersionNeeded: + (OFZIPArchiveEntryAttributeCompatibility)minVersionNeeded { _minVersionNeeded = minVersionNeeded; } - (void)setModificationDate: (OFDate *)date @@ -110,11 +108,12 @@ ((date.localMinute & 0x3F) << 5) | ((date.second >> 1) & 0x0F); objc_autoreleasePoolPop(pool); } -- (void)setCompressionMethod: (uint16_t)compressionMethod +- (void)setCompressionMethod: + (OFZIPArchiveEntryCompressionMethod)compressionMethod { _compressionMethod = compressionMethod; } - (void)setCompressedSize: (uint64_t)compressedSize Index: src/OFMutex.h ================================================================== --- src/OFMutex.h +++ src/OFMutex.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -15,12 +13,11 @@ * file. */ #import "OFObject.h" #import "OFLocking.h" - -#import "mutex.h" +#import "OFPlainMutex.h" OF_ASSUME_NONNULL_BEGIN /** * @class OFMutex OFMutex.h ObjFW/OFMutex.h @@ -27,11 +24,11 @@ * * @brief A class for creating mutual exclusions. */ @interface OFMutex: OFObject { - of_mutex_t _mutex; + OFPlainMutex _mutex; bool _initialized; OFString *_Nullable _name; OF_RESERVE_IVARS(OFMutex, 4) } Index: src/OFMutex.m ================================================================== --- src/OFMutex.m +++ src/OFMutex.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -37,11 +35,11 @@ - (instancetype)init { self = [super init]; - if (!of_mutex_new(&_mutex)) { + if (OFPlainMutexNew(&_mutex) != 0) { Class c = self.class; [self release]; @throw [OFInitializationFailedException exceptionWithClass: c]; } @@ -51,12 +49,14 @@ } - (void)dealloc { if (_initialized) { - if (!of_mutex_free(&_mutex)) { - OF_ENSURE(errno == EBUSY); + int error = OFPlainMutexFree(&_mutex); + + if (error != 0) { + OFEnsure(error == EBUSY); @throw [OFStillLockedException exceptionWithLock: self]; } } @@ -65,33 +65,39 @@ [super dealloc]; } - (void)lock { - if (!of_mutex_lock(&_mutex)) + int error = OFPlainMutexLock(&_mutex); + + if (error != 0) @throw [OFLockFailedException exceptionWithLock: self - errNo: errno]; + errNo: error]; } - (bool)tryLock { - if (!of_mutex_trylock(&_mutex)) { - if (errno == EBUSY) + int error = OFPlainMutexTryLock(&_mutex); + + if (error != 0) { + if (error == EBUSY) return false; else @throw [OFLockFailedException exceptionWithLock: self - errNo: errno]; + errNo: error]; } return true; } - (void)unlock { - if (!of_mutex_unlock(&_mutex)) + int error = OFPlainMutexUnlock(&_mutex); + + if (error != 0) @throw [OFUnlockFailedException exceptionWithLock: self - errNo: errno]; + errNo: error]; } - (OFString *)description { if (_name == nil) Index: src/OFNonretainedObjectValue.h ================================================================== --- src/OFNonretainedObjectValue.h +++ src/OFNonretainedObjectValue.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -21,8 +19,10 @@ @interface OFNonretainedObjectValue: OFValue { id _object; } + +- (instancetype)initWithNonretainedObject: (id)object; @end OF_ASSUME_NONNULL_END Index: src/OFNonretainedObjectValue.m ================================================================== --- src/OFNonretainedObjectValue.m +++ src/OFNonretainedObjectValue.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -35,12 +33,11 @@ - (const char *)objCType { return @encode(id); } -- (void)getValue: (void *)value - size: (size_t)size +- (void)getValue: (void *)value size: (size_t)size { if (size != sizeof(_object)) @throw [OFOutOfRangeException exception]; memcpy(value, &_object, sizeof(_object)); ADDED src/OFNotification.h Index: src/OFNotification.h ================================================================== --- /dev/null +++ src/OFNotification.h @@ -0,0 +1,115 @@ +/* + * 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 + +/** @file */ + +@class OFConstantString; +@class OFDictionary OF_GENERIC(KeyType, ObjectType); + +/** + * @brief A name for a notification. + */ +typedef OFConstantString *OFNotificationName; + +/** + * @class OFNotification OFNotification.h ObjFW/OFNotification.h + * + * @brief A class to represent a notification for or from + * @ref OFNotificationCenter. + */ +OF_SUBCLASSING_RESTRICTED +@interface OFNotification: OFObject +{ + OFNotificationName _name; + id _Nullable _object; + OFDictionary *_Nullable _userInfo; +} + +/** + * @brief The name of the notification. + */ +@property (readonly, nonatomic) OFNotificationName name; + +/** + * @brief The object of the notification. This is commonly the sender of the + * notification. + */ +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) id object; + +/** + * @brief Additional information about the notification. + */ +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFDictionary *userInfo; + +/** + * @brief Creates a new notification with the specified name and object. + * + * @param name The name for the notification + * @param object The object for the notification. This is commonly the sender + * of the notification. + * @return A new, autoreleased OFNotification + */ ++ (instancetype)notificationWithName: (OFNotificationName)name + object: (nullable id)object; + +/** + * @brief Creates a new notification with the specified name, object and + * additional information. + * + * @param name The name for the notification + * @param object The object for the notification. This is commonly the sender + * of the notification. + * @param userInfo Additional information for the notification + * @return A new, autoreleased OFNotification + */ ++ (instancetype)notificationWithName: (OFNotificationName)name + object: (nullable id)object + userInfo: (nullable OFDictionary *)userInfo; + +/** + * @brief Initializes an already allocated notification with the specified + * name and object. + * + * @param name The name for the notification + * @param object The object for the notification. This is commonly the sender + * of the notification. + * @return An initialized OFNotification + */ +- (instancetype)initWithName: (OFNotificationName)name + object: (nullable id)object; + +/** + * @brief Initializes an already allocated notification with the specified + * name, object and additional information. + * + * @param name The name for the notification + * @param object The object for the notification. This is commonly the sender + * of the notification. + * @param userInfo Additional information for the notification + * @return An initialized OFNotification + */ +- (instancetype)initWithName: (OFNotificationName)name + object: (nullable id)object + userInfo: (nullable OFDictionary *)userInfo + OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFNotification.m Index: src/OFNotification.m ================================================================== --- /dev/null +++ src/OFNotification.m @@ -0,0 +1,81 @@ +/* + * 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 "OFNotification.h" +#import "OFDictionary.h" +#import "OFString.h" + +@implementation OFNotification +@synthesize name = _name, object = _object, userInfo = _userInfo; + ++ (instancetype)notificationWithName: (OFNotificationName)name + object: (id)object +{ + return [[[self alloc] initWithName: name object: object] autorelease]; +} + ++ (instancetype)notificationWithName: (OFNotificationName)name + object: (id)object + userInfo: (OFDictionary *)userInfo +{ + return [[[self alloc] initWithName: name + object: object + userInfo: userInfo] autorelease]; +} + +- (instancetype)initWithName: (OFNotificationName)name object: (id)object +{ + return [self initWithName: name object: object userInfo: nil]; +} + +- (instancetype)initWithName: (OFNotificationName)name + object: (id)object + userInfo: (OFDictionary *)userInfo +{ + self = [super init]; + + @try { + _name = [name copy]; + _object = [object retain]; + _userInfo = [userInfo copy]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} + +- (void)dealloc +{ + [_name release]; + [_object release]; + [_userInfo release]; + + [super dealloc]; +} + +- (id)copy +{ + return [self retain]; +} +@end ADDED src/OFNotificationCenter.h Index: src/OFNotificationCenter.h ================================================================== --- /dev/null +++ src/OFNotificationCenter.h @@ -0,0 +1,147 @@ +/* + * 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 "OFNotification.h" + +OF_ASSUME_NONNULL_BEGIN + +@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. + * + * @param notification The notification that has been posted + */ +typedef void (^OFNotificationCenterBlock)(OFNotification *notification); +#endif + +/** + * @class OFNotificationCenter OFNotificationCenter.h \ + * ObjFW/OFNotificationCenter.h + * + * @brief A class to send and register for notifications. + */ +@interface OFNotificationCenter: OFObject +{ +#ifdef OF_HAVE_THREADS + OFMutex *_mutex; +#endif + OFMutableDictionary *_handles; + OF_RESERVE_IVARS(OFNotificationCenter, 4) +} + +#ifdef OF_HAVE_CLASS_PROPERTIES +@property (class, readonly, nonatomic) OFNotificationCenter *defaultCenter; +#endif + +/** + * @brief Returns the default notification center. + */ ++ (OFNotificationCenter *)defaultCenter; + +/** + * @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. + * @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 + */ +- (void)addObserver: (id)observer + selector: (SEL)selector + name: (OFNotificationName)name + object: (nullable id)object; + +/** + * @brief Removes an observer. All parameters must match those used with + * @ref addObserver:selector:name:object:. + * + * @param observer The observer that was specified when adding the observer + * @param selector The selector that was specified when adding the observer + * @param name The name that was specified when adding the observer + * @param object The object that was specified when adding the observer + */ +- (void)removeObserver: (id)observer + selector: (SEL)selector + name: (OFNotificationName)name + object: (nullable id)object; + +#ifdef OF_HAVE_BLOCKS +/** + * @brief Adds an observer for the specified notification and object. + * + * To remove the observer again, use @ref removeObserver:. + * + * @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 + * @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; + +/** + * @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; +#endif + +/** + * @brief Posts the specified notification. + * + * @param notification The notification to post + */ +- (void)postNotification: (OFNotification *)notification; + +/** + * @brief Posts a notification with the specified name and object. + * + * @param name The name for the notification + * @param object The object for the notification + */ +- (void)postNotificationName: (OFNotificationName)name + object: (nullable id)object; + +/** + * @brief Posts a notification with the specified name, object and additional + * information. + * + * @param name The name for the notification + * @param object The object for the notification + * @param userInfo Additional information for the notification + */ +- (void)postNotificationName: (OFNotificationName)name + object: (nullable id)object + userInfo: (nullable OFDictionary *)userInfo; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFNotificationCenter.m Index: src/OFNotificationCenter.m ================================================================== --- /dev/null +++ src/OFNotificationCenter.m @@ -0,0 +1,397 @@ +/* + * 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 "OFNotificationCenter.h" +#import "OFArray.h" +#import "OFDictionary.h" +#ifdef OF_HAVE_THREADS +# import "OFMutex.h" +#endif +#import "OFSet.h" +#import "OFString.h" + +#import "OFInvalidArgumentException.h" + +@interface OFDefaultNotificationCenter: OFNotificationCenter +@end + +@interface OFNotificationCenterHandle: OFObject +{ +@public + OFNotificationName _name; + id _observer; + SEL _selector; + unsigned long _selectorHash; +#ifdef OF_HAVE_BLOCKS + OFNotificationCenterBlock _block; +#endif + id _object; +} + +- (instancetype)initWithName: (OFNotificationName)name + observer: (id)observer + selector: (SEL)selector + object: (id)object; +#ifdef OF_HAVE_BLOCKS +- (instancetype)initWithName: (OFNotificationName)name + object: (id)object + block: (OFNotificationCenterBlock)block; +#endif +@end + +static OFNotificationCenter *defaultCenter; + +@implementation OFNotificationCenterHandle +- (instancetype)initWithName: (OFNotificationName)name + observer: (id)observer + selector: (SEL)selector + object: (id)object +{ + self = [super init]; + + @try { + void *pool = objc_autoreleasePoolPush(); + + _name = [name copy]; + _observer = [observer retain]; + _selector = selector; + _object = [object retain]; + + _selectorHash = [[OFString stringWithUTF8String: + sel_getName(_selector)] hash]; + + objc_autoreleasePoolPop(pool); + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +#ifdef OF_HAVE_BLOCKS +- (instancetype)initWithName: (OFNotificationName)name + object: (id)object + block: (OFNotificationCenterBlock)block +{ + self = [super init]; + + @try { + _name = [name copy]; + _object = [object retain]; + _block = [block copy]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} +#endif + +- (void)dealloc +{ + [_name release]; + [_observer release]; + [_object release]; +#ifdef OF_HAVE_BLOCKS + [_block release]; +#endif + + [super dealloc]; +} + +- (bool)isEqual: (OFNotificationCenterHandle *)handle +{ + if (![handle isKindOfClass: [OFNotificationCenterHandle class]]) + return false; + + if (![handle->_name isEqual: _name]) + return false; + + if (handle->_observer != _observer && + ![handle->_observer isEqual: _observer]) + return false; + + if (handle->_selector != _selector && + !sel_isEqual(handle->_selector, _selector)) + return false; + +#ifdef OF_HAVE_BLOCKS + if (handle->_block != _block) + return false; +#endif + + if (handle->_object != _object && ![handle->_object isEqual: _object]) + return false; + + return true; +} + +- (unsigned long)hash +{ + unsigned long hash; + + OFHashInit(&hash); + + OFHashAddHash(&hash, _name.hash); + OFHashAddHash(&hash, [_observer hash]); + OFHashAddHash(&hash, _selectorHash); +#ifdef OF_HAVE_BLOCKS + if (_block != NULL) + OFHashAddHash(&hash, (unsigned long)(uintptr_t)_block); +#endif + OFHashAddHash(&hash, [_object hash]); + + OFHashFinalize(&hash); + + return hash; +} +@end + +@implementation OFNotificationCenter ++ (void)initialize +{ + if (self != [OFNotificationCenter class]) + return; + + defaultCenter = [[OFDefaultNotificationCenter alloc] init]; +} + ++ (OFNotificationCenter *)defaultCenter +{ + return defaultCenter; +} + +- (instancetype)init +{ + self = [super init]; + + @try { +#ifdef OF_HAVE_THREADS + _mutex = [[OFMutex alloc] init]; +#endif + _handles = [[OFMutableDictionary alloc] init]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ +#ifdef OF_HAVE_THREADS + [_mutex release]; +#endif + [_handles release]; + + [super dealloc]; +} + +- (void)of_addObserver: (OFNotificationCenterHandle *)handle +{ +#ifdef OF_HAVE_THREADS + [_mutex lock]; + @try { +#endif + OFMutableSet *handlesForName = + [_handles objectForKey: handle->_name]; + + if (handlesForName == nil) { + handlesForName = [OFMutableSet set]; + [_handles setObject: handlesForName + forKey: handle->_name]; + } + + [handlesForName addObject: handle]; +#ifdef OF_HAVE_THREADS + } @finally { + [_mutex unlock]; + } +#endif +} + +- (void)addObserver: (id)observer + selector: (SEL)selector + name: (OFNotificationName)name + object: (id)object +{ + void *pool = objc_autoreleasePoolPush(); + + [self of_addObserver: + [[[OFNotificationCenterHandle alloc] initWithName: name + observer: observer + selector: selector + object: object] + autorelease]]; + + objc_autoreleasePoolPop(pool); +} + +#ifdef OF_HAVE_BLOCKS +- (OFNotificationCenterHandle *) + addObserverForName: (OFNotificationName)name + object: (id)object + usingBlock: (OFNotificationCenterBlock)block +{ + void *pool = objc_autoreleasePoolPush(); + OFNotificationCenterHandle *handle = + [[[OFNotificationCenterHandle alloc] initWithName: name + object: object + block: block] + autorelease]; + + [self of_addObserver: handle]; + + [handle retain]; + + objc_autoreleasePoolPop(pool); + + return [handle autorelease]; +} +#endif + +- (void)removeObserver: (OFNotificationCenterHandle *)handle +{ + void *pool = objc_autoreleasePoolPush(); + + /* {} required to avoid -Wmisleading-indentation false positive. */ + if (![handle isKindOfClass: [OFNotificationCenterHandle class]]) { + @throw [OFInvalidArgumentException exception]; + } + +#ifdef OF_HAVE_THREADS + [_mutex lock]; + @try { +#endif + OFNotificationName name = [[handle->_name copy] autorelease]; + OFMutableSet *handlesForName = [_handles objectForKey: name]; + + [handlesForName removeObject: handle]; + + if (handlesForName.count == 0) + [_handles removeObjectForKey: name]; +#ifdef OF_HAVE_THREADS + } @finally { + [_mutex unlock]; + } +#endif + + objc_autoreleasePoolPop(pool); +} + +- (void)removeObserver: (id)observer + selector: (SEL)selector + name: (OFNotificationName)name + object: (id)object +{ + void *pool = objc_autoreleasePoolPush(); + + [self removeObserver: + [[[OFNotificationCenterHandle alloc] initWithName: name + observer: observer + selector: selector + object: object] + autorelease]]; + + objc_autoreleasePoolPop(pool); +} + +- (void)postNotification: (OFNotification *)notification +{ + void *pool = objc_autoreleasePoolPush(); + OFMutableArray *matchedHandles = [OFMutableArray array]; + +#ifdef OF_HAVE_THREADS + [_mutex lock]; + @try { +#endif + for (OFNotificationCenterHandle *handle in + [_handles objectForKey: notification.name]) + if (handle->_object == nil || + handle->_object == notification.object) + [matchedHandles addObject: handle]; +#ifdef OF_HAVE_THREADS + } @finally { + [_mutex unlock]; + } +#endif + + for (OFNotificationCenterHandle *handle in matchedHandles) { +#ifdef OF_HAVE_BLOCKS + if (handle->_block != NULL) + handle->_block(notification); + else { +#endif + void (*callback)(id, SEL, OFNotification *) = + (void (*)(id, SEL, OFNotification *)) + [handle->_observer methodForSelector: + handle->_selector]; + + callback(handle->_observer, handle->_selector, + notification); +#ifdef OF_HAVE_BLOCKS + } +#endif + } + + objc_autoreleasePoolPop(pool); +} + +- (void)postNotificationName: (OFNotificationName)name + object: (nullable id)object +{ + [self postNotificationName: name object: object userInfo: nil]; +} + +- (void)postNotificationName: (OFNotificationName)name + object: (nullable id)object + userInfo: (nullable OFDictionary *)userInfo +{ + void *pool = objc_autoreleasePoolPush(); + + [self postNotification: + [OFNotification notificationWithName: name + object: object + userInfo: userInfo]]; + + objc_autoreleasePoolPop(pool); +} +@end + +@implementation OFDefaultNotificationCenter +- (instancetype)autorelease +{ + return self; +} + +- (instancetype)retain +{ + return self; +} + +- (void)release +{ +} + +- (unsigned int)retainCount +{ + return OFMaxRetainCount; +} +@end Index: src/OFNull.h ================================================================== --- src/OFNull.h +++ src/OFNull.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -14,11 +12,10 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #import "OFObject.h" -#import "OFASN1DERRepresentation.h" #import "OFJSONRepresentation.h" #import "OFMessagePackRepresentation.h" #import "OFSerialization.h" OF_ASSUME_NONNULL_BEGIN @@ -28,15 +25,15 @@ * * @brief A class for representing null values in collections. */ OF_SUBCLASSING_RESTRICTED @interface OFNull: OFObject + OFMessagePackRepresentation> /** * @brief Returns an OFNull singleton. * * @return An OFNull singleton */ + (OFNull *)null; @end OF_ASSUME_NONNULL_END Index: src/OFNull.m ================================================================== --- src/OFNull.m +++ src/OFNull.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -23,12 +21,13 @@ #import "OFData.h" #import "OFInvalidArgumentException.h" @interface OFNull () -- (OFString *)of_JSONRepresentationWithOptions: (int)options - depth: (size_t)depth; +- (OFString *) + of_JSONRepresentationWithOptions: (OFJSONRepresentationOptions)options + depth: (size_t)depth; @end static OFNull *null = nil; @implementation OFNull @@ -49,11 +48,11 @@ [self release]; pool = objc_autoreleasePoolPush(); if (![element.name isEqual: self.className] || - ![element.namespace isEqual: OF_SERIALIZATION_NS]) + ![element.namespace isEqual: OFSerializationNS]) @throw [OFInvalidArgumentException exception]; objc_autoreleasePoolPop(pool); return [OFNull null]; @@ -73,11 +72,11 @@ { void *pool = objc_autoreleasePoolPush(); OFXMLElement *element; element = [OFXMLElement elementWithName: self.className - namespace: OF_SERIALIZATION_NS]; + namespace: OFSerializationNS]; [element retain]; objc_autoreleasePoolPop(pool); @@ -84,40 +83,30 @@ return [element autorelease]; } - (OFString *)JSONRepresentation { - return [self of_JSONRepresentationWithOptions: 0 - depth: 0]; + return [self of_JSONRepresentationWithOptions: 0 depth: 0]; } -- (OFString *)JSONRepresentationWithOptions: (int)options +- (OFString *)JSONRepresentationWithOptions: + (OFJSONRepresentationOptions)options { - return [self of_JSONRepresentationWithOptions: options - depth: 0]; + return [self of_JSONRepresentationWithOptions: options depth: 0]; } -- (OFString *)of_JSONRepresentationWithOptions: (int)options +- (OFString *) + of_JSONRepresentationWithOptions: (OFJSONRepresentationOptions)options depth: (size_t)depth { return @"null"; } - (OFData *)messagePackRepresentation { uint8_t type = 0xC0; - - return [OFData dataWithItems: &type - count: 1]; -} - -- (OFData *)ASN1DERRepresentation -{ - const unsigned char bytes[] = { OF_ASN1_TAG_NUMBER_NULL, 0 }; - - return [OFData dataWithItems: bytes - count: sizeof(bytes)]; + return [OFData dataWithItems: &type count: 1]; } - (instancetype)autorelease { return self; @@ -132,13 +121,13 @@ { } - (unsigned int)retainCount { - return OF_RETAIN_COUNT_MAX; + return OFMaxRetainCount; } - (void)dealloc { OF_DEALLOC_UNSUPPORTED } @end Index: src/OFNumber.h ================================================================== --- src/OFNumber.h +++ src/OFNumber.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -46,11 +44,11 @@ OF_SUBCLASSING_RESTRICTED #endif @interface OFNumber: OFValue { - union of_number_value { + union { double float_; long long signed_; unsigned long long unsigned_; } _value; const char *_typeEncoding; @@ -124,20 +122,18 @@ /** * @brief The OFNumber as a string. */ @property (readonly, nonatomic) OFString *stringValue; -#ifdef OF_HAVE_UNAVAILABLE + (instancetype)valueWithBytes: (const void *)bytes objCType: (const char *)objCType OF_UNAVAILABLE; + (instancetype)valueWithPointer: (const void *)pointer OF_UNAVAILABLE; + (instancetype)valueWithNonretainedObject: (id)object OF_UNAVAILABLE; -+ (instancetype)valueWithRange: (of_range_t)range OF_UNAVAILABLE; -+ (instancetype)valueWithPoint: (of_point_t)point OF_UNAVAILABLE; -+ (instancetype)valueWithDimension: (of_dimension_t)dimension OF_UNAVAILABLE; -+ (instancetype)valueWithRectangle: (of_rectangle_t)rectangle OF_UNAVAILABLE; -#endif ++ (instancetype)valueWithRange: (OFRange)range OF_UNAVAILABLE; ++ (instancetype)valueWithPoint: (OFPoint)point OF_UNAVAILABLE; ++ (instancetype)valueWithSize: (OFSize)size OF_UNAVAILABLE; ++ (instancetype)valueWithRect: (OFRect)rect OF_UNAVAILABLE; /** * @brief Creates a new OFNumber with the specified `bool`. * * @param value The `bool` value which the OFNumber should contain @@ -240,20 +236,12 @@ * @return A new autoreleased OFNumber */ + (instancetype)numberWithDouble: (double)value; - (instancetype)init OF_UNAVAILABLE; -#ifdef OF_HAVE_UNAVAILABLE - (instancetype)initWithBytes: (const void *)bytes objCType: (const char *)objCType OF_UNAVAILABLE; -- (instancetype)initWithPointer: (const void *)pointer OF_UNAVAILABLE; -- (instancetype)initWithNonretainedObject: (id)object OF_UNAVAILABLE; -- (instancetype)initWithRange: (of_range_t)range OF_UNAVAILABLE; -- (instancetype)initWithPoint: (of_point_t)point OF_UNAVAILABLE; -- (instancetype)initWithDimension: (of_dimension_t)dimension OF_UNAVAILABLE; -- (instancetype)initWithRectangle: (of_rectangle_t)rectangle OF_UNAVAILABLE; -#endif /** * @brief Initializes an already allocated OFNumber with the specified `bool`. * * @param value The `bool` value which the OFNumber should contain @@ -361,13 +349,21 @@ * * @param value The `double` value which the OFNumber should contain * @return An initialized OFNumber */ - (instancetype)initWithDouble: (double)value; + +/** + * @brief Compares the number to another number. + * + * @param number The number to compare the number to + * @return The result of the comparison + */ +- (OFComparisonResult)compare: (OFNumber *)number; @end OF_ASSUME_NONNULL_END #if !defined(NSINTEGER_DEFINED) && !__has_feature(modules) /* Required for number literals to work */ @compatibility_alias NSNumber OFNumber; #endif Index: src/OFNumber.m ================================================================== --- src/OFNumber.m +++ src/OFNumber.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -31,35 +29,36 @@ #import "OFInvalidFormatException.h" #import "OFOutOfRangeException.h" @interface OFNumber () + (instancetype)of_alloc; -- (OFString *)of_JSONRepresentationWithOptions: (int)options - depth: (size_t)depth; +- (OFString *) + of_JSONRepresentationWithOptions: (OFJSONRepresentationOptions)options + depth: (size_t)depth; @end @interface OFNumberPlaceholder: OFNumber @end @interface OFNumberSingleton: OFNumber @end #ifdef OF_OBJFW_RUNTIME -enum { - TAG_CHAR, - TAG_SHORT, - TAG_INT, - TAG_LONG, - TAG_LONG_LONG, - TAG_UNSIGNED_CHAR, - TAG_UNSIGNED_SHORT, - TAG_UNSIGNED_INT, - TAG_UNSIGNED_LONG, - TAG_UNSIGNED_LONG_LONG, +enum Tag { + tagChar, + tagShort, + tagInt, + tagLong, + tagLongLong, + tagUnsignedChar, + tagUnsignedShort, + tagUnsignedInt, + tagUnsignedLong, + tagUnsignedLongLong, }; -# define TAG_BITS 4 -# define TAG_MASK 0xF +static const uint_fast8_t tagBits = 4; +static const uintptr_t tagMask = 0xF; @interface OFTaggedPointerNumber: OFNumberSingleton @end #endif @@ -150,16 +149,16 @@ @implementation OFNumberPlaceholder - (instancetype)initWithBool: (bool)value { if (value) { - static of_once_t once = OF_ONCE_INIT; - of_once(&once, trueNumberInit); + static OFOnceControl onceControl = OFOnceControlInitValue; + OFOnce(&onceControl, trueNumberInit); return (id)trueNumber; } else { - static of_once_t once = OF_ONCE_INIT; - of_once(&once, falseNumberInit); + static OFOnceControl onceControl = OFOnceControlInitValue; + OFOnce(&onceControl, falseNumberInit); return (id)falseNumber; } } #ifdef __clang__ @@ -167,17 +166,17 @@ # pragma clang diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif - (instancetype)initWithChar: (signed char)value { if (value == 0) { - static of_once_t once = OF_ONCE_INIT; - of_once(&once, charZeroNumberInit); + static OFOnceControl onceControl = OFOnceControlInitValue; + OFOnce(&onceControl, charZeroNumberInit); return (id)charZeroNumber; #ifdef OF_OBJFW_RUNTIME - } else if ((unsigned char)value <= (UINTPTR_MAX >> TAG_BITS)) { + } else if ((unsigned char)value <= (UINTPTR_MAX >> tagBits)) { id ret = objc_createTaggedPointer(numberTag, - ((uintptr_t)(unsigned char)value << TAG_BITS) | TAG_CHAR); + ((uintptr_t)(unsigned char)value << tagBits) | tagChar); if (ret != nil) return ret; #endif } @@ -186,17 +185,17 @@ } - (instancetype)initWithShort: (short)value { if (value == 0) { - static of_once_t once = OF_ONCE_INIT; - of_once(&once, shortZeroNumberInit); + static OFOnceControl onceControl = OFOnceControlInitValue; + OFOnce(&onceControl, shortZeroNumberInit); return (id)shortZeroNumber; #ifdef OF_OBJFW_RUNTIME - } else if ((unsigned short)value <= (UINTPTR_MAX >> TAG_BITS)) { + } else if ((unsigned short)value <= (UINTPTR_MAX >> tagBits)) { id ret = objc_createTaggedPointer(numberTag, - ((uintptr_t)(unsigned short)value << TAG_BITS) | TAG_SHORT); + ((uintptr_t)(unsigned short)value << tagBits) | tagShort); if (ret != nil) return ret; #endif } @@ -205,17 +204,17 @@ } - (instancetype)initWithInt: (int)value { if (value == 0) { - static of_once_t once = OF_ONCE_INIT; - of_once(&once, intZeroNumberInit); + static OFOnceControl onceControl = OFOnceControlInitValue; + OFOnce(&onceControl, intZeroNumberInit); return (id)intZeroNumber; #ifdef OF_OBJFW_RUNTIME - } else if ((unsigned int)value <= (UINTPTR_MAX >> TAG_BITS)) { + } else if ((unsigned int)value <= (UINTPTR_MAX >> tagBits)) { id ret = objc_createTaggedPointer(numberTag, - ((uintptr_t)(unsigned int)value << TAG_BITS) | TAG_INT); + ((uintptr_t)(unsigned int)value << tagBits) | tagInt); if (ret != nil) return ret; #endif } @@ -224,17 +223,17 @@ } - (instancetype)initWithLong: (long)value { if (value == 0) { - static of_once_t once = OF_ONCE_INIT; - of_once(&once, longZeroNumberInit); + static OFOnceControl onceControl = OFOnceControlInitValue; + OFOnce(&onceControl, longZeroNumberInit); return (id)longZeroNumber; #ifdef OF_OBJFW_RUNTIME - } else if ((unsigned long)value <= (UINTPTR_MAX >> TAG_BITS)) { + } else if ((unsigned long)value <= (UINTPTR_MAX >> tagBits)) { id ret = objc_createTaggedPointer(numberTag, - ((uintptr_t)(unsigned long)value << TAG_BITS) | TAG_LONG); + ((uintptr_t)(unsigned long)value << tagBits) | tagLong); if (ret != nil) return ret; #endif } @@ -243,18 +242,18 @@ } - (instancetype)initWithLongLong: (long long)value { if (value == 0) { - static of_once_t once = OF_ONCE_INIT; - of_once(&once, longLongZeroNumberInit); + static OFOnceControl onceControl = OFOnceControlInitValue; + OFOnce(&onceControl, longLongZeroNumberInit); return (id)longLongZeroNumber; #ifdef OF_OBJFW_RUNTIME - } else if ((unsigned long long)value <= (UINTPTR_MAX >> TAG_BITS)) { + } else if ((unsigned long long)value <= (UINTPTR_MAX >> tagBits)) { id ret = objc_createTaggedPointer(numberTag, - ((uintptr_t)(unsigned long long)value << TAG_BITS) | - TAG_LONG_LONG); + ((uintptr_t)(unsigned long long)value << tagBits) | + tagLongLong); if (ret != nil) return ret; #endif } @@ -263,17 +262,17 @@ } - (instancetype)initWithUnsignedChar: (unsigned char)value { if (value == 0) { - static of_once_t once = OF_ONCE_INIT; - of_once(&once, unsignedCharZeroNumberInit); + static OFOnceControl onceControl = OFOnceControlInitValue; + OFOnce(&onceControl, unsignedCharZeroNumberInit); return (id)unsignedCharZeroNumber; #ifdef OF_OBJFW_RUNTIME - } else if (value <= (UINTPTR_MAX >> TAG_BITS)) { + } else if (value <= (UINTPTR_MAX >> tagBits)) { id ret = objc_createTaggedPointer(numberTag, - ((uintptr_t)value << TAG_BITS) | TAG_UNSIGNED_CHAR); + ((uintptr_t)value << tagBits) | tagUnsignedChar); if (ret != nil) return ret; #endif } @@ -282,17 +281,17 @@ } - (instancetype)initWithUnsignedShort: (unsigned short)value { if (value == 0) { - static of_once_t once = OF_ONCE_INIT; - of_once(&once, unsignedShortZeroNumberInit); + static OFOnceControl onceControl = OFOnceControlInitValue; + OFOnce(&onceControl, unsignedShortZeroNumberInit); return (id)unsignedShortZeroNumber; #ifdef OF_OBJFW_RUNTIME - } else if (value <= (UINTPTR_MAX >> TAG_BITS)) { + } else if (value <= (UINTPTR_MAX >> tagBits)) { id ret = objc_createTaggedPointer(numberTag, - ((uintptr_t)value << TAG_BITS) | TAG_UNSIGNED_SHORT); + ((uintptr_t)value << tagBits) | tagUnsignedShort); if (ret != nil) return ret; #endif } @@ -301,17 +300,17 @@ } - (instancetype)initWithUnsignedInt: (unsigned int)value { if (value == 0) { - static of_once_t once = OF_ONCE_INIT; - of_once(&once, unsignedIntZeroNumberInit); + static OFOnceControl onceControl = OFOnceControlInitValue; + OFOnce(&onceControl, unsignedIntZeroNumberInit); return (id)unsignedIntZeroNumber; #ifdef OF_OBJFW_RUNTIME - } else if (value <= (UINTPTR_MAX >> TAG_BITS)) { + } else if (value <= (UINTPTR_MAX >> tagBits)) { id ret = objc_createTaggedPointer(numberTag, - ((uintptr_t)value << TAG_BITS) | TAG_UNSIGNED_INT); + ((uintptr_t)value << tagBits) | tagUnsignedInt); if (ret != nil) return ret; #endif } @@ -320,17 +319,17 @@ } - (instancetype)initWithUnsignedLong: (unsigned long)value { if (value == 0) { - static of_once_t once = OF_ONCE_INIT; - of_once(&once, unsignedLongZeroNumberInit); + static OFOnceControl onceControl = OFOnceControlInitValue; + OFOnce(&onceControl, unsignedLongZeroNumberInit); return (id)unsignedLongZeroNumber; #ifdef OF_OBJFW_RUNTIME - } else if (value <= (UINTPTR_MAX >> TAG_BITS)) { + } else if (value <= (UINTPTR_MAX >> tagBits)) { id ret = objc_createTaggedPointer(numberTag, - ((uintptr_t)value << TAG_BITS) | TAG_UNSIGNED_LONG); + ((uintptr_t)value << tagBits) | tagUnsignedLong); if (ret != nil) return ret; #endif } @@ -339,17 +338,17 @@ } - (instancetype)initWithUnsignedLongLong: (unsigned long long)value { if (value == 0) { - static of_once_t once = OF_ONCE_INIT; - of_once(&once, unsignedLongLongZeroNumberInit); + static OFOnceControl onceControl = OFOnceControlInitValue; + OFOnce(&onceControl, unsignedLongLongZeroNumberInit); return (id)unsignedLongLongZeroNumber; #ifdef OF_OBJFW_RUNTIME - } else if (value <= (UINTPTR_MAX >> TAG_BITS)) { + } else if (value <= (UINTPTR_MAX >> tagBits)) { id ret = objc_createTaggedPointer(numberTag, - ((uintptr_t)value << TAG_BITS) | TAG_UNSIGNED_LONG_LONG); + ((uintptr_t)value << tagBits) | tagUnsignedLongLong); if (ret != nil) return ret; #endif } @@ -358,23 +357,23 @@ } - (instancetype)initWithFloat: (float)value { if (value == 0) { - static of_once_t once = OF_ONCE_INIT; - of_once(&once, floatZeroNumberInit); + static OFOnceControl onceControl = OFOnceControlInitValue; + OFOnce(&onceControl, floatZeroNumberInit); return (id)floatZeroNumber; } return (id)[[OFNumber of_alloc] initWithFloat: value]; } - (instancetype)initWithDouble: (double)value { if (value == 0) { - static of_once_t once = OF_ONCE_INIT; - of_once(&once, doubleZeroNumberInit); + static OFOnceControl onceControl = OFOnceControlInitValue; + OFOnce(&onceControl, doubleZeroNumberInit); return (id)doubleZeroNumber; } return (id)[[OFNumber of_alloc] initWithDouble: value]; } @@ -403,72 +402,72 @@ { } - (unsigned int)retainCount { - return OF_RETAIN_COUNT_MAX; + return OFMaxRetainCount; } @end #ifdef OF_OBJFW_RUNTIME @implementation OFTaggedPointerNumber - (const char *)objCType { uintptr_t value = object_getTaggedPointerValue(self); - switch (value & TAG_MASK) { - case TAG_CHAR: + switch (value & tagMask) { + case tagChar: return @encode(signed char); - case TAG_SHORT: + case tagShort: return @encode(short); - case TAG_INT: + case tagInt: return @encode(int); - case TAG_LONG: + case tagLong: return @encode(long); - case TAG_LONG_LONG: + case tagLongLong: return @encode(long long); - case TAG_UNSIGNED_CHAR: + case tagUnsignedChar: return @encode(unsigned char); - case TAG_UNSIGNED_SHORT: + case tagUnsignedShort: return @encode(unsigned short); - case TAG_UNSIGNED_INT: + case tagUnsignedInt: return @encode(unsigned int); - case TAG_UNSIGNED_LONG: + case tagUnsignedLong: return @encode(unsigned long); - case TAG_UNSIGNED_LONG_LONG: + case tagUnsignedLongLong: return @encode(unsigned long long); default: @throw [OFInvalidArgumentException exception]; } } -# define RETURN_VALUE \ - uintptr_t value = object_getTaggedPointerValue(self); \ - \ - switch (value & TAG_MASK) { \ - case TAG_CHAR: \ - return (signed char)(unsigned char)(value >> TAG_BITS); \ - case TAG_SHORT: \ - return (short)(unsigned short)(value >> TAG_BITS); \ - case TAG_INT: \ - return (int)(unsigned int)(value >> TAG_BITS); \ - case TAG_LONG: \ - return (long)(unsigned long)(value >> TAG_BITS); \ - case TAG_LONG_LONG: \ - return (long long)(unsigned long long)(value >> TAG_BITS); \ - case TAG_UNSIGNED_CHAR: \ - return (unsigned char)(value >> TAG_BITS); \ - case TAG_UNSIGNED_SHORT: \ - return (unsigned short)(value >> TAG_BITS); \ - case TAG_UNSIGNED_INT: \ - return (unsigned int)(value >> TAG_BITS); \ - case TAG_UNSIGNED_LONG: \ - return (unsigned long)(value >> TAG_BITS); \ - case TAG_UNSIGNED_LONG_LONG: \ - return (unsigned long long)(value >> TAG_BITS); \ - default: \ - @throw [OFInvalidArgumentException exception]; \ +# define RETURN_VALUE \ + uintptr_t value = object_getTaggedPointerValue(self); \ + \ + switch (value & tagMask) { \ + case tagChar: \ + return (signed char)(unsigned char)(value >> tagBits); \ + case tagShort: \ + return (short)(unsigned short)(value >> tagBits); \ + case tagInt: \ + return (int)(unsigned int)(value >> tagBits); \ + case tagLong: \ + return (long)(unsigned long)(value >> tagBits); \ + case tagLongLong: \ + return (long long)(unsigned long long)(value >> tagBits); \ + case tagUnsignedChar: \ + return (unsigned char)(value >> tagBits); \ + case tagUnsignedShort: \ + return (unsigned short)(value >> tagBits); \ + case tagUnsignedInt: \ + return (unsigned int)(value >> tagBits); \ + case tagUnsignedLong: \ + return (unsigned long)(value >> tagBits); \ + case tagUnsignedLongLong: \ + return (unsigned long long)(value >> tagBits); \ + default: \ + @throw [OFInvalidArgumentException exception]; \ } - (long long)longLongValue { RETURN_VALUE } @@ -510,10 +509,46 @@ if (self == [OFNumber class]) return (id)&placeholder; return [super alloc]; } + ++ (instancetype)valueWithBytes: (const void *)bytes + objCType: (const char *)objCType +{ + OF_UNRECOGNIZED_SELECTOR +} + ++ (instancetype)valueWithPointer: (const void *)pointer +{ + OF_UNRECOGNIZED_SELECTOR +} + ++ (instancetype)valueWithNonretainedObject: (id)object +{ + OF_UNRECOGNIZED_SELECTOR +} + ++ (instancetype)valueWithRange: (OFRange)range +{ + OF_UNRECOGNIZED_SELECTOR +} + ++ (instancetype)valueWithPoint: (OFPoint)point +{ + OF_UNRECOGNIZED_SELECTOR +} + ++ (instancetype)valueWithSize: (OFSize)size +{ + OF_UNRECOGNIZED_SELECTOR +} + ++ (instancetype)valueWithRect: (OFRect)rect +{ + OF_UNRECOGNIZED_SELECTOR +} + (instancetype)numberWithBool: (bool)value { return [[[self alloc] initWithBool: value] autorelease]; } @@ -578,10 +613,16 @@ return [[[self alloc] initWithDouble: value] autorelease]; } - (instancetype)init { + OF_INVALID_INIT_METHOD +} + +- (instancetype)initWithBytes: (const void *)bytes + objCType: (const char *)objCType +{ OF_INVALID_INIT_METHOD } - (instancetype)initWithBool: (bool)value { @@ -750,11 +791,11 @@ @try { void *pool = objc_autoreleasePoolPush(); OFString *typeString; if (![element.name isEqual: @"OFNumber"] || - ![element.namespace isEqual: OF_SERIALIZATION_NS]) + ![element.namespace isEqual: OFSerializationNS]) @throw [OFInvalidArgumentException exception]; typeString = [element attributeForName: @"type"].stringValue; if ([typeString isEqual: @"bool"]) { @@ -770,12 +811,12 @@ [element unsignedLongLongValueWithBase: 16]; if (value > UINT64_MAX) @throw [OFOutOfRangeException exception]; - self = [self initWithDouble: OF_BSWAP_DOUBLE_IF_LE( - OF_INT_TO_DOUBLE_RAW(OF_BSWAP64_IF_LE(value)))]; + 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]; @@ -794,12 +835,11 @@ - (const char *)objCType { return _typeEncoding; } -- (void)getValue: (void *)value - size: (size_t)size +- (void)getValue: (void *)value size: (size_t)size { switch (*self.objCType) { #define CASE(enc, type, property) \ case enc: { \ type tmp = (type)self.property; \ @@ -943,79 +983,75 @@ return (number.longLongValue == self.longLongValue); return (number.unsignedLongLongValue == self.unsignedLongLongValue); } -- (of_comparison_result_t)compare: (id )object -{ - OFNumber *number; - - if (![(id)object isKindOfClass: [OFNumber class]]) - @throw [OFInvalidArgumentException exception]; - - number = (OFNumber *)object; +- (OFComparisonResult)compare: (OFNumber *)number +{ + if (![number isKindOfClass: [OFNumber class]]) + @throw [OFInvalidArgumentException exception]; if (isFloat(self) || isFloat(number)) { double double1 = self.doubleValue; double double2 = number.doubleValue; if (double1 > double2) - return OF_ORDERED_DESCENDING; + return OFOrderedDescending; if (double1 < double2) - return OF_ORDERED_ASCENDING; + return OFOrderedAscending; - return OF_ORDERED_SAME; + return OFOrderedSame; } else if (isSigned(self) || isSigned(number)) { long long int1 = self.longLongValue; long long int2 = number.longLongValue; if (int1 > int2) - return OF_ORDERED_DESCENDING; + return OFOrderedDescending; if (int1 < int2) - return OF_ORDERED_ASCENDING; + return OFOrderedAscending; - return OF_ORDERED_SAME; + return OFOrderedSame; } else { unsigned long long uint1 = self.unsignedLongLongValue; unsigned long long uint2 = number.unsignedLongLongValue; if (uint1 > uint2) - return OF_ORDERED_DESCENDING; + return OFOrderedDescending; if (uint1 < uint2) - return OF_ORDERED_ASCENDING; + return OFOrderedAscending; - return OF_ORDERED_SAME; + return OFOrderedSame; } } - (unsigned long)hash { - uint32_t hash; + unsigned long hash; - OF_HASH_INIT(hash); + OFHashInit(&hash); if (isFloat(self)) { double d; if (isnan(self.doubleValue)) return 0; - d = OF_BSWAP_DOUBLE_IF_BE(self.doubleValue); + d = OFToLittleEndianDouble(self.doubleValue); for (uint_fast8_t i = 0; i < sizeof(double); i++) - OF_HASH_ADD(hash, ((char *)&d)[i]); + OFHashAdd(&hash, ((char *)&d)[i]); } else if (isSigned(self) || isUnsigned(self)) { unsigned long long value = self.unsignedLongLongValue; while (value != 0) { - OF_HASH_ADD(hash, value & 0xFF); + OFHashAdd(&hash, value & 0xFF); value >>= 8; } } else @throw [OFInvalidFormatException exception]; - OF_HASH_FINALIZE(hash); + OFHashFinalize(&hash); return hash; } - (id)copy @@ -1047,26 +1083,23 @@ { void *pool = objc_autoreleasePoolPush(); OFXMLElement *element; element = [OFXMLElement elementWithName: @"OFNumber" - namespace: OF_SERIALIZATION_NS + namespace: OFSerializationNS stringValue: self.description]; if (*self.objCType == 'B') - [element addAttributeWithName: @"type" - stringValue: @"bool"]; + [element addAttributeWithName: @"type" stringValue: @"bool"]; else if (isFloat(self)) { - [element addAttributeWithName: @"type" - stringValue: @"float"]; + [element addAttributeWithName: @"type" stringValue: @"float"]; element.stringValue = [OFString stringWithFormat: @"%016" PRIx64, - OF_BSWAP64_IF_LE(OF_DOUBLE_TO_INT_RAW(OF_BSWAP_DOUBLE_IF_LE( + OFFromBigEndian64(OFDoubleToRawUInt64(OFToBigEndianDouble( self.doubleValue)))]; } else if (isSigned(self)) - [element addAttributeWithName: @"type" - stringValue: @"signed"]; + [element addAttributeWithName: @"type" stringValue: @"signed"]; else if (isUnsigned(self)) [element addAttributeWithName: @"type" stringValue: @"unsigned"]; else @throw [OFInvalidFormatException exception]; @@ -1078,31 +1111,31 @@ return [element autorelease]; } - (OFString *)JSONRepresentation { - return [self of_JSONRepresentationWithOptions: 0 - depth: 0]; + return [self of_JSONRepresentationWithOptions: 0 depth: 0]; } -- (OFString *)JSONRepresentationWithOptions: (int)options +- (OFString *)JSONRepresentationWithOptions: + (OFJSONRepresentationOptions)options { - return [self of_JSONRepresentationWithOptions: options - depth: 0]; + return [self of_JSONRepresentationWithOptions: options depth: 0]; } -- (OFString *)of_JSONRepresentationWithOptions: (int)options - depth: (size_t)depth +- (OFString *) + of_JSONRepresentationWithOptions: (OFJSONRepresentationOptions)options + depth: (size_t)depth { double doubleValue; if (*self.objCType == 'B') return (self.boolValue ? @"true" : @"false"); doubleValue = self.doubleValue; if (isinf(doubleValue)) { - if (options & OF_JSON_REPRESENTATION_JSON5) { + if (options & OFJSONRepresentationOptionJSON5) { if (doubleValue > 0) return @"Infinity"; else return @"-Infinity"; } else @@ -1117,129 +1150,96 @@ OFMutableData *data; const char *typeEncoding = self.objCType; if (*typeEncoding == 'B') { uint8_t type = (self.boolValue ? 0xC3 : 0xC2); - - data = [OFMutableData dataWithItems: &type - count: 1]; + data = [OFMutableData dataWithItems: &type count: 1]; } else if (*typeEncoding == 'f') { uint8_t type = 0xCA; - float tmp = OF_BSWAP_FLOAT_IF_LE(self.floatValue); + float tmp = OFToBigEndianFloat(self.floatValue); - data = [OFMutableData dataWithItemSize: 1 - capacity: 5]; - + data = [OFMutableData dataWithCapacity: 5]; [data addItem: &type]; - [data addItems: &tmp - count: sizeof(tmp)]; + [data addItems: &tmp count: sizeof(tmp)]; } else if (*typeEncoding == 'd') { uint8_t type = 0xCB; - double tmp = OF_BSWAP_DOUBLE_IF_LE(self.doubleValue); + double tmp = OFToBigEndianDouble(self.doubleValue); - data = [OFMutableData dataWithItemSize: 1 - capacity: 9]; - + data = [OFMutableData dataWithCapacity: 9]; [data addItem: &type]; - [data addItems: &tmp - count: sizeof(tmp)]; + [data addItems: &tmp count: sizeof(tmp)]; } else if (isSigned(self)) { long long value = self.longLongValue; if (value >= -32 && value < 0) { uint8_t tmp = 0xE0 | ((uint8_t)(value - 32) & 0x1F); - data = [OFMutableData dataWithItems: &tmp - count: 1]; + data = [OFMutableData dataWithItems: &tmp count: 1]; } else if (value >= INT8_MIN && value <= INT8_MAX) { uint8_t type = 0xD0; int8_t tmp = (int8_t)value; - data = [OFMutableData dataWithItemSize: 1 - capacity: 2]; - + data = [OFMutableData dataWithCapacity: 2]; [data addItem: &type]; [data addItem: &tmp]; } else if (value >= INT16_MIN && value <= INT16_MAX) { uint8_t type = 0xD1; - int16_t tmp = OF_BSWAP16_IF_LE((int16_t)value); - - data = [OFMutableData dataWithItemSize: 1 - capacity: 3]; - - [data addItem: &type]; - [data addItems: &tmp - count: sizeof(tmp)]; + int16_t tmp = OFToBigEndian16((int16_t)value); + + data = [OFMutableData dataWithCapacity: 3]; + [data addItem: &type]; + [data addItems: &tmp count: sizeof(tmp)]; } else if (value >= INT32_MIN && value <= INT32_MAX) { uint8_t type = 0xD2; - int32_t tmp = OF_BSWAP32_IF_LE((int32_t)value); + int32_t tmp = OFToBigEndian32((int32_t)value); - data = [OFMutableData dataWithItemSize: 1 - capacity: 5]; - + data = [OFMutableData dataWithCapacity: 5]; [data addItem: &type]; - [data addItems: &tmp - count: sizeof(tmp)]; + [data addItems: &tmp count: sizeof(tmp)]; } else if (value >= INT64_MIN && value <= INT64_MAX) { uint8_t type = 0xD3; - int64_t tmp = OF_BSWAP64_IF_LE((int64_t)value); + int64_t tmp = OFToBigEndian64((int64_t)value); - data = [OFMutableData dataWithItemSize: 1 - capacity: 9]; - + data = [OFMutableData dataWithCapacity: 9]; [data addItem: &type]; - [data addItems: &tmp - count: sizeof(tmp)]; + [data addItems: &tmp count: sizeof(tmp)]; } else @throw [OFOutOfRangeException exception]; } else if (isUnsigned(self)) { unsigned long long value = self.unsignedLongLongValue; if (value <= 127) { uint8_t tmp = ((uint8_t)value & 0x7F); - - data = [OFMutableData dataWithItems: &tmp - count: 1]; + data = [OFMutableData dataWithItems: &tmp count: 1]; } else if (value <= UINT8_MAX) { uint8_t type = 0xCC; uint8_t tmp = (uint8_t)value; - data = [OFMutableData dataWithItemSize: 1 - capacity: 2]; - + data = [OFMutableData dataWithCapacity: 2]; [data addItem: &type]; [data addItem: &tmp]; } else if (value <= UINT16_MAX) { uint8_t type = 0xCD; - uint16_t tmp = OF_BSWAP16_IF_LE((uint16_t)value); - - data = [OFMutableData dataWithItemSize: 1 - capacity: 3]; - - [data addItem: &type]; - [data addItems: &tmp - count: sizeof(tmp)]; + uint16_t tmp = OFToBigEndian16((uint16_t)value); + + data = [OFMutableData dataWithCapacity: 3]; + [data addItem: &type]; + [data addItems: &tmp count: sizeof(tmp)]; } else if (value <= UINT32_MAX) { uint8_t type = 0xCE; - uint32_t tmp = OF_BSWAP32_IF_LE((uint32_t)value); - - data = [OFMutableData dataWithItemSize: 1 - capacity: 5]; - - [data addItem: &type]; - [data addItems: &tmp - count: sizeof(tmp)]; + uint32_t tmp = OFToBigEndian32((uint32_t)value); + + data = [OFMutableData dataWithCapacity: 5]; + [data addItem: &type]; + [data addItems: &tmp count: sizeof(tmp)]; } else if (value <= UINT64_MAX) { uint8_t type = 0xCF; - uint64_t tmp = OF_BSWAP64_IF_LE((uint64_t)value); - - data = [OFMutableData dataWithItemSize: 1 - capacity: 9]; - - [data addItem: &type]; - [data addItems: &tmp - count: sizeof(tmp)]; + uint64_t tmp = OFToBigEndian64((uint64_t)value); + + data = [OFMutableData dataWithCapacity: 9]; + [data addItem: &type]; + [data addItems: &tmp count: sizeof(tmp)]; } else @throw [OFOutOfRangeException exception]; } else @throw [OFInvalidFormatException exception]; Index: src/OFObject+KeyValueCoding.h ================================================================== --- src/OFObject+KeyValueCoding.h +++ src/OFObject+KeyValueCoding.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFObject+KeyValueCoding.m ================================================================== --- src/OFObject+KeyValueCoding.m +++ src/OFObject+KeyValueCoding.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -48,21 +46,21 @@ if ((keyLength = key.UTF8StringLength) < 1) { objc_autoreleasePoolPop(pool); return [self valueForUndefinedKey: key]; } - name = of_malloc(1, keyLength + 3); + name = OFAllocMemory(keyLength + 3, 1); @try { memcpy(name, "is", 2); memcpy(name + 2, key.UTF8String, keyLength); name[keyLength + 2] = '\0'; - name[2] = of_ascii_toupper(name[2]); + name[2] = OFASCIIToUpper(name[2]); selector = sel_registerName(name); } @finally { - of_free(name); + OFFreeMemory(name); } methodSignature = [self methodSignatureForSelector: selector]; if (methodSignature == NULL) { @@ -139,16 +137,14 @@ return [ret autorelease]; } - (id)valueForUndefinedKey: (OFString *)key { - @throw [OFUndefinedKeyException exceptionWithObject: self - key: key]; + @throw [OFUndefinedKeyException exceptionWithObject: self key: key]; } -- (void)setValue: (id)value - forKey: (OFString *)key +- (void)setValue: (id)value forKey: (OFString *)key { void *pool = objc_autoreleasePoolPush(); size_t keyLength; char *name; SEL selector; @@ -155,26 +151,25 @@ OFMethodSignature *methodSignature; const char *valueType; if ((keyLength = key.UTF8StringLength) < 1) { objc_autoreleasePoolPop(pool); - [self setValue: value - forUndefinedKey: key]; + [self setValue: value forUndefinedKey: key]; return; } - name = of_malloc(1, keyLength + 5); + name = OFAllocMemory(keyLength + 5, 1); @try { memcpy(name, "set", 3); memcpy(name + 3, key.UTF8String, keyLength); memcpy(name + keyLength + 3, ":", 2); - name[3] = of_ascii_toupper(name[3]); + name[3] = OFASCIIToUpper(name[3]); selector = sel_registerName(name); } @finally { - of_free(name); + OFFreeMemory(name); } methodSignature = [self methodSignatureForSelector: selector]; if (methodSignature == nil || @@ -181,12 +176,11 @@ methodSignature.numberOfArguments != 3 || *methodSignature.methodReturnType != 'v' || *[methodSignature argumentTypeAtIndex: 0] != '@' || *[methodSignature argumentTypeAtIndex: 1] != ':') { objc_autoreleasePoolPop(pool); - [self setValue: value - forUndefinedKey: key]; + [self setValue: value forUndefinedKey: key]; return; } valueType = [methodSignature argumentTypeAtIndex: 2]; @@ -228,40 +222,36 @@ CASE('f', float, floatValue) CASE('d', double, doubleValue) #undef CASE default: objc_autoreleasePoolPop(pool); - [self setValue: value - forUndefinedKey: key]; + [self setValue: value forUndefinedKey: key]; return; } objc_autoreleasePoolPop(pool); } -- (void)setValue: (id)value - forKeyPath: (OFString *)keyPath +- (void)setValue: (id)value forKeyPath: (OFString *)keyPath { void *pool = objc_autoreleasePoolPush(); OFArray *keys = [keyPath componentsSeparatedByString: @"."]; size_t keysCount = keys.count; id object = self; size_t i = 0; for (OFString *key in keys) { if (++i == keysCount) - [object setValue: value - forKey: key]; + [object setValue: value forKey: key]; else object = [object valueForKey: key]; } objc_autoreleasePoolPop(pool); } -- (void)setValue: (id)value - forUndefinedKey: (OFString *)key +- (void)setValue: (id)value forUndefinedKey: (OFString *)key { @throw [OFUndefinedKeyException exceptionWithObject: self key: key value: value]; } Index: src/OFObject+Serialization.h ================================================================== --- src/OFObject+Serialization.h +++ src/OFObject+Serialization.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFObject+Serialization.m ================================================================== --- src/OFObject+Serialization.m +++ src/OFObject+Serialization.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -42,13 +40,12 @@ pool = objc_autoreleasePoolPush(); element = ((id )self).XMLElementBySerializing; root = [OFXMLElement elementWithName: @"serialization" - namespace: OF_SERIALIZATION_NS]; - [root addAttributeWithName: @"version" - stringValue: @"1"]; + namespace: OFSerializationNS]; + [root addAttributeWithName: @"version" stringValue: @"1"]; [root addChild: element]; ret = [@"\n" stringByAppendingString: [root XMLStringWithIndentation: 2]]; Index: src/OFObject.h ================================================================== --- src/OFObject.h +++ src/OFObject.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -30,13 +28,13 @@ #include #include #include #include -#include "block.h" #include "macros.h" -#include "once.h" + +#include "OFOnce.h" /* * Some versions of MinGW require to be included before * . Do this here to make sure this is always done in the correct * order, even if another header includes just . @@ -56,63 +54,67 @@ /** * @brief A result of a comparison. */ typedef enum { /** The left object is smaller than the right */ - OF_ORDERED_ASCENDING = -1, + OFOrderedAscending = -1, /** Both objects are equal */ - OF_ORDERED_SAME = 0, + OFOrderedSame = 0, /** The left object is bigger than the right */ - OF_ORDERED_DESCENDING = 1 -} of_comparison_result_t; + OFOrderedDescending = 1 +} OFComparisonResult; #ifdef OF_HAVE_BLOCKS /** * @brief A comparator to compare two objects. * * @param left The left object * @param right The right object * @return The order of the objects */ -typedef of_comparison_result_t (^of_comparator_t)(id _Nonnull left, - id _Nonnull right); +typedef OFComparisonResult (^OFComparator)(id _Nonnull left, id _Nonnull right); #endif /** - * @brief An enum for storing endianess. + * @brief An enum for representing endianess. */ typedef enum { /** Most significant byte first (big endian) */ - OF_BYTE_ORDER_BIG_ENDIAN, + OFByteOrderBigEndian, /** Least significant byte first (little endian) */ - OF_BYTE_ORDER_LITTLE_ENDIAN -} of_byte_order_t; + OFByteOrderLittleEndian, + /** Native byte order of the system */ +#ifdef OF_BIG_ENDIAN + OFByteOrderNative = OFByteOrderBigEndian +#else + OFByteOrderNative = OFByteOrderLittleEndian +#endif +} OFByteOrder; /** - * @struct of_range_t OFObject.h ObjFW/OFObject.h + * @struct OFRange OFObject.h ObjFW/OFObject.h * * @brief A range. */ -struct OF_BOXABLE of_range_t { +typedef struct OF_BOXABLE { /** The start of the range */ size_t location; /** The length of the range */ size_t length; -}; -typedef struct of_range_t of_range_t; +} OFRange; /** - * @brief Creates a new of_range_t. + * @brief Creates a new OFRange. * * @param start The starting index of the range * @param length The length of the range - * @return An of_range with the specified start and length + * @return An OFRangeith the specified start and length */ -static OF_INLINE of_range_t OF_CONST_FUNC -of_range(size_t start, size_t length) +static OF_INLINE OFRange OF_CONST_FUNC +OFRangeMake(size_t start, size_t length) { - of_range_t range = { start, length }; + OFRange range = { start, length }; return range; } /** @@ -121,11 +123,11 @@ * @param range1 The first range for the comparison * @param range2 The second range for the comparison * @return Whether the two ranges are equal */ static OF_INLINE bool -of_range_equal(of_range_t range1, of_range_t range2) +OFRangeEqual(OFRange range1, OFRange range2) { if (range1.location != range2.location) return false; if (range1.length != range2.length) @@ -135,36 +137,35 @@ } /** * @brief A time interval in seconds. */ -typedef double of_time_interval_t; +typedef double OFTimeInterval; /** - * @struct of_point_t OFObject.h ObjFW/OFObject.h + * @struct OFPoint OFObject.h ObjFW/OFObject.h * * @brief A point. */ -struct OF_BOXABLE of_point_t { +typedef struct OF_BOXABLE { /** The x coordinate of the point */ float x; /** The y coordinate of the point */ float y; -}; -typedef struct of_point_t of_point_t; +} OFPoint; /** - * @brief Creates a new of_point_t. + * @brief Creates a new OFPoint. * * @param x The x coordinate of the point * @param y The x coordinate of the point - * @return An of_point_t with the specified coordinates + * @return An OFPoint with the specified coordinates */ -static OF_INLINE of_point_t OF_CONST_FUNC -of_point(float x, float y) +static OF_INLINE OFPoint OF_CONST_FUNC +OFPointMake(float x, float y) { - of_point_t point = { x, y }; + OFPoint point = { x, y }; return point; } /** @@ -173,11 +174,11 @@ * @param point1 The first point for the comparison * @param point2 The second point for the comparison * @return Whether the two points are equal */ static OF_INLINE bool -of_point_equal(of_point_t point1, of_point_t point2) +OFPointEqual(OFPoint point1, OFPoint point2) { if (point1.x != point2.x) return false; if (point1.y != point2.y) @@ -185,107 +186,157 @@ return true; } /** - * @struct of_dimension_t OFObject.h ObjFW/OFObject.h + * @struct OFSize OFObject.h ObjFW/OFObject.h * - * @brief A dimension. + * @brief A size. */ -struct OF_BOXABLE of_dimension_t { - /** The width of the dimension */ +typedef struct OF_BOXABLE { + /** The width of the size */ float width; - /** The height of the dimension */ + /** The height of the size */ float height; -}; -typedef struct of_dimension_t of_dimension_t; - -/** - * @brief Creates a new of_dimension_t. - * - * @param width The width of the dimension - * @param height The height of the dimension - * @return An of_dimension_t with the specified width and height - */ -static OF_INLINE of_dimension_t OF_CONST_FUNC -of_dimension(float width, float height) -{ - of_dimension_t dimension = { width, height }; - - return dimension; -} - -/** - * @brief Returns whether the two dimensions are equal. - * - * @param dimension1 The first dimension for the comparison - * @param dimension2 The second dimension for the comparison - * @return Whether the two dimensions are equal +} OFSize; + +/** + * @brief Creates a new OFSize. + * + * @param width The width of the size + * @param height The height of the size + * @return An OFSize with the specified width and height + */ +static OF_INLINE OFSize OF_CONST_FUNC +OFSizeMake(float width, float height) +{ + OFSize size = { width, height }; + + return size; +} + +/** + * @brief Returns whether the two sizes are equal. + * + * @param size1 The first size for the comparison + * @param size2 The second size for the comparison + * @return Whether the two sizes are equal + */ +static OF_INLINE bool +OFSizeEqual(OFSize size1, OFSize size2) +{ + if (size1.width != size2.width) + return false; + + if (size1.height != size2.height) + return false; + + return true; +} + +/** + * @struct OFRect OFObject.h ObjFW/OFObject.h + * + * @brief A rectangle. + */ +typedef struct OF_BOXABLE { + /** The point from where the rectangle originates */ + OFPoint origin; + /** The size of the rectangle */ + OFSize size; +} OFRect; + +/** + * @brief Creates a new OFRect. + * + * @param x The x coordinate of the top left corner of the rectangle + * @param y The y coordinate of the top left corner of the rectangle + * @param width The width of the rectangle + * @param height The height of the rectangle + * @return An OFRect with the specified origin and size + */ +static OF_INLINE OFRect OF_CONST_FUNC +OFRectMake(float x, float y, float width, float height) +{ + OFRect rect = { + OFPointMake(x, y), + OFSizeMake(width, height) + }; + + return rect; +} + +/** + * @brief Returns whether the two rectangles are equal. + * + * @param rect1 The first rectangle for the comparison + * @param rect2 The second rectangle for the comparison + * @return Whether the two rectangles are equal */ static OF_INLINE bool -of_dimension_equal(of_dimension_t dimension1, of_dimension_t dimension2) +OFRectEqual(OFRect rect1, OFRect rect2) { - if (dimension1.width != dimension2.width) + if (!OFPointEqual(rect1.origin, rect2.origin)) return false; - if (dimension1.height != dimension2.height) + if (!OFSizeEqual(rect1.size, rect2.size)) return false; return true; } /** - * @struct of_rectangle_t OFObject.h ObjFW/OFObject.h - * - * @brief A rectangle. - */ -struct OF_BOXABLE of_rectangle_t { - /** The point from where the rectangle originates */ - of_point_t origin; - /** The size of the rectangle */ - of_dimension_t size; -}; -typedef struct of_rectangle_t of_rectangle_t; - -/** - * @brief Creates a new of_rectangle_t. - * - * @param x The x coordinate of the top left corner of the rectangle - * @param y The y coordinate of the top left corner of the rectangle - * @param width The width of the rectangle - * @param height The height of the rectangle - * @return An of_rectangle_t with the specified origin and size - */ -static OF_INLINE of_rectangle_t OF_CONST_FUNC -of_rectangle(float x, float y, float width, float height) -{ - of_rectangle_t rectangle = { - of_point(x, y), - of_dimension(width, height) - }; - - return rectangle; -} - -/** - * @brief Returns whether the two rectangles are equal. - * - * @param rectangle1 The first rectangle for the comparison - * @param rectangle2 The second rectangle for the comparison - * @return Whether the two rectangles are equal - */ -static OF_INLINE bool -of_rectangle_equal(of_rectangle_t rectangle1, of_rectangle_t rectangle2) -{ - if (!of_point_equal(rectangle1.origin, rectangle2.origin)) - return false; - - if (!of_dimension_equal(rectangle1.size, rectangle2.size)) - return false; - - return true; -} + * @brief Adds the specified byte to the hash. + * + * @param hash A pointer to a hash to add the byte to + * @param byte The byte to add to the hash + */ +static OF_INLINE void +OFHashAdd(unsigned long *_Nonnull hash, unsigned char byte) +{ + uint32_t tmp = (uint32_t)*hash; + + tmp += byte; + tmp += tmp << 10; + tmp ^= tmp >> 6; + + *hash = tmp; +} + +/** + * @brief Adds the specified hash to the hash. + * + * @param hash A pointer to a hash to add the hash to + * @param otherHash The hash to add to the hash + */ +static OF_INLINE void +OFHashAddHash(unsigned long *_Nonnull hash, unsigned long otherHash) +{ + OFHashAdd(hash, (otherHash >> 24) & 0xFF); + OFHashAdd(hash, (otherHash >> 16) & 0xFF); + OFHashAdd(hash, (otherHash >> 8) & 0xFF); + OFHashAdd(hash, otherHash & 0xFF); +} + +/** + * @brief Finalizes the specified hash. + * + * @param hash A pointer to the hash to finalize + */ +static OF_INLINE void +OFHashFinalize(unsigned long *_Nonnull hash) +{ + uint32_t tmp = (uint32_t)*hash; + + tmp += tmp << 3; + tmp ^= tmp >> 11; + tmp += tmp << 15; + + *hash = tmp; +} + +static const size_t OFNotFound = SIZE_MAX; #ifdef __OBJC__ @class OFMethodSignature; @class OFString; @class OFThread; @@ -401,12 +452,11 @@ * @param selector The selector to perform * @param object The object that is passed to the method specified by the * selector * @return The object returned by the method specified by the selector */ -- (nullable id)performSelector: (SEL)selector - withObject: (nullable id)object; +- (nullable id)performSelector: (SEL)selector withObject: (nullable id)object; /** * @brief Performs the specified selector with the specified objects. * * @param selector The selector to perform @@ -537,11 +587,11 @@ @property (class, readonly, nonatomic) OFString *className; @property (class, readonly, nullable, nonatomic) Class superclass; @property (class, readonly, nonatomic) OFString *description; # endif -# ifdef __cplusplus +# ifndef __cplusplus @property (readonly, nonatomic) Class class; # else @property (readonly, nonatomic, getter=class) Class class_; #endif @property OF_NULLABLE_PROPERTY (readonly, nonatomic) Class superclass; @@ -577,14 +627,13 @@ * * Derived classes can override this to execute their own code when the class * is unloaded. * * @warning This is not supported by the Apple runtime and currently only - * called by the ObjFW runtime when objc_unregister_class() or - * objc_exit() has been called! + * called by the ObjFW runtime when @ref objc_deinit has been called! * In the future, this might also be called by the ObjFW runtime when - * the class is part of a plugin that has been unloaded. + * the class is part of a plugin that is being unloaded. */ + (void)unload; /** * @brief A method which is called the moment before the first call to the class @@ -804,101 +853,10 @@ * returned * @return The method signature for the specified selector */ - (nullable OFMethodSignature *)methodSignatureForSelector: (SEL)selector; -/** - * @brief Allocates memory and stores it in the object's memory pool. - * - * It will be free'd automatically when the object is deallocated. - * - * @param size The size of the memory to allocate - * @return A pointer to the allocated memory. May return NULL if the specified - * size is 0. - */ -- (nullable void *)allocMemoryWithSize: (size_t)size OF_WARN_UNUSED_RESULT; - -/** - * @brief Allocates memory for the specified number of items and stores it in - * the object's memory pool. - * - * It will be free'd automatically when the object is deallocated. - * - * @param size The size of each item to allocate - * @param count The number of items to allocate - * @return A pointer to the allocated memory. May return NULL if the specified - * size or count is 0. - */ -- (nullable void *)allocMemoryWithSize: (size_t)size - count: (size_t)count OF_WARN_UNUSED_RESULT; - -/** - * @brief Allocates memory, initializes it with zeros and stores it in the - * object's memory pool. - * - * It will be free'd automatically when the object is deallocated. - * - * @param size The size of the memory to allocate - * @return A pointer to the allocated memory. May return NULL if the specified - * size is 0. - */ -- (nullable void *)allocZeroedMemoryWithSize: (size_t)size - OF_WARN_UNUSED_RESULT; - -/** - * @brief Allocates memory for the specified number of items, initializes it - * with zeros and stores it in the object's memory pool. - * - * It will be free'd automatically when the object is deallocated. - * - * @param size The size of each item to allocate - * @param count The number of items to allocate - * @return A pointer to the allocated memory. May return NULL if the specified - * size or count is 0. - */ -- (nullable void *)allocZeroedMemoryWithSize: (size_t)size - count: (size_t)count - OF_WARN_UNUSED_RESULT; - -/** - * @brief Resizes memory in the object's memory pool to the specified size. - * - * If the pointer is NULL, this is equivalent to allocating memory. - * If the size is 0, this is equivalent to freeing memory. - * - * @param pointer A pointer to the already allocated memory - * @param size The new size for the memory chunk - * @return A pointer to the resized memory chunk - */ -- (nullable void *)resizeMemory: (nullable void *)pointer - size: (size_t)size OF_WARN_UNUSED_RESULT; - -/** - * @brief Resizes memory in the object's memory pool to the specific number of - * items of the specified size. - * - * If the pointer is NULL, this is equivalent to allocating memory. - * If the size or number of items is 0, this is equivalent to freeing memory. - * - * @param pointer A pointer to the already allocated memory - * @param size The size of each item to resize to - * @param count The number of items to resize to - * @return A pointer to the resized memory chunk - */ -- (nullable void *)resizeMemory: (nullable void *)pointer - size: (size_t)size - count: (size_t)count OF_WARN_UNUSED_RESULT; - -/** - * @brief Frees allocated memory and removes it from the object's memory pool. - * - * Does nothing if the pointer is NULL. - * - * @param pointer A pointer to the allocated memory - */ -- (void)freeMemory: (nullable void *)pointer; - /** * @brief Deallocates the object. * * It is automatically called when the retain count reaches zero. * @@ -910,12 +868,11 @@ * @brief Performs the specified selector after the specified delay. * * @param selector The selector to perform * @param delay The delay after which the selector will be performed */ -- (void)performSelector: (SEL)selector - afterDelay: (of_time_interval_t)delay; +- (void)performSelector: (SEL)selector afterDelay: (OFTimeInterval)delay; /** * @brief Performs the specified selector with the specified object after the * specified delay. * @@ -924,11 +881,11 @@ * selector * @param delay The delay after which the selector will be performed */ - (void)performSelector: (SEL)selector withObject: (nullable id)object - afterDelay: (of_time_interval_t)delay; + afterDelay: (OFTimeInterval)delay; /** * @brief Performs the specified selector with the specified objects after the * specified delay. * @@ -940,11 +897,11 @@ * @param delay The delay after which the selector will be performed */ - (void)performSelector: (SEL)selector withObject: (nullable id)object1 withObject: (nullable id)object2 - afterDelay: (of_time_interval_t)delay; + afterDelay: (OFTimeInterval)delay; /** * @brief Performs the specified selector with the specified objects after the * specified delay. * @@ -959,11 +916,11 @@ */ - (void)performSelector: (SEL)selector withObject: (nullable id)object1 withObject: (nullable id)object2 withObject: (nullable id)object3 - afterDelay: (of_time_interval_t)delay; + afterDelay: (OFTimeInterval)delay; /** * @brief Performs the specified selector with the specified objects after the * specified delay. * @@ -981,11 +938,11 @@ - (void)performSelector: (SEL)selector withObject: (nullable id)object1 withObject: (nullable id)object2 withObject: (nullable id)object3 withObject: (nullable id)object4 - afterDelay: (of_time_interval_t)delay; + afterDelay: (OFTimeInterval)delay; # ifdef OF_HAVE_THREADS /** * @brief Performs the specified selector on the specified thread. * @@ -1162,11 +1119,11 @@ * @param thread The thread on which to perform the selector * @param delay The delay after which the selector will be performed */ - (void)performSelector: (SEL)selector onThread: (OFThread *)thread - afterDelay: (of_time_interval_t)delay; + afterDelay: (OFTimeInterval)delay; /** * @brief Performs the specified selector on the specified thread with the * specified object after the specified delay. * @@ -1177,11 +1134,11 @@ * @param delay The delay after which the selector will be performed */ - (void)performSelector: (SEL)selector onThread: (OFThread *)thread withObject: (nullable id)object - afterDelay: (of_time_interval_t)delay; + afterDelay: (OFTimeInterval)delay; /** * @brief Performs the specified selector on the specified thread with the * specified objects after the specified delay. * @@ -1195,11 +1152,11 @@ */ - (void)performSelector: (SEL)selector onThread: (OFThread *)thread withObject: (nullable id)object1 withObject: (nullable id)object2 - afterDelay: (of_time_interval_t)delay; + afterDelay: (OFTimeInterval)delay; /** * @brief Performs the specified selector on the specified thread with the * specified objects after the specified delay. * @@ -1216,11 +1173,11 @@ - (void)performSelector: (SEL)selector onThread: (OFThread *)thread withObject: (nullable id)object1 withObject: (nullable id)object2 withObject: (nullable id)object3 - afterDelay: (of_time_interval_t)delay; + afterDelay: (OFTimeInterval)delay; /** * @brief Performs the specified selector on the specified thread with the * specified objects after the specified delay. * @@ -1240,11 +1197,11 @@ onThread: (OFThread *)thread withObject: (nullable id)object1 withObject: (nullable id)object2 withObject: (nullable id)object3 withObject: (nullable id)object4 - afterDelay: (of_time_interval_t)delay; + afterDelay: (OFTimeInterval)delay; # endif /** * @brief This method is called when @ref resolveClassMethod: or * @ref resolveInstanceMethod: returned false. It should return a target @@ -1311,57 +1268,64 @@ /** * @protocol OFComparing OFObject.h ObjFW/OFObject.h * * @brief A protocol for comparing objects. * - * This protocol is implemented by objects that can be compared. + * This protocol is implemented by objects that can be compared. Its only method, @ref compare:, should be overridden with a stronger type. */ @protocol OFComparing /** - * @brief Compares the object with another object. + * @brief Compares the object to another object. * * @param object An object to compare the object to * @return The result of the comparison */ -- (of_comparison_result_t)compare: (id )object; +- (OFComparisonResult)compare: (id )object; @end #endif #ifdef __cplusplus extern "C" { #endif /** - * @brief Allocates memory for the specified number of items. + * @brief Allocates memory for the specified number of items of the specified + * size. + * + * To free the allocated memory, use @ref OFFreeMemory. * * Throws @ref OFOutOfMemoryException if allocating failed and * @ref OFOutOfRangeException if the requested size exceeds the address space. * * @param count The number of items to allocate * @param size The size of each item to allocate * @return A pointer to the allocated memory. May return NULL if the specified * size or count is 0. */ -extern void *_Nullable of_malloc(size_t count, size_t size) +extern void *_Nullable OFAllocMemory(size_t count, size_t size) OF_WARN_UNUSED_RESULT; /** - * @brief Allocates memory for the specified number of items and initializes it - * with zeros. + * @brief Allocates memory for the specified number of items of the specified + * size and initializes it with zeros. + * + * To free the allocated memory, use @ref OFFreeMemory. * * Throws @ref OFOutOfMemoryException if allocating failed and * @ref OFOutOfRangeException if the requested size exceeds the address space. * * @param size The size of each item to allocate * @param count The number of items to allocate * @return A pointer to the allocated memory. May return NULL if the specified * size or count is 0. */ -extern void *_Nullable of_calloc(size_t count, size_t size) +extern void *_Nullable OFAllocZeroedMemory(size_t count, size_t size) OF_WARN_UNUSED_RESULT; /** - * @brief Resizes memory to the specific number of items of the specified size. + * @brief Resizes memory to the specified number of items of the specified size. + * + * To free the allocated memory, use @ref OFFreeMemory. * * If the pointer is NULL, this is equivalent to allocating memory. * If the size or number of items is 0, this is equivalent to freeing memory. * * Throws @ref OFOutOfMemoryException if allocating failed and @@ -1370,21 +1334,21 @@ * @param pointer A pointer to the already allocated memory * @param size The size of each item to resize to * @param count The number of items to resize to * @return A pointer to the resized memory chunk */ -extern void *_Nullable of_realloc(void *_Nullable pointer, size_t count, +extern void *_Nullable OFResizeMemory(void *_Nullable pointer, size_t count, size_t size) OF_WARN_UNUSED_RESULT; /** - * @brief Frees allocated memory. - * - * Does nothing if the pointer is NULL. + * @brief Frees memory allocated by @ref OFAllocMemory, @ref OFAllocZeroedMemory + * or @ref OFResizeMemory. * - * @param pointer A pointer to the allocated memory + * @param pointer A pointer to the memory to free or nil (passing nil ooes + * nothing) */ -extern void of_free(void *_Nullable pointer); +extern void OFFreeMemory(void *_Nullable pointer); #ifdef OF_APPLE_RUNTIME extern void *_Null_unspecified objc_autoreleasePoolPush(void); extern void objc_autoreleasePoolPop(void *_Null_unspecified pool); # ifndef __OBJC2__ @@ -1391,25 +1355,50 @@ extern id _Nullable objc_constructInstance(Class _Nullable class_, void *_Nullable bytes); extern void *_Nullable objc_destructInstance(id _Nullable object); # endif #endif -extern id of_alloc_object(Class class_, size_t extraSize, - size_t extraAlignment, void *_Nullable *_Nullable extra); -extern void OF_NO_RETURN_FUNC of_method_not_found(id self, SEL _cmd); -extern uint32_t of_hash_seed; -/* These do *NOT* provide cryptographically secure randomness! */ -extern uint16_t of_random16(void); -extern uint32_t of_random32(void); -extern uint64_t of_random64(void); +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 Returns 16 bit or non-cryptographical randomness. + * + * @return 16 bit or non-cryptographical randomness + */ +extern uint16_t OFRandom16(void); + +/** + * @brief Returns 32 bit or non-cryptographical randomness. + * + * @return 32 bit or non-cryptographical randomness + */ +extern uint32_t OFRandom32(void); + +/** + * @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 + +#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,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -18,10 +16,11 @@ #include "config.h" #include #include #include +#include "unistd_wrapper.h" #include #ifdef OF_APPLE_RUNTIME # include @@ -31,21 +30,27 @@ # include #endif #import "OFObject.h" #import "OFArray.h" +#ifdef OF_HAVE_ATOMIC_OPS +# import "OFAtomic.h" +#endif #import "OFLocale.h" #import "OFMethodSignature.h" #import "OFRunLoop.h" +#if !defined(OF_HAVE_ATOMIC_OPS) && defined(OF_HAVE_THREADS) +# import "OFPlainMutex.h" /* For OFSpinlock */ +#endif +#import "OFString.h" #import "OFThread.h" #import "OFTimer.h" #import "OFAllocFailedException.h" #import "OFEnumerationMutationException.h" #import "OFInitializationFailedException.h" #import "OFInvalidArgumentException.h" -#import "OFMemoryNotPartOfObjectException.h" #import "OFNotImplementedException.h" #import "OFOutOfMemoryException.h" #import "OFOutOfRangeException.h" #if defined(OF_APPLE_RUNTIME) && __OBJC2__ @@ -60,58 +65,40 @@ #ifdef OF_AMIGAOS # include #endif -#import "OFString.h" - -#if defined(OF_HAVE_ATOMIC_OPS) -# import "atomic.h" -#elif defined(OF_HAVE_THREADS) -# import "mutex.h" -#endif - #ifdef OF_APPLE_RUNTIME extern id _Nullable _objc_rootAutorelease(id _Nullable object); #endif #if defined(OF_HAVE_FORWARDING_TARGET_FOR_SELECTOR) -extern id of_forward(id, SEL, ...); -extern struct stret of_forward_stret(id, SEL, ...); +extern id OFForward(id, SEL, ...); +extern struct Stret OFForward_stret(id, SEL, ...); #else -# define of_forward of_method_not_found -# define of_forward_stret of_method_not_found_stret +# define OFForward OFMethodNotFound +# define OFForward_stret OFMethodNotFound_stret #endif -struct pre_ivar { +struct PreIvars { int retainCount; #if !defined(OF_HAVE_ATOMIC_OPS) && !defined(OF_AMIGAOS) - of_spinlock_t retainCountSpinlock; -#endif - struct pre_mem *firstMem, *lastMem; -}; - -struct pre_mem { - struct pre_mem *prev, *next; - id owner; -}; - -#define PRE_IVARS_ALIGN ((sizeof(struct pre_ivar) + \ - (OF_BIGGEST_ALIGNMENT - 1)) & ~(OF_BIGGEST_ALIGNMENT - 1)) -#define PRE_IVARS ((struct pre_ivar *)(void *)((char *)self - PRE_IVARS_ALIGN)) - -#define PRE_MEM_ALIGN ((sizeof(struct pre_mem) + \ - (OF_BIGGEST_ALIGNMENT - 1)) & ~(OF_BIGGEST_ALIGNMENT - 1)) -#define PRE_MEM(mem) ((struct pre_mem *)(void *)((char *)mem - PRE_MEM_ALIGN)) + OFSpinlock retainCountSpinlock; +#endif +}; + +#define PRE_IVARS_ALIGN ((sizeof(struct PreIvars) + \ + (OF_BIGGEST_ALIGNMENT - 1)) & ~(OF_BIGGEST_ALIGNMENT - 1)) +#define PRE_IVARS ((struct PreIvars *)(void *)((char *)self - PRE_IVARS_ALIGN)) static struct { Class isa; } allocFailedException; -uint32_t of_hash_seed; +unsigned long OFHashSeed; void * -of_malloc(size_t count, size_t size) +OFAllocMemory(size_t count, size_t size) { void *pointer; if OF_UNLIKELY (count == 0 || size == 0) return NULL; @@ -125,11 +112,11 @@ return pointer; } void * -of_calloc(size_t count, size_t size) +OFAllocZeroedMemory(size_t count, size_t size) { void *pointer; if OF_UNLIKELY (count == 0 || size == 0) return NULL; @@ -144,14 +131,16 @@ return pointer; } void * -of_realloc(void *pointer, size_t count, size_t size) +OFResizeMemory(void *pointer, size_t count, size_t size) { - if OF_UNLIKELY (count == 0 || size == 0) + if OF_UNLIKELY (count == 0 || size == 0) { + free(pointer); return NULL; + } if OF_UNLIKELY (count > SIZE_MAX / size) @throw [OFOutOfRangeException exception]; if OF_UNLIKELY ((pointer = realloc(pointer, count * size)) == NULL) @@ -160,11 +149,11 @@ return pointer; } void -of_free(void *pointer) +OFFreeMemory(void *pointer) { free(pointer); } #if !defined(HAVE_ARC4RANDOM) && !defined(HAVE_GETRANDOM) @@ -182,50 +171,49 @@ # endif } #endif uint16_t -of_random16(void) +OFRandom16(void) { #if defined(HAVE_ARC4RANDOM) return arc4random(); #elif defined(HAVE_GETRANDOM) uint16_t buffer; - OF_ENSURE(getrandom(&buffer, sizeof(buffer), 0) == sizeof(buffer)); + OFEnsure(getrandom(&buffer, sizeof(buffer), 0) == sizeof(buffer)); return buffer; #else - static of_once_t onceControl = OF_ONCE_INIT; - - of_once(&onceControl, initRandom); + static OFOnceControl onceControl = OFOnceControlInitValue; + OFOnce(&onceControl, initRandom); # ifdef HAVE_RANDOM return random() & 0xFFFF; # else return rand() & 0xFFFF; # endif #endif } uint32_t -of_random32(void) +OFRandom32(void) { #if defined(HAVE_ARC4RANDOM) return arc4random(); #elif defined(HAVE_GETRANDOM) uint32_t buffer; - OF_ENSURE(getrandom(&buffer, sizeof(buffer), 0) == sizeof(buffer)); + OFEnsure(getrandom(&buffer, sizeof(buffer), 0) == sizeof(buffer)); return buffer; #else - return ((uint32_t)of_random16() << 16) | of_random16(); + return ((uint32_t)OFRandom16() << 16) | OFRandom16(); #endif } uint64_t -of_random64(void) +OFRandom64(void) { #if defined(HAVE_ARC4RANDOM_BUF) uint64_t buffer; arc4random_buf(&buffer, sizeof(buffer)); @@ -232,17 +220,23 @@ return buffer; #elif defined(HAVE_GETRANDOM) uint64_t buffer; - OF_ENSURE(getrandom(&buffer, sizeof(buffer), 0) == sizeof(buffer)); + OFEnsure(getrandom(&buffer, sizeof(buffer), 0) == sizeof(buffer)); return buffer; #else - return ((uint64_t)of_random32() << 32) | of_random32(); + return ((uint64_t)OFRandom32() << 32) | OFRandom32(); #endif } + +void +OFHashInit(unsigned long *hash) +{ + *hash = OFHashSeed; +} static const char * typeEncodingForSelector(Class class, SEL selector) { Method method; @@ -257,11 +251,11 @@ static void uncaughtExceptionHandler(id exception) { OFString *description = [exception description]; OFArray *backtrace = nil; - of_string_encoding_t encoding = [OFLocale encoding]; + OFStringEncoding encoding = [OFLocale encoding]; fprintf(stderr, "\nRuntime error: Unhandled exception:\n%s\n", [description cStringWithEncoding: encoding]); if ([exception respondsToSelector: @selector(backtrace)]) @@ -282,11 +276,11 @@ { @throw [OFEnumerationMutationException exceptionWithObject: object]; } void OF_NO_RETURN_FUNC -of_method_not_found(id object, SEL selector) +OFMethodNotFound(id object, SEL selector) { [object doesNotRecognizeSelector: selector]; /* * Just in case doesNotRecognizeSelector: returned, even though it must @@ -296,17 +290,17 @@ OF_UNREACHABLE } void OF_NO_RETURN_FUNC -of_method_not_found_stret(void *stret, id object, SEL selector) +OFMethodNotFound_stret(void *stret, id object, SEL selector) { - of_method_not_found(object, selector); + OFMethodNotFound(object, selector); } id -of_alloc_object(Class class, size_t extraSize, size_t extraAlignment, +OFAllocObject(Class class, size_t extraSize, size_t extraAlignment, void **extra) { OFObject *instance; size_t instanceSize; @@ -322,15 +316,15 @@ if OF_UNLIKELY (instance == nil) { allocFailedException.isa = [OFAllocFailedException class]; @throw (id)&allocFailedException; } - ((struct pre_ivar *)instance)->retainCount = 1; + ((struct PreIvars *)instance)->retainCount = 1; #if !defined(OF_HAVE_ATOMIC_OPS) && !defined(OF_AMIGAOS) - if OF_UNLIKELY (!of_spinlock_new( - &((struct pre_ivar *)instance)->retainCountSpinlock)) { + if OF_UNLIKELY (OFSpinlockNew( + &((struct PreIvars *)instance)->retainCountSpinlock) != 0) { free(instance); @throw [OFInitializationFailedException exceptionWithClass: class]; } #endif @@ -379,25 +373,25 @@ * * Unfortunately, there is no way to check if a forward handler has * already been set, so this is the best we can do. */ if (dlsym(RTLD_DEFAULT, "NSFoundationVersionNumber") == NULL) - objc_setForwardHandler((void *)&of_forward, - (void *)&of_forward_stret); + objc_setForwardHandler((void *)&OFForward, + (void *)&OFForward_stret); #else - objc_setForwardHandler((IMP)&of_forward, (IMP)&of_forward_stret); + objc_setForwardHandler((IMP)&OFForward, (IMP)&OFForward_stret); #endif objc_setEnumerationMutationHandler(enumerationMutationHandler); do { - of_hash_seed = of_random32(); - } while (of_hash_seed == 0); + OFHashSeed = OFRandom32(); + } while (OFHashSeed == 0); #ifdef OF_OBJFW_RUNTIME objc_setTaggedPointerSecret(sizeof(uintptr_t) == 4 - ? (uintptr_t)of_random32() : (uintptr_t)of_random64()); + ? (uintptr_t)OFRandom32() : (uintptr_t)OFRandom64()); #endif } + (void)unload { @@ -407,11 +401,11 @@ { } + (instancetype)alloc { - return of_alloc_object(self, 0, 0, NULL); + return OFAllocObject(self, 0, 0, NULL); } + (instancetype)new { return [[self alloc] init]; @@ -423,11 +417,11 @@ } + (OFString *)className { return [OFString stringWithCString: class_getName(self) - encoding: OF_STRING_ENCODING_ASCII]; + encoding: OFStringEncodingASCII]; } + (bool)isSubclassOfClass: (Class)class { for (Class iter = self; iter != Nil; iter = class_getSuperclass(iter)) @@ -476,12 +470,11 @@ + (OFString *)description { return [self className]; } -+ (IMP)replaceClassMethod: (SEL)selector - withMethodFromClass: (Class)class ++ (IMP)replaceClassMethod: (SEL)selector withMethodFromClass: (Class)class { IMP method = [class methodForSelector: selector]; if (method == NULL) @throw [OFInvalidArgumentException exception]; @@ -488,12 +481,11 @@ return class_replaceMethod(object_getClass(self), selector, method, typeEncodingForSelector(object_getClass(class), selector)); } -+ (IMP)replaceInstanceMethod: (SEL)selector - withMethodFromClass: (Class)class ++ (IMP)replaceInstanceMethod: (SEL)selector withMethodFromClass: (Class)class { IMP method = [class instanceMethodForSelector: selector]; if (method == NULL) @throw [OFInvalidArgumentException exception]; @@ -580,11 +572,11 @@ } - (OFString *)className { return [OFString stringWithCString: object_getClassName(self) - encoding: OF_STRING_ENCODING_ASCII]; + encoding: OFStringEncodingASCII]; } - (bool)isKindOfClass: (Class)class { for (Class iter = object_getClass(self); iter != Nil; @@ -624,12 +616,11 @@ #endif return imp(self, selector); } -- (id)performSelector: (SEL)selector - withObject: (id)object +- (id)performSelector: (SEL)selector withObject: (id)object { #if defined(OF_OBJFW_RUNTIME) id (*imp)(id, SEL, id) = (id (*)(id, SEL, id))objc_msg_lookup(self, selector); #elif defined(OF_APPLE_RUNTIME) @@ -684,12 +675,11 @@ #endif return imp(self, selector, object1, object2, object3, object4); } -- (void)performSelector: (SEL)selector - afterDelay: (of_time_interval_t)delay +- (void)performSelector: (SEL)selector afterDelay: (OFTimeInterval)delay { void *pool = objc_autoreleasePoolPush(); [OFTimer scheduledTimerWithTimeInterval: delay target: self @@ -699,11 +689,11 @@ objc_autoreleasePoolPop(pool); } - (void)performSelector: (SEL)selector withObject: (id)object - afterDelay: (of_time_interval_t)delay + afterDelay: (OFTimeInterval)delay { void *pool = objc_autoreleasePoolPush(); [OFTimer scheduledTimerWithTimeInterval: delay target: self @@ -715,11 +705,11 @@ } - (void)performSelector: (SEL)selector withObject: (id)object1 withObject: (id)object2 - afterDelay: (of_time_interval_t)delay + afterDelay: (OFTimeInterval)delay { void *pool = objc_autoreleasePoolPush(); [OFTimer scheduledTimerWithTimeInterval: delay target: self @@ -733,11 +723,11 @@ - (void)performSelector: (SEL)selector withObject: (id)object1 withObject: (id)object2 withObject: (id)object3 - afterDelay: (of_time_interval_t)delay + afterDelay: (OFTimeInterval)delay { void *pool = objc_autoreleasePoolPush(); [OFTimer scheduledTimerWithTimeInterval: delay target: self @@ -753,11 +743,11 @@ - (void)performSelector: (SEL)selector withObject: (id)object1 withObject: (id)object2 withObject: (id)object3 withObject: (id)object4 - afterDelay: (of_time_interval_t)delay + afterDelay: (OFTimeInterval)delay { void *pool = objc_autoreleasePoolPush(); [OFTimer scheduledTimerWithTimeInterval: delay target: self @@ -977,11 +967,11 @@ objc_autoreleasePoolPop(pool); } - (void)performSelector: (SEL)selector onThread: (OFThread *)thread - afterDelay: (of_time_interval_t)delay + afterDelay: (OFTimeInterval)delay { void *pool = objc_autoreleasePoolPush(); [thread.runLoop addTimer: [OFTimer timerWithTimeInterval: delay target: self @@ -992,11 +982,11 @@ } - (void)performSelector: (SEL)selector onThread: (OFThread *)thread withObject: (id)object - afterDelay: (of_time_interval_t)delay + afterDelay: (OFTimeInterval)delay { void *pool = objc_autoreleasePoolPush(); [thread.runLoop addTimer: [OFTimer timerWithTimeInterval: delay target: self @@ -1009,11 +999,11 @@ - (void)performSelector: (SEL)selector onThread: (OFThread *)thread withObject: (id)object1 withObject: (id)object2 - afterDelay: (of_time_interval_t)delay + afterDelay: (OFTimeInterval)delay { void *pool = objc_autoreleasePoolPush(); [thread.runLoop addTimer: [OFTimer timerWithTimeInterval: delay target: self @@ -1028,11 +1018,11 @@ - (void)performSelector: (SEL)selector onThread: (OFThread *)thread withObject: (id)object1 withObject: (id)object2 withObject: (id)object3 - afterDelay: (of_time_interval_t)delay + afterDelay: (OFTimeInterval)delay { void *pool = objc_autoreleasePoolPush(); [thread.runLoop addTimer: [OFTimer timerWithTimeInterval: delay target: self @@ -1049,11 +1039,11 @@ onThread: (OFThread *)thread withObject: (id)object1 withObject: (id)object2 withObject: (id)object3 withObject: (id)object4 - afterDelay: (of_time_interval_t)delay + afterDelay: (OFTimeInterval)delay { void *pool = objc_autoreleasePoolPush(); [thread.runLoop addTimer: [OFTimer timerWithTimeInterval: delay target: self @@ -1085,20 +1075,20 @@ } - (unsigned long)hash { uintptr_t ptr = (uintptr_t)self; - uint32_t hash; + unsigned long hash; - OF_HASH_INIT(hash); + OFHashInit(&hash); for (size_t i = 0; i < sizeof(ptr); i++) { - OF_HASH_ADD(hash, ptr & 0xFF); + OFHashAdd(&hash, ptr & 0xFF); ptr >>= 8; } - OF_HASH_FINALIZE(hash); + OFHashFinalize(&hash); return hash; } - (OFString *)description @@ -1106,175 +1096,10 @@ /* Classes containing data should reimplement this! */ return [OFString stringWithFormat: @"<%@>", self.className]; } -- (void *)allocMemoryWithSize: (size_t)size -{ - void *pointer; - struct pre_mem *preMem; - - if OF_UNLIKELY (size == 0) - return NULL; - - if OF_UNLIKELY (size > SIZE_MAX - PRE_IVARS_ALIGN) - @throw [OFOutOfRangeException exception]; - - if OF_UNLIKELY ((pointer = malloc(PRE_MEM_ALIGN + size)) == NULL) - @throw [OFOutOfMemoryException - exceptionWithRequestedSize: size]; - - preMem = pointer; - preMem->owner = self; - preMem->prev = PRE_IVARS->lastMem; - preMem->next = NULL; - - if OF_LIKELY (PRE_IVARS->lastMem != NULL) - PRE_IVARS->lastMem->next = preMem; - - if OF_UNLIKELY (PRE_IVARS->firstMem == NULL) - PRE_IVARS->firstMem = preMem; - - PRE_IVARS->lastMem = preMem; - - return (char *)pointer + PRE_MEM_ALIGN; -} - -- (void *)allocMemoryWithSize: (size_t)size - count: (size_t)count -{ - if OF_UNLIKELY (count > SIZE_MAX / size) - @throw [OFOutOfRangeException exception]; - - return [self allocMemoryWithSize: size * count]; -} - -- (void *)allocZeroedMemoryWithSize: (size_t)size -{ - void *pointer; - struct pre_mem *preMem; - - if OF_UNLIKELY (size == 0) - return NULL; - - if OF_UNLIKELY (size > SIZE_MAX - PRE_IVARS_ALIGN) - @throw [OFOutOfRangeException exception]; - - if OF_UNLIKELY ((pointer = calloc(1, PRE_MEM_ALIGN + size)) == NULL) - @throw [OFOutOfMemoryException - exceptionWithRequestedSize: size]; - - preMem = pointer; - preMem->owner = self; - preMem->prev = PRE_IVARS->lastMem; - - if OF_LIKELY (PRE_IVARS->lastMem != NULL) - PRE_IVARS->lastMem->next = preMem; - - if OF_UNLIKELY (PRE_IVARS->firstMem == NULL) - PRE_IVARS->firstMem = preMem; - - PRE_IVARS->lastMem = preMem; - - return (char *)pointer + PRE_MEM_ALIGN; -} - -- (void *)allocZeroedMemoryWithSize: (size_t)size - count: (size_t)count -{ - if OF_UNLIKELY (count > SIZE_MAX / size) - @throw [OFOutOfRangeException exception]; - - return [self allocZeroedMemoryWithSize: size * count]; -} - -- (void *)resizeMemory: (void *)pointer - size: (size_t)size -{ - void *new; - struct pre_mem *preMem; - - if OF_UNLIKELY (pointer == NULL) - return [self allocMemoryWithSize: size]; - - if OF_UNLIKELY (size == 0) { - [self freeMemory: pointer]; - return NULL; - } - - if OF_UNLIKELY (PRE_MEM(pointer)->owner != self) - @throw [OFMemoryNotPartOfObjectException - exceptionWithPointer: pointer - object: self]; - - if OF_UNLIKELY ((new = realloc(PRE_MEM(pointer), - PRE_MEM_ALIGN + size)) == NULL) - @throw [OFOutOfMemoryException - exceptionWithRequestedSize: size]; - preMem = new; - - if OF_UNLIKELY (preMem != PRE_MEM(pointer)) { - if OF_LIKELY (preMem->prev != NULL) - preMem->prev->next = preMem; - if OF_LIKELY (preMem->next != NULL) - preMem->next->prev = preMem; - - if OF_UNLIKELY (PRE_IVARS->firstMem == PRE_MEM(pointer)) - PRE_IVARS->firstMem = preMem; - if OF_UNLIKELY (PRE_IVARS->lastMem == PRE_MEM(pointer)) - PRE_IVARS->lastMem = preMem; - } - - return (char *)new + PRE_MEM_ALIGN; -} - -- (void *)resizeMemory: (void *)pointer - size: (size_t)size - count: (size_t)count -{ - if OF_UNLIKELY (pointer == NULL) - return [self allocMemoryWithSize: size - count: count]; - - if OF_UNLIKELY (size == 0 || count == 0) { - [self freeMemory: pointer]; - return NULL; - } - - if OF_UNLIKELY (count > SIZE_MAX / size) - @throw [OFOutOfRangeException exception]; - - return [self resizeMemory: pointer - size: size * count]; -} - -- (void)freeMemory: (void *)pointer -{ - if OF_UNLIKELY (pointer == NULL) - return; - - if OF_UNLIKELY (PRE_MEM(pointer)->owner != self) - @throw [OFMemoryNotPartOfObjectException - exceptionWithPointer: pointer - object: self]; - - if OF_LIKELY (PRE_MEM(pointer)->prev != NULL) - PRE_MEM(pointer)->prev->next = PRE_MEM(pointer)->next; - if OF_LIKELY (PRE_MEM(pointer)->next != NULL) - PRE_MEM(pointer)->next->prev = PRE_MEM(pointer)->prev; - - if OF_UNLIKELY (PRE_IVARS->firstMem == PRE_MEM(pointer)) - PRE_IVARS->firstMem = PRE_MEM(pointer)->next; - if OF_UNLIKELY (PRE_IVARS->lastMem == PRE_MEM(pointer)) - PRE_IVARS->lastMem = PRE_MEM(pointer)->prev; - - /* To detect double-free */ - PRE_MEM(pointer)->owner = nil; - - free(PRE_MEM(pointer)); -} - - (id)forwardingTargetForSelector: (SEL)selector { return nil; } @@ -1285,11 +1110,11 @@ } - (instancetype)retain { #if defined(OF_HAVE_ATOMIC_OPS) - of_atomic_int_inc(&PRE_IVARS->retainCount); + OFAtomicIntIncrease(&PRE_IVARS->retainCount); #elif defined(OF_AMIGAOS) /* * On AmigaOS, we can only have one CPU. As increasing a variable is a * single instruction on M68K, we don't need Forbid() / Permit() on * M68K. @@ -1300,13 +1125,13 @@ PRE_IVARS->retainCount++; # ifndef OF_AMIGAOS_M68K Permit(); # endif #else - OF_ENSURE(of_spinlock_lock(&PRE_IVARS->retainCountSpinlock)); + OFEnsure(OFSpinlockLock(&PRE_IVARS->retainCountSpinlock) == 0); PRE_IVARS->retainCount++; - OF_ENSURE(of_spinlock_unlock(&PRE_IVARS->retainCountSpinlock)); + OFEnsure(OFSpinlockUnlock(&PRE_IVARS->retainCountSpinlock) == 0); #endif return self; } @@ -1317,14 +1142,14 @@ } - (void)release { #if defined(OF_HAVE_ATOMIC_OPS) - of_memory_barrier_release(); + OFReleaseMemoryBarrier(); - if (of_atomic_int_dec(&PRE_IVARS->retainCount) <= 0) { - of_memory_barrier_acquire(); + if (OFAtomicIntDecrease(&PRE_IVARS->retainCount) <= 0) { + OFAcquireMemoryBarrier(); [self dealloc]; } #elif defined(OF_AMIGAOS) int retainCount; @@ -1336,13 +1161,13 @@ if (retainCount == 0) [self dealloc]; #else int retainCount; - OF_ENSURE(of_spinlock_lock(&PRE_IVARS->retainCountSpinlock)); + OFEnsure(OFSpinlockLock(&PRE_IVARS->retainCountSpinlock) == 0); retainCount = --PRE_IVARS->retainCount; - OF_ENSURE(of_spinlock_unlock(&PRE_IVARS->retainCountSpinlock)); + OFEnsure(OFSpinlockUnlock(&PRE_IVARS->retainCountSpinlock) == 0); if (retainCount == 0) [self dealloc]; #endif } @@ -1374,29 +1199,12 @@ return true; } - (void)dealloc { - struct pre_mem *iter; - objc_destructInstance(self); - iter = PRE_IVARS->firstMem; - while (iter != NULL) { - struct pre_mem *next = iter->next; - - /* - * We can use owner as a sentinel to prevent exploitation in - * case there is a buffer underflow somewhere. - */ - OF_ENSURE(iter->owner == self); - - free(iter); - - iter = next; - } - free((char *)self - PRE_IVARS_ALIGN); } /* Required to use properties with the Apple runtime */ - (id)copyWithZone: (void *)zone @@ -1418,41 +1226,14 @@ return [(id)self mutableCopy]; } /* - * Those are needed as the root class is the superclass of the root class's - * metaclass and thus instance methods can be sent to class objects as well. + * The following are needed as the root class is the superclass of the root + * class's metaclass and thus instance methods can be sent to class objects as + * well. */ -+ (void *)allocMemoryWithSize: (size_t)size -{ - OF_UNRECOGNIZED_SELECTOR -} - -+ (void *)allocMemoryWithSize: (size_t)size - count: (size_t)count -{ - OF_UNRECOGNIZED_SELECTOR -} - -+ (void *)resizeMemory: (void *)pointer - size: (size_t)size -{ - OF_UNRECOGNIZED_SELECTOR -} - -+ (void *)resizeMemory: (void *)pointer - size: (size_t)size - count: (size_t)count -{ - OF_UNRECOGNIZED_SELECTOR -} - -+ (void)freeMemory: (void *)pointer -{ - OF_UNRECOGNIZED_SELECTOR -} + (id)retain { return self; } @@ -1462,11 +1243,11 @@ return self; } + (unsigned int)retainCount { - return OF_RETAIN_COUNT_MAX; + return OFMaxRetainCount; } + (void)release { } ADDED src/OFOnce.h Index: src/OFOnce.h ================================================================== --- /dev/null +++ src/OFOnce.h @@ -0,0 +1,46 @@ +/* + * 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 "objfw-defs.h" + +#include "platform.h" + +#if defined(OF_HAVE_PTHREADS) +# include +typedef pthread_once_t OFOnceControl; +# define OFOnceControlInitValue PTHREAD_ONCE_INIT +#elif defined(OF_HAVE_ATOMIC_OPS) +typedef volatile int OFOnceControl; +# define OFOnceControlInitValue 0 +#elif defined(OF_AMIGAOS) || !defined(OF_HAVE_THREADS) +typedef int OFOnceControl; +# define OFOnceControlInitValue 0 +#endif + +#ifdef __cplusplus +extern "C" { +#endif +/** + * @brief Executes the specified function exactly once in the application's + * lifetime, even in a multi-threaded environment. + * + * @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)); +#ifdef __cplusplus +} +#endif ADDED src/OFOnce.m Index: src/OFOnce.m ================================================================== --- /dev/null +++ src/OFOnce.m @@ -0,0 +1,84 @@ +/* + * 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 "OFOnce.h" +#if defined(OF_HAVE_THREADS) && defined(OF_HAVE_ATOMIC_OPS) +# import "OFAtomic.h" +# import "OFPlainMutex.h" +#endif + +#ifdef OF_AMIGAOS +# include +#endif + +void +OFOnce(OFOnceControl *control, void (*function)(void)) +{ +#if !defined(OF_HAVE_THREADS) + if (*control == 0) { + function(); + *control = 1; + } +#elif defined(OF_HAVE_PTHREADS) + pthread_once(control, function); +#elif defined(OF_HAVE_ATOMIC_OPS) + /* Avoid atomic operations in case it's already done. */ + if (*control == 2) + return; + + if (OFAtomicIntCompareAndSwap(control, 0, 1)) { + function(); + + OFMemoryBarrier(); + + OFAtomicIntIncrease(control); + } else + while (*control == 1) + OFYieldThread(); +#elif defined(OF_AMIGAOS) + bool run = false; + + /* Avoid Forbid() in case it's already done. */ + if (*control == 2) + return; + + Forbid(); + + switch (*control) { + case 0: + *control = 1; + run = true; + break; + case 1: + while (*control == 1) { + Permit(); + Forbid(); + } + } + + Permit(); + + if (run) { + function(); + *control = 2; + } +#else +# error No OFOnce available +#endif +} Index: src/OFOptionsParser.h ================================================================== --- src/OFOptionsParser.h +++ src/OFOptionsParser.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -21,17 +19,17 @@ @class OFMapTable; OF_ASSUME_NONNULL_BEGIN /** - * @struct of_options_parser_option_t OFOptionsParser.h ObjFW/OFOptionsParser.h + * @struct OFOptionsParserOption OFOptionsParser.h ObjFW/OFOptionsParser.h * * @brief An option which can be parsed by an @ref OFOptionsParser. */ -struct of_options_parser_option_t { +typedef struct { /** The short version (e.g. `-v`) of the option or `\0` for none. */ - of_unichar_t shortOption; + OFUnichar shortOption; /** * The long version (e.g. `--verbose`) of the option or `nil` for none. */ OFString *__unsafe_unretained _Nullable longOption; @@ -57,26 +55,25 @@ /** * An optional pointer to an `OFString *` that is set to the * argument specified for the option or `nil` for no argument. */ OFString *__autoreleasing _Nullable *_Nullable argumentPtr; -}; -typedef struct of_options_parser_option_t of_options_parser_option_t; +} OFOptionsParserOption; /** * @class OFOptionsParser OFOptionsParser.h ObjFW/OFOptionsParser.h * * @brief A class for parsing the program options specified on the command line. */ OF_SUBCLASSING_RESTRICTED @interface OFOptionsParser: OFObject { - of_options_parser_option_t *_options; + OFOptionsParserOption *_options; OFMapTable *_longOptions; OFArray OF_GENERIC(OFString *) *_arguments; size_t _index, _subIndex; - of_unichar_t _lastOption; + OFUnichar _lastOption; OFString *_Nullable _lastLongOption, *_Nullable _argument; bool _done; } /** @@ -85,11 +82,11 @@ * If @ref nextOption returned `?` or `:`, this returns the option which was * unknown or for which the argument was missing.@n * If this returns `-`, the last option is only available as a long option (see * lastLongOption). */ -@property (readonly, nonatomic) of_unichar_t lastOption; +@property (readonly, nonatomic) OFUnichar lastOption; /** * @brief The long option for the last parsed option, or `nil` if the last * parsed option was not passed as a long option by the user. * @@ -119,31 +116,31 @@ OFArray OF_GENERIC(OFString *) *remainingArguments; /** * @brief Creates a new OFOptionsParser which accepts the specified options. * - * @param options An array of @ref of_options_parser_option_t specifying all + * @param options An array of @ref OFOptionsParserOption specifying all * accepted options, terminated with an option whose short * option is `\0` and long option is `nil`. * * @return A new, autoreleased OFOptionsParser */ -+ (instancetype)parserWithOptions: (const of_options_parser_option_t *)options; ++ (instancetype)parserWithOptions: (const OFOptionsParserOption *)options; - (instancetype)init OF_UNAVAILABLE; /** * @brief Initializes an already allocated OFOptionsParser so that it accepts * the specified options. * - * @param options An array of @ref of_options_parser_option_t specifying all + * @param options An array of @ref OFOptionsParserOption specifying all * accepted options, terminated with an option whose short * option is `\0` and long option is `nil`. * * @return An initialized OFOptionsParser */ -- (instancetype)initWithOptions: (const of_options_parser_option_t *)options +- (instancetype)initWithOptions: (const OFOptionsParserOption *)options OF_DESIGNATED_INITIALIZER; /** * @brief Returns the next option. * @@ -160,9 +157,9 @@ * make sure all options have been parsed, even if you only rely on the * optional pointers specified and don't do any parsing yourself. * * @return The next option */ -- (of_unichar_t)nextOption; +- (OFUnichar)nextOption; @end OF_ASSUME_NONNULL_END Index: src/OFOptionsParser.m ================================================================== --- src/OFOptionsParser.m +++ src/OFOptionsParser.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -38,33 +36,33 @@ @implementation OFOptionsParser @synthesize lastOption = _lastOption, lastLongOption = _lastLongOption; @synthesize argument = _argument; -+ (instancetype)parserWithOptions: (const of_options_parser_option_t *)options ++ (instancetype)parserWithOptions: (const OFOptionsParserOption *)options { return [[[self alloc] initWithOptions: options] autorelease]; } - (instancetype)init { OF_INVALID_INIT_METHOD } -- (instancetype)initWithOptions: (const of_options_parser_option_t *)options +- (instancetype)initWithOptions: (const OFOptionsParserOption *)options { self = [super init]; @try { size_t count = 0; - const of_options_parser_option_t *iter; - of_options_parser_option_t *iter2; - const of_map_table_functions_t keyFunctions = { + const OFOptionsParserOption *iter; + OFOptionsParserOption *iter2; + const OFMapTableFunctions keyFunctions = { .hash = stringHash, .equal = stringEqual }; - const of_map_table_functions_t objectFunctions = { NULL }; + const OFMapTableFunctions objectFunctions = { NULL }; /* Count, sanity check, initialize pointers */ for (iter = options; iter->shortOption != '\0' || iter->longOption != nil; iter++) { @@ -84,16 +82,14 @@ *iter->argumentPtr = nil; count++; } + _options = OFAllocMemory(count + 1, sizeof(*_options)); _longOptions = [[OFMapTable alloc] initWithKeyFunctions: keyFunctions objectFunctions: objectFunctions]; - _options = [self - allocMemoryWithSize: sizeof(*_options) - count: count + 1]; for (iter = options, iter2 = _options; iter->shortOption != '\0' || iter->longOption != nil; iter++, iter2++) { iter2->shortOption = iter->shortOption; @@ -142,29 +138,28 @@ return self; } - (void)dealloc { - of_options_parser_option_t *iter; - - [_longOptions release]; - if (_options != NULL) - for (iter = _options; + for (OFOptionsParserOption *iter = _options; iter->shortOption != '\0' || iter->longOption != nil; iter++) [iter->longOption release]; + + OFFreeMemory(_options); + [_longOptions release]; [_arguments release]; [_argument release]; [super dealloc]; } -- (of_unichar_t)nextOption +- (OFUnichar)nextOption { - of_options_parser_option_t *iter; + OFOptionsParserOption *iter; OFString *argument; if (_done || _index >= _arguments.count) return '\0'; @@ -189,24 +184,24 @@ } if ([argument hasPrefix: @"--"]) { void *pool = objc_autoreleasePoolPush(); size_t pos; - of_options_parser_option_t *option; + OFOptionsParserOption *option; _lastOption = '-'; _index++; if ((pos = [argument rangeOfString: @"="].location) != - OF_NOT_FOUND) + OFNotFound) _argument = [[argument substringFromIndex: pos + 1] copy]; else pos = argument.length; _lastLongOption = [[argument substringWithRange: - of_range(2, pos - 2)] copy]; + OFRangeMake(2, pos - 2)] copy]; objc_autoreleasePoolPop(pool); option = [_longOptions objectForKey: _lastLongOption]; if (option == NULL) @@ -274,8 +269,8 @@ } - (OFArray *)remainingArguments { return [_arguments objectsInRange: - of_range(_index, _arguments.count - _index)]; + OFRangeMake(_index, _arguments.count - _index)]; } @end ADDED src/OFPBKDF2.h Index: src/OFPBKDF2.h ================================================================== --- /dev/null +++ src/OFPBKDF2.h @@ -0,0 +1,76 @@ +/* + * 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. + */ + +#ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS +#endif +#ifndef __STDC_CONSTANT_MACROS +# define __STDC_CONSTANT_MACROS +#endif + +#import "macros.h" + +OF_ASSUME_NONNULL_BEGIN + +/** @file */ + +@class OFHMAC; + +/** + * @brief The parameters for @ref OFPBKDF2. + */ +typedef struct { + /** @brief The HMAC to use to derive a key. */ + __unsafe_unretained OFHMAC *HMAC; + /** @brief The number of iterations to perform. */ + size_t iterations; + /** @brief The salt to derive a key with. */ + const unsigned char *salt; + /** @brief The length of the salt. */ + size_t saltLength; + /** @brief The password to derive a key from. */ + const char *password; + /** @brief The length of the password. */ + size_t passwordLength; + /** @brief The buffer to write the key to. */ + unsigned char *key; + /** + * @brief The desired length for the derived key. + * + * @ref key needs to have enough storage. + */ + size_t keyLength; + /** @brief Whether data may be stored in swappable memory. */ + bool allowsSwappableMemory; +} OFPBKDF2Parameters; + +#ifdef __cplusplus +extern "C" { +#endif +/** + * @brief Derives a key from a password and a salt using PBKDF2. + * + * @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 + */ +extern void OFPBKDF2(OFPBKDF2Parameters param); +#ifdef __cplusplus +} +#endif + +OF_ASSUME_NONNULL_END ADDED src/OFPBKDF2.m Index: src/OFPBKDF2.m ================================================================== --- /dev/null +++ src/OFPBKDF2.m @@ -0,0 +1,113 @@ +/* + * 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 "OFPBKDF2.h" +#import "OFHMAC.h" +#import "OFSecureData.h" + +#import "OFInvalidArgumentException.h" +#import "OFOutOfMemoryException.h" +#import "OFOutOfRangeException.h" + +void +OFPBKDF2(OFPBKDF2Parameters param) +{ + void *pool = objc_autoreleasePoolPush(); + size_t blocks, digestSize = param.HMAC.digestSize; + OFSecureData *buffer = [OFSecureData + dataWithCount: digestSize + allowsSwappableMemory: param.allowsSwappableMemory]; + OFSecureData *digest = [OFSecureData + dataWithCount: digestSize + allowsSwappableMemory: param.allowsSwappableMemory]; + unsigned char *bufferItems = buffer.mutableItems; + unsigned char *digestItems = digest.mutableItems; + OFSecureData *extendedSalt; + unsigned char *extendedSaltItems; + + if (param.HMAC == nil || param.iterations == 0 || param.salt == NULL || + param.password == NULL || param.key == NULL || param.keyLength == 0) + @throw [OFInvalidArgumentException exception]; + + blocks = param.keyLength / digestSize; + if (param.keyLength % digestSize != 0) + blocks++; + + if (param.saltLength > SIZE_MAX - 4 || blocks > UINT32_MAX) + @throw [OFOutOfRangeException exception]; + + extendedSalt = [OFSecureData + dataWithCount: param.saltLength + 4 + allowsSwappableMemory: param.allowsSwappableMemory]; + extendedSaltItems = extendedSalt.mutableItems; + + @try { + uint32_t i = OFToBigEndian32(1); + + [param.HMAC setKey: param.password + length: param.passwordLength]; + + memcpy(extendedSaltItems, param.salt, param.saltLength); + + while (param.keyLength > 0) { + size_t length; + + memcpy(extendedSaltItems + param.saltLength, &i, 4); + + [param.HMAC reset]; + [param.HMAC updateWithBuffer: extendedSaltItems + length: param.saltLength + 4]; + [param.HMAC calculate]; + memcpy(bufferItems, param.HMAC.digest, digestSize); + memcpy(digestItems, param.HMAC.digest, digestSize); + + for (size_t j = 1; j < param.iterations; j++) { + [param.HMAC reset]; + [param.HMAC updateWithBuffer: digestItems + length: digestSize]; + [param.HMAC calculate]; + memcpy(digestItems, param.HMAC.digest, + digestSize); + + for (size_t k = 0; k < digestSize; k++) + bufferItems[k] ^= digestItems[k]; + } + + length = digestSize; + if (length > param.keyLength) + length = param.keyLength; + + memcpy(param.key, bufferItems, length); + param.key += length; + param.keyLength -= length; + + i = OFToBigEndian32(OFFromBigEndian32(i) + 1); + } + } @catch (id e) { + [extendedSalt zero]; + [buffer zero]; + [digest zero]; + + @throw e; + } @finally { + [param.HMAC zero]; + } + + objc_autoreleasePoolPop(pool); +} Index: src/OFPair.h ================================================================== --- src/OFPair.h +++ src/OFPair.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFPair.m ================================================================== --- src/OFPair.m +++ src/OFPair.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -85,18 +83,18 @@ return true; } - (unsigned long)hash { - uint32_t hash; - - OF_HASH_INIT(hash); - - OF_HASH_ADD_HASH(hash, [_firstObject hash]); - OF_HASH_ADD_HASH(hash, [_secondObject hash]); - - OF_HASH_FINALIZE(hash); + unsigned long hash; + + OFHashInit(&hash); + + OFHashAddHash(&hash, [_firstObject hash]); + OFHashAddHash(&hash, [_secondObject hash]); + + OFHashFinalize(&hash); return hash; } - (id)copy ADDED src/OFPlainCondition.h Index: src/OFPlainCondition.h ================================================================== --- /dev/null +++ src/OFPlainCondition.h @@ -0,0 +1,68 @@ +/* + * 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 "objfw-defs.h" + +#include "platform.h" + +#if !defined(OF_HAVE_THREADS) || \ + (!defined(OF_HAVE_PTHREADS) && !defined(OF_WINDOWS) && !defined(OF_AMIGAOS)) +# error No conditions available! +#endif + +/* For OFTimeInterval */ +#import "OFObject.h" +#import "OFPlainMutex.h" + +#if defined(OF_HAVE_PTHREADS) +# include +typedef pthread_cond_t OFPlainCondition; +#elif defined(OF_WINDOWS) +# include +typedef struct { + HANDLE event; + volatile int count; +} OFPlainCondition; +#elif defined(OF_AMIGAOS) +# include +typedef struct { + struct OFPlainConditionWaitingTask { + struct Task *task; + unsigned char sigBit; + struct OFPlainConditionWaitingTask *next; + } *waitingTasks; +} OFPlainCondition; +#endif + +#ifdef __cplusplus +extern "C" { +#endif +extern int OFPlainConditionNew(OFPlainCondition *condition); +extern int OFPlainConditionSignal(OFPlainCondition *condition); +extern int OFPlainConditionBroadcast(OFPlainCondition *condition); +extern int OFPlainConditionWait(OFPlainCondition *condition, + OFPlainMutex *mutex); +extern int OFPlainConditionTimedWait(OFPlainCondition *condition, + OFPlainMutex *mutex, OFTimeInterval timeout); +#ifdef OF_AMIGAOS +extern int OFPlainConditionWaitOrExecSignal(OFPlainCondition *condition, + OFPlainMutex *mutex, ULONG *signalMask); +extern int OFPlainConditionTimedWaitOrExecSignal(OFPlainCondition *condition, + OFPlainMutex *mutex, OFTimeInterval timeout, ULONG *signalMask); +#endif +extern int OFPlainConditionFree(OFPlainCondition *condition); +#ifdef __cplusplus +} +#endif ADDED src/OFPlainCondition.m Index: src/OFPlainCondition.m ================================================================== --- /dev/null +++ src/OFPlainCondition.m @@ -0,0 +1,26 @@ +/* + * 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" + +#if defined(OF_HAVE_PTHREADS) +# include "platform/POSIX/OFPlainCondition.m" +#elif defined(OF_WINDOWS) +# include "platform/Windows/OFPlainCondition.m" +#elif defined(OF_AMIGAOS) +# include "platform/AmigaOS/OFPlainCondition.m" +#endif ADDED src/OFPlainMutex.h Index: src/OFPlainMutex.h ================================================================== --- /dev/null +++ src/OFPlainMutex.h @@ -0,0 +1,170 @@ +/* + * 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 "objfw-defs.h" + +#include + +#include "platform.h" + +#if !defined(OF_HAVE_THREADS) || \ + (!defined(OF_HAVE_PTHREADS) && !defined(OF_WINDOWS) && !defined(OF_AMIGAOS)) +# error No mutexes available! +#endif + +#import "macros.h" + +#if defined(OF_HAVE_PTHREADS) +# include +typedef pthread_mutex_t OFPlainMutex; +#elif defined(OF_WINDOWS) +# include +typedef CRITICAL_SECTION OFPlainMutex; +#elif defined(OF_AMIGAOS) +# include +typedef struct SignalSemaphore OFPlainMutex; +#endif + +#if defined(OF_HAVE_ATOMIC_OPS) +# import "OFAtomic.h" +typedef volatile int OFSpinlock; +#elif defined(OF_HAVE_PTHREAD_SPINLOCKS) +typedef pthread_spinlock_t OFSpinlock; +#else +typedef OFPlainMutex OFSpinlock; +#endif + +#ifdef OF_HAVE_SCHED_YIELD +# include +#endif + +#if defined(OF_HAVE_RECURSIVE_PTHREAD_MUTEXES) || defined(OF_WINDOWS) || \ + defined(OF_AMIGAOS) +# define OFPlainRecursiveMutex OFPlainMutex +#else +# import "OFTLSKey.h" +typedef struct { + OFPlainMutex mutex; + OFTLSKey count; +} OFPlainRecursiveMutex; +#endif + +#ifdef __cplusplus +extern "C" { +#endif +extern int OFPlainMutexNew(OFPlainMutex *mutex); +extern int OFPlainMutexLock(OFPlainMutex *mutex); +extern int OFPlainMutexTryLock(OFPlainMutex *mutex); +extern int OFPlainMutexUnlock(OFPlainMutex *mutex); +extern int OFPlainMutexFree(OFPlainMutex *mutex); +extern int OFPlainRecursiveMutexNew(OFPlainRecursiveMutex *rmutex); +extern int OFPlainRecursiveMutexLock(OFPlainRecursiveMutex *rmutex); +extern int OFPlainRecursiveMutexTryLock(OFPlainRecursiveMutex *rmutex); +extern int OFPlainRecursiveMutexUnlock(OFPlainRecursiveMutex *rmutex); +extern int OFPlainRecursiveMutexFree(OFPlainRecursiveMutex *rmutex); +#ifdef __cplusplus +} +#endif + +/* Spinlocks are inlined for performance. */ + +static OF_INLINE void +OFYieldThread(void) +{ +#if defined(OF_HAVE_SCHED_YIELD) + sched_yield(); +#elif defined(OF_WINDOWS) + Sleep(0); +#endif +} + +static OF_INLINE int +OFSpinlockNew(OFSpinlock *spinlock) +{ +#if defined(OF_HAVE_ATOMIC_OPS) + *spinlock = 0; + return 0; +#elif defined(OF_HAVE_PTHREAD_SPINLOCKS) + return pthread_spin_init(spinlock, 0); +#else + return OFPlainMutexNew(spinlock); +#endif +} + +static OF_INLINE int +OFSpinlockTryLock(OFSpinlock *spinlock) +{ +#if defined(OF_HAVE_ATOMIC_OPS) + if (OFAtomicIntCompareAndSwap(spinlock, 0, 1)) { + OFAcquireMemoryBarrier(); + return 0; + } + + return EBUSY; +#elif defined(OF_HAVE_PTHREAD_SPINLOCKS) + return pthread_spin_trylock(spinlock); +#else + return OFPlainMutexTryLock(spinlock); +#endif +} + +static OF_INLINE int +OFSpinlockLock(OFSpinlock *spinlock) +{ +#if defined(OF_HAVE_ATOMIC_OPS) + size_t i; + + for (i = 0; i < 10; i++) + if (OFSpinlockTryLock(spinlock) == 0) + return 0; + + while (OFSpinlockTryLock(spinlock) == EBUSY) + OFYieldThread(); + + return 0; +#elif defined(OF_HAVE_PTHREAD_SPINLOCKS) + return pthread_spin_lock(spinlock); +#else + return OFPlainMutexLock(spinlock); +#endif +} + +static OF_INLINE int +OFSpinlockUnlock(OFSpinlock *spinlock) +{ +#if defined(OF_HAVE_ATOMIC_OPS) + bool ret = OFAtomicIntCompareAndSwap(spinlock, 1, 0); + + OFReleaseMemoryBarrier(); + + return (ret ? 0 : EINVAL); +#elif defined(OF_HAVE_PTHREAD_SPINLOCKS) + return pthread_spin_unlock(spinlock); +#else + return OFPlainMutexUnlock(spinlock); +#endif +} + +static OF_INLINE int +OFSpinlockFree(OFSpinlock *spinlock) +{ +#if defined(OF_HAVE_ATOMIC_OPS) + return 0; +#elif defined(OF_HAVE_PTHREAD_SPINLOCKS) + return pthread_spin_destroy(spinlock); +#else + return OFPlainMutexFree(spinlock); +#endif +} ADDED src/OFPlainMutex.m Index: src/OFPlainMutex.m ================================================================== --- /dev/null +++ src/OFPlainMutex.m @@ -0,0 +1,26 @@ +/* + * 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" + +#if defined(OF_HAVE_PTHREADS) +# include "platform/POSIX/OFPlainMutex.m" +#elif defined(OF_WINDOWS) +# include "platform/Windows/OFPlainMutex.m" +#elif defined(OF_AMIGAOS) +# include "platform/AmigaOS/OFPlainMutex.m" +#endif ADDED src/OFPlainThread.h Index: src/OFPlainThread.h ================================================================== --- /dev/null +++ src/OFPlainThread.h @@ -0,0 +1,92 @@ +/* + * 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 "objfw-defs.h" + +#include "platform.h" + +#if !defined(OF_HAVE_THREADS) || \ + (!defined(OF_HAVE_PTHREADS) && !defined(OF_WINDOWS) && !defined(OF_AMIGAOS)) +# error No threads available! +#endif + +#import "macros.h" + +#if defined(OF_HAVE_PTHREADS) +# include +typedef pthread_t OFPlainThread; +#elif defined(OF_WINDOWS) +# include +typedef HANDLE OFPlainThread; +#elif defined(OF_AMIGAOS) +# include +# include +typedef struct { + struct Task *task; + void (*function)(id); + id object; + struct SignalSemaphore semaphore; + struct Task *joinTask; + unsigned char joinSigBit; + bool detached, done; +} *OFPlainThread; +#endif + +typedef struct { + float priority; + size_t stackSize; +} OFPlainThreadAttributes; + +#if defined(OF_HAVE_PTHREADS) +static OF_INLINE OFPlainThread +OFCurrentPlainThread(void) +{ + return pthread_self(); +} + +static OF_INLINE bool +OFPlainThreadIsCurrent(OFPlainThread thread) +{ + return pthread_equal(thread, pthread_self()); +} +#elif defined(OF_WINDOWS) +static OF_INLINE OFPlainThread +OFCurrentPlainThread(void) +{ + return GetCurrentThread(); +} + +static OF_INLINE bool +OFPlainThreadIsCurrent(OFPlainThread thread) +{ + return (thread == GetCurrentThread()); +} +#elif defined(OF_AMIGAOS) +extern OFPlainThread OFCurrentPlainThread(void); +extern bool OFPlainThreadIsCurrent(OFPlainThread); +#endif + +#ifdef __cplusplus +extern "C" { +#endif +extern int OFPlainThreadAttributesInit(OFPlainThreadAttributes *attr); +extern int OFPlainThreadNew(OFPlainThread *thread, const char *name, + void (*function)(id), id object, const OFPlainThreadAttributes *attr); +extern void OFSetThreadName(const char *name); +extern int OFPlainThreadJoin(OFPlainThread thread); +extern int OFPlainThreadDetach(OFPlainThread thread); +#ifdef __cplusplus +} +#endif ADDED src/OFPlainThread.m Index: src/OFPlainThread.m ================================================================== --- /dev/null +++ src/OFPlainThread.m @@ -0,0 +1,26 @@ +/* + * 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" + +#if defined(OF_HAVE_PTHREADS) +# include "platform/POSIX/OFPlainThread.m" +#elif defined(OF_WINDOWS) +# include "platform/Windows/OFPlainThread.m" +#elif defined(OF_AMIGAOS) +# include "platform/AmigaOS/OFPlainThread.m" +#endif Index: src/OFPlugin.h ================================================================== --- src/OFPlugin.h +++ src/OFPlugin.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -19,49 +17,65 @@ @class OFString; #ifndef OF_WINDOWS # include -# define OF_RTLD_LAZY RTLD_LAZY -# define OF_RTLD_NOW RTLD_NOW -typedef void *of_plugin_handle_t; +typedef void *OFPluginHandle; #else # include -# define OF_RTLD_LAZY 0 -# define OF_RTLD_NOW 0 -typedef HMODULE of_plugin_handle_t; +typedef HMODULE OFPluginHandle; #endif OF_ASSUME_NONNULL_BEGIN /** * @class OFPlugin OFPlugin.h ObjFW/OFPlugin.h * - * @brief Provides a system for loading plugins at runtime. + * @brief A class representing a loaded plugin (shared library). + * */ +OF_SUBCLASSING_RESTRICTED @interface OFPlugin: OFObject { - of_plugin_handle_t _pluginHandle; - OF_RESERVE_IVARS(OFPlugin, 4) + OFPluginHandle _handle; } /** - * @brief Loads a plugin from a file. - * - * @param path Path to the plugin file. The suffix is appended automatically. - * @return The loaded plugin - */ -+ (OF_KINDOF(OFPlugin *))pluginFromFile: (OFString *)path; -@end - -#ifdef __cplusplus -extern "C" { -#endif -extern of_plugin_handle_t of_dlopen(OFString *path, int flags); -extern void *of_dlsym(of_plugin_handle_t handle, const char *symbol); -extern OFString *_Nullable of_dlerror(void); -extern void of_dlclose(of_plugin_handle_t handle); -#ifdef __cplusplus -} -#endif + * @brief Returns the plugin path for a plugin with the specified name. + * + * E.g. on ELF systems, it appends .so, while on macOS and iOS, it creates the + * appropriate plugin path. This can also be prefixed by a directory. + * + * @param name The name to return the plugin path for + * @return The plugin path + */ ++ (OFString *)pathForName: (OFString *)name; + +/** + * @brief Creates a new OFPlugin by loading the plugin with the specified path. + * + * @param path The path to the plugin file. The suffix is appended + * automatically. + * @return An new, autoreleased OFPlugin + */ ++ (instancetype)pluginWithPath: (OFString *)path; + +/** + * @brief Initializes an already allocated OFPlugin by loading the plugin with + * the specified path. + * + * @param path The path to the plugin file. The suffix is appended + * automatically. + * @return An initialized OFPlugin + */ +- (instancetype)initWithPath: (OFString *)path; + +/** + * @brief Returns the address for the specified symbol, or `nil` if not found. + * + * @param symbol The symbol to return the address for + * @return The address for the speccified symbol, or `nil` if not found + */ +- (nullable void *)addressForSymbol: (OFString *)symbol; +@end OF_ASSUME_NONNULL_END Index: src/OFPlugin.m ================================================================== --- src/OFPlugin.m +++ src/OFPlugin.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -30,116 +28,90 @@ #import "OFSystemInfo.h" #import "OFInitializationFailedException.h" #import "OFLoadPluginFailedException.h" -typedef OFPlugin *(*init_plugin_t)(void); - -of_plugin_handle_t -of_dlopen(OFString *path, int flags) -{ -#ifndef OF_WINDOWS - return dlopen([path cStringWithEncoding: [OFLocale encoding]], flags); -#else - if (path == nil) - return GetModuleHandle(NULL); - - if ([OFSystemInfo isWindowsNT]) - return LoadLibraryW(path.UTF16String); - else - return LoadLibraryA( - [path cStringWithEncoding: [OFLocale encoding]]); -#endif -} - -void * -of_dlsym(of_plugin_handle_t handle, const char *symbol) -{ -#ifndef OF_WINDOWS - return dlsym(handle, symbol); -#else - return (void *)(uintptr_t)GetProcAddress(handle, symbol); -#endif -} - -void -of_dlclose(of_plugin_handle_t handle) -{ -#ifndef OF_WINDOWS - dlclose(handle); -#else - FreeLibrary(handle); -#endif -} - -OFString * -of_dlerror(void) -{ -#ifndef OF_WINDOWS - return [OFString stringWithCString: dlerror() - encoding: [OFLocale encoding]]; -#else - return nil; -#endif -} - -@implementation OFPlugin -+ (id)pluginFromFile: (OFString *)path -{ - void *pool = objc_autoreleasePoolPush(); - of_plugin_handle_t handle; - init_plugin_t initPlugin; - OFPlugin *plugin; - -#if defined(OF_MACOS) - path = [path stringByAppendingFormat: @".bundle/Contents/MacOS/%@", - path.lastPathComponent]; -#elif defined(OF_IOS) - path = [path stringByAppendingFormat: @".bundle/%@", - path.lastPathComponent]; -#else - path = [path stringByAppendingString: @PLUGIN_SUFFIX]; -#endif - - if ((handle = of_dlopen(path, OF_RTLD_LAZY)) == NULL) - @throw [OFLoadPluginFailedException - exceptionWithPath: path - error: of_dlerror()]; - - objc_autoreleasePoolPop(pool); - - initPlugin = (init_plugin_t)(uintptr_t)of_dlsym(handle, "init_plugin"); - if (initPlugin == (init_plugin_t)0 || (plugin = initPlugin()) == nil) { - of_dlclose(handle); - @throw [OFInitializationFailedException - exceptionWithClass: self]; - } - - plugin->_pluginHandle = handle; - return plugin; -} - -- (instancetype)init -{ - if ([self isMemberOfClass: [OFPlugin class]]) { - @try { - [self doesNotRecognizeSelector: _cmd]; - } @catch (id e) { - [self release]; - @throw e; - } - - abort(); - } - - return [super init]; +#ifndef RTLD_LAZY +# define RTLD_LAZY 0 +#endif + +@implementation OFPlugin ++ (instancetype)pluginWithPath: (OFString *)path +{ + return [[[self alloc] initWithPath: path] autorelease]; +} + ++ (OFString *)pathForName: (OFString *)name +{ +#if defined(OF_MACOS) + return [name stringByAppendingFormat: @".bundle/Contents/MacOS/%@", + name.lastPathComponent]; +#elif defined(OF_IOS) + return [name stringByAppendingFormat: @".bundle/%@", + name.lastPathComponent]; +#else + return [name stringByAppendingString: @PLUGIN_SUFFIX]; +#endif +} + +- (instancetype)initWithPath: (OFString *)path +{ + self = [super init]; + + @try { + void *pool = objc_autoreleasePoolPush(); + +#ifndef OF_WINDOWS + _handle = dlopen( + [path cStringWithEncoding: [OFLocale encoding]], RTLD_LAZY); +#else + if ([OFSystemInfo isWindowsNT]) + _handle = LoadLibraryW(path.UTF16String); + else + _handle = LoadLibraryA( + [path cStringWithEncoding: [OFLocale encoding]]); +#endif + + if (_handle == NULL) { +#ifndef OF_WINDOWS + OFString *error = [OFString + stringWithCString: dlerror() + encoding: [OFLocale encoding]]; +#else + OFString *error = nil; +#endif + @throw [OFLoadPluginFailedException + exceptionWithPath: path + error: error]; + } + + objc_autoreleasePoolPop(pool); + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void *)addressForSymbol: (OFString *)symbol +{ +#ifndef OF_WINDOWS + return dlsym(_handle, + [symbol cStringWithEncoding: [OFLocale encoding]]); +#else + return (void *)(uintptr_t)GetProcAddress(_handle, + [symbol cStringWithEncoding: [OFLocale encoding]]); +#endif } - (void)dealloc { - of_plugin_handle_t h = _pluginHandle; +#ifndef OF_WINDOWS + dlclose(_handle); +#else + FreeLibrary(_handle); +#endif [super dealloc]; - - of_dlclose(h); } @end Index: src/OFPointValue.h ================================================================== --- src/OFPointValue.h +++ src/OFPointValue.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -19,10 +17,12 @@ OF_ASSUME_NONNULL_BEGIN @interface OFPointValue: OFValue { - of_point_t _point; + OFPoint _point; } + +- (instancetype)initWithPoint: (OFPoint)point; @end OF_ASSUME_NONNULL_END Index: src/OFPointValue.m ================================================================== --- src/OFPointValue.m +++ src/OFPointValue.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -22,11 +20,11 @@ #import "OFOutOfRangeException.h" @implementation OFPointValue @synthesize pointValue = _point; -- (instancetype)initWithPoint: (of_point_t)point +- (instancetype)initWithPoint: (OFPoint)point { self = [super init]; _point = point; @@ -33,15 +31,14 @@ return self; } - (const char *)objCType { - return @encode(of_point_t); + return @encode(OFPoint); } -- (void)getValue: (void *)value - size: (size_t)size +- (void)getValue: (void *)value size: (size_t)size { if (size != sizeof(_point)) @throw [OFOutOfRangeException exception]; memcpy(value, &_point, sizeof(_point)); @@ -48,8 +45,8 @@ } - (OFString *)description { return [OFString stringWithFormat: - @"", _point.x, _point.y]; + @"", _point.x, _point.y]; } @end Index: src/OFPointerValue.h ================================================================== --- src/OFPointerValue.h +++ src/OFPointerValue.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -21,8 +19,10 @@ @interface OFPointerValue: OFValue { void *_pointer; } + +- (instancetype)initWithPointer: (const void *)pointer; @end OF_ASSUME_NONNULL_END Index: src/OFPointerValue.m ================================================================== --- src/OFPointerValue.m +++ src/OFPointerValue.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -35,12 +33,11 @@ - (const char *)objCType { return @encode(void *); } -- (void)getValue: (void *)value - size: (size_t)size +- (void)getValue: (void *)value size: (size_t)size { if (size != sizeof(_pointer)) @throw [OFOutOfRangeException exception]; memcpy(value, &_pointer, sizeof(_pointer)); Index: src/OFPollKernelEventObserver.h ================================================================== --- src/OFPollKernelEventObserver.h +++ src/OFPollKernelEventObserver.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFPollKernelEventObserver.m ================================================================== --- src/OFPollKernelEventObserver.m +++ src/OFPollKernelEventObserver.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -26,16 +24,15 @@ # include #endif #import "OFPollKernelEventObserver.h" #import "OFData.h" +#import "OFSocket+Private.h" #import "OFObserveFailedException.h" #import "OFOutOfRangeException.h" -#import "socket_helpers.h" - #ifdef OF_WII # define pollfd pollsd # define fd socket #endif @@ -50,12 +47,11 @@ _FDs = [[OFMutableData alloc] initWithItemSize: sizeof(struct pollfd)]; [_FDs addItem: &p]; _maxFD = _cancelFD[0]; - _FDToObject = [self allocMemoryWithSize: sizeof(id) - count: (size_t)_maxFD + 1]; + _FDToObject = OFAllocMemory((size_t)_maxFD + 1, sizeof(id)); } @catch (id e) { [self release]; @throw e; } @@ -63,28 +59,28 @@ } - (void)dealloc { [_FDs release]; + OFFreeMemory(_FDToObject); [super dealloc]; } -- (void)of_addObject: (id)object - fileDescriptor: (int)fd - events: (short)events OF_DIRECT +static void +addObject(OFPollKernelEventObserver *self, id object, int fd, short events) { struct pollfd *FDs; size_t count; bool found; if (fd < 0) @throw [OFObserveFailedException exceptionWithObserver: self errNo: EBADF]; - FDs = _FDs.mutableItems; - count = _FDs.count; + FDs = self->_FDs.mutableItems; + count = self->_FDs.count; found = false; for (size_t i = 0; i < count; i++) { if (FDs[i].fd == fd) { FDs[i].events |= events; @@ -94,35 +90,33 @@ } if (!found) { struct pollfd p = { fd, events, 0 }; - if (fd > _maxFD) { - _maxFD = fd; - _FDToObject = [self resizeMemory: _FDToObject - size: sizeof(id) - count: (size_t)_maxFD + 1]; + if (fd > self->_maxFD) { + self->_maxFD = fd; + self->_FDToObject = OFResizeMemory(self->_FDToObject, + (size_t)self->_maxFD + 1, sizeof(id)); } - _FDToObject[fd] = object; - [_FDs addItem: &p]; + self->_FDToObject[fd] = object; + [self->_FDs addItem: &p]; } } -- (void)of_removeObject: (id)object - fileDescriptor: (int)fd - events: (short)events OF_DIRECT +static void +removeObject(OFPollKernelEventObserver *self, id object, int fd, short events) { struct pollfd *FDs; size_t nFDs; if (fd < 0) @throw [OFObserveFailedException exceptionWithObserver: self errNo: EBADF]; - FDs = _FDs.mutableItems; - nFDs = _FDs.count; + FDs = self->_FDs.mutableItems; + nFDs = self->_FDs.count; for (size_t i = 0; i < nFDs; i++) { if (FDs[i].fd == fd) { FDs[i].events &= ~events; @@ -129,55 +123,47 @@ if (FDs[i].events == 0) { /* * TODO: Remove from and resize _FDToObject, * adjust _maxFD. */ - [_FDs removeItemAtIndex: i]; + [self->_FDs removeItemAtIndex: i]; } break; } } } - (void)addObjectForReading: (id )object { - [self of_addObject: object - fileDescriptor: object.fileDescriptorForReading - events: POLLIN]; + addObject(self, object, object.fileDescriptorForReading, POLLIN); [super addObjectForReading: object]; } - (void)addObjectForWriting: (id )object { - [self of_addObject: object - fileDescriptor: object.fileDescriptorForWriting - events: POLLOUT]; + addObject(self, object, object.fileDescriptorForWriting, POLLOUT); [super addObjectForWriting: object]; } - (void)removeObjectForReading: (id )object { - [self of_removeObject: object - fileDescriptor: object.fileDescriptorForReading - events: POLLIN]; + removeObject(self, object, object.fileDescriptorForReading, POLLIN); [super removeObjectForReading: object]; } - (void)removeObjectForWriting: (id )object { - [self of_removeObject: object - fileDescriptor: object.fileDescriptorForWriting - events: POLLOUT]; + removeObject(self, object, object.fileDescriptorForWriting, POLLOUT); [super removeObjectForWriting: object]; } -- (void)observeForTimeInterval: (of_time_interval_t)timeInterval +- (void)observeForTimeInterval: (OFTimeInterval)timeInterval { void *pool; struct pollfd *FDs; int events; size_t nFDs; @@ -210,14 +196,14 @@ if (FDs[i].fd == _cancelFD[0]) { char buffer; #ifdef OF_HAVE_PIPE - OF_ENSURE(read(_cancelFD[0], &buffer, 1) == 1); + OFEnsure(read(_cancelFD[0], &buffer, 1) == 1); #else - OF_ENSURE(recvfrom(_cancelFD[0], &buffer, 1, - 0, NULL, NULL) == 1); + OFEnsure(recvfrom(_cancelFD[0], &buffer, 1, 0, + NULL, NULL) == 1); #endif FDs[i].revents = 0; continue; } DELETED src/OFProcess.h Index: src/OFProcess.h ================================================================== --- src/OFProcess.h +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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. - */ - -#ifndef __STDC_LIMIT_MACROS -# define __STDC_LIMIT_MACROS -#endif -#ifndef __STDC_CONSTANT_MACROS -# define __STDC_CONSTANT_MACROS -#endif - -#include "objfw-defs.h" - -#ifdef OF_HAVE_SYS_TYPES_H -# include -#endif - -#import "OFStream.h" -#import "OFKernelEventObserver.h" -#import "OFString.h" - -#ifdef OF_WINDOWS -# include -#endif - -OF_ASSUME_NONNULL_BEGIN - -@class OFArray OF_GENERIC(ObjectType); -@class OFDictionary OF_GENERIC(KeyType, ObjectType); - -/** - * @class OFProcess OFProcess.h ObjFW/OFProcess.h - * - * @brief A class for stream-like communication with a newly created process. - */ -OF_SUBCLASSING_RESTRICTED -@interface OFProcess: OFStream -#ifndef OF_WINDOWS - -#endif -{ -#ifndef OF_WINDOWS - pid_t _pid; - int _readPipe[2], _writePipe[2]; -#else - HANDLE _process, _readPipe[2], _writePipe[2]; -#endif - int _status; - bool _atEndOfStream; -} - -/** - * @brief Creates a new OFProcess with the specified program and invokes the - * program. - * - * @param program The program to execute. If it does not start with a slash, the - * search path specified in PATH is used. - * @return A new, autoreleased OFProcess. - */ -+ (instancetype)processWithProgram: (OFString *)program; - -/** - * @brief Creates a new OFProcess with the specified program and arguments and - * invokes the program. - * - * @param program The program to execute. If it does not start with a slash, the - * search path specified in PATH is used. - * @param arguments The arguments to pass to the program, or `nil` - * @return A new, autoreleased OFProcess. - */ -+ (instancetype) - processWithProgram: (OFString *)program - arguments: (nullable OFArray OF_GENERIC(OFString *) *)arguments; - -/** - * @brief Creates a new OFProcess with the specified program, program name and - * arguments and invokes the program. - * - * @param program The program to execute. If it does not start with a slash, the - * search path specified in PATH is used. - * @param programName The program name for the program to invoke (argv[0]). - * Usually, this is equal to program. - * @param arguments The arguments to pass to the program, or `nil` - * @return A new, autoreleased OFProcess. - */ -+ (instancetype) - processWithProgram: (OFString *)program - programName: (OFString *)programName - arguments: (nullable OFArray OF_GENERIC(OFString *) *)arguments; - -/** - * @brief Creates a new OFProcess with the specified program, program name, - * arguments and environment and invokes the program. - * - * @param program The program to execute. If it does not start with a slash, the - * search path specified in PATH is used. - * @param programName The program name for the program to invoke (argv[0]). - * Usually, this is equal to program. - * @param arguments The arguments to pass to the program, or `nil` - * @param environment The environment to pass to the program, or `nil`. If it - * is not `nil`, the passed dictionary will be used to - * override the environment. If you want to add to the - * existing environment, you need to get the existing - * environment first, copy it, modify it and then pass it. - * @return A new, autoreleased OFProcess. - */ -+ (instancetype) - processWithProgram: (OFString *)program - programName: (OFString *)programName - arguments: (nullable OFArray OF_GENERIC(OFString *) *)arguments - environment: (nullable OFDictionary - OF_GENERIC(OFString *, OFString *) *)environment; - -- (instancetype)init OF_UNAVAILABLE; - -/** - * @brief Initializes an already allocated OFProcess with the specified program - * and invokes the program. - * - * @param program The program to execute. If it does not start with a slash, the - * search path specified in PATH is used. - * @return An initialized OFProcess. - */ -- (instancetype)initWithProgram: (OFString *)program; - -/** - * @brief Initializes an already allocated OFProcess with the specified program - * and arguments and invokes the program. - * - * @param program The program to execute. If it does not start with a slash, the - * search path specified in PATH is used. - * @param arguments The arguments to pass to the program, or `nil` - * @return An initialized OFProcess. - */ -- (instancetype) - initWithProgram: (OFString *)program - arguments: (nullable OFArray OF_GENERIC(OFString *) *)arguments; - -/** - * @brief Initializes an already allocated OFProcess with the specified program, - * program name and arguments and invokes the program. - * - * @param program The program to execute. If it does not start with a slash, the - * search path specified in PATH is used. - * @param programName The program name for the program to invoke (argv[0]). - * Usually, this is equal to program. - * @param arguments The arguments to pass to the program, or `nil` - * @return An initialized OFProcess. - */ -- (instancetype) - initWithProgram: (OFString *)program - programName: (OFString *)programName - arguments: (nullable OFArray OF_GENERIC(OFString *) *)arguments; - -/** - * @brief Initializes an already allocated OFProcess with the specified program, - * program name, arguments and environment and invokes the program. - * - * @param program The program to execute. If it does not start with a slash, the - * search path specified in PATH is used. - * @param programName The program name for the program to invoke (argv[0]). - * Usually, this is equal to program. - * @param arguments The arguments to pass to the program, or `nil` - * @param environment The environment to pass to the program, or `nil`. If it - * is not `nil`, the passed dictionary will be used to - * override the environment. If you want to add to the - * existing environment, you need to get the existing - * environment first, copy it, modify it and then pass it. - * @return An initialized OFProcess. - */ -- (instancetype) - initWithProgram: (OFString *)program - programName: (OFString *)programName - arguments: (nullable OFArray OF_GENERIC(OFString *) *)arguments - environment: (nullable OFDictionary - OF_GENERIC(OFString *, OFString *) *)environment - OF_DESIGNATED_INITIALIZER; - -/** - * @brief Closes the write direction of the process. - * - * 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. - */ -- (void)closeForWriting; - -/** - * @brief Waits for the process to terminate and returns the exit status. - * - * If the process has already exited, this returns the exit status immediately. - */ -- (int)waitForTermination; -@end - -OF_ASSUME_NONNULL_END DELETED src/OFProcess.m Index: src/OFProcess.m ================================================================== --- src/OFProcess.m +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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" - -#ifdef OF_WINDOWS -# include "platform/windows/OFProcess.m" -#else -# include "platform/posix/OFProcess.m" -#endif Index: src/OFRIPEMD160Hash.h ================================================================== --- src/OFRIPEMD160Hash.h +++ src/OFRIPEMD160Hash.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -13,11 +11,11 @@ * 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 "OFCryptoHash.h" +#import "OFCryptographicHash.h" OF_ASSUME_NONNULL_BEGIN @class OFSecureData; @@ -25,17 +23,17 @@ * @class OFRIPEMD160Hash OFRIPEMD160Hash.h ObjFW/OFRIPEMD160Hash.h * * @brief A class which provides methods to create a RIPEMD-160 hash. */ OF_SUBCLASSING_RESTRICTED -@interface OFRIPEMD160Hash: OFObject +@interface OFRIPEMD160Hash: OFObject { OFSecureData *_iVarsData; - struct of_ripemd160_hash_ivars { + struct { uint32_t state[5]; uint64_t bits; - union of_ripemd160_hash_buffer { + union { unsigned char bytes[64]; uint32_t words[16]; } buffer; size_t bufferLength; } *_iVars; Index: src/OFRIPEMD160Hash.m ================================================================== --- src/OFRIPEMD160Hash.m +++ src/OFRIPEMD160Hash.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -21,14 +19,15 @@ #import "OFRIPEMD160Hash.h" #import "OFSecureData.h" #import "OFHashAlreadyCalculatedException.h" +#import "OFHashNotCalculatedException.h" #import "OFOutOfRangeException.h" -#define DIGEST_SIZE 20 -#define BLOCK_SIZE 64 +static const size_t digestSize = 20; +static const size_t blockSize = 64; OF_DIRECT_MEMBERS @interface OFRIPEMD160Hash () - (void)of_resetState; @end @@ -71,11 +70,11 @@ static OF_INLINE void byteSwapVectorIfBE(uint32_t *vector, uint_fast8_t length) { #ifdef OF_BIG_ENDIAN for (uint_fast8_t i = 0; i < length; i++) - vector[i] = OF_BSWAP32(vector[i]); + vector[i] = OFByteSwap32(vector[i]); #endif } static void processBlock(uint32_t *state, uint32_t *buffer) @@ -89,33 +88,33 @@ new[3] = new2[3] = state[3]; new[4] = new2[4] = state[4]; byteSwapVectorIfBE(buffer, 16); -#define LOOP_BODY(f, g, k, k2) \ - { \ - uint32_t tmp; \ - \ - tmp = new[0] + f(new[1], new[2], new[3]) + \ - buffer[wordOrder[i]] + k; \ - tmp = OF_ROL(tmp, rotateBits[i]) + new[4]; \ - \ - new[0] = new[4]; \ - new[4] = new[3]; \ - new[3] = OF_ROL(new[2], 10); \ - new[2] = new[1]; \ - new[1] = tmp; \ - \ - tmp = new2[0] + g(new2[1], new2[2], new2[3]) + \ - buffer[wordOrder2[i]] + k2; \ - tmp = OF_ROL(tmp, rotateBits2[i]) + new2[4]; \ - \ - new2[0] = new2[4]; \ - new2[4] = new2[3]; \ - new2[3] = OF_ROL(new2[2], 10); \ - new2[2] = new2[1]; \ - new2[1] = tmp; \ +#define LOOP_BODY(f, g, k, k2) \ + { \ + uint32_t tmp; \ + \ + tmp = new[0] + f(new[1], new[2], new[3]) + \ + buffer[wordOrder[i]] + k; \ + tmp = OFRotateLeft(tmp, rotateBits[i]) + new[4]; \ + \ + new[0] = new[4]; \ + new[4] = new[3]; \ + new[3] = OFRotateLeft(new[2], 10); \ + new[2] = new[1]; \ + new[1] = tmp; \ + \ + tmp = new2[0] + g(new2[1], new2[2], new2[3]) + \ + buffer[wordOrder2[i]] + k2; \ + tmp = OFRotateLeft(tmp, rotateBits2[i]) + new2[4]; \ + \ + new2[0] = new2[4]; \ + new2[4] = new2[3]; \ + new2[3] = OFRotateLeft(new2[2], 10); \ + new2[2] = new2[1]; \ + new2[1] = tmp; \ } for (; i < 16; i++) LOOP_BODY(F, J, 0x00000000, 0x50A28BE6) for (; i < 32; i++) @@ -141,19 +140,19 @@ @synthesize calculated = _calculated; @synthesize allowsSwappableMemory = _allowsSwappableMemory; + (size_t)digestSize { - return DIGEST_SIZE; + return digestSize; } + (size_t)blockSize { - return BLOCK_SIZE; + return blockSize; } -+ (instancetype)cryptoHashWithAllowsSwappableMemory: (bool)allowsSwappableMemory ++ (instancetype)hashWithAllowsSwappableMemory: (bool)allowsSwappableMemory { return [[[self alloc] initWithAllowsSwappableMemory: allowsSwappableMemory] autorelease]; } @@ -194,16 +193,16 @@ [super dealloc]; } - (size_t)digestSize { - return DIGEST_SIZE; + return digestSize; } - (size_t)blockSize { - return BLOCK_SIZE; + return blockSize; } - (id)copy { OFRIPEMD160Hash *copy = [[OFRIPEMD160Hash alloc] of_init]; @@ -223,12 +222,11 @@ _iVars->state[2] = 0x98BADCFE; _iVars->state[3] = 0x10325476; _iVars->state[4] = 0xC3D2E1F0; } -- (void)updateWithBuffer: (const void *)buffer_ - length: (size_t)length +- (void)updateWithBuffer: (const void *)buffer_ length: (size_t)length { const unsigned char *buffer = buffer_; if (_calculated) @throw [OFHashAlreadyCalculatedException @@ -259,39 +257,46 @@ } } - (const unsigned char *)digest { + if (!_calculated) + @throw [OFHashNotCalculatedException exceptionWithObject: self]; + + return (const unsigned char *)_iVars->state; +} + +- (void)calculate +{ if (_calculated) - return (const unsigned char *)_iVars->state; + @throw [OFHashAlreadyCalculatedException + exceptionWithObject: self]; _iVars->buffer.bytes[_iVars->bufferLength] = 0x80; - of_explicit_memset(_iVars->buffer.bytes + _iVars->bufferLength + 1, 0, + OFZeroMemory(_iVars->buffer.bytes + _iVars->bufferLength + 1, 64 - _iVars->bufferLength - 1); if (_iVars->bufferLength >= 56) { processBlock(_iVars->state, _iVars->buffer.words); - of_explicit_memset(_iVars->buffer.bytes, 0, 64); + OFZeroMemory(_iVars->buffer.bytes, 64); } _iVars->buffer.words[14] = - OF_BSWAP32_IF_BE((uint32_t)(_iVars->bits & 0xFFFFFFFF)); + OFToLittleEndian32((uint32_t)(_iVars->bits & 0xFFFFFFFF)); _iVars->buffer.words[15] = - OF_BSWAP32_IF_BE((uint32_t)(_iVars->bits >> 32)); + OFToLittleEndian32((uint32_t)(_iVars->bits >> 32)); processBlock(_iVars->state, _iVars->buffer.words); - of_explicit_memset(&_iVars->buffer, 0, sizeof(_iVars->buffer)); + OFZeroMemory(&_iVars->buffer, sizeof(_iVars->buffer)); byteSwapVectorIfBE(_iVars->state, 5); _calculated = true; - - return (const unsigned char *)_iVars->state; } - (void)reset { [self of_resetState]; _iVars->bits = 0; - of_explicit_memset(&_iVars->buffer, 0, sizeof(_iVars->buffer)); + OFZeroMemory(&_iVars->buffer, sizeof(_iVars->buffer)); _iVars->bufferLength = 0; _calculated = false; } @end Index: src/OFRangeCharacterSet.h ================================================================== --- src/OFRangeCharacterSet.h +++ src/OFRangeCharacterSet.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -19,10 +17,10 @@ OF_ASSUME_NONNULL_BEGIN @interface OFRangeCharacterSet: OFCharacterSet { - of_range_t _range; + OFRange _range; } @end OF_ASSUME_NONNULL_END Index: src/OFRangeCharacterSet.m ================================================================== --- src/OFRangeCharacterSet.m +++ src/OFRangeCharacterSet.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -26,11 +24,11 @@ - (instancetype)init { OF_INVALID_INIT_METHOD } -- (instancetype)initWithRange: (of_range_t)range +- (instancetype)initWithRange: (OFRange)range { self = [super init]; @try { if (SIZE_MAX - range.location < range.length) @@ -43,11 +41,11 @@ } return self; } -- (bool)characterIsMember: (of_unichar_t)character +- (bool)characterIsMember: (OFUnichar)character { return (character >= _range.location && character < _range.location + _range.length); } @end Index: src/OFRangeValue.h ================================================================== --- src/OFRangeValue.h +++ src/OFRangeValue.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -19,10 +17,12 @@ OF_ASSUME_NONNULL_BEGIN @interface OFRangeValue: OFValue { - of_range_t _range; + OFRange _range; } + +- (instancetype)initWithRange: (OFRange)range; @end OF_ASSUME_NONNULL_END Index: src/OFRangeValue.m ================================================================== --- src/OFRangeValue.m +++ src/OFRangeValue.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -22,11 +20,11 @@ #import "OFOutOfRangeException.h" @implementation OFRangeValue @synthesize rangeValue = _range; -- (instancetype)initWithRange: (of_range_t)range +- (instancetype)initWithRange: (OFRange)range { self = [super init]; _range = range; @@ -33,15 +31,14 @@ return self; } - (const char *)objCType { - return @encode(of_range_t); + return @encode(OFRange); } -- (void)getValue: (void *)value - size: (size_t)size +- (void)getValue: (void *)value size: (size_t)size { if (size != sizeof(_range)) @throw [OFOutOfRangeException exception]; memcpy(value, &_range, sizeof(_range)); @@ -48,9 +45,9 @@ } - (OFString *)description { return [OFString stringWithFormat: - @"", + @"", _range.location, _range.length]; } @end ADDED src/OFRectValue.h Index: src/OFRectValue.h ================================================================== --- /dev/null +++ src/OFRectValue.h @@ -0,0 +1,28 @@ +/* + * 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 "OFValue.h" + +OF_ASSUME_NONNULL_BEGIN + +@interface OFRectValue: OFValue +{ + OFRect _rect; +} + +- (instancetype)initWithRect: (OFRect)rect; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFRectValue.m Index: src/OFRectValue.m ================================================================== --- /dev/null +++ src/OFRectValue.m @@ -0,0 +1,54 @@ +/* + * 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 "OFRectValue.h" +#import "OFMethodSignature.h" +#import "OFString.h" + +#import "OFOutOfRangeException.h" + +@implementation OFRectValue +@synthesize rectValue = _rect; + +- (instancetype)initWithRect: (OFRect)rect +{ + self = [super init]; + + _rect = rect; + + return self; +} + +- (const char *)objCType +{ + return @encode(OFRect); +} + +- (void)getValue: (void *)value size: (size_t)size +{ + if (size != sizeof(_rect)) + @throw [OFOutOfRangeException exception]; + + memcpy(value, &_rect, sizeof(_rect)); +} + +- (OFString *)description +{ + return [OFString stringWithFormat: + @"", + _rect.origin.x, _rect.origin.y, + _rect.size.width, _rect.size.height]; +} +@end DELETED src/OFRectangleValue.h Index: src/OFRectangleValue.h ================================================================== --- src/OFRectangleValue.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "OFValue.h" - -OF_ASSUME_NONNULL_BEGIN - -@interface OFRectangleValue: OFValue -{ - of_rectangle_t _rectangle; -} -@end - -OF_ASSUME_NONNULL_END DELETED src/OFRectangleValue.m Index: src/OFRectangleValue.m ================================================================== --- src/OFRectangleValue.m +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "OFRectangleValue.h" -#import "OFMethodSignature.h" -#import "OFString.h" - -#import "OFOutOfRangeException.h" - -@implementation OFRectangleValue -@synthesize rectangleValue = _rectangle; - -- (instancetype)initWithRectangle: (of_rectangle_t)rectangle -{ - self = [super init]; - - _rectangle = rectangle; - - return self; -} - -- (const char *)objCType -{ - return @encode(of_rectangle_t); -} - -- (void)getValue: (void *)value - size: (size_t)size -{ - if (size != sizeof(_rectangle)) - @throw [OFOutOfRangeException exception]; - - memcpy(value, &_rectangle, sizeof(_rectangle)); -} - -- (OFString *)description -{ - return [OFString stringWithFormat: - @"", - _rectangle.origin.x, _rectangle.origin.y, - _rectangle.size.width, _rectangle.size.height]; -} -@end Index: src/OFRecursiveMutex.h ================================================================== --- src/OFRecursiveMutex.h +++ src/OFRecursiveMutex.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -15,12 +13,11 @@ * file. */ #import "OFObject.h" #import "OFLocking.h" - -#import "mutex.h" +#import "OFPlainMutex.h" OF_ASSUME_NONNULL_BEGIN /** * @class OFRecursiveMutex OFRecursiveMutex.h ObjFW/OFRecursiveMutex.h @@ -29,11 +26,11 @@ * recursively. */ OF_SUBCLASSING_RESTRICTED @interface OFRecursiveMutex: OFObject { - of_rmutex_t _rmutex; + OFPlainRecursiveMutex _rmutex; bool _initialized; OFString *_Nullable _name; } /** Index: src/OFRecursiveMutex.m ================================================================== --- src/OFRecursiveMutex.m +++ src/OFRecursiveMutex.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -37,11 +35,11 @@ - (instancetype)init { self = [super init]; - if (!of_rmutex_new(&_rmutex)) { + if (OFPlainRecursiveMutexNew(&_rmutex) != 0) { Class c = self.class; [self release]; @throw [OFInitializationFailedException exceptionWithClass: c]; } @@ -51,12 +49,14 @@ } - (void)dealloc { if (_initialized) { - if (!of_rmutex_free(&_rmutex)) { - OF_ENSURE(errno == EBUSY); + int error = OFPlainRecursiveMutexFree(&_rmutex); + + if (error != 0) { + OFEnsure(error == EBUSY); @throw [OFStillLockedException exceptionWithLock: self]; } } @@ -65,33 +65,39 @@ [super dealloc]; } - (void)lock { - if (!of_rmutex_lock(&_rmutex)) + int error = OFPlainRecursiveMutexLock(&_rmutex); + + if (error != 0) @throw [OFLockFailedException exceptionWithLock: self - errNo: errno]; + errNo: error]; } - (bool)tryLock { - if (!of_rmutex_trylock(&_rmutex)) { - if (errno == EBUSY) + int error = OFPlainRecursiveMutexTryLock(&_rmutex); + + if (error != 0) { + if (error == EBUSY) return false; else @throw [OFLockFailedException exceptionWithLock: self - errNo: errno]; + errNo: error]; } return true; } - (void)unlock { - if (!of_rmutex_unlock(&_rmutex)) + int error = OFPlainRecursiveMutexUnlock(&_rmutex); + + if (error != 0) @throw [OFUnlockFailedException exceptionWithLock: self - errNo: errno]; + errNo: error]; } - (OFString *)description { if (_name == nil) Index: src/OFRunLoop+Private.h ================================================================== --- src/OFRunLoop+Private.h +++ src/OFRunLoop+Private.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -39,99 +37,92 @@ #ifdef OF_HAVE_SOCKETS + (void)of_addAsyncReadForStream: (OFStream *) stream buffer: (void *)buffer length: (size_t)length - mode: (of_run_loop_mode_t)mode + mode: (OFRunLoopMode)mode # ifdef OF_HAVE_BLOCKS - block: (nullable of_stream_async_read_block_t)block + block: (nullable OFStreamAsyncReadBlock)block # endif delegate: (nullable id )delegate; + (void)of_addAsyncReadForStream: (OFStream *) stream buffer: (void *)buffer exactLength: (size_t)length - mode: (of_run_loop_mode_t)mode + mode: (OFRunLoopMode)mode # ifdef OF_HAVE_BLOCKS - block: (nullable of_stream_async_read_block_t)block + block: (nullable OFStreamAsyncReadBlock)block # endif delegate: (nullable id )delegate; + (void)of_addAsyncReadLineForStream: (OFStream *) stream - encoding: (of_string_encoding_t)encoding - mode: (of_run_loop_mode_t)mode + encoding: (OFStringEncoding)encoding + mode: (OFRunLoopMode)mode # ifdef OF_HAVE_BLOCKS - block: (nullable - of_stream_async_read_line_block_t) - block + block: (nullable OFStreamAsyncReadLineBlock)block # endif delegate: (nullable id )delegate; + (void)of_addAsyncWriteForStream: (OFStream *) stream data: (OFData *)data - mode: (of_run_loop_mode_t)mode + mode: (OFRunLoopMode)mode # ifdef OF_HAVE_BLOCKS - block: (nullable of_stream_async_write_data_block_t) - block + block: (nullable OFStreamAsyncWriteDataBlock)block # endif delegate: (nullable id )delegate; + (void)of_addAsyncWriteForStream: (OFStream *) stream string: (OFString *)string - encoding: (of_string_encoding_t)encoding - mode: (of_run_loop_mode_t)mode + encoding: (OFStringEncoding)encoding + mode: (OFRunLoopMode)mode # ifdef OF_HAVE_BLOCKS - block: (nullable - of_stream_async_write_string_block_t) - block + block: (nullable OFStreamAsyncWriteStringBlock)block # endif delegate: (nullable id )delegate; # if !defined(OF_WII) && !defined(OF_NINTENDO_3DS) + (void)of_addAsyncConnectForSocket: (id)socket - mode: (of_run_loop_mode_t)mode + mode: (OFRunLoopMode)mode delegate: (id )delegate; # endif + (void)of_addAsyncAcceptForSocket: (id)socket - mode: (of_run_loop_mode_t)mode + mode: (OFRunLoopMode)mode block: (nullable id)block delegate: (nullable id)delegate; + (void)of_addAsyncReceiveForDatagramSocket: (OFDatagramSocket *)socket buffer: (void *)buffer length: (size_t)length - mode: (of_run_loop_mode_t)mode + mode: (OFRunLoopMode)mode # ifdef OF_HAVE_BLOCKS - block: (nullable of_datagram_socket_async_receive_block_t)block + block: (nullable OFDatagramSocketAsyncReceiveBlock)block # endif delegate: (nullable id ) delegate; + (void)of_addAsyncSendForDatagramSocket: (OFDatagramSocket *)socket data: (OFData *)data - receiver: (const of_socket_address_t *)receiver - mode: (of_run_loop_mode_t)mode + receiver: (const OFSocketAddress *)receiver + mode: (OFRunLoopMode)mode # ifdef OF_HAVE_BLOCKS - block: (nullable of_datagram_socket_async_send_data_block_t)block + block: (nullable OFDatagramSocketAsyncSendDataBlock)block # endif delegate: (nullable id )delegate; + (void)of_addAsyncReceiveForSequencedPacketSocket: (OFSequencedPacketSocket *)socket buffer: (void *)buffer length: (size_t)length - mode: (of_run_loop_mode_t)mode + mode: (OFRunLoopMode)mode # ifdef OF_HAVE_BLOCKS - block: (nullable of_sequenced_packet_socket_async_receive_block_t)block + block: (nullable OFSequencedPacketSocketAsyncReceiveBlock)block # endif delegate: (nullable id ) delegate; + (void)of_addAsyncSendForSequencedPacketSocket: (OFSequencedPacketSocket *)socket data: (OFData *)data - mode: (of_run_loop_mode_t)mode + mode: (OFRunLoopMode)mode # ifdef OF_HAVE_BLOCKS - block: (nullable of_sequenced_packet_socket_async_send_data_block_t)block + block: (nullable OFSequencedPacketSocketAsyncSendDataBlock)block # endif delegate: (nullable id )delegate; -+ (void)of_cancelAsyncRequestsForObject: (id)object - mode: (of_run_loop_mode_t)mode; ++ (void)of_cancelAsyncRequestsForObject: (id)object mode: (OFRunLoopMode)mode; #endif -- (void)of_removeTimer: (OFTimer *)timer - forMode: (of_run_loop_mode_t)mode; +- (void)of_removeTimer: (OFTimer *)timer forMode: (OFRunLoopMode)mode; @end OF_ASSUME_NONNULL_END Index: src/OFRunLoop.h ================================================================== --- src/OFRunLoop.h +++ src/OFRunLoop.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -39,19 +37,19 @@ @class OFDate; /** * @brief A mode for an OFRunLoop. */ -typedef OFConstantString *of_run_loop_mode_t; +typedef OFConstantString *OFRunLoopMode; #ifdef __cplusplus extern "C" { #endif /** * @brief The default mode for an OFRunLoop. */ -extern const of_run_loop_mode_t of_run_loop_mode_default; +extern const OFRunLoopMode OFDefaultRunLoopMode; #ifdef __cplusplus } #endif /** @@ -64,20 +62,19 @@ { OFMutableDictionary *_states; #ifdef OF_HAVE_THREADS OFMutex *_statesMutex; #endif - of_run_loop_mode_t _Nullable _currentMode; + OFRunLoopMode _Nullable _currentMode; volatile bool _stop; } #ifdef OF_HAVE_CLASS_PROPERTIES @property (class, readonly, nullable, nonatomic) OFRunLoop *mainRunLoop; @property (class, readonly, nullable, nonatomic) OFRunLoop *currentRunLoop; #endif -@property OF_NULLABLE_PROPERTY (readonly, nonatomic) - of_run_loop_mode_t currentMode; +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFRunLoopMode currentMode; /** * @brief Returns the run loop for the main thread. * * @return The run loop for the main thread @@ -102,12 +99,11 @@ * @brief Adds an OFTimer to the run loop for the specified mode. * * @param timer The timer to add * @param mode The run loop mode in which to run the timer */ -- (void)addTimer: (OFTimer *)timer - forMode: (of_run_loop_mode_t)mode; +- (void)addTimer: (OFTimer *)timer forMode: (OFRunLoopMode)mode; #ifdef OF_AMIGAOS /** * @brief Adds an Exec Signal to the run loop. * @@ -120,13 +116,11 @@ * @param target The target to call when the signal was received * @param selector The selector to call on the target when the signal was * received. The selector must have one parameter for the ULONG * of the signal that was received. */ -- (void)addExecSignal: (ULONG)signal - target: (id)target - selector: (SEL)selector; +- (void)addExecSignal: (ULONG)signal target: (id)target selector: (SEL)selector; /** * @brief Adds an Exec Signal to the run loop for the specified mode. * * If a signal is added multiple times, the specified methods will be performed @@ -140,11 +134,11 @@ * @param selector The selector to call on the target when the signal was * received. The selector must have one parameter for the ULONG * of the signal that was received. */ - (void)addExecSignal: (ULONG)signal - forMode: (of_run_loop_mode_t)mode + forMode: (OFRunLoopMode)mode target: (id)target selector: (SEL)selector; /** * @brief Removes the specified Exec Signal with the specified target and @@ -166,11 +160,11 @@ * @param mode The run loop mode to which the signal was added * @param target The target which was specified when adding the signal * @param selector The selector which was specified when adding the signal */ - (void)removeExecSignal: (ULONG)signal - forMode: (of_run_loop_mode_t)mode + forMode: (OFRunLoopMode)mode target: (id)target selector: (SEL)selector; #endif /** @@ -190,16 +184,15 @@ * deadline is reached. * * @param mode The mode in which to run the run loop * @param deadline The date until which the run loop should run at the longest */ -- (void)runMode: (of_run_loop_mode_t)mode - beforeDate: (nullable OFDate *)deadline; +- (void)runMode: (OFRunLoopMode)mode beforeDate: (nullable OFDate *)deadline; /** * @brief Stops the run loop. If there is still an operation being executed, it * is finished before the run loop stops. */ - (void)stop; @end OF_ASSUME_NONNULL_END Index: src/OFRunLoop.m ================================================================== --- src/OFRunLoop.m +++ src/OFRunLoop.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -42,12 +40,14 @@ #import "OFTimer.h" #import "OFTimer+Private.h" #import "OFDate.h" #import "OFObserveFailedException.h" +#import "OFWriteFailedException.h" -const of_run_loop_mode_t of_run_loop_mode_default = @"of_run_loop_mode_default"; +#include "OFRunLoopConstants.inc" + static OFRunLoop *mainRunLoop = nil; @interface OFRunLoopState: OFObject #ifdef OF_HAVE_SOCKETS @@ -76,16 +76,10 @@ # endif #endif } @end -OF_DIRECT_MEMBERS -@interface OFRunLoop () -- (OFRunLoopState *)of_stateForMode: (of_run_loop_mode_t)mode - create: (bool)create; -@end - #ifdef OF_HAVE_SOCKETS @interface OFRunLoopQueueItem: OFObject { @public id _delegate; @@ -96,11 +90,11 @@ @interface OFRunLoopReadQueueItem: OFRunLoopQueueItem { @public # ifdef OF_HAVE_BLOCKS - of_stream_async_read_block_t _block; + OFStreamAsyncReadBlock _block; # endif void *_buffer; size_t _length; } @end @@ -107,11 +101,11 @@ @interface OFRunLoopExactReadQueueItem: OFRunLoopQueueItem { @public # ifdef OF_HAVE_BLOCKS - of_stream_async_read_block_t _block; + OFStreamAsyncReadBlock _block; # endif void *_buffer; size_t _exactLength, _readLength; } @end @@ -118,21 +112,21 @@ @interface OFRunLoopReadLineQueueItem: OFRunLoopQueueItem { @public # ifdef OF_HAVE_BLOCKS - of_stream_async_read_line_block_t _block; + OFStreamAsyncReadLineBlock _block; # endif - of_string_encoding_t _encoding; + OFStringEncoding _encoding; } @end @interface OFRunLoopWriteDataQueueItem: OFRunLoopQueueItem { @public # ifdef OF_HAVE_BLOCKS - of_stream_async_write_data_block_t _block; + OFStreamAsyncWriteDataBlock _block; # endif OFData *_data; size_t _writtenLength; } @end @@ -139,14 +133,14 @@ @interface OFRunLoopWriteStringQueueItem: OFRunLoopQueueItem { @public # ifdef OF_HAVE_BLOCKS - of_stream_async_write_string_block_t _block; + OFStreamAsyncWriteStringBlock _block; # endif OFString *_string; - of_string_encoding_t _encoding; + OFStringEncoding _encoding; size_t _writtenLength; } @end # if !defined(OF_WII) && !defined(OF_NINTENDO_3DS) @@ -165,11 +159,11 @@ @interface OFRunLoopDatagramReceiveQueueItem: OFRunLoopQueueItem { @public # ifdef OF_HAVE_BLOCKS - of_datagram_socket_async_receive_block_t _block; + OFDatagramSocketAsyncReceiveBlock _block; # endif void *_buffer; size_t _length; } @end @@ -176,22 +170,22 @@ @interface OFRunLoopDatagramSendQueueItem: OFRunLoopQueueItem { @public # ifdef OF_HAVE_BLOCKS - of_datagram_socket_async_send_data_block_t _block; + OFDatagramSocketAsyncSendDataBlock _block; # endif OFData *_data; - of_socket_address_t _receiver; + OFSocketAddress _receiver; } @end @interface OFRunLoopPacketReceiveQueueItem: OFRunLoopQueueItem { @public # ifdef OF_HAVE_BLOCKS - of_sequenced_packet_socket_async_receive_block_t _block; + OFSequencedPacketSocketAsyncReceiveBlock _block; # endif void *_buffer; size_t _length; } @end @@ -198,11 +192,11 @@ @interface OFRunLoopPacketSendQueueItem: OFRunLoopQueueItem { @public # ifdef OF_HAVE_BLOCKS - of_sequenced_packet_socket_async_send_data_block_t _block; + OFSequencedPacketSocketAsyncSendDataBlock _block; # endif OFData *_data; } @end #endif @@ -282,27 +276,28 @@ assert(queue != nil); @try { if (![queue.firstObject handleObject: object]) { - of_list_object_t *listObject = queue.firstListObject; + OFListItem listItem = queue.firstListItem; /* * The handler might have called -[cancelAsyncRequests] * so that our queue is now empty, in which case we * should do nothing. */ - if (listObject != NULL) { + if (listItem != NULL) { /* * Make sure we keep the target until after we * are done removing the object. The reason for * this is that the target might call * -[cancelAsyncRequests] in its dealloc. */ - [[listObject->object retain] autorelease]; + [[OFListItemObject(listItem) retain] + autorelease]; - [queue removeListObject: listObject]; + [queue removeListItem: listItem]; if (queue.count == 0) { [_kernelEventObserver removeObjectForReading: object]; [_readQueues @@ -325,27 +320,28 @@ assert(queue != nil); @try { if (![queue.firstObject handleObject: object]) { - of_list_object_t *listObject = queue.firstListObject; + OFListItem listItem = queue.firstListItem; /* * The handler might have called -[cancelAsyncRequests] * so that our queue is now empty, in which case we * should do nothing. */ - if (listObject != NULL) { + if (listItem != NULL) { /* * Make sure we keep the target until after we * are done removing the object. The reason for * this is that the target might call * -[cancelAsyncRequests] in its dealloc. */ - [[listObject->object retain] autorelease]; + [[OFListItemObject(listItem) retain] + autorelease]; - [queue removeListObject: listObject]; + [queue removeListItem: listItem]; if (queue.count == 0) { [_kernelEventObserver removeObjectForWriting: object]; [_writeQueues @@ -429,12 +425,11 @@ { size_t length; id exception = nil; @try { - length = [object readIntoBuffer: _buffer - length: _length]; + length = [object readIntoBuffer: _buffer length: _length]; } @catch (id e) { length = 0; exception = e; } @@ -573,26 +568,31 @@ size_t dataLength = _data.count * _data.itemSize; OFData *newData, *oldData; @try { const char *dataItems = _data.items; + length = dataLength - _writtenLength; + [object writeBuffer: dataItems + _writtenLength length: length]; + } @catch (OFWriteFailedException *e) { + length = e.bytesWritten; - length = [object writeBuffer: dataItems + _writtenLength - length: dataLength - _writtenLength]; + if (e.errNo != EWOULDBLOCK && e.errNo != EAGAIN) + exception = e; } @catch (id e) { length = 0; exception = e; } _writtenLength += length; + OFEnsure(_writtenLength <= dataLength); if (_writtenLength != dataLength && exception == nil) return true; # ifdef OF_HAVE_BLOCKS if (_block != NULL) { - newData = _block(_data, _writtenLength, exception); + newData = _block(_writtenLength, exception); if (newData == nil) return false; oldData = _data; @@ -645,26 +645,31 @@ size_t cStringLength = [_string cStringLengthWithEncoding: _encoding]; OFString *newString, *oldString; @try { const char *cString = [_string cStringWithEncoding: _encoding]; + length = cStringLength - _writtenLength; + [object writeBuffer: cString + _writtenLength length: length]; + } @catch (OFWriteFailedException *e) { + length = e.bytesWritten; - length = [object writeBuffer: cString + _writtenLength - length: cStringLength - _writtenLength]; + if (e.errNo != EWOULDBLOCK && e.errNo != EAGAIN) + exception = e; } @catch (id e) { length = 0; exception = e; } _writtenLength += length; + OFEnsure(_writtenLength <= cStringLength); if (_writtenLength != cStringLength && exception == nil) return true; # ifdef OF_HAVE_BLOCKS if (_block != NULL) { - newString = _block(_string, _writtenLength, exception); + newString = _block(_writtenLength, exception); if (newString == nil) return false; oldString = _string; @@ -738,13 +743,11 @@ selector: @selector(of_socketDidConnect: exception:) object: object object: exception repeats: false]; - - [runLoop addTimer: timer - forMode: runLoop.currentMode]; + [runLoop addTimer: timer forMode: runLoop.currentMode]; } return false; } @end @@ -763,19 +766,18 @@ } # ifdef OF_HAVE_BLOCKS if (_block != NULL) { if ([object isKindOfClass: [OFStreamSocket class]]) - return ((of_stream_socket_async_accept_block_t) - _block)(acceptedSocket, exception); + return ((OFStreamSocketAsyncAcceptBlock)_block)( + acceptedSocket, exception); else if ([object isKindOfClass: [OFSequencedPacketSocket class]]) - return - ((of_sequenced_packet_socket_async_accept_block_t) + return ((OFSequencedPacketSocketAsyncAcceptBlock) _block)(acceptedSocket, exception); else - OF_ENSURE(0); + OFEnsure(0); } else { # endif if (![_delegate respondsToSelector: @selector(socket:didAcceptSocket:exception:)]) return false; @@ -800,11 +802,11 @@ @implementation OFRunLoopDatagramReceiveQueueItem - (bool)handleObject: (id)object { size_t length; - of_socket_address_t address; + OFSocketAddress address; id exception = nil; @try { length = [object receiveIntoBuffer: _buffer length: _length @@ -857,11 +859,11 @@ exception = e; } # ifdef OF_HAVE_BLOCKS if (_block != NULL) { - newData = _block(_data, &_receiver, exception); + newData = _block(exception); if (newData == nil) return false; oldData = _data; @@ -909,12 +911,11 @@ { size_t length; id exception = nil; @try { - length = [object receiveIntoBuffer: _buffer - length: _length]; + length = [object receiveIntoBuffer: _buffer length: _length]; } @catch (id e) { length = 0; exception = e; } @@ -959,11 +960,11 @@ exception = e; } # ifdef OF_HAVE_BLOCKS if (_block != NULL) { - newData = _block(_data, exception); + newData = _block(exception); if (newData == nil) return false; oldData = _data; @@ -1025,24 +1026,50 @@ + (void)of_setMainRunLoop: (OFRunLoop *)runLoop { mainRunLoop = [runLoop retain]; } + +static OFRunLoopState * +stateForMode(OFRunLoop *self, OFRunLoopMode mode, bool create) +{ + OFRunLoopState *state; + +#ifdef OF_HAVE_THREADS + [self->_statesMutex lock]; + @try { +#endif + state = [self->_states objectForKey: mode]; + + if (create && state == nil) { + state = [[OFRunLoopState alloc] init]; + @try { + [self->_states setObject: state forKey: mode]; + } @finally { + [state release]; + } + } +#ifdef OF_HAVE_THREADS + } @finally { + [self->_statesMutex unlock]; + } +#endif + + return state; +} #ifdef OF_HAVE_SOCKETS # define NEW_READ(type, object, mode) \ void *pool = objc_autoreleasePoolPush(); \ OFRunLoop *runLoop = [self currentRunLoop]; \ - OFRunLoopState *state = [runLoop of_stateForMode: mode \ - create: true]; \ + OFRunLoopState *state = stateForMode(runLoop, mode, true); \ OFList *queue = [state->_readQueues objectForKey: object]; \ type *queueItem; \ \ if (queue == nil) { \ queue = [OFList list]; \ - [state->_readQueues setObject: queue \ - forKey: object]; \ + [state->_readQueues setObject: queue forKey: object]; \ } \ \ if (queue.count == 0) \ [state->_kernelEventObserver \ addObjectForReading: object]; \ @@ -1049,19 +1076,17 @@ \ queueItem = [[[type alloc] init] autorelease]; # define NEW_WRITE(type, object, mode) \ void *pool = objc_autoreleasePoolPush(); \ OFRunLoop *runLoop = [self currentRunLoop]; \ - OFRunLoopState *state = [runLoop of_stateForMode: mode \ - create: true]; \ + OFRunLoopState *state = stateForMode(runLoop, mode, true); \ OFList *queue = [state->_writeQueues objectForKey: object]; \ type *queueItem; \ \ if (queue == nil) { \ queue = [OFList list]; \ - [state->_writeQueues setObject: queue \ - forKey: object]; \ + [state->_writeQueues setObject: queue forKey: object]; \ } \ \ if (queue.count == 0) \ [state->_kernelEventObserver \ addObjectForWriting: object]; \ @@ -1074,13 +1099,13 @@ + (void)of_addAsyncReadForStream: (OFStream *) stream buffer: (void *)buffer length: (size_t)length - mode: (of_run_loop_mode_t)mode + mode: (OFRunLoopMode)mode # ifdef OF_HAVE_BLOCKS - block: (of_stream_async_read_block_t)block + block: (OFStreamAsyncReadBlock)block # endif delegate: (id )delegate { NEW_READ(OFRunLoopReadQueueItem, stream, mode) @@ -1096,13 +1121,13 @@ + (void)of_addAsyncReadForStream: (OFStream *) stream buffer: (void *)buffer exactLength: (size_t)exactLength - mode: (of_run_loop_mode_t)mode + mode: (OFRunLoopMode)mode # ifdef OF_HAVE_BLOCKS - block: (of_stream_async_read_block_t)block + block: (OFStreamAsyncReadBlock)block # endif delegate: (id )delegate { NEW_READ(OFRunLoopExactReadQueueItem, stream, mode) @@ -1116,14 +1141,14 @@ QUEUE_ITEM } + (void)of_addAsyncReadLineForStream: (OFStream *) stream - encoding: (of_string_encoding_t)encoding - mode: (of_run_loop_mode_t)mode + encoding: (OFStringEncoding)encoding + mode: (OFRunLoopMode)mode # ifdef OF_HAVE_BLOCKS - block: (of_stream_async_read_line_block_t)block + block: (OFStreamAsyncReadLineBlock)block # endif delegate: (id )delegate { NEW_READ(OFRunLoopReadLineQueueItem, stream, mode) @@ -1137,13 +1162,13 @@ } + (void)of_addAsyncWriteForStream: (OFStream *) stream data: (OFData *)data - mode: (of_run_loop_mode_t)mode + mode: (OFRunLoopMode)mode # ifdef OF_HAVE_BLOCKS - block: (of_stream_async_write_data_block_t)block + block: (OFStreamAsyncWriteDataBlock)block # endif delegate: (id )delegate { NEW_WRITE(OFRunLoopWriteDataQueueItem, stream, mode) @@ -1157,14 +1182,14 @@ } + (void)of_addAsyncWriteForStream: (OFStream *) stream string: (OFString *)string - encoding: (of_string_encoding_t)encoding - mode: (of_run_loop_mode_t)mode + encoding: (OFStringEncoding)encoding + mode: (OFRunLoopMode)mode # ifdef OF_HAVE_BLOCKS - block: (of_stream_async_write_string_block_t)block + block: (OFStreamAsyncWriteStringBlock)block # endif delegate: (id )delegate { NEW_WRITE(OFRunLoopWriteStringQueueItem, stream, mode) @@ -1178,11 +1203,11 @@ QUEUE_ITEM } # if !defined(OF_WII) && !defined(OF_NINTENDO_3DS) + (void)of_addAsyncConnectForSocket: (id)sock - mode: (of_run_loop_mode_t)mode + mode: (OFRunLoopMode)mode delegate: (id )delegate { NEW_WRITE(OFRunLoopConnectQueueItem, sock, mode) queueItem->_delegate = [delegate retain]; @@ -1190,11 +1215,11 @@ QUEUE_ITEM } # endif + (void)of_addAsyncAcceptForSocket: (id)sock - mode: (of_run_loop_mode_t)mode + mode: (OFRunLoopMode)mode block: (id)block delegate: (id)delegate { NEW_READ(OFRunLoopAcceptQueueItem, sock, mode) @@ -1207,13 +1232,13 @@ } + (void)of_addAsyncReceiveForDatagramSocket: (OFDatagramSocket *)sock buffer: (void *)buffer length: (size_t)length - mode: (of_run_loop_mode_t)mode + mode: (OFRunLoopMode)mode # ifdef OF_HAVE_BLOCKS - block: (of_datagram_socket_async_receive_block_t)block + block: (OFDatagramSocketAsyncReceiveBlock)block # endif delegate: (id )delegate { NEW_READ(OFRunLoopDatagramReceiveQueueItem, sock, mode) @@ -1227,14 +1252,14 @@ QUEUE_ITEM } + (void)of_addAsyncSendForDatagramSocket: (OFDatagramSocket *)sock data: (OFData *)data - receiver: (const of_socket_address_t *)receiver - mode: (of_run_loop_mode_t)mode + receiver: (const OFSocketAddress *)receiver + mode: (OFRunLoopMode)mode # ifdef OF_HAVE_BLOCKS - block: (of_datagram_socket_async_send_data_block_t)block + block: (OFDatagramSocketAsyncSendDataBlock)block # endif delegate: (id )delegate { NEW_WRITE(OFRunLoopDatagramSendQueueItem, sock, mode) @@ -1250,13 +1275,13 @@ + (void)of_addAsyncReceiveForSequencedPacketSocket: (OFSequencedPacketSocket *) sock buffer: (void *)buffer length: (size_t)length - mode: (of_run_loop_mode_t)mode + mode: (OFRunLoopMode)mode # ifdef OF_HAVE_BLOCKS - block: (of_sequenced_packet_socket_async_receive_block_t)block + block: (OFSequencedPacketSocketAsyncReceiveBlock)block # endif delegate: (id )delegate { NEW_READ(OFRunLoopPacketReceiveQueueItem, sock, mode) @@ -1270,13 +1295,13 @@ QUEUE_ITEM } + (void)of_addAsyncSendForSequencedPacketSocket: (OFSequencedPacketSocket *)sock data: (OFData *)data - mode: (of_run_loop_mode_t)mode + mode: (OFRunLoopMode)mode # ifdef OF_HAVE_BLOCKS - block: (of_sequenced_packet_socket_async_send_data_block_t)block + block: (OFSequencedPacketSocketAsyncSendDataBlock)block # endif delegate: (id )delegate { NEW_WRITE(OFRunLoopPacketSendQueueItem, sock, mode) @@ -1290,17 +1315,15 @@ } # undef NEW_READ # undef NEW_WRITE # undef QUEUE_ITEM -+ (void)of_cancelAsyncRequestsForObject: (id)object - mode: (of_run_loop_mode_t)mode ++ (void)of_cancelAsyncRequestsForObject: (id)object mode: (OFRunLoopMode)mode { void *pool = objc_autoreleasePoolPush(); OFRunLoop *runLoop = [self currentRunLoop]; - OFRunLoopState *state = [runLoop of_stateForMode: mode - create: false]; + OFRunLoopState *state = stateForMode(runLoop, mode, false); OFList *queue; if (state == nil) return; @@ -1343,12 +1366,11 @@ _states = [[OFMutableDictionary alloc] init]; state = [[OFRunLoopState alloc] init]; @try { - [_states setObject: state - forKey: of_run_loop_mode_default]; + [_states setObject: state forKey: OFDefaultRunLoopMode]; } @finally { [state release]; } #ifdef OF_HAVE_THREADS @@ -1370,50 +1392,18 @@ #endif [super dealloc]; } -- (OFRunLoopState *)of_stateForMode: (of_run_loop_mode_t)mode - create: (bool)create -{ - OFRunLoopState *state; - -#ifdef OF_HAVE_THREADS - [_statesMutex lock]; - @try { -#endif - state = [_states objectForKey: mode]; - - if (create && state == nil) { - state = [[OFRunLoopState alloc] init]; - @try { - [_states setObject: state - forKey: mode]; - } @finally { - [state release]; - } - } -#ifdef OF_HAVE_THREADS - } @finally { - [_statesMutex unlock]; - } -#endif - - return state; -} - -- (void)addTimer: (OFTimer *)timer -{ - [self addTimer: timer - forMode: of_run_loop_mode_default]; -} - -- (void)addTimer: (OFTimer *)timer - forMode: (of_run_loop_mode_t)mode -{ - OFRunLoopState *state = [self of_stateForMode: mode - create: true]; +- (void)addTimer: (OFTimer *)timer +{ + [self addTimer: timer forMode: OFDefaultRunLoopMode]; +} + +- (void)addTimer: (OFTimer *)timer forMode: (OFRunLoopMode)mode +{ + OFRunLoopState *state = stateForMode(self, mode, true); #ifdef OF_HAVE_THREADS [state->_timersQueueMutex lock]; @try { #endif @@ -1422,39 +1412,36 @@ } @finally { [state->_timersQueueMutex unlock]; } #endif - [timer of_setInRunLoop: self - mode: mode]; + [timer of_setInRunLoop: self mode: mode]; #if defined(OF_HAVE_SOCKETS) [state->_kernelEventObserver cancel]; #elif defined(OF_HAVE_THREADS) [state->_condition signal]; #endif } -- (void)of_removeTimer: (OFTimer *)timer - forMode: (of_run_loop_mode_t)mode +- (void)of_removeTimer: (OFTimer *)timer forMode: (OFRunLoopMode)mode { - OFRunLoopState *state = [self of_stateForMode: mode - create: false]; + OFRunLoopState *state = stateForMode(self, mode, false); - if (state == nil) + /* {} required to avoid -Wmisleading-indentation false positive. */ + if (state == nil) { return; + } #ifdef OF_HAVE_THREADS [state->_timersQueueMutex lock]; @try { #endif - of_list_object_t *iter; - - for (iter = state->_timersQueue.firstListObject; iter != NULL; - iter = iter->next) { - if ([iter->object isEqual: timer]) { - [state->_timersQueue removeListObject: iter]; + for (OFListItem iter = state->_timersQueue.firstListItem; + iter != NULL; iter = OFListItemNext(iter)) { + if ([OFListItemObject(iter) isEqual: timer]) { + [state->_timersQueue removeListItem: iter]; break; } } #ifdef OF_HAVE_THREADS } @finally { @@ -1462,27 +1449,24 @@ } #endif } #ifdef OF_AMIGAOS -- (void)addExecSignal: (ULONG)signal - target: (id)target - selector: (SEL)selector +- (void)addExecSignal: (ULONG)signal target: (id)target selector: (SEL)selector { [self addExecSignal: signal - forMode: of_run_loop_mode_default + forMode: OFDefaultRunLoopMode target: target selector: selector]; } - (void)addExecSignal: (ULONG)signal - forMode: (of_run_loop_mode_t)mode + forMode: (OFRunLoopMode)mode target: (id)target selector: (SEL)selector { - OFRunLoopState *state = [self of_stateForMode: mode - create: true]; + OFRunLoopState *state = stateForMode(self, mode, true); # ifdef OF_HAVE_THREADS [state->_execSignalsMutex lock]; @try { # endif @@ -1511,22 +1495,21 @@ - (void)removeExecSignal: (ULONG)signal target: (id)target selector: (SEL)selector { [self removeExecSignal: signal - forMode: of_run_loop_mode_default + forMode: OFDefaultRunLoopMode target: target selector: selector]; } - (void)removeExecSignal: (ULONG)signal - forMode: (of_run_loop_mode_t)mode + forMode: (OFRunLoopMode)mode target: (id)target selector: (SEL)selector { - OFRunLoopState *state = [self of_stateForMode: mode - create: false]; + OFRunLoopState *state = stateForMode(self, mode, false); if (state == nil) return; # ifdef OF_HAVE_THREADS @@ -1582,21 +1565,18 @@ { _stop = false; while (!_stop && (deadline == nil || deadline.timeIntervalSinceNow >= 0)) - [self runMode: of_run_loop_mode_default - beforeDate: deadline]; + [self runMode: OFDefaultRunLoopMode beforeDate: deadline]; } -- (void)runMode: (of_run_loop_mode_t)mode - beforeDate: (OFDate *)deadline +- (void)runMode: (OFRunLoopMode)mode beforeDate: (OFDate *)deadline { void *pool = objc_autoreleasePoolPush(); - of_run_loop_mode_t previousMode = _currentMode; - OFRunLoopState *state = [self of_stateForMode: mode - create: false]; + OFRunLoopMode previousMode = _currentMode; + OFRunLoopState *state = stateForMode(self, mode, false); if (state == nil) return; _currentMode = mode; @@ -1611,23 +1591,23 @@ #ifdef OF_HAVE_THREADS [state->_timersQueueMutex lock]; @try { #endif - of_list_object_t *listObject = - state->_timersQueue.firstListObject; + OFListItem listItem = + state->_timersQueue.firstListItem; - if (listObject != NULL && [listObject->object - fireDate].timeIntervalSinceNow <= 0) { - timer = [[listObject->object + if (listItem != NULL && + [OFListItemObject(listItem) fireDate] + .timeIntervalSinceNow <= 0) { + timer = [[OFListItemObject(listItem) retain] autorelease]; [state->_timersQueue - removeListObject: listObject]; + removeListItem: listItem]; - [timer of_setInRunLoop: nil - mode: nil]; + [timer of_setInRunLoop: nil mode: nil]; } else break; #ifdef OF_HAVE_THREADS } @finally { [state->_timersQueueMutex unlock]; @@ -1652,11 +1632,11 @@ } #endif /* Watch for I/O events until the next timer is due */ if (nextTimer != nil || deadline != nil) { - of_time_interval_t timeout; + OFTimeInterval timeout; if (nextTimer != nil && deadline == nil) timeout = nextTimer.timeIntervalSinceNow; else if (nextTimer == nil && deadline != nil) timeout = deadline.timeIntervalSinceNow; @@ -1726,12 +1706,11 @@ } } - (void)stop { - OFRunLoopState *state = [self of_stateForMode: of_run_loop_mode_default - create: false]; + OFRunLoopState *state = stateForMode(self, OFDefaultRunLoopMode, false); _stop = true; if (state == nil) return; ADDED src/OFRunLoopConstants.inc Index: src/OFRunLoopConstants.inc ================================================================== --- /dev/null +++ src/OFRunLoopConstants.inc @@ -0,0 +1,16 @@ +/* + * 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. + */ + +const OFRunLoopMode OFDefaultRunLoopMode = @"OFDefaultRunLoopMode"; DELETED src/OFSCTPSocket.h Index: src/OFSCTPSocket.h ================================================================== --- src/OFSCTPSocket.h +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "OFSequencedPacketSocket.h" -#import "OFRunLoop.h" - -OF_ASSUME_NONNULL_BEGIN - -/** @file */ - -@class OFSCTPSocket; -@class OFString; - -#ifdef OF_HAVE_BLOCKS -/** - * @brief A block which is called when the socket connected. - * - * @param exception An exception which occurred while connecting the socket or - * `nil` on success - */ -typedef void (^of_sctp_socket_async_connect_block_t)(id _Nullable exception); -#endif - -/** - * @protocol OFSCTPSocketDelegate OFSCTPSocket.h ObjFW/OFSCTPSocket.h - * - * A delegate for OFSCTPSocket. - */ -@protocol OFSCTPSocketDelegate -@optional -/** - * @brief A method which is called when a socket connected. - * - * @param socket The socket which connected - * @param host The host connected to - * @param port The port on the host connected to - * @param exception An exception that occurred while connecting, or nil on - * success - */ -- (void)socket: (OFSCTPSocket *)socket - didConnectToHost: (OFString *)host - port: (uint16_t)port - exception: (nullable id)exception; -@end - -/** - * @class OFSCTPSocket OFSCTPSocket.h ObjFW/OFSCTPSocket.h - * - * @brief A class which provides methods to create and use SCTP sockets in - * one-to-one mode. - * - * To connect to a server, create a socket and connect it. - * To create a server, create a socket, bind it and listen on it. - */ -@interface OFSCTPSocket: OFSequencedPacketSocket -{ - OF_RESERVE_IVARS(OFSCTPSocket, 4) -} - -/** - * @brief Whether sending packets can be delayed. Setting this to NO sets - * SCTP_NODELAY on the socket. - */ -@property (nonatomic) bool canDelaySendingPackets; - -/** - * @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 Connect the OFSCTPSocket to the specified destination. - * - * @param host The host to connect to - * @param port The port on the host to connect to - */ -- (void)connectToHost: (OFString *)host - port: (uint16_t)port; - -/** - * @brief Asynchronously connect the OFSCTPSocket to the specified destination. - * - * @param host The host to connect to - * @param port The port on the host to connect to - */ -- (void)asyncConnectToHost: (OFString *)host - port: (uint16_t)port; - -/** - * @brief Asynchronously connect the OFSCTPSocket to the specified destination. - * - * @param host The host to connect to - * @param port The port on the host to connect to - * @param runLoopMode The run loop mode in which to perform the async connect - */ -- (void)asyncConnectToHost: (OFString *)host - port: (uint16_t)port - runLoopMode: (of_run_loop_mode_t)runLoopMode; - -#ifdef OF_HAVE_BLOCKS -/** - * @brief Asynchronously connect the OFSCTPSocket to the specified destination. - * - * @param host The host to connect to - * @param port The port on the host to connect to - * @param block The block to execute once the connection has been established - */ -- (void)asyncConnectToHost: (OFString *)host - port: (uint16_t)port - block: (of_sctp_socket_async_connect_block_t)block; - -/** - * @brief Asynchronously connect the OFSCTPSocket to the specified destination. - * - * @param host The host to connect to - * @param port The port on the host to 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)asyncConnectToHost: (OFString *)host - port: (uint16_t)port - runLoopMode: (of_run_loop_mode_t)runLoopMode - block: (of_sctp_socket_async_connect_block_t)block; -#endif - -/** - * @brief Bind the socket to the specified host and port. - * - * @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 - */ -- (uint16_t)bindToHost: (OFString *)host - port: (uint16_t)port; -@end - -OF_ASSUME_NONNULL_END DELETED src/OFSCTPSocket.m Index: src/OFSCTPSocket.m ================================================================== --- src/OFSCTPSocket.m +++ /dev/null @@ -1,332 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 -#include - -#ifdef HAVE_FCNTL_H -# include -#endif - -#import "OFSCTPSocket.h" -#import "OFDNSResolver.h" -#import "OFData.h" -#import "OFDate.h" -#import "OFIPSocketAsyncConnector.h" -#import "OFRunLoop.h" -#import "OFRunLoop+Private.h" -#import "OFString.h" -#import "OFThread.h" - -#import "OFAlreadyConnectedException.h" -#import "OFBindFailedException.h" -#import "OFGetOptionFailedException.h" -#import "OFNotOpenException.h" -#import "OFSetOptionFailedException.h" - -#import "socket.h" -#import "socket_helpers.h" - -static const of_run_loop_mode_t connectRunLoopMode = - @"of_sctp_socket_connect_mode"; - -@interface OFSCTPSocket () -@end - -@interface OFSCTPSocketConnectDelegate: OFObject -{ -@public - bool _done; - id _exception; -} -@end - -@implementation OFSCTPSocketConnectDelegate -- (void)dealloc -{ - [_exception release]; - - [super dealloc]; -} - -- (void)socket: (OFSCTPSocket *)sock - didConnectToHost: (OFString *)host - port: (uint16_t)port - exception: (id)exception -{ - _done = true; - _exception = [exception retain]; -} -@end - -@implementation OFSCTPSocket -@dynamic delegate; - -- (bool)of_createSocketForAddress: (const of_socket_address_t *)address - errNo: (int *)errNo -{ -#if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) - int flags; -#endif - - if (_socket != INVALID_SOCKET) - @throw [OFAlreadyConnectedException exceptionWithSocket: self]; - - if ((_socket = socket(address->sockaddr.sockaddr.sa_family, - SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_SCTP)) == INVALID_SOCKET) { - *errNo = of_socket_errno(); - return false; - } - -#if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) - if ((flags = fcntl(_socket, F_GETFD, 0)) != -1) - fcntl(_socket, F_SETFD, flags | FD_CLOEXEC); -#endif - - return true; -} - -- (bool)of_connectSocketToAddress: (const of_socket_address_t *)address - errNo: (int *)errNo -{ - if (_socket == INVALID_SOCKET) - @throw [OFNotOpenException exceptionWithObject: self]; - - if (connect(_socket, &address->sockaddr.sockaddr, - address->length) != 0) { - *errNo = of_socket_errno(); - return false; - } - - return true; -} - -- (void)of_closeSocket -{ - closesocket(_socket); - _socket = INVALID_SOCKET; -} - -- (void)connectToHost: (OFString *)host - port: (uint16_t)port -{ - void *pool = objc_autoreleasePoolPush(); - id delegate = _delegate; - OFSCTPSocketConnectDelegate *connectDelegate = - [[[OFSCTPSocketConnectDelegate alloc] init] autorelease]; - OFRunLoop *runLoop = [OFRunLoop currentRunLoop]; - - self.delegate = connectDelegate; - [self asyncConnectToHost: host - port: port - runLoopMode: connectRunLoopMode]; - - while (!connectDelegate->_done) - [runLoop runMode: connectRunLoopMode - beforeDate: nil]; - - /* Cleanup */ - [runLoop runMode: connectRunLoopMode - beforeDate: [OFDate date]]; - - if (connectDelegate->_exception != nil) - @throw connectDelegate->_exception; - - self.delegate = delegate; - - objc_autoreleasePoolPop(pool); -} - -- (void)asyncConnectToHost: (OFString *)host - port: (uint16_t)port -{ - [self asyncConnectToHost: host - port: port - runLoopMode: of_run_loop_mode_default]; -} - -- (void)asyncConnectToHost: (OFString *)host - port: (uint16_t)port - runLoopMode: (of_run_loop_mode_t)runLoopMode -{ - void *pool = objc_autoreleasePoolPush(); - - if (_socket != INVALID_SOCKET) - @throw [OFAlreadyConnectedException exceptionWithSocket: self]; - - [[[[OFIPSocketAsyncConnector alloc] - initWithSocket: self - host: host - port: port - delegate: _delegate - block: NULL - ] autorelease] startWithRunLoopMode: runLoopMode]; - - objc_autoreleasePoolPop(pool); -} - -#ifdef OF_HAVE_BLOCKS -- (void)asyncConnectToHost: (OFString *)host - port: (uint16_t)port - block: (of_sctp_socket_async_connect_block_t)block -{ - [self asyncConnectToHost: host - port: port - runLoopMode: of_run_loop_mode_default - block: block]; -} - -- (void)asyncConnectToHost: (OFString *)host - port: (uint16_t)port - runLoopMode: (of_run_loop_mode_t)runLoopMode - block: (of_sctp_socket_async_connect_block_t)block -{ - void *pool = objc_autoreleasePoolPush(); - - if (_socket != INVALID_SOCKET) - @throw [OFAlreadyConnectedException exceptionWithSocket: self]; - - [[[[OFIPSocketAsyncConnector alloc] - initWithSocket: self - host: host - port: port - delegate: nil - block: block] autorelease] - startWithRunLoopMode: runLoopMode]; - - objc_autoreleasePoolPop(pool); -} -#endif - -- (uint16_t)bindToHost: (OFString *)host - port: (uint16_t)port -{ - const int one = 1; - void *pool = objc_autoreleasePoolPush(); - OFData *socketAddresses; - of_socket_address_t address; -#if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) - int flags; -#endif - - if (_socket != INVALID_SOCKET) - @throw [OFAlreadyConnectedException exceptionWithSocket: self]; - - socketAddresses = [[OFThread DNSResolver] - resolveAddressesForHost: host - addressFamily: OF_SOCKET_ADDRESS_FAMILY_ANY]; - - address = *(of_socket_address_t *)[socketAddresses itemAtIndex: 0]; - of_socket_address_set_port(&address, port); - - if ((_socket = socket(address.sockaddr.sockaddr.sa_family, - SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_SCTP)) == INVALID_SOCKET) - @throw [OFBindFailedException - exceptionWithHost: host - port: port - socket: self - errNo: of_socket_errno()]; - - _canBlock = true; - -#if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) - if ((flags = fcntl(_socket, F_GETFD, 0)) != -1) - fcntl(_socket, F_SETFD, flags | FD_CLOEXEC); -#endif - - setsockopt(_socket, SOL_SOCKET, SO_REUSEADDR, - (char *)&one, (socklen_t)sizeof(one)); - - if (bind(_socket, &address.sockaddr.sockaddr, address.length) != 0) { - int errNo = of_socket_errno(); - - closesocket(_socket); - _socket = INVALID_SOCKET; - - @throw [OFBindFailedException exceptionWithHost: host - port: port - socket: self - errNo: errNo]; - } - - objc_autoreleasePoolPop(pool); - - if (port > 0) - return port; - - memset(&address, 0, sizeof(address)); - - address.length = (socklen_t)sizeof(address.sockaddr); - if (of_getsockname(_socket, &address.sockaddr.sockaddr, - &address.length) != 0) { - int errNo = of_socket_errno(); - - closesocket(_socket); - _socket = INVALID_SOCKET; - - @throw [OFBindFailedException exceptionWithHost: host - port: port - socket: self - errNo: errNo]; - } - - if (address.sockaddr.sockaddr.sa_family == AF_INET) - return OF_BSWAP16_IF_LE(address.sockaddr.in.sin_port); -# ifdef OF_HAVE_IPV6 - else if (address.sockaddr.sockaddr.sa_family == AF_INET6) - return OF_BSWAP16_IF_LE(address.sockaddr.in6.sin6_port); -# endif - else { - closesocket(_socket); - _socket = INVALID_SOCKET; - - @throw [OFBindFailedException exceptionWithHost: host - port: port - socket: self - errNo: EAFNOSUPPORT]; - } -} - -- (void)setCanDelaySendingPackets: (bool)canDelaySendingPackets -{ - int v = !canDelaySendingPackets; - - if (setsockopt(_socket, IPPROTO_SCTP, SCTP_NODELAY, - (char *)&v, (socklen_t)sizeof(v)) != 0) - @throw [OFSetOptionFailedException - exceptionWithObject: self - errNo: of_socket_errno()]; -} - -- (bool)canDelaySendingPackets -{ - int v; - socklen_t len = sizeof(v); - - if (getsockopt(_socket, IPPROTO_SCTP, SCTP_NODELAY, - (char *)&v, &len) != 0 || len != sizeof(v)) - @throw [OFGetOptionFailedException - exceptionWithObject: self - errNo: of_socket_errno()]; - - return !v; -} -@end Index: src/OFSHA1Hash.h ================================================================== --- src/OFSHA1Hash.h +++ src/OFSHA1Hash.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -13,11 +11,11 @@ * 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 "OFCryptoHash.h" +#import "OFCryptographicHash.h" OF_ASSUME_NONNULL_BEGIN @class OFSecureData; @@ -25,17 +23,17 @@ * @class OFSHA1Hash OFSHA1Hash.h ObjFW/OFSHA1Hash.h * * @brief A class which provides methods to create an SHA-1 hash. */ OF_SUBCLASSING_RESTRICTED -@interface OFSHA1Hash: OFObject +@interface OFSHA1Hash: OFObject { OFSecureData *_iVarsData; - struct of_sha1_hash_ivars { + struct { uint32_t state[5]; uint64_t bits; - union of_sha1_hash_buffer { + union { unsigned char bytes[64]; uint32_t words[80]; } buffer; size_t bufferLength; } *_iVars; Index: src/OFSHA1Hash.m ================================================================== --- src/OFSHA1Hash.m +++ src/OFSHA1Hash.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -21,14 +19,15 @@ #import "OFSHA1Hash.h" #import "OFSecureData.h" #import "OFHashAlreadyCalculatedException.h" +#import "OFHashNotCalculatedException.h" #import "OFOutOfRangeException.h" -#define DIGEST_SIZE 20 -#define BLOCK_SIZE 64 +static const size_t digestSize = 20; +static const size_t blockSize = 64; OF_DIRECT_MEMBERS @interface OFSHA1Hash () - (void)of_resetState; @end @@ -41,11 +40,11 @@ static OF_INLINE void byteSwapVectorIfLE(uint32_t *vector, uint_fast8_t length) { #ifndef OF_BIG_ENDIAN for (uint_fast8_t i = 0; i < length; i++) - vector[i] = OF_BSWAP32(vector[i]); + vector[i] = OFByteSwap32(vector[i]); #endif } static void processBlock(uint32_t *state, uint32_t *buffer) @@ -62,21 +61,21 @@ byteSwapVectorIfLE(buffer, 16); for (i = 16; i < 80; i++) { uint32_t tmp = buffer[i - 3] ^ buffer[i - 8] ^ buffer[i - 14] ^ buffer[i - 16]; - buffer[i] = OF_ROL(tmp, 1); + buffer[i] = OFRotateLeft(tmp, 1); } #define LOOP_BODY(f, k) \ { \ - uint32_t tmp = OF_ROL(new[0], 5) + \ + uint32_t tmp = OFRotateLeft(new[0], 5) + \ f(new[0], new[1], new[2], new[3]) + \ new[4] + k + buffer[i]; \ new[4] = new[3]; \ new[3] = new[2]; \ - new[2] = OF_ROL(new[1], 30); \ + new[2] = OFRotateLeft(new[1], 30); \ new[1] = new[0]; \ new[0] = tmp; \ } for (i = 0; i < 20; i++) @@ -101,19 +100,19 @@ @synthesize calculated = _calculated; @synthesize allowsSwappableMemory = _allowsSwappableMemory; + (size_t)digestSize { - return DIGEST_SIZE; + return digestSize; } + (size_t)blockSize { - return BLOCK_SIZE; + return blockSize; } -+ (instancetype)cryptoHashWithAllowsSwappableMemory: (bool)allowsSwappableMemory ++ (instancetype)hashWithAllowsSwappableMemory: (bool)allowsSwappableMemory { return [[[self alloc] initWithAllowsSwappableMemory: allowsSwappableMemory] autorelease]; } @@ -154,16 +153,16 @@ [super dealloc]; } - (size_t)digestSize { - return DIGEST_SIZE; + return digestSize; } - (size_t)blockSize { - return BLOCK_SIZE; + return blockSize; } - (id)copy { OFSHA1Hash *copy = [[OFSHA1Hash alloc] of_init]; @@ -183,12 +182,11 @@ _iVars->state[2] = 0x98BADCFE; _iVars->state[3] = 0x10325476; _iVars->state[4] = 0xC3D2E1F0; } -- (void)updateWithBuffer: (const void *)buffer_ - length: (size_t)length +- (void)updateWithBuffer: (const void *)buffer_ length: (size_t)length { const unsigned char *buffer = buffer_; if (_calculated) @throw [OFHashAlreadyCalculatedException @@ -219,39 +217,46 @@ } } - (const unsigned char *)digest { + if (!_calculated) + @throw [OFHashNotCalculatedException exceptionWithObject: self]; + + return (const unsigned char *)_iVars->state; +} + +- (void)calculate +{ if (_calculated) - return (const unsigned char *)_iVars->state; + @throw [OFHashAlreadyCalculatedException + exceptionWithObject: self]; _iVars->buffer.bytes[_iVars->bufferLength] = 0x80; - of_explicit_memset(_iVars->buffer.bytes + _iVars->bufferLength + 1, 0, + OFZeroMemory(_iVars->buffer.bytes + _iVars->bufferLength + 1, 64 - _iVars->bufferLength - 1); if (_iVars->bufferLength >= 56) { processBlock(_iVars->state, _iVars->buffer.words); - of_explicit_memset(_iVars->buffer.bytes, 0, 64); + OFZeroMemory(_iVars->buffer.bytes, 64); } _iVars->buffer.words[14] = - OF_BSWAP32_IF_LE((uint32_t)(_iVars->bits >> 32)); + OFToBigEndian32((uint32_t)(_iVars->bits >> 32)); _iVars->buffer.words[15] = - OF_BSWAP32_IF_LE((uint32_t)(_iVars->bits & 0xFFFFFFFF)); + OFToBigEndian32((uint32_t)(_iVars->bits & 0xFFFFFFFF)); processBlock(_iVars->state, _iVars->buffer.words); - of_explicit_memset(&_iVars->buffer, 0, sizeof(_iVars->buffer)); + OFZeroMemory(&_iVars->buffer, sizeof(_iVars->buffer)); byteSwapVectorIfLE(_iVars->state, 5); _calculated = true; - - return (const unsigned char *)_iVars->state; } - (void)reset { [self of_resetState]; _iVars->bits = 0; - of_explicit_memset(&_iVars->buffer, 0, sizeof(_iVars->buffer)); + OFZeroMemory(&_iVars->buffer, sizeof(_iVars->buffer)); _iVars->bufferLength = 0; _calculated = false; } @end Index: src/OFSHA224Hash.h ================================================================== --- src/OFSHA224Hash.h +++ src/OFSHA224Hash.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFSHA224Hash.m ================================================================== --- src/OFSHA224Hash.m +++ src/OFSHA224Hash.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -17,21 +15,21 @@ #include "config.h" #import "OFSHA224Hash.h" -#define DIGEST_SIZE 28 +static const size_t digestSize = 28; @implementation OFSHA224Hash + (size_t)digestSize { - return DIGEST_SIZE; + return digestSize; } - (size_t)digestSize { - return DIGEST_SIZE; + return digestSize; } - (void)of_resetState { _iVars->state[0] = 0xC1059ED8; Index: src/OFSHA224Or256Hash.h ================================================================== --- src/OFSHA224Or256Hash.h +++ src/OFSHA224Or256Hash.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -13,11 +11,11 @@ * 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 "OFCryptoHash.h" +#import "OFCryptographicHash.h" OF_ASSUME_NONNULL_BEGIN @class OFSecureData; @@ -24,19 +22,19 @@ /** * @class OFSHA224Or256Hash OFSHA224Or256Hash.h ObjFW/OFSHA224Or256Hash.h * * @brief A base class for SHA-224 and SHA-256. */ -@interface OFSHA224Or256Hash: OFObject +@interface OFSHA224Or256Hash: OFObject { @private OFSecureData *_iVarsData; @protected - struct of_sha224_or_256_hash_ivars { + struct { uint32_t state[8]; uint64_t bits; - union of_sha224_or_256_hash_buffer { + union { unsigned char bytes[64]; uint32_t words[64]; } buffer; size_t bufferLength; } *_iVars; Index: src/OFSHA224Or256Hash.m ================================================================== --- src/OFSHA224Or256Hash.m +++ src/OFSHA224Or256Hash.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -22,13 +20,14 @@ #import "OFSHA224Or256Hash.h" #import "OFSecureData.h" #import "OFHashAlreadyCalculatedException.h" +#import "OFHashNotCalculatedException.h" #import "OFOutOfRangeException.h" -#define BLOCK_SIZE 64 +static const size_t blockSize = 64; @interface OFSHA224Or256Hash () - (void)of_resetState; @end @@ -54,11 +53,11 @@ static OF_INLINE void byteSwapVectorIfLE(uint32_t *vector, uint_fast8_t length) { #ifndef OF_BIG_ENDIAN for (uint_fast8_t i = 0; i < length; i++) - vector[i] = OF_BSWAP32(vector[i]); + vector[i] = OFByteSwap32(vector[i]); #endif } static void processBlock(uint32_t *state, uint32_t *buffer) @@ -79,24 +78,24 @@ for (i = 16; i < 64; i++) { uint32_t tmp; tmp = buffer[i - 2]; - buffer[i] = (OF_ROR(tmp, 17) ^ OF_ROR(tmp, 19) ^ (tmp >> 10)) + - buffer[i - 7]; + buffer[i] = (OFRotateRight(tmp, 17) ^ OFRotateRight(tmp, 19) ^ + (tmp >> 10)) + buffer[i - 7]; tmp = buffer[i - 15]; - buffer[i] += (OF_ROR(tmp, 7) ^ OF_ROR(tmp, 18) ^ (tmp >> 3)) + - buffer[i - 16]; + buffer[i] += (OFRotateRight(tmp, 7) ^ OFRotateRight(tmp, 18) ^ + (tmp >> 3)) + buffer[i - 16]; } for (i = 0; i < 64; i++) { - uint32_t tmp1 = new[7] + (OF_ROR(new[4], 6) ^ - OF_ROR(new[4], 11) ^ OF_ROR(new[4], 25)) + + uint32_t tmp1 = new[7] + (OFRotateRight(new[4], 6) ^ + OFRotateRight(new[4], 11) ^ OFRotateRight(new[4], 25)) + ((new[4] & (new[5] ^ new[6])) ^ new[6]) + table[i] + buffer[i]; - uint32_t tmp2 = (OF_ROR(new[0], 2) ^ OF_ROR(new[0], 13) ^ - OF_ROR(new[0], 22)) + + uint32_t tmp2 = (OFRotateRight(new[0], 2) ^ + OFRotateRight(new[0], 13) ^ OFRotateRight(new[0], 22)) + ((new[0] & (new[1] | new[2])) | (new[1] & new[2])); new[7] = new[6]; new[6] = new[5]; new[5] = new[4]; @@ -126,14 +125,14 @@ OF_UNRECOGNIZED_SELECTOR } + (size_t)blockSize { - return BLOCK_SIZE; + return blockSize; } -+ (instancetype)cryptoHashWithAllowsSwappableMemory: (bool)allowsSwappableMemory ++ (instancetype)hashWithAllowsSwappableMemory: (bool)allowsSwappableMemory { return [[[self alloc] initWithAllowsSwappableMemory: allowsSwappableMemory] autorelease]; } @@ -184,11 +183,11 @@ OF_UNRECOGNIZED_SELECTOR } - (size_t)blockSize { - return BLOCK_SIZE; + return blockSize; } - (id)copy { OFSHA224Or256Hash *copy = [[[self class] alloc] of_init]; @@ -199,12 +198,11 @@ copy->_calculated = _calculated; return copy; } -- (void)updateWithBuffer: (const void *)buffer_ - length: (size_t)length +- (void)updateWithBuffer: (const void *)buffer_ length: (size_t)length { const unsigned char *buffer = buffer_; if (_calculated) @throw [OFHashAlreadyCalculatedException @@ -235,44 +233,51 @@ } } - (const unsigned char *)digest { + if (!_calculated) + @throw [OFHashNotCalculatedException exceptionWithObject: self]; + + return (const unsigned char *)_iVars->state; +} + +- (void)calculate +{ if (_calculated) - return (const unsigned char *)_iVars->state; + @throw [OFHashAlreadyCalculatedException + exceptionWithObject: self]; _iVars->buffer.bytes[_iVars->bufferLength] = 0x80; - of_explicit_memset(_iVars->buffer.bytes + _iVars->bufferLength + 1, 0, + OFZeroMemory(_iVars->buffer.bytes + _iVars->bufferLength + 1, 64 - _iVars->bufferLength - 1); if (_iVars->bufferLength >= 56) { processBlock(_iVars->state, _iVars->buffer.words); - of_explicit_memset(_iVars->buffer.bytes, 0, 64); + OFZeroMemory(_iVars->buffer.bytes, 64); } _iVars->buffer.words[14] = - OF_BSWAP32_IF_LE((uint32_t)(_iVars->bits >> 32)); + OFToBigEndian32((uint32_t)(_iVars->bits >> 32)); _iVars->buffer.words[15] = - OF_BSWAP32_IF_LE((uint32_t)(_iVars->bits & 0xFFFFFFFF)); + OFToBigEndian32((uint32_t)(_iVars->bits & 0xFFFFFFFF)); processBlock(_iVars->state, _iVars->buffer.words); - of_explicit_memset(&_iVars->buffer, 0, sizeof(_iVars->buffer)); + OFZeroMemory(&_iVars->buffer, sizeof(_iVars->buffer)); byteSwapVectorIfLE(_iVars->state, 8); _calculated = true; - - return (const unsigned char *)_iVars->state; } - (void)reset { [self of_resetState]; _iVars->bits = 0; - of_explicit_memset(&_iVars->buffer, 0, sizeof(_iVars->buffer)); + OFZeroMemory(&_iVars->buffer, sizeof(_iVars->buffer)); _iVars->bufferLength = 0; _calculated = false; } - (void)of_resetState { OF_UNRECOGNIZED_SELECTOR } @end Index: src/OFSHA256Hash.h ================================================================== --- src/OFSHA256Hash.h +++ src/OFSHA256Hash.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFSHA256Hash.m ================================================================== --- src/OFSHA256Hash.m +++ src/OFSHA256Hash.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -17,21 +15,21 @@ #include "config.h" #import "OFSHA256Hash.h" -#define DIGEST_SIZE 32 +static const size_t digestSize = 32; @implementation OFSHA256Hash + (size_t)digestSize { - return DIGEST_SIZE; + return digestSize; } - (size_t)digestSize { - return DIGEST_SIZE; + return digestSize; } - (void)of_resetState { _iVars->state[0] = 0x6A09E667; Index: src/OFSHA384Hash.h ================================================================== --- src/OFSHA384Hash.h +++ src/OFSHA384Hash.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFSHA384Hash.m ================================================================== --- src/OFSHA384Hash.m +++ src/OFSHA384Hash.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -17,21 +15,21 @@ #include "config.h" #import "OFSHA384Hash.h" -#define DIGEST_SIZE 48 +static const size_t digestSize = 48; @implementation OFSHA384Hash + (size_t)digestSize { - return DIGEST_SIZE; + return digestSize; } - (size_t)digestSize { - return DIGEST_SIZE; + return digestSize; } - (void)of_resetState { _iVars->state[0] = 0xCBBB9D5DC1059ED8; Index: src/OFSHA384Or512Hash.h ================================================================== --- src/OFSHA384Or512Hash.h +++ src/OFSHA384Or512Hash.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -13,11 +11,11 @@ * 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 "OFCryptoHash.h" +#import "OFCryptographicHash.h" OF_ASSUME_NONNULL_BEGIN @class OFSecureData; @@ -24,19 +22,19 @@ /** * @class OFSHA384Or512Hash OFSHA384Or512Hash.h ObjFW/OFSHA384Or512Hash.h * * @brief A base class for SHA-384 and SHA-512. */ -@interface OFSHA384Or512Hash: OFObject +@interface OFSHA384Or512Hash: OFObject { @private OFSecureData *_iVarsData; @protected - struct of_sha384_or_512_hash_ivars { + struct { uint64_t state[8]; uint64_t bits[2]; - union of_sha384_or_512_hash_buffer { + union { unsigned char bytes[128]; uint64_t words[80]; } buffer; size_t bufferLength; } *_iVars; Index: src/OFSHA384Or512Hash.m ================================================================== --- src/OFSHA384Or512Hash.m +++ src/OFSHA384Or512Hash.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -22,13 +20,14 @@ #import "OFSHA384Or512Hash.h" #import "OFSecureData.h" #import "OFHashAlreadyCalculatedException.h" +#import "OFHashNotCalculatedException.h" #import "OFOutOfRangeException.h" -#define BLOCK_SIZE 128 +static const size_t blockSize = 128; @interface OFSHA384Or512Hash () - (void)of_resetState; @end @@ -65,11 +64,11 @@ static OF_INLINE void byteSwapVectorIfLE(uint64_t *vector, uint_fast8_t length) { #ifndef OF_BIG_ENDIAN for (uint_fast8_t i = 0; i < length; i++) - vector[i] = OF_BSWAP64(vector[i]); + vector[i] = OFByteSwap64(vector[i]); #endif } static void processBlock(uint64_t *state, uint64_t *buffer) @@ -90,24 +89,24 @@ for (i = 16; i < 80; i++) { uint64_t tmp; tmp = buffer[i - 2]; - buffer[i] = (OF_ROR(tmp, 19) ^ OF_ROR(tmp, 61) ^ (tmp >> 6)) + - buffer[i - 7]; + buffer[i] = (OFRotateRight(tmp, 19) ^ OFRotateRight(tmp, 61) ^ + (tmp >> 6)) + buffer[i - 7]; tmp = buffer[i - 15]; - buffer[i] += (OF_ROR(tmp, 1) ^ OF_ROR(tmp, 8) ^ (tmp >> 7)) + - buffer[i - 16]; + buffer[i] += (OFRotateRight(tmp, 1) ^ OFRotateRight(tmp, 8) ^ + (tmp >> 7)) + buffer[i - 16]; } for (i = 0; i < 80; i++) { - uint64_t tmp1 = new[7] + (OF_ROR(new[4], 14) ^ - OF_ROR(new[4], 18) ^ OF_ROR(new[4], 41)) + + uint64_t tmp1 = new[7] + (OFRotateRight(new[4], 14) ^ + OFRotateRight(new[4], 18) ^ OFRotateRight(new[4], 41)) + ((new[4] & (new[5] ^ new[6])) ^ new[6]) + table[i] + buffer[i]; - uint64_t tmp2 = (OF_ROR(new[0], 28) ^ OF_ROR(new[0], 34) ^ - OF_ROR(new[0], 39)) + + uint64_t tmp2 = (OFRotateRight(new[0], 28) ^ + OFRotateRight(new[0], 34) ^ OFRotateRight(new[0], 39)) + ((new[0] & (new[1] | new[2])) | (new[1] & new[2])); new[7] = new[6]; new[6] = new[5]; new[5] = new[4]; @@ -137,14 +136,14 @@ OF_UNRECOGNIZED_SELECTOR } + (size_t)blockSize { - return BLOCK_SIZE; + return blockSize; } -+ (instancetype)cryptoHashWithAllowsSwappableMemory: (bool)allowsSwappableMemory ++ (instancetype)hashWithAllowsSwappableMemory: (bool)allowsSwappableMemory { return [[[self alloc] initWithAllowsSwappableMemory: allowsSwappableMemory] autorelease]; } @@ -195,11 +194,11 @@ OF_UNRECOGNIZED_SELECTOR } - (size_t)blockSize { - return BLOCK_SIZE; + return blockSize; } - (id)copy { OFSHA384Or512Hash *copy = [[[self class] alloc] of_init]; @@ -210,12 +209,11 @@ copy->_calculated = _calculated; return copy; } -- (void)updateWithBuffer: (const void *)buffer_ - length: (size_t)length +- (void)updateWithBuffer: (const void *)buffer_ length: (size_t)length { const unsigned char *buffer = buffer_; if (_calculated) @throw [OFHashAlreadyCalculatedException @@ -248,42 +246,49 @@ } } - (const unsigned char *)digest { + if (!_calculated) + @throw [OFHashNotCalculatedException exceptionWithObject: self]; + + return (const unsigned char *)_iVars->state; +} + +- (void)calculate +{ if (_calculated) - return (const unsigned char *)_iVars->state; + @throw [OFHashAlreadyCalculatedException + exceptionWithObject: self]; _iVars->buffer.bytes[_iVars->bufferLength] = 0x80; - of_explicit_memset(_iVars->buffer.bytes + _iVars->bufferLength + 1, 0, + OFZeroMemory(_iVars->buffer.bytes + _iVars->bufferLength + 1, 128 - _iVars->bufferLength - 1); if (_iVars->bufferLength >= 112) { processBlock(_iVars->state, _iVars->buffer.words); - of_explicit_memset(_iVars->buffer.bytes, 0, 128); + OFZeroMemory(_iVars->buffer.bytes, 128); } - _iVars->buffer.words[14] = OF_BSWAP64_IF_LE(_iVars->bits[1]); - _iVars->buffer.words[15] = OF_BSWAP64_IF_LE(_iVars->bits[0]); + _iVars->buffer.words[14] = OFToBigEndian64(_iVars->bits[1]); + _iVars->buffer.words[15] = OFToBigEndian64(_iVars->bits[0]); processBlock(_iVars->state, _iVars->buffer.words); - of_explicit_memset(&_iVars->buffer, 0, sizeof(_iVars->buffer)); + OFZeroMemory(&_iVars->buffer, sizeof(_iVars->buffer)); byteSwapVectorIfLE(_iVars->state, 8); _calculated = true; - - return (const unsigned char *)_iVars->state; } - (void)reset { [self of_resetState]; - of_explicit_memset(_iVars->bits, 0, sizeof(_iVars->bits)); - of_explicit_memset(&_iVars->buffer, 0, sizeof(_iVars->buffer)); + OFZeroMemory(_iVars->bits, sizeof(_iVars->bits)); + OFZeroMemory(&_iVars->buffer, sizeof(_iVars->buffer)); _iVars->bufferLength = 0; _calculated = false; } - (void)of_resetState { OF_UNRECOGNIZED_SELECTOR } @end Index: src/OFSHA512Hash.h ================================================================== --- src/OFSHA512Hash.h +++ src/OFSHA512Hash.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFSHA512Hash.m ================================================================== --- src/OFSHA512Hash.m +++ src/OFSHA512Hash.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -17,21 +15,21 @@ #include "config.h" #import "OFSHA512Hash.h" -#define DIGEST_SIZE 64 +static const size_t digestSize = 64; @implementation OFSHA512Hash + (size_t)digestSize { - return DIGEST_SIZE; + return digestSize; } - (size_t)digestSize { - return DIGEST_SIZE; + return digestSize; } - (void)of_resetState { _iVars->state[0] = 0x6A09E667F3BCC908; Index: src/OFSPXSocket.h ================================================================== --- src/OFSPXSocket.h +++ src/OFSPXSocket.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -30,11 +28,11 @@ * @brief A block which is called when the socket connected. * * @param exception An exception which occurred while connecting the socket or * `nil` on success */ -typedef void (^of_spx_socket_async_connect_block_t)(id _Nullable exception); +typedef void (^OFSPXSocketAsyncConnectBlock)(id _Nullable exception); #endif /** * @protocol OFSPXSocketDelegate OFSPXSocket.h ObjFW/OFSPXSocket.h * @@ -118,11 +116,11 @@ * @param runLoopMode The run loop mode in which to perform the async connect */ - (void)asyncConnectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node network: (uint32_t)network port: (uint16_t)port - runLoopMode: (of_run_loop_mode_t)runLoopMode; + runLoopMode: (OFRunLoopMode)runLoopMode; #ifdef OF_HAVE_BLOCKS /** * @brief Asynchronously connect the OFSPXSocket to the specified destination. * @@ -133,11 +131,11 @@ * @param block The block to execute once the connection has been established */ - (void)asyncConnectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node network: (uint32_t)network port: (uint16_t)port - block: (of_spx_socket_async_connect_block_t)block; + block: (OFSPXSocketAsyncConnectBlock)block; /** * @brief Asynchronously connect the OFSPXSocket to the specified destination. * * @param node The node to connect to @@ -148,20 +146,20 @@ * @param block The block to execute once the connection has been established */ - (void)asyncConnectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node network: (uint32_t)network port: (uint16_t)port - runLoopMode: (of_run_loop_mode_t)runLoopMode - block: (of_spx_socket_async_connect_block_t)block; + runLoopMode: (OFRunLoopMode)runLoopMode + block: (OFSPXSocketAsyncConnectBlock)block; #endif /** * @brief Bind the socket to the specified network, node and port. * * @param port The port (sometimes called socket number) to bind to. 0 means to * pick one and return it. * @return The address on which this socket can be reached */ -- (of_socket_address_t)bindToPort: (uint16_t)port; +- (OFSocketAddress)bindToPort: (uint16_t)port; @end OF_ASSUME_NONNULL_END Index: src/OFSPXSocket.m ================================================================== --- src/OFSPXSocket.m +++ src/OFSPXSocket.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -20,29 +18,28 @@ #include #import "OFSPXSocket.h" #import "OFRunLoop.h" #import "OFRunLoop+Private.h" +#import "OFSocket.h" +#import "OFSocket+Private.h" #import "OFAlreadyConnectedException.h" #import "OFBindFailedException.h" #import "OFConnectionFailedException.h" #import "OFNotOpenException.h" -#import "socket.h" -#import "socket_helpers.h" - #ifndef NSPROTO_SPX # define NSPROTO_SPX 0 #endif -#define SPX_PACKET_TYPE 5 +static const uint8_t SPXPacketType = 5; @interface OFSPXSocket () -- (int)of_createSocketForAddress: (const of_socket_address_t *)address +- (int)of_createSocketForAddress: (const OFSocketAddress *)address errNo: (int *)errNo; -- (bool)of_connectSocketToAddress: (const of_socket_address_t *)address +- (bool)of_connectSocketToAddress: (const OFSocketAddress *)address errNo: (int *)errNo; - (void)of_closeSocket; @end OF_DIRECT_MEMBERS @@ -51,32 +48,32 @@ OFSPXSocket *_socket; unsigned char _node[IPX_NODE_LEN]; uint32_t _network; uint16_t _port; #ifdef OF_HAVE_BLOCKS - of_spx_socket_async_connect_block_t _block; + OFSPXSocketAsyncConnectBlock _block; #endif } - (instancetype)initWithSocket: (OFSPXSocket *)socket node: (unsigned char [IPX_NODE_LEN])node network: (uint32_t)network port: (uint16_t)port #ifdef OF_HAVE_BLOCKS - block: (of_spx_socket_async_connect_block_t)block + block: (OFSPXSocketAsyncConnectBlock)block #endif ; -- (void)startWithRunLoopMode: (of_run_loop_mode_t)runLoopMode; +- (void)startWithRunLoopMode: (OFRunLoopMode)runLoopMode; @end @implementation OFSPXSocketAsyncConnectDelegate - (instancetype)initWithSocket: (OFSPXSocket *)sock node: (unsigned char [IPX_NODE_LEN])node network: (uint32_t)network port: (uint16_t)port #ifdef OF_HAVE_BLOCKS - block: (of_spx_socket_async_connect_block_t)block + block: (OFSPXSocketAsyncConnectBlock)block #endif { self = [super init]; @try { @@ -103,28 +100,30 @@ #endif [super dealloc]; } -- (void)startWithRunLoopMode: (of_run_loop_mode_t)runLoopMode +- (void)startWithRunLoopMode: (OFRunLoopMode)runLoopMode { - of_socket_address_t address = - of_socket_address_ipx(_node, _network, _port); + OFSocketAddress address = + OFSocketAddressMakeIPX(_node, _network, _port); id exception = nil; int errNo; - if (![_socket of_createSocketForAddress: &address - errNo: &errNo]) { + if (![_socket of_createSocketForAddress: &address errNo: &errNo]) { exception = [self of_connectionFailedExceptionForErrNo: errNo]; goto inform_delegate; } _socket.canBlock = false; - if (![_socket of_connectSocketToAddress: &address - errNo: &errNo]) { + if (![_socket of_connectSocketToAddress: &address errNo: &errNo]) { +#ifdef OF_WINDOWS + if (errNo == EINPROGRESS || errNo == EWOULDBLOCK) { +#else if (errNo == EINPROGRESS) { +#endif [OFRunLoop of_addAsyncConnectForSocket: _socket mode: runLoopMode delegate: self]; return; } @@ -139,12 +138,11 @@ withObject: _socket withObject: exception afterDelay: 0]; } -- (void)of_socketDidConnect: (id)sock - exception: (id)exception +- (void)of_socketDidConnect: (id)sock exception: (id)exception { id delegate = ((OFSPXSocket *)sock).delegate; if (exception == nil) ((OFSPXSocket *)sock).canBlock = true; @@ -177,23 +175,24 @@ @end @implementation OFSPXSocket @dynamic delegate; -- (int)of_createSocketForAddress: (const of_socket_address_t *)address +- (int)of_createSocketForAddress: (const OFSocketAddress *)address errNo: (int *)errNo { #if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) int flags; #endif - if (_socket != INVALID_SOCKET) + if (_socket != OFInvalidSocketHandle) @throw [OFAlreadyConnectedException exceptionWithSocket: self]; if ((_socket = socket(address->sockaddr.ipx.sipx_family, - SOCK_SEQPACKET | SOCK_CLOEXEC, NSPROTO_SPX)) == INVALID_SOCKET) { - *errNo = of_socket_errno(); + SOCK_SEQPACKET | SOCK_CLOEXEC, NSPROTO_SPX)) == + OFInvalidSocketHandle) { + *errNo = OFSocketErrNo(); return false; } #if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) if ((flags = fcntl(_socket, F_GETFD, 0)) != -1) @@ -201,50 +200,47 @@ #endif return true; } -- (bool)of_connectSocketToAddress: (const of_socket_address_t *)address +- (bool)of_connectSocketToAddress: (const OFSocketAddress *)address errNo: (int *)errNo { - if (_socket == INVALID_SOCKET) + if (_socket == OFInvalidSocketHandle) @throw [OFNotOpenException exceptionWithObject: self]; if (connect(_socket, &address->sockaddr.sockaddr, address->length) != 0) { - *errNo = of_socket_errno(); + *errNo = OFSocketErrNo(); return false; } return true; } - (void)of_closeSocket { closesocket(_socket); - _socket = INVALID_SOCKET; + _socket = OFInvalidSocketHandle; } - (void)connectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node network: (uint32_t)network port: (uint16_t)port { - of_socket_address_t address = - of_socket_address_ipx(node, network, port); + OFSocketAddress address = OFSocketAddressMakeIPX(node, network, port); int errNo; - if (![self of_createSocketForAddress: &address - errNo: &errNo]) + if (![self of_createSocketForAddress: &address errNo: &errNo]) @throw [OFConnectionFailedException exceptionWithNode: node network: network port: port socket: self errNo: errNo]; - if (![self of_connectSocketToAddress: &address - errNo: &errNo]) { + if (![self of_connectSocketToAddress: &address errNo: &errNo]) { [self of_closeSocket]; @throw [OFConnectionFailedException exceptionWithNode: node network: network @@ -259,17 +255,17 @@ port: (uint16_t)port { [self asyncConnectToNode: node network: network port: port - runLoopMode: of_run_loop_mode_default]; + runLoopMode: OFDefaultRunLoopMode]; } - (void)asyncConnectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node network: (uint32_t)network port: (uint16_t)port - runLoopMode: (of_run_loop_mode_t)runLoopMode + runLoopMode: (OFRunLoopMode)runLoopMode { void *pool = objc_autoreleasePoolPush(); [[[[OFSPXSocketAsyncConnectDelegate alloc] initWithSocket: self @@ -286,24 +282,24 @@ #ifdef OF_HAVE_BLOCKS - (void)asyncConnectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node network: (uint32_t)network port: (uint16_t)port - block: (of_spx_socket_async_connect_block_t)block + block: (OFSPXSocketAsyncConnectBlock)block { [self asyncConnectToNode: node network: network port: port - runLoopMode: of_run_loop_mode_default + runLoopMode: OFDefaultRunLoopMode block: block]; } - (void)asyncConnectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node network: (uint32_t)network port: (uint16_t)port - runLoopMode: (of_run_loop_mode_t)runLoopMode - block: (of_spx_socket_async_connect_block_t)block + runLoopMode: (OFRunLoopMode)runLoopMode + block: (OFSPXSocketAsyncConnectBlock)block { void *pool = objc_autoreleasePoolPush(); [[[[OFSPXSocketAsyncConnectDelegate alloc] initWithSocket: self @@ -315,75 +311,76 @@ objc_autoreleasePoolPop(pool); } #endif -- (of_socket_address_t)bindToPort: (uint16_t)port +- (OFSocketAddress)bindToPort: (uint16_t)port { const unsigned char zeroNode[IPX_NODE_LEN] = { 0 }; - of_socket_address_t address; + OFSocketAddress address; #if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL_H) && defined(FD_CLOEXEC) int flags; #endif - if (_socket != INVALID_SOCKET) + if (_socket != OFInvalidSocketHandle) @throw [OFAlreadyConnectedException exceptionWithSocket: self]; - address = of_socket_address_ipx(zeroNode, 0, port); + address = OFSocketAddressMakeIPX(zeroNode, 0, port); if ((_socket = socket(address.sockaddr.sockaddr.sa_family, - SOCK_SEQPACKET | SOCK_CLOEXEC, NSPROTO_SPX)) == INVALID_SOCKET) + SOCK_SEQPACKET | SOCK_CLOEXEC, NSPROTO_SPX)) == + OFInvalidSocketHandle) @throw [OFBindFailedException exceptionWithPort: port - packetType: SPX_PACKET_TYPE + packetType: SPXPacketType socket: self - errNo: of_socket_errno()]; + 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, &address.sockaddr.sockaddr, address.length) != 0) { - int errNo = of_socket_errno(); + int errNo = OFSocketErrNo(); closesocket(_socket); - _socket = INVALID_SOCKET; + _socket = OFInvalidSocketHandle; @throw [OFBindFailedException exceptionWithPort: port - packetType: SPX_PACKET_TYPE + packetType: SPXPacketType socket: self errNo: errNo]; } memset(&address, 0, sizeof(address)); - address.family = OF_SOCKET_ADDRESS_FAMILY_IPX; + address.family = OFSocketAddressFamilyIPX; address.length = (socklen_t)sizeof(address.sockaddr); - if (of_getsockname(_socket, &address.sockaddr.sockaddr, + if (OFGetSockName(_socket, &address.sockaddr.sockaddr, &address.length) != 0) { - int errNo = of_socket_errno(); + int errNo = OFSocketErrNo(); closesocket(_socket); - _socket = INVALID_SOCKET; + _socket = OFInvalidSocketHandle; @throw [OFBindFailedException exceptionWithPort: port - packetType: SPX_PACKET_TYPE + packetType: SPXPacketType socket: self errNo: errNo]; } if (address.sockaddr.sockaddr.sa_family != AF_IPX) { closesocket(_socket); - _socket = INVALID_SOCKET; + _socket = OFInvalidSocketHandle; @throw [OFBindFailedException exceptionWithPort: port - packetType: SPX_PACKET_TYPE + packetType: SPXPacketType socket: self errNo: EAFNOSUPPORT]; } return address; } @end Index: src/OFSPXStreamSocket.h ================================================================== --- src/OFSPXStreamSocket.h +++ src/OFSPXStreamSocket.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -30,12 +28,11 @@ * @brief A block which is called when the socket connected. * * @param exception An exception which occurred while connecting the socket or * `nil` on success */ -typedef void (^of_spx_stream_socket_async_connect_block_t)( - id _Nullable exception); +typedef void (^OFSPXStreamSocketAsyncConnectBlock)(id _Nullable exception); #endif /** * @protocol OFSPXStreamSocketDelegate OFSPXStreamSocket.h \ * ObjFW/OFSPXStreamSocket.h @@ -122,11 +119,11 @@ * @param runLoopMode The run loop mode in which to perform the async connect */ - (void)asyncConnectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node network: (uint32_t)network port: (uint16_t)port - runLoopMode: (of_run_loop_mode_t)runLoopMode; + runLoopMode: (OFRunLoopMode)runLoopMode; #ifdef OF_HAVE_BLOCKS /** * @brief Asynchronously connect the OFSPXStreamSocket to the specified * destination. @@ -138,11 +135,11 @@ * @param block The block to execute once the connection has been established */ - (void)asyncConnectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node network: (uint32_t)network port: (uint16_t)port - block: (of_spx_stream_socket_async_connect_block_t)block; + block: (OFSPXStreamSocketAsyncConnectBlock)block; /** * @brief Asynchronously connect the OFSPXStreamSocket to the specified * destination. * @@ -154,20 +151,20 @@ * @param block The block to execute once the connection has been established */ - (void)asyncConnectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node network: (uint32_t)network port: (uint16_t)port - runLoopMode: (of_run_loop_mode_t)runLoopMode - block: (of_spx_stream_socket_async_connect_block_t)block; + runLoopMode: (OFRunLoopMode)runLoopMode + block: (OFSPXStreamSocketAsyncConnectBlock)block; #endif /** * @brief Bind the socket to the specified network, node and port. * * @param port The port (sometimes called socket number) to bind to. 0 means to * pick one and return it. * @return The address on which this socket can be reached */ -- (of_socket_address_t)bindToPort: (uint16_t)port; +- (OFSocketAddress)bindToPort: (uint16_t)port; @end OF_ASSUME_NONNULL_END Index: src/OFSPXStreamSocket.m ================================================================== --- src/OFSPXStreamSocket.m +++ src/OFSPXStreamSocket.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -20,29 +18,28 @@ #include #import "OFSPXStreamSocket.h" #import "OFRunLoop.h" #import "OFRunLoop+Private.h" +#import "OFSocket.h" +#import "OFSocket+Private.h" #import "OFAlreadyConnectedException.h" #import "OFBindFailedException.h" #import "OFConnectionFailedException.h" #import "OFNotOpenException.h" -#import "socket.h" -#import "socket_helpers.h" - #ifndef NSPROTO_SPX # define NSPROTO_SPX 0 #endif -#define SPX_PACKET_TYPE 5 +static const uint8_t SPXPacketType = 5; @interface OFSPXStreamSocket () -- (int)of_createSocketForAddress: (const of_socket_address_t *)address +- (int)of_createSocketForAddress: (const OFSocketAddress *)address errNo: (int *)errNo; -- (bool)of_connectSocketToAddress: (const of_socket_address_t *)address +- (bool)of_connectSocketToAddress: (const OFSocketAddress *)address errNo: (int *)errNo; - (void)of_closeSocket; @end OF_DIRECT_MEMBERS @@ -52,34 +49,32 @@ OFSPXStreamSocket *_socket; unsigned char _node[IPX_NODE_LEN]; uint32_t _network; uint16_t _port; #ifdef OF_HAVE_BLOCKS - of_spx_stream_socket_async_connect_block_t _block; + OFSPXStreamSocketAsyncConnectBlock _block; #endif } - (instancetype)initWithSocket: (OFSPXStreamSocket *)socket node: (unsigned char [IPX_NODE_LEN])node network: (uint32_t)network port: (uint16_t)port #ifdef OF_HAVE_BLOCKS - block: (of_spx_stream_socket_async_connect_block_t) - block + block: (OFSPXStreamSocketAsyncConnectBlock)block #endif ; -- (void)startWithRunLoopMode: (of_run_loop_mode_t)runLoopMode; +- (void)startWithRunLoopMode: (OFRunLoopMode)runLoopMode; @end @implementation OFSPXStreamSocketAsyncConnectDelegate - (instancetype)initWithSocket: (OFSPXStreamSocket *)sock node: (unsigned char [IPX_NODE_LEN])node network: (uint32_t)network port: (uint16_t)port #ifdef OF_HAVE_BLOCKS - block: (of_spx_stream_socket_async_connect_block_t) - block + block: (OFSPXStreamSocketAsyncConnectBlock)block #endif { self = [super init]; @try { @@ -106,28 +101,30 @@ #endif [super dealloc]; } -- (void)startWithRunLoopMode: (of_run_loop_mode_t)runLoopMode +- (void)startWithRunLoopMode: (OFRunLoopMode)runLoopMode { - of_socket_address_t address = - of_socket_address_ipx(_node, _network, _port); + OFSocketAddress address = + OFSocketAddressMakeIPX(_node, _network, _port); id exception = nil; int errNo; - if (![_socket of_createSocketForAddress: &address - errNo: &errNo]) { + if (![_socket of_createSocketForAddress: &address errNo: &errNo]) { exception = [self of_connectionFailedExceptionForErrNo: errNo]; goto inform_delegate; } _socket.canBlock = false; - if (![_socket of_connectSocketToAddress: &address - errNo: &errNo]) { + if (![_socket of_connectSocketToAddress: &address errNo: &errNo]) { +#ifdef OF_WINDOWS + if (errNo == EINPROGRESS || errNo == EWOULDBLOCK) { +#else if (errNo == EINPROGRESS) { +#endif [OFRunLoop of_addAsyncConnectForSocket: _socket mode: runLoopMode delegate: self]; return; } @@ -142,12 +139,11 @@ withObject: _socket withObject: exception afterDelay: 0]; } -- (void)of_socketDidConnect: (id)sock - exception: (id)exception +- (void)of_socketDidConnect: (id)sock exception: (id)exception { id delegate = ((OFSPXStreamSocket *)sock).delegate; if (exception == nil) @@ -181,23 +177,24 @@ @end @implementation OFSPXStreamSocket @dynamic delegate; -- (int)of_createSocketForAddress: (const of_socket_address_t *)address +- (int)of_createSocketForAddress: (const OFSocketAddress *)address errNo: (int *)errNo { #if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) int flags; #endif - if (_socket != INVALID_SOCKET) + if (_socket != OFInvalidSocketHandle) @throw [OFAlreadyConnectedException exceptionWithSocket: self]; if ((_socket = socket(address->sockaddr.ipx.sipx_family, - SOCK_SEQPACKET | SOCK_CLOEXEC, NSPROTO_SPX)) == INVALID_SOCKET) { - *errNo = of_socket_errno(); + SOCK_SEQPACKET | SOCK_CLOEXEC, NSPROTO_SPX)) == + OFInvalidSocketHandle) { + *errNo = OFSocketErrNo(); return false; } #if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) if ((flags = fcntl(_socket, F_GETFD, 0)) != -1) @@ -205,50 +202,47 @@ #endif return true; } -- (bool)of_connectSocketToAddress: (const of_socket_address_t *)address +- (bool)of_connectSocketToAddress: (const OFSocketAddress *)address errNo: (int *)errNo { - if (_socket == INVALID_SOCKET) + if (_socket == OFInvalidSocketHandle) @throw [OFNotOpenException exceptionWithObject: self]; if (connect(_socket, &address->sockaddr.sockaddr, address->length) != 0) { - *errNo = of_socket_errno(); + *errNo = OFSocketErrNo(); return false; } return true; } - (void)of_closeSocket { closesocket(_socket); - _socket = INVALID_SOCKET; + _socket = OFInvalidSocketHandle; } - (void)connectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node network: (uint32_t)network port: (uint16_t)port { - of_socket_address_t address = - of_socket_address_ipx(node, network, port); + OFSocketAddress address = OFSocketAddressMakeIPX(node, network, port); int errNo; - if (![self of_createSocketForAddress: &address - errNo: &errNo]) + if (![self of_createSocketForAddress: &address errNo: &errNo]) @throw [OFConnectionFailedException exceptionWithNode: node network: network port: port socket: self errNo: errNo]; - if (![self of_connectSocketToAddress: &address - errNo: &errNo]) { + if (![self of_connectSocketToAddress: &address errNo: &errNo]) { [self of_closeSocket]; @throw [OFConnectionFailedException exceptionWithNode: node network: network @@ -263,17 +257,17 @@ port: (uint16_t)port { [self asyncConnectToNode: node network: network port: port - runLoopMode: of_run_loop_mode_default]; + runLoopMode: OFDefaultRunLoopMode]; } - (void)asyncConnectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node network: (uint32_t)network port: (uint16_t)port - runLoopMode: (of_run_loop_mode_t)runLoopMode + runLoopMode: (OFRunLoopMode)runLoopMode { void *pool = objc_autoreleasePoolPush(); [[[[OFSPXStreamSocketAsyncConnectDelegate alloc] initWithSocket: self @@ -290,24 +284,24 @@ #ifdef OF_HAVE_BLOCKS - (void)asyncConnectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node network: (uint32_t)network port: (uint16_t)port - block: (of_spx_stream_socket_async_connect_block_t)block + block: (OFSPXStreamSocketAsyncConnectBlock)block { [self asyncConnectToNode: node network: network port: port - runLoopMode: of_run_loop_mode_default + runLoopMode: OFDefaultRunLoopMode block: block]; } - (void)asyncConnectToNode: (unsigned char [_Nonnull IPX_NODE_LEN])node network: (uint32_t)network port: (uint16_t)port - runLoopMode: (of_run_loop_mode_t)runLoopMode - block: (of_spx_stream_socket_async_connect_block_t)block + runLoopMode: (OFRunLoopMode)runLoopMode + block: (OFSPXStreamSocketAsyncConnectBlock)block { void *pool = objc_autoreleasePoolPush(); [[[[OFSPXStreamSocketAsyncConnectDelegate alloc] initWithSocket: self @@ -319,75 +313,75 @@ objc_autoreleasePoolPop(pool); } #endif -- (of_socket_address_t)bindToPort: (uint16_t)port +- (OFSocketAddress)bindToPort: (uint16_t)port { const unsigned char zeroNode[IPX_NODE_LEN] = { 0 }; - of_socket_address_t address; + OFSocketAddress address; #if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL_H) && defined(FD_CLOEXEC) int flags; #endif - if (_socket != INVALID_SOCKET) + if (_socket != OFInvalidSocketHandle) @throw [OFAlreadyConnectedException exceptionWithSocket: self]; - address = of_socket_address_ipx(zeroNode, 0, port); + address = OFSocketAddressMakeIPX(zeroNode, 0, port); if ((_socket = socket(address.sockaddr.sockaddr.sa_family, - SOCK_STREAM | SOCK_CLOEXEC, NSPROTO_SPX)) == INVALID_SOCKET) + SOCK_STREAM | SOCK_CLOEXEC, NSPROTO_SPX)) == OFInvalidSocketHandle) @throw [OFBindFailedException exceptionWithPort: port - packetType: SPX_PACKET_TYPE + packetType: SPXPacketType socket: self - errNo: of_socket_errno()]; + 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, &address.sockaddr.sockaddr, address.length) != 0) { - int errNo = of_socket_errno(); + int errNo = OFSocketErrNo(); closesocket(_socket); - _socket = INVALID_SOCKET; + _socket = OFInvalidSocketHandle; @throw [OFBindFailedException exceptionWithPort: port - packetType: SPX_PACKET_TYPE + packetType: SPXPacketType socket: self errNo: errNo]; } memset(&address, 0, sizeof(address)); - address.family = OF_SOCKET_ADDRESS_FAMILY_IPX; + address.family = OFSocketAddressFamilyIPX; address.length = (socklen_t)sizeof(address.sockaddr); - if (of_getsockname(_socket, &address.sockaddr.sockaddr, + if (OFGetSockName(_socket, &address.sockaddr.sockaddr, &address.length) != 0) { - int errNo = of_socket_errno(); + int errNo = OFSocketErrNo(); closesocket(_socket); - _socket = INVALID_SOCKET; + _socket = OFInvalidSocketHandle; @throw [OFBindFailedException exceptionWithPort: port - packetType: SPX_PACKET_TYPE + packetType: SPXPacketType socket: self errNo: errNo]; } if (address.sockaddr.sockaddr.sa_family != AF_IPX) { closesocket(_socket); - _socket = INVALID_SOCKET; + _socket = OFInvalidSocketHandle; @throw [OFBindFailedException exceptionWithPort: port - packetType: SPX_PACKET_TYPE + packetType: SPXPacketType socket: self errNo: EAFNOSUPPORT]; } return address; } @end Index: src/OFSandbox.h ================================================================== --- src/OFSandbox.h +++ src/OFSandbox.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -17,27 +15,16 @@ #import "OFObject.h" OF_ASSUME_NONNULL_BEGIN -/** @file */ - @class OFArray OF_GENERIC(ObjectType); @class OFMutableArray OF_GENERIC(ObjectType); @class OFPair OF_GENERIC(FirstType, SecondType); -/** - * @brief An @ref OFPair for a path to unveil, with the first string being the - * path and the second the permissions. - */ -typedef OFPair OF_GENERIC(OFString *, OFString *) *of_sandbox_unveil_path_t; - -/** - * @class OFSandbox OFSandbox.h ObjFW/OFSandbox.h - * - * @brief A class which describes a sandbox for the application. - */ +typedef OFPair OF_GENERIC(OFString *, OFString *) *OFSandboxUnveilPath; + @interface OFSandbox: OFObject { unsigned int _allowsStdIO: 1; unsigned int _allowsReadingFiles: 1; unsigned int _allowsWritingFiles: 1; @@ -66,204 +53,52 @@ unsigned int _allowsPF: 1; unsigned int _allowsAudio: 1; unsigned int _allowsBPF: 1; unsigned int _allowsUnveil: 1; unsigned int _returnsErrors: 1; - OFMutableArray OF_GENERIC(of_sandbox_unveil_path_t) *_unveiledPaths; + OFMutableArray OF_GENERIC(OFSandboxUnveilPath) *_unveiledPaths; @public size_t _unveiledPathsIndex; OF_RESERVE_IVARS(OFSandbox, 4) } -/** - * @brief Allows IO operations on previously allocated file descriptors. - */ @property (nonatomic) bool allowsStdIO; - -/** - * @brief Allows read access to the file system. - */ @property (nonatomic) bool allowsReadingFiles; - -/** - * @brief Allows write access to the file system. - */ @property (nonatomic) bool allowsWritingFiles; - -/** - * @brief Allows creating files in the file system. - */ @property (nonatomic) bool allowsCreatingFiles; - -/** - * @brief Allows creating special files in the file system. - */ @property (nonatomic) bool allowsCreatingSpecialFiles; - -/** - * @brief Allows creating, reading and writing temporary files in `/tmp`. - */ @property (nonatomic) bool allowsTemporaryFiles; - -/** - * @brief Allows using IP sockets. - */ @property (nonatomic) bool allowsIPSockets; - -/** - * @brief Allows multicast sockets. - */ @property (nonatomic) bool allowsMulticastSockets; - -/** - * @brief Allows explicit changes to file attributes. - */ @property (nonatomic) bool allowsChangingFileAttributes; - -/** - * @brief Allows changing ownership of files. - */ @property (nonatomic) bool allowsFileOwnerChanges; - -/** - * @brief Allows file locks. - */ @property (nonatomic) bool allowsFileLocks; - -/** - * @brief Allows UNIX sockets. - */ @property (nonatomic) bool allowsUNIXSockets; - -/** - * @brief Allows syscalls necessary for DNS lookups. - */ @property (nonatomic) bool allowsDNS; - -/** - * @brief Allows to look up users and groups. - */ @property (nonatomic) bool allowsUserDatabaseReading; - -/** - * @brief Allows sending file descriptors via sendmsg(). - */ @property (nonatomic) bool allowsFileDescriptorSending; - -/** - * @brief Allows receiving file descriptors via recvmsg(). - */ @property (nonatomic) bool allowsFileDescriptorReceiving; - -/** - * @brief Allows MTIOCGET and MTIOCTOP operations on tape devices. - */ @property (nonatomic) bool allowsTape; - -/** - * @brief Allows read-write operations and ioctls on the TTY. - */ @property (nonatomic) bool allowsTTY; - -/** - * @brief Allows various process relationshop operations. - */ @property (nonatomic) bool allowsProcessOperations; - -/** - * @brief Allows execve(). - */ @property (nonatomic) bool allowsExec; - -/** - * @brief Allows PROT_EXEC for `mmap()` and `mprotect()`. - */ @property (nonatomic) bool allowsProtExec; - -/** - * @brief Allows `settime()`. - */ @property (nonatomic) bool allowsSetTime; - -/** - * @brief Allows introspection of processes on the system. - */ @property (nonatomic) bool allowsPS; - -/** - * @brief Allows introspection of the system's virtual memory. - */ @property (nonatomic) bool allowsVMInfo; - -/** - * @brief Allows changing the rights of process, for example the UID. - */ @property (nonatomic) bool allowsChangingProcessRights; - -/** - * @brief Allows certain ioctls on the PF device. - */ @property (nonatomic) bool allowsPF; - -/** - * @brief Allows certain ioctls on audio devices. - */ @property (nonatomic) bool allowsAudio; - -/** - * @brief Allows BIOCGSTATS to collect statistics from a BPF device. - */ @property (nonatomic) bool allowsBPF; - -/** - * @brief Allows unveiling more paths. - */ @property (nonatomic) bool allowsUnveil; - -/** - * @brief Returns errors instead of killing the process. - */ @property (nonatomic) bool returnsErrors; - #ifdef OF_HAVE_PLEDGE -/** - * The string for OpenBSD's pledge() call. - * - * @warning Only available on systems with the pledge() call! - */ @property (readonly, nonatomic) OFString *pledgeString; #endif - -/** - * @brief A list of unveiled paths. - */ @property (readonly, nonatomic) - OFArray OF_GENERIC(of_sandbox_unveil_path_t) *unveiledPaths; + OFArray OF_GENERIC(OFSandboxUnveilPath) *unveiledPaths; -/** - * @brief Create a new, autorelease OFSandbox. - */ + (instancetype)sandbox; - -/** - * @brief "Unveils" the specified path, meaning that it becomes visible from - * the sandbox with the specified permissions. - * - * @param path The path to unveil - * @param permissions The permissions for the path. The following permissions - * can be combined: - * Permission | Description - * -----------|-------------------- - * r | Make the path available for reading, like - * | @ref allowsReadingFiles - * w | Make the path available for writing, like - * | @ref allowsWritingFiles - * x | Make the path available for executing, like - * | @ref allowsExec - * c | Make the path available for creation and - * | deletion, like @ref allowsCreatingFiles - */ -- (void)unveilPath: (OFString *)path - permissions: (OFString *)permissions; +- (void)unveilPath: (OFString *)path permissions: (OFString *)permissions; @end OF_ASSUME_NONNULL_END Index: src/OFSandbox.m ================================================================== --- src/OFSandbox.m +++ src/OFSandbox.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -469,46 +467,46 @@ return true; } - (unsigned long)hash { - uint32_t hash; - - OF_HASH_INIT(hash); - - OF_HASH_ADD(hash, _allowsStdIO); - OF_HASH_ADD(hash, _allowsReadingFiles); - OF_HASH_ADD(hash, _allowsWritingFiles); - OF_HASH_ADD(hash, _allowsCreatingFiles); - OF_HASH_ADD(hash, _allowsCreatingSpecialFiles); - OF_HASH_ADD(hash, _allowsTemporaryFiles); - OF_HASH_ADD(hash, _allowsIPSockets); - OF_HASH_ADD(hash, _allowsMulticastSockets); - OF_HASH_ADD(hash, _allowsChangingFileAttributes); - OF_HASH_ADD(hash, _allowsFileOwnerChanges); - OF_HASH_ADD(hash, _allowsFileLocks); - OF_HASH_ADD(hash, _allowsUNIXSockets); - OF_HASH_ADD(hash, _allowsDNS); - OF_HASH_ADD(hash, _allowsUserDatabaseReading); - OF_HASH_ADD(hash, _allowsFileDescriptorSending); - OF_HASH_ADD(hash, _allowsFileDescriptorReceiving); - OF_HASH_ADD(hash, _allowsTape); - OF_HASH_ADD(hash, _allowsTTY); - OF_HASH_ADD(hash, _allowsProcessOperations); - OF_HASH_ADD(hash, _allowsExec); - OF_HASH_ADD(hash, _allowsProtExec); - OF_HASH_ADD(hash, _allowsSetTime); - OF_HASH_ADD(hash, _allowsPS); - OF_HASH_ADD(hash, _allowsVMInfo); - OF_HASH_ADD(hash, _allowsChangingProcessRights); - OF_HASH_ADD(hash, _allowsPF); - OF_HASH_ADD(hash, _allowsAudio); - OF_HASH_ADD(hash, _allowsBPF); - OF_HASH_ADD(hash, _allowsUnveil); - OF_HASH_ADD(hash, _returnsErrors); - - OF_HASH_FINALIZE(hash); + unsigned long hash; + + OFHashInit(&hash); + + OFHashAdd(&hash, _allowsStdIO); + OFHashAdd(&hash, _allowsReadingFiles); + OFHashAdd(&hash, _allowsWritingFiles); + OFHashAdd(&hash, _allowsCreatingFiles); + OFHashAdd(&hash, _allowsCreatingSpecialFiles); + OFHashAdd(&hash, _allowsTemporaryFiles); + OFHashAdd(&hash, _allowsIPSockets); + OFHashAdd(&hash, _allowsMulticastSockets); + OFHashAdd(&hash, _allowsChangingFileAttributes); + OFHashAdd(&hash, _allowsFileOwnerChanges); + OFHashAdd(&hash, _allowsFileLocks); + OFHashAdd(&hash, _allowsUNIXSockets); + OFHashAdd(&hash, _allowsDNS); + OFHashAdd(&hash, _allowsUserDatabaseReading); + OFHashAdd(&hash, _allowsFileDescriptorSending); + OFHashAdd(&hash, _allowsFileDescriptorReceiving); + OFHashAdd(&hash, _allowsTape); + OFHashAdd(&hash, _allowsTTY); + OFHashAdd(&hash, _allowsProcessOperations); + OFHashAdd(&hash, _allowsExec); + OFHashAdd(&hash, _allowsProtExec); + OFHashAdd(&hash, _allowsSetTime); + OFHashAdd(&hash, _allowsPS); + OFHashAdd(&hash, _allowsVMInfo); + OFHashAdd(&hash, _allowsChangingProcessRights); + OFHashAdd(&hash, _allowsPF); + OFHashAdd(&hash, _allowsAudio); + OFHashAdd(&hash, _allowsBPF); + OFHashAdd(&hash, _allowsUnveil); + OFHashAdd(&hash, _returnsErrors); + + OFHashFinalize(&hash); return hash; } #ifdef OF_HAVE_PLEDGE @@ -587,21 +585,20 @@ return [ret autorelease]; } #endif -- (void)unveilPath: (OFString *)path - permissions: (OFString *)permissions +- (void)unveilPath: (OFString *)path permissions: (OFString *)permissions { void *pool = objc_autoreleasePoolPush(); [_unveiledPaths addObject: [OFPair pairWithFirstObject: path secondObject: permissions]]; objc_autoreleasePoolPop(pool); } -- (OFArray OF_GENERIC(of_sandbox_unveil_path_t) *)unveiledPaths +- (OFArray OF_GENERIC(OFSandboxUnveilPath) *)unveiledPaths { return [[_unveiledPaths copy] autorelease]; } @end ADDED src/OFScrypt.h Index: src/OFScrypt.h ================================================================== --- /dev/null +++ src/OFScrypt.h @@ -0,0 +1,80 @@ +/* + * 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. + */ + +#ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS +#endif +#ifndef __STDC_CONSTANT_MACROS +# define __STDC_CONSTANT_MACROS +#endif + +#import "macros.h" + +OF_ASSUME_NONNULL_BEGIN + +/** @file */ + +@class OFHMAC; + +/** + * @brief The parameters for @ref OFScrypt. + */ +typedef struct { + /** @brief The block size to use. */ + size_t blockSize; + /** @brief The CPU/memory cost factor to use. */ + size_t costFactor; + /** @brief The parallelization to use. */ + size_t parallelization; + /** @brief The salt to derive a key with. */ + const unsigned char *salt; + /** @brief The length of the salt. */ + size_t saltLength; + /** @brief The password to derive a key from. */ + const char *password; + /** @brief The length of the password. */ + size_t passwordLength; + /** @brief The buffer to write the key to. */ + unsigned char *key; + /** + * @brief The desired length for the derived key. + * + * @ref key needs to have enough storage. + */ + size_t keyLength; + /** @brief Whether data may be stored in swappable memory. */ + bool allowsSwappableMemory; +} OFScryptParameters; + +#ifdef __cplusplus +extern "C" { +#endif +extern void OFSalsa20_8Core(uint32_t buffer[_Nonnull 16]); +extern void OFScryptBlockMix(uint32_t *output, const uint32_t *input, + size_t blockSize); +extern void OFScryptROMix(uint32_t *buffer, size_t blockSize, + size_t costFactor, uint32_t *tmp); + +/** + * @brief Derives a key from a password and a salt using scrypt. + * + * @param param The parameters to use + */ +extern void OFScrypt(OFScryptParameters param); +#ifdef __cplusplus +} +#endif + +OF_ASSUME_NONNULL_END ADDED src/OFScrypt.m Index: src/OFScrypt.m ================================================================== --- /dev/null +++ src/OFScrypt.m @@ -0,0 +1,219 @@ +/* + * 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 "OFHMAC.h" +#import "OFSHA256Hash.h" +#import "OFSecureData.h" + +#import "OFInvalidArgumentException.h" +#import "OFOutOfMemoryException.h" +#import "OFOutOfRangeException.h" + +#import "OFScrypt.h" +#import "OFPBKDF2.h" + +void +OFSalsa20_8Core(uint32_t buffer[16]) +{ + uint32_t tmp[16]; + + for (uint_fast8_t i = 0; i < 16; i++) + tmp[i] = OFToLittleEndian32(buffer[i]); + + for (uint_fast8_t i = 0; i < 8; i += 2) { + tmp[ 4] ^= OFRotateLeft(tmp[ 0] + tmp[12], 7); + tmp[ 8] ^= OFRotateLeft(tmp[ 4] + tmp[ 0], 9); + tmp[12] ^= OFRotateLeft(tmp[ 8] + tmp[ 4], 13); + tmp[ 0] ^= OFRotateLeft(tmp[12] + tmp[ 8], 18); + tmp[ 9] ^= OFRotateLeft(tmp[ 5] + tmp[ 1], 7); + tmp[13] ^= OFRotateLeft(tmp[ 9] + tmp[ 5], 9); + tmp[ 1] ^= OFRotateLeft(tmp[13] + tmp[ 9], 13); + tmp[ 5] ^= OFRotateLeft(tmp[ 1] + tmp[13], 18); + tmp[14] ^= OFRotateLeft(tmp[10] + tmp[ 6], 7); + tmp[ 2] ^= OFRotateLeft(tmp[14] + tmp[10], 9); + tmp[ 6] ^= OFRotateLeft(tmp[ 2] + tmp[14], 13); + tmp[10] ^= OFRotateLeft(tmp[ 6] + tmp[ 2], 18); + tmp[ 3] ^= OFRotateLeft(tmp[15] + tmp[11], 7); + tmp[ 7] ^= OFRotateLeft(tmp[ 3] + tmp[15], 9); + tmp[11] ^= OFRotateLeft(tmp[ 7] + tmp[ 3], 13); + tmp[15] ^= OFRotateLeft(tmp[11] + tmp[ 7], 18); + tmp[ 1] ^= OFRotateLeft(tmp[ 0] + tmp[ 3], 7); + tmp[ 2] ^= OFRotateLeft(tmp[ 1] + tmp[ 0], 9); + tmp[ 3] ^= OFRotateLeft(tmp[ 2] + tmp[ 1], 13); + tmp[ 0] ^= OFRotateLeft(tmp[ 3] + tmp[ 2], 18); + tmp[ 6] ^= OFRotateLeft(tmp[ 5] + tmp[ 4], 7); + tmp[ 7] ^= OFRotateLeft(tmp[ 6] + tmp[ 5], 9); + tmp[ 4] ^= OFRotateLeft(tmp[ 7] + tmp[ 6], 13); + tmp[ 5] ^= OFRotateLeft(tmp[ 4] + tmp[ 7], 18); + tmp[11] ^= OFRotateLeft(tmp[10] + tmp[ 9], 7); + tmp[ 8] ^= OFRotateLeft(tmp[11] + tmp[10], 9); + tmp[ 9] ^= OFRotateLeft(tmp[ 8] + tmp[11], 13); + tmp[10] ^= OFRotateLeft(tmp[ 9] + tmp[ 8], 18); + tmp[12] ^= OFRotateLeft(tmp[15] + tmp[14], 7); + tmp[13] ^= OFRotateLeft(tmp[12] + tmp[15], 9); + tmp[14] ^= OFRotateLeft(tmp[13] + tmp[12], 13); + tmp[15] ^= OFRotateLeft(tmp[14] + tmp[13], 18); + } + + for (uint_fast8_t i = 0; i < 16; i++) + buffer[i] = OFToLittleEndian32(OFFromLittleEndian32(buffer[i]) + + tmp[i]); + + OFZeroMemory(tmp, sizeof(tmp)); +} + +void +OFScryptBlockMix(uint32_t *output, const uint32_t *input, size_t blockSize) +{ + uint32_t tmp[16]; + + /* Check defined here and executed in OFScrypt() */ +#define OVERFLOW_CHECK_1 \ + if (param.blockSize > SIZE_MAX / 2 || \ + 2 * param.blockSize - 1 > SIZE_MAX / 16) \ + @throw [OFOutOfRangeException exception]; + + memcpy(tmp, input + (2 * blockSize - 1) * 16, 64); + + for (size_t i = 0; i < 2 * blockSize; i++) { + for (size_t j = 0; j < 16; j++) + tmp[j] ^= input[i * 16 + j]; + + OFSalsa20_8Core(tmp); + + /* + * Even indices are stored in the first half and odd ones in + * the second. + */ + memcpy(output + ((i / 2) + (i & 1) * blockSize) * 16, tmp, 64); + } + + OFZeroMemory(tmp, sizeof(tmp)); +} + +void +OFScryptROMix(uint32_t *buffer, size_t blockSize, size_t costFactor, + uint32_t *tmp) +{ + /* Check defined here and executed in OFScrypt() */ +#define OVERFLOW_CHECK_2 \ + if (param.blockSize > SIZE_MAX / 128 / param.costFactor) \ + @throw [OFOutOfRangeException exception]; + + uint32_t *tmp2 = tmp + 32 * blockSize; + + memcpy(tmp, buffer, 128 * blockSize); + + for (size_t i = 0; i < costFactor; i++) { + memcpy(tmp2 + i * 32 * blockSize, tmp, 128 * blockSize); + OFScryptBlockMix(tmp, tmp2 + i * 32 * blockSize, blockSize); + } + + for (size_t i = 0; i < costFactor; i++) { + uint32_t j = OFFromLittleEndian32( + tmp[(2 * blockSize - 1) * 16]) & (costFactor - 1); + + for (size_t k = 0; k < 32 * blockSize; k++) + tmp[k] ^= tmp2[j * 32 * blockSize + k]; + + OFScryptBlockMix(buffer, tmp, blockSize); + + if (i < costFactor - 1) + memcpy(tmp, buffer, 128 * blockSize); + } +} + +void +OFScrypt(OFScryptParameters param) +{ + OFSecureData *tmp = nil, *buffer = nil; + OFHMAC *HMAC = nil; + + if (param.blockSize == 0 || param.costFactor <= 1 || + (param.costFactor & (param.costFactor - 1)) != 0 || + param.parallelization == 0) + @throw [OFInvalidArgumentException exception]; + + /* + * These are defined by the functions above. They are defined there so + * that the check is next to the code and easy to verify, but actually + * checked here for performance. + */ + OVERFLOW_CHECK_1 + OVERFLOW_CHECK_2 + + @try { + uint32_t *tmpItems, *bufferItems; + + if (param.costFactor > SIZE_MAX - 1 || + (param.costFactor + 1) > SIZE_MAX / 128) + @throw [OFOutOfRangeException exception]; + + tmp = [[OFSecureData alloc] + initWithCount: (param.costFactor + 1) * 128 + itemSize: param.blockSize + allowsSwappableMemory: param.allowsSwappableMemory]; + tmpItems = tmp.mutableItems; + + if (param.parallelization > SIZE_MAX / 128) + @throw [OFOutOfRangeException exception]; + + buffer = [[OFSecureData alloc] + initWithCount: param.parallelization * 128 + itemSize: param.blockSize + allowsSwappableMemory: param.allowsSwappableMemory]; + bufferItems = buffer.mutableItems; + + HMAC = [[OFHMAC alloc] + initWithHashClass: [OFSHA256Hash class] + allowsSwappableMemory: param.allowsSwappableMemory]; + + OFPBKDF2((OFPBKDF2Parameters){ + .HMAC = HMAC, + .iterations = 1, + .salt = param.salt, + .saltLength = param.saltLength, + .password = param.password, + .passwordLength = param.passwordLength, + .key = (unsigned char *)bufferItems, + .keyLength = param.parallelization * 128 * + param.blockSize, + .allowsSwappableMemory = param.allowsSwappableMemory + }); + + for (size_t i = 0; i < param.parallelization; i++) + OFScryptROMix(bufferItems + i * 32 * param.blockSize, + param.blockSize, param.costFactor, tmpItems); + + OFPBKDF2((OFPBKDF2Parameters){ + .HMAC = HMAC, + .iterations = 1, + .salt = (unsigned char *)bufferItems, + .saltLength = param.parallelization * 128 * + param.blockSize, + .password = param.password, + .passwordLength = param.passwordLength, + .key = param.key, + .keyLength = param.keyLength, + .allowsSwappableMemory = param.allowsSwappableMemory + }); + } @finally { + [tmp release]; + [buffer release]; + [HMAC release]; + } +} Index: src/OFSecureData.h ================================================================== --- src/OFSecureData.h +++ src/OFSecureData.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -32,11 +30,11 @@ * memory. */ OF_SUBCLASSING_RESTRICTED @interface OFSecureData: OFData { - struct page *_page; + void *_page; bool _allowsSwappableMemory; } /** * @brief Whether the data may be stored in swappable memory. @@ -79,31 +77,31 @@ /** * @brief Creates a new, autoreleased OFSecureData with count items of the * specified item size, all set to zero. * - * @param itemSize The size of a single item in the OFSecureData in bytes * @param count The number of zero items the OFSecureData should contain + * @param itemSize The size of a single item in the OFSecureData in bytes * @param allowsSwappableMemory Whether the data may be stored in swappable * memory * @return A new, autoreleased OFSecureData */ -+ (instancetype)dataWithItemSize: (size_t)itemSize - count: (size_t)count - allowsSwappableMemory: (bool)allowsSwappableMemory; ++ (instancetype)dataWithCount: (size_t)count + itemSize: (size_t)itemSize + allowsSwappableMemory: (bool)allowsSwappableMemory; + (instancetype)dataWithItems: (const void *)items count: (size_t)count OF_UNAVAILABLE; + (instancetype)dataWithItems: (const void *)items - itemSize: (size_t)itemSize - count: (size_t)count OF_UNAVAILABLE; + count: (size_t)count + itemSize: (size_t)itemSize OF_UNAVAILABLE; + (instancetype)dataWithItemsNoCopy: (void *)items count: (size_t)count freeWhenDone: (bool)freeWhenDone OF_UNAVAILABLE; + (instancetype)dataWithItemsNoCopy: (void *)items - itemSize: (size_t)itemSize count: (size_t)count + itemSize: (size_t)itemSize freeWhenDone: (bool)freeWhenDone OF_UNAVAILABLE; #ifdef OF_HAVE_FILES + (instancetype)dataWithContentsOfFile: (OFString *)path OF_UNAVAILABLE; #endif + (instancetype)dataWithContentsOfURL: (OFURL *)URL OF_UNAVAILABLE; @@ -130,26 +128,26 @@ * @param count The number of zero items the OFSecureData should contain * @param allowsSwappableMemory Whether the data may be stored in swappable * memory * @return An initialized OFSecureData */ -- (instancetype)initWithItemSize: (size_t)itemSize - count: (size_t)count - allowsSwappableMemory: (bool)allowsSwappableMemory +- (instancetype)initWithCount: (size_t)count + itemSize: (size_t)itemSize + allowsSwappableMemory: (bool)allowsSwappableMemory OF_DESIGNATED_INITIALIZER; - (instancetype)initWithItems: (const void *)items count: (size_t)count OF_UNAVAILABLE; - (instancetype)initWithItems: (const void *)items - itemSize: (size_t)itemSize - count: (size_t)count OF_UNAVAILABLE; + count: (size_t)count + itemSize: (size_t)itemSize OF_UNAVAILABLE; - (instancetype)initWithItemsNoCopy: (void *)items count: (size_t)count freeWhenDone: (bool)freeWhenDone OF_UNAVAILABLE; - (instancetype)initWithItemsNoCopy: (void *)items - itemSize: (size_t)itemSize count: (size_t)count + itemSize: (size_t)itemSize freeWhenDone: (bool)freeWhenDone OF_UNAVAILABLE; #ifdef OF_HAVE_FILES - (instancetype)initWithContentsOfFile: (OFString *)path OF_UNAVAILABLE; #endif - (instancetype)initWithContentsOfURL: (OFURL *)URL OF_UNAVAILABLE; Index: src/OFSecureData.m ================================================================== --- src/OFSecureData.m +++ src/OFSecureData.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -25,42 +23,41 @@ #endif #import "OFSecureData.h" #import "OFString.h" #import "OFSystemInfo.h" +#ifdef OF_HAVE_THREADS +# import "OFTLSKey.h" +#endif #import "OFInitializationFailedException.h" #import "OFInvalidArgumentException.h" #import "OFNotImplementedException.h" #import "OFOutOfMemoryException.h" #import "OFOutOfRangeException.h" -#ifdef OF_HAVE_THREADS -# import "tlskey.h" -#endif - -#define CHUNK_SIZE 16 - #if defined(HAVE_MMAP) && defined(HAVE_MLOCK) && defined(MAP_ANON) -struct page { - struct page *next, *previous; +static const size_t chunkSize = 16; + +struct Page { + struct Page *next, *previous; void *map; unsigned char *page; }; # if defined(OF_HAVE_COMPILER_TLS) -static thread_local struct page *firstPage = NULL; -static thread_local struct page *lastPage = NULL; -static thread_local struct page **preallocatedPages = NULL; +static thread_local struct Page *firstPage = NULL; +static thread_local struct Page *lastPage = NULL; +static thread_local struct Page **preallocatedPages = NULL; static thread_local size_t numPreallocatedPages = 0; # elif defined(OF_HAVE_THREADS) -static of_tlskey_t firstPageKey, lastPageKey; -static of_tlskey_t preallocatedPagesKey, numPreallocatedPagesKey; +static OFTLSKey firstPageKey, lastPageKey; +static OFTLSKey preallocatedPagesKey, numPreallocatedPagesKey; # else -static struct page *firstPage = NULL; -static struct page *lastPage = NULL; -static struct page **preallocatedPages = NULL; +static struct Page *firstPage = NULL; +static struct Page *lastPage = NULL; +static struct Page **preallocatedPages = NULL; static size_t numPreallocatedPages = 0; # endif static void * mapPages(size_t numPages) @@ -95,71 +92,72 @@ munlock(pointer, numPages * pageSize); munmap(pointer, numPages * pageSize); } -static struct page * +static struct Page * addPage(bool allowPreallocated) { size_t pageSize = [OFSystemInfo pageSize]; - size_t mapSize = OF_ROUND_UP_POW2(8, pageSize / CHUNK_SIZE) / 8; - struct page *page; + size_t mapSize = OFRoundUpToPowerOf2(CHAR_BIT, pageSize / chunkSize) / + CHAR_BIT; + struct Page *page; # if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) - struct page *lastPage; + struct Page *lastPage; # endif if (allowPreallocated) { # if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) uintptr_t numPreallocatedPages = - (uintptr_t)of_tlskey_get(numPreallocatedPagesKey); + (uintptr_t)OFTLSKeyGet(numPreallocatedPagesKey); # endif if (numPreallocatedPages > 0) { # if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) - struct page **preallocatedPages = - of_tlskey_get(preallocatedPagesKey); + struct Page **preallocatedPages = + OFTLSKeyGet(preallocatedPagesKey); # endif numPreallocatedPages--; # if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) - OF_ENSURE(of_tlskey_set(numPreallocatedPagesKey, - (void *)numPreallocatedPages)); + OFEnsure(OFTLSKeySet(numPreallocatedPagesKey, + (void *)numPreallocatedPages) == 0); # endif page = preallocatedPages[numPreallocatedPages]; if (numPreallocatedPages == 0) { - of_free(preallocatedPages); + OFFreeMemory(preallocatedPages); preallocatedPages = NULL; # if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) - OF_ENSURE(of_tlskey_set(preallocatedPagesKey, - preallocatedPages)); + OFEnsure(OFTLSKeySet(preallocatedPagesKey, + preallocatedPages) == 0); # endif } return page; } } - page = of_malloc(1, sizeof(*page)); + page = OFAllocMemory(1, sizeof(*page)); @try { - page->map = of_calloc(1, mapSize); + page->map = OFAllocZeroedMemory(1, mapSize); } @catch (id e) { - of_free(page); + OFFreeMemory(page); @throw e; } @try { page->page = mapPages(1); } @catch (id e) { - of_free(page->map); - of_free(page); + OFFreeMemory(page->map); + OFFreeMemory(page); @throw e; } - of_explicit_memset(page->page, 0, pageSize); + OFZeroMemory(page->page, pageSize); # if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) - lastPage = of_tlskey_get(lastPageKey); + lastPage = OFTLSKeyGet(lastPageKey); # endif page->previous = lastPage; page->next = NULL; @@ -170,32 +168,33 @@ lastPage = page; if (firstPage == NULL) firstPage = page; # else - OF_ENSURE(of_tlskey_set(lastPageKey, page)); + OFEnsure(OFTLSKeySet(lastPageKey, page) == 0); - if (of_tlskey_get(firstPageKey) == NULL) - OF_ENSURE(of_tlskey_set(firstPageKey, page)); + if (OFTLSKeyGet(firstPageKey) == NULL) + OFEnsure(OFTLSKeySet(firstPageKey, page) == 0); # endif return page; } static void -removePageIfEmpty(struct page *page) +removePageIfEmpty(struct Page *page) { unsigned char *map = page->map; size_t pageSize = [OFSystemInfo pageSize]; - size_t mapSize = OF_ROUND_UP_POW2(8, pageSize / CHUNK_SIZE) / 8; + size_t mapSize = OFRoundUpToPowerOf2(CHAR_BIT, pageSize / chunkSize) / + CHAR_BIT; for (size_t i = 0; i < mapSize; i++) if (map[i] != 0) return; unmapPages(page->page, 1); - of_free(page->map); + OFFreeMemory(page->map); if (page->previous != NULL) page->previous->next = page->next; if (page->next != NULL) page->next->previous = page->previous; @@ -204,31 +203,31 @@ if (firstPage == page) firstPage = page->next; if (lastPage == page) lastPage = page->previous; # else - if (of_tlskey_get(firstPageKey) == page) - OF_ENSURE(of_tlskey_set(firstPageKey, page->next)); - if (of_tlskey_get(lastPageKey) == page) - OF_ENSURE(of_tlskey_set(lastPageKey, page->previous)); + if (OFTLSKeyGet(firstPageKey) == page) + OFEnsure(OFTLSKeySet(firstPageKey, page->next) == 0); + if (OFTLSKeyGet(lastPageKey) == page) + OFEnsure(OFTLSKeySet(lastPageKey, page->previous) == 0); # endif - of_free(page); + OFFreeMemory(page); } static void * -allocateMemory(struct page *page, size_t bytes) +allocateMemory(struct Page *page, size_t bytes) { size_t chunks, chunksLeft, pageSize, i, firstChunk; - bytes = OF_ROUND_UP_POW2(CHUNK_SIZE, bytes); - chunks = chunksLeft = bytes / CHUNK_SIZE; + bytes = OFRoundUpToPowerOf2(chunkSize, bytes); + chunks = chunksLeft = bytes / chunkSize; firstChunk = 0; pageSize = [OFSystemInfo pageSize]; - for (i = 0; i < pageSize / CHUNK_SIZE; i++) { - if (of_bitset_isset(page->map, i)) { + for (i = 0; i < pageSize / chunkSize; i++) { + if (OFBitsetIsSet(page->map, i)) { chunksLeft = chunks; firstChunk = i + 1; continue; } @@ -236,31 +235,31 @@ break; } if (chunksLeft == 0) { for (size_t j = firstChunk; j < firstChunk + chunks; j++) - of_bitset_set(page->map, j); + OFBitsetSet(page->map, j); - return page->page + (CHUNK_SIZE * firstChunk); + return page->page + (chunkSize * firstChunk); } return NULL; } static void -freeMemory(struct page *page, void *pointer, size_t bytes) +freeMemory(struct Page *page, void *pointer, size_t bytes) { size_t chunks, chunkIndex; - bytes = OF_ROUND_UP_POW2(CHUNK_SIZE, bytes); - chunks = bytes / CHUNK_SIZE; - chunkIndex = ((uintptr_t)pointer - (uintptr_t)page->page) / CHUNK_SIZE; + bytes = OFRoundUpToPowerOf2(chunkSize, bytes); + chunks = bytes / chunkSize; + chunkIndex = ((uintptr_t)pointer - (uintptr_t)page->page) / chunkSize; - of_explicit_memset(pointer, 0, bytes); + OFZeroMemory(pointer, bytes); for (size_t i = 0; i < chunks; i++) - of_bitset_clear(page->map, chunkIndex + i); + OFBitsetClear(page->map, chunkIndex + i); } #endif @implementation OFSecureData @synthesize allowsSwappableMemory = _allowsSwappableMemory; @@ -270,54 +269,54 @@ + (void)initialize { if (self != [OFSecureData class]) return; - if (!of_tlskey_new(&firstPageKey) || !of_tlskey_new(&lastPageKey) || - !of_tlskey_new(&preallocatedPagesKey) || - !of_tlskey_new(&numPreallocatedPagesKey)) + if (OFTLSKeyNew(&firstPageKey) != 0 || OFTLSKeyNew(&lastPageKey) != 0 || + OFTLSKeyNew(&preallocatedPagesKey) != 0 || + OFTLSKeyNew(&numPreallocatedPagesKey) != 0) @throw [OFInitializationFailedException exceptionWithClass: self]; } #endif + (void)preallocateUnswappableMemoryWithSize: (size_t)size { #if defined(HAVE_MMAP) && defined(HAVE_MLOCK) && defined(MAP_ANON) size_t pageSize = [OFSystemInfo pageSize]; - size_t numPages = OF_ROUND_UP_POW2(pageSize, size) / pageSize; + size_t numPages = OFRoundUpToPowerOf2(pageSize, size) / pageSize; # if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) - struct page **preallocatedPages = of_tlskey_get(preallocatedPagesKey); + struct Page **preallocatedPages = OFTLSKeyGet(preallocatedPagesKey); size_t numPreallocatedPages; # endif size_t i; if (preallocatedPages != NULL) @throw [OFInvalidArgumentException exception]; - preallocatedPages = of_calloc(numPages, sizeof(struct page)); + preallocatedPages = OFAllocZeroedMemory(numPages, sizeof(struct Page)); # if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) - of_tlskey_set(preallocatedPagesKey, preallocatedPages); + OFEnsure(OFTLSKeySet(preallocatedPagesKey, preallocatedPages) == 0); # endif @try { for (i = 0; i < numPages; i++) preallocatedPages[i] = addPage(false); } @catch (id e) { for (size_t j = 0; j < i; j++) removePageIfEmpty(preallocatedPages[j]); - of_free(preallocatedPages); + OFFreeMemory(preallocatedPages); preallocatedPages = NULL; @throw e; } numPreallocatedPages = numPages; # if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) - of_tlskey_set(numPreallocatedPagesKey, - (void *)(uintptr_t)numPreallocatedPages); + OFEnsure(OFTLSKeySet(numPreallocatedPagesKey, + (void *)(uintptr_t)numPreallocatedPages) == 0); # endif #else @throw [OFNotImplementedException exceptionWithSelector: _cmd object: self]; #endif @@ -329,17 +328,17 @@ return [[[self alloc] initWithCount: count allowsSwappableMemory: allowsSwappableMemory] autorelease]; } -+ (instancetype)dataWithItemSize: (size_t)itemSize - count: (size_t)count - allowsSwappableMemory: (bool)allowsSwappableMemory ++ (instancetype)dataWithCount: (size_t)count + itemSize: (size_t)itemSize + allowsSwappableMemory: (bool)allowsSwappableMemory { - return [[[self alloc] initWithItemSize: itemSize - count: count - allowsSwappableMemory: allowsSwappableMemory] + return [[[self alloc] initWithCount: count + itemSize: itemSize + allowsSwappableMemory: allowsSwappableMemory] autorelease]; } + (instancetype)dataWithItems: (const void *)items count: (size_t)count @@ -346,12 +345,12 @@ { OF_UNRECOGNIZED_SELECTOR } + (instancetype)dataWithItems: (const void *)items - itemSize: (size_t)itemSize count: (size_t)count + itemSize: (size_t)itemSize { OF_UNRECOGNIZED_SELECTOR } + (instancetype)dataWithItemsNoCopy: (void *)items @@ -360,12 +359,12 @@ { OF_UNRECOGNIZED_SELECTOR } + (instancetype)dataWithItemsNoCopy: (void *)items - itemSize: (size_t)itemSize count: (size_t)count + itemSize: (size_t)itemSize freeWhenDone: (bool)freeWhenDone { OF_UNRECOGNIZED_SELECTOR } @@ -393,18 +392,18 @@ - (instancetype)initWithCount: (size_t)count allowsSwappableMemory: (bool)allowsSwappableMemory { - return [self initWithItemSize: 1 - count: count - allowsSwappableMemory: allowsSwappableMemory]; + return [self initWithCount: count + itemSize: 1 + allowsSwappableMemory: allowsSwappableMemory]; } -- (instancetype)initWithItemSize: (size_t)itemSize - count: (size_t)count - allowsSwappableMemory: (bool)allowsSwappableMemory +- (instancetype)initWithCount: (size_t)count + itemSize: (size_t)itemSize + allowsSwappableMemory: (bool)allowsSwappableMemory { self = [super init]; @try { #if defined(HAVE_MMAP) && defined(HAVE_MLOCK) && defined(MAP_ANON) @@ -413,23 +412,23 @@ if (count > SIZE_MAX / itemSize) @throw [OFOutOfRangeException exception]; if (allowsSwappableMemory) { - _items = [self allocMemoryWithSize: itemSize - count: count]; + _items = OFAllocMemory(count, itemSize); + _freeWhenDone = true; memset(_items, 0, count * itemSize); #if defined(HAVE_MMAP) && defined(HAVE_MLOCK) && defined(MAP_ANON) } else if (count * itemSize >= pageSize) - _items = mapPages(OF_ROUND_UP_POW2(pageSize, + _items = mapPages(OFRoundUpToPowerOf2(pageSize, count * itemSize) / pageSize); else { # if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) - struct page *lastPage = of_tlskey_get(lastPageKey); + struct Page *lastPage = OFTLSKeyGet(lastPageKey); # endif - for (struct page *page = lastPage; page != NULL; + for (struct Page *page = lastPage; page != NULL; page = page->previous) { _items = allocateMemory(page, count * itemSize); if (_items != NULL) { _page = page; @@ -453,30 +452,29 @@ @throw [OFNotImplementedException exceptionWithSelector: _cmd object: nil]; #endif - _itemSize = itemSize; _count = count; + _itemSize = itemSize; _allowsSwappableMemory = allowsSwappableMemory; } @catch (id e) { [self release]; @throw e; } return self; } -- (instancetype)initWithItems: (const void *)items - count: (size_t)count +- (instancetype)initWithItems: (const void *)items count: (size_t)count { OF_INVALID_INIT_METHOD } - (instancetype)initWithItems: (const void *)items - itemSize: (size_t)itemSize count: (size_t)count + itemSize: (size_t)itemSize { OF_INVALID_INIT_METHOD } - (instancetype)initWithItemsNoCopy: (void *)items @@ -485,12 +483,12 @@ { OF_INVALID_INIT_METHOD } - (instancetype)initWithItemsNoCopy: (void *)items - itemSize: (size_t)itemSize count: (size_t)count + itemSize: (size_t)itemSize freeWhenDone: (bool)freeWhenDone { OF_INVALID_INIT_METHOD } @@ -529,11 +527,11 @@ if (!_allowsSwappableMemory) { size_t pageSize = [OFSystemInfo pageSize]; if (_count * _itemSize > pageSize) unmapPages(_items, - OF_ROUND_UP_POW2(pageSize, _count * _itemSize) / + OFRoundUpToPowerOf2(pageSize, _count * _itemSize) / pageSize); else if (_page != NULL) { if (_items != NULL) freeMemory(_page, _items, _count * _itemSize); @@ -558,18 +556,18 @@ return _items + idx * _itemSize; } - (void)zero { - of_explicit_memset(_items, 0, _count * _itemSize); + OFZeroMemory(_items, _count * _itemSize); } - (id)copy { OFSecureData *copy = [[OFSecureData alloc] - initWithItemSize: _itemSize - count: _count + initWithCount: _count + itemSize: _itemSize allowsSwappableMemory: _allowsSwappableMemory]; memcpy(copy.mutableItems, _items, _count * _itemSize); return copy; @@ -576,12 +574,12 @@ } - (id)mutableCopy { OFSecureData *copy = [[OFSecureData alloc] - initWithItemSize: _itemSize - count: _count + initWithCount: _count + itemSize: _itemSize allowsSwappableMemory: _allowsSwappableMemory]; memcpy(copy.mutableItems, _items, _count * _itemSize); return copy; Index: src/OFSeekableStream.h ================================================================== --- src/OFSeekableStream.h +++ src/OFSeekableStream.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -31,19 +29,19 @@ #import "OFStream.h" OF_ASSUME_NONNULL_BEGIN #if defined(OF_WINDOWS) -typedef __int64 of_offset_t; +typedef __int64 OFFileOffset; #elif defined(OF_ANDROID) -typedef long long of_offset_t; +typedef long long OFFileOffset; #elif defined(OF_MORPHOS) -typedef signed long long of_offset_t; +typedef signed long long OFFileOffset; #elif defined(OF_HAVE_OFF64_T) -typedef off64_t of_offset_t; +typedef off64_t OFFileOffset; #else -typedef off_t of_offset_t; +typedef off_t OFFileOffset; #endif /** * @class OFSeekableStream OFSeekableStream.h ObjFW/OFSeekableStream.h * @@ -71,12 +69,11 @@ * `SEEK_SET` | Seek to the specified byte * `SEEK_CUR` | Seek to the current location + offset * `SEEK_END` | Seek to the end of the stream + offset * @return The new offset form the start of the file */ -- (of_offset_t)seekToOffset: (of_offset_t)offset - whence: (int)whence; +- (OFFileOffset)seekToOffset: (OFFileOffset)offset whence: (int)whence; /** * @brief Seek the stream on the lowlevel. * * @warning Do not call this directly! @@ -92,10 +89,9 @@ * `SEEK_SET` | Seek to the specified byte * `SEEK_CUR` | Seek to the current location + offset * `SEEK_END` | Seek to the end of the stream + offset * @return The new offset from the start of the file */ -- (of_offset_t)lowlevelSeekToOffset: (of_offset_t)offset - whence: (int)whence; +- (OFFileOffset)lowlevelSeekToOffset: (OFFileOffset)offset whence: (int)whence; @end OF_ASSUME_NONNULL_END Index: src/OFSeekableStream.m ================================================================== --- src/OFSeekableStream.m +++ src/OFSeekableStream.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -38,27 +36,24 @@ } return [super init]; } -- (of_offset_t)lowlevelSeekToOffset: (of_offset_t)offset - whence: (int)whence +- (OFFileOffset)lowlevelSeekToOffset: (OFFileOffset)offset whence: (int)whence { OF_UNRECOGNIZED_SELECTOR } -- (of_offset_t)seekToOffset: (of_offset_t)offset - whence: (int)whence +- (OFFileOffset)seekToOffset: (OFFileOffset)offset whence: (int)whence { if (whence == SEEK_CUR) offset -= _readBufferLength; - offset = [self lowlevelSeekToOffset: offset - whence: whence]; + offset = [self lowlevelSeekToOffset: offset whence: whence]; - [self freeMemory: _readBufferMemory]; + OFFreeMemory(_readBufferMemory); _readBuffer = _readBufferMemory = NULL; _readBufferLength = 0; return offset; } @end Index: src/OFSelectKernelEventObserver.h ================================================================== --- src/OFSelectKernelEventObserver.h +++ src/OFSelectKernelEventObserver.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFSelectKernelEventObserver.m ================================================================== --- src/OFSelectKernelEventObserver.m +++ src/OFSelectKernelEventObserver.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -13,13 +11,13 @@ * 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. */ -#define __NO_EXT_QNX - #include "config.h" + +#define __NO_EXT_QNX #include "platform.h" #ifdef OF_WINDOWS /* Win32 has a ridiculous default of 64, even though it supports much more. */ @@ -31,38 +29,43 @@ #include #import "OFSelectKernelEventObserver.h" #import "OFArray.h" +#import "OFSocket+Private.h" #import "OFInitializationFailedException.h" #import "OFObserveFailedException.h" #import "OFOutOfRangeException.h" -#import "socket_helpers.h" - #ifdef OF_AMIGAOS # include #endif + +#ifdef OF_HPUX +/* FD_SET causes warnings on HP-UX/IA64. */ +# pragma GCC diagnostic ignored "-Wstrict-aliasing" +#endif @implementation OFSelectKernelEventObserver - (instancetype)init { self = [super init]; @try { + FD_ZERO(&_readFDs); + FD_ZERO(&_writeFDs); + #ifdef OF_AMIGAOS - _maxFD = 0; + _maxFD = -1; #else # ifndef OF_WINDOWS if (_cancelFD[0] >= (int)FD_SETSIZE) @throw [OFInitializationFailedException exceptionWithClass: self.class]; # endif - FD_ZERO(&_readFDs); - FD_ZERO(&_writeFDs); FD_SET(_cancelFD[0], &_readFDs); if (_cancelFD[0] > INT_MAX) @throw [OFOutOfRangeException exception]; @@ -93,11 +96,11 @@ #endif if (fd > _maxFD) _maxFD = fd; - FD_SET((of_socket_t)fd, &_readFDs); + FD_SET((OFSocketHandle)fd, &_readFDs); [super addObjectForReading: object]; } - (void)addObjectForWriting: (id )object @@ -117,11 +120,11 @@ #endif if (fd > _maxFD) _maxFD = fd; - FD_SET((of_socket_t)fd, &_writeFDs); + FD_SET((OFSocketHandle)fd, &_writeFDs); [super addObjectForWriting: object]; } - (void)removeObjectForReading: (id )object @@ -137,11 +140,11 @@ #ifndef OF_WINDOWS if (fd >= (int)FD_SETSIZE) @throw [OFOutOfRangeException exception]; #endif - FD_CLR((of_socket_t)fd, &_readFDs); + FD_CLR((OFSocketHandle)fd, &_readFDs); [super removeObjectForReading: object]; } - (void)removeObjectForWriting: (id )object @@ -158,23 +161,24 @@ #ifndef OF_WINDOWS if (fd >= (int)FD_SETSIZE) @throw [OFOutOfRangeException exception]; #endif - FD_CLR((of_socket_t)fd, &_writeFDs); + FD_CLR((OFSocketHandle)fd, &_writeFDs); [super removeObjectForWriting: object]; } -- (void)observeForTimeInterval: (of_time_interval_t)timeInterval +- (void)observeForTimeInterval: (OFTimeInterval)timeInterval { fd_set readFDs; fd_set writeFDs; struct timeval timeout; int events; #ifdef OF_AMIGAOS - ULONG execSignalMask, cancelSignal; + BYTE cancelSignal; + ULONG execSignalMask; #endif void *pool; if ([self of_processReadBuffers]) return; @@ -196,14 +200,14 @@ #ifndef OF_WINDOWS timeout.tv_sec = (time_t)timeInterval; #else timeout.tv_sec = (long)timeInterval; #endif - timeout.tv_usec = (int)((timeInterval - timeout.tv_sec) * 1000); + timeout.tv_usec = (int)((timeInterval - timeout.tv_sec) * 1000000); #ifdef OF_AMIGAOS - if ((cancelSignal = AllocSignal(-1)) == (ULONG)-1) + if ((cancelSignal = AllocSignal(-1)) == (BYTE)-1) @throw [OFObserveFailedException exceptionWithObserver: self errNo: EAGAIN]; execSignalMask = _execSignalMask | (1ul << cancelSignal); @@ -227,11 +231,11 @@ #endif if (events < 0) @throw [OFObserveFailedException exceptionWithObserver: self - errNo: of_socket_errno()]; + errNo: OFSocketErrNo()]; #ifdef OF_AMIGAOS if (execSignalMask != 0 && [_delegate respondsToSelector: @selector(execSignalWasReceived:)]) [_delegate execSignalWasReceived: execSignalMask]; @@ -238,13 +242,13 @@ #else if (FD_ISSET(_cancelFD[0], &readFDs)) { char buffer; # ifdef OF_HAVE_PIPE - OF_ENSURE(read(_cancelFD[0], &buffer, 1) == 1); + OFEnsure(read(_cancelFD[0], &buffer, 1) == 1); # else - OF_ENSURE(recvfrom(_cancelFD[0], (void *)&buffer, 1, 0, NULL, + OFEnsure(recvfrom(_cancelFD[0], (void *)&buffer, 1, 0, NULL, NULL) == 1); # endif } #endif @@ -253,11 +257,11 @@ for (id object in [[_readObjects copy] autorelease]) { void *pool2 = objc_autoreleasePoolPush(); int fd = object.fileDescriptorForReading; - if (FD_ISSET((of_socket_t)fd, &readFDs) && + if (FD_ISSET((OFSocketHandle)fd, &readFDs) && [_delegate respondsToSelector: @selector(objectIsReadyForReading:)]) [_delegate objectIsReadyForReading: object]; objc_autoreleasePoolPop(pool2); @@ -266,11 +270,11 @@ for (id object in [[_writeObjects copy] autorelease]) { void *pool2 = objc_autoreleasePoolPush(); int fd = object.fileDescriptorForWriting; - if (FD_ISSET((of_socket_t)fd, &writeFDs) && + if (FD_ISSET((OFSocketHandle)fd, &writeFDs) && [_delegate respondsToSelector: @selector(objectIsReadyForWriting:)]) [_delegate objectIsReadyForWriting: object]; objc_autoreleasePoolPop(pool2); Index: src/OFSequencedPacketSocket+Private.h ================================================================== --- src/OFSequencedPacketSocket+Private.h +++ src/OFSequencedPacketSocket+Private.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFSequencedPacketSocket.h ================================================================== --- src/OFSequencedPacketSocket.h +++ src/OFSequencedPacketSocket.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -16,12 +14,11 @@ */ #import "OFObject.h" #import "OFKernelEventObserver.h" #import "OFRunLoop.h" - -#import "socket.h" +#import "OFSocket.h" OF_ASSUME_NONNULL_BEGIN /** @file */ @@ -35,23 +32,22 @@ * @param length The length of the packet * @param exception An exception which occurred while receiving or `nil` on * success * @return A bool whether the same block should be used for the next receive */ -typedef bool (^of_sequenced_packet_socket_async_receive_block_t)(size_t length, +typedef bool (^OFSequencedPacketSocketAsyncReceiveBlock)(size_t length, id _Nullable exception); /** * @brief A block which is called when a packet has been sent. * - * @param data The data which was sent * @param exception An exception which occurred while reading or `nil` on * success * @return The data to repeat the send with or nil if it should not repeat */ -typedef OFData *_Nullable (^of_sequenced_packet_socket_async_send_data_block_t)( - OFData *_Nonnull data, id _Nullable exception); +typedef OFData *_Nullable (^OFSequencedPacketSocketAsyncSendDataBlock)( + id _Nullable exception); /** * @brief A block which is called when the socket accepted a connection. * * @param acceptedSocket The socket which has been accepted @@ -58,11 +54,11 @@ * @param exception An exception which occurred while accepting the socket or * `nil` on success * @return A bool whether the same block should be used for the next incoming * connection */ -typedef bool (^of_sequenced_packet_socket_async_accept_block_t)( +typedef bool (^OFSequencedPacketSocketAsyncAcceptBlock)( OFSequencedPacketSocket *acceptedSocket, id _Nullable exception); #endif /** * @protocol OFSequencedPacketSocketDelegate OFSequencedPacketSocket.h \ @@ -127,13 +123,13 @@ * was called to create one "instance" for every thread! */ @interface OFSequencedPacketSocket: OFObject { - of_socket_t _socket; + OFSocketHandle _socket; bool _canBlock, _listening; - of_socket_address_t _remoteAddress; + OFSocketAddress _remoteAddress; id _Nullable _delegate; OF_RESERVE_IVARS(OFSequencedPacketSocket, 4) } /** @@ -151,11 +147,11 @@ /** * @brief The remote address. * * @note This only works for accepted sockets! */ -@property (readonly, nonatomic) const of_socket_address_t *remoteAddress; +@property (readonly, nonatomic) const OFSocketAddress *remoteAddress; /** * @brief The delegate for asynchronous operations on the socket. * * @note The delegate is retained for as long as asynchronous operations are @@ -178,12 +174,11 @@ * * @param buffer The buffer to write the packet to * @param length The length of the buffer * @return The length of the received packet */ -- (size_t)receiveIntoBuffer: (void *)buffer - length: (size_t)length; +- (size_t)receiveIntoBuffer: (void *)buffer length: (size_t)length; /** * @brief Asynchronously receives a packet and stores it into the specified * buffer. * @@ -190,12 +185,11 @@ * If the buffer is too small, the receive operation fails. * * @param buffer The buffer to write the packet to * @param length The length of the buffer */ -- (void)asyncReceiveIntoBuffer: (void *)buffer - length: (size_t)length; +- (void)asyncReceiveIntoBuffer: (void *)buffer length: (size_t)length; /** * @brief Asynchronously receives a packet and stores it into the specified * buffer. * @@ -205,11 +199,11 @@ * @param length The length of the buffer * @param runLoopMode The run loop mode in which to perform the async receive */ - (void)asyncReceiveIntoBuffer: (void *)buffer length: (size_t)length - runLoopMode: (of_run_loop_mode_t)runLoopMode; + runLoopMode: (OFRunLoopMode)runLoopMode; #ifdef OF_HAVE_BLOCKS /** * @brief Asynchronously receives a packet and stores it into the specified * buffer. @@ -222,15 +216,13 @@ * block returns true, it will be called again with the same * buffer and maximum length when more packets have been received. * If you want the next method in the queue to handle the packet * received next, you need to return false from the method. */ -- (void) - asyncReceiveIntoBuffer: (void *)buffer - length: (size_t)length - block: (of_sequenced_packet_socket_async_receive_block_t) - block; +- (void)asyncReceiveIntoBuffer: (void *)buffer + length: (size_t)length + block: (OFSequencedPacketSocketAsyncReceiveBlock)block; /** * @brief Asynchronously receives a packet and stores it into the specified * buffer. * @@ -243,26 +235,23 @@ * block returns true, it will be called again with the same * buffer and maximum length when more packets have been received. * If you want the next method in the queue to handle the packet * received next, you need to return false from the method. */ -- (void) - asyncReceiveIntoBuffer: (void *)buffer - length: (size_t)length - runLoopMode: (of_run_loop_mode_t)runLoopMode - block: (of_sequenced_packet_socket_async_receive_block_t) - block; +- (void)asyncReceiveIntoBuffer: (void *)buffer + length: (size_t)length + runLoopMode: (OFRunLoopMode)runLoopMode + block: (OFSequencedPacketSocketAsyncReceiveBlock)block; #endif /** * @brief Sends the specified packet. * * @param buffer The buffer to send as a packet * @param length The length of the buffer */ -- (void)sendBuffer: (const void *)buffer - length: (size_t)length; +- (void)sendBuffer: (const void *)buffer length: (size_t)length; /** * @brief Asynchronously sends the specified packet. * * @param data The data to send as a packet @@ -273,12 +262,11 @@ * @brief Asynchronously sends the specified packet. * * @param data The data to send as a packet * @param runLoopMode The run loop mode in which to perform the async send */ -- (void)asyncSendData: (OFData *)data - runLoopMode: (of_run_loop_mode_t)runLoopMode; +- (void)asyncSendData: (OFData *)data runLoopMode: (OFRunLoopMode)runLoopMode; #ifdef OF_HAVE_BLOCKS /** * @brief Asynchronously sends the specified packet. * @@ -286,12 +274,11 @@ * @param block The block to call when the packet has been sent. It should * return the data for the next send with the same callback or nil * if it should not repeat. */ - (void)asyncSendData: (OFData *)data - block: (of_sequenced_packet_socket_async_send_data_block_t) - block; + block: (OFSequencedPacketSocketAsyncSendDataBlock)block; /** * @brief Asynchronously sends the specified packet. * * @param data The data to send as a packet @@ -299,13 +286,12 @@ * @param block The block to call when the packet has been sent. It should * return the data for the next send with the same callback or nil * if it should not repeat. */ - (void)asyncSendData: (OFData *)data - runLoopMode: (of_run_loop_mode_t)runLoopMode - block: (of_sequenced_packet_socket_async_send_data_block_t) - block; + runLoopMode: (OFRunLoopMode)runLoopMode + block: (OFSequencedPacketSocketAsyncSendDataBlock)block; #endif /** * @brief Listen on the socket. * @@ -333,33 +319,33 @@ /** * @brief Asynchronously accept an incoming connection. * * @param runLoopMode The run loop mode in which to perform the async accept */ -- (void)asyncAcceptWithRunLoopMode: (of_run_loop_mode_t)runLoopMode; +- (void)asyncAcceptWithRunLoopMode: (OFRunLoopMode)runLoopMode; #ifdef OF_HAVE_BLOCKS /** * @brief Asynchronously accept an incoming connection. * * @param block The block to execute when a new connection has been accepted. * Returns whether the next incoming connection should be accepted * by the specified block as well. */ -- (void)asyncAcceptWithBlock: - (of_sequenced_packet_socket_async_accept_block_t)block; +- (void)asyncAcceptWithBlock: (OFSequencedPacketSocketAsyncAcceptBlock)block; /** * @brief Asynchronously accept an incoming connection. * * @param runLoopMode The run loop mode in which to perform the async accept * @param block The block to execute when a new connection has been accepted. * Returns whether the next incoming connection should be accepted * by the specified block as well. */ -- (void)asyncAcceptWithRunLoopMode: (of_run_loop_mode_t)runLoopMode - block: (of_sequenced_packet_socket_async_accept_block_t)block; +- (void) + asyncAcceptWithRunLoopMode: (OFRunLoopMode)runLoopMode + block: (OFSequencedPacketSocketAsyncAcceptBlock)block; #endif /** * @brief Cancels all pending asynchronous requests on the socket. */ Index: src/OFSequencedPacketSocket.m ================================================================== --- src/OFSequencedPacketSocket.m +++ src/OFSequencedPacketSocket.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -15,10 +13,15 @@ * file. */ #include "config.h" +#ifndef _XOPEN_SOURCE_EXTENDED +# define _XOPEN_SOURCE_EXTENDED +#endif +#define _HPUX_ALT_XOPEN_SOCKET_API + #include #include #ifdef HAVE_FCNTL_H # include @@ -27,10 +30,12 @@ #import "OFSequencedPacketSocket.h" #import "OFSequencedPacketSocket+Private.h" #import "OFData.h" #import "OFRunLoop+Private.h" #import "OFRunLoop.h" +#import "OFSocket.h" +#import "OFSocket+Private.h" #import "OFAcceptFailedException.h" #import "OFInitializationFailedException.h" #import "OFInvalidArgumentException.h" #import "OFListenFailedException.h" @@ -38,22 +43,19 @@ #import "OFOutOfRangeException.h" #import "OFReadFailedException.h" #import "OFSetOptionFailedException.h" #import "OFWriteFailedException.h" -#import "socket.h" -#import "socket_helpers.h" - @implementation OFSequencedPacketSocket @synthesize listening = _listening, delegate = _delegate; + (void)initialize { if (self != [OFSequencedPacketSocket class]) return; - if (!of_socket_init()) + if (!OFSocketInit()) @throw [OFInitializationFailedException exceptionWithClass: self]; } + (instancetype)socket @@ -69,11 +71,11 @@ if (self.class == [OFSequencedPacketSocket class]) { [self doesNotRecognizeSelector: _cmd]; abort(); } - _socket = INVALID_SOCKET; + _socket = OFInvalidSocketHandle; _canBlock = true; } @catch (id e) { [self release]; @throw e; } @@ -81,11 +83,11 @@ return self; } - (void)dealloc { - if (_socket != INVALID_SOCKET) + if (_socket != OFInvalidSocketHandle) [self close]; [super dealloc]; } @@ -95,11 +97,11 @@ int errNo; socklen_t len = sizeof(errNo); if (getsockopt(_socket, SOL_SOCKET, SO_ERROR, (char *)&errNo, &len) != 0) - return of_socket_errno(); + return OFSocketErrNo(); return errNo; } #endif @@ -131,62 +133,60 @@ @throw [OFSetOptionFailedException exceptionWithObject: self errNo: errno]; _canBlock = canBlock; #elif defined(OF_WINDOWS) - u_long v = canBlock; + u_long v = !canBlock; if (ioctlsocket(_socket, FIONBIO, &v) == SOCKET_ERROR) @throw [OFSetOptionFailedException exceptionWithObject: self - errNo: of_socket_errno()]; + errNo: OFSocketErrNo()]; _canBlock = canBlock; #else OF_UNRECOGNIZED_SELECTOR #endif } -- (size_t)receiveIntoBuffer: (void *)buffer - length: (size_t)length +- (size_t)receiveIntoBuffer: (void *)buffer length: (size_t)length { ssize_t ret; - if (_socket == INVALID_SOCKET) + if (_socket == OFInvalidSocketHandle) @throw [OFNotOpenException exceptionWithObject: self]; #ifndef OF_WINDOWS if ((ret = recv(_socket, buffer, length, 0)) < 0) @throw [OFReadFailedException exceptionWithObject: self requestedLength: length - errNo: of_socket_errno()]; + errNo: OFSocketErrNo()]; #else if (length > INT_MAX) @throw [OFOutOfRangeException exception]; if ((ret = recv(_socket, buffer, (int)length, 0)) < 0) @throw [OFReadFailedException exceptionWithObject: self requestedLength: length - errNo: of_socket_errno()]; + errNo: OFSocketErrNo()]; #endif return ret; } -- (void)asyncReceiveIntoBuffer: (void *)buffer - length: (size_t)length +- (void)asyncReceiveIntoBuffer: (void *)buffer length: (size_t)length { [self asyncReceiveIntoBuffer: buffer length: length - runLoopMode: of_run_loop_mode_default]; + runLoopMode: OFDefaultRunLoopMode]; } - (void)asyncReceiveIntoBuffer: (void *)buffer length: (size_t)length - runLoopMode: (of_run_loop_mode_t)runLoopMode + runLoopMode: (OFRunLoopMode)runLoopMode { [OFRunLoop of_addAsyncReceiveForSequencedPacketSocket: self buffer: buffer length: length mode: runLoopMode @@ -195,28 +195,25 @@ # endif delegate: _delegate]; } #ifdef OF_HAVE_BLOCKS -- (void) - asyncReceiveIntoBuffer: (void *)buffer - length: (size_t)length - block: (of_sequenced_packet_socket_async_receive_block_t) - block +- (void)asyncReceiveIntoBuffer: (void *)buffer + length: (size_t)length + block: (OFSequencedPacketSocketAsyncReceiveBlock)block { [self asyncReceiveIntoBuffer: buffer length: length - runLoopMode: of_run_loop_mode_default + runLoopMode: OFDefaultRunLoopMode block: block]; } - (void) asyncReceiveIntoBuffer: (void *)buffer length: (size_t)length - runLoopMode: (of_run_loop_mode_t)runLoopMode - block: (of_sequenced_packet_socket_async_receive_block_t) - block + runLoopMode: (OFRunLoopMode)runLoopMode + block: (OFSequencedPacketSocketAsyncReceiveBlock)block { [OFRunLoop of_addAsyncReceiveForSequencedPacketSocket: self buffer: buffer length: length mode: runLoopMode @@ -223,14 +220,13 @@ block: block delegate: nil]; } #endif -- (void)sendBuffer: (const void *)buffer - length: (size_t)length +- (void)sendBuffer: (const void *)buffer length: (size_t)length { - if (_socket == INVALID_SOCKET) + if (_socket == OFInvalidSocketHandle) @throw [OFNotOpenException exceptionWithObject: self]; #ifndef OF_WINDOWS ssize_t bytesWritten; @@ -240,11 +236,11 @@ if ((bytesWritten = send(_socket, (void *)buffer, length, 0)) < 0) @throw [OFWriteFailedException exceptionWithObject: self requestedLength: length bytesWritten: 0 - errNo: of_socket_errno()]; + errNo: OFSocketErrNo()]; #else int bytesWritten; if (length > INT_MAX) @throw [OFOutOfRangeException exception]; @@ -252,11 +248,11 @@ if ((bytesWritten = send(_socket, buffer, (int)length, 0)) < 0) @throw [OFWriteFailedException exceptionWithObject: self requestedLength: length bytesWritten: 0 - errNo: of_socket_errno()]; + errNo: OFSocketErrNo()]; #endif if ((size_t)bytesWritten != length) @throw [OFWriteFailedException exceptionWithObject: self requestedLength: length @@ -264,16 +260,14 @@ errNo: 0]; } - (void)asyncSendData: (OFData *)data { - [self asyncSendData: data - runLoopMode: of_run_loop_mode_default]; + [self asyncSendData: data runLoopMode: OFDefaultRunLoopMode]; } -- (void)asyncSendData: (OFData *)data - runLoopMode: (of_run_loop_mode_t)runLoopMode +- (void)asyncSendData: (OFData *)data runLoopMode: (OFRunLoopMode)runLoopMode { [OFRunLoop of_addAsyncSendForSequencedPacketSocket: self data: data mode: runLoopMode # ifdef OF_HAVE_BLOCKS @@ -282,20 +276,20 @@ delegate: _delegate]; } #ifdef OF_HAVE_BLOCKS - (void)asyncSendData: (OFData *)data - block: (of_sequenced_packet_socket_async_send_data_block_t)block + block: (OFSequencedPacketSocketAsyncSendDataBlock)block { [self asyncSendData: data - runLoopMode: of_run_loop_mode_default + runLoopMode: OFDefaultRunLoopMode block: block]; } - (void)asyncSendData: (OFData *)data - runLoopMode: (of_run_loop_mode_t)runLoopMode - block: (of_sequenced_packet_socket_async_send_data_block_t)block + runLoopMode: (OFRunLoopMode)runLoopMode + block: (OFSequencedPacketSocketAsyncSendDataBlock)block { [OFRunLoop of_addAsyncSendForSequencedPacketSocket: self data: data mode: runLoopMode block: block @@ -308,18 +302,18 @@ [self listenWithBacklog: SOMAXCONN]; } - (void)listenWithBacklog: (int)backlog { - if (_socket == INVALID_SOCKET) + if (_socket == OFInvalidSocketHandle) @throw [OFNotOpenException exceptionWithObject: self]; if (listen(_socket, backlog) == -1) @throw [OFListenFailedException exceptionWithSocket: self backlog: backlog - errNo: of_socket_errno()]; + errNo: OFSocketErrNo()]; _listening = true; } - (instancetype)accept @@ -337,28 +331,29 @@ #if defined(HAVE_PACCEPT) && defined(SOCK_CLOEXEC) if ((client->_socket = paccept(_socket, &client->_remoteAddress.sockaddr.sockaddr, &client->_remoteAddress.length, NULL, SOCK_CLOEXEC)) == - INVALID_SOCKET) + OFInvalidSocketHandle) @throw [OFAcceptFailedException exceptionWithSocket: self - errNo: of_socket_errno()]; + errNo: OFSocketErrNo()]; #elif defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) if ((client->_socket = accept4(_socket, &client->_remoteAddress.sockaddr.sockaddr, - &client->_remoteAddress.length, SOCK_CLOEXEC)) == INVALID_SOCKET) + &client->_remoteAddress.length, SOCK_CLOEXEC)) == + OFInvalidSocketHandle) @throw [OFAcceptFailedException exceptionWithSocket: self - errNo: of_socket_errno()]; + errNo: OFSocketErrNo()]; #else if ((client->_socket = accept(_socket, &client->_remoteAddress.sockaddr.sockaddr, - &client->_remoteAddress.length)) == INVALID_SOCKET) + &client->_remoteAddress.length)) == OFInvalidSocketHandle) @throw [OFAcceptFailedException exceptionWithSocket: self - errNo: of_socket_errno()]; + 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 @@ -367,65 +362,63 @@ assert(client->_remoteAddress.length <= (socklen_t)sizeof(client->_remoteAddress.sockaddr)); switch (client->_remoteAddress.sockaddr.sockaddr.sa_family) { case AF_INET: - client->_remoteAddress.family = OF_SOCKET_ADDRESS_FAMILY_IPV4; + client->_remoteAddress.family = OFSocketAddressFamilyIPv4; break; #ifdef OF_HAVE_IPV6 case AF_INET6: - client->_remoteAddress.family = OF_SOCKET_ADDRESS_FAMILY_IPV6; + client->_remoteAddress.family = OFSocketAddressFamilyIPv6; break; #endif #ifdef OF_HAVE_IPX case AF_IPX: - client->_remoteAddress.family = OF_SOCKET_ADDRESS_FAMILY_IPX; + client->_remoteAddress.family = OFSocketAddressFamilyIPX; break; #endif default: - client->_remoteAddress.family = - OF_SOCKET_ADDRESS_FAMILY_UNKNOWN; + client->_remoteAddress.family = OFSocketAddressFamilyUnknown; break; } return client; } - (void)asyncAccept { - [self asyncAcceptWithRunLoopMode: of_run_loop_mode_default]; + [self asyncAcceptWithRunLoopMode: OFDefaultRunLoopMode]; } -- (void)asyncAcceptWithRunLoopMode: (of_run_loop_mode_t)runLoopMode +- (void)asyncAcceptWithRunLoopMode: (OFRunLoopMode)runLoopMode { [OFRunLoop of_addAsyncAcceptForSocket: self mode: runLoopMode block: NULL delegate: _delegate]; } #ifdef OF_HAVE_BLOCKS -- (void)asyncAcceptWithBlock: (of_sequenced_packet_socket_async_accept_block_t) - block +- (void)asyncAcceptWithBlock: (OFSequencedPacketSocketAsyncAcceptBlock)block { - [self asyncAcceptWithRunLoopMode: of_run_loop_mode_default - block: block]; + [self asyncAcceptWithRunLoopMode: OFDefaultRunLoopMode block: block]; } -- (void)asyncAcceptWithRunLoopMode: (of_run_loop_mode_t)runLoopMode - block: (of_sequenced_packet_socket_async_accept_block_t)block +- (void) + asyncAcceptWithRunLoopMode: (OFRunLoopMode)runLoopMode + block: (OFSequencedPacketSocketAsyncAcceptBlock)block { [OFRunLoop of_addAsyncAcceptForSocket: self mode: runLoopMode block: block delegate: nil]; } #endif -- (const of_socket_address_t *)remoteAddress +- (const OFSocketAddress *)remoteAddress { - if (_socket == INVALID_SOCKET) + if (_socket == OFInvalidSocketHandle) @throw [OFNotOpenException exceptionWithObject: self]; if (_remoteAddress.length == 0) @throw [OFInvalidArgumentException exception]; @@ -436,19 +429,19 @@ } - (void)cancelAsyncRequests { [OFRunLoop of_cancelAsyncRequestsForObject: self - mode: of_run_loop_mode_default]; + mode: OFDefaultRunLoopMode]; } - (int)fileDescriptorForReading { #ifndef OF_WINDOWS return _socket; #else - if (_socket == INVALID_SOCKET) + if (_socket == OFInvalidSocketHandle) return -1; if (_socket > INT_MAX) @throw [OFOutOfRangeException exception]; @@ -459,11 +452,11 @@ - (int)fileDescriptorForWriting { #ifndef OF_WINDOWS return _socket; #else - if (_socket == INVALID_SOCKET) + if (_socket == OFInvalidSocketHandle) return -1; if (_socket > INT_MAX) @throw [OFOutOfRangeException exception]; @@ -471,15 +464,15 @@ #endif } - (void)close { - if (_socket == INVALID_SOCKET) + if (_socket == OFInvalidSocketHandle) @throw [OFNotOpenException exceptionWithObject: self]; _listening = false; memset(&_remoteAddress, 0, sizeof(_remoteAddress)); closesocket(_socket); - _socket = INVALID_SOCKET; + _socket = OFInvalidSocketHandle; } @end Index: src/OFSerialization.h ================================================================== --- src/OFSerialization.h +++ src/OFSerialization.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -17,12 +15,11 @@ #import "OFObject.h" OF_ASSUME_NONNULL_BEGIN -#define OF_SERIALIZATION_NS @"https://objfw.nil.im/serialization" - +@class OFConstantString; @class OFXMLElement; /** * @protocol OFSerialization OFSerialization.h ObjFW/OFSerialization.h * @@ -40,7 +37,15 @@ * @param element An OFXMLElement with the serialized object * @return An initialized object */ - (instancetype)initWithSerialization: (OFXMLElement *)element; @end + +#ifdef __cplusplus +extern "C" { +#endif +extern OFConstantString *const OFSerializationNS; +#ifdef __cplusplus +} +#endif OF_ASSUME_NONNULL_END ADDED src/OFSerialization.m Index: src/OFSerialization.m ================================================================== --- /dev/null +++ src/OFSerialization.m @@ -0,0 +1,20 @@ +/* + * 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,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -40,19 +38,19 @@ * * @param object The current object * @param stop A pointer to a variable that can be set to true to stop the * enumeration */ -typedef void (^of_set_enumeration_block_t)(id object, bool *stop); +typedef void (^OFSetEnumerationBlock)(id object, bool *stop); /** * @brief A block for filtering an OFSet. * * @param object The object to inspect * @return Whether the object should be in the filtered set */ -typedef bool (^of_set_filter_block_t)(id object); +typedef bool (^OFSetFilterBlock)(id object); #endif /** * @class OFSet OFSet.h ObjFW/OFSet.h * @@ -142,10 +140,21 @@ * @param firstObject The first object for the set * @return An initialized set with the specified objects */ - (instancetype)initWithObjects: (ObjectType)firstObject, ... OF_SENTINEL; +/** + * @brief Initializes an already allocated set with the specified object and + * va_list. + * + * @param firstObject The first object for the set + * @param arguments A va_list with the other objects + * @return An initialized set with the specified object and va_list + */ +- (instancetype)initWithObject: (ObjectType)firstObject + arguments: (va_list)arguments; + /** * @brief Initializes an already allocated set with the specified objects. * * @param objects An array of objects for the set * @param count The number of objects in the specified array @@ -153,19 +162,15 @@ */ - (instancetype)initWithObjects: (ObjectType const _Nonnull *_Nonnull)objects count: (size_t)count; /** - * @brief Initializes an already allocated set with the specified object and - * va_list. - * - * @param firstObject The first object for the set - * @param arguments A va_list with the other objects - * @return An initialized set with the specified object and va_list - */ -- (instancetype)initWithObject: (ObjectType)firstObject - arguments: (va_list)arguments; + * @brief Returns an OFEnumerator to enumerate through all objects of the set. + * + * @return An OFEnumerator to enumerate through all objects of the set + */ +- (OFEnumerator OF_GENERIC(ObjectType) *)objectEnumerator; /** * @brief Returns whether the receiver is a subset of the specified set. * * @return Whether the receiver is a subset of the specified set @@ -179,35 +184,17 @@ * @return Whether the receiver and the specified set have at least one object * in common */ - (bool)intersectsSet: (OFSet OF_GENERIC(ObjectType) *)set; -/** - * @brief Creates a new set which contains the objects which are in the - * receiver, but not in the specified set. - * - * @param set The set whose objects will not be in the new set - */ -- (OFSet OF_GENERIC(ObjectType) *)setBySubtractingSet: - (OFSet OF_GENERIC(ObjectType) *)set; - -/** - * @brief Creates a new set by creating the intersection of the receiver and - * the specified set. - * - * @param set The set to intersect with - */ -- (OFSet OF_GENERIC(ObjectType) *)setByIntersectingWithSet: - (OFSet OF_GENERIC(ObjectType) *)set; - /** * @brief Creates a new set by creating the union of the receiver and the * specified set. * * @param set The set to create the union with */ -- (OFSet OF_GENERIC(ObjectType) *)setByAddingSet: +- (OFSet OF_GENERIC(ObjectType) *)setByAddingObjectsFromSet: (OFSet OF_GENERIC(ObjectType) *)set; /** * @brief Checks whether the set contains an object equal to the specified * object. @@ -239,34 +226,33 @@ * @note A @ref OFNull value is translated to nil! * * @param value The value for the specified key * @param key The key of the value to set */ -- (void)setValue: (nullable id)value - forKey: (OFString *)key; +- (void)setValue: (nullable id)value forKey: (OFString *)key; #ifdef OF_HAVE_BLOCKS /** * @brief Executes a block for each object in the set. * * @param block The block to execute for each object in the set */ -- (void)enumerateObjectsUsingBlock: (of_set_enumeration_block_t)block; +- (void)enumerateObjectsUsingBlock: (OFSetEnumerationBlock)block; /** * @brief Creates a new set, only containing the objects for which the block * returns true. * * @param block A block which determines if the object should be in the new set * @return A new, autoreleased OFSet */ -- (OFSet OF_GENERIC(ObjectType) *)filteredSetUsingBlock: - (of_set_filter_block_t)block; +- (OFSet OF_GENERIC(ObjectType) *) + filteredSetUsingBlock: (OFSetFilterBlock)block; #endif #if !defined(OF_HAVE_GENERICS) && !defined(DOXYGEN) # undef ObjectType #endif @end OF_ASSUME_NONNULL_END #import "OFMutableSet.h" Index: src/OFSet.m ================================================================== --- src/OFSet.m +++ src/OFSet.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -60,19 +58,17 @@ va_end(arguments); return ret; } -- (instancetype)initWithObjects: (id const *)objects - count: (size_t)count +- (instancetype)initWithObjects: (id const *)objects count: (size_t)count { return (id)[[OFMapTableSet alloc] initWithObjects: objects count: count]; } -- (instancetype)initWithObject: (id)firstObject - arguments: (va_list)arguments +- (instancetype)initWithObject: (id)firstObject arguments: (va_list)arguments { return (id)[[OFMapTableSet alloc] initWithObject: firstObject arguments: arguments]; } @@ -142,12 +138,11 @@ va_end(arguments); return ret; } -+ (instancetype)setWithObjects: (id const *)objects - count: (size_t)count ++ (instancetype)setWithObjects: (id const *)objects count: (size_t)count { return [[[self alloc] initWithObjects: objects count: count] autorelease]; } @@ -175,12 +170,11 @@ - (instancetype)initWithArray: (OFArray *)array { OF_INVALID_INIT_METHOD } -- (instancetype)initWithObjects: (id const *)objects - count: (size_t)count +- (instancetype)initWithObjects: (id const *)objects count: (size_t)count { OF_INVALID_INIT_METHOD } - (instancetype)initWithObjects: (id)firstObject, ... @@ -187,19 +181,17 @@ { id ret; va_list arguments; va_start(arguments, firstObject); - ret = [self initWithObject: firstObject - arguments: arguments]; + ret = [self initWithObject: firstObject arguments: arguments]; va_end(arguments); return ret; } -- (instancetype)initWithObject: (id)firstObject - arguments: (va_list)arguments +- (instancetype)initWithObject: (id)firstObject arguments: (va_list)arguments { OF_INVALID_INIT_METHOD } - (instancetype)initWithSerialization: (OFXMLElement *)element @@ -231,16 +223,14 @@ [ret makeImmutable]; return ret; } -- (void)setValue: (id)value - forKey: (OFString *)key +- (void)setValue: (id)value forKey: (OFString *)key { for (id object in self) - [object setValue: value - forKey: key]; + [object setValue: value forKey: key]; } - (bool)containsObject: (id)object { OF_UNRECOGNIZED_SELECTOR @@ -249,11 +239,11 @@ - (OFEnumerator *)objectEnumerator { OF_UNRECOGNIZED_SELECTOR } -- (int)countByEnumeratingWithState: (of_fast_enumeration_state_t *)state +- (int)countByEnumeratingWithState: (OFFastEnumerationState *)state objects: (id *)objects count: (int)count { OFEnumerator *enumerator; int i; @@ -333,14 +323,12 @@ if (++i < count) [ret appendString: @",\n"]; objc_autoreleasePoolPop(pool2); } - [ret replaceOccurrencesOfString: @"\n" - withString: @"\n\t"]; + [ret replaceOccurrencesOfString: @"\n" withString: @"\n\t"]; [ret appendString: @"\n)}"]; - [ret makeImmutable]; objc_autoreleasePoolPop(pool); return ret; @@ -379,20 +367,18 @@ void *pool = objc_autoreleasePoolPush(); OFXMLElement *element; if ([self isKindOfClass: [OFMutableSet class]]) element = [OFXMLElement elementWithName: @"OFMutableSet" - namespace: OF_SERIALIZATION_NS]; + namespace: OFSerializationNS]; else element = [OFXMLElement elementWithName: @"OFSet" - namespace: OF_SERIALIZATION_NS]; + namespace: OFSerializationNS]; for (id object in self) { void *pool2 = objc_autoreleasePoolPush(); - [element addChild: object.XMLElementBySerializing]; - objc_autoreleasePoolPop(pool2); } [element retain]; @@ -399,66 +385,36 @@ objc_autoreleasePoolPop(pool); return [element autorelease]; } -- (OFSet *)setBySubtractingSet: (OFSet *)set -{ - OFMutableSet *new; - - new = [[self mutableCopy] autorelease]; - [new minusSet: set]; - - [new makeImmutable]; - - return new; -} - -- (OFSet *)setByIntersectingWithSet: (OFSet *)set -{ - OFMutableSet *new; - - new = [[self mutableCopy] autorelease]; - [new intersectSet: set]; - - [new makeImmutable]; - - return new; -} - -- (OFSet *)setByAddingSet: (OFSet *)set -{ - OFMutableSet *new; - - new = [[self mutableCopy] autorelease]; - [new unionSet: set]; - - [new makeImmutable]; - +- (OFSet *)setByAddingObjectsFromSet: (OFSet *)set +{ + OFMutableSet *new = [[self mutableCopy] autorelease]; + [new unionSet: set]; + [new makeImmutable]; return new; } - (OFArray *)allObjects { void *pool = objc_autoreleasePoolPush(); OFArray *ret = [[[self objectEnumerator] allObjects] retain]; objc_autoreleasePoolPop(pool); - return [ret autorelease]; } - (id)anyObject { void *pool = objc_autoreleasePoolPush(); id ret = [[[self objectEnumerator] nextObject] retain]; objc_autoreleasePoolPop(pool); - return [ret autorelease]; } #ifdef OF_HAVE_BLOCKS -- (void)enumerateObjectsUsingBlock: (of_set_enumeration_block_t)block +- (void)enumerateObjectsUsingBlock: (OFSetEnumerationBlock)block { bool stop = false; for (id object in self) { block(object, &stop); @@ -466,11 +422,11 @@ if (stop) break; } } -- (OFSet *)filteredSetUsingBlock: (of_set_filter_block_t)block +- (OFSet *)filteredSetUsingBlock: (OFSetFilterBlock)block { OFMutableSet *ret = [OFMutableSet set]; [self enumerateObjectsUsingBlock: ^ (id object, bool *stop) { if (block(object)) Index: src/OFSettings.h ================================================================== --- src/OFSettings.h +++ src/OFSettings.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -72,130 +70,122 @@ * @brief Sets the specified path to the specified string. * * @param string The string to set * @param path The path to store the string at */ -- (void)setString: (OFString *)string - forPath: (OFString *)path; +- (void)setString: (OFString *)string forPath: (OFString *)path; /** - * @brief Sets the specified path to the specified integer. + * @brief Sets the specified path to the specified long long. * - * @param integer The integer to set - * @param path The path to store the integer at + * @param longLong The long long to set + * @param path The path to store the long long at */ -- (void)setInteger: (long long)integer - forPath: (OFString *)path; +- (void)setLongLong: (long long)longLong forPath: (OFString *)path; /** * @brief Sets the specified path to the specified bool. * * @param bool_ The bool to set * @param path The path to store the bool at */ -- (void)setBool: (bool)bool_ - forPath: (OFString *)path; +- (void)setBool: (bool)bool_ forPath: (OFString *)path; /** * @brief Sets the specified path to the specified float. * * @param float_ The float to set * @param path The path to store the float at */ -- (void)setFloat: (float)float_ - forPath: (OFString *)path; +- (void)setFloat: (float)float_ forPath: (OFString *)path; /** * @brief Sets the specified path to the specified double. * * @param double_ The double to set * @param path The path to store the double at */ -- (void)setDouble: (double)double_ - forPath: (OFString *)path; +- (void)setDouble: (double)double_ forPath: (OFString *)path; /** * @brief Sets the specified path to the specified array of strings. * * @param array The array of strings to set - * @param path The path to store the array of strings at + * @param path The path to store the array of string at */ -- (void)setArray: (OFArray OF_GENERIC(OFString *) *)array - forPath: (OFString *)path; +- (void)setStringArray: (OFArray OF_GENERIC(OFString *) *)array + forPath: (OFString *)path; /** * @brief Returns the string for the specified path, or `nil` if the path does * not exist. * - * @param path The path for which the string value should be returned - * @return The string value of the specified path + * @param path The path for which the string should be returned + * @return The string of the specified path */ - (nullable OFString *)stringForPath: (OFString *)path; /** * @brief Returns the string for the specified path, or the default value if * the path does not exist. * - * @param path The path for which the string value should be returned + * @param path The path for which the string should be returned * @param defaultValue The default value to return if the path does not exist - * @return The string value of the specified path + * @return The string of the specified path */ - (nullable OFString *)stringForPath: (OFString *)path defaultValue: (nullable OFString *)defaultValue; /** - * @brief Returns the integer for the specified path, or the default value if + * @brief Returns the long long for the specified path, or the default value if * the path does not exist. * - * @param path The path for which the integer value should be returned + * @param path The path for which the long long should be returned * @param defaultValue The default value to return if the path does not exist - * @return The integer value of the specified path + * @return The long long of the specified path */ -- (long long)integerForPath: (OFString *)path - defaultValue: (long long)defaultValue; +- (long long)longLongForPath: (OFString *)path + defaultValue: (long long)defaultValue; /** * @brief Returns the bool for the specified path, or the default value if the * path does not exist. * - * @param path The path for which the bool value should be returned + * @param path The path for which the bool should be returned * @param defaultValue The default value to return if the path does not exist - * @return The bool value of the specified path + * @return The bool of the specified path */ -- (bool)boolForPath: (OFString *)path - defaultValue: (bool)defaultValue; +- (bool)boolForPath: (OFString *)path defaultValue: (bool)defaultValue; /** * @brief Returns the float for the specified path, or the default value if the * path does not exist. * - * @param path The path for which the float value should be returned + * @param path The path for which the float should be returned * @param defaultValue The default value to return if the path does not exist - * @return The float value of the specified path + * @return The float of the specified path */ -- (float)floatForPath: (OFString *)path - defaultValue: (float)defaultValue; +- (float)floatForPath: (OFString *)path defaultValue: (float)defaultValue; /** * @brief Returns the double for the specified path, or the default value if * the path does not exist. * - * @param path The path for which the double value should be returned + * @param path The path for which the double should be returned * @param defaultValue The default value to return if the path does not exist - * @return The double value of the specified path + * @return The double of the specified path */ -- (double)doubleForPath: (OFString *)path - defaultValue: (double)defaultValue; +- (double)doubleForPath: (OFString *)path defaultValue: (double)defaultValue; /** * @brief Returns the array of strings for the specified path, or an empty * array if the path does not exist. * * @param path The path for which the array of strings should be returned - * @return The array of strings of the specified path + * @return The array of string values of the specified path */ -- (OFArray OF_GENERIC(OFString *) *)arrayForPath: (OFString *)path; +- (OFArray OF_GENERIC(OFString *) *)stringArrayForPath: (OFString *)path; /** * @brief Removes the value for the specified path. * * @param path The path for which the value should be removed Index: src/OFSettings.m ================================================================== --- src/OFSettings.m +++ src/OFSettings.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -48,12 +46,12 @@ self = [super init]; @try { _applicationName = [applicationName copy]; } @catch (id e) { - @throw e; [self release]; + @throw e; } return self; } @@ -62,83 +60,74 @@ [_applicationName release]; [super dealloc]; } -- (void)setString: (OFString *)string - forPath: (OFString *)path -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (void)setInteger: (long long)integer - forPath: (OFString *)path -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (void)setBool: (bool)bool_ - forPath: (OFString *)path -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (void)setFloat: (float)float_ - forPath: (OFString *)path -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (void)setDouble: (double)double_ - forPath: (OFString *)path -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (void)setArray: (OFArray *)array - forPath: (OFString *)path +- (void)setString: (OFString *)string forPath: (OFString *)path +{ + OF_UNRECOGNIZED_SELECTOR +} + +- (void)setLongLong: (long long)longLong forPath: (OFString *)path +{ + OF_UNRECOGNIZED_SELECTOR +} + +- (void)setBool: (bool)bool_ forPath: (OFString *)path +{ + OF_UNRECOGNIZED_SELECTOR +} + +- (void)setFloat: (float)float_ forPath: (OFString *)path +{ + OF_UNRECOGNIZED_SELECTOR +} + +- (void)setDouble: (double)double_ forPath: (OFString *)path +{ + OF_UNRECOGNIZED_SELECTOR +} + +- (void)setStringArray: (OFArray OF_GENERIC(OFString *) *)array + forPath: (OFString *)path { OF_UNRECOGNIZED_SELECTOR } - (OFString *)stringForPath: (OFString *)path { - return [self stringForPath: path - defaultValue: nil]; + return [self stringForPath: path defaultValue: nil]; } - (OFString *)stringForPath: (OFString *)path defaultValue: (OFString *)defaultValue { OF_UNRECOGNIZED_SELECTOR } -- (long long)integerForPath: (OFString *)path - defaultValue: (long long)defaultValue +- (long long)longLongForPath: (OFString *)path + defaultValue: (long long)defaultValue +{ + OF_UNRECOGNIZED_SELECTOR +} + +- (bool)boolForPath: (OFString *)path defaultValue: (bool)defaultValue { OF_UNRECOGNIZED_SELECTOR } -- (bool)boolForPath: (OFString *)path - defaultValue: (bool)defaultValue +- (float)floatForPath: (OFString *)path defaultValue: (float)defaultValue { OF_UNRECOGNIZED_SELECTOR } -- (float)floatForPath: (OFString *)path - defaultValue: (float)defaultValue +- (double)doubleForPath: (OFString *)path defaultValue: (double)defaultValue { OF_UNRECOGNIZED_SELECTOR } -- (double)doubleForPath: (OFString *)path - defaultValue: (double)defaultValue -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (OFArray *)arrayForPath: (OFString *)path +- (OFArray OF_GENERIC(OFString *) *)stringArrayForPath: (OFString *)path { OF_UNRECOGNIZED_SELECTOR } - (void)removeValueForPath: (OFString *)path ADDED src/OFSizeValue.h Index: src/OFSizeValue.h ================================================================== --- /dev/null +++ src/OFSizeValue.h @@ -0,0 +1,28 @@ +/* + * 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 "OFValue.h" + +OF_ASSUME_NONNULL_BEGIN + +@interface OFSizeValue: OFValue +{ + OFSize _size; +} + +- (instancetype)initWithSize: (OFSize)size; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFSizeValue.m Index: src/OFSizeValue.m ================================================================== --- /dev/null +++ src/OFSizeValue.m @@ -0,0 +1,52 @@ +/* + * 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 "OFSizeValue.h" +#import "OFMethodSignature.h" +#import "OFString.h" + +#import "OFOutOfRangeException.h" + +@implementation OFSizeValue +@synthesize sizeValue = _size; + +- (instancetype)initWithSize: (OFSize)size +{ + self = [super init]; + + _size = size; + + return self; +} + +- (const char *)objCType +{ + return @encode(OFSize); +} + +- (void)getValue: (void *)value size: (size_t)size +{ + if (size != sizeof(_size)) + @throw [OFOutOfRangeException exception]; + + memcpy(value, &_size, sizeof(_size)); +} + +- (OFString *)description +{ + return [OFString stringWithFormat: + @"", _size.width, _size.height]; +} +@end ADDED src/OFSocket+Private.h Index: src/OFSocket+Private.h ================================================================== --- /dev/null +++ src/OFSocket+Private.h @@ -0,0 +1,93 @@ +/* + * 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 "unistd_wrapper.h" + +#ifdef HAVE_ARPA_INET_H +# include +#endif +#ifdef HAVE_NETDB_H +# include +#endif + +#include "OFSocket.h" + +#ifndef INADDR_NONE +# define INADDR_NONE ((in_addr_t)-1) +#endif + +#ifndef SOMAXCONN +/* + * Use 16 as everything > 17 fails on Nintendo 3DS and 16 is a less arbitrary + * number than 17. + */ +# define SOMAXCONN 16 +#endif + +#ifndef SOCK_CLOEXEC +# define SOCK_CLOEXEC 0 +#endif + +#if defined(OF_AMIGAOS) +# ifdef OF_MORPHOS +# include +# else +# include +# endif +# include +# define closesocket(sock) CloseSocket(sock) +# define ioctlsocket(fd, req, arg) IoctlSocket(fd, req, arg) +# define hstrerror(err) "unknown (no hstrerror)" +# define SOCKET_ERROR -1 +# if defined(OF_HAVE_THREADS) && !defined(OF_MORPHOS) +# define SocketBase ((struct Library *)OFTLSKeyGet(OFSocketBaseKey)) +# ifdef OF_AMIGAOS4 +# define ISocket ((struct SocketIFace *)OFTLSKeyGet(OFSocketInterfaceKey)) +# endif +# endif +# ifdef OF_MORPHOS +typedef uint32_t in_addr_t; +# endif +#elif !defined(OF_WINDOWS) && !defined(OF_WII) +# define closesocket(sock) close(sock) +#endif + +#ifdef OF_WII +# define accept(sock, addr, addrlen) net_accept(sock, addr, addrlen) +# define bind(sock, addr, addrlen) net_bind(sock, addr, addrlen) +# define closesocket(sock) net_close(sock) +# define connect(sock, addr, addrlen) \ + net_connect(sock, (struct sockaddr *)addr, addrlen) +# define fcntl(fd, cmd, flags) net_fcntl(fd, cmd, flags) +# define h_errno 0 +# define hstrerror(err) "unknown (no hstrerror)" +# define listen(sock, backlog) net_listen(sock, backlog) +# define poll(fds, nfds, timeout) net_poll(fds, nfds, timeout) +# define recv(sock, buf, len, flags) net_recv(sock, buf, len, flags) +# define recvfrom(sock, buf, len, flags, addr, addrlen) \ + net_recvfrom(sock, buf, len, flags, addr, addrlen) +# define select(nfds, readfds, writefds, errorfds, timeout) \ + net_select(nfds, readfds, writefds, errorfds, timeout) +# define send(sock, buf, len, flags) net_send(sock, buf, len, flags) +# define sendto(sock, buf, len, flags, addr, addrlen) \ + net_sendto(sock, buf, len, flags, (struct sockaddr *)(addr), addrlen) +# define setsockopt(sock, level, name, value, len) \ + net_setsockopt(sock, level, name, value, len) +# define socket(domain, type, proto) net_socket(domain, type, proto) +typedef u32 in_addr_t; +typedef u32 nfds_t; +#endif ADDED src/OFSocket.h Index: src/OFSocket.h ================================================================== --- /dev/null +++ src/OFSocket.h @@ -0,0 +1,334 @@ +/* + * 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 "objfw-defs.h" + +#ifndef OF_HAVE_SOCKETS +# error No sockets available! +#endif + +#include + +#import "OFString.h" +#if defined(OF_HAVE_THREADS) && defined(OF_AMIGAOS) +# import "OFTLSKey.h" +#endif + +#ifdef OF_HAVE_SYS_SOCKET_H +# include +#endif +#ifdef OF_HAVE_NETINET_IN_H +# 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_WINDOWS +# include +# include +# ifdef OF_HAVE_IPX +# include +# endif +#endif + +/** @file */ + +#ifdef OF_WII +# include +#endif + +#ifdef OF_PSP +# include +#endif + +#import "macros.h" + +OF_ASSUME_NONNULL_BEGIN + +#ifndef OF_WINDOWS +typedef int OFSocketHandle; +static const OFSocketHandle OFInvalidSocketHandle = -1; +#else +typedef SOCKET OFSocketHandle; +static const OFSocketHandle OFInvalidSocketHandle = INVALID_SOCKET; +#endif + +#ifdef OF_WINDOWS +typedef short sa_family_t; +#endif + +#ifdef OF_WII +typedef u8 sa_family_t; +#endif + +#ifdef OF_MORPHOS +typedef long socklen_t; +typedef u_char sa_family_t; +typedef u_short in_port_t; +#endif + +/** + * @brief A socket address family. + */ +typedef enum { + /** An unknown address family. */ + OFSocketAddressFamilyUnknown, + /** IPv4 */ + OFSocketAddressFamilyIPv4, + /** IPv6 */ + OFSocketAddressFamilyIPv6, + /** IPX */ + OFSocketAddressFamilyIPX, + /** UNIX */ + OFSocketAddressFamilyUNIX, + /** Any address family */ + OFSocketAddressFamilyAny = 255 +} OFSocketAddressFamily; + +#ifndef OF_HAVE_IPV6 +struct sockaddr_in6 { + sa_family_t sin6_family; + in_port_t sin6_port; + uint32_t sin6_flowinfo; + struct in6_addr { + uint8_t s6_addr[16]; + } sin6_addr; + uint32_t sin6_scope_id; +}; +#endif + +#ifndef OF_HAVE_IPX +# define IPX_NODE_LEN 6 +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 +# 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 +#endif + +#if !defined(OF_HAVE_UNIX_SOCKETS) && !defined(OF_MORPHOS) && !defined(OF_MINT) +struct sockaddr_un { + sa_family_t sun_family; + char sun_path[108]; +}; +#endif + +/** + * @struct OFSocketAddress OFSocket.h ObjFW/OFSocket.h + * + * @brief A struct which represents a host / port pair for a socket. + */ +typedef struct OF_BOXABLE { + /* + * Even though struct sockaddr contains the family, we need to use our + * own family, as we need to support storing an IPv6 address on systems + * that don't support IPv6. These may not have AF_INET6 defined and we + * can't just define it, as the value is system-dependent and might + * clash with an existing value. + */ + OFSocketAddressFamily family; + union { + struct sockaddr sockaddr; + struct sockaddr_in in; + struct sockaddr_in6 in6; + struct sockaddr_ipx ipx; + struct sockaddr_un un; + } sockaddr; + socklen_t length; +} OFSocketAddress; + +#ifdef __cplusplus +extern "C" { +#endif +/** + * @brief Parses the specified IP (either v4 or v6) and port into an + * @ref OFSocketAddress. + * + * @param IP The IP to parse + * @param port The port to use + * @return The parsed IP and port as an OFSocketAddress + */ +extern OFSocketAddress OFSocketAddressParseIP(OFString *IP, uint16_t port); + +/** + * @brief Parses the specified IPv4 and port into an @ref OFSocketAddress. + * + * @param IP The IPv4 to parse + * @param port The port to use + * @return The parsed IPv4 and port as an OFSocketAddress + */ +extern OFSocketAddress OFSocketAddressParseIPv4(OFString *IP, uint16_t port); + +/** + * @brief Parses the specified IPv6 and port into an @ref OFSocketAddress. + * + * @param IP The IPv6 to parse + * @param port The port to use + * @return The parsed IPv6 and port as an OFSocketAddress + */ +extern OFSocketAddress OFSocketAddressParseIPv6(OFString *IP, uint16_t port); + +/** + * @brief Creates an IPX address for the specified node, network and port. + * + * @param node The node in the IPX network + * @param network 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( + const unsigned char node[_Nonnull IPX_NODE_LEN], uint32_t network, + uint16_t port); + +/** + * @brief Creates a UNIX socket address from the specified path. + * + * @param path The path of the UNIX socket + * @return A UNIX socket address with the specified path + */ +extern OFSocketAddress OFSocketAddressMakeUNIX(OFString *path); + +/** + * @brief Compares two OFSocketAddress for equality. + * + * @param address1 The address to compare with the second address + * @param address2 The second address + * @return Whether the two addresses are equal + */ +extern bool OFSocketAddressEqual(const OFSocketAddress *_Nonnull address1, + const OFSocketAddress *_Nonnull address2); + +/** + * @brief Returns the hash for the specified @ref OFSocketAddress. + * + * @param address The address to hash + * @return The hash for the specified OFSocketAddress + */ +extern unsigned long OFSocketAddressHash( + const OFSocketAddress *_Nonnull address); + +/** + * @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 + */ +extern OFString *_Nonnull OFSocketAddressString( + const OFSocketAddress *_Nonnull address); + +/** + * @brief Sets the port of the specified @ref OFSocketAddress, independent of + * the address family used. + * + * @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, + uint16_t port); + +/** + * @brief Returns the port of the specified @ref OFSocketAddress, independent of + * the address family used. + * + * @param address The address on which to get the port + * @return The port of the address + */ +extern uint16_t OFSocketAddressPort(const OFSocketAddress *_Nonnull address); + +/** + * @brief Sets the IPX network of the specified @ref OFSocketAddress. + * + * @param address The address on which to set the IPX network + * @param network The IPX network to set on the address + */ +extern void OFSocketAddressSetIPXNetwork(OFSocketAddress *_Nonnull address, + uint32_t network); + +/** + * @brief Returns the IPX network of the specified @ref OFSocketAddress. + * + * @param address The address on which to get the IPX network + * @return The IPX network of the address + */ +extern uint32_t OFSocketAddressIPXNetwork( + const OFSocketAddress *_Nonnull address); + +/** + * @brief Sets the IPX node of the specified @ref OFSocketAddress. + * + * @param address The address on which to set the IPX node + * @param node The IPX node to set on the address + */ +extern void OFSocketAddressSetIPXNode(OFSocketAddress *_Nonnull address, + const unsigned char node[_Nonnull IPX_NODE_LEN]); + +/** + * @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, + unsigned char node[_Nonnull IPX_NODE_LEN]); + +/** + * @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( + 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); +#if !defined(OF_WII) && !defined(OF_NINTENDO_3DS) +extern int OFGetSockName(OFSocketHandle sock, struct sockaddr *restrict addr, + socklen_t *restrict addrLen); +#endif + +#if defined(OF_HAVE_THREADS) && defined(OF_AMIGAOS) && !defined(OF_MORPHOS) +extern OFTLSKey OFSocketBaseKey; +# ifdef OF_AMIGAOS4 +extern OFTLSKey OFSocketInterfaceKey; +# endif +#endif +#ifdef __cplusplus +} +#endif + +OF_ASSUME_NONNULL_END ADDED src/OFSocket.m Index: src/OFSocket.m ================================================================== --- /dev/null +++ src/OFSocket.m @@ -0,0 +1,928 @@ +/* + * 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" + +#ifndef _XOPEN_SOURCE_EXTENDED +# define _XOPEN_SOURCE_EXTENDED +#endif +#define _HPUX_ALT_XOPEN_SOCKET_API + +#ifdef OF_NINTENDO_3DS +# include /* For memalign() */ +#endif + +#include + +#import "OFArray.h" +#import "OFCharacterSet.h" +#import "OFLocale.h" +#ifdef OF_HAVE_THREADS +# import "OFMutex.h" +#endif +#import "OFOnce.h" +#import "OFSocket.h" +#import "OFSocket+Private.h" +#import "OFString.h" +#ifdef OF_HAVE_THREADS +# import "OFTLSKey.h" +#endif + +#import "OFException.h" /* For some E* -> WSAE* defines */ +#import "OFInitializationFailedException.h" +#import "OFInvalidArgumentException.h" +#import "OFInvalidFormatException.h" +#import "OFLockFailedException.h" +#import "OFOutOfRangeException.h" +#import "OFUnlockFailedException.h" + +#ifdef OF_AMIGAOS +# include +#endif + +#ifdef OF_NINTENDO_3DS +# include <3ds/types.h> +# include <3ds/services/soc.h> +#endif + +#if defined(OF_HAVE_THREADS) && (!defined(OF_AMIGAOS) || defined(OF_MORPHOS)) +static OFMutex *mutex; + +static void +releaseMutex(void) +{ + [mutex release]; +} +#endif +#if !defined(OF_AMIGAOS) || defined(OF_MORPHOS) || !defined(OF_HAVE_THREADS) +static bool initSuccessful = false; +#endif + +#ifdef OF_AMIGAOS +# if defined(OF_HAVE_THREADS) && !defined(OF_MORPHOS) +OFTLSKey OFSocketBaseKey; +# ifdef OF_AMIGAOS4 +OFTLSKey OFSocketInterfaceKey; +# endif +# else +struct Library *SocketBase; +# ifdef OF_AMIGAOS4 +struct SocketIFace *ISocket = NULL; +# endif +# endif +#endif + +#if defined(OF_HAVE_THREADS) && defined(OF_AMIGAOS) && !defined(OF_MORPHOS) +OF_CONSTRUCTOR() +{ + if (OFTLSKeyNew(&OFSocketBaseKey) != 0) + @throw [OFInitializationFailedException exception]; + +# ifdef OF_AMIGAOS4 + if (OFTLSKeyNew(&OFSocketInterfaceKey) != 0) + @throw [OFInitializationFailedException exception]; +# endif +} +#endif + +#if !defined(OF_AMIGAOS) || defined(OF_MORPHOS) || !defined(OF_HAVE_THREADS) +static void +init(void) +{ +# if defined(OF_WINDOWS) + WSADATA wsa; + + if (WSAStartup(MAKEWORD(2, 0), &wsa)) + return; +# elif defined(OF_AMIGAOS) + if ((SocketBase = OpenLibrary("bsdsocket.library", 4)) == NULL) + return; + +# ifdef OF_AMIGAOS4 + if ((ISocket = (struct SocketIFace *) + GetInterface(SocketBase, "main", 1, NULL)) == NULL) { + CloseLibrary(SocketBase); + return; + } +# endif +# elif defined(OF_WII) + if (net_init() < 0) + return; +# elif defined(OF_NINTENDO_3DS) + void *ctx; + + if ((ctx = memalign(0x1000, 0x100000)) == NULL) + return; + + if (socInit(ctx, 0x100000) != 0) + return; + + atexit((void (*)(void))socExit); +# endif + +# if defined(OF_HAVE_THREADS) && (!defined(OF_AMIGAOS) || defined(OF_MORPHOS)) + mutex = [[OFMutex alloc] init]; + atexit(releaseMutex); + +# ifdef OF_WII + if (OFSpinlockNew(&spinlock) != 0) + return; +# endif +# endif + + initSuccessful = true; +} + +OF_DESTRUCTOR() +{ +# ifdef OF_AMIGAOS +# ifdef OF_AMIGAOS4 + if (ISocket != NULL) + DropInterface((struct Interface *)ISocket); +# endif + + if (SocketBase != NULL) + CloseLibrary(SocketBase); +# endif +} +#endif + +bool +OFSocketInit(void) +{ +#if !defined(OF_AMIGAOS) || defined(OF_MORPHOS) || !defined(OF_HAVE_THREADS) + static OFOnceControl onceControl = OFOnceControlInitValue; + OFOnce(&onceControl, init); + + return initSuccessful; +#else + struct Library *socketBase; +# ifdef OF_AMIGAOS4 + struct SocketIFace *socketInterface; +# endif + +# ifdef OF_AMIGAOS4 + if ((socketInterface = OFTLSKeyGet(OFSocketInterfaceKey)) != NULL) +# else + if ((socketBase = OFTLSKeyGet(OFSocketBaseKey)) != NULL) +# endif + return true; + + if ((socketBase = OpenLibrary("bsdsocket.library", 4)) == NULL) + return false; + +# ifdef OF_AMIGAOS4 + if ((socketInterface = (struct SocketIFace *) + GetInterface(socketBase, "main", 1, NULL)) == NULL) { + CloseLibrary(socketBase); + return false; + } +# endif + + if (OFTLSKeySet(OFSocketBaseKey, socketBase) != 0) { + CloseLibrary(socketBase); +# ifdef OF_AMIGAOS4 + DropInterface((struct Interface *)socketInterface); +# endif + return false; + } + +# ifdef OF_AMIGAOS4 + if (OFTLSKeySet(OFSocketInterfaceKey, socketInterface) != 0) { + CloseLibrary(socketBase); + DropInterface((struct Interface *)socketInterface); + return false; + } +# endif + + return true; +#endif +} + +#if defined(OF_HAVE_THREADS) && defined(OF_AMIGAOS) && !defined(OF_MORPHOS) +void +OFSocketDeinit(void) +{ + struct Library *socketBase = OFTLSKeyGet(OFSocketBaseKey); +# ifdef OF_AMIGAOS4 + struct SocketIFace *socketInterface = OFTLSKeyGet(OFSocketInterfaceKey); + + if (socketInterface != NULL) + DropInterface((struct Interface *)socketInterface); +# endif + if (socketBase != NULL) + CloseLibrary(socketBase); +} +#endif + +int +OFSocketErrNo() +{ +#if defined(OF_WINDOWS) + switch (WSAGetLastError()) { + case WSAEACCES: + return EACCES; + case WSAEADDRINUSE: + return EADDRINUSE; + case WSAEADDRNOTAVAIL: + return EADDRNOTAVAIL; + case WSAEAFNOSUPPORT: + return EAFNOSUPPORT; + case WSAEALREADY: + return EALREADY; + case WSAEBADF: + return EBADF; + case WSAECONNABORTED: + return ECONNABORTED; + case WSAECONNREFUSED: + return ECONNREFUSED; + case WSAECONNRESET: + return ECONNRESET; + case WSAEDESTADDRREQ: + return EDESTADDRREQ; + case WSAEDISCON: + return EPIPE; + case WSAEDQUOT: + return EDQUOT; + case WSAEFAULT: + return EFAULT; + case WSAEHOSTDOWN: + return EHOSTDOWN; + case WSAEHOSTUNREACH: + return EHOSTUNREACH; + case WSAEINPROGRESS: + return EINPROGRESS; + case WSAEINTR: + return EINTR; + case WSAEINVAL: + return EINVAL; + case WSAEISCONN: + return EISCONN; + case WSAELOOP: + return ELOOP; + case WSAEMSGSIZE: + return EMSGSIZE; + case WSAENAMETOOLONG: + return ENAMETOOLONG; + case WSAENETDOWN: + return ENETDOWN; + case WSAENETRESET: + return ENETRESET; + case WSAENETUNREACH: + return ENETUNREACH; + case WSAENOBUFS: + return ENOBUFS; + case WSAENOPROTOOPT: + return ENOPROTOOPT; + case WSAENOTCONN: + return ENOTCONN; + case WSAENOTEMPTY: + return ENOTEMPTY; + case WSAENOTSOCK: + return ENOTSOCK; + case WSAEOPNOTSUPP: + return EOPNOTSUPP; + case WSAEPFNOSUPPORT: + return EPFNOSUPPORT; + case WSAEPROCLIM: + return EPROCLIM; + case WSAEPROTONOSUPPORT: + return EPROTONOSUPPORT; + case WSAEPROTOTYPE: + return EPROTOTYPE; + case WSAEREMOTE: + return EREMOTE; + case WSAESHUTDOWN: + return ESHUTDOWN; + case WSAESOCKTNOSUPPORT: + return ESOCKTNOSUPPORT; + case WSAESTALE: + return ESTALE; + case WSAETIMEDOUT: + return ETIMEDOUT; + case WSAETOOMANYREFS: + return ETOOMANYREFS; + case WSAEUSERS: + return EUSERS; + case WSAEWOULDBLOCK: + return EWOULDBLOCK; + } + + return 0; +#elif defined(OF_AMIGAOS) + return Errno(); +#else + return errno; +#endif +} + +#ifndef OF_WII +int +OFGetSockName(OFSocketHandle sock, struct sockaddr *restrict addr, + socklen_t *restrict addrLen) +{ + int ret; + +# if defined(OF_HAVE_THREADS) && (!defined(OF_AMIGAOS) || defined(OF_MORPHOS)) + [mutex lock]; +# endif + ret = getsockname(sock, addr, addrLen); +# if defined(OF_HAVE_THREADS) && (!defined(OF_AMIGAOS) || defined(OF_MORPHOS)) + [mutex unlock]; +# endif + + return ret; +} +#endif + +OFSocketAddress +OFSocketAddressParseIPv4(OFString *IPv4, uint16_t port) +{ + void *pool = objc_autoreleasePoolPush(); + OFCharacterSet *whitespaceCharacterSet = + [OFCharacterSet whitespaceCharacterSet]; + OFSocketAddress ret; + struct sockaddr_in *addrIn = &ret.sockaddr.in; + OFArray OF_GENERIC(OFString *) *components; + uint32_t addr; + + memset(&ret, '\0', sizeof(ret)); + ret.family = OFSocketAddressFamilyIPv4; +#if defined(OF_WII) || defined(OF_NINTENDO_3DS) + ret.length = 8; +#else + ret.length = sizeof(ret.sockaddr.in); +#endif + + addrIn->sin_family = AF_INET; + addrIn->sin_port = OFToBigEndian16(port); +#ifdef OF_WII + addrIn->sin_len = ret.length; +#endif + + components = [IPv4 componentsSeparatedByString: @"."]; + + if (components.count != 4) + @throw [OFInvalidFormatException exception]; + + addr = 0; + + for (OFString *component in components) { + unsigned long long number; + + if (component.length == 0) + @throw [OFInvalidFormatException exception]; + + if ([component indexOfCharacterFromSet: + whitespaceCharacterSet] != OFNotFound) + @throw [OFInvalidFormatException exception]; + + number = component.unsignedLongLongValue; + + if (number > UINT8_MAX) + @throw [OFInvalidFormatException exception]; + + addr = (addr << 8) | ((uint32_t)number & 0xFF); + } + + addrIn->sin_addr.s_addr = OFToBigEndian32(addr); + + objc_autoreleasePoolPop(pool); + + return ret; +} + +static uint16_t +parseIPv6Component(OFString *component) +{ + unsigned long long number; + + if ([component indexOfCharacterFromSet: + [OFCharacterSet whitespaceCharacterSet]] != OFNotFound) + @throw [OFInvalidFormatException exception]; + + number = [component unsignedLongLongValueWithBase: 16]; + + if (number > UINT16_MAX) + @throw [OFInvalidFormatException exception]; + + return (uint16_t)number; +} + +OFSocketAddress +OFSocketAddressParseIPv6(OFString *IPv6, uint16_t port) +{ + void *pool = objc_autoreleasePoolPush(); + OFSocketAddress ret; + struct sockaddr_in6 *addrIn6 = &ret.sockaddr.in6; + size_t doubleColon; + + memset(&ret, '\0', sizeof(ret)); + ret.family = OFSocketAddressFamilyIPv6; + ret.length = sizeof(ret.sockaddr.in6); + +#ifdef AF_INET6 + addrIn6->sin6_family = AF_INET6; +#else + addrIn6->sin6_family = AF_UNSPEC; +#endif + addrIn6->sin6_port = OFToBigEndian16(port); + + 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; + size_t i; + + if ([right hasPrefix: @":"] || [right containsString: @"::"]) + @throw [OFInvalidFormatException exception]; + + leftComponents = [left componentsSeparatedByString: @":"]; + rightComponents = [right componentsSeparatedByString: @":"]; + + if (leftComponents.count + rightComponents.count > 7) + @throw [OFInvalidFormatException exception]; + + i = 0; + for (OFString *component in leftComponents) { + uint16_t number = parseIPv6Component(component); + + addrIn6->sin6_addr.s6_addr[i++] = number >> 8; + addrIn6->sin6_addr.s6_addr[i++] = number; + } + + i = 16; + for (OFString *component in rightComponents.reversedArray) { + uint16_t number = parseIPv6Component(component); + + addrIn6->sin6_addr.s6_addr[--i] = number; + addrIn6->sin6_addr.s6_addr[--i] = number >> 8; + } + } else { + OFArray OF_GENERIC(OFString *) *components = + [IPv6 componentsSeparatedByString: @":"]; + size_t i; + + if (components.count != 8) + @throw [OFInvalidFormatException exception]; + + i = 0; + for (OFString *component in components) { + uint16_t number; + + if (component.length == 0) + @throw [OFInvalidFormatException exception]; + + number = parseIPv6Component(component); + + addrIn6->sin6_addr.s6_addr[i++] = number >> 8; + addrIn6->sin6_addr.s6_addr[i++] = number; + } + } + + objc_autoreleasePoolPop(pool); + + return ret; +} + +OFSocketAddress +OFSocketAddressParseIP(OFString *IP, uint16_t port) +{ + OFSocketAddress ret; + + @try { + ret = OFSocketAddressParseIPv6(IP, port); + } @catch (OFInvalidFormatException *e) { + ret = OFSocketAddressParseIPv4(IP, port); + } + + return ret; +} + +OFSocketAddress +OFSocketAddressMakeIPX(const unsigned char node[IPX_NODE_LEN], uint32_t network, + uint16_t port) +{ + OFSocketAddress ret; + + memset(&ret, '\0', sizeof(ret)); + ret.family = OFSocketAddressFamilyIPX; + ret.length = sizeof(ret.sockaddr.ipx); + +#ifdef AF_IPX + ret.sockaddr.ipx.sipx_family = AF_IPX; +#else + ret.sockaddr.ipx.sipx_family = AF_UNSPEC; +#endif + memcpy(ret.sockaddr.ipx.sipx_node, node, IPX_NODE_LEN); + network = OFToBigEndian32(network); + memcpy(&ret.sockaddr.ipx.sipx_network, &network, + sizeof(ret.sockaddr.ipx.sipx_network)); + ret.sockaddr.ipx.sipx_port = OFToBigEndian16(port); + + return ret; +} + +OFSocketAddress +OFSocketAddressMakeUNIX(OFString *path) +{ + void *pool = objc_autoreleasePoolPush(); + OFStringEncoding encoding = [OFLocale encoding]; + size_t length = [path cStringLengthWithEncoding: encoding]; + OFSocketAddress ret; + + if (length > sizeof(ret.sockaddr.un.sun_path)) + @throw [OFOutOfRangeException exception]; + + memset(&ret, '\0', sizeof(ret)); + ret.family = OFSocketAddressFamilyUNIX; + ret.length = (socklen_t) + (offsetof(struct sockaddr_un, sun_path) + length); + +#ifdef AF_UNIX + ret.sockaddr.un.sun_family = AF_UNIX; +#else + ret.sockaddr.un.sun_family = AF_UNSPEC; +#endif + memcpy(ret.sockaddr.un.sun_path, + [path cStringWithEncoding: encoding], length); + + objc_autoreleasePoolPop(pool); + + 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; + void *pool; + OFString *path1, *path2; + bool ret; + + if (address1->family != address2->family) + return false; + + switch (address1->family) { + case OFSocketAddressFamilyIPv4: +#if defined(OF_WII) || defined(OF_NINTENDO_3DS) + if (address1->length < 8 || address2->length < 8) + @throw [OFInvalidArgumentException exception]; +#else + if (address1->length < (socklen_t)sizeof(struct sockaddr_in) || + address2->length < (socklen_t)sizeof(struct sockaddr_in)) + @throw [OFInvalidArgumentException exception]; +#endif + + addrIn1 = &address1->sockaddr.in; + addrIn2 = &address2->sockaddr.in; + + if (addrIn1->sin_port != addrIn2->sin_port) + return false; + if (addrIn1->sin_addr.s_addr != addrIn2->sin_addr.s_addr) + return false; + + return true; + case OFSocketAddressFamilyIPv6: + if (address1->length < (socklen_t)sizeof(struct sockaddr_in6) || + address2->length < (socklen_t)sizeof(struct sockaddr_in6)) + @throw [OFInvalidArgumentException exception]; + + addrIn6_1 = &address1->sockaddr.in6; + addrIn6_2 = &address2->sockaddr.in6; + + if (addrIn6_1->sin6_port != addrIn6_2->sin6_port) + return false; + if (memcmp(addrIn6_1->sin6_addr.s6_addr, + addrIn6_2->sin6_addr.s6_addr, + sizeof(addrIn6_1->sin6_addr.s6_addr)) != 0) + return false; + + return true; + case OFSocketAddressFamilyIPX: + if (address1->length < (socklen_t)sizeof(struct sockaddr_ipx) || + address2->length < (socklen_t)sizeof(struct sockaddr_ipx)) + @throw [OFInvalidArgumentException exception]; + + addrIPX1 = &address1->sockaddr.ipx; + addrIPX2 = &address2->sockaddr.ipx; + + if (addrIPX1->sipx_port != addrIPX2->sipx_port) + return false; + if (memcmp(&addrIPX1->sipx_network, &addrIPX2->sipx_network, + 4) != 0) + return false; + if (memcmp(addrIPX1->sipx_node, addrIPX2->sipx_node, + IPX_NODE_LEN) != 0) + return false; + + return true; + case OFSocketAddressFamilyUNIX: + pool = objc_autoreleasePoolPush(); + + path1 = OFSocketAddressUNIXPath(address1); + path2 = OFSocketAddressUNIXPath(address2); + + if (path1 == nil || path2 == nil) { + objc_autoreleasePoolPop(pool); + + return false; + } + + ret = [path1 isEqual: path2]; + + objc_autoreleasePoolPop(pool); + + return ret; + default: + @throw [OFInvalidArgumentException exception]; + } +} + +unsigned long +OFSocketAddressHash(const OFSocketAddress *address) +{ + unsigned long hash; + + OFHashInit(&hash); + OFHashAdd(&hash, address->family); + + switch (address->family) { + case OFSocketAddressFamilyIPv4: +#if defined(OF_WII) || defined(OF_NINTENDO_3DS) + if (address->length < 8) + @throw [OFInvalidArgumentException exception]; +#else + if (address->length < (socklen_t)sizeof(struct sockaddr_in)) + @throw [OFInvalidArgumentException exception]; +#endif + + OFHashAdd(&hash, address->sockaddr.in.sin_port >> 8); + OFHashAdd(&hash, address->sockaddr.in.sin_port); + OFHashAdd(&hash, address->sockaddr.in.sin_addr.s_addr >> 24); + OFHashAdd(&hash, address->sockaddr.in.sin_addr.s_addr >> 16); + OFHashAdd(&hash, address->sockaddr.in.sin_addr.s_addr >> 8); + OFHashAdd(&hash, address->sockaddr.in.sin_addr.s_addr); + + break; + case OFSocketAddressFamilyIPv6: + if (address->length < (socklen_t)sizeof(struct sockaddr_in6)) + @throw [OFInvalidArgumentException exception]; + + OFHashAdd(&hash, address->sockaddr.in6.sin6_port >> 8); + OFHashAdd(&hash, address->sockaddr.in6.sin6_port); + + for (size_t i = 0; + i < sizeof(address->sockaddr.in6.sin6_addr.s6_addr); i++) + OFHashAdd(&hash, + address->sockaddr.in6.sin6_addr.s6_addr[i]); + + break; + case OFSocketAddressFamilyIPX:; + unsigned char network[ + sizeof(address->sockaddr.ipx.sipx_network)]; + + if (address->length < (socklen_t)sizeof(struct sockaddr_ipx)) + @throw [OFInvalidArgumentException exception]; + + OFHashAdd(&hash, address->sockaddr.ipx.sipx_port >> 8); + OFHashAdd(&hash, address->sockaddr.ipx.sipx_port); + + memcpy(network, &address->sockaddr.ipx.sipx_network, + sizeof(network)); + + for (size_t i = 0; i < sizeof(network); i++) + OFHashAdd(&hash, network[i]); + + for (size_t i = 0; i < IPX_NODE_LEN; i++) + OFHashAdd(&hash, address->sockaddr.ipx.sipx_node[i]); + + break; + case OFSocketAddressFamilyUNIX:; + void *pool = objc_autoreleasePoolPush(); + OFString *path = OFSocketAddressUNIXPath(address); + + hash = path.hash; + + objc_autoreleasePoolPop(pool); + + return hash; + default: + @throw [OFInvalidArgumentException exception]; + } + + OFHashFinalize(&hash); + + return hash; +} + +static OFString * +IPv4String(const OFSocketAddress *address) +{ + const struct sockaddr_in *addrIn = &address->sockaddr.in; + uint32_t addr = OFFromBigEndian32(addrIn->sin_addr.s_addr); + OFString *string; + + string = [OFString stringWithFormat: @"%u.%u.%u.%u", + (addr & 0xFF000000) >> 24, (addr & 0x00FF0000) >> 16, + (addr & 0x0000FF00) >> 8, addr & 0x000000FF]; + + return string; +} + +static OFString * +IPv6String(const OFSocketAddress *address) +{ + OFMutableString *string = [OFMutableString string]; + const struct sockaddr_in6 *addrIn6 = &address->sockaddr.in6; + int_fast8_t zerosStart = -1, maxZerosStart = -1; + uint_fast8_t zerosCount = 0, maxZerosCount = 0; + bool first = true; + + for (uint_fast8_t i = 0; i < 16; i += 2) { + if (addrIn6->sin6_addr.s6_addr[i] == 0 && + addrIn6->sin6_addr.s6_addr[i + 1] == 0) { + if (zerosStart >= 0) + zerosCount++; + else { + zerosStart = i; + zerosCount = 1; + } + } else { + if (zerosCount > maxZerosCount) { + maxZerosStart = zerosStart; + maxZerosCount = zerosCount; + } + + zerosStart = -1; + } + } + if (zerosCount > maxZerosCount) { + maxZerosStart = zerosStart; + maxZerosCount = zerosCount; + } + + if (maxZerosCount >= 2) { + for (int_fast8_t i = 0; i < maxZerosStart; i += 2) { + [string appendFormat: + (first ? @"%x" : @":%x"), + (addrIn6->sin6_addr.s6_addr[(uint_fast8_t)i] << 8) | + addrIn6->sin6_addr.s6_addr[(uint_fast8_t)i + 1]]; + first = false; + } + + [string appendString: @"::"]; + first = true; + + for (int_fast8_t i = maxZerosStart + (maxZerosCount * 2); + i < 16; i += 2) { + [string appendFormat: + (first ? @"%x" : @":%x"), + (addrIn6->sin6_addr.s6_addr[(uint_fast8_t)i] << 8) | + addrIn6->sin6_addr.s6_addr[(uint_fast8_t)i + 1]]; + first = false; + } + } else { + for (uint_fast8_t i = 0; i < 16; i += 2) { + [string appendFormat: + (first ? @"%x" : @":%x"), + (addrIn6->sin6_addr.s6_addr[i] << 8) | + addrIn6->sin6_addr.s6_addr[i + 1]]; + first = false; + } + } + + [string makeImmutable]; + + return string; +} + +OFString * +OFSocketAddressString(const OFSocketAddress *address) +{ + switch (address->family) { + case OFSocketAddressFamilyIPv4: + return IPv4String(address); + case OFSocketAddressFamilyIPv6: + return IPv6String(address); + default: + @throw [OFInvalidArgumentException exception]; + } +} + +void +OFSocketAddressSetPort(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) +{ + 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]; + } +} + +void +OFSocketAddressSetIPXNetwork(OFSocketAddress *address, uint32_t network) +{ + if (address->family != OFSocketAddressFamilyIPX) + @throw [OFInvalidArgumentException exception]; + + network = OFToBigEndian32(network); + memcpy(&address->sockaddr.ipx.sipx_network, &network, + sizeof(address->sockaddr.ipx.sipx_network)); +} + +uint32_t +OFSocketAddressIPXNetwork(const OFSocketAddress *address) +{ + uint32_t network; + + if (address->family != OFSocketAddressFamilyIPX) + @throw [OFInvalidArgumentException exception]; + + memcpy(&network, &address->sockaddr.ipx.sipx_network, sizeof(network)); + + return OFFromBigEndian32(network); +} + +void +OFSocketAddressSetIPXNode(OFSocketAddress *address, + const unsigned char node[IPX_NODE_LEN]) +{ + if (address->family != OFSocketAddressFamilyIPX) + @throw [OFInvalidArgumentException exception]; + + memcpy(address->sockaddr.ipx.sipx_node, node, IPX_NODE_LEN); +} + +void +OFSocketAddressIPXNode(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); +} + +OFString * +OFSocketAddressUNIXPath(const OFSocketAddress *_Nonnull address) +{ + socklen_t length; + + if (address->family != OFSocketAddressFamilyUNIX) + @throw [OFInvalidArgumentException exception]; + + length = address->length - offsetof(struct sockaddr_un, sun_path); + + 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]; +} Index: src/OFSortedList.h ================================================================== --- src/OFSortedList.h +++ src/OFSortedList.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -33,27 +31,25 @@ #endif { OF_RESERVE_IVARS(OFSortedList, 4) } -- (of_list_object_t *)appendObject: (ObjectType)object OF_UNAVAILABLE; -- (of_list_object_t *)prependObject: (ObjectType)object OF_UNAVAILABLE; -- (of_list_object_t *)insertObject: (ObjectType)object - beforeListObject: (of_list_object_t *)listObject - OF_UNAVAILABLE; -- (of_list_object_t *)insertObject: (ObjectType)object - afterListObject: (of_list_object_t *)listObject - OF_UNAVAILABLE; +- (OFListItem)appendObject: (ObjectType)object OF_UNAVAILABLE; +- (OFListItem)prependObject: (ObjectType)object OF_UNAVAILABLE; +- (OFListItem)insertObject: (ObjectType)object + beforeListItem: (OFListItem)listItem OF_UNAVAILABLE; +- (OFListItem)insertObject: (ObjectType)object + afterListItem: (OFListItem)listItem OF_UNAVAILABLE; /** * @brief Inserts the object to the list while keeping the list sorted. * * @param object The object to insert * @return The list object for the object just added */ -- (of_list_object_t *)insertObject: (ObjectType )object; +- (OFListItem)insertObject: (ObjectType )object; #if !defined(OF_HAVE_GENERICS) && !defined(DOXYGEN) # undef ObjectType #endif @end OF_ASSUME_NONNULL_END Index: src/OFSortedList.m ================================================================== --- src/OFSortedList.m +++ src/OFSortedList.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -18,40 +16,39 @@ #include "config.h" #import "OFSortedList.h" @implementation OFSortedList -- (of_list_object_t *)appendObject: (id)object -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (of_list_object_t *)prependObject: (id)object -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (of_list_object_t *)insertObject: (id)object - beforeListObject: (of_list_object_t *)listObject -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (of_list_object_t *)insertObject: (id)object - afterListObject: (of_list_object_t *)listObject -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (of_list_object_t *)insertObject: (id )object -{ - of_list_object_t *iter; - - for (iter = _lastListObject; iter != NULL; iter = iter->previous) { - if ([object compare: iter->object] != OF_ORDERED_ASCENDING) - return [super insertObject: object - afterListObject: iter]; +- (OFListItem)appendObject: (id)object +{ + OF_UNRECOGNIZED_SELECTOR +} + +- (OFListItem)prependObject: (id)object +{ + OF_UNRECOGNIZED_SELECTOR +} + +- (OFListItem)insertObject: (id)object beforeListItem: (OFListItem)listItem +{ + OF_UNRECOGNIZED_SELECTOR +} + +- (OFListItem)insertObject: (id)object afterListItem: (OFListItem)listItem +{ + OF_UNRECOGNIZED_SELECTOR +} + +- (OFListItem)insertObject: (id )object +{ + OFListItem iter; + + for (iter = _lastListItem; iter != NULL; + iter = OFListItemPrevious(iter)) { + if ([object compare: OFListItemObject(iter)] != + OFOrderedAscending) + return [super insertObject: object afterListItem: iter]; } return [super prependObject: object]; } @end Index: src/OFStdIOStream+Private.h ================================================================== --- src/OFStdIOStream+Private.h +++ src/OFStdIOStream+Private.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFStdIOStream.h ================================================================== --- src/OFStdIOStream.h +++ src/OFStdIOStream.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -31,11 +29,11 @@ /** * @class OFStdIOStream OFStdIOStream.h ObjFW/OFStdIOStream.h * * @brief A class for providing standard input, output and error as OFStream. * - * The global variables @ref of_stdin, @ref of_stdout and @ref of_stderr are + * The global variables @ref OFStdIn, @ref OFStdOut and @ref OFStdErr are * instances of this class and need no initialization. */ #ifdef OF_STDIO_STREAM_WIN32_CONSOLE_H OF_SUBCLASSING_RESTRICTED #endif @@ -118,19 +116,19 @@ * @brief Moves the cursor to the specified absolute position. Does nothing if * there is no underlying terminal. * * @param position The position to move the cursor to */ -- (void)setCursorPosition: (of_point_t)position; +- (void)setCursorPosition: (OFPoint)position; /** * @brief Moves the cursor to the specified relative position. Does nothing if * there is no underlying terminal. * * @param position The position to move the cursor to */ -- (void)setRelativeCursorPosition: (of_point_t)position; +- (void)setRelativeCursorPosition: (OFPoint)position; @end #ifdef __cplusplus extern "C" { #endif @@ -137,29 +135,40 @@ /** @file */ /** * @brief The standard input as an OFStream. */ -extern OFStdIOStream *_Nullable of_stdin; +extern OFStdIOStream *_Nullable OFStdIn; /** * @brief The standard output as an OFStream. */ -extern OFStdIOStream *_Nullable of_stdout; +extern OFStdIOStream *_Nullable OFStdOut; /** * @brief The standard error as an OFStream. */ -extern OFStdIOStream *_Nullable of_stderr; +extern OFStdIOStream *_Nullable OFStdErr; + +/** + * @brief Logs the specified printf-style format to @ref OFStdErr. + * + * This prefixes the output with the date, timestamp, process name and PID. + * + * @param format The format for the line to log. See @ref OFStream#writeFormat:. + */ +extern void OFLog(OFConstantString *format, ...); /** - * @brief Log the specified printf-style format to @ref of_stderr. + * @brief Logs the specified printf-style format to @ref OFStdErr. + * + * This prefixes the output with the date, timestamp, process name and PID. * - * This prefixes the output with the date, timestamp, process name and PID and - * allows `%@` as a printf-style formatted to print objects. + * @param format The format for the line to log. See @ref OFStream#writeFormat:. + * @param arguments The arguments for the format */ -extern void of_log(OFConstantString *format, ...); +extern void OFLogV(OFConstantString *format, va_list arguments); #ifdef __cplusplus } #endif OF_ASSUME_NONNULL_END Index: src/OFStdIOStream.m ================================================================== --- src/OFStdIOStream.m +++ src/OFStdIOStream.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -61,46 +59,53 @@ { [OFWin32ConsoleStdIOStream class]; } #endif -OFStdIOStream *of_stdin = nil; -OFStdIOStream *of_stdout = nil; -OFStdIOStream *of_stderr = nil; +OFStdIOStream *OFStdIn = nil; +OFStdIOStream *OFStdOut = nil; +OFStdIOStream *OFStdErr = nil; #ifdef OF_AMIGAOS OF_DESTRUCTOR() { - [of_stdin dealloc]; - [of_stdout dealloc]; - [of_stderr dealloc]; + [OFStdIn dealloc]; + [OFStdOut dealloc]; + [OFStdErr dealloc]; } #endif + +void +OFLog(OFConstantString *format, ...) +{ + va_list arguments; + + va_start(arguments, format); + OFLogV(format, arguments); + va_end(arguments); +} void -of_log(OFConstantString *format, ...) +OFLogV(OFConstantString *format, va_list arguments) { void *pool = objc_autoreleasePoolPush(); OFDate *date; OFString *dateString, *me, *msg; - va_list arguments; date = [OFDate date]; dateString = [date localDateStringWithFormat: @"%Y-%m-%d %H:%M:%S"]; #ifdef OF_HAVE_FILES me = [OFApplication programName].lastPathComponent; #else me = [OFApplication programName]; #endif - va_start(arguments, format); msg = [[[OFString alloc] initWithFormat: format arguments: arguments] autorelease]; - va_end(arguments); - [of_stderr writeFormat: @"[%@.%03d %@(%d)] %@\n", dateString, - date.microsecond / 1000, me, getpid(), msg]; + [OFStdErr writeFormat: @"[%@.%03d %@(%d)] %@\n", dateString, + date.microsecond / 1000, me, getpid(), msg]; objc_autoreleasePoolPop(pool); } #ifdef HAVE_ISATTY @@ -153,17 +158,16 @@ # ifndef OF_AMIGAOS int fd; if ((fd = fileno(stdin)) >= 0) - of_stdin = [[OFStdIOStream alloc] - of_initWithFileDescriptor: fd]; + OFStdIn = [[OFStdIOStream alloc] of_initWithFileDescriptor: fd]; if ((fd = fileno(stdout)) >= 0) - of_stdout = [[OFStdIOStream alloc] + OFStdOut = [[OFStdIOStream alloc] of_initWithFileDescriptor: fd]; if ((fd = fileno(stderr)) >= 0) - of_stderr = [[OFStdIOStream alloc] + OFStdErr = [[OFStdIOStream alloc] of_initWithFileDescriptor: fd]; # else BPTR input, output, error; bool inputClosable = false, outputClosable = false, errorClosable = false; @@ -185,16 +189,16 @@ if (error == 0) { error = Open("*", MODE_OLDFILE); errorClosable = true; } - of_stdin = [[OFStdIOStream alloc] of_initWithHandle: input - closable: inputClosable]; - of_stdout = [[OFStdIOStream alloc] of_initWithHandle: output - closable: outputClosable]; - of_stderr = [[OFStdIOStream alloc] of_initWithHandle: error - closable: errorClosable]; + OFStdIn = [[OFStdIOStream alloc] of_initWithHandle: input + closable: inputClosable]; + OFStdOut = [[OFStdIOStream alloc] of_initWithHandle: output + closable: outputClosable]; + OFStdErr = [[OFStdIOStream alloc] of_initWithHandle: error + closable: errorClosable]; # endif } #endif - (instancetype)init @@ -210,12 +214,11 @@ _fd = fd; return self; } #else -- (instancetype)of_initWithHandle: (BPTR)handle - closable: (bool)closable +- (instancetype)of_initWithHandle: (BPTR)handle closable: (bool)closable { self = [super init]; _handle = handle; _closable = closable; @@ -246,12 +249,11 @@ @throw [OFNotOpenException exceptionWithObject: self]; return _atEndOfStream; } -- (size_t)lowlevelReadIntoBuffer: (void *)buffer - length: (size_t)length +- (size_t)lowlevelReadIntoBuffer: (void *)buffer length: (size_t)length { ssize_t ret; #ifndef OF_AMIGAOS if (_fd == -1) @@ -288,12 +290,11 @@ _atEndOfStream = true; return ret; } -- (size_t)lowlevelWriteBuffer: (const void *)buffer - length: (size_t)length +- (size_t)lowlevelWriteBuffer: (const void *)buffer length: (size_t)length { #ifndef OF_AMIGAOS if (_fd == -1) @throw [OFNotOpenException exceptionWithObject: self]; @@ -386,11 +387,11 @@ { } - (unsigned int)retainCount { - return OF_RETAIN_COUNT_MAX; + return OFMaxRetainCount; } - (bool)hasTerminal { #ifdef HAVE_ISATTY @@ -496,11 +497,11 @@ [self writeFormat: @"\033[%uG", column + 1]; #endif } -- (void)setCursorPosition: (of_point_t)position +- (void)setCursorPosition: (OFPoint)position { if (position.x < 0 || position.y < 0) @throw [OFInvalidArgumentException exception]; #ifdef HAVE_ISATTY @@ -510,11 +511,11 @@ [self writeFormat: @"\033[%u;%uH", (unsigned)position.y + 1, (unsigned)position.x + 1]; #endif } -- (void)setRelativeCursorPosition: (of_point_t)position +- (void)setRelativeCursorPosition: (OFPoint)position { #ifdef HAVE_ISATTY if (!isatty(_fd)) return; ADDED src/OFStrPTime.h Index: src/OFStrPTime.h ================================================================== --- /dev/null +++ src/OFStrPTime.h @@ -0,0 +1,38 @@ +/* + * 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. + */ + +#ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS +#endif +#ifndef __STDC_CONSTANT_MACROS +# define __STDC_CONSTANT_MACROS +#endif + +#include + +#import "macros.h" + +OF_ASSUME_NONNULL_BEGIN + +#ifdef __cplusplus +extern "C" { +#endif +extern const char *_Nullable OFStrPTime(const char *buffer, const char *format, + struct tm *tm, short *_Nullable tz); +#ifdef __cplusplus +} +#endif + +OF_ASSUME_NONNULL_END ADDED src/OFStrPTime.m Index: src/OFStrPTime.m ================================================================== --- /dev/null +++ src/OFStrPTime.m @@ -0,0 +1,230 @@ +/* + * 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 "macros.h" + +const char * +OFStrPTime(const char *buffer, const char *format, struct tm *tm, short *tz) +{ + enum { + stateSearchConversionSpecifier, + stateInConversionSpecifier + } state = stateSearchConversionSpecifier; + size_t j, bufferLen, formatLen; + + bufferLen = strlen(buffer); + formatLen = strlen(format); + + j = 0; + for (size_t i = 0; i < formatLen; i++) { + if (j >= bufferLen) + return NULL; + + switch (state) { + case stateSearchConversionSpecifier: + if (format[i] == '%') + state = stateInConversionSpecifier; + else if (format[i] != buffer[j++]) + return NULL; + + break; + case stateInConversionSpecifier:; + int k, maxLen, number = 0; + + switch (format[i]) { + case 'd': + case 'e': + case 'H': + case 'm': + case 'M': + case 'S': + case 'y': + maxLen = 2; + break; + case 'Y': + maxLen = 4; + break; + case '%': + case 'a': + case 'b': + case 'n': + case 't': + case 'z': + maxLen = 0; + break; + default: + return NULL; + } + + if (maxLen > 0 && (buffer[j] < '0' || buffer[j] > '9')) + return NULL; + + for (k = 0; k < maxLen && j < bufferLen && + buffer[j] >= '0' && buffer[j] <= '9'; k++, j++) { + number *= 10; + number += buffer[j] - '0'; + } + + switch (format[i]) { + case 'a': + if (bufferLen < j + 3) + return NULL; + + if (memcmp(buffer + j, "Sun", 3) == 0) + tm->tm_wday = 0; + else if (memcmp(buffer + j, "Mon", 3) == 0) + tm->tm_wday = 1; + else if (memcmp(buffer + j, "Tue", 3) == 0) + tm->tm_wday = 2; + else if (memcmp(buffer + j, "Wed", 3) == 0) + tm->tm_wday = 3; + else if (memcmp(buffer + j, "Thu", 3) == 0) + tm->tm_wday = 4; + else if (memcmp(buffer + j, "Fri", 3) == 0) + tm->tm_wday = 5; + else if (memcmp(buffer + j, "Sat", 3) == 0) + tm->tm_wday = 6; + else + return NULL; + + j += 3; + break; + case 'b': + if (bufferLen < j + 3) + return NULL; + + if (memcmp(buffer + j, "Jan", 3) == 0) + tm->tm_mon = 0; + else if (memcmp(buffer + j, "Feb", 3) == 0) + tm->tm_mon = 1; + else if (memcmp(buffer + j, "Mar", 3) == 0) + tm->tm_mon = 2; + else if (memcmp(buffer + j, "Apr", 3) == 0) + tm->tm_mon = 3; + else if (memcmp(buffer + j, "May", 3) == 0) + tm->tm_mon = 4; + else if (memcmp(buffer + j, "Jun", 3) == 0) + tm->tm_mon = 5; + else if (memcmp(buffer + j, "Jul", 3) == 0) + tm->tm_mon = 6; + else if (memcmp(buffer + j, "Aug", 3) == 0) + tm->tm_mon = 7; + else if (memcmp(buffer + j, "Sep", 3) == 0) + tm->tm_mon = 8; + else if (memcmp(buffer + j, "Oct", 3) == 0) + tm->tm_mon = 9; + else if (memcmp(buffer + j, "Nov", 3) == 0) + tm->tm_mon = 10; + else if (memcmp(buffer + j, "Dec", 3) == 0) + tm->tm_mon = 11; + else + return NULL; + + j += 3; + break; + case 'd': + case 'e': + tm->tm_mday = number; + break; + case 'H': + tm->tm_hour = number; + break; + case 'm': + tm->tm_mon = number - 1; + break; + case 'M': + tm->tm_min = number; + break; + case 'S': + tm->tm_sec = number; + break; + case 'y': + if (number <= 68) + number += 100; + + tm->tm_year = number; + break; + case 'Y': + if (number < 1900) + return NULL; + + tm->tm_year = number - 1900; + break; + case 'z': + if (buffer[j] == '-' || buffer[j] == '+') { + const char *b = buffer + j; + + if (bufferLen < j + 5) + return NULL; + + if (tz == NULL) + break; + + *tz = (((short)b[1] - '0') * 600 + + ((short)b[2] - '0') * 60 + + ((short)b[3] - '0') * 10 + + ((short)b[4] - '0')) * + (b[0] == '-' ? -1 : 1); + + j += 5; + } else if (buffer[j] == 'Z') { + if (tz != NULL) + *tz = 0; + + j++; + } else if (buffer[j] == 'G') { + if (bufferLen < j + 3) + return NULL; + + if (buffer[j + 1] != 'M' || + buffer[j + 2] != 'T') + return NULL; + + if (tz != NULL) + *tz = 0; + + j += 3; + } else + return NULL; + + break; + case '%': + if (buffer[j++] != '%') + return NULL; + break; + case 'n': + if (buffer[j++] != '\n') + return NULL; + break; + case 't': + if (buffer[j++] != '\t') + return NULL; + break; + } + + state = stateSearchConversionSpecifier; + + break; + } + } + + return buffer + j; +} Index: src/OFStream+Private.h ================================================================== --- src/OFStream+Private.h +++ src/OFStream+Private.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFStream.h ================================================================== --- src/OFStream.h +++ src/OFStream.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -46,12 +44,11 @@ * @param length The length of the data that has been read * @param exception An exception which occurred while reading or `nil` on * success * @return A bool whether the same block should be used for the next read */ -typedef bool (^of_stream_async_read_block_t)(size_t length, - id _Nullable exception); +typedef bool (^OFStreamAsyncReadBlock)(size_t length, id _Nullable exception); /** * @brief A block which is called when a line was read asynchronously from a * stream. * @@ -59,42 +56,40 @@ * occurred * @param exception An exception which occurred while reading or `nil` on * success * @return A bool whether the same block should be used for the next read */ -typedef bool (^of_stream_async_read_line_block_t)(OFString *_Nullable line, +typedef bool (^OFStreamAsyncReadLineBlock)(OFString *_Nullable line, id _Nullable exception); /** * @brief A block which is called when data was written asynchronously to a * stream. * - * @param data The data which was written to the stream * @param bytesWritten The number of bytes which have been written. This * matches the length of the specified data on the * asynchronous write if no exception was encountered. * @param exception An exception which occurred while writing or `nil` on * success * @return The data to repeat the write with or nil if it should not repeat */ -typedef OFData *_Nullable (^of_stream_async_write_data_block_t)( - OFData *_Nonnull data, size_t bytesWritten, id _Nullable exception); +typedef OFData *_Nullable (^OFStreamAsyncWriteDataBlock)(size_t bytesWritten, + id _Nullable exception); /** * @brief A block which is called when a string was written asynchronously to a * stream. * - * @param string The string which was written to the stream * @param bytesWritten The number of bytes which have been written. This * matches the length of the specified data on the * asynchronous write if no exception was encountered. * @param exception An exception which occurred while writing or `nil` on * success * @return The string to repeat the write with or nil if it should not repeat */ -typedef OFString *_Nullable (^of_stream_async_write_string_block_t)( - OFString *_Nonnull string, size_t bytesWritten, id _Nullable exception); +typedef OFString *_Nullable (^OFStreamAsyncWriteStringBlock)( + size_t bytesWritten, id _Nullable exception); #endif /** * @protocol OFStreamDelegate OFStream.h ObjFW/OFStream.h * @@ -161,11 +156,11 @@ * @param exception An exception that occurred while writing, or nil on success * @return The string to repeat the write with or nil if it should not repeat */ - (nullable OFString *)stream: (OFStream *)stream didWriteString: (OFString *)string - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding bytesWritten: (size_t)bytesWritten exception: (nullable id)exception; @end /** @@ -208,11 +203,11 @@ @property (readonly, nonatomic, getter=isAtEndOfStream) bool atEndOfStream; /** * @brief Whether writes are buffered. */ -@property (nonatomic, nonatomic) bool buffersWrites; +@property (nonatomic) bool buffersWrites; /** * @brief Whether data is present in the internal read buffer. */ @property (readonly, nonatomic) bool hasDataInReadBuffer; @@ -248,12 +243,11 @@ * @param buffer The buffer into which the data is read * @param length The length of the data that should be read at most. * The buffer *must* be *at least* this big! * @return The number of bytes read */ -- (size_t)readIntoBuffer: (void *)buffer - length: (size_t)length; +- (size_t)readIntoBuffer: (void *)buffer length: (size_t)length; /** * @brief Reads exactly the specified length bytes from the stream into a * buffer. * @@ -266,12 +260,11 @@ * * @param buffer The buffer into which the data is read * @param length The length of the data that should be read. * The buffer *must* be *at least* this big! */ - - (void)readIntoBuffer: (void *)buffer - exactLength: (size_t)length; + - (void)readIntoBuffer: (void *)buffer exactLength: (size_t)length; #ifdef OF_HAVE_SOCKETS /** * @brief Asynchronously reads *at most* size bytes from the stream into a * buffer. @@ -290,12 +283,11 @@ * @param buffer The buffer into which the data is read. * The buffer must not be freed before the async read completed! * @param length The length of the data that should be read at most. * The buffer *must* be *at least* this big! */ -- (void)asyncReadIntoBuffer: (void *)buffer - length: (size_t)length; +- (void)asyncReadIntoBuffer: (void *)buffer length: (size_t)length; /** * @brief Asynchronously reads *at most* size bytes from the stream into a * buffer. * @@ -316,11 +308,11 @@ * The buffer *must* be *at least* this big! * @param runLoopMode The run loop mode in which to perform the async read */ - (void)asyncReadIntoBuffer: (void *)buffer length: (size_t)length - runLoopMode: (of_run_loop_mode_t)runLoopMode; + runLoopMode: (OFRunLoopMode)runLoopMode; /** * @brief Asynchronously reads exactly the specified length bytes from the * stream into a buffer. * @@ -334,12 +326,11 @@ * * @param buffer The buffer into which the data is read * @param length The length of the data that should be read. * The buffer *must* be *at least* this big! */ -- (void)asyncReadIntoBuffer: (void *)buffer - exactLength: (size_t)length; +- (void)asyncReadIntoBuffer: (void *)buffer exactLength: (size_t)length; /** * @brief Asynchronously reads exactly the specified length bytes from the * stream into a buffer. * @@ -356,11 +347,11 @@ * The buffer *must* be *at least* this big! * @param runLoopMode The run loop mode in which to perform the async read */ - (void)asyncReadIntoBuffer: (void *)buffer exactLength: (size_t)length - runLoopMode: (of_run_loop_mode_t)runLoopMode; + runLoopMode: (OFRunLoopMode)runLoopMode; # ifdef OF_HAVE_BLOCKS /** * @brief Asynchronously reads *at most* ref size bytes from the stream into a * buffer. @@ -386,11 +377,11 @@ * you want the next block in the queue to handle the data * received next, you need to return false from the block. */ - (void)asyncReadIntoBuffer: (void *)buffer length: (size_t)length - block: (of_stream_async_read_block_t)block; + block: (OFStreamAsyncReadBlock)block; /** * @brief Asynchronously reads *at most* ref size bytes from the stream into a * buffer. * @@ -416,12 +407,12 @@ * you want the next block in the queue to handle the data * received next, you need to return false from the block. */ - (void)asyncReadIntoBuffer: (void *)buffer length: (size_t)length - runLoopMode: (of_run_loop_mode_t)runLoopMode - block: (of_stream_async_read_block_t)block; + runLoopMode: (OFRunLoopMode)runLoopMode + block: (OFStreamAsyncReadBlock)block; /** * @brief Asynchronously reads exactly the specified length bytes from the * stream into a buffer. * @@ -442,11 +433,11 @@ * you want the next block in the queue to handle the data * received next, you need to return false from the block. */ - (void)asyncReadIntoBuffer: (void *)buffer exactLength: (size_t)length - block: (of_stream_async_read_block_t)block; + block: (OFStreamAsyncReadBlock)block; /** * @brief Asynchronously reads exactly the specified length bytes from the * stream into a buffer. * @@ -468,12 +459,12 @@ * you want the next block in the queue to handle the data * received next, you need to return false from the block. */ - (void)asyncReadIntoBuffer: (void *)buffer exactLength: (size_t)length - runLoopMode: (of_run_loop_mode_t)runLoopMode - block: (of_stream_async_read_block_t)block; + runLoopMode: (OFRunLoopMode)runLoopMode + block: (OFStreamAsyncReadBlock)block; # endif #endif /** * @brief Reads a uint8_t from the stream. @@ -533,85 +524,10 @@ * * @return A double from the stream in the native endianess */ - (double)readBigEndianDouble; -/** - * @brief Reads the specified number of uint16_ts from the stream which are - * encoded in big endian. - * - * @warning Only call this when you know that enough data is available! - * Otherwise you will get an exception! - * - * @param buffer A buffer of sufficient size to store the specified number of - * uint16_ts - * @param count The number of uint16_ts to read - * @return The number of bytes read - */ -- (size_t)readBigEndianInt16sIntoBuffer: (uint16_t *)buffer - count: (size_t)count; - -/** - * @brief Reads the specified number of uint32_ts from the stream which are - * encoded in big endian. - * - * @warning Only call this when you know that enough data is available! - * Otherwise you will get an exception! - * - * @param buffer A buffer of sufficient size to store the specified number of - * uint32_ts - * @param count The number of uint32_ts to read - * @return The number of bytes read - */ -- (size_t)readBigEndianInt32sIntoBuffer: (uint32_t *)buffer - count: (size_t)count; - -/** - * @brief Reads the specified number of uint64_ts from the stream which are - * encoded in big endian. - * - * @warning Only call this when you know that enough data is available! - * Otherwise you will get an exception! - * - * @param buffer A buffer of sufficient size to store the specified number of - * uint64_ts - * @param count The number of uint64_ts to read - * @return The number of bytes read - */ -- (size_t)readBigEndianInt64sIntoBuffer: (uint64_t *)buffer - count: (size_t)count; - -/** - * @brief Reads the specified number of floats from the stream which are encoded - * in big endian. - * - * @warning Only call this when you know that enough data is available! - * Otherwise you will get an exception! - * - * @param buffer A buffer of sufficient size to store the specified number of - * floats - * @param count The number of floats to read - * @return The number of bytes read - */ -- (size_t)readBigEndianFloatsIntoBuffer: (float *)buffer - count: (size_t)count; - -/** - * @brief Reads the specified number of doubles from the stream which are - * encoded in big endian. - * - * @warning Only call this when you know that enough data is available! - * Otherwise you will get an exception! - * - * @param buffer A buffer of sufficient size to store the specified number of - * doubles - * @param count The number of doubles to read - * @return The number of bytes read - */ -- (size_t)readBigEndianDoublesIntoBuffer: (double *)buffer - count: (size_t)count; - /** * @brief Reads a uint16_t from the stream which is encoded in little endian. * * @warning Only call this when you know that enough data is available! * Otherwise you will get an exception! @@ -658,85 +574,10 @@ * * @return A double from the stream in the native endianess */ - (double)readLittleEndianDouble; -/** - * @brief Reads the specified number of uint16_ts from the stream which are - * encoded in little endian. - * - * @warning Only call this when you know that enough data is available! - * Otherwise you will get an exception! - * - * @param buffer A buffer of sufficient size to store the specified number of - * uint16_ts - * @param count The number of uint16_ts to read - * @return The number of bytes read - */ -- (size_t)readLittleEndianInt16sIntoBuffer: (uint16_t *)buffer - count: (size_t)count; - -/** - * @brief Reads the specified number of uint32_ts from the stream which are - * encoded in little endian. - * - * @warning Only call this when you know that enough data is available! - * Otherwise you will get an exception! - * - * @param buffer A buffer of sufficient size to store the specified number of - * uint32_ts - * @param count The number of uint32_ts to read - * @return The number of bytes read - */ -- (size_t)readLittleEndianInt32sIntoBuffer: (uint32_t *)buffer - count: (size_t)count; - -/** - * @brief Reads the specified number of uint64_ts from the stream which are - * encoded in little endian. - * - * @warning Only call this when you know that enough data is available! - * Otherwise you will get an exception! - * - * @param buffer A buffer of sufficient size to store the specified number of - * uint64_ts - * @param count The number of uint64_ts to read - * @return The number of bytes read - */ -- (size_t)readLittleEndianInt64sIntoBuffer: (uint64_t *)buffer - count: (size_t)count; - -/** - * @brief Reads the specified number of floats from the stream which are - * encoded in little endian. - * - * @warning Only call this when you know that enough data is available! - * Otherwise you will get an exception! - * - * @param buffer A buffer of sufficient size to store the specified number of - * floats - * @param count The number of floats to read - * @return The number of bytes read - */ -- (size_t)readLittleEndianFloatsIntoBuffer: (float *)buffer - count: (size_t)count; - -/** - * @brief Reads the specified number of doubles from the stream which are - * encoded in little endian. - * - * @warning Only call this when you know that enough data is available! - * Otherwise you will get an exception! - * - * @param buffer A buffer of sufficient size to store the specified number of - * doubles - * @param count The number of doubles to read - * @return The number of bytes read - */ -- (size_t)readLittleEndianDoublesIntoBuffer: (double *)buffer - count: (size_t)count; - /** * @brief Reads the specified number of items with an item size of 1 from the * stream and returns them as OFData. * * @warning Only call this when you know that enough data is available! @@ -756,12 +597,11 @@ * * @param itemSize The size of each item * @param count The number of items to read * @return OFData with count items. */ -- (OFData *)readDataWithItemSize: (size_t)itemSize - count: (size_t)count; +- (OFData *)readDataWithItemSize: (size_t)itemSize count: (size_t)count; /** * @brief Returns OFData with all the remaining data of the stream. * * @return OFData with an item size of 1 with all the data of the stream until @@ -799,11 +639,11 @@ * @param encoding The encoding of the string to read from the stream * @param length The length (in bytes) of the string to read from the stream * @return A string with the specified length */ - (OFString *)readStringWithLength: (size_t)length - encoding: (of_string_encoding_t)encoding; + encoding: (OFStringEncoding)encoding; /** * @brief Reads until a newline, `\0` or end of stream occurs. * * @return The line that was read, autoreleased, or `nil` if the end of the @@ -817,11 +657,11 @@ * * @param encoding The encoding used by the stream * @return The line that was read, autoreleased, or `nil` if the end of the * stream has been reached. */ -- (nullable OFString *)readLineWithEncoding: (of_string_encoding_t)encoding; +- (nullable OFString *)readLineWithEncoding: (OFStringEncoding)encoding; #ifdef OF_HAVE_SOCKETS /** * @brief Asynchronously reads until a newline, `\0`, end of stream or an * exception occurs. @@ -838,11 +678,11 @@ * @note The stream must conform to @ref OFReadyForReadingObserving in order * for this to work! * * @param encoding The encoding used by the stream */ -- (void)asyncReadLineWithEncoding: (of_string_encoding_t)encoding; +- (void)asyncReadLineWithEncoding: (OFStringEncoding)encoding; /** * @brief Asynchronously reads with the specified encoding until a newline, * `\0`, end of stream or an exception occurs. * @@ -850,12 +690,12 @@ * for this to work! * * @param encoding The encoding used by the stream * @param runLoopMode The run loop mode in which to perform the async read */ -- (void)asyncReadLineWithEncoding: (of_string_encoding_t)encoding - runLoopMode: (of_run_loop_mode_t)runLoopMode; +- (void)asyncReadLineWithEncoding: (OFStringEncoding)encoding + runLoopMode: (OFRunLoopMode)runLoopMode; # ifdef OF_HAVE_BLOCKS /** * @brief Asynchronously reads until a newline, `\0`, end of stream or an * exception occurs. @@ -867,11 +707,11 @@ * If the block returns true, it will be called again when the next * line has been received. If you want the next block in the queue * to handle the next line, you need to return false from the * block. */ -- (void)asyncReadLineWithBlock: (of_stream_async_read_line_block_t)block; +- (void)asyncReadLineWithBlock: (OFStreamAsyncReadLineBlock)block; /** * @brief Asynchronously reads with the specified encoding until a newline, * `\0`, end of stream or an exception occurs. * @@ -883,12 +723,12 @@ * If the block returns true, it will be called again when the next * line has been received. If you want the next block in the queue * to handle the next line, you need to return false from the * block. */ -- (void)asyncReadLineWithEncoding: (of_string_encoding_t)encoding - block: (of_stream_async_read_line_block_t)block; +- (void)asyncReadLineWithEncoding: (OFStringEncoding)encoding + block: (OFStreamAsyncReadLineBlock)block; /** * @brief Asynchronously reads with the specified encoding until a newline, * `\0`, end of stream or an exception occurs. * @@ -901,13 +741,13 @@ * If the block returns true, it will be called again when the next * line has been received. If you want the next block in the queue * to handle the next line, you need to return false from the * block. */ -- (void)asyncReadLineWithEncoding: (of_string_encoding_t)encoding - runLoopMode: (of_run_loop_mode_t)runLoopMode - block: (of_stream_async_read_line_block_t)block; +- (void)asyncReadLineWithEncoding: (OFStringEncoding)encoding + runLoopMode: (OFRunLoopMode)runLoopMode + block: (OFStreamAsyncReadLineBlock)block; # endif #endif /** * @brief Tries to read a line from the stream (see @ref readLine) and returns @@ -925,11 +765,11 @@ * * @param encoding The encoding used by the stream * @return The line that was read, autoreleased, or `nil` if the line is not * complete yet */ -- (nullable OFString *)tryReadLineWithEncoding: (of_string_encoding_t)encoding; +- (nullable OFString *)tryReadLineWithEncoding: (OFStringEncoding)encoding; /** * @brief Reads until the specified string or `\0` is found or the end of * stream occurs. * @@ -947,11 +787,11 @@ * @param encoding The encoding used by the stream * @return The line that was read, autoreleased, or `nil` if the end of the * stream has been reached. */ - (nullable OFString *)readTillDelimiter: (OFString *)delimiter - encoding: (of_string_encoding_t)encoding; + encoding: (OFStringEncoding)encoding; /** * @brief Tries to reads until the specified string or `\0` is found or the end * of stream (see @ref readTillDelimiter:) and returns `nil` if not * enough data has been received yet. @@ -971,27 +811,35 @@ * @param encoding The encoding used by the stream * @return The line that was read, autoreleased, or `nil` if the end of the * stream has been reached. */ - (nullable OFString *)tryReadTillDelimiter: (OFString *)delimiter - encoding: (of_string_encoding_t)encoding; + encoding: (OFStringEncoding)encoding; /** * @brief Writes everything in the write buffer to the stream. + * + * @return Whether the write buffer was flushed entirely. On non-blocking + * sockets, this can return `false` if flushing the write buffer in its + * entirety would block. */ -- (void)flushWriteBuffer; +- (bool)flushWriteBuffer; /** * @brief Writes from a buffer into the stream. + * + * In non-blocking mode, if less than the specified length could be written, an + * @ref OFWriteFailedException is thrown with @ref OFWriteFailedException#errNo + * being set to `EWOULDBLOCK` or `EAGAIN` (you need to check for both, as they + * are not the same on some systems) and + * @ref OFWriteFailedException#bytesWritten being set to the number of bytes + * that were written, if any. * * @param buffer The buffer from which the data is written into the stream * @param length The length of the data that should be written - * @return The number of bytes written. This can only differ from the specified - * length in non-blocking mode. */ -- (size_t)writeBuffer: (const void *)buffer - length: (size_t)length; +- (void)writeBuffer: (const void *)buffer length: (size_t)length; #ifdef OF_HAVE_SOCKETS /** * @brief Asynchronously writes data into the stream. * @@ -1010,11 +858,11 @@ * * @param data The data which is written into the stream * @param runLoopMode The run loop mode in which to perform the async write */ - (void)asyncWriteData: (OFData *)data - runLoopMode: (of_run_loop_mode_t)runLoopMode; + runLoopMode: (OFRunLoopMode)runLoopMode; /** * @brief Asynchronously writes a string in UTF-8 encoding into the stream. * * @note The stream must conform to @ref OFReadyForWritingObserving in order @@ -1034,11 +882,11 @@ * @param string The string which is written into the stream * @param encoding The encoding in which the string should be written to the * stream */ - (void)asyncWriteString: (OFString *)string - encoding: (of_string_encoding_t)encoding; + encoding: (OFStringEncoding)encoding; /** * @brief Asynchronously writes a string in the specified encoding into the * stream. * @@ -1049,12 +897,12 @@ * @param encoding The encoding in which the string should be written to the * stream * @param runLoopMode The run loop mode in which to perform the async write */ - (void)asyncWriteString: (OFString *)string - encoding: (of_string_encoding_t)encoding - runLoopMode: (of_run_loop_mode_t)runLoopMode; + encoding: (OFStringEncoding)encoding + runLoopMode: (OFRunLoopMode)runLoopMode; # ifdef OF_HAVE_BLOCKS /** * @brief Asynchronously writes data into the stream. * @@ -1065,11 +913,11 @@ * @param block The block to call when the data has been written. It should * return the data for the next write with the same callback or * nil if it should not repeat. */ - (void)asyncWriteData: (OFData *)data - block: (of_stream_async_write_data_block_t)block; + block: (OFStreamAsyncWriteDataBlock)block; /** * @brief Asynchronously writes data into the stream. * * @note The stream must conform to @ref OFReadyForWritingObserving in order @@ -1080,12 +928,12 @@ * @param block The block to call when the data has been written. It should * return the data for the next write with the same callback or * nil if it should not repeat. */ - (void)asyncWriteData: (OFData *)data - runLoopMode: (of_run_loop_mode_t)runLoopMode - block: (of_stream_async_write_data_block_t)block; + runLoopMode: (OFRunLoopMode)runLoopMode + block: (OFStreamAsyncWriteDataBlock)block; /** * @brief Asynchronously writes a string into the stream. * * @note The stream must conform to @ref OFReadyForWritingObserving in order @@ -1095,11 +943,11 @@ * @param block The block to call when the string has been written. It should * return the string for the next write with the same callback or * nil if it should not repeat. */ - (void)asyncWriteString: (OFString *)string - block: (of_stream_async_write_string_block_t)block; + block: (OFStreamAsyncWriteStringBlock)block; /** * @brief Asynchronously writes a string in the specified encoding into the * stream. * @@ -1112,12 +960,12 @@ * @param block The block to call when the string has been written. It should * return the string for the next write with the same callback or * nil if it should not repeat. */ - (void)asyncWriteString: (OFString *)string - encoding: (of_string_encoding_t)encoding - block: (of_stream_async_write_string_block_t)block; + encoding: (OFStringEncoding)encoding + block: (OFStreamAsyncWriteStringBlock)block; /** * @brief Asynchronously writes a string in the specified encoding into the * stream. * @@ -1131,284 +979,190 @@ * @param block The block to call when the string has been written. It should * return the string for the next write with the same callback or * nil if it should not repeat. */ - (void)asyncWriteString: (OFString *)string - encoding: (of_string_encoding_t)encoding - runLoopMode: (of_run_loop_mode_t)runLoopMode - block: (of_stream_async_write_string_block_t)block; + encoding: (OFStringEncoding)encoding + runLoopMode: (OFRunLoopMode)runLoopMode + block: (OFStreamAsyncWriteStringBlock)block; # endif #endif /** * @brief Writes a uint8_t into the stream. + * + * In non-blocking mode, the behavior is the same as @ref writeBuffer:length:. * * @param int8 A uint8_t */ - (void)writeInt8: (uint8_t)int8; /** * @brief Writes a uint16_t into the stream, encoded in big endian. + * + * In non-blocking mode, the behavior is the same as @ref writeBuffer:length:. * * @param int16 A uint16_t */ - (void)writeBigEndianInt16: (uint16_t)int16; /** * @brief Writes a uint32_t into the stream, encoded in big endian. * + * In non-blocking mode, the behavior is the same as @ref writeBuffer:length:. + * * @param int32 A uint32_t */ - (void)writeBigEndianInt32: (uint32_t)int32; /** * @brief Writes a uint64_t into the stream, encoded in big endian. * + * In non-blocking mode, the behavior is the same as @ref writeBuffer:length:. + * * @param int64 A uint64_t */ - (void)writeBigEndianInt64: (uint64_t)int64; /** * @brief Writes a float into the stream, encoded in big endian. + * + * In non-blocking mode, the behavior is the same as @ref writeBuffer:length:. * * @param float_ A float */ - (void)writeBigEndianFloat: (float)float_; /** * @brief Writes a double into the stream, encoded in big endian. * + * In non-blocking mode, the behavior is the same as @ref writeBuffer:length:. + * * @param double_ A double */ - (void)writeBigEndianDouble: (double)double_; -/** - * @brief Writes the specified number of uint16_ts into the stream, encoded in - * big endian. - * - * @param buffer The buffer from which the data is written to the stream after - * it has been byte swapped if necessary - * @param count The number of uint16_ts to write - * @return The number of bytes written to the stream - */ -- (size_t)writeBigEndianInt16s: (const uint16_t *)buffer - count: (size_t)count; - -/** - * @brief Writes the specified number of uint32_ts into the stream, encoded in - * big endian. - * - * @param buffer The buffer from which the data is written to the stream after - * it has been byte swapped if necessary - * @param count The number of uint32_ts to write - * @return The number of bytes written to the stream - */ -- (size_t)writeBigEndianInt32s: (const uint32_t *)buffer - count: (size_t)count; - -/** - * @brief Writes the specified number of uint64_ts into the stream, encoded in - * big endian. - * - * @param buffer The buffer from which the data is written to the stream after - * it has been byte swapped if necessary - * @param count The number of uint64_ts to write - * @return The number of bytes written to the stream - */ -- (size_t)writeBigEndianInt64s: (const uint64_t *)buffer - count: (size_t)count; - -/** - * @brief Writes the specified number of floats into the stream, encoded in big - * endian. - * - * @param buffer The buffer from which the data is written to the stream after - * it has been byte swapped if necessary - * @param count The number of floats to write - * @return The number of bytes written to the stream - */ -- (size_t)writeBigEndianFloats: (const float *)buffer - count: (size_t)count; - -/** - * @brief Writes the specified number of doubles into the stream, encoded in - * big endian. - * - * @param buffer The buffer from which the data is written to the stream after - * it has been byte swapped if necessary - * @param count The number of doubles to write - * @return The number of bytes written to the stream - */ -- (size_t)writeBigEndianDoubles: (const double *)buffer - count: (size_t)count; - /** * @brief Writes a uint16_t into the stream, encoded in little endian. + * + * In non-blocking mode, the behavior is the same as @ref writeBuffer:length:. * * @param int16 A uint16_t */ - (void)writeLittleEndianInt16: (uint16_t)int16; /** * @brief Writes a uint32_t into the stream, encoded in little endian. * + * In non-blocking mode, the behavior is the same as @ref writeBuffer:length:. + * * @param int32 A uint32_t */ - (void)writeLittleEndianInt32: (uint32_t)int32; /** * @brief Writes a uint64_t into the stream, encoded in little endian. * + * In non-blocking mode, the behavior is the same as @ref writeBuffer:length:. + * * @param int64 A uint64_t */ - (void)writeLittleEndianInt64: (uint64_t)int64; /** * @brief Writes a float into the stream, encoded in little endian. + * + * In non-blocking mode, the behavior is the same as @ref writeBuffer:length:. * * @param float_ A float */ - (void)writeLittleEndianFloat: (float)float_; /** * @brief Writes a double into the stream, encoded in little endian. * + * In non-blocking mode, the behavior is the same as @ref writeBuffer:length:. + * * @param double_ A double */ - (void)writeLittleEndianDouble: (double)double_; -/** - * @brief Writes the specified number of uint16_ts into the stream, encoded in - * little endian. - * - * @param buffer The buffer from which the data is written to the stream after - * it has been byte swapped if necessary - * @param count The number of uint16_ts to write - * @return The number of bytes written to the stream - */ -- (size_t)writeLittleEndianInt16s: (const uint16_t *)buffer - count: (size_t)count; - -/** - * @brief Writes the specified number of uint32_ts into the stream, encoded in - * little endian. - * - * @param count The number of uint32_ts to write - * @param buffer The buffer from which the data is written to the stream after - * it has been byte swapped if necessary - * @return The number of bytes written to the stream - */ -- (size_t)writeLittleEndianInt32s: (const uint32_t *)buffer - count: (size_t)count; - -/** - * @brief Writes the specified number of uint64_ts into the stream, encoded in - * little endian. - * - * @param buffer The buffer from which the data is written to the stream after - * it has been byte swapped if necessary - * @param count The number of uint64_ts to write - * @return The number of bytes written to the stream - */ -- (size_t)writeLittleEndianInt64s: (const uint64_t *)buffer - count: (size_t)count; - -/** - * @brief Writes the specified number of floats into the stream, encoded in - * little endian. - * - * @param buffer The buffer from which the data is written to the stream after - * it has been byte swapped if necessary - * @param count The number of floats to write - * @return The number of bytes written to the stream - */ -- (size_t)writeLittleEndianFloats: (const float *)buffer - count: (size_t)count; - -/** - * @brief Writes the specified number of doubles into the stream, encoded in - * little endian. - * - * @param buffer The buffer from which the data is written to the stream after - * it has been byte swapped if necessary - * @param count The number of doubles to write - * @return The number of bytes written to the stream - */ -- (size_t)writeLittleEndianDoubles: (const double *)buffer - count: (size_t)count; - /** * @brief Writes OFData into the stream. + * + * In non-blocking mode, the behavior is the same as @ref writeBuffer:length:. * * @param data The OFData to write into the stream - * @return The number of bytes written */ -- (size_t)writeData: (OFData *)data; +- (void)writeData: (OFData *)data; /** * @brief Writes a string into the stream, without the trailing zero. * + * In non-blocking mode, the behavior is the same as @ref writeBuffer:length:. + * * @param string The string from which the data is written to the stream - * @return The number of bytes written */ -- (size_t)writeString: (OFString *)string; +- (void)writeString: (OFString *)string; /** * @brief Writes a string into the stream in the specified encoding, without * the trailing zero. * + * In non-blocking mode, the behavior is the same as @ref writeBuffer:length:. + * * @param string The string from which the data is written to the stream * @param encoding The encoding in which to write the string to the stream - * @return The number of bytes written */ -- (size_t)writeString: (OFString *)string - encoding: (of_string_encoding_t)encoding; +- (void)writeString: (OFString *)string encoding: (OFStringEncoding)encoding; /** * @brief Writes a string into the stream with a trailing newline. * + * In non-blocking mode, the behavior is the same as @ref writeBuffer:length:. + * * @param string The string from which the data is written to the stream - * @return The number of bytes written */ -- (size_t)writeLine: (OFString *)string; +- (void)writeLine: (OFString *)string; /** * @brief Writes a string into the stream in the specified encoding with a * trailing newline. * + * In non-blocking mode, the behavior is the same as @ref writeBuffer:length:. + * * @param string The string from which the data is written to the stream * @param encoding The encoding in which to write the string to the stream - * @return The number of bytes written */ -- (size_t)writeLine: (OFString *)string - encoding: (of_string_encoding_t)encoding; +- (void)writeLine: (OFString *)string encoding: (OFStringEncoding)encoding; /** * @brief Writes a formatted string into the stream. * * See printf for the format syntax. As an addition, `%@` is available as - * format specifier for objects, `%C` for `of_unichar_t` and `%S` for - * `const of_unichar_t *`. + * format specifier for objects, `%C` for `OFUnichar` and `%S` for + * `const OFUnichar *`. + * + * In non-blocking mode, the behavior is the same as @ref writeBuffer:length:. * * @param format A string used as format - * @return The number of bytes written */ -- (size_t)writeFormat: (OFConstantString *)format, ...; +- (void)writeFormat: (OFConstantString *)format, ...; /** * @brief Writes a formatted string into the stream. * * See printf for the format syntax. As an addition, `%@` is available as - * format specifier for objects, `%C` for `of_unichar_t` and `%S` for - * `const of_unichar_t *`. + * format specifier for objects, `%C` for `OFUnichar` and `%S` for + * `const OFUnichar *`. + * + * In non-blocking mode, the behavior is the same as @ref writeBuffer:length:. * * @param format A string used as format * @param arguments The arguments used in the format string - * @return The number of bytes written */ -- (size_t)writeFormat: (OFConstantString *)format - arguments: (va_list)arguments; +- (void)writeFormat: (OFConstantString *)format arguments: (va_list)arguments; #ifdef OF_HAVE_SOCKETS /** * @brief Cancels all pending asynchronous requests on the stream. */ @@ -1434,12 +1188,11 @@ * unread. * * @param buffer The buffer to unread * @param length The length of the buffer to unread */ -- (void)unreadFromBuffer: (const void *)buffer - length: (size_t)length; +- (void)unreadFromBuffer: (const void *)buffer length: (size_t)length; /** * @brief Closes the stream. * * @note If you override this, make sure to call `[super close]`! @@ -1456,12 +1209,11 @@ * * @param buffer The buffer for the data to read * @param length The length of the buffer * @return The number of bytes read */ -- (size_t)lowlevelReadIntoBuffer: (void *)buffer - length: (size_t)length; +- (size_t)lowlevelReadIntoBuffer: (void *)buffer length: (size_t)length; /** * @brief Performs a lowlevel write. * * @warning Do not call this directly! @@ -1471,12 +1223,11 @@ * * @param buffer The buffer with the data to write * @param length The length of the data to write * @return The number of bytes written */ -- (size_t)lowlevelWriteBuffer: (const void *)buffer - length: (size_t)length; +- (size_t)lowlevelWriteBuffer: (const void *)buffer length: (size_t)length; /** * @brief Returns whether the lowlevel is at the end of the stream. * * @warning Do not call this directly! Index: src/OFStream.m ================================================================== --- src/OFStream.m +++ src/OFStream.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -28,26 +26,26 @@ #ifdef HAVE_FCNTL_H # include #endif -#ifdef OF_HAVE_SOCKETS -# import "socket_helpers.h" -#endif - #include "platform.h" #if !defined(OF_WINDOWS) && !defined(OF_MORPHOS) # include #endif #import "OFStream.h" #import "OFStream+Private.h" +#import "OFASPrintF.h" #import "OFData.h" #import "OFKernelEventObserver.h" #import "OFRunLoop+Private.h" #import "OFRunLoop.h" +#ifdef OF_HAVE_SOCKETS +# import "OFSocket+Private.h" +#endif #import "OFString.h" #import "OFSystemInfo.h" #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" @@ -56,13 +54,11 @@ #import "OFOutOfRangeException.h" #import "OFSetOptionFailedException.h" #import "OFTruncatedDataException.h" #import "OFWriteFailedException.h" -#import "of_asprintf.h" - -#define MIN_READ_SIZE 512 +#define minReadSize 512 @implementation OFStream @synthesize buffersWrites = _buffersWrites; @synthesize of_waitingForDelimiter = _waitingForDelimiter, delegate = _delegate; @@ -90,24 +86,30 @@ @throw e; } return self; } + +- (void)dealloc +{ + OFFreeMemory(_readBufferMemory); + OFFreeMemory(_writeBuffer); + + [super dealloc]; +} - (bool)lowlevelIsAtEndOfStream { OF_UNRECOGNIZED_SELECTOR } -- (size_t)lowlevelReadIntoBuffer: (void *)buffer - length: (size_t)length +- (size_t)lowlevelReadIntoBuffer: (void *)buffer length: (size_t)length { OF_UNRECOGNIZED_SELECTOR } -- (size_t)lowlevelWriteBuffer: (const void *)buffer - length: (size_t)length +- (size_t)lowlevelWriteBuffer: (const void *)buffer length: (size_t)length { OF_UNRECOGNIZED_SELECTOR } - (id)copy @@ -121,32 +123,30 @@ return false; return [self lowlevelIsAtEndOfStream]; } -- (size_t)readIntoBuffer: (void *)buffer - length: (size_t)length +- (size_t)readIntoBuffer: (void *)buffer length: (size_t)length { if (_readBufferLength == 0) { /* * For small sizes, it is cheaper to read more and cache the * remainder - even if that means more copying of data - than * to do a syscall for every read. */ - if (length < MIN_READ_SIZE) { - char tmp[MIN_READ_SIZE], *readBuffer; + if (length < minReadSize) { + char tmp[minReadSize], *readBuffer; size_t bytesRead; - bytesRead = [self - lowlevelReadIntoBuffer: tmp - length: MIN_READ_SIZE]; + bytesRead = [self lowlevelReadIntoBuffer: tmp + length: minReadSize]; if (bytesRead > length) { memcpy(buffer, tmp, length); - readBuffer = [self allocMemoryWithSize: - bytesRead - length]; + readBuffer = OFAllocMemory(bytesRead - length, + 1); memcpy(readBuffer, tmp + length, bytesRead - length); _readBuffer = _readBufferMemory = readBuffer; _readBufferLength = bytesRead - length; @@ -156,19 +156,18 @@ memcpy(buffer, tmp, bytesRead); return bytesRead; } } - return [self lowlevelReadIntoBuffer: buffer - length: length]; + return [self lowlevelReadIntoBuffer: buffer length: length]; } if (length >= _readBufferLength) { size_t ret = _readBufferLength; memcpy(buffer, _readBuffer, _readBufferLength); - [self freeMemory: _readBufferMemory]; + OFFreeMemory(_readBufferMemory); _readBuffer = _readBufferMemory = NULL; _readBufferLength = 0; return ret; } else { @@ -179,12 +178,11 @@ return length; } } -- (void)readIntoBuffer: (void *)buffer - exactLength: (size_t)length +- (void)readIntoBuffer: (void *)buffer exactLength: (size_t)length { size_t readLength = 0; while (readLength < length) { if (self.atEndOfStream) @@ -194,21 +192,20 @@ length: length - readLength]; } } #ifdef OF_HAVE_SOCKETS -- (void)asyncReadIntoBuffer: (void *)buffer - length: (size_t)length +- (void)asyncReadIntoBuffer: (void *)buffer length: (size_t)length { [self asyncReadIntoBuffer: buffer length: length - runLoopMode: of_run_loop_mode_default]; + runLoopMode: OFDefaultRunLoopMode]; } - (void)asyncReadIntoBuffer: (void *)buffer length: (size_t)length - runLoopMode: (of_run_loop_mode_t)runLoopMode + runLoopMode: (OFRunLoopMode)runLoopMode { OFStream *stream = (OFStream *)self; [OFRunLoop of_addAsyncReadForStream: stream @@ -219,21 +216,20 @@ block: NULL # endif delegate: _delegate]; } -- (void)asyncReadIntoBuffer: (void *)buffer - exactLength: (size_t)length +- (void)asyncReadIntoBuffer: (void *)buffer exactLength: (size_t)length { [self asyncReadIntoBuffer: buffer exactLength: length - runLoopMode: of_run_loop_mode_default]; + runLoopMode: OFDefaultRunLoopMode]; } - (void)asyncReadIntoBuffer: (void *)buffer exactLength: (size_t)length - runLoopMode: (of_run_loop_mode_t)runLoopMode + runLoopMode: (OFRunLoopMode)runLoopMode { OFStream *stream = (OFStream *)self; [OFRunLoop of_addAsyncReadForStream: stream @@ -247,22 +243,22 @@ } # ifdef OF_HAVE_BLOCKS - (void)asyncReadIntoBuffer: (void *)buffer length: (size_t)length - block: (of_stream_async_read_block_t)block + block: (OFStreamAsyncReadBlock)block { [self asyncReadIntoBuffer: buffer length: length - runLoopMode: of_run_loop_mode_default + runLoopMode: OFDefaultRunLoopMode block: block]; } - (void)asyncReadIntoBuffer: (void *)buffer length: (size_t)length - runLoopMode: (of_run_loop_mode_t)runLoopMode - block: (of_stream_async_read_block_t)block + runLoopMode: (OFRunLoopMode)runLoopMode + block: (OFStreamAsyncReadBlock)block { OFStream *stream = (OFStream *)self; [OFRunLoop of_addAsyncReadForStream: stream @@ -273,22 +269,22 @@ delegate: nil]; } - (void)asyncReadIntoBuffer: (void *)buffer exactLength: (size_t)length - block: (of_stream_async_read_block_t)block + block: (OFStreamAsyncReadBlock)block { [self asyncReadIntoBuffer: buffer exactLength: length - runLoopMode: of_run_loop_mode_default + runLoopMode: OFDefaultRunLoopMode block: block]; } - (void)asyncReadIntoBuffer: (void *)buffer exactLength: (size_t)length - runLoopMode: (of_run_loop_mode_t)runLoopMode - block: (of_stream_async_read_block_t)block + runLoopMode: (OFRunLoopMode)runLoopMode + block: (OFStreamAsyncReadBlock)block { OFStream *stream = (OFStream *)self; [OFRunLoop of_addAsyncReadForStream: stream @@ -302,353 +298,106 @@ #endif - (uint8_t)readInt8 { uint8_t ret; - - [self readIntoBuffer: (char *)&ret - exactLength: 1]; - + [self readIntoBuffer: (char *)&ret exactLength: 1]; return ret; } - (uint16_t)readBigEndianInt16 { uint16_t ret; - - [self readIntoBuffer: (char *)&ret - exactLength: 2]; - - return OF_BSWAP16_IF_LE(ret); + [self readIntoBuffer: (char *)&ret exactLength: 2]; + return OFFromBigEndian16(ret); } - (uint32_t)readBigEndianInt32 { uint32_t ret; - - [self readIntoBuffer: (char *)&ret - exactLength: 4]; - - return OF_BSWAP32_IF_LE(ret); + [self readIntoBuffer: (char *)&ret exactLength: 4]; + return OFFromBigEndian32(ret); } - (uint64_t)readBigEndianInt64 { uint64_t ret; - - [self readIntoBuffer: (char *)&ret - exactLength: 8]; - - return OF_BSWAP64_IF_LE(ret); + [self readIntoBuffer: (char *)&ret exactLength: 8]; + return OFFromBigEndian64(ret); } - (float)readBigEndianFloat { float ret; - - [self readIntoBuffer: (char *)&ret - exactLength: 4]; - - return OF_BSWAP_FLOAT_IF_LE(ret); + [self readIntoBuffer: (char *)&ret exactLength: 4]; + return OFFromBigEndianFloat(ret); } - (double)readBigEndianDouble { double ret; - - [self readIntoBuffer: (char *)&ret - exactLength: 8]; - - return OF_BSWAP_DOUBLE_IF_LE(ret); -} - -- (size_t)readBigEndianInt16sIntoBuffer: (uint16_t *)buffer - count: (size_t)count -{ - size_t size; - - if OF_UNLIKELY (count > SIZE_MAX / sizeof(uint16_t)) - @throw [OFOutOfRangeException exception]; - - size = count * sizeof(uint16_t); - - [self readIntoBuffer: buffer - exactLength: size]; - -#ifndef OF_BIG_ENDIAN - for (size_t i = 0; i < count; i++) - buffer[i] = OF_BSWAP16(buffer[i]); -#endif - - return size; -} - -- (size_t)readBigEndianInt32sIntoBuffer: (uint32_t *)buffer - count: (size_t)count -{ - size_t size; - - if OF_UNLIKELY (count > SIZE_MAX / sizeof(uint32_t)) - @throw [OFOutOfRangeException exception]; - - size = count * sizeof(uint32_t); - - [self readIntoBuffer: buffer - exactLength: size]; - -#ifndef OF_BIG_ENDIAN - for (size_t i = 0; i < count; i++) - buffer[i] = OF_BSWAP32(buffer[i]); -#endif - - return size; -} - -- (size_t)readBigEndianInt64sIntoBuffer: (uint64_t *)buffer - count: (size_t)count -{ - size_t size; - - if OF_UNLIKELY (count > SIZE_MAX / sizeof(uint64_t)) - @throw [OFOutOfRangeException exception]; - - size = count * sizeof(uint64_t); - - [self readIntoBuffer: buffer - exactLength: size]; - -#ifndef OF_BIG_ENDIAN - for (size_t i = 0; i < count; i++) - buffer[i] = OF_BSWAP64(buffer[i]); -#endif - - return size; -} - -- (size_t)readBigEndianFloatsIntoBuffer: (float *)buffer - count: (size_t)count -{ - size_t size; - - if OF_UNLIKELY (count > SIZE_MAX / sizeof(float)) - @throw [OFOutOfRangeException exception]; - - size = count * sizeof(float); - - [self readIntoBuffer: buffer - exactLength: size]; - -#ifndef OF_FLOAT_BIG_ENDIAN - for (size_t i = 0; i < count; i++) - buffer[i] = OF_BSWAP_FLOAT(buffer[i]); -#endif - - return size; -} - -- (size_t)readBigEndianDoublesIntoBuffer: (double *)buffer - count: (size_t)count -{ - size_t size; - - if OF_UNLIKELY (count > SIZE_MAX / sizeof(double)) - @throw [OFOutOfRangeException exception]; - - size = count * sizeof(double); - - [self readIntoBuffer: buffer - exactLength: size]; - -#ifndef OF_FLOAT_BIG_ENDIAN - for (size_t i = 0; i < count; i++) - buffer[i] = OF_BSWAP_DOUBLE(buffer[i]); -#endif - - return size; + [self readIntoBuffer: (char *)&ret exactLength: 8]; + return OFFromBigEndianDouble(ret); } - (uint16_t)readLittleEndianInt16 { uint16_t ret; - - [self readIntoBuffer: (char *)&ret - exactLength: 2]; - - return OF_BSWAP16_IF_BE(ret); + [self readIntoBuffer: (char *)&ret exactLength: 2]; + return OFFromLittleEndian16(ret); } - (uint32_t)readLittleEndianInt32 { uint32_t ret; - - [self readIntoBuffer: (char *)&ret - exactLength: 4]; - - return OF_BSWAP32_IF_BE(ret); + [self readIntoBuffer: (char *)&ret exactLength: 4]; + return OFFromLittleEndian32(ret); } - (uint64_t)readLittleEndianInt64 { uint64_t ret; - - [self readIntoBuffer: (char *)&ret - exactLength: 8]; - - return OF_BSWAP64_IF_BE(ret); + [self readIntoBuffer: (char *)&ret exactLength: 8]; + return OFFromLittleEndian64(ret); } - (float)readLittleEndianFloat { float ret; - - [self readIntoBuffer: (char *)&ret - exactLength: 4]; - - return OF_BSWAP_FLOAT_IF_BE(ret); + [self readIntoBuffer: (char *)&ret exactLength: 4]; + return OFFromLittleEndianFloat(ret); } - (double)readLittleEndianDouble { double ret; - - [self readIntoBuffer: (char *)&ret - exactLength: 8]; - - return OF_BSWAP_DOUBLE_IF_BE(ret); -} - -- (size_t)readLittleEndianInt16sIntoBuffer: (uint16_t *)buffer - count: (size_t)count -{ - size_t size; - - if OF_UNLIKELY (count > SIZE_MAX / sizeof(uint16_t)) - @throw [OFOutOfRangeException exception]; - - size = count * sizeof(uint16_t); - - [self readIntoBuffer: buffer - exactLength: size]; - -#ifdef OF_BIG_ENDIAN - for (size_t i = 0; i < count; i++) - buffer[i] = OF_BSWAP16(buffer[i]); -#endif - - return size; -} - -- (size_t)readLittleEndianInt32sIntoBuffer: (uint32_t *)buffer - count: (size_t)count -{ - size_t size; - - if OF_UNLIKELY (count > SIZE_MAX / sizeof(uint32_t)) - @throw [OFOutOfRangeException exception]; - - size = count * sizeof(uint32_t); - - [self readIntoBuffer: buffer - exactLength: size]; - -#ifdef OF_BIG_ENDIAN - for (size_t i = 0; i < count; i++) - buffer[i] = OF_BSWAP32(buffer[i]); -#endif - - return size; -} - -- (size_t)readLittleEndianInt64sIntoBuffer: (uint64_t *)buffer - count: (size_t)count -{ - size_t size; - - if OF_UNLIKELY (count > SIZE_MAX / sizeof(uint64_t)) - @throw [OFOutOfRangeException exception]; - - size = count * sizeof(uint64_t); - - [self readIntoBuffer: buffer - exactLength: size]; - -#ifdef OF_BIG_ENDIAN - for (size_t i = 0; i < count; i++) - buffer[i] = OF_BSWAP64(buffer[i]); -#endif - - return size; -} - -- (size_t)readLittleEndianFloatsIntoBuffer: (float *)buffer - count: (size_t)count -{ - size_t size; - - if OF_UNLIKELY (count > SIZE_MAX / sizeof(float)) - @throw [OFOutOfRangeException exception]; - - size = count * sizeof(float); - - [self readIntoBuffer: buffer - exactLength: size]; - -#ifdef OF_FLOAT_BIG_ENDIAN - for (size_t i = 0; i < count; i++) - buffer[i] = OF_BSWAP_FLOAT(buffer[i]); -#endif - - return size; -} - -- (size_t)readLittleEndianDoublesIntoBuffer: (double *)buffer - count: (size_t)count -{ - size_t size; - - if OF_UNLIKELY (count > SIZE_MAX / sizeof(double)) - @throw [OFOutOfRangeException exception]; - - size = count * sizeof(double); - - [self readIntoBuffer: buffer - exactLength: size]; - -#ifdef OF_FLOAT_BIG_ENDIAN - for (size_t i = 0; i < count; i++) - buffer[i] = OF_BSWAP_DOUBLE(buffer[i]); -#endif - - return size; + [self readIntoBuffer: (char *)&ret exactLength: 8]; + return OFFromLittleEndianDouble(ret); } - (OFData *)readDataWithCount: (size_t)count { - return [self readDataWithItemSize: 1 - count: count]; + return [self readDataWithItemSize: 1 count: count]; } -- (OFData *)readDataWithItemSize: (size_t)itemSize - count: (size_t)count +- (OFData *)readDataWithItemSize: (size_t)itemSize count: (size_t)count { OFData *ret; char *buffer; if OF_UNLIKELY (count > SIZE_MAX / itemSize) @throw [OFOutOfRangeException exception]; - buffer = of_malloc(count, itemSize); + buffer = OFAllocMemory(count, itemSize); @try { - [self readIntoBuffer: buffer - exactLength: count * itemSize]; - + [self readIntoBuffer: buffer exactLength: count * itemSize]; ret = [OFData dataWithItemsNoCopy: buffer - itemSize: itemSize count: count + itemSize: itemSize freeWhenDone: true]; } @catch (id e) { - of_free(buffer); + OFFreeMemory(buffer); @throw e; } return ret; } @@ -655,68 +404,61 @@ - (OFData *)readDataUntilEndOfStream { OFMutableData *data = [OFMutableData data]; size_t pageSize = [OFSystemInfo pageSize]; - char *buffer = [self allocMemoryWithSize: pageSize]; + char *buffer = OFAllocMemory(1, pageSize); @try { while (!self.atEndOfStream) { - size_t length; - - length = [self readIntoBuffer: buffer - length: pageSize]; - [data addItems: buffer - count: length]; + size_t length = + [self readIntoBuffer: buffer length: pageSize]; + [data addItems: buffer count: length]; } } @finally { - [self freeMemory: buffer]; + OFFreeMemory(buffer); } [data makeImmutable]; - return data; } - (OFString *)readStringWithLength: (size_t)length { return [self readStringWithLength: length - encoding: OF_STRING_ENCODING_UTF_8]; + encoding: OFStringEncodingUTF8]; } - (OFString *)readStringWithLength: (size_t)length - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding { OFString *ret; - char *buffer = [self allocMemoryWithSize: length + 1]; + char *buffer = OFAllocMemory(length + 1, 1); buffer[length] = 0; @try { - [self readIntoBuffer: buffer - exactLength: length]; - - ret = [OFString stringWithCString: buffer - encoding: encoding]; + [self readIntoBuffer: buffer exactLength: length]; + ret = [OFString stringWithCString: buffer encoding: encoding]; } @finally { - [self freeMemory: buffer]; + OFFreeMemory(buffer); } return ret; } -- (OFString *)tryReadLineWithEncoding: (of_string_encoding_t)encoding +- (OFString *)tryReadLineWithEncoding: (OFStringEncoding)encoding { - size_t pageSize, bufferLength, retLength; - char *retCString, *buffer, *readBuffer; + size_t pageSize, bufferLength; + char *buffer, *readBuffer; OFString *ret; /* Look if there's a line or \0 in our buffer */ if (!_waitingForDelimiter && _readBuffer != NULL) { for (size_t i = 0; i < _readBufferLength; i++) { if OF_UNLIKELY (_readBuffer[i] == '\n' || _readBuffer[i] == '\0') { - retLength = i; + size_t retLength = i; if (i > 0 && _readBuffer[i - 1] == '\r') retLength--; ret = [OFString stringWithCString: _readBuffer @@ -732,14 +474,16 @@ } } /* Read and see if we got a newline or \0 */ pageSize = [OFSystemInfo pageSize]; - buffer = [self allocMemoryWithSize: pageSize]; + buffer = OFAllocMemory(1, pageSize); @try { if ([self lowlevelIsAtEndOfStream]) { + size_t retLength; + if (_readBuffer == NULL) { _waitingForDelimiter = false; return nil; } @@ -750,11 +494,11 @@ ret = [OFString stringWithCString: _readBuffer encoding: encoding length: retLength]; - [self freeMemory: _readBufferMemory]; + OFFreeMemory(_readBufferMemory); _readBuffer = _readBufferMemory = NULL; _readBufferLength = 0; _waitingForDelimiter = false; return ret; @@ -765,13 +509,12 @@ /* Look if there's a newline or \0 */ for (size_t i = 0; i < bufferLength; i++) { if OF_UNLIKELY (buffer[i] == '\n' || buffer[i] == '\0') { - retLength = _readBufferLength + i; - retCString = [self - allocMemoryWithSize: retLength]; + size_t retLength = _readBufferLength + i; + char *retCString = OFAllocMemory(retLength, 1); if (_readBuffer != NULL) memcpy(retCString, _readBuffer, _readBufferLength); memcpy(retCString + _readBufferLength, @@ -780,54 +523,49 @@ if (retLength > 0 && retCString[retLength - 1] == '\r') retLength--; @try { - char *rcs = retCString; - size_t rl = retLength; - ret = [OFString - stringWithCString: rcs + stringWithCString: retCString encoding: encoding - length: rl]; + length: retLength]; } @catch (id e) { if (bufferLength > 0) { /* * Append data to _readBuffer * to prevent loss of data. */ - readBuffer = [self - allocMemoryWithSize: + readBuffer = OFAllocMemory( _readBufferLength + - bufferLength]; + bufferLength, 1); memcpy(readBuffer, _readBuffer, _readBufferLength); memcpy(readBuffer + _readBufferLength, buffer, bufferLength); - [self freeMemory: - _readBufferMemory]; + OFFreeMemory(_readBufferMemory); _readBuffer = readBuffer; _readBufferMemory = readBuffer; _readBufferLength += bufferLength; } @throw e; } @finally { - [self freeMemory: retCString]; + OFFreeMemory(retCString); } - readBuffer = [self - allocMemoryWithSize: bufferLength - i - 1]; + readBuffer = OFAllocMemory(bufferLength - i - 1, + 1); if (readBuffer != NULL) memcpy(readBuffer, buffer + i + 1, bufferLength - i - 1); - [self freeMemory: _readBufferMemory]; + OFFreeMemory(_readBufferMemory); _readBuffer = _readBufferMemory = readBuffer; _readBufferLength = bufferLength - i - 1; _waitingForDelimiter = false; return ret; @@ -834,35 +572,35 @@ } } /* There was no newline or \0 */ if (bufferLength > 0) { - readBuffer = [self allocMemoryWithSize: - _readBufferLength + bufferLength]; + readBuffer = OFAllocMemory( + _readBufferLength + bufferLength, 1); memcpy(readBuffer, _readBuffer, _readBufferLength); memcpy(readBuffer + _readBufferLength, buffer, bufferLength); - [self freeMemory: _readBufferMemory]; + OFFreeMemory(_readBufferMemory); _readBuffer = _readBufferMemory = readBuffer; _readBufferLength += bufferLength; } } @finally { - [self freeMemory: buffer]; + OFFreeMemory(buffer); } _waitingForDelimiter = true; return nil; } - (OFString *)readLine { - return [self readLineWithEncoding: OF_STRING_ENCODING_UTF_8]; + return [self readLineWithEncoding: OFStringEncodingUTF8]; } -- (OFString *)readLineWithEncoding: (of_string_encoding_t)encoding +- (OFString *)readLineWithEncoding: (OFStringEncoding)encoding { OFString *line = nil; while ((line = [self tryReadLineWithEncoding: encoding]) == nil) if (self.atEndOfStream) @@ -872,22 +610,22 @@ } #ifdef OF_HAVE_SOCKETS - (void)asyncReadLine { - [self asyncReadLineWithEncoding: OF_STRING_ENCODING_UTF_8 - runLoopMode: of_run_loop_mode_default]; + [self asyncReadLineWithEncoding: OFStringEncodingUTF8 + runLoopMode: OFDefaultRunLoopMode]; } -- (void)asyncReadLineWithEncoding: (of_string_encoding_t)encoding +- (void)asyncReadLineWithEncoding: (OFStringEncoding)encoding { [self asyncReadLineWithEncoding: encoding - runLoopMode: of_run_loop_mode_default]; + runLoopMode: OFDefaultRunLoopMode]; } -- (void)asyncReadLineWithEncoding: (of_string_encoding_t)encoding - runLoopMode: (of_run_loop_mode_t)runLoopMode +- (void)asyncReadLineWithEncoding: (OFStringEncoding)encoding + runLoopMode: (OFRunLoopMode)runLoopMode { OFStream *stream = (OFStream *)self; [OFRunLoop of_addAsyncReadLineForStream: stream @@ -898,28 +636,28 @@ # endif delegate: _delegate]; } # ifdef OF_HAVE_BLOCKS -- (void)asyncReadLineWithBlock: (of_stream_async_read_line_block_t)block +- (void)asyncReadLineWithBlock: (OFStreamAsyncReadLineBlock)block { - [self asyncReadLineWithEncoding: OF_STRING_ENCODING_UTF_8 - runLoopMode: of_run_loop_mode_default + [self asyncReadLineWithEncoding: OFStringEncodingUTF8 + runLoopMode: OFDefaultRunLoopMode block: block]; } -- (void)asyncReadLineWithEncoding: (of_string_encoding_t)encoding - block: (of_stream_async_read_line_block_t)block +- (void)asyncReadLineWithEncoding: (OFStringEncoding)encoding + block: (OFStreamAsyncReadLineBlock)block { [self asyncReadLineWithEncoding: encoding - runLoopMode: of_run_loop_mode_default + runLoopMode: OFDefaultRunLoopMode block: block]; } -- (void)asyncReadLineWithEncoding: (of_string_encoding_t)encoding - runLoopMode: (of_run_loop_mode_t)runLoopMode - block: (of_stream_async_read_line_block_t)block +- (void)asyncReadLineWithEncoding: (OFStringEncoding)encoding + runLoopMode: (OFRunLoopMode)runLoopMode + block: (OFStreamAsyncReadLineBlock)block { OFStream *stream = (OFStream *)self; [OFRunLoop of_addAsyncReadLineForStream: stream @@ -931,19 +669,19 @@ # endif #endif - (OFString *)tryReadLine { - return [self tryReadLineWithEncoding: OF_STRING_ENCODING_UTF_8]; + return [self tryReadLineWithEncoding: OFStringEncodingUTF8]; } - (OFString *)tryReadTillDelimiter: (OFString *)delimiter - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding { const char *delimiterCString; - size_t j, delimiterLength, pageSize, bufferLength, retLength; - char *retCString, *buffer, *readBuffer; + size_t j, delimiterLength, pageSize, bufferLength; + char *buffer, *readBuffer; OFString *ret; delimiterCString = [delimiter cStringWithEncoding: encoding]; delimiterLength = [delimiter cStringLengthWithEncoding: encoding]; j = 0; @@ -975,11 +713,11 @@ } } /* Read and see if we got a delimiter or \0 */ pageSize = [OFSystemInfo pageSize]; - buffer = [self allocMemoryWithSize: pageSize]; + buffer = OFAllocMemory(1, pageSize); @try { if ([self lowlevelIsAtEndOfStream]) { if (_readBuffer == NULL) { _waitingForDelimiter = false; @@ -988,11 +726,11 @@ ret = [OFString stringWithCString: _readBuffer encoding: encoding length: _readBufferLength]; - [self freeMemory: _readBufferMemory]; + OFFreeMemory(_readBufferMemory); _readBuffer = _readBufferMemory = NULL; _readBufferLength = 0; _waitingForDelimiter = false; return ret; @@ -1005,17 +743,19 @@ for (size_t i = 0; i < bufferLength; i++) { if (buffer[i] != delimiterCString[j++]) j = 0; if (j == delimiterLength || buffer[i] == '\0') { + size_t retLength; + char *retCString; + if (buffer[i] == '\0') delimiterLength = 1; retLength = _readBufferLength + i + 1 - delimiterLength; - retCString = [self - allocMemoryWithSize: retLength]; + retCString = OFAllocMemory(retLength, 1); if (_readBuffer != NULL && _readBufferLength <= retLength) memcpy(retCString, _readBuffer, _readBufferLength); @@ -1025,54 +765,49 @@ if (i >= delimiterLength) memcpy(retCString + _readBufferLength, buffer, i + 1 - delimiterLength); @try { - char *rcs = retCString; - size_t rl = retLength; - ret = [OFString - stringWithCString: rcs + stringWithCString: retCString encoding: encoding - length: rl]; + length: retLength]; } @catch (id e) { if (bufferLength > 0) { /* * Append data to _readBuffer * to prevent loss of data. */ - readBuffer = [self - allocMemoryWithSize: + readBuffer = OFAllocMemory( _readBufferLength + - bufferLength]; + bufferLength, 1); memcpy(readBuffer, _readBuffer, _readBufferLength); memcpy(readBuffer + _readBufferLength, buffer, bufferLength); - [self freeMemory: - _readBufferMemory]; + OFFreeMemory(_readBufferMemory); _readBuffer = readBuffer; _readBufferMemory = readBuffer; _readBufferLength += bufferLength; } @throw e; } @finally { - [self freeMemory: retCString]; + OFFreeMemory(retCString); } - readBuffer = [self allocMemoryWithSize: - bufferLength - i - 1]; + readBuffer = OFAllocMemory(bufferLength - i - 1, + 1); if (readBuffer != NULL) memcpy(readBuffer, buffer + i + 1, bufferLength - i - 1); - [self freeMemory: _readBufferMemory]; + OFFreeMemory(_readBufferMemory); _readBuffer = _readBufferMemory = readBuffer; _readBufferLength = bufferLength - i - 1; _waitingForDelimiter = false; return ret; @@ -1079,23 +814,23 @@ } } /* Neither the delimiter nor \0 was found */ if (bufferLength > 0) { - readBuffer = [self allocMemoryWithSize: - _readBufferLength + bufferLength]; + readBuffer = OFAllocMemory( + _readBufferLength + bufferLength, 1); memcpy(readBuffer, _readBuffer, _readBufferLength); memcpy(readBuffer + _readBufferLength, buffer, bufferLength); - [self freeMemory: _readBufferMemory]; + OFFreeMemory(_readBufferMemory); _readBuffer = _readBufferMemory = readBuffer; _readBufferLength += bufferLength; } } @finally { - [self freeMemory: buffer]; + OFFreeMemory(buffer); } _waitingForDelimiter = true; return nil; } @@ -1102,15 +837,15 @@ - (OFString *)readTillDelimiter: (OFString *)delimiter { return [self readTillDelimiter: delimiter - encoding: OF_STRING_ENCODING_UTF_8]; + encoding: OFStringEncodingUTF8]; } - (OFString *)readTillDelimiter: (OFString *)delimiter - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding { OFString *ret = nil; while ((ret = [self tryReadTillDelimiter: delimiter encoding: encoding]) == nil) @@ -1121,60 +856,79 @@ } - (OFString *)tryReadTillDelimiter: (OFString *)delimiter { return [self tryReadTillDelimiter: delimiter - encoding: OF_STRING_ENCODING_UTF_8]; + encoding: OFStringEncodingUTF8]; } -- (void)flushWriteBuffer +- (bool)flushWriteBuffer { + size_t bytesWritten; + if (_writeBuffer == NULL) - return; - - [self lowlevelWriteBuffer: _writeBuffer - length: _writeBufferLength]; - - [self freeMemory: _writeBuffer]; - _writeBuffer = NULL; - _writeBufferLength = 0; + return true; + + bytesWritten = [self lowlevelWriteBuffer: _writeBuffer + length: _writeBufferLength]; + + if (bytesWritten == 0) + return false; + + if (bytesWritten == _writeBufferLength) { + OFFreeMemory(_writeBuffer); + _writeBuffer = NULL; + _writeBufferLength = 0; + + return true; + } + + OFEnsure(bytesWritten <= _writeBufferLength); + + memmove(_writeBuffer, _writeBuffer + bytesWritten, + _writeBufferLength - bytesWritten); + _writeBufferLength -= bytesWritten; + @try { + _writeBuffer = OFResizeMemory(_writeBuffer, + _writeBufferLength, 1); + } @catch (OFOutOfMemoryException *e) { + /* We don't care, as we only made it smaller. */ + } + + return false; } -- (size_t)writeBuffer: (const void *)buffer - length: (size_t)length +- (void)writeBuffer: (const void *)buffer length: (size_t)length { if (!_buffersWrites) { size_t bytesWritten = [self lowlevelWriteBuffer: buffer length: length]; - if (_canBlock && bytesWritten < length) + if (bytesWritten < length) @throw [OFWriteFailedException exceptionWithObject: self requestedLength: length bytesWritten: bytesWritten errNo: 0]; - - return bytesWritten; } else { - _writeBuffer = [self resizeMemory: _writeBuffer - size: _writeBufferLength + length]; + if (SIZE_MAX - _writeBufferLength < length) + @throw [OFOutOfRangeException exception]; + + _writeBuffer = OFResizeMemory(_writeBuffer, + _writeBufferLength + length, 1); memcpy(_writeBuffer + _writeBufferLength, buffer, length); _writeBufferLength += length; - - return length; } } #ifdef OF_HAVE_SOCKETS - (void)asyncWriteData: (OFData *)data { - [self asyncWriteData: data - runLoopMode: of_run_loop_mode_default]; + [self asyncWriteData: data runLoopMode: OFDefaultRunLoopMode]; } -- (void)asyncWriteData: (OFData *)data - runLoopMode: (of_run_loop_mode_t)runLoopMode +- (void)asyncWriteData: (OFData *)data runLoopMode: (OFRunLoopMode)runLoopMode { OFStream *stream = (OFStream *)self; [OFRunLoop of_addAsyncWriteForStream: stream @@ -1187,25 +941,25 @@ } - (void)asyncWriteString: (OFString *)string { [self asyncWriteString: string - encoding: OF_STRING_ENCODING_UTF_8 - runLoopMode: of_run_loop_mode_default]; + encoding: OFStringEncodingUTF8 + runLoopMode: OFDefaultRunLoopMode]; } - (void)asyncWriteString: (OFString *)string - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding { [self asyncWriteString: string encoding: encoding - runLoopMode: of_run_loop_mode_default]; + runLoopMode: OFDefaultRunLoopMode]; } - (void)asyncWriteString: (OFString *)string - encoding: (of_string_encoding_t)encoding - runLoopMode: (of_run_loop_mode_t)runLoopMode + encoding: (OFStringEncoding)encoding + runLoopMode: (OFRunLoopMode)runLoopMode { OFStream *stream = (OFStream *)self; [OFRunLoop of_addAsyncWriteForStream: stream @@ -1217,21 +971,20 @@ # endif delegate: _delegate]; } # ifdef OF_HAVE_BLOCKS -- (void)asyncWriteData: (OFData *)data - block: (of_stream_async_write_data_block_t)block +- (void)asyncWriteData: (OFData *)data block: (OFStreamAsyncWriteDataBlock)block { [self asyncWriteData: data - runLoopMode: of_run_loop_mode_default + runLoopMode: OFDefaultRunLoopMode block: block]; } - (void)asyncWriteData: (OFData *)data - runLoopMode: (of_run_loop_mode_t)runLoopMode - block: (of_stream_async_write_data_block_t)block + runLoopMode: (OFRunLoopMode)runLoopMode + block: (OFStreamAsyncWriteDataBlock)block { OFStream *stream = (OFStream *)self; [OFRunLoop of_addAsyncWriteForStream: stream @@ -1240,32 +993,32 @@ block: block delegate: nil]; } - (void)asyncWriteString: (OFString *)string - block: (of_stream_async_write_string_block_t)block + block: (OFStreamAsyncWriteStringBlock)block { [self asyncWriteString: string - encoding: OF_STRING_ENCODING_UTF_8 - runLoopMode: of_run_loop_mode_default + encoding: OFStringEncodingUTF8 + runLoopMode: OFDefaultRunLoopMode block: block]; } - (void)asyncWriteString: (OFString *)string - encoding: (of_string_encoding_t)encoding - block: (of_stream_async_write_string_block_t)block + encoding: (OFStringEncoding)encoding + block: (OFStreamAsyncWriteStringBlock)block { [self asyncWriteString: string encoding: encoding - runLoopMode: of_run_loop_mode_default + runLoopMode: OFDefaultRunLoopMode block: block]; } - (void)asyncWriteString: (OFString *)string - encoding: (of_string_encoding_t)encoding - runLoopMode: (of_run_loop_mode_t)runLoopMode - block: (of_stream_async_write_string_block_t)block + encoding: (OFStringEncoding)encoding + runLoopMode: (OFRunLoopMode)runLoopMode + block: (OFStreamAsyncWriteStringBlock)block { OFStream *stream = (OFStream *)self; [OFRunLoop of_addAsyncWriteForStream: stream @@ -1278,431 +1031,95 @@ # endif #endif - (void)writeInt8: (uint8_t)int8 { - [self writeBuffer: (char *)&int8 - length: 1]; + [self writeBuffer: (char *)&int8 length: 1]; } - (void)writeBigEndianInt16: (uint16_t)int16 { - int16 = OF_BSWAP16_IF_LE(int16); - - [self writeBuffer: (char *)&int16 - length: 2]; + int16 = OFToBigEndian16(int16); + [self writeBuffer: (char *)&int16 length: 2]; } - (void)writeBigEndianInt32: (uint32_t)int32 { - int32 = OF_BSWAP32_IF_LE(int32); - - [self writeBuffer: (char *)&int32 - length: 4]; + int32 = OFToBigEndian32(int32); + [self writeBuffer: (char *)&int32 length: 4]; } - (void)writeBigEndianInt64: (uint64_t)int64 { - int64 = OF_BSWAP64_IF_LE(int64); - - [self writeBuffer: (char *)&int64 - length: 8]; + int64 = OFToBigEndian64(int64); + [self writeBuffer: (char *)&int64 length: 8]; } - (void)writeBigEndianFloat: (float)float_ { - float_ = OF_BSWAP_FLOAT_IF_LE(float_); - - [self writeBuffer: (char *)&float_ - length: 4]; + float_ = OFToBigEndianFloat(float_); + [self writeBuffer: (char *)&float_ length: 4]; } - (void)writeBigEndianDouble: (double)double_ { - double_ = OF_BSWAP_DOUBLE_IF_LE(double_); - - [self writeBuffer: (char *)&double_ - length: 8]; -} - -- (size_t)writeBigEndianInt16s: (const uint16_t *)buffer - count: (size_t)count -{ - size_t size; - - if OF_UNLIKELY (count > SIZE_MAX / sizeof(uint16_t)) - @throw [OFOutOfRangeException exception]; - - size = count * sizeof(uint16_t); - -#ifdef OF_BIG_ENDIAN - [self writeBuffer: buffer - length: size]; -#else - uint16_t *tmp = [self allocMemoryWithSize: sizeof(uint16_t) - count: count]; - - @try { - for (size_t i = 0; i < count; i++) - tmp[i] = OF_BSWAP16(buffer[i]); - - [self writeBuffer: tmp - length: size]; - } @finally { - [self freeMemory: tmp]; - } -#endif - - return size; -} - -- (size_t)writeBigEndianInt32s: (const uint32_t *)buffer - count: (size_t)count -{ - size_t size; - - if OF_UNLIKELY (count > SIZE_MAX / sizeof(uint32_t)) - @throw [OFOutOfRangeException exception]; - - size = count * sizeof(uint32_t); - -#ifdef OF_BIG_ENDIAN - [self writeBuffer: buffer - length: size]; -#else - uint32_t *tmp = [self allocMemoryWithSize: sizeof(uint32_t) - count: count]; - - @try { - for (size_t i = 0; i < count; i++) - tmp[i] = OF_BSWAP32(buffer[i]); - - [self writeBuffer: tmp - length: size]; - } @finally { - [self freeMemory: tmp]; - } -#endif - - return size; -} - -- (size_t)writeBigEndianInt64s: (const uint64_t *)buffer - count: (size_t)count -{ - size_t size; - - if OF_UNLIKELY (count > SIZE_MAX / sizeof(uint64_t)) - @throw [OFOutOfRangeException exception]; - - size = count * sizeof(uint64_t); - -#ifdef OF_BIG_ENDIAN - [self writeBuffer: buffer - length: size]; -#else - uint64_t *tmp = [self allocMemoryWithSize: sizeof(uint64_t) - count: count]; - - @try { - for (size_t i = 0; i < count; i++) - tmp[i] = OF_BSWAP64(buffer[i]); - - [self writeBuffer: tmp - length: size]; - } @finally { - [self freeMemory: tmp]; - } -#endif - - return size; -} - -- (size_t)writeBigEndianFloats: (const float *)buffer - count: (size_t)count -{ - size_t size; - - if OF_UNLIKELY (count > SIZE_MAX / sizeof(float)) - @throw [OFOutOfRangeException exception]; - - size = count * sizeof(float); - -#ifdef OF_FLOAT_BIG_ENDIAN - [self writeBuffer: buffer - length: size]; -#else - float *tmp = [self allocMemoryWithSize: sizeof(float) - count: count]; - - @try { - for (size_t i = 0; i < count; i++) - tmp[i] = OF_BSWAP_FLOAT(buffer[i]); - - [self writeBuffer: tmp - length: size]; - } @finally { - [self freeMemory: tmp]; - } -#endif - - return size; -} - -- (size_t)writeBigEndianDoubles: (const double *)buffer - count: (size_t)count -{ - size_t size; - - if OF_UNLIKELY (count > SIZE_MAX / sizeof(double)) - @throw [OFOutOfRangeException exception]; - - size = count * sizeof(double); - -#ifdef OF_FLOAT_BIG_ENDIAN - [self writeBuffer: buffer - length: size]; -#else - double *tmp = [self allocMemoryWithSize: sizeof(double) - count: count]; - - @try { - for (size_t i = 0; i < count; i++) - tmp[i] = OF_BSWAP_DOUBLE(buffer[i]); - - [self writeBuffer: tmp - length: size]; - } @finally { - [self freeMemory: tmp]; - } -#endif - - return size; + double_ = OFToBigEndianDouble(double_); + [self writeBuffer: (char *)&double_ length: 8]; } - (void)writeLittleEndianInt16: (uint16_t)int16 { - int16 = OF_BSWAP16_IF_BE(int16); - - [self writeBuffer: (char *)&int16 - length: 2]; + int16 = OFToLittleEndian16(int16); + [self writeBuffer: (char *)&int16 length: 2]; } - (void)writeLittleEndianInt32: (uint32_t)int32 { - int32 = OF_BSWAP32_IF_BE(int32); - - [self writeBuffer: (char *)&int32 - length: 4]; + int32 = OFToLittleEndian32(int32); + [self writeBuffer: (char *)&int32 length: 4]; } - (void)writeLittleEndianInt64: (uint64_t)int64 { - int64 = OF_BSWAP64_IF_BE(int64); - - [self writeBuffer: (char *)&int64 - length: 8]; + int64 = OFToLittleEndian64(int64); + [self writeBuffer: (char *)&int64 length: 8]; } - (void)writeLittleEndianFloat: (float)float_ { - float_ = OF_BSWAP_FLOAT_IF_BE(float_); - - [self writeBuffer: (char *)&float_ - length: 4]; + float_ = OFToLittleEndianFloat(float_); + [self writeBuffer: (char *)&float_ length: 4]; } - (void)writeLittleEndianDouble: (double)double_ { - double_ = OF_BSWAP_DOUBLE_IF_BE(double_); - - [self writeBuffer: (char *)&double_ - length: 8]; -} - -- (size_t)writeLittleEndianInt16s: (const uint16_t *)buffer - count: (size_t)count -{ - size_t size; - - if OF_UNLIKELY (count > SIZE_MAX / sizeof(uint16_t)) - @throw [OFOutOfRangeException exception]; - - size = count * sizeof(uint16_t); - -#ifndef OF_BIG_ENDIAN - [self writeBuffer: buffer - length: size]; -#else - uint16_t *tmp = [self allocMemoryWithSize: sizeof(uint16_t) - count: count]; - - @try { - for (size_t i = 0; i < count; i++) - tmp[i] = OF_BSWAP16(buffer[i]); - - [self writeBuffer: tmp - length: size]; - } @finally { - [self freeMemory: tmp]; - } -#endif - - return size; -} - -- (size_t)writeLittleEndianInt32s: (const uint32_t *)buffer - count: (size_t)count -{ - size_t size; - - if OF_UNLIKELY (count > SIZE_MAX / sizeof(uint32_t)) - @throw [OFOutOfRangeException exception]; - - size = count * sizeof(uint32_t); - -#ifndef OF_BIG_ENDIAN - [self writeBuffer: buffer - length: size]; -#else - uint32_t *tmp = [self allocMemoryWithSize: sizeof(uint32_t) - count: count]; - - @try { - for (size_t i = 0; i < count; i++) - tmp[i] = OF_BSWAP32(buffer[i]); - - [self writeBuffer: tmp - length: size]; - } @finally { - [self freeMemory: tmp]; - } -#endif - - return size; -} - -- (size_t)writeLittleEndianInt64s: (const uint64_t *)buffer - count: (size_t)count -{ - size_t size; - - if OF_UNLIKELY (count > SIZE_MAX / sizeof(uint64_t)) - @throw [OFOutOfRangeException exception]; - - size = count * sizeof(uint64_t); - -#ifndef OF_BIG_ENDIAN - [self writeBuffer: buffer - length: size]; -#else - uint64_t *tmp = [self allocMemoryWithSize: sizeof(uint64_t) - count: count]; - - @try { - for (size_t i = 0; i < count; i++) - tmp[i] = OF_BSWAP64(buffer[i]); - - [self writeBuffer: tmp - length: size]; - } @finally { - [self freeMemory: tmp]; - } -#endif - - return size; -} - -- (size_t)writeLittleEndianFloats: (const float *)buffer - count: (size_t)count -{ - size_t size; - - if OF_UNLIKELY (count > SIZE_MAX / sizeof(float)) - @throw [OFOutOfRangeException exception]; - - size = count * sizeof(float); - -#ifndef OF_FLOAT_BIG_ENDIAN - [self writeBuffer: buffer - length: size]; -#else - float *tmp = [self allocMemoryWithSize: sizeof(float) - count: count]; - - @try { - for (size_t i = 0; i < count; i++) - tmp[i] = OF_BSWAP_FLOAT(buffer[i]); - - [self writeBuffer: tmp - length: size]; - } @finally { - [self freeMemory: tmp]; - } -#endif - - return size; -} - -- (size_t)writeLittleEndianDoubles: (const double *)buffer - count: (size_t)count -{ - size_t size; - - if OF_UNLIKELY (count > SIZE_MAX / sizeof(double)) - @throw [OFOutOfRangeException exception]; - - size = count * sizeof(double); - -#ifndef OF_FLOAT_BIG_ENDIAN - [self writeBuffer: buffer - length: size]; -#else - double *tmp = [self allocMemoryWithSize: sizeof(double) - count: count]; - - @try { - for (size_t i = 0; i < count; i++) - tmp[i] = OF_BSWAP_DOUBLE(buffer[i]); - - [self writeBuffer: tmp - length: size]; - } @finally { - [self freeMemory: tmp]; - } -#endif - - return size; -} - -- (size_t)writeData: (OFData *)data + double_ = OFToLittleEndianDouble(double_); + [self writeBuffer: (char *)&double_ length: 8]; +} + +- (void)writeData: (OFData *)data { void *pool; size_t length; if (data == nil) @throw [OFInvalidArgumentException exception]; pool = objc_autoreleasePoolPush(); + length = data.count * data.itemSize; - - [self writeBuffer: data.items - length: length]; + [self writeBuffer: data.items length: length]; objc_autoreleasePoolPop(pool); +} - return length; +- (void)writeString: (OFString *)string +{ + [self writeString: string encoding: OFStringEncodingUTF8]; } -- (size_t)writeString: (OFString *)string -{ - return [self writeString: string - encoding: OF_STRING_ENCODING_UTF_8]; -} - -- (size_t)writeString: (OFString *)string - encoding: (of_string_encoding_t)encoding +- (void)writeString: (OFString *)string encoding: (OFStringEncoding)encoding { void *pool; size_t length; if (string == nil) @@ -1713,76 +1130,61 @@ [self writeBuffer: [string cStringWithEncoding: encoding] length: length]; objc_autoreleasePoolPop(pool); +} - return length; +- (void)writeLine: (OFString *)string +{ + [self writeLine: string encoding: OFStringEncodingUTF8]; } -- (size_t)writeLine: (OFString *)string -{ - return [self writeLine: string - encoding: OF_STRING_ENCODING_UTF_8]; -} - -- (size_t)writeLine: (OFString *)string - encoding: (of_string_encoding_t)encoding +- (void)writeLine: (OFString *)string encoding: (OFStringEncoding)encoding { size_t stringLength = [string cStringLengthWithEncoding: encoding]; char *buffer; - buffer = [self allocMemoryWithSize: stringLength + 1]; + buffer = OFAllocMemory(stringLength + 1, 1); @try { memcpy(buffer, [string cStringWithEncoding: encoding], stringLength); buffer[stringLength] = '\n'; - [self writeBuffer: buffer - length: stringLength + 1]; - } @finally { - [self freeMemory: buffer]; - } - - return stringLength + 1; -} - -- (size_t)writeFormat: (OFConstantString *)format, ... + [self writeBuffer: buffer length: stringLength + 1]; + } @finally { + OFFreeMemory(buffer); + } +} + +- (void)writeFormat: (OFConstantString *)format, ... { va_list arguments; - size_t ret; va_start(arguments, format); - ret = [self writeFormat: format - arguments: arguments]; + [self writeFormat: format arguments: arguments]; va_end(arguments); - - return ret; } -- (size_t)writeFormat: (OFConstantString *)format - arguments: (va_list)arguments +- (void)writeFormat: (OFConstantString *)format arguments: (va_list)arguments { char *UTF8String; int length; if (format == nil) @throw [OFInvalidArgumentException exception]; - if ((length = of_vasprintf(&UTF8String, format.UTF8String, + if ((length = OFVASPrintF(&UTF8String, format.UTF8String, arguments)) == -1) @throw [OFInvalidFormatException exception]; @try { - [self writeBuffer: UTF8String - length: length]; + [self writeBuffer: UTF8String length: length]; } @finally { free(UTF8String); } - - return length; } - (bool)hasDataInReadBuffer { return (_readBufferLength > 0); @@ -1872,40 +1274,39 @@ #ifdef OF_HAVE_SOCKETS - (void)cancelAsyncRequests { [OFRunLoop of_cancelAsyncRequestsForObject: self - mode: of_run_loop_mode_default]; + mode: OFDefaultRunLoopMode]; } #endif -- (void)unreadFromBuffer: (const void *)buffer - length: (size_t)length +- (void)unreadFromBuffer: (const void *)buffer length: (size_t)length { char *readBuffer; if (length > SIZE_MAX - _readBufferLength) @throw [OFOutOfRangeException exception]; - readBuffer = [self allocMemoryWithSize: _readBufferLength + length]; + readBuffer = OFAllocMemory(_readBufferLength + length, 1); memcpy(readBuffer, buffer, length); memcpy(readBuffer + length, _readBuffer, _readBufferLength); - [self freeMemory: _readBufferMemory]; + OFFreeMemory(_readBufferMemory); _readBuffer = _readBufferMemory = readBuffer; _readBufferLength += length; } - (void)close { - [self freeMemory: _readBufferMemory]; + OFFreeMemory(_readBufferMemory); _readBuffer = _readBufferMemory = NULL; _readBufferLength = 0; - [self freeMemory: _writeBuffer]; + OFFreeMemory(_writeBuffer); _writeBuffer = NULL; _writeBufferLength = 0; _buffersWrites = false; _waitingForDelimiter = false; } @end Index: src/OFStreamSocket+Private.h ================================================================== --- src/OFStreamSocket+Private.h +++ src/OFStreamSocket+Private.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFStreamSocket.h ================================================================== --- src/OFStreamSocket.h +++ src/OFStreamSocket.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -14,12 +12,11 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #import "OFStream.h" - -#import "socket.h" +#import "OFSocket.h" OF_ASSUME_NONNULL_BEGIN /** @file */ @@ -33,12 +30,12 @@ * @param exception An exception which occurred while accepting the socket or * `nil` on success * @return A bool whether the same block should be used for the next incoming * connection */ -typedef bool (^of_stream_socket_async_accept_block_t)( - OFStreamSocket *acceptedSocket, id _Nullable exception); +typedef bool (^OFStreamSocketAsyncAcceptBlock)(OFStreamSocket *acceptedSocket, + id _Nullable exception); #endif /** * @protocol OFStreamSocketDelegate OFStreamSocket.h ObjFW/OFStreamSocket.h * @@ -66,13 +63,13 @@ * @brief A class which provides methods to create and use stream sockets. */ @interface OFStreamSocket: OFStream { - of_socket_t _socket; + OFSocketHandle _socket; bool _atEndOfStream, _listening; - of_socket_address_t _remoteAddress; + OFSocketAddress _remoteAddress; OF_RESERVE_IVARS(OFStreamSocket, 4) } /** * @brief Whether the socket is a listening socket. @@ -82,11 +79,11 @@ /** * @brief The remote address. * * @note This only works for accepted sockets! */ -@property (readonly, nonatomic) const of_socket_address_t *remoteAddress; +@property (readonly, nonatomic) const OFSocketAddress *remoteAddress; /** * @brief The delegate for asynchronous operations on the socket. * * @note The delegate is retained for as long as asynchronous operations are @@ -129,32 +126,31 @@ /** * @brief Asynchronously accept an incoming connection. * * @param runLoopMode The run loop mode in which to perform the async accept */ -- (void)asyncAcceptWithRunLoopMode: (of_run_loop_mode_t)runLoopMode; +- (void)asyncAcceptWithRunLoopMode: (OFRunLoopMode)runLoopMode; #ifdef OF_HAVE_BLOCKS /** * @brief Asynchronously accept an incoming connection. * * @param block The block to execute when a new connection has been accepted. * Returns whether the next incoming connection should be accepted * by the specified block as well. */ -- (void)asyncAcceptWithBlock: (of_stream_socket_async_accept_block_t)block; +- (void)asyncAcceptWithBlock: (OFStreamSocketAsyncAcceptBlock)block; /** * @brief Asynchronously accept an incoming connection. * * @param runLoopMode The run loop mode in which to perform the async accept * @param block The block to execute when a new connection has been accepted. * Returns whether the next incoming connection should be accepted * by the specified block as well. */ -- (void)asyncAcceptWithRunLoopMode: (of_run_loop_mode_t)runLoopMode - block: (of_stream_socket_async_accept_block_t) - block; +- (void)asyncAcceptWithRunLoopMode: (OFRunLoopMode)runLoopMode + block: (OFStreamSocketAsyncAcceptBlock)block; #endif @end OF_ASSUME_NONNULL_END Index: src/OFStreamSocket.m ================================================================== --- src/OFStreamSocket.m +++ src/OFStreamSocket.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -13,22 +11,27 @@ * 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. */ -#define __NO_EXT_QNX - #include "config.h" +#ifndef _XOPEN_SOURCE_EXTENDED +# 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 "OFInitializationFailedException.h" #import "OFInvalidArgumentException.h" #import "OFListenFailedException.h" @@ -37,22 +40,20 @@ #import "OFOutOfRangeException.h" #import "OFReadFailedException.h" #import "OFSetOptionFailedException.h" #import "OFWriteFailedException.h" -#import "socket_helpers.h" - @implementation OFStreamSocket @dynamic delegate; @synthesize listening = _listening; + (void)initialize { if (self != [OFStreamSocket class]) return; - if (!of_socket_init()) + if (!OFSocketInit()) @throw [OFInitializationFailedException exceptionWithClass: self]; } + (instancetype)socket @@ -68,11 +69,11 @@ if (self.class == [OFStreamSocket class]) { [self doesNotRecognizeSelector: _cmd]; abort(); } - _socket = INVALID_SOCKET; + _socket = OFInvalidSocketHandle; } @catch (id e) { [self release]; @throw e; } @@ -79,59 +80,57 @@ return self; } - (void)dealloc { - if (_socket != INVALID_SOCKET) + if (_socket != OFInvalidSocketHandle) [self close]; [super dealloc]; } - (bool)lowlevelIsAtEndOfStream { - if (_socket == INVALID_SOCKET) + if (_socket == OFInvalidSocketHandle) @throw [OFNotOpenException exceptionWithObject: self]; return _atEndOfStream; } -- (size_t)lowlevelReadIntoBuffer: (void *)buffer - length: (size_t)length +- (size_t)lowlevelReadIntoBuffer: (void *)buffer length: (size_t)length { ssize_t ret; - if (_socket == INVALID_SOCKET) + if (_socket == OFInvalidSocketHandle) @throw [OFNotOpenException exceptionWithObject: self]; #ifndef OF_WINDOWS if ((ret = recv(_socket, buffer, length, 0)) < 0) @throw [OFReadFailedException exceptionWithObject: self requestedLength: length - errNo: of_socket_errno()]; + errNo: OFSocketErrNo()]; #else if (length > INT_MAX) @throw [OFOutOfRangeException exception]; if ((ret = recv(_socket, buffer, (int)length, 0)) < 0) @throw [OFReadFailedException exceptionWithObject: self requestedLength: length - errNo: of_socket_errno()]; + errNo: OFSocketErrNo()]; #endif if (ret == 0) _atEndOfStream = true; return ret; } -- (size_t)lowlevelWriteBuffer: (const void *)buffer - length: (size_t)length +- (size_t)lowlevelWriteBuffer: (const void *)buffer length: (size_t)length { - if (_socket == INVALID_SOCKET) + if (_socket == OFInvalidSocketHandle) @throw [OFNotOpenException exceptionWithObject: self]; #ifndef OF_WINDOWS ssize_t bytesWritten; @@ -141,11 +140,11 @@ if ((bytesWritten = send(_socket, (void *)buffer, length, 0)) < 0) @throw [OFWriteFailedException exceptionWithObject: self requestedLength: length bytesWritten: 0 - errNo: of_socket_errno()]; + errNo: OFSocketErrNo()]; #else int bytesWritten; if (length > INT_MAX) @throw [OFOutOfRangeException exception]; @@ -153,29 +152,29 @@ if ((bytesWritten = send(_socket, buffer, (int)length, 0)) < 0) @throw [OFWriteFailedException exceptionWithObject: self requestedLength: length bytesWritten: 0 - errNo: of_socket_errno()]; + errNo: OFSocketErrNo()]; #endif return (size_t)bytesWritten; } #if defined(OF_WINDOWS) || defined(OF_AMIGAOS) - (void)setCanBlock: (bool)canBlock { # ifdef OF_WINDOWS - u_long v = canBlock; + u_long v = !canBlock; # else - char v = canBlock; + char v = !canBlock; # endif if (ioctlsocket(_socket, FIONBIO, &v) == SOCKET_ERROR) @throw [OFSetOptionFailedException exceptionWithObject: self - errNo: of_socket_errno()]; + errNo: OFSocketErrNo()]; _canBlock = canBlock; } #endif @@ -182,11 +181,11 @@ - (int)fileDescriptorForReading { #ifndef OF_WINDOWS return _socket; #else - if (_socket == INVALID_SOCKET) + if (_socket == OFInvalidSocketHandle) return -1; if (_socket > INT_MAX) @throw [OFOutOfRangeException exception]; @@ -197,11 +196,11 @@ - (int)fileDescriptorForWriting { #ifndef OF_WINDOWS return _socket; #else - if (_socket == INVALID_SOCKET) + if (_socket == OFInvalidSocketHandle) return -1; if (_socket > INT_MAX) @throw [OFOutOfRangeException exception]; @@ -215,11 +214,11 @@ int errNo; socklen_t len = sizeof(errNo); if (getsockopt(_socket, SOL_SOCKET, SO_ERROR, (char *)&errNo, &len) != 0) - return of_socket_errno(); + return OFSocketErrNo(); return errNo; } #endif @@ -228,18 +227,18 @@ [self listenWithBacklog: SOMAXCONN]; } - (void)listenWithBacklog: (int)backlog { - if (_socket == INVALID_SOCKET) + if (_socket == OFInvalidSocketHandle) @throw [OFNotOpenException exceptionWithObject: self]; if (listen(_socket, backlog) == -1) @throw [OFListenFailedException exceptionWithSocket: self backlog: backlog - errNo: of_socket_errno()]; + errNo: OFSocketErrNo()]; _listening = true; } - (instancetype)accept @@ -256,28 +255,29 @@ #if defined(HAVE_PACCEPT) && defined(SOCK_CLOEXEC) if ((client->_socket = paccept(_socket, &client->_remoteAddress.sockaddr.sockaddr, &client->_remoteAddress.length, NULL, SOCK_CLOEXEC)) == - INVALID_SOCKET) + OFInvalidSocketHandle) @throw [OFAcceptFailedException exceptionWithSocket: self - errNo: of_socket_errno()]; + errNo: OFSocketErrNo()]; #elif defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) if ((client->_socket = accept4(_socket, &client->_remoteAddress.sockaddr.sockaddr, - &client->_remoteAddress.length, SOCK_CLOEXEC)) == INVALID_SOCKET) + &client->_remoteAddress.length, SOCK_CLOEXEC)) == + OFInvalidSocketHandle) @throw [OFAcceptFailedException exceptionWithSocket: self - errNo: of_socket_errno()]; + errNo: OFSocketErrNo()]; #else if ((client->_socket = accept(_socket, &client->_remoteAddress.sockaddr.sockaddr, - &client->_remoteAddress.length)) == INVALID_SOCKET) + &client->_remoteAddress.length)) == OFInvalidSocketHandle) @throw [OFAcceptFailedException exceptionWithSocket: self - errNo: of_socket_errno()]; + 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 @@ -286,64 +286,67 @@ assert(client->_remoteAddress.length <= (socklen_t)sizeof(client->_remoteAddress.sockaddr)); switch (client->_remoteAddress.sockaddr.sockaddr.sa_family) { case AF_INET: - client->_remoteAddress.family = OF_SOCKET_ADDRESS_FAMILY_IPV4; + client->_remoteAddress.family = OFSocketAddressFamilyIPv4; break; #ifdef OF_HAVE_IPV6 case AF_INET6: - client->_remoteAddress.family = OF_SOCKET_ADDRESS_FAMILY_IPV6; + client->_remoteAddress.family = OFSocketAddressFamilyIPv6; break; #endif #ifdef OF_HAVE_IPX case AF_IPX: - client->_remoteAddress.family = OF_SOCKET_ADDRESS_FAMILY_IPX; + client->_remoteAddress.family = OFSocketAddressFamilyIPX; + break; +#endif +#ifdef OF_HAVE_UNIX_SOCKETS + case AF_UNIX: + client->_remoteAddress.family = OFSocketAddressFamilyUNIX; break; #endif default: - client->_remoteAddress.family = - OF_SOCKET_ADDRESS_FAMILY_UNKNOWN; + client->_remoteAddress.family = OFSocketAddressFamilyUnknown; break; } return client; } - (void)asyncAccept { - [self asyncAcceptWithRunLoopMode: of_run_loop_mode_default]; + [self asyncAcceptWithRunLoopMode: OFDefaultRunLoopMode]; } -- (void)asyncAcceptWithRunLoopMode: (of_run_loop_mode_t)runLoopMode +- (void)asyncAcceptWithRunLoopMode: (OFRunLoopMode)runLoopMode { [OFRunLoop of_addAsyncAcceptForSocket: self mode: runLoopMode block: NULL delegate: _delegate]; } #ifdef OF_HAVE_BLOCKS -- (void)asyncAcceptWithBlock: (of_stream_socket_async_accept_block_t)block +- (void)asyncAcceptWithBlock: (OFStreamSocketAsyncAcceptBlock)block { - [self asyncAcceptWithRunLoopMode: of_run_loop_mode_default - block: block]; + [self asyncAcceptWithRunLoopMode: OFDefaultRunLoopMode block: block]; } -- (void)asyncAcceptWithRunLoopMode: (of_run_loop_mode_t)runLoopMode - block: (of_stream_socket_async_accept_block_t)block +- (void)asyncAcceptWithRunLoopMode: (OFRunLoopMode)runLoopMode + block: (OFStreamSocketAsyncAcceptBlock)block { [OFRunLoop of_addAsyncAcceptForSocket: self mode: runLoopMode block: block delegate: nil]; } #endif -- (const of_socket_address_t *)remoteAddress +- (const OFSocketAddress *)remoteAddress { - if (_socket == INVALID_SOCKET) + if (_socket == OFInvalidSocketHandle) @throw [OFNotOpenException exceptionWithObject: self]; if (_remoteAddress.length == 0) @throw [OFInvalidArgumentException exception]; @@ -353,19 +356,19 @@ return &_remoteAddress; } - (void)close { - if (_socket == INVALID_SOCKET) + if (_socket == OFInvalidSocketHandle) @throw [OFNotOpenException exceptionWithObject: self]; _listening = false; memset(&_remoteAddress, 0, sizeof(_remoteAddress)); closesocket(_socket); - _socket = INVALID_SOCKET; + _socket = OFInvalidSocketHandle; _atEndOfStream = false; [super close]; } @end DELETED src/OFString+CryptoHashing.h Index: src/OFString+CryptoHashing.h ================================================================== --- src/OFString+CryptoHashing.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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_CryptoHashing_reference; -#ifdef __cplusplus -} -#endif - -@interface OFString (CryptoHashing) -/** - * @brief The MD5 hash of the string as a string. - */ -@property (readonly, nonatomic) OFString *MD5Hash; - -/** - * @brief The RIPEMD-160 hash of the string as a string. - */ -@property (readonly, nonatomic) OFString *RIPEMD160Hash; - -/** - * @brief The SHA-1 hash of the string as a string. - */ -@property (readonly, nonatomic) OFString *SHA1Hash; - -/** - * @brief The SHA-224 hash of the string as a string. - */ -@property (readonly, nonatomic) OFString *SHA224Hash; - -/** - * @brief The SHA-256 hash of the string as a string. - */ -@property (readonly, nonatomic) OFString *SHA256Hash; - -/** - * @brief The SHA-384 hash of the string as a string. - */ -@property (readonly, nonatomic) OFString *SHA384Hash; - -/** - * @brief The SHA-512 hash of the string as a string. - */ -@property (readonly, nonatomic) OFString *SHA512Hash; -@end - -OF_ASSUME_NONNULL_END DELETED src/OFString+CryptoHashing.m Index: src/OFString+CryptoHashing.m ================================================================== --- src/OFString+CryptoHashing.m +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "OFCryptoHash.h" -#import "OFMD5Hash.h" -#import "OFRIPEMD160Hash.h" -#import "OFSHA1Hash.h" -#import "OFSHA224Hash.h" -#import "OFSHA256Hash.h" -#import "OFSHA384Hash.h" -#import "OFSHA512Hash.h" - -int _OFString_CryptoHashing_reference; - -@implementation OFString (CryptoHashing) -- (OFString *)of_cryptoHashWithClass: (Class )class -{ - void *pool = objc_autoreleasePoolPush(); - id hash = [class - cryptoHashWithAllowsSwappableMemory: true]; - size_t digestSize = [class digestSize]; - const unsigned char *digest; - char cString[digestSize * 2]; - - [hash updateWithBuffer: self.UTF8String - length: self.UTF8StringLength]; - digest = hash.digest; - - for (size_t i = 0; i < digestSize; i++) { - uint8_t high, low; - - high = digest[i] >> 4; - low = digest[i] & 0x0F; - - cString[i * 2] = (high > 9 ? high - 10 + 'a' : high + '0'); - cString[i * 2 + 1] = (low > 9 ? low - 10 + 'a' : low + '0'); - } - - objc_autoreleasePoolPop(pool); - - return [OFString stringWithCString: cString - encoding: OF_STRING_ENCODING_ASCII - length: digestSize * 2]; -} - -- (OFString *)MD5Hash -{ - return [self of_cryptoHashWithClass: [OFMD5Hash class]]; -} - -- (OFString *)RIPEMD160Hash -{ - return [self of_cryptoHashWithClass: [OFRIPEMD160Hash class]]; -} - -- (OFString *)SHA1Hash -{ - return [self of_cryptoHashWithClass: [OFSHA1Hash class]]; -} - -- (OFString *)SHA224Hash -{ - return [self of_cryptoHashWithClass: [OFSHA224Hash class]]; -} - -- (OFString *)SHA256Hash -{ - return [self of_cryptoHashWithClass: [OFSHA256Hash class]]; -} - -- (OFString *)SHA384Hash -{ - return [self of_cryptoHashWithClass: [OFSHA384Hash class]]; -} - -- (OFString *)SHA512Hash -{ - return [self of_cryptoHashWithClass: [OFSHA512Hash class]]; -} -@end ADDED src/OFString+CryptographicHashing.h Index: src/OFString+CryptographicHashing.h ================================================================== --- /dev/null +++ src/OFString+CryptographicHashing.h @@ -0,0 +1,65 @@ +/* + * 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_CryptographicHashing_reference; +#ifdef __cplusplus +} +#endif + +@interface OFString (CryptographicHashing) +/** + * @brief The MD5 hash of the string as a string. + */ +@property (readonly, nonatomic) OFString *stringByMD5Hashing; + +/** + * @brief The RIPEMD-160 hash of the string as a string. + */ +@property (readonly, nonatomic) OFString *stringByRIPEMD160Hashing; + +/** + * @brief The SHA-1 hash of the string as a string. + */ +@property (readonly, nonatomic) OFString *stringBySHA1Hashing; + +/** + * @brief The SHA-224 hash of the string as a string. + */ +@property (readonly, nonatomic) OFString *stringBySHA224Hashing; + +/** + * @brief The SHA-256 hash of the string as a string. + */ +@property (readonly, nonatomic) OFString *stringBySHA256Hashing; + +/** + * @brief The SHA-384 hash of the string as a string. + */ +@property (readonly, nonatomic) OFString *stringBySHA384Hashing; + +/** + * @brief The SHA-512 hash of the string as a string. + */ +@property (readonly, nonatomic) OFString *stringBySHA512Hashing; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFString+CryptographicHashing.m Index: src/OFString+CryptographicHashing.m ================================================================== --- /dev/null +++ src/OFString+CryptographicHashing.m @@ -0,0 +1,96 @@ +/* + * 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 "OFCryptographicHash.h" +#import "OFMD5Hash.h" +#import "OFRIPEMD160Hash.h" +#import "OFSHA1Hash.h" +#import "OFSHA224Hash.h" +#import "OFSHA256Hash.h" +#import "OFSHA384Hash.h" +#import "OFSHA512Hash.h" + +int _OFString_CryptographicHashing_reference; + +@implementation OFString (CryptographicHashing) +static OFString * +stringByHashing(Class class, OFString *self) +{ + void *pool = objc_autoreleasePoolPush(); + id hash = + [class hashWithAllowsSwappableMemory: true]; + size_t digestSize = [class digestSize]; + const unsigned char *digest; + char cString[digestSize * 2]; + + [hash updateWithBuffer: self.UTF8String length: self.UTF8StringLength]; + [hash calculate]; + digest = hash.digest; + + for (size_t i = 0; i < digestSize; i++) { + uint8_t high, low; + + high = digest[i] >> 4; + low = digest[i] & 0x0F; + + cString[i * 2] = (high > 9 ? high - 10 + 'a' : high + '0'); + cString[i * 2 + 1] = (low > 9 ? low - 10 + 'a' : low + '0'); + } + + objc_autoreleasePoolPop(pool); + + return [OFString stringWithCString: cString + encoding: OFStringEncodingASCII + length: digestSize * 2]; +} + +- (OFString *)stringByMD5Hashing +{ + return stringByHashing([OFMD5Hash class], self); +} + +- (OFString *)stringByRIPEMD160Hashing +{ + return stringByHashing([OFRIPEMD160Hash class], self); +} + +- (OFString *)stringBySHA1Hashing +{ + return stringByHashing([OFSHA1Hash class], self); +} + +- (OFString *)stringBySHA224Hashing +{ + return stringByHashing([OFSHA224Hash class], self); +} + +- (OFString *)stringBySHA256Hashing +{ + return stringByHashing([OFSHA256Hash class], self); +} + +- (OFString *)stringBySHA384Hashing +{ + return stringByHashing([OFSHA384Hash class], self); +} + +- (OFString *)stringBySHA512Hashing +{ + return stringByHashing([OFSHA512Hash class], self); +} +@end Index: src/OFString+JSONParsing.h ================================================================== --- src/OFString+JSONParsing.h +++ src/OFString+JSONParsing.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFString+JSONParsing.m ================================================================== --- src/OFString+JSONParsing.m +++ src/OFString+JSONParsing.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -29,10 +27,14 @@ #import "OFDictionary.h" #import "OFNumber.h" #import "OFNull.h" #import "OFInvalidJSONException.h" + +#ifndef INFINITY +# define INFINITY __builtin_inf() +#endif int _OFString_JSONParsing_reference; static id nextObject(const char **pointer, const char *stop, size_t *line, size_t depthLimit); @@ -105,14 +107,14 @@ skipWhitespaces(pointer, stop, line); skipComment(pointer, stop, line); } } -static inline of_char16_t +static inline OFChar16 parseUnicodeEscape(const char *pointer, const char *stop) { - of_char16_t ret = 0; + OFChar16 ret = 0; if (pointer + 5 >= stop) return 0xFFFF; if (pointer[0] != '\\' || pointer[1] != 'u') @@ -146,17 +148,17 @@ char delimiter = **pointer; if (++(*pointer) + 1 >= stop) return nil; - buffer = of_malloc(1, stop - *pointer); + buffer = OFAllocMemory(stop - *pointer, 1); while (*pointer < stop) { /* Parse escape codes */ if (**pointer == '\\') { if (++(*pointer) >= stop) { - of_free(buffer); + OFFreeMemory(buffer); return nil; } switch (**pointer) { case '"': @@ -185,32 +187,31 @@ buffer[i++] = '\t'; (*pointer)++; break; /* Parse Unicode escape sequence */ case 'u':; - of_char16_t c1, c2; - of_unichar_t c; + OFChar16 c1, c2; + OFUnichar c; size_t l; c1 = parseUnicodeEscape(*pointer - 1, stop); if (c1 == 0xFFFF) { - of_free(buffer); + OFFreeMemory(buffer); return nil; } /* Low surrogate */ if ((c1 & 0xFC00) == 0xDC00) { - of_free(buffer); + OFFreeMemory(buffer); return nil; } /* Normal character */ if ((c1 & 0xFC00) != 0xD800) { - l = of_string_utf8_encode(c1, - buffer + i); + l = OFUTF8StringEncode(c1, buffer + i); if (l == 0) { - of_free(buffer); + OFFreeMemory(buffer); return nil; } i += l; *pointer += 5; @@ -223,20 +224,20 @@ * surrogate and now need to get the other one * in order to produce UTF-8 and not CESU-8. */ c2 = parseUnicodeEscape(*pointer + 5, stop); if (c2 == 0xFFFF) { - of_free(buffer); + OFFreeMemory(buffer); return nil; } c = (((c1 & 0x3FF) << 10) | (c2 & 0x3FF)) + 0x10000; - l = of_string_utf8_encode(c, buffer + i); + l = OFUTF8StringEncode(c, buffer + i); if (l == 0) { - of_free(buffer); + OFFreeMemory(buffer); return nil; } i += l; *pointer += 11; @@ -254,11 +255,11 @@ case '\n': (*pointer)++; (*line)++; break; default: - of_free(buffer); + OFFreeMemory(buffer); return nil; } /* End of string found */ } else if (**pointer == delimiter) { OFString *ret; @@ -265,38 +266,38 @@ @try { ret = [OFString stringWithUTF8String: buffer length: i]; } @finally { - of_free(buffer); + OFFreeMemory(buffer); } (*pointer)++; return ret; /* Newlines in strings are disallowed */ } else if (**pointer == '\n' || **pointer == '\r') { (*line)++; - of_free(buffer); + OFFreeMemory(buffer); return nil; } else { buffer[i++] = **pointer; (*pointer)++; } } - of_free(buffer); + OFFreeMemory(buffer); return nil; } static inline OFString * parseIdentifier(const char **pointer, const char *stop) { char *buffer; size_t i = 0; - buffer = of_malloc(1, stop - *pointer); + buffer = OFAllocMemory(stop - *pointer, 1); while (*pointer < stop) { if ((**pointer >= 'a' && **pointer <= 'z') || (**pointer >= 'A' && **pointer <= 'Z') || (**pointer >= '0' && **pointer <= '9') || @@ -303,36 +304,36 @@ **pointer == '_' || **pointer == '$' || (**pointer & 0x80)) { buffer[i++] = **pointer; (*pointer)++; } else if (**pointer == '\\') { - of_char16_t c1, c2; - of_unichar_t c; + OFChar16 c1, c2; + OFUnichar c; size_t l; if (++(*pointer) >= stop || **pointer != 'u') { - of_free(buffer); + OFFreeMemory(buffer); return nil; } c1 = parseUnicodeEscape(*pointer - 1, stop); if (c1 == 0xFFFF) { - of_free(buffer); + OFFreeMemory(buffer); return nil; } /* Low surrogate */ if ((c1 & 0xFC00) == 0xDC00) { - of_free(buffer); + OFFreeMemory(buffer); return nil; } /* Normal character */ if ((c1 & 0xFC00) != 0xD800) { - l = of_string_utf8_encode(c1, buffer + i); + l = OFUTF8StringEncode(c1, buffer + i); if (l == 0) { - of_free(buffer); + OFFreeMemory(buffer); return nil; } i += l; *pointer += 5; @@ -345,37 +346,37 @@ * surrogate and now need to get the other one in order * to produce UTF-8 and not CESU-8. */ c2 = parseUnicodeEscape(*pointer + 5, stop); if (c2 == 0xFFFF) { - of_free(buffer); + OFFreeMemory(buffer); return nil; } c = (((c1 & 0x3FF) << 10) | (c2 & 0x3FF)) + 0x10000; - l = of_string_utf8_encode(c, buffer + i); + l = OFUTF8StringEncode(c, buffer + i); if (l == 0) { - of_free(buffer); + OFFreeMemory(buffer); return nil; } i += l; *pointer += 11; } else { OFString *ret; if (i == 0 || (buffer[0] >= '0' && buffer[0] <= '9')) { - of_free(buffer); + OFFreeMemory(buffer); return nil; } @try { ret = [OFString stringWithUTF8String: buffer length: i]; } @finally { - of_free(buffer); + OFFreeMemory(buffer); } return ret; } } @@ -382,11 +383,11 @@ /* * It is never possible to end with an identifier, thus we should never * reach stop. */ - of_free(buffer); + OFFreeMemory(buffer); return nil; } static inline OFMutableArray * parseArray(const char **pointer, const char *stop, size_t *line, @@ -500,12 +501,11 @@ object = nextObject(pointer, stop, line, depthLimit); if (object == nil) return nil; - [dictionary setObject: object - forKey: key]; + [dictionary setObject: object forKey: key]; skipWhitespacesAndComments(pointer, stop, line); if (*pointer >= stop) return nil; @@ -546,12 +546,11 @@ break; } } - string = [[OFString alloc] initWithUTF8String: *pointer - length: i]; + string = [[OFString alloc] initWithUTF8String: *pointer length: i]; *pointer += i; @try { if (hasDecimal) number = [OFNumber numberWithDouble: Index: src/OFString+PathAdditions.h ================================================================== --- src/OFString+PathAdditions.h +++ src/OFString+PathAdditions.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -17,16 +15,10 @@ #import "OFString.h" OF_ASSUME_NONNULL_BEGIN -#ifdef OF_AMIGAOS -# define OF_PATH_CURRENT_DIRECTORY @"" -#else -# define OF_PATH_CURRENT_DIRECTORY @"." -#endif - #ifdef __cplusplus extern "C" { #endif extern int _OFString_PathAdditions_reference; #ifdef __cplusplus Index: src/OFString+PathAdditions.m ================================================================== --- src/OFString+PathAdditions.m +++ src/OFString+PathAdditions.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -17,14 +15,14 @@ #include "config.h" #include "platform.h" -#if defined(OF_WINDOWS) || defined(OF_MSDOS) -# import "platform/windows/OFString+PathAdditions.m" +#if defined(OF_WINDOWS) || defined(OF_MSDOS) || defined(OF_MINT) +# import "platform/Windows/OFString+PathAdditions.m" #elif defined(OF_AMIGAOS) -# import "platform/amiga/OFString+PathAdditions.m" +# import "platform/AmigaOS/OFString+PathAdditions.m" #elif defined(OF_NINTENDO_3DS) || defined(OF_WII) # import "platform/libfat/OFString+PathAdditions.m" #else -# import "platform/posix/OFString+PathAdditions.m" +# import "platform/POSIX/OFString+PathAdditions.m" #endif Index: src/OFString+PropertyListParsing.h ================================================================== --- src/OFString+PropertyListParsing.h +++ src/OFString+PropertyListParsing.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFString+PropertyListParsing.m ================================================================== --- src/OFString+PropertyListParsing.m +++ src/OFString+PropertyListParsing.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -66,12 +64,11 @@ (object = [enumerator nextObject])) { if (key.namespace != nil || key.attributes.count != 0 || ![key.name isEqual: @"key"]) @throw [OFInvalidFormatException exception]; - [ret setObject: parseElement(object) - forKey: key.stringValue]; + [ret setObject: parseElement(object) forKey: key.stringValue]; } [ret makeImmutable]; objc_autoreleasePoolPop(pool); Index: src/OFString+Serialization.h ================================================================== --- src/OFString+Serialization.h +++ src/OFString+Serialization.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFString+Serialization.m ================================================================== --- src/OFString+Serialization.m +++ src/OFString+Serialization.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -54,11 +52,11 @@ if (version.unsignedLongLongValue != 1) @throw [OFUnsupportedVersionException exceptionWithVersion: version]; - elements = [root elementsForNamespace: OF_SERIALIZATION_NS]; + elements = [root elementsForNamespace: OFSerializationNS]; if (elements.count != 1) @throw [OFInvalidArgumentException exception]; object = [[elements.firstObject objectByDeserializing] retain]; Index: src/OFString+URLEncoding.h ================================================================== --- src/OFString+URLEncoding.h +++ src/OFString+URLEncoding.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFString+URLEncoding.m ================================================================== --- src/OFString+URLEncoding.m +++ src/OFString+URLEncoding.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -34,28 +32,27 @@ - (OFString *)stringByURLEncodingWithAllowedCharacters: (OFCharacterSet *)allowedCharacters { OFMutableString *ret = [OFMutableString string]; void *pool = objc_autoreleasePoolPush(); - const of_unichar_t *characters = self.characters; + const OFUnichar *characters = self.characters; size_t length = self.length; - bool (*characterIsMember)(id, SEL, of_unichar_t) = - (bool (*)(id, SEL, of_unichar_t))[allowedCharacters + bool (*characterIsMember)(id, SEL, OFUnichar) = + (bool (*)(id, SEL, OFUnichar))[allowedCharacters methodForSelector: @selector(characterIsMember:)]; for (size_t i = 0; i < length; i++) { - of_unichar_t c = characters[i]; + OFUnichar c = characters[i]; if (characterIsMember(allowedCharacters, @selector(characterIsMember:), c)) - [ret appendCharacters: &c - length: 1]; + [ret appendCharacters: &c length: 1]; else { char buffer[4]; size_t bufferLen; - if ((bufferLen = of_string_utf8_encode(c, buffer)) == 0) + if ((bufferLen = OFUTF8StringEncode(c, buffer)) == 0) @throw [OFInvalidEncodingException exception]; for (size_t j = 0; j < bufferLen; j++) { unsigned char byte = buffer[j]; unsigned char high = byte >> 4; @@ -66,12 +63,11 @@ escaped[1] = (high > 9 ? high - 10 + 'A' : high + '0'); escaped[2] = (low > 9 ? low - 10 + 'A' : low + '0'); - [ret appendUTF8String: escaped - length: 3]; + [ret appendUTF8String: escaped length: 3]; } } } objc_autoreleasePoolPop(pool); @@ -86,12 +82,13 @@ size_t length = self.UTF8StringLength; char *retCString; char byte = 0; int state = 0; size_t i = 0; + OFString *ret; - retCString = of_malloc(1, length + 1); + retCString = OFAllocMemory(length + 1, 1); while (length--) { char c = *string++; switch (state) { @@ -110,11 +107,11 @@ else if (c >= 'A' && c <= 'F') byte += (c - 'A' + 10) << shift; else if (c >= 'a' && c <= 'f') byte += (c - 'a' + 10) << shift; else { - of_free(retCString); + OFFreeMemory(retCString); @throw [OFInvalidFormatException exception]; } if (++state == 3) { retCString[i++] = byte; @@ -128,20 +125,27 @@ retCString[i] = '\0'; objc_autoreleasePoolPop(pool); if (state != 0) { - of_free(retCString); + OFFreeMemory(retCString); @throw [OFInvalidFormatException exception]; } @try { - retCString = of_realloc(retCString, 1, i + 1); + retCString = OFResizeMemory(retCString, 1, i + 1); } @catch (OFOutOfMemoryException *e) { /* We don't care if it fails, as we only made it smaller. */ } - return [OFString stringWithUTF8StringNoCopy: retCString - length: i - freeWhenDone: true]; + @try { + ret = [OFString stringWithUTF8StringNoCopy: retCString + length: i + freeWhenDone: true]; + } @catch (id e) { + OFFreeMemory(retCString); + @throw e; + } + + return ret; } @end Index: src/OFString+XMLEscaping.h ================================================================== --- src/OFString+XMLEscaping.h +++ src/OFString+XMLEscaping.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFString+XMLEscaping.m ================================================================== --- src/OFString+XMLEscaping.m +++ src/OFString+XMLEscaping.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -40,15 +38,11 @@ string = self.UTF8String; length = self.UTF8StringLength; j = 0; retLength = length; - - /* - * We can't use allocMemoryWithSize: here as it might be a @"" literal - */ - retCString = of_malloc(1, retLength); + retCString = OFAllocMemory(retLength, 1); for (size_t i = 0; i < length; i++) { switch (string[i]) { case '<': append = "<"; @@ -79,14 +73,14 @@ appendLen = 0; } if (append != NULL) { @try { - retCString = of_realloc(retCString, 1, + retCString = OFResizeMemory(retCString, 1, retLength + appendLen); } @catch (id e) { - of_free(retCString); + OFFreeMemory(retCString); @throw e; } retLength += appendLen - 1; memcpy(retCString + j, append, appendLen); @@ -100,10 +94,10 @@ @try { ret = [OFString stringWithUTF8String: retCString length: retLength]; } @finally { - of_free(retCString); + OFFreeMemory(retCString); } return ret; } @end Index: src/OFString+XMLUnescaping.h ================================================================== --- src/OFString+XMLUnescaping.h +++ src/OFString+XMLUnescaping.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -36,12 +34,12 @@ * * @param string The XML string which contains an unknown entity * @param entity The XML entity which is unknown * @return A replacement string for the unknown entity */ -typedef OFString *_Nullable (^of_string_xml_unescaping_block_t)( - OFString *string, OFString *entity); +typedef OFString *_Nullable (^OFStringXMLUnescapingBlock)(OFString *string, + OFString *entity); #endif /** * @protocol OFStringXMLUnescapingDelegate OFString.h ObjFW/OFString.h * @@ -85,11 +83,10 @@ * @brief Unescapes XML in the string and uses the specified block for unknown * entities. * * @param block A block which handles unknown entities */ -- (OFString *)stringByXMLUnescapingWithBlock: - (of_string_xml_unescaping_block_t)block; +- (OFString *)stringByXMLUnescapingWithBlock: (OFStringXMLUnescapingBlock)block; #endif @end OF_ASSUME_NONNULL_END Index: src/OFString+XMLUnescaping.m ================================================================== --- src/OFString+XMLUnescaping.m +++ src/OFString+XMLUnescaping.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -27,11 +25,11 @@ int _OFString_XMLUnescaping_reference; static OF_INLINE OFString * parseNumericEntity(const char *entity, size_t length) { - of_unichar_t c; + OFUnichar c; size_t i; char buffer[5]; if (length == 1 || *entity != '#') return nil; @@ -64,16 +62,15 @@ else return nil; } } - if ((i = of_string_utf8_encode(c, buffer)) == 0) + if ((i = OFUTF8StringEncode(c, buffer)) == 0) return nil; buffer[i] = 0; - return [OFString stringWithUTF8String: buffer - length: i]; + return [OFString stringWithUTF8String: buffer length: i]; } static OFString * parseEntities(OFString *self, id (*lookup)(void *, OFString *, OFString *), void *context) @@ -94,42 +91,40 @@ last = 0; inEntity = false; for (i = 0; i < length; i++) { if (!inEntity && string[i] == '&') { - [ret appendUTF8String: string + last - length: i - last]; - + [ret appendUTF8String: string + last length: i - last]; last = i + 1; inEntity = true; } else if (inEntity && string[i] == ';') { const char *entity = string + last; size_t entityLength = i - last; if (entityLength == 2 && memcmp(entity, "lt", 2) == 0) [ret appendCString: "<" - encoding: OF_STRING_ENCODING_ASCII + encoding: OFStringEncodingASCII length: 1]; else if (entityLength == 2 && memcmp(entity, "gt", 2) == 0) [ret appendCString: ">" - encoding: OF_STRING_ENCODING_ASCII + encoding: OFStringEncodingASCII length: 1]; else if (entityLength == 4 && memcmp(entity, "quot", 4) == 0) [ret appendCString: "\"" - encoding: OF_STRING_ENCODING_ASCII + encoding: OFStringEncodingASCII length: 1]; else if (entityLength == 4 && memcmp(entity, "apos", 4) == 0) [ret appendCString: "'" - encoding: OF_STRING_ENCODING_ASCII + encoding: OFStringEncodingASCII length: 1]; else if (entityLength == 3 && memcmp(entity, "amp", 3) == 0) [ret appendCString: "&" - encoding: OF_STRING_ENCODING_ASCII + encoding: OFStringEncodingASCII length: 1]; else if (entity[0] == '#') { void *pool2; OFString *tmp; @@ -170,13 +165,11 @@ } if (inEntity) @throw [OFInvalidFormatException exception]; - [ret appendUTF8String: string + last - length: i - last]; - + [ret appendUTF8String: string + last length: i - last]; [ret makeImmutable]; objc_autoreleasePoolPop(pool); return ret; @@ -188,19 +181,18 @@ id delegate = context; if (delegate == nil) return nil; - return [delegate string: self - containsUnknownEntityNamed: entity]; + return [delegate string: self containsUnknownEntityNamed: entity]; } #ifdef OF_HAVE_BLOCKS static id lookupUsingBlock(void *context, OFString *self, OFString *entity) { - of_string_xml_unescaping_block_t block = context; + OFStringXMLUnescapingBlock block = context; if (block == NULL) return nil; return block(self, entity); @@ -218,12 +210,11 @@ { return parseEntities(self, lookupUsingDelegate, delegate); } #ifdef OF_HAVE_BLOCKS -- (OFString *)stringByXMLUnescapingWithBlock: - (of_string_xml_unescaping_block_t)block +- (OFString *)stringByXMLUnescapingWithBlock: (OFStringXMLUnescapingBlock)block { return parseEntities(self, lookupUsingBlock, block); } #endif @end Index: src/OFString.h ================================================================== --- src/OFString.h +++ src/OFString.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -54,72 +52,87 @@ #else typedef void OFString; #endif #if defined(__cplusplus) && __cplusplus >= 201103L -typedef char16_t of_char16_t; -typedef char32_t of_char32_t; +typedef char16_t OFChar16; +typedef char32_t OFChar32; #else -typedef uint_least16_t of_char16_t; -typedef uint_least32_t of_char32_t; +typedef uint_least16_t OFChar16; +typedef uint_least32_t OFChar32; #endif -typedef of_char32_t of_unichar_t; +typedef OFChar32 OFUnichar; /** * @brief The encoding of a string. */ -typedef enum of_string_encoding_t { +typedef enum { /* * UTF-8 *has* to be 0, so that if the current @ref OFLocale is * `nil`, `[OFLocale encoding]` returns UTF-8. */ /** UTF-8 */ - OF_STRING_ENCODING_UTF_8, + OFStringEncodingUTF8, /** ASCII */ - OF_STRING_ENCODING_ASCII, + OFStringEncodingASCII, /** ISO 8859-1 */ - OF_STRING_ENCODING_ISO_8859_1, + OFStringEncodingISO8859_1, /** ISO 8859-2 */ - OF_STRING_ENCODING_ISO_8859_2, + OFStringEncodingISO8859_2, /** ISO 8859-3 */ - OF_STRING_ENCODING_ISO_8859_3, + OFStringEncodingISO8859_3, /** ISO 8859-15 */ - OF_STRING_ENCODING_ISO_8859_15, + OFStringEncodingISO8859_15, /** Windows-1251 */ - OF_STRING_ENCODING_WINDOWS_1251, + OFStringEncodingWindows1251, /** Windows-1252 */ - OF_STRING_ENCODING_WINDOWS_1252, + OFStringEncodingWindows1252, /** Codepage 437 */ - OF_STRING_ENCODING_CODEPAGE_437, + OFStringEncodingCodepage437, /** Codepage 850 */ - OF_STRING_ENCODING_CODEPAGE_850, + OFStringEncodingCodepage850, /** Codepage 858 */ - OF_STRING_ENCODING_CODEPAGE_858, + OFStringEncodingCodepage858, /** Mac OS Roman */ - OF_STRING_ENCODING_MAC_ROMAN, + OFStringEncodingMacRoman, /** KOI8-R */ - OF_STRING_ENCODING_KOI8_R, + OFStringEncodingKOI8R, /** KOI8-U */ - OF_STRING_ENCODING_KOI8_U, + OFStringEncodingKOI8U, /** Try to automatically detect the encoding */ - OF_STRING_ENCODING_AUTODETECT = 0xFF -} of_string_encoding_t; + OFStringEncodingAutodetect = 0xFF +} OFStringEncoding; -enum { - OF_STRING_SEARCH_BACKWARDS = 1, - OF_STRING_SKIP_EMPTY = 2 -}; +/** + * @brief Options for searching in strings. + * + * This is a bit mask. + */ +typedef enum { + /** Search backwards in the string */ + OFStringSearchBackwards = 1 +} OFStringSearchOptions; + +/** + * @brief Options for separating strings. + * + * This is a bit mask. + */ +typedef enum { + /** Skip empty components */ + OFStringSkipEmptyComponents = 1 +} OFStringSeparationOptions; #ifdef OF_HAVE_BLOCKS /** * @brief A block for enumerating the lines of a string. * * @param line The current line * @param stop A pointer to a variable that can be set to true to stop the * enumeration */ -typedef void (^of_string_line_enumeration_block_t)(OFString *line, bool *stop); +typedef void (^OFStringLineEnumerationBlock)(OFString *line, bool *stop); #endif #ifdef __OBJC__ @class OFArray OF_GENERIC(ObjectType); @class OFCharacterSet; @@ -217,21 +230,21 @@ * * 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 of_unichar_t *characters +@property (readonly, nonatomic) const OFUnichar *characters OF_RETURNS_INNER_POINTER; /** * @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 * use the result outside the scope of the current autorelease pool, you have to * copy it. */ -@property (readonly, nonatomic) const of_char16_t *UTF16String +@property (readonly, nonatomic) const OFChar16 *UTF16String OF_RETURNS_INNER_POINTER; /** * @brief The length of the string in UTF-16 characters. */ @@ -242,11 +255,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 of_char32_t *UTF32String +@property (readonly, nonatomic) const OFChar32 *UTF32String OF_RETURNS_INNER_POINTER; /** * @brief The string with leading whitespaces deleted. */ @@ -311,12 +324,12 @@ /** * @brief Creates a new OFString from a UTF-8 encoded C string without copying * the string, if possible. * - * If initialization fails for whatever reason, the passed C string is free'd - * if `freeWhenDone` is true. + * If initialization fails for whatever reason, the passed C string is *not* + * free'd if `freeWhenDone` is true. * * @note OFMutableString always creates a copy! * * @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 @@ -328,12 +341,12 @@ /** * @brief Creates a new OFString from a UTF-8 encoded C string with the * specified length without copying the string, if possible. * - * If initialization fails for whatever reason, the passed C string is free'd - * if `freeWhenDone` is true. + * If initialization fails for whatever reason, the passed C string is *not* + * free'd if `freeWhenDone` is true. * * @note OFMutableString always creates a copy! * * @param UTF8String A UTF-8 encoded C string to initialize the OFString with * @param UTF8StringLength The length of the UTF-8 encoded C string @@ -351,11 +364,11 @@ * @param cString A C string to initialize the OFString with * @param encoding The encoding of the C string * @return A new autoreleased OFString */ + (instancetype)stringWithCString: (const char *)cString - encoding: (of_string_encoding_t)encoding; + encoding: (OFStringEncoding)encoding; /** * @brief Creates a new OFString from a C string with the specified encoding * and length. * @@ -363,11 +376,11 @@ * @param encoding The encoding of the C string * @param cStringLength The length of the C string * @return A new autoreleased OFString */ + (instancetype)stringWithCString: (const char *)cString - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding length: (size_t)cStringLength; /** * @brief Creates a new OFString from OFData with the specified encoding. * @@ -374,11 +387,11 @@ * @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 */ + (instancetype)stringWithData: (OFData *)data - encoding: (of_string_encoding_t)encoding; + encoding: (OFStringEncoding)encoding; /** * @brief Creates a new OFString from another string. * * @param string A string to initialize the OFString with @@ -392,30 +405,30 @@ * * @param characters An array of Unicode characters * @param length The length of the Unicode character array * @return A new autoreleased OFString */ -+ (instancetype)stringWithCharacters: (const of_unichar_t *)characters ++ (instancetype)stringWithCharacters: (const OFUnichar *)characters length: (size_t)length; /** * @brief Creates a new OFString from a UTF-16 encoded string. * * @param string The UTF-16 string * @return A new autoreleased OFString */ -+ (instancetype)stringWithUTF16String: (const of_char16_t *)string; ++ (instancetype)stringWithUTF16String: (const OFChar16 *)string; /** * @brief Creates a new OFString from a UTF-16 encoded string with the * specified length. * * @param string The UTF-16 string * @param length The length of the UTF-16 string * @return A new autoreleased OFString */ -+ (instancetype)stringWithUTF16String: (const of_char16_t *)string ++ (instancetype)stringWithUTF16String: (const OFChar16 *)string length: (size_t)length; /** * @brief Creates a new OFString from a UTF-16 encoded string, assuming the * specified byte order if no byte order mark is found. @@ -422,12 +435,12 @@ * * @param string The UTF-16 string * @param byteOrder The byte order to assume if there is no byte order mark * @return A new autoreleased OFString */ -+ (instancetype)stringWithUTF16String: (const of_char16_t *)string - byteOrder: (of_byte_order_t)byteOrder; ++ (instancetype)stringWithUTF16String: (const OFChar16 *)string + byteOrder: (OFByteOrder)byteOrder; /** * @brief Creates a new OFString from a UTF-16 encoded string with the * specified length, assuming the specified byte order if no byte order * mark is found. @@ -435,31 +448,31 @@ * @param string The 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 */ -+ (instancetype)stringWithUTF16String: (const of_char16_t *)string ++ (instancetype)stringWithUTF16String: (const OFChar16 *)string length: (size_t)length - byteOrder: (of_byte_order_t)byteOrder; + byteOrder: (OFByteOrder)byteOrder; /** * @brief Creates a new OFString from a UTF-32 encoded string. * * @param string The UTF-32 string * @return A new autoreleased OFString */ -+ (instancetype)stringWithUTF32String: (const of_char32_t *)string; ++ (instancetype)stringWithUTF32String: (const OFChar32 *)string; /** * @brief Creates a new OFString from a UTF-32 encoded string with the * specified length. * * @param string The UTF-32 string * @param length The length of the UTF-32 string * @return A new autoreleased OFString */ -+ (instancetype)stringWithUTF32String: (const of_char32_t *)string ++ (instancetype)stringWithUTF32String: (const OFChar32 *)string length: (size_t)length; /** * @brief Creates a new OFString from a UTF-32 encoded string, assuming the * specified byte order if no byte order mark is found. @@ -466,12 +479,12 @@ * * @param string The UTF-32 string * @param byteOrder The byte order to assume if there is no byte order mark * @return A new autoreleased OFString */ -+ (instancetype)stringWithUTF32String: (const of_char32_t *)string - byteOrder: (of_byte_order_t)byteOrder; ++ (instancetype)stringWithUTF32String: (const OFChar32 *)string + byteOrder: (OFByteOrder)byteOrder; /** * @brief Creates a new OFString from a UTF-32 encoded string with the * specified length, assuming the specified byte order if no byte order * mark is found. @@ -479,20 +492,20 @@ * @param string The UTF-32 string * @param length The length of the UTF-32 string * @param byteOrder The byte order to assume if there is no byte order mark * @return A new autoreleased OFString */ -+ (instancetype)stringWithUTF32String: (const of_char32_t *)string ++ (instancetype)stringWithUTF32String: (const OFChar32 *)string length: (size_t)length - byteOrder: (of_byte_order_t)byteOrder; + byteOrder: (OFByteOrder)byteOrder; /** * @brief Creates a new OFString from a format string. * * See printf for the format syntax. As an addition, `%@` is available as - * format specifier for objects, `%C` for `of_unichar_t` and `%S` for - * `const of_unichar_t *`. + * 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 */ + (instancetype)stringWithFormat: (OFConstantString *)format, ...; @@ -514,14 +527,13 @@ * @param path The path to the file * @param encoding The encoding of the file * @return A new autoreleased OFString */ + (instancetype)stringWithContentsOfFile: (OFString *)path - encoding: (of_string_encoding_t)encoding; + encoding: (OFStringEncoding)encoding; # endif -# if defined(OF_HAVE_FILES) || defined(OF_HAVE_SOCKETS) /** * @brief Creates a new OFString with the contents of the specified URL. * * If the URL's scheme is file, it tries UTF-8 encoding. * @@ -541,12 +553,11 @@ * @param URL The URL to the contents for the string * @param encoding The encoding to assume * @return A new autoreleased OFString */ + (instancetype)stringWithContentsOfURL: (OFURL *)URL - encoding: (of_string_encoding_t)encoding; -# endif + encoding: (OFStringEncoding)encoding; /** * @brief Initializes an already allocated OFString from a UTF-8 encoded C * string. * @@ -568,12 +579,12 @@ /** * @brief Initializes an already allocated OFString from an UTF-8 encoded C * string without copying the string, if possible. * - * If initialization fails for whatever reason, the passed C string is free'd - * if `freeWhenDone` is true. + * If initialization fails for whatever reason, the passed C string is *not* + * free'd if `freeWhenDone` is true. * * @note OFMutableString always creates a copy! * * @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 @@ -586,12 +597,12 @@ /** * @brief Initializes an already allocated OFString from an UTF-8 encoded C * string with the specified length without copying the string, if * possible. * - * If initialization fails for whatever reason, the passed C string is free'd - * if `freeWhenDone` is true. + * If initialization fails for whatever reason, the passed C string is *not* + * free'd if `freeWhenDone` is true. * * @note OFMutableString always creates a copy! * * @param UTF8String A UTF-8 encoded C string to initialize the OFString with * @param UTF8StringLength The length of the UTF-8 encoded C string @@ -610,11 +621,11 @@ * @param cString A C string to initialize the OFString with * @param encoding The encoding of the C string * @return An initialized OFString */ - (instancetype)initWithCString: (const char *)cString - encoding: (of_string_encoding_t)encoding; + encoding: (OFStringEncoding)encoding; /** * @brief Initializes an already allocated OFString from a C string with the * specified encoding and length. * @@ -622,11 +633,11 @@ * @param encoding The encoding of the C string * @param cStringLength The length of the C string * @return An initialized OFString */ - (instancetype)initWithCString: (const char *)cString - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding length: (size_t)cStringLength; /** * @brief Initializes an already allocated OFString from OFData with the * specified encoding. @@ -634,11 +645,11 @@ * @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 */ - (instancetype)initWithData: (OFData *)data - encoding: (of_string_encoding_t)encoding; + encoding: (OFStringEncoding)encoding; /** * @brief Initializes an already allocated OFString with another string. * * @param string A string to initialize the OFString with @@ -652,30 +663,30 @@ * * @param characters An array of Unicode characters * @param length The length of the Unicode character array * @return An initialized OFString */ -- (instancetype)initWithCharacters: (const of_unichar_t *)characters +- (instancetype)initWithCharacters: (const OFUnichar *)characters length: (size_t)length; /** * @brief Initializes an already allocated OFString with a UTF-16 string. * * @param string The UTF-16 string * @return An initialized OFString */ -- (instancetype)initWithUTF16String: (const of_char16_t *)string; +- (instancetype)initWithUTF16String: (const OFChar16 *)string; /** * @brief Initializes an already allocated OFString with a UTF-16 string with * the specified length. * * @param string The UTF-16 string * @param length The length of the UTF-16 string * @return An initialized OFString */ -- (instancetype)initWithUTF16String: (const of_char16_t *)string +- (instancetype)initWithUTF16String: (const OFChar16 *)string length: (size_t)length; /** * @brief Initializes an already allocated OFString with a UTF-16 string, * assuming the specified byte order if no byte order mark is found. @@ -682,12 +693,12 @@ * * @param string The UTF-16 string * @param byteOrder The byte order to assume if there is no byte order mark * @return An initialized OFString */ -- (instancetype)initWithUTF16String: (const of_char16_t *)string - byteOrder: (of_byte_order_t)byteOrder; +- (instancetype)initWithUTF16String: (const OFChar16 *)string + byteOrder: (OFByteOrder)byteOrder; /** * @brief Initializes an already allocated OFString with a UTF-16 string with * the specified length, assuming the specified byte order if no byte * order mark is found. @@ -695,31 +706,31 @@ * @param string The 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 */ -- (instancetype)initWithUTF16String: (const of_char16_t *)string +- (instancetype)initWithUTF16String: (const OFChar16 *)string length: (size_t)length - byteOrder: (of_byte_order_t)byteOrder; + byteOrder: (OFByteOrder)byteOrder; /** * @brief Initializes an already allocated OFString with a UTF-32 string. * * @param string The UTF-32 string * @return An initialized OFString */ -- (instancetype)initWithUTF32String: (const of_char32_t *)string; +- (instancetype)initWithUTF32String: (const OFChar32 *)string; /** * @brief Initializes an already allocated OFString with a UTF-32 string with * the specified length * * @param string The UTF-32 string * @param length The length of the UTF-32 string * @return An initialized OFString */ -- (instancetype)initWithUTF32String: (const of_char32_t *)string +- (instancetype)initWithUTF32String: (const OFChar32 *)string length: (size_t)length; /** * @brief Initializes an already allocated OFString with a UTF-32 string, * assuming the specified byte order if no byte order mark is found. @@ -726,12 +737,12 @@ * * @param string The UTF-32 string * @param byteOrder The byte order to assume if there is no byte order mark * @return An initialized OFString */ -- (instancetype)initWithUTF32String: (const of_char32_t *)string - byteOrder: (of_byte_order_t)byteOrder; +- (instancetype)initWithUTF32String: (const OFChar32 *)string + byteOrder: (OFByteOrder)byteOrder; /** * @brief Initializes an already allocated OFString with a UTF-32 string with * the specified length, assuming the specified byte order if no byte * order mark is found. @@ -739,20 +750,20 @@ * @param string The UTF-32 string * @param length The length of the UTF-32 string * @param byteOrder The byte order to assume if there is no byte order mark * @return An initialized OFString */ -- (instancetype)initWithUTF32String: (const of_char32_t *)string +- (instancetype)initWithUTF32String: (const OFChar32 *)string length: (size_t)length - byteOrder: (of_byte_order_t)byteOrder; + byteOrder: (OFByteOrder)byteOrder; /** * @brief Initializes an already allocated OFString with a format string. * * See printf for the format syntax. As an addition, `%@` is available as - * format specifier for objects, `%C` for `of_unichar_t` and `%S` for - * `const of_unichar_t *`. + * 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 */ - (instancetype)initWithFormat: (OFConstantString *)format, ...; @@ -759,12 +770,12 @@ /** * @brief Initializes an already allocated OFString with a format string. * * See printf for the format syntax. As an addition, `%@` is available as - * format specifier for objects, `%C` for `of_unichar_t` and `%S` for - * `const of_unichar_t *`. + * format specifier for objects, `%C` for `OFUnichar` and `%S` for + * `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 */ @@ -788,11 +799,11 @@ * @param path The path to the file * @param encoding The encoding of the file * @return An initialized OFString */ - (instancetype)initWithContentsOfFile: (OFString *)path - encoding: (of_string_encoding_t)encoding; + encoding: (OFStringEncoding)encoding; # endif /** * @brief Initializes an already allocated OFString with the contents of the * specified URL. @@ -815,11 +826,11 @@ * @param URL The URL to the contents for the string * @param encoding The encoding to assume * @return An initialized OFString */ - (instancetype)initWithContentsOfURL: (OFURL *)URL - encoding: (of_string_encoding_t)encoding; + encoding: (OFStringEncoding)encoding; /** * @brief Writes the OFString into the specified C string with the specified * encoding. * @@ -830,11 +841,11 @@ * @return The number of bytes written into the C string, without the * terminating zero */ - (size_t)getCString: (char *)cString maxLength: (size_t)maxLength - encoding: (of_string_encoding_t)encoding; + encoding: (OFStringEncoding)encoding; /** * @brief Writes the OFString into the specified C string with the specified * encoding, replacing characters that cannot be represented in the * specified encoding with a question mark. @@ -846,11 +857,11 @@ * @return The number of bytes written into the C string, without the * terminating zero */ - (size_t)getLossyCString: (char *)cString maxLength: (size_t)maxLength - encoding: (of_string_encoding_t)encoding; + encoding: (OFStringEncoding)encoding; /** * @brief Returns the OFString as a C string in the specified encoding. * * The result is valid until the autorelease pool is released. If you want to @@ -858,11 +869,11 @@ * copy it. * * @param encoding The encoding for the C string * @return The OFString as a C string in the specified encoding */ -- (const char *)cStringWithEncoding: (of_string_encoding_t)encoding +- (const char *)cStringWithEncoding: (OFStringEncoding)encoding OF_RETURNS_INNER_POINTER; /** * @brief Returns the OFString as a C string in the specified encoding, * replacing characters that cannot be represented in the specified @@ -873,130 +884,120 @@ * copy it. * * @param encoding The encoding for the C string * @return The OFString as a C string in the specified encoding */ -- (const char *)lossyCStringWithEncoding: (of_string_encoding_t)encoding +- (const char *)lossyCStringWithEncoding: (OFStringEncoding)encoding OF_RETURNS_INNER_POINTER; /** * @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. */ -- (size_t)cStringLengthWithEncoding: (of_string_encoding_t)encoding; +- (size_t)cStringLengthWithEncoding: (OFStringEncoding)encoding; + +/** + * @brief Compares the string to another string. + * + * @param string The string to compare the string to + * @return The result of the comparison + */ +- (OFComparisonResult)compare: (OFString *)string; /** - * @brief Compares the OFString to another OFString without caring about the - * case. + * @brief Compares the string to another string without caring about the case. * - * @param otherString A string to compare with - * @return An of_comparison_result_t + * @param string The string to compare the string to + * @return The result of the comparison */ -- (of_comparison_result_t)caseInsensitiveCompare: (OFString *)otherString; +- (OFComparisonResult)caseInsensitiveCompare: (OFString *)string; /** * @brief Returns the Unicode character at the specified index. * * @param index The index of the Unicode character to return * @return The Unicode character at the specified index */ -- (of_unichar_t)characterAtIndex: (size_t)index; +- (OFUnichar)characterAtIndex: (size_t)index; /** * @brief Copies the Unicode characters in the specified range to the specified * buffer. * * @param buffer The buffer to store the Unicode characters * @param range The range of the Unicode characters to copy */ -- (void)getCharacters: (of_unichar_t *)buffer - inRange: (of_range_t)range; +- (void)getCharacters: (OFUnichar *)buffer inRange: (OFRange)range; /** * @brief Returns the range of the first occurrence of the string. * * @param string The string to search * @return The range of the first occurrence of the string or a range with - * `OF_NOT_FOUND` as start position if it was not found + * `OFNotFound` as start position if it was not found */ -- (of_range_t)rangeOfString: (OFString *)string; +- (OFRange)rangeOfString: (OFString *)string; /** * @brief Returns the range of the string. * * @param string The string to search - * @param options Options modifying search behavior.@n - * Possible values are: - * Value | Description - * -----------------------------|------------------------------- - * `OF_STRING_SEARCH_BACKWARDS` | Search backwards in the string + * @param options Options modifying search behavior * @return The range of the first occurrence of the string or a range with - * `OF_NOT_FOUND` as start position if it was not found + * `OFNotFound` as start position if it was not found */ -- (of_range_t)rangeOfString: (OFString *)string - options: (int)options; +- (OFRange)rangeOfString: (OFString *)string + options: (OFStringSearchOptions)options; /** * @brief Returns the range of the string in the specified range. * * @param string The string to search - * @param options Options modifying search behaviour.@n - * Possible values are: - * Value | Description - * -----------------------------|------------------------------- - * `OF_STRING_SEARCH_BACKWARDS` | Search backwards in the string + * @param options Options modifying search behaviour * @param range The range in which to search * @return The range of the first occurrence of the string or a range with - * `OF_NOT_FOUND` as start position if it was not found + * `OFNotFound` as start position if it was not found */ -- (of_range_t)rangeOfString: (OFString *)string - options: (int)options - range: (of_range_t)range; +- (OFRange)rangeOfString: (OFString *)string + options: (OFStringSearchOptions)options + range: (OFRange)range; /** * @brief Returns the index of the first character from the set. * * @param characterSet The set of characters to search for * @return The index of the first occurrence of a character from the set or - * `OF_NOT_FOUND` if it was not found + * `OFNotFound` if it was not found */ - (size_t)indexOfCharacterFromSet: (OFCharacterSet *)characterSet; /** * @brief Returns the index of the first character from the set. * * @param characterSet The set of characters to search for - * @param options Options modifying search behaviour.@n - * Possible values are: - * Value | Description - * -----------------------------|------------------------------- - * `OF_STRING_SEARCH_BACKWARDS` | Search backwards in the string + * @param options Options modifying search behaviour * @return The index of the first occurrence of a character from the set or - * `OF_NOT_FOUND` if it was not found + * `OFNotFound` if it was not found */ - (size_t)indexOfCharacterFromSet: (OFCharacterSet *)characterSet - options: (int)options; + options: (OFStringSearchOptions)options; /** * @brief Returns the index of the first character from the set. * * @param characterSet The set of characters to search for - * @param options Options modifying search behaviour.@n - * Possible values are: - * Value | Description - * -----------------------------|------------------------------- - * `OF_STRING_SEARCH_BACKWARDS` | Search backwards in the string + * @param options Options modifying search behaviour * @param range The range in which to search * @return The index of the first occurrence of a character from the set or - * `OF_NOT_FOUND` if it was not found + * `OFNotFound` if it was not found */ - (size_t)indexOfCharacterFromSet: (OFCharacterSet *)characterSet - options: (int)options - range: (of_range_t)range; + options: (OFStringSearchOptions)options + range: (OFRange)range; /** * @brief Returns whether the string contains the specified string. * * @param string The string to search @@ -1024,11 +1025,11 @@ * @brief Creates a substring with the specified range. * * @param range The range of the substring * @return The substring as a new autoreleased OFString */ -- (OFString *)substringWithRange: (of_range_t)range; +- (OFString *)substringWithRange: (OFRange)range; /** * @brief The value of the string in the specified base as a `long long`. * * Leading and trailing whitespaces are ignored. @@ -1125,11 +1126,11 @@ * @return A new string with the occurrences of the specified string replaced */ - (OFString *)stringByReplacingOccurrencesOfString: (OFString *)string withString: (OFString *)replacement options: (int)options - range: (of_range_t)range; + range: (OFRange)range; /** * @brief Checks whether the string has the specified prefix. * * @param prefix The prefix to check for @@ -1158,20 +1159,16 @@ /** * @brief Separates the string into an array of strings, split by the specified * delimiter. * * @param delimiter The delimiter for separating - * @param options Options according to which the string should be separated.@n - * Possible values are: - * Value | Description - * -----------------------|---------------------- - * `OF_STRING_SKIP_EMPTY` | Skip empty components + * @param options Options according to which the string should be separated * @return An autoreleased OFArray with the separated string */ - (OFArray OF_GENERIC(OFString *) *) componentsSeparatedByString: (OFString *)delimiter - options: (int)options; + options: (OFStringSeparationOptions)options; /** * @brief Separates the string into an array of strings, split by characters in * the specified set. * @@ -1184,20 +1181,16 @@ /** * @brief Separates the string into an array of strings, split by characters in * the specified set. * * @param characterSet The character set for separating - * @param options Options according to which the string should be separated.@n - * Possible values are: - * Value | Description - * -----------------------|---------------------- - * `OF_STRING_SKIP_EMPTY` | Skip empty components + * @param options Options according to which the string should be separated * @return An autoreleased OFArray with the separated string */ - (OFArray OF_GENERIC(OFString *) *) componentsSeparatedByCharactersInSet: (OFCharacterSet *)characterSet - options: (int)options; + options: (OFStringSeparationOptions)options; /** * @brief Returns the string in UTF-16 encoding with the specified byte order. * * The result is valid until the autorelease pool is released. If you want to @@ -1205,11 +1198,11 @@ * copy it. * * @param byteOrder The byte order for the UTF-16 encoding * @return The string in UTF-16 encoding with the specified byte order */ -- (const of_char16_t *)UTF16StringWithByteOrder: (of_byte_order_t)byteOrder +- (const OFChar16 *)UTF16StringWithByteOrder: (OFByteOrder)byteOrder OF_RETURNS_INNER_POINTER; /** * @brief Returns the string in UTF-32 encoding with the specified byte order. * @@ -1218,20 +1211,20 @@ * copy it. * * @param byteOrder The byte order for the UTF-32 encoding * @return The string in UTF-32 encoding with the specified byte order */ -- (const of_char32_t *)UTF32StringWithByteOrder: (of_byte_order_t)byteOrder +- (const OFChar32 *)UTF32StringWithByteOrder: (OFByteOrder)byteOrder OF_RETURNS_INNER_POINTER; /** * @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 */ -- (OFData *)dataWithEncoding: (of_string_encoding_t)encoding; +- (OFData *)dataWithEncoding: (OFStringEncoding)encoding; # ifdef OF_HAVE_FILES /** * @brief Writes the string into the specified file using UTF-8 encoding. * @@ -1244,12 +1237,11 @@ * encoding. * * @param path The path of the file to write to * @param encoding The encoding to use to write the string into the file */ -- (void)writeToFile: (OFString *)path - encoding: (of_string_encoding_t)encoding; +- (void)writeToFile: (OFString *)path encoding: (OFStringEncoding)encoding; # endif /** * @brief Writes the string to the specified URL using UTF-8 encoding. * @@ -1261,43 +1253,61 @@ * @brief Writes the string to the specified URL using the specified encoding. * * @param URL The URL to write to * @param encoding The encoding to use to write the string to the URL */ -- (void)writeToURL: (OFURL *)URL - encoding: (of_string_encoding_t)encoding; +- (void)writeToURL: (OFURL *)URL encoding: (OFStringEncoding)encoding; # ifdef OF_HAVE_BLOCKS /** * Enumerates all lines in the receiver using the specified block. * * @brief block The block to call for each line */ -- (void)enumerateLinesUsingBlock: (of_string_line_enumeration_block_t)block; +- (void)enumerateLinesUsingBlock: (OFStringLineEnumerationBlock)block; # endif @end #endif #ifdef __cplusplus extern "C" { #endif -extern of_string_encoding_t of_string_parse_encoding(OFString *); -extern OFString *_Nullable of_string_name_of_encoding(of_string_encoding_t); -extern size_t of_string_utf8_encode(of_unichar_t, char *); -extern ssize_t of_string_utf8_decode(const char *, size_t, of_unichar_t *); -extern size_t of_string_utf16_length(const of_char16_t *); -extern size_t of_string_utf32_length(const of_char32_t *); +/** + * @brief Parses the specified string encoding name and returns the + * OFStringEncoding for it. + * + * Throws @ref OFInvalidArgumentException if the specified name is not a valid + * encoding name. + * + * @param name The name to parse as a string encoding + * @return The OFStringEncoding for the specified name + */ +extern OFStringEncoding OFStringEncodingParseName(OFString *name); + +/** + * @brief Returns the name of the specified OFStringEncoding. + * + * @param encoding The encoding for which to return the name + * @return The name of the specified OFStringEncoding + */ +extern OFString *_Nullable OFStringEncodingName(OFStringEncoding encoding); + +extern char *_Nullable OFStrDup(const char *_Nonnull); +extern size_t OFUTF8StringEncode(OFUnichar, char *); +extern ssize_t OFUTF8StringDecode(const char *, size_t, OFUnichar *); +extern size_t OFUTF16StringLength(const OFChar16 *); +extern size_t OFUTF32StringLength(const OFChar32 *); #ifdef __cplusplus } #endif OF_ASSUME_NONNULL_END #include "OFConstantString.h" #include "OFMutableString.h" #ifdef __OBJC__ -# import "OFString+CryptoHashing.h" +# import "OFString+CryptographicHashing.h" # import "OFString+JSONParsing.h" # ifdef OF_HAVE_FILES # import "OFString+PathAdditions.h" # endif # import "OFString+PropertyListParsing.h" Index: src/OFString.m ================================================================== --- src/OFString.m +++ src/OFString.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -30,10 +28,11 @@ #ifdef HAVE_XLOCALE_H # include #endif #import "OFString.h" +#import "OFASPrintF.h" #import "OFArray.h" #import "OFCharacterSet.h" #import "OFData.h" #import "OFDictionary.h" #ifdef OF_HAVE_FILES @@ -59,11 +58,10 @@ #import "OFOutOfRangeException.h" #import "OFRetrieveItemAttributesFailedException.h" #import "OFTruncatedDataException.h" #import "OFUnsupportedProtocolException.h" -#import "of_asprintf.h" #import "unicode.h" /* * It seems strtod is buggy on Win32. * However, the MinGW version __strtod seems to be ok. @@ -70,14 +68,17 @@ */ #ifdef __MINGW32__ # define strtod __strtod #endif -#ifdef OF_AMIGAOS_M68K -/* libnix has strtod, but not strtof */ +#ifndef HAVE_STRTOF # define strtof strtod #endif + +#ifndef INFINITY +# define INFINITY __builtin_inf() +#endif static struct { Class isa; } placeholder; @@ -86,49 +87,50 @@ #endif @interface OFString () - (size_t)of_getCString: (char *)cString maxLength: (size_t)maxLength - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding lossy: (bool)lossy OF_DIRECT; -- (const char *)of_cStringWithEncoding: (of_string_encoding_t)encoding +- (const char *)of_cStringWithEncoding: (OFStringEncoding)encoding lossy: (bool)lossy OF_DIRECT; -- (OFString *)of_JSONRepresentationWithOptions: (int)options - depth: (size_t)depth; +- (OFString *) + of_JSONRepresentationWithOptions: (OFJSONRepresentationOptions)options + depth: (size_t)depth; @end @interface OFStringPlaceholder: OFString @end -extern bool of_unicode_to_iso_8859_2(const of_unichar_t *, unsigned char *, - size_t, bool); -extern bool of_unicode_to_iso_8859_3(const of_unichar_t *, unsigned char *, - size_t, bool); -extern bool of_unicode_to_iso_8859_15(const of_unichar_t *, unsigned char *, - size_t, bool); -extern bool of_unicode_to_windows_1251(const of_unichar_t *, unsigned char *, - size_t, bool); -extern bool of_unicode_to_windows_1252(const of_unichar_t *, unsigned char *, - size_t, bool); -extern bool of_unicode_to_codepage_437(const of_unichar_t *, unsigned char *, - size_t, bool); -extern bool of_unicode_to_codepage_850(const of_unichar_t *, unsigned char *, - size_t, bool); -extern bool of_unicode_to_codepage_858(const of_unichar_t *, unsigned char *, - size_t, bool); -extern bool of_unicode_to_mac_roman(const of_unichar_t *, unsigned char *, - size_t, bool); -extern bool of_unicode_to_koi8_r(const of_unichar_t *, unsigned char *, - size_t, bool); -extern bool of_unicode_to_koi8_u(const of_unichar_t *, unsigned char *, +extern bool OFUnicodeToISO8859_2(const OFUnichar *, unsigned char *, + size_t, bool); +extern bool OFUnicodeToISO8859_3(const OFUnichar *, unsigned char *, + size_t, bool); +extern bool OFUnicodeToISO8859_15(const OFUnichar *, unsigned char *, + size_t, bool); +extern bool OFUnicodeToWindows1251(const OFUnichar *, unsigned char *, + size_t, bool); +extern bool OFUnicodeToWindows1252(const OFUnichar *, unsigned char *, + size_t, bool); +extern bool OFUnicodeToCodepage437(const OFUnichar *, unsigned char *, + size_t, bool); +extern bool OFUnicodeToCodepage850(const OFUnichar *, unsigned char *, + size_t, bool); +extern bool OFUnicodeToCodepage858(const OFUnichar *, unsigned char *, + size_t, bool); +extern bool OFUnicodeToMacRoman(const OFUnichar *, unsigned char *, + size_t, bool); +extern bool OFUnicodeToKOI8R(const OFUnichar *, unsigned char *, + size_t, bool); +extern bool OFUnicodeToKOI8U(const OFUnichar *, unsigned char *, size_t, bool); /* References for static linking */ void _references_to_categories_of_OFString(void) { - _OFString_CryptoHashing_reference = 1; + _OFString_CryptographicHashing_reference = 1; _OFString_JSONParsing_reference = 1; #ifdef OF_HAVE_FILES _OFString_PathAdditions_reference = 1; #endif _OFString_PropertyListParsing_reference = 1; @@ -142,106 +144,106 @@ _reference_to_OFConstantString(void) { [OFConstantString class]; } -of_string_encoding_t -of_string_parse_encoding(OFString *string) +OFStringEncoding +OFStringEncodingParseName(OFString *string) { void *pool = objc_autoreleasePoolPush(); - of_string_encoding_t encoding; + OFStringEncoding encoding; string = string.lowercaseString; if ([string isEqual: @"utf8"] || [string isEqual: @"utf-8"]) - encoding = OF_STRING_ENCODING_UTF_8; + encoding = OFStringEncodingUTF8; else if ([string isEqual: @"ascii"] || [string isEqual: @"us-ascii"]) - encoding = OF_STRING_ENCODING_ASCII; + encoding = OFStringEncodingASCII; else if ([string isEqual: @"iso-8859-1"] || [string isEqual: @"iso_8859-1"]) - encoding = OF_STRING_ENCODING_ISO_8859_1; + encoding = OFStringEncodingISO8859_1; else if ([string isEqual: @"iso-8859-2"] || [string isEqual: @"iso_8859-2"]) - encoding = OF_STRING_ENCODING_ISO_8859_2; + encoding = OFStringEncodingISO8859_2; else if ([string isEqual: @"iso-8859-3"] || [string isEqual: @"iso_8859-3"]) - encoding = OF_STRING_ENCODING_ISO_8859_3; + encoding = OFStringEncodingISO8859_3; else if ([string isEqual: @"iso-8859-15"] || [string isEqual: @"iso_8859-15"]) - encoding = OF_STRING_ENCODING_ISO_8859_15; + encoding = OFStringEncodingISO8859_15; else if ([string isEqual: @"windows-1251"] || [string isEqual: @"cp1251"] || [string isEqual: @"cp-1251"] || [string isEqual: @"1251"]) - encoding = OF_STRING_ENCODING_WINDOWS_1251; + encoding = OFStringEncodingWindows1251; else if ([string isEqual: @"windows-1252"] || [string isEqual: @"cp1252"] || [string isEqual: @"cp-1252"] || [string isEqual: @"1252"]) - encoding = OF_STRING_ENCODING_WINDOWS_1252; + encoding = OFStringEncodingWindows1252; else if ([string isEqual: @"cp437"] || [string isEqual: @"cp-437"] || [string isEqual: @"ibm437"] || [string isEqual: @"437"]) - encoding = OF_STRING_ENCODING_CODEPAGE_437; + encoding = OFStringEncodingCodepage437; else if ([string isEqual: @"cp850"] || [string isEqual: @"cp-850"] || [string isEqual: @"ibm850"] || [string isEqual: @"850"]) - encoding = OF_STRING_ENCODING_CODEPAGE_850; + encoding = OFStringEncodingCodepage850; else if ([string isEqual: @"cp858"] || [string isEqual: @"cp-858"] || [string isEqual: @"ibm858"] || [string isEqual: @"858"]) - encoding = OF_STRING_ENCODING_CODEPAGE_858; + encoding = OFStringEncodingCodepage858; else if ([string isEqual: @"macintosh"] || [string isEqual: @"mac"]) - encoding = OF_STRING_ENCODING_MAC_ROMAN; + encoding = OFStringEncodingMacRoman; else if ([string isEqual: @"koi8-r"]) - encoding = OF_STRING_ENCODING_KOI8_R; + encoding = OFStringEncodingKOI8R; else if ([string isEqual: @"koi8-u"]) - encoding = OF_STRING_ENCODING_KOI8_U; + encoding = OFStringEncodingKOI8U; else @throw [OFInvalidArgumentException exception]; objc_autoreleasePoolPop(pool); return encoding; } OFString * -of_string_name_of_encoding(of_string_encoding_t encoding) +OFStringEncodingName(OFStringEncoding encoding) { switch (encoding) { - case OF_STRING_ENCODING_UTF_8: + case OFStringEncodingUTF8: return @"UTF-8"; - case OF_STRING_ENCODING_ASCII: + case OFStringEncodingASCII: return @"ASCII"; - case OF_STRING_ENCODING_ISO_8859_1: + case OFStringEncodingISO8859_1: return @"ISO 8859-1"; - case OF_STRING_ENCODING_ISO_8859_2: + case OFStringEncodingISO8859_2: return @"ISO 8859-2"; - case OF_STRING_ENCODING_ISO_8859_3: + case OFStringEncodingISO8859_3: return @"ISO 8859-3"; - case OF_STRING_ENCODING_ISO_8859_15: + case OFStringEncodingISO8859_15: return @"ISO 8859-15"; - case OF_STRING_ENCODING_WINDOWS_1251: + case OFStringEncodingWindows1251: return @"Windows-1251"; - case OF_STRING_ENCODING_WINDOWS_1252: + case OFStringEncodingWindows1252: return @"Windows-1252"; - case OF_STRING_ENCODING_CODEPAGE_437: + case OFStringEncodingCodepage437: return @"Codepage 437"; - case OF_STRING_ENCODING_CODEPAGE_850: + case OFStringEncodingCodepage850: return @"Codepage 850"; - case OF_STRING_ENCODING_CODEPAGE_858: + case OFStringEncodingCodepage858: return @"Codepage 858"; - case OF_STRING_ENCODING_MAC_ROMAN: + case OFStringEncodingMacRoman: return @"Mac Roman"; - case OF_STRING_ENCODING_KOI8_R: + case OFStringEncodingKOI8R: return @"KOI8-R"; - case OF_STRING_ENCODING_KOI8_U: + case OFStringEncodingKOI8U: return @"KOI8-U"; - case OF_STRING_ENCODING_AUTODETECT: + case OFStringEncodingAutodetect: return @"autodetect"; } return nil; } size_t -of_string_utf8_encode(of_unichar_t character, char *buffer) +OFUTF8StringEncode(OFUnichar character, char *buffer) { if (character < 0x80) { buffer[0] = character; return 1; } else if (character < 0x800) { @@ -263,11 +265,11 @@ return 0; } ssize_t -of_string_utf8_decode(const char *buffer_, size_t length, of_unichar_t *ret) +OFUTF8StringDecode(const char *buffer_, size_t length, OFUnichar *ret) { const unsigned char *buffer = (const unsigned char *)buffer_; if (!(*buffer & 0x80)) { *ret = buffer[0]; @@ -313,11 +315,11 @@ return 0; } size_t -of_string_utf16_length(const of_char16_t *string) +OFUTF16StringLength(const OFChar16 *string) { size_t length = 0; while (*string++ != 0) length++; @@ -324,45 +326,53 @@ return length; } size_t -of_string_utf32_length(const of_char32_t *string) +OFUTF32StringLength(const OFChar32 *string) { size_t length = 0; while (*string++ != 0) length++; return length; } + +char * +OFStrDup(const char *string) +{ + size_t length = strlen(string); + char *copy = (char *)OFAllocMemory(1, length + 1); + memcpy(copy, string, length + 1); + + return copy; +} #ifdef OF_HAVE_UNICODE_TABLES static OFString * decomposedString(OFString *self, const char *const *const *table, size_t size) { OFMutableString *ret = [OFMutableString string]; void *pool = objc_autoreleasePoolPush(); - const of_unichar_t *characters = self.characters; + const OFUnichar *characters = self.characters; size_t length = self.length; for (size_t i = 0; i < length; i++) { - of_unichar_t c = characters[i]; + OFUnichar c = characters[i]; const char *const *page; if (c >= size) { - [ret appendCharacters: &c - length: 1]; + [ret appendCharacters: &c length: 1]; continue; } page = table[c >> 8]; if (page != NULL && page[c & 0xFF] != NULL) [ret appendUTF8String: page[c & 0xFF]]; else - [ret appendCharacters: &c - length: 1]; + [ret appendCharacters: &c length: 1]; } objc_autoreleasePoolPop(pool); return ret; @@ -380,11 +390,11 @@ OFUTF8String *string; size_t length; void *storage; length = strlen(UTF8String); - string = of_alloc_object([OFUTF8String class], length + 1, 1, &storage); + string = OFAllocObject([OFUTF8String class], length + 1, 1, &storage); return (id)[string of_initWithUTF8String: UTF8String length: length storage: storage]; } @@ -393,11 +403,11 @@ length: (size_t)UTF8StringLength { OFUTF8String *string; void *storage; - string = of_alloc_object([OFUTF8String class], UTF8StringLength + 1, 1, + string = OFAllocObject([OFUTF8String class], UTF8StringLength + 1, 1, &storage); return (id)[string of_initWithUTF8String: UTF8String length: UTF8StringLength storage: storage]; @@ -420,19 +430,19 @@ length: UTF8StringLength freeWhenDone: freeWhenDone]; } - (instancetype)initWithCString: (const char *)cString - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding { - if (encoding == OF_STRING_ENCODING_UTF_8) { + if (encoding == OFStringEncodingUTF8) { OFUTF8String *string; size_t length; void *storage; length = strlen(cString); - string = of_alloc_object([OFUTF8String class], length + 1, 1, + string = OFAllocObject([OFUTF8String class], length + 1, 1, &storage); return (id)[string of_initWithUTF8String: cString length: length storage: storage]; @@ -441,19 +451,19 @@ return (id)[[OFUTF8String alloc] initWithCString: cString encoding: encoding]; } - (instancetype)initWithCString: (const char *)cString - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding length: (size_t)cStringLength { - if (encoding == OF_STRING_ENCODING_UTF_8) { + if (encoding == OFStringEncodingUTF8) { OFUTF8String *string; void *storage; - string = of_alloc_object([OFUTF8String class], - cStringLength + 1, 1, &storage); + string = OFAllocObject([OFUTF8String class], cStringLength + 1, + 1, &storage); return (id)[string of_initWithUTF8String: cString length: cStringLength storage: storage]; } @@ -462,11 +472,11 @@ encoding: encoding length: cStringLength]; } - (instancetype)initWithData: (OFData *)data - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding { return (id)[[OFUTF8String alloc] initWithData: data encoding: encoding]; } @@ -473,67 +483,67 @@ - (instancetype)initWithString: (OFString *)string { return (id)[[OFUTF8String alloc] initWithString: string]; } -- (instancetype)initWithCharacters: (const of_unichar_t *)string +- (instancetype)initWithCharacters: (const OFUnichar *)string length: (size_t)length { return (id)[[OFUTF8String alloc] initWithCharacters: string length: length]; } -- (instancetype)initWithUTF16String: (const of_char16_t *)string +- (instancetype)initWithUTF16String: (const OFChar16 *)string { return (id)[[OFUTF8String alloc] initWithUTF16String: string]; } -- (instancetype)initWithUTF16String: (const of_char16_t *)string +- (instancetype)initWithUTF16String: (const OFChar16 *)string length: (size_t)length { return (id)[[OFUTF8String alloc] initWithUTF16String: string length: length]; } -- (instancetype)initWithUTF16String: (const of_char16_t *)string - byteOrder: (of_byte_order_t)byteOrder +- (instancetype)initWithUTF16String: (const OFChar16 *)string + byteOrder: (OFByteOrder)byteOrder { return (id)[[OFUTF8String alloc] initWithUTF16String: string byteOrder: byteOrder]; } -- (instancetype)initWithUTF16String: (const of_char16_t *)string +- (instancetype)initWithUTF16String: (const OFChar16 *)string length: (size_t)length - byteOrder: (of_byte_order_t)byteOrder + byteOrder: (OFByteOrder)byteOrder { return (id)[[OFUTF8String alloc] initWithUTF16String: string length: length byteOrder: byteOrder]; } -- (instancetype)initWithUTF32String: (const of_char32_t *)string +- (instancetype)initWithUTF32String: (const OFChar32 *)string { return (id)[[OFUTF8String alloc] initWithUTF32String: string]; } -- (instancetype)initWithUTF32String: (const of_char32_t *)string +- (instancetype)initWithUTF32String: (const OFChar32 *)string length: (size_t)length { return (id)[[OFUTF8String alloc] initWithUTF32String: string length: length]; } -- (instancetype)initWithUTF32String: (const of_char32_t *)string - byteOrder: (of_byte_order_t)byteOrder +- (instancetype)initWithUTF32String: (const OFChar32 *)string + byteOrder: (OFByteOrder)byteOrder { return (id)[[OFUTF8String alloc] initWithUTF32String: string byteOrder: byteOrder]; } -- (instancetype)initWithUTF32String: (const of_char32_t *)string +- (instancetype)initWithUTF32String: (const OFChar32 *)string length: (size_t)length - byteOrder: (of_byte_order_t)byteOrder + byteOrder: (OFByteOrder)byteOrder { return (id)[[OFUTF8String alloc] initWithUTF32String: string length: length byteOrder: byteOrder]; } @@ -563,30 +573,28 @@ { return (id)[[OFUTF8String alloc] initWithContentsOfFile: path]; } - (instancetype)initWithContentsOfFile: (OFString *)path - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding { return (id)[[OFUTF8String alloc] initWithContentsOfFile: path encoding: encoding]; } #endif -#if defined(OF_HAVE_FILES) || defined(OF_HAVE_SOCKETS) - (instancetype)initWithContentsOfURL: (OFURL *)URL { return (id)[[OFUTF8String alloc] initWithContentsOfURL: URL]; } - (instancetype)initWithContentsOfURL: (OFURL *)URL - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding { return (id)[[OFUTF8String alloc] initWithContentsOfURL: URL encoding: encoding]; } -#endif - (instancetype)initWithSerialization: (OFXMLElement *)element { return (id)[[OFUTF8String alloc] initWithSerialization: element]; } @@ -669,27 +677,27 @@ length: UTF8StringLength freeWhenDone: freeWhenDone] autorelease]; } + (instancetype)stringWithCString: (const char *)cString - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding { return [[[self alloc] initWithCString: cString encoding: encoding] autorelease]; } + (instancetype)stringWithCString: (const char *)cString - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding length: (size_t)cStringLength { return [[[self alloc] initWithCString: cString encoding: encoding length: cStringLength] autorelease]; } + (instancetype)stringWithData: (OFData *)data - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding { return [[[self alloc] initWithData: data encoding: encoding] autorelease]; } @@ -696,67 +704,67 @@ + (instancetype)stringWithString: (OFString *)string { return [[[self alloc] initWithString: string] autorelease]; } -+ (instancetype)stringWithCharacters: (const of_unichar_t *)string ++ (instancetype)stringWithCharacters: (const OFUnichar *)string length: (size_t)length { return [[[self alloc] initWithCharacters: string length: length] autorelease]; } -+ (instancetype)stringWithUTF16String: (const of_char16_t *)string ++ (instancetype)stringWithUTF16String: (const OFChar16 *)string { return [[[self alloc] initWithUTF16String: string] autorelease]; } -+ (instancetype)stringWithUTF16String: (const of_char16_t *)string ++ (instancetype)stringWithUTF16String: (const OFChar16 *)string length: (size_t)length { return [[[self alloc] initWithUTF16String: string length: length] autorelease]; } -+ (instancetype)stringWithUTF16String: (const of_char16_t *)string - byteOrder: (of_byte_order_t)byteOrder ++ (instancetype)stringWithUTF16String: (const OFChar16 *)string + byteOrder: (OFByteOrder)byteOrder { return [[[self alloc] initWithUTF16String: string byteOrder: byteOrder] autorelease]; } -+ (instancetype)stringWithUTF16String: (const of_char16_t *)string ++ (instancetype)stringWithUTF16String: (const OFChar16 *)string length: (size_t)length - byteOrder: (of_byte_order_t)byteOrder + byteOrder: (OFByteOrder)byteOrder { return [[[self alloc] initWithUTF16String: string length: length byteOrder: byteOrder] autorelease]; } -+ (instancetype)stringWithUTF32String: (const of_char32_t *)string ++ (instancetype)stringWithUTF32String: (const OFChar32 *)string { return [[[self alloc] initWithUTF32String: string] autorelease]; } -+ (instancetype)stringWithUTF32String: (const of_char32_t *)string ++ (instancetype)stringWithUTF32String: (const OFChar32 *)string length: (size_t)length { return [[[self alloc] initWithUTF32String: string length: length] autorelease]; } -+ (instancetype)stringWithUTF32String: (const of_char32_t *)string - byteOrder: (of_byte_order_t)byteOrder ++ (instancetype)stringWithUTF32String: (const OFChar32 *)string + byteOrder: (OFByteOrder)byteOrder { return [[[self alloc] initWithUTF32String: string byteOrder: byteOrder] autorelease]; } -+ (instancetype)stringWithUTF32String: (const of_char32_t *)string ++ (instancetype)stringWithUTF32String: (const OFChar32 *)string length: (size_t)length - byteOrder: (of_byte_order_t)byteOrder + byteOrder: (OFByteOrder)byteOrder { return [[[self alloc] initWithUTF32String: string length: length byteOrder: byteOrder] autorelease]; } @@ -779,30 +787,28 @@ { return [[[self alloc] initWithContentsOfFile: path] autorelease]; } + (instancetype)stringWithContentsOfFile: (OFString *)path - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding { return [[[self alloc] initWithContentsOfFile: path encoding: encoding] autorelease]; } #endif -#if defined(OF_HAVE_FILES) || defined(OF_HAVE_SOCKETS) + (instancetype)stringWithContentsOfURL: (OFURL *)URL { return [[[self alloc] initWithContentsOfURL: URL] autorelease]; } + (instancetype)stringWithContentsOfURL: (OFURL *)URL - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding { return [[[self alloc] initWithContentsOfURL: URL encoding: encoding] autorelease]; } -#endif - (instancetype)init { if ([self isMemberOfClass: [OFString class]]) { @try { @@ -819,71 +825,62 @@ } - (instancetype)initWithUTF8String: (const char *)UTF8String { return [self initWithCString: UTF8String - encoding: OF_STRING_ENCODING_UTF_8 + encoding: OFStringEncodingUTF8 length: strlen(UTF8String)]; } - (instancetype)initWithUTF8String: (const char *)UTF8String length: (size_t)UTF8StringLength { return [self initWithCString: UTF8String - encoding: OF_STRING_ENCODING_UTF_8 + encoding: OFStringEncodingUTF8 length: UTF8StringLength]; } - (instancetype)initWithUTF8StringNoCopy: (char *)UTF8String freeWhenDone: (bool)freeWhenDone { - id ret; - - @try { - ret = [self initWithUTF8String: UTF8String]; - } @finally { - if (freeWhenDone) - of_free(UTF8String); - } + id ret = [self initWithUTF8String: UTF8String]; + + if (freeWhenDone) + OFFreeMemory(UTF8String); return ret; } - (instancetype)initWithUTF8StringNoCopy: (char *)UTF8String length: (size_t)UTF8StringLength freeWhenDone: (bool)freeWhenDone { - id ret; - - @try { - ret = [self initWithUTF8String: UTF8String - length: UTF8StringLength]; - } @finally { - if (freeWhenDone) - of_free(UTF8String); - } + id ret = [self initWithUTF8String: UTF8String length: UTF8StringLength]; + + if (freeWhenDone) + OFFreeMemory(UTF8String); return ret; } - (instancetype)initWithCString: (const char *)cString - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding { return [self initWithCString: cString encoding: encoding length: strlen(cString)]; } - (instancetype)initWithCString: (const char *)cString - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding length: (size_t)cStringLength { OF_INVALID_INIT_METHOD } - (instancetype)initWithData: (OFData *)data - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding { @try { if (data.itemSize != 1) @throw [OFInvalidArgumentException exception]; } @catch (id e) { @@ -901,72 +898,72 @@ - (instancetype)initWithString: (OFString *)string { OF_INVALID_INIT_METHOD } -- (instancetype)initWithCharacters: (const of_unichar_t *)string - length: (size_t)length -{ - OF_INVALID_INIT_METHOD -} - -- (instancetype)initWithUTF16String: (const of_char16_t *)string -{ - return [self initWithUTF16String: string - length: of_string_utf16_length(string) - byteOrder: OF_BYTE_ORDER_NATIVE]; -} - -- (instancetype)initWithUTF16String: (const of_char16_t *)string - length: (size_t)length -{ - return [self initWithUTF16String: string - length: length - byteOrder: OF_BYTE_ORDER_NATIVE]; -} - -- (instancetype)initWithUTF16String: (const of_char16_t *)string - byteOrder: (of_byte_order_t)byteOrder -{ - return [self initWithUTF16String: string - length: of_string_utf16_length(string) - byteOrder: byteOrder]; -} - -- (instancetype)initWithUTF16String: (const of_char16_t *)string - length: (size_t)length - byteOrder: (of_byte_order_t)byteOrder -{ - OF_INVALID_INIT_METHOD -} - -- (instancetype)initWithUTF32String: (const of_char32_t *)string -{ - return [self initWithUTF32String: string - length: of_string_utf32_length(string) - byteOrder: OF_BYTE_ORDER_NATIVE]; -} - -- (instancetype)initWithUTF32String: (const of_char32_t *)string - length: (size_t)length -{ - return [self initWithUTF32String: string - length: length - byteOrder: OF_BYTE_ORDER_NATIVE]; -} - -- (instancetype)initWithUTF32String: (const of_char32_t *)string - byteOrder: (of_byte_order_t)byteOrder -{ - return [self initWithUTF32String: string - length: of_string_utf32_length(string) - byteOrder: byteOrder]; -} - -- (instancetype)initWithUTF32String: (const of_char32_t *)string - length: (size_t)length - byteOrder: (of_byte_order_t)byteOrder +- (instancetype)initWithCharacters: (const OFUnichar *)string + length: (size_t)length +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)initWithUTF16String: (const OFChar16 *)string +{ + return [self initWithUTF16String: string + length: OFUTF16StringLength(string) + byteOrder: OFByteOrderNative]; +} + +- (instancetype)initWithUTF16String: (const OFChar16 *)string + length: (size_t)length +{ + return [self initWithUTF16String: string + length: length + byteOrder: OFByteOrderNative]; +} + +- (instancetype)initWithUTF16String: (const OFChar16 *)string + byteOrder: (OFByteOrder)byteOrder +{ + return [self initWithUTF16String: string + length: OFUTF16StringLength(string) + byteOrder: byteOrder]; +} + +- (instancetype)initWithUTF16String: (const OFChar16 *)string + length: (size_t)length + byteOrder: (OFByteOrder)byteOrder +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)initWithUTF32String: (const OFChar32 *)string +{ + return [self initWithUTF32String: string + length: OFUTF32StringLength(string) + byteOrder: OFByteOrderNative]; +} + +- (instancetype)initWithUTF32String: (const OFChar32 *)string + length: (size_t)length +{ + return [self initWithUTF32String: string + length: length + byteOrder: OFByteOrderNative]; +} + +- (instancetype)initWithUTF32String: (const OFChar32 *)string + byteOrder: (OFByteOrder)byteOrder +{ + return [self initWithUTF32String: string + length: OFUTF32StringLength(string) + byteOrder: byteOrder]; +} + +- (instancetype)initWithUTF32String: (const OFChar32 *)string + length: (size_t)length + byteOrder: (OFByteOrder)byteOrder { OF_INVALID_INIT_METHOD } - (instancetype)initWithFormat: (OFConstantString *)format, ... @@ -973,12 +970,11 @@ { id ret; va_list arguments; va_start(arguments, format); - ret = [self initWithFormat: format - arguments: arguments]; + ret = [self initWithFormat: format arguments: arguments]; va_end(arguments); return ret; } @@ -990,15 +986,15 @@ #ifdef OF_HAVE_FILES - (instancetype)initWithContentsOfFile: (OFString *)path { return [self initWithContentsOfFile: path - encoding: OF_STRING_ENCODING_UTF_8]; + encoding: OFStringEncodingUTF8]; } - (instancetype)initWithContentsOfFile: (OFString *)path - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding { char *tmp; unsigned long long fileSize; @try { @@ -1027,19 +1023,17 @@ * to use -[initWithUTF8StringNoCopy:length:freeWhenDone:]. */ if (SIZE_MAX - (size_t)fileSize < 1) @throw [OFOutOfRangeException exception]; - tmp = of_malloc(1, (size_t)fileSize + 1); + tmp = OFAllocMemory((size_t)fileSize + 1, 1); @try { - file = [[OFFile alloc] initWithPath: path - mode: @"r"]; - + file = [[OFFile alloc] initWithPath: path mode: @"r"]; [file readIntoBuffer: tmp exactLength: (size_t)fileSize]; } @catch (id e) { - of_free(tmp); + OFFreeMemory(tmp); @throw e; } @finally { [file release]; } @@ -1047,21 +1041,26 @@ } @catch (id e) { [self release]; @throw e; } - if (encoding == OF_STRING_ENCODING_UTF_8) - self = [self initWithUTF8StringNoCopy: tmp - length: (size_t)fileSize - freeWhenDone: true]; - else { + if (encoding == OFStringEncodingUTF8) { + @try { + self = [self initWithUTF8StringNoCopy: tmp + length: (size_t)fileSize + freeWhenDone: true]; + } @catch (id e) { + OFFreeMemory(tmp); + @throw e; + } + } else { @try { self = [self initWithCString: tmp encoding: encoding length: (size_t)fileSize]; } @finally { - of_free(tmp); + OFFreeMemory(tmp); } } return self; } @@ -1068,15 +1067,15 @@ #endif - (instancetype)initWithContentsOfURL: (OFURL *)URL { return [self initWithContentsOfURL: URL - encoding: OF_STRING_ENCODING_AUTODETECT]; + encoding: OFStringEncodingAutodetect]; } - (instancetype)initWithContentsOfURL: (OFURL *)URL - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding { void *pool = objc_autoreleasePoolPush(); OFData *data; @try { @@ -1099,11 +1098,11 @@ { void *pool = objc_autoreleasePoolPush(); OFString *stringValue; @try { - if (![element.namespace isEqual: OF_SERIALIZATION_NS]) + if (![element.namespace isEqual: OFSerializationNS]) @throw [OFInvalidArgumentException exception]; if ([self isKindOfClass: [OFMutableString class]]) { if (![element.name isEqual: @"OFMutableString"]) @throw [OFInvalidArgumentException exception]; @@ -1125,24 +1124,23 @@ return self; } - (size_t)of_getCString: (char *)cString maxLength: (size_t)maxLength - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding lossy: (bool)lossy { - const of_unichar_t *characters = self.characters; + const OFUnichar *characters = self.characters; size_t i, length = self.length; switch (encoding) { - case OF_STRING_ENCODING_UTF_8:; + case OFStringEncodingUTF8:; size_t j = 0; for (i = 0; i < length; i++) { char buffer[4]; - size_t len = of_string_utf8_encode(characters[i], - buffer); + size_t len = OFUTF8StringEncode(characters[i], buffer); /* * Check for one more than the current index, as we * need one for the terminating zero. */ @@ -1169,11 +1167,11 @@ } cString[j] = '\0'; return j; - case OF_STRING_ENCODING_ASCII: + case OFStringEncodingASCII: if (length + 1 > maxLength) @throw [OFOutOfRangeException exception]; for (i = 0; i < length; i++) { if OF_UNLIKELY (characters[i] > 0x80) { @@ -1187,11 +1185,11 @@ } cString[i] = '\0'; return length; - case OF_STRING_ENCODING_ISO_8859_1: + case OFStringEncodingISO8859_1: if (length + 1 > maxLength) @throw [OFOutOfRangeException exception]; for (i = 0; i < length; i++) { if OF_UNLIKELY (characters[i] > 0xFF) { @@ -1206,146 +1204,146 @@ cString[i] = '\0'; return length; #ifdef HAVE_ISO_8859_2 - case OF_STRING_ENCODING_ISO_8859_2: + case OFStringEncodingISO8859_2: if (length + 1 > maxLength) @throw [OFOutOfRangeException exception]; - if (!of_unicode_to_iso_8859_2(characters, - (unsigned char *)cString, length, lossy)) + if (!OFUnicodeToISO8859_2(characters, (unsigned char *)cString, + length, lossy)) @throw [OFInvalidEncodingException exception]; cString[length] = '\0'; return length; #endif #ifdef HAVE_ISO_8859_3 - case OF_STRING_ENCODING_ISO_8859_3: + case OFStringEncodingISO8859_3: if (length + 1 > maxLength) @throw [OFOutOfRangeException exception]; - if (!of_unicode_to_iso_8859_3(characters, - (unsigned char *)cString, length, lossy)) + if (!OFUnicodeToISO8859_3(characters, (unsigned char *)cString, + length, lossy)) @throw [OFInvalidEncodingException exception]; cString[length] = '\0'; return length; #endif #ifdef HAVE_ISO_8859_15 - case OF_STRING_ENCODING_ISO_8859_15: + case OFStringEncodingISO8859_15: if (length + 1 > maxLength) @throw [OFOutOfRangeException exception]; - if (!of_unicode_to_iso_8859_15(characters, - (unsigned char *)cString, length, lossy)) + if (!OFUnicodeToISO8859_15(characters, (unsigned char *)cString, + length, lossy)) @throw [OFInvalidEncodingException exception]; cString[length] = '\0'; return length; #endif #ifdef HAVE_WINDOWS_1251 - case OF_STRING_ENCODING_WINDOWS_1251: + case OFStringEncodingWindows1251: if (length + 1 > maxLength) @throw [OFOutOfRangeException exception]; - if (!of_unicode_to_windows_1251(characters, + if (!OFUnicodeToWindows1251(characters, (unsigned char *)cString, length, lossy)) @throw [OFInvalidEncodingException exception]; cString[length] = '\0'; return length; #endif #ifdef HAVE_WINDOWS_1252 - case OF_STRING_ENCODING_WINDOWS_1252: + case OFStringEncodingWindows1252: if (length + 1 > maxLength) @throw [OFOutOfRangeException exception]; - if (!of_unicode_to_windows_1252(characters, + if (!OFUnicodeToWindows1252(characters, (unsigned char *)cString, length, lossy)) @throw [OFInvalidEncodingException exception]; cString[length] = '\0'; return length; #endif #ifdef HAVE_CODEPAGE_437 - case OF_STRING_ENCODING_CODEPAGE_437: + case OFStringEncodingCodepage437: if (length + 1 > maxLength) @throw [OFOutOfRangeException exception]; - if (!of_unicode_to_codepage_437(characters, + if (!OFUnicodeToCodepage437(characters, (unsigned char *)cString, length, lossy)) @throw [OFInvalidEncodingException exception]; cString[length] = '\0'; return length; #endif #ifdef HAVE_CODEPAGE_850 - case OF_STRING_ENCODING_CODEPAGE_850: + case OFStringEncodingCodepage850: if (length + 1 > maxLength) @throw [OFOutOfRangeException exception]; - if (!of_unicode_to_codepage_850(characters, + if (!OFUnicodeToCodepage850(characters, (unsigned char *)cString, length, lossy)) @throw [OFInvalidEncodingException exception]; cString[length] = '\0'; return length; #endif #ifdef HAVE_CODEPAGE_858 - case OF_STRING_ENCODING_CODEPAGE_858: + case OFStringEncodingCodepage858: if (length + 1 > maxLength) @throw [OFOutOfRangeException exception]; - if (!of_unicode_to_codepage_858(characters, + if (!OFUnicodeToCodepage858(characters, (unsigned char *)cString, length, lossy)) @throw [OFInvalidEncodingException exception]; cString[length] = '\0'; return length; #endif #ifdef HAVE_MAC_ROMAN - case OF_STRING_ENCODING_MAC_ROMAN: + case OFStringEncodingMacRoman: if (length + 1 > maxLength) @throw [OFOutOfRangeException exception]; - if (!of_unicode_to_mac_roman(characters, - (unsigned char *)cString, length, lossy)) + if (!OFUnicodeToMacRoman(characters, (unsigned char *)cString, + length, lossy)) @throw [OFInvalidEncodingException exception]; cString[length] = '\0'; return length; #endif #ifdef HAVE_KOI8_R - case OF_STRING_ENCODING_KOI8_R: + case OFStringEncodingKOI8R: if (length + 1 > maxLength) @throw [OFOutOfRangeException exception]; - if (!of_unicode_to_koi8_r(characters, - (unsigned char *)cString, length, lossy)) + if (!OFUnicodeToKOI8R(characters, (unsigned char *)cString, + length, lossy)) @throw [OFInvalidEncodingException exception]; cString[length] = '\0'; return length; #endif #ifdef HAVE_KOI8_U - case OF_STRING_ENCODING_KOI8_U: + case OFStringEncodingKOI8U: if (length + 1 > maxLength) @throw [OFOutOfRangeException exception]; - if (!of_unicode_to_koi8_u(characters, - (unsigned char *)cString, length, lossy)) + if (!OFUnicodeToKOI8U(characters, (unsigned char *)cString, + length, lossy)) @throw [OFInvalidEncodingException exception]; cString[length] = '\0'; return length; @@ -1356,188 +1354,203 @@ } } - (size_t)getCString: (char *)cString maxLength: (size_t)maxLength - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding { return [self of_getCString: cString maxLength: maxLength encoding: encoding lossy: false]; } - (size_t)getLossyCString: (char *)cString maxLength: (size_t)maxLength - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding { return [self of_getCString: cString maxLength: maxLength encoding: encoding lossy: true]; } -- (const char *)of_cStringWithEncoding: (of_string_encoding_t)encoding +- (const char *)of_cStringWithEncoding: (OFStringEncoding)encoding lossy: (bool)lossy { - OFObject *object = [[[OFObject alloc] init] autorelease]; size_t length = self.length; char *cString; + size_t cStringLength; + const char *ret; switch (encoding) { - case OF_STRING_ENCODING_UTF_8:; - size_t cStringLength; - - cString = [object allocMemoryWithSize: (length * 4) + 1]; - - cStringLength = [self of_getCString: cString - maxLength: (length * 4) + 1 - encoding: OF_STRING_ENCODING_UTF_8 - lossy: lossy]; + case OFStringEncodingUTF8: + cString = OFAllocMemory((length * 4) + 1, 1); + + @try { + cStringLength = [self + of_getCString: cString + maxLength: (length * 4) + 1 + encoding: OFStringEncodingUTF8 + lossy: lossy]; + } @catch (id e) { + OFFreeMemory(cString); + @throw e; + } @try { - cString = [object resizeMemory: cString - size: cStringLength + 1]; + cString = OFResizeMemory(cString, cStringLength + 1, 1); } @catch (OFOutOfMemoryException *e) { /* We don't care, as we only tried to make it smaller */ } break; - case OF_STRING_ENCODING_ASCII: - case OF_STRING_ENCODING_ISO_8859_1: - case OF_STRING_ENCODING_ISO_8859_2: - case OF_STRING_ENCODING_ISO_8859_3: - case OF_STRING_ENCODING_ISO_8859_15: - case OF_STRING_ENCODING_WINDOWS_1251: - case OF_STRING_ENCODING_WINDOWS_1252: - case OF_STRING_ENCODING_CODEPAGE_437: - case OF_STRING_ENCODING_CODEPAGE_850: - case OF_STRING_ENCODING_CODEPAGE_858: - case OF_STRING_ENCODING_MAC_ROMAN: - case OF_STRING_ENCODING_KOI8_R: - case OF_STRING_ENCODING_KOI8_U: - cString = [object allocMemoryWithSize: length + 1]; - - [self of_getCString: cString - maxLength: length + 1 - encoding: encoding - lossy: lossy]; + case OFStringEncodingASCII: + case OFStringEncodingISO8859_1: + case OFStringEncodingISO8859_2: + case OFStringEncodingISO8859_3: + case OFStringEncodingISO8859_15: + case OFStringEncodingWindows1251: + case OFStringEncodingWindows1252: + case OFStringEncodingCodepage437: + case OFStringEncodingCodepage850: + case OFStringEncodingCodepage858: + case OFStringEncodingMacRoman: + case OFStringEncodingKOI8R: + case OFStringEncodingKOI8U: + cString = OFAllocMemory(length + 1, 1); + + @try { + cStringLength = [self of_getCString: cString + maxLength: length + 1 + encoding: encoding + lossy: lossy]; + } @catch (id e) { + OFFreeMemory(cString); + @throw e; + } break; default: @throw [OFInvalidEncodingException exception]; } - return cString; + @try { + ret = [[OFData dataWithItemsNoCopy: cString + count: cStringLength + 1 + freeWhenDone: true] items]; + } @catch (id e) { + OFFreeMemory(cString); + @throw e; + } + + return ret; } -- (const char *)cStringWithEncoding: (of_string_encoding_t)encoding +- (const char *)cStringWithEncoding: (OFStringEncoding)encoding { - return [self of_cStringWithEncoding: encoding - lossy: false]; + return [self of_cStringWithEncoding: encoding lossy: false]; } -- (const char *)lossyCStringWithEncoding: (of_string_encoding_t)encoding +- (const char *)lossyCStringWithEncoding: (OFStringEncoding)encoding { - return [self of_cStringWithEncoding: encoding - lossy: true]; + return [self of_cStringWithEncoding: encoding lossy: true]; } - (const char *)UTF8String { - return [self cStringWithEncoding: OF_STRING_ENCODING_UTF_8]; + return [self cStringWithEncoding: OFStringEncodingUTF8]; } - (size_t)length { OF_UNRECOGNIZED_SELECTOR } -- (size_t)cStringLengthWithEncoding: (of_string_encoding_t)encoding +- (size_t)cStringLengthWithEncoding: (OFStringEncoding)encoding { switch (encoding) { - case OF_STRING_ENCODING_UTF_8:; - const of_unichar_t *characters; + case OFStringEncodingUTF8:; + const OFUnichar *characters; size_t length, UTF8StringLength = 0; characters = self.characters; length = self.length; for (size_t i = 0; i < length; i++) { char buffer[4]; - size_t len = of_string_utf8_encode(characters[i], - buffer); + size_t len = OFUTF8StringEncode(characters[i], buffer); if (len == 0) @throw [OFInvalidEncodingException exception]; UTF8StringLength += len; } return UTF8StringLength; - case OF_STRING_ENCODING_ASCII: - case OF_STRING_ENCODING_ISO_8859_1: - case OF_STRING_ENCODING_ISO_8859_2: - case OF_STRING_ENCODING_ISO_8859_3: - case OF_STRING_ENCODING_ISO_8859_15: - case OF_STRING_ENCODING_WINDOWS_1251: - case OF_STRING_ENCODING_WINDOWS_1252: - case OF_STRING_ENCODING_CODEPAGE_437: - case OF_STRING_ENCODING_CODEPAGE_850: - case OF_STRING_ENCODING_CODEPAGE_858: - case OF_STRING_ENCODING_MAC_ROMAN: - case OF_STRING_ENCODING_KOI8_R: - case OF_STRING_ENCODING_KOI8_U: + case OFStringEncodingASCII: + case OFStringEncodingISO8859_1: + case OFStringEncodingISO8859_2: + case OFStringEncodingISO8859_3: + case OFStringEncodingISO8859_15: + case OFStringEncodingWindows1251: + case OFStringEncodingWindows1252: + case OFStringEncodingCodepage437: + case OFStringEncodingCodepage850: + case OFStringEncodingCodepage858: + case OFStringEncodingMacRoman: + case OFStringEncodingKOI8R: + case OFStringEncodingKOI8U: return self.length; default: @throw [OFInvalidEncodingException exception]; } } - (size_t)UTF8StringLength { - return [self cStringLengthWithEncoding: OF_STRING_ENCODING_UTF_8]; + return [self cStringLengthWithEncoding: OFStringEncodingUTF8]; } -- (of_unichar_t)characterAtIndex: (size_t)idx +- (OFUnichar)characterAtIndex: (size_t)idx { OF_UNRECOGNIZED_SELECTOR } -- (void)getCharacters: (of_unichar_t *)buffer - inRange: (of_range_t)range +- (void)getCharacters: (OFUnichar *)buffer + inRange: (OFRange)range { for (size_t i = 0; i < range.length; i++) buffer[i] = [self characterAtIndex: range.location + i]; } - (bool)isEqual: (id)object { void *pool; - OFString *otherString; - const of_unichar_t *characters, *otherCharacters; + OFString *string; + const OFUnichar *characters, *otherCharacters; size_t length; if (object == self) return true; if (![object isKindOfClass: [OFString class]]) return false; - otherString = object; + string = object; length = self.length; - if (otherString.length != length) + if (string.length != length) return false; pool = objc_autoreleasePoolPush(); characters = self.characters; - otherCharacters = otherString.characters; + otherCharacters = string.characters; if (memcmp(characters, otherCharacters, - length * sizeof(of_unichar_t)) != 0) { + length * sizeof(OFUnichar)) != 0) { objc_autoreleasePoolPop(pool); return false; } objc_autoreleasePoolPop(pool); @@ -1553,131 +1566,129 @@ - (id)mutableCopy { return [[OFMutableString alloc] initWithString: self]; } -- (of_comparison_result_t)compare: (id )object +- (OFComparisonResult)compare: (OFString *)string { void *pool; - OFString *otherString; - const of_unichar_t *characters, *otherCharacters; + const OFUnichar *characters, *otherCharacters; size_t minimumLength; - if (object == self) - return OF_ORDERED_SAME; + if (string == self) + return OFOrderedSame; - if (![(id)object isKindOfClass: [OFString class]]) + if (![string isKindOfClass: [OFString class]]) @throw [OFInvalidArgumentException exception]; - otherString = (OFString *)object; - minimumLength = (self.length > otherString.length - ? otherString.length : self.length); + minimumLength = (self.length > string.length + ? string.length : self.length); pool = objc_autoreleasePoolPush(); characters = self.characters; - otherCharacters = otherString.characters; + otherCharacters = string.characters; for (size_t i = 0; i < minimumLength; i++) { if (characters[i] > otherCharacters[i]) { objc_autoreleasePoolPop(pool); - return OF_ORDERED_DESCENDING; + return OFOrderedDescending; } if (characters[i] < otherCharacters[i]) { objc_autoreleasePoolPop(pool); - return OF_ORDERED_ASCENDING; + return OFOrderedAscending; } } objc_autoreleasePoolPop(pool); - if (self.length > otherString.length) - return OF_ORDERED_DESCENDING; - if (self.length < otherString.length) - return OF_ORDERED_ASCENDING; + if (self.length > string.length) + return OFOrderedDescending; + if (self.length < string.length) + return OFOrderedAscending; - return OF_ORDERED_SAME; + return OFOrderedSame; } -- (of_comparison_result_t)caseInsensitiveCompare: (OFString *)otherString +- (OFComparisonResult)caseInsensitiveCompare: (OFString *)string { void *pool = objc_autoreleasePoolPush(); - const of_unichar_t *characters, *otherCharacters; + const OFUnichar *characters, *otherCharacters; size_t length, otherLength, minimumLength; - if (otherString == self) - return OF_ORDERED_SAME; + if (string == self) + return OFOrderedSame; characters = self.characters; - otherCharacters = otherString.characters; + otherCharacters = string.characters; length = self.length; - otherLength = otherString.length; + otherLength = string.length; minimumLength = (length > otherLength ? otherLength : length); for (size_t i = 0; i < minimumLength; i++) { - of_unichar_t c = characters[i]; - of_unichar_t oc = otherCharacters[i]; + OFUnichar c = characters[i]; + OFUnichar oc = otherCharacters[i]; #ifdef OF_HAVE_UNICODE_TABLES - if (c >> 8 < OF_UNICODE_CASEFOLDING_TABLE_SIZE) { - of_unichar_t tc = - of_unicode_casefolding_table[c >> 8][c & 0xFF]; + if (c >> 8 < OFUnicodeCaseFoldingTableSize) { + OFUnichar tc = + OFUnicodeCaseFoldingTable[c >> 8][c & 0xFF]; if (tc) c = tc; } - if (oc >> 8 < OF_UNICODE_CASEFOLDING_TABLE_SIZE) { - of_unichar_t tc = - of_unicode_casefolding_table[oc >> 8][oc & 0xFF]; + if (oc >> 8 < OFUnicodeCaseFoldingTableSize) { + OFUnichar tc = + OFUnicodeCaseFoldingTable[oc >> 8][oc & 0xFF]; if (tc) oc = tc; } #else - c = of_ascii_toupper(c); - oc = of_ascii_toupper(oc); + c = OFASCIIToUpper(c); + oc = OFASCIIToUpper(oc); #endif if (c > oc) { objc_autoreleasePoolPop(pool); - return OF_ORDERED_DESCENDING; + return OFOrderedDescending; } if (c < oc) { objc_autoreleasePoolPop(pool); - return OF_ORDERED_ASCENDING; + return OFOrderedAscending; } } objc_autoreleasePoolPop(pool); if (length > otherLength) - return OF_ORDERED_DESCENDING; + return OFOrderedDescending; if (length < otherLength) - return OF_ORDERED_ASCENDING; + return OFOrderedAscending; - return OF_ORDERED_SAME; + return OFOrderedSame; } - (unsigned long)hash { - const of_unichar_t *characters = self.characters; + const OFUnichar *characters = self.characters; size_t length = self.length; - uint32_t hash; + unsigned long hash; - OF_HASH_INIT(hash); + OFHashInit(&hash); for (size_t i = 0; i < length; i++) { - const of_unichar_t c = characters[i]; + const OFUnichar c = characters[i]; - OF_HASH_ADD(hash, (c & 0xFF0000) >> 16); - OF_HASH_ADD(hash, (c & 0x00FF00) >> 8); - OF_HASH_ADD(hash, c & 0x0000FF); + OFHashAdd(&hash, (c & 0xFF0000) >> 16); + OFHashAdd(&hash, (c & 0x00FF00) >> 8); + OFHashAdd(&hash, c & 0x0000FF); } - OF_HASH_FINALIZE(hash); + OFHashFinalize(&hash); return hash; } - (OFString *)description @@ -1695,11 +1706,11 @@ className = @"OFMutableString"; else className = @"OFString"; element = [OFXMLElement elementWithName: className - namespace: OF_SERIALIZATION_NS + namespace: OFSerializationNS stringValue: self]; [element retain]; objc_autoreleasePoolPop(pool); @@ -1707,47 +1718,40 @@ return [element autorelease]; } - (OFString *)JSONRepresentation { - return [self of_JSONRepresentationWithOptions: 0 - depth: 0]; + return [self of_JSONRepresentationWithOptions: 0 depth: 0]; } -- (OFString *)JSONRepresentationWithOptions: (int)options +- (OFString *)JSONRepresentationWithOptions: + (OFJSONRepresentationOptions)options { - return [self of_JSONRepresentationWithOptions: options - depth: 0]; + return [self of_JSONRepresentationWithOptions: options depth: 0]; } -- (OFString *)of_JSONRepresentationWithOptions: (int)options - depth: (size_t)depth +- (OFString *) + of_JSONRepresentationWithOptions: (OFJSONRepresentationOptions)options + depth: (size_t)depth { OFMutableString *JSON = [[self mutableCopy] autorelease]; /* FIXME: This is slow! Write it in pure C! */ - [JSON replaceOccurrencesOfString: @"\\" - withString: @"\\\\"]; - [JSON replaceOccurrencesOfString: @"\"" - withString: @"\\\""]; - [JSON replaceOccurrencesOfString: @"\b" - withString: @"\\b"]; - [JSON replaceOccurrencesOfString: @"\f" - withString: @"\\f"]; - [JSON replaceOccurrencesOfString: @"\r" - withString: @"\\r"]; - [JSON replaceOccurrencesOfString: @"\t" - withString: @"\\t"]; - - if (options & OF_JSON_REPRESENTATION_JSON5) { - [JSON replaceOccurrencesOfString: @"\n" - withString: @"\\\n"]; - - if (options & OF_JSON_REPRESENTATION_IDENTIFIER) { + [JSON replaceOccurrencesOfString: @"\\" withString: @"\\\\"]; + [JSON replaceOccurrencesOfString: @"\"" withString: @"\\\""]; + [JSON replaceOccurrencesOfString: @"\b" withString: @"\\b"]; + [JSON replaceOccurrencesOfString: @"\f" withString: @"\\f"]; + [JSON replaceOccurrencesOfString: @"\r" withString: @"\\r"]; + [JSON replaceOccurrencesOfString: @"\t" withString: @"\\t"]; + + if (options & OFJSONRepresentationOptionJSON5) { + [JSON replaceOccurrencesOfString: @"\n" withString: @"\\\n"]; + + if (options & OFJSONRepresentationOptionIsIdentifier) { const char *cString = self.UTF8String; - if ((!of_ascii_isalpha(cString[0]) && + if ((!OFASCIIIsAlpha(cString[0]) && cString[0] != '_' && cString[0] != '$') || strpbrk(cString, " \n\r\t\b\f\\\"'") != NULL) { [JSON prependString: @"\""]; [JSON appendString: @"\""]; } @@ -1754,12 +1758,11 @@ } else { [JSON prependString: @"\""]; [JSON appendString: @"\""]; } } else { - [JSON replaceOccurrencesOfString: @"\n" - withString: @"\\n"]; + [JSON replaceOccurrencesOfString: @"\n" withString: @"\\n"]; [JSON prependString: @"\""]; [JSON appendString: @"\""]; } @@ -1776,100 +1779,88 @@ length = self.UTF8StringLength; if (length <= 31) { uint8_t tmp = 0xA0 | ((uint8_t)length & 0x1F); - data = [OFMutableData dataWithItemSize: 1 - capacity: length + 1]; - + data = [OFMutableData dataWithCapacity: length + 1]; [data addItem: &tmp]; } else if (length <= UINT8_MAX) { uint8_t type = 0xD9; uint8_t tmp = (uint8_t)length; - data = [OFMutableData dataWithItemSize: 1 - capacity: length + 2]; - + data = [OFMutableData dataWithCapacity: length + 2]; [data addItem: &type]; [data addItem: &tmp]; } else if (length <= UINT16_MAX) { uint8_t type = 0xDA; - uint16_t tmp = OF_BSWAP16_IF_LE((uint16_t)length); + uint16_t tmp = OFToBigEndian16((uint16_t)length); - data = [OFMutableData dataWithItemSize: 1 - capacity: length + 3]; - + data = [OFMutableData dataWithCapacity: length + 3]; [data addItem: &type]; - [data addItems: &tmp - count: sizeof(tmp)]; + [data addItems: &tmp count: sizeof(tmp)]; } else if (length <= UINT32_MAX) { uint8_t type = 0xDB; - uint32_t tmp = OF_BSWAP32_IF_LE((uint32_t)length); + uint32_t tmp = OFToBigEndian32((uint32_t)length); - data = [OFMutableData dataWithItemSize: 1 - capacity: length + 5]; - + data = [OFMutableData dataWithCapacity: length + 5]; [data addItem: &type]; - [data addItems: &tmp - count: sizeof(tmp)]; + [data addItems: &tmp count: sizeof(tmp)]; } else @throw [OFOutOfRangeException exception]; - [data addItems: self.UTF8String - count: length]; + [data addItems: self.UTF8String count: length]; return data; } -- (of_range_t)rangeOfString: (OFString *)string +- (OFRange)rangeOfString: (OFString *)string { return [self rangeOfString: string options: 0 - range: of_range(0, self.length)]; + range: OFRangeMake(0, self.length)]; } -- (of_range_t)rangeOfString: (OFString *)string - options: (int)options +- (OFRange)rangeOfString: (OFString *)string + options: (OFStringSearchOptions)options { return [self rangeOfString: string options: options - range: of_range(0, self.length)]; + range: OFRangeMake(0, self.length)]; } -- (of_range_t)rangeOfString: (OFString *)string - options: (int)options - range: (of_range_t)range +- (OFRange)rangeOfString: (OFString *)string + options: (OFStringSearchOptions)options + range: (OFRange)range { void *pool; - const of_unichar_t *searchCharacters; - of_unichar_t *characters; + const OFUnichar *searchCharacters; + OFUnichar *characters; size_t searchLength; if ((searchLength = string.length) == 0) - return of_range(0, 0); + return OFRangeMake(0, 0); if (searchLength > range.length) - return of_range(OF_NOT_FOUND, 0); + return OFRangeMake(OFNotFound, 0); - if (range.length > SIZE_MAX / sizeof(of_unichar_t)) + if (range.length > SIZE_MAX / sizeof(OFUnichar)) @throw [OFOutOfRangeException exception]; pool = objc_autoreleasePoolPush(); searchCharacters = string.characters; - characters = of_malloc(range.length, sizeof(of_unichar_t)); + characters = OFAllocMemory(range.length, sizeof(OFUnichar)); @try { - [self getCharacters: characters - inRange: range]; + [self getCharacters: characters inRange: range]; - if (options & OF_STRING_SEARCH_BACKWARDS) { + if (options & OFStringSearchBackwards) { for (size_t i = range.length - searchLength;; i--) { if (memcmp(characters + i, searchCharacters, - searchLength * sizeof(of_unichar_t)) == 0) { + searchLength * sizeof(OFUnichar)) == 0) { objc_autoreleasePoolPop(pool); - return of_range(range.location + i, + return OFRangeMake(range.location + i, searchLength); } /* No match and we're at the last character */ if (i == 0) @@ -1877,62 +1868,61 @@ } } else { for (size_t i = 0; i <= range.length - searchLength; i++) { if (memcmp(characters + i, searchCharacters, - searchLength * sizeof(of_unichar_t)) == 0) { + searchLength * sizeof(OFUnichar)) == 0) { objc_autoreleasePoolPop(pool); - return of_range(range.location + i, + return OFRangeMake(range.location + i, searchLength); } } } } @finally { - of_free(characters); + OFFreeMemory(characters); } objc_autoreleasePoolPop(pool); - return of_range(OF_NOT_FOUND, 0); + return OFRangeMake(OFNotFound, 0); } - (size_t)indexOfCharacterFromSet: (OFCharacterSet *)characterSet { return [self indexOfCharacterFromSet: characterSet options: 0 - range: of_range(0, self.length)]; -} - -- (size_t)indexOfCharacterFromSet: (OFCharacterSet *)characterSet - options: (int)options -{ - return [self indexOfCharacterFromSet: characterSet - options: options - range: of_range(0, self.length)]; -} - -- (size_t)indexOfCharacterFromSet: (OFCharacterSet *)characterSet - options: (int)options - range: (of_range_t)range -{ - bool (*characterIsMember)(id, SEL, of_unichar_t) = - (bool (*)(id, SEL, of_unichar_t))[characterSet - methodForSelector: @selector(characterIsMember:)]; - of_unichar_t *characters; - - if (range.length == 0) - return OF_NOT_FOUND; - - if (range.length > SIZE_MAX / sizeof(of_unichar_t)) - @throw [OFOutOfRangeException exception]; - - characters = of_malloc(range.length, sizeof(of_unichar_t)); - @try { - [self getCharacters: characters - inRange: range]; - - if (options & OF_STRING_SEARCH_BACKWARDS) { + range: OFRangeMake(0, self.length)]; +} + +- (size_t)indexOfCharacterFromSet: (OFCharacterSet *)characterSet + options: (OFStringSearchOptions)options +{ + return [self indexOfCharacterFromSet: characterSet + options: options + range: OFRangeMake(0, self.length)]; +} + +- (size_t)indexOfCharacterFromSet: (OFCharacterSet *)characterSet + options: (OFStringSearchOptions)options + range: (OFRange)range +{ + bool (*characterIsMember)(id, SEL, OFUnichar) = + (bool (*)(id, SEL, OFUnichar))[characterSet + methodForSelector: @selector(characterIsMember:)]; + OFUnichar *characters; + + if (range.length == 0) + return OFNotFound; + + if (range.length > SIZE_MAX / sizeof(OFUnichar)) + @throw [OFOutOfRangeException exception]; + + characters = OFAllocMemory(range.length, sizeof(OFUnichar)); + @try { + [self getCharacters: characters inRange: range]; + + if (options & OFStringSearchBackwards) { for (size_t i = range.length - 1;; i--) { if (characterIsMember(characterSet, @selector(characterIsMember:), characters[i])) return range.location + i; @@ -1947,20 +1937,20 @@ @selector(characterIsMember:), characters[i])) return range.location + i; } } @finally { - of_free(characters); + OFFreeMemory(characters); } - return OF_NOT_FOUND; + return OFNotFound; } - (bool)containsString: (OFString *)string { void *pool; - const of_unichar_t *characters, *searchCharacters; + const OFUnichar *characters, *searchCharacters; size_t length, searchLength; if ((searchLength = string.length) == 0) return true; @@ -1972,11 +1962,11 @@ characters = self.characters; searchCharacters = string.characters; for (size_t i = 0; i <= length - searchLength; i++) { if (memcmp(characters + i, searchCharacters, - searchLength * sizeof(of_unichar_t)) == 0) { + searchLength * sizeof(OFUnichar)) == 0) { objc_autoreleasePoolPop(pool); return true; } } @@ -1985,19 +1975,19 @@ return false; } - (OFString *)substringFromIndex: (size_t)idx { - return [self substringWithRange: of_range(idx, self.length - idx)]; + return [self substringWithRange: OFRangeMake(idx, self.length - idx)]; } - (OFString *)substringToIndex: (size_t)idx { - return [self substringWithRange: of_range(0, idx)]; + return [self substringWithRange: OFRangeMake(0, idx)]; } -- (OFString *)substringWithRange: (of_range_t)range +- (OFString *)substringWithRange: (OFRange)range { void *pool; OFString *ret; if (range.length > SIZE_MAX - range.location || @@ -2029,217 +2019,186 @@ { OFString *ret; va_list arguments; va_start(arguments, format); - ret = [self stringByAppendingFormat: format - arguments: arguments]; + ret = [self stringByAppendingFormat: format arguments: arguments]; va_end(arguments); return ret; } - (OFString *)stringByAppendingFormat: (OFConstantString *)format arguments: (va_list)arguments { - OFMutableString *new; - - new = [OFMutableString stringWithString: self]; - [new appendFormat: format - arguments: arguments]; - + OFMutableString *new = [OFMutableString stringWithString: self]; + [new appendFormat: format arguments: arguments]; [new makeImmutable]; - return new; } - (OFString *)stringByPrependingString: (OFString *)string { OFMutableString *new = [[string mutableCopy] autorelease]; - [new appendString: self]; - [new makeImmutable]; - return new; } - (OFString *)stringByReplacingOccurrencesOfString: (OFString *)string withString: (OFString *)replacement { OFMutableString *new = [[self mutableCopy] autorelease]; - - [new replaceOccurrencesOfString: string - withString: replacement]; - + [new replaceOccurrencesOfString: string withString: replacement]; [new makeImmutable]; - return new; } - (OFString *)stringByReplacingOccurrencesOfString: (OFString *)string withString: (OFString *)replacement options: (int)options - range: (of_range_t)range + range: (OFRange)range { OFMutableString *new = [[self mutableCopy] autorelease]; - [new replaceOccurrencesOfString: string withString: replacement options: options range: range]; - [new makeImmutable]; - return new; } - (OFString *)uppercaseString { OFMutableString *new = [[self mutableCopy] autorelease]; - [new uppercase]; - [new makeImmutable]; - return new; } - (OFString *)lowercaseString { OFMutableString *new = [[self mutableCopy] autorelease]; - [new lowercase]; - [new makeImmutable]; - return new; } - (OFString *)capitalizedString { OFMutableString *new = [[self mutableCopy] autorelease]; - [new capitalize]; - [new makeImmutable]; - return new; } - (OFString *)stringByDeletingLeadingWhitespaces { OFMutableString *new = [[self mutableCopy] autorelease]; - [new deleteLeadingWhitespaces]; - [new makeImmutable]; - return new; } - (OFString *)stringByDeletingTrailingWhitespaces { OFMutableString *new = [[self mutableCopy] autorelease]; - [new deleteTrailingWhitespaces]; - [new makeImmutable]; - return new; } - (OFString *)stringByDeletingEnclosingWhitespaces { OFMutableString *new = [[self mutableCopy] autorelease]; - [new deleteEnclosingWhitespaces]; - [new makeImmutable]; - return new; } - (bool)hasPrefix: (OFString *)prefix { - of_unichar_t *tmp; + OFUnichar *tmp; size_t prefixLength; bool hasPrefix; if ((prefixLength = prefix.length) > self.length) return false; - tmp = [self allocMemoryWithSize: sizeof(of_unichar_t) - count: prefixLength]; + tmp = OFAllocMemory(prefixLength, sizeof(OFUnichar)); @try { void *pool = objc_autoreleasePoolPush(); - [self getCharacters: tmp - inRange: of_range(0, prefixLength)]; + [self getCharacters: tmp inRange: OFRangeMake(0, prefixLength)]; hasPrefix = (memcmp(tmp, prefix.characters, - prefixLength * sizeof(of_unichar_t)) == 0); + prefixLength * sizeof(OFUnichar)) == 0); objc_autoreleasePoolPop(pool); } @finally { - [self freeMemory: tmp]; + OFFreeMemory(tmp); } return hasPrefix; } - (bool)hasSuffix: (OFString *)suffix { - of_unichar_t *tmp; - const of_unichar_t *suffixCharacters; + OFUnichar *tmp; + const OFUnichar *suffixCharacters; size_t length, suffixLength; bool hasSuffix; if ((suffixLength = suffix.length) > self.length) return false; length = self.length; - tmp = [self allocMemoryWithSize: sizeof(of_unichar_t) - count: suffixLength]; + tmp = OFAllocMemory(suffixLength, sizeof(OFUnichar)); @try { void *pool = objc_autoreleasePoolPush(); [self getCharacters: tmp - inRange: of_range(length - suffixLength, + inRange: OFRangeMake(length - suffixLength, suffixLength)]; suffixCharacters = suffix.characters; hasSuffix = (memcmp(tmp, suffixCharacters, - suffixLength * sizeof(of_unichar_t)) == 0); + suffixLength * sizeof(OFUnichar)) == 0); objc_autoreleasePoolPop(pool); } @finally { - [self freeMemory: tmp]; + OFFreeMemory(tmp); } return hasSuffix; } - (OFArray *)componentsSeparatedByString: (OFString *)delimiter { - return [self componentsSeparatedByString: delimiter - options: 0]; + return [self componentsSeparatedByString: delimiter options: 0]; } - (OFArray *)componentsSeparatedByString: (OFString *)delimiter - options: (int)options + options: (OFStringSeparationOptions)options { void *pool; - OFMutableArray *array = [OFMutableArray array]; - const of_unichar_t *characters, *delimiterCharacters; - bool skipEmpty = (options & OF_STRING_SKIP_EMPTY); + OFMutableArray *array; + const OFUnichar *characters, *delimiterCharacters; + bool skipEmpty = (options & OFStringSkipEmptyComponents); size_t length = self.length; size_t delimiterLength = delimiter.length; size_t last; OFString *component; + if (delimiter == nil) + @throw [OFInvalidArgumentException exception]; + + if (delimiter.length == 0) + return [OFArray arrayWithObject: self]; + + array = [OFMutableArray array]; pool = objc_autoreleasePoolPush(); characters = self.characters; delimiterCharacters = delimiter.characters; @@ -2253,21 +2212,22 @@ } last = 0; for (size_t i = 0; i <= length - delimiterLength; i++) { if (memcmp(characters + i, delimiterCharacters, - delimiterLength * sizeof(of_unichar_t)) != 0) + delimiterLength * sizeof(OFUnichar)) != 0) continue; - component = [self substringWithRange: of_range(last, i - last)]; + component = [self substringWithRange: + OFRangeMake(last, i - last)]; if (!skipEmpty || component.length > 0) [array addObject: component]; i += delimiterLength - 1; last = i + 1; } - component = [self substringWithRange: of_range(last, length - last)]; + component = [self substringWithRange: OFRangeMake(last, length - last)]; if (!skipEmpty || component.length > 0) [array addObject: component]; [array makeImmutable]; @@ -2283,38 +2243,38 @@ options: 0]; } - (OFArray *) componentsSeparatedByCharactersInSet: (OFCharacterSet *)characterSet - options: (int)options + options: (OFStringSeparationOptions)options { OFMutableArray *array = [OFMutableArray array]; void *pool = objc_autoreleasePoolPush(); - bool skipEmpty = (options & OF_STRING_SKIP_EMPTY); - const of_unichar_t *characters = self.characters; + bool skipEmpty = (options & OFStringSkipEmptyComponents); + const OFUnichar *characters = self.characters; size_t length = self.length; - bool (*characterIsMember)(id, SEL, of_unichar_t) = - (bool (*)(id, SEL, of_unichar_t))[characterSet + bool (*characterIsMember)(id, SEL, OFUnichar) = + (bool (*)(id, SEL, OFUnichar))[characterSet methodForSelector: @selector(characterIsMember:)]; size_t last; last = 0; for (size_t i = 0; i < length; i++) { if (characterIsMember(characterSet, @selector(characterIsMember:), characters[i])) { if (!skipEmpty || i != last) { OFString *component = [self substringWithRange: - of_range(last, i - last)]; + OFRangeMake(last, i - last)]; [array addObject: component]; } last = i + 1; } } if (!skipEmpty || length != last) { OFString *component = [self substringWithRange: - of_range(last, length - last)]; + OFRangeMake(last, length - last)]; [array addObject: component]; } [array makeImmutable]; @@ -2330,25 +2290,71 @@ - (long long)longLongValueWithBase: (int)base { void *pool = objc_autoreleasePoolPush(); const char *UTF8String = self.UTF8String; - char *endPointer = NULL; - long long value; - - errno = 0; - value = strtoll(UTF8String, &endPointer, base); - - if ((value == LLONG_MIN || value == LLONG_MAX) && errno == ERANGE) - @throw [OFOutOfRangeException exception]; - - /* Check if there are any invalid chars left */ - if (endPointer != NULL) - for (; *endPointer != '\0'; endPointer++) - /* Use isspace since strtoll uses the same. */ - if (!isspace((unsigned char)*endPointer)) + bool negative = false; + long long value = 0; + + while (OFASCIIIsSpace(*UTF8String)) + UTF8String++; + + switch (*UTF8String) { + case '-': + negative = true; + case '+': + UTF8String++; + } + + if (UTF8String[0] == '0') { + if (UTF8String[1] == 'x') { + if (base == 0) + base = 16; + + if (base != 16 || UTF8String[2] == '\0') @throw [OFInvalidFormatException exception]; + + UTF8String += 2; + } else { + if (base == 0) + base = 8; + + UTF8String++; + } + } + + if (base == 0) + base = 10; + + while (*UTF8String != '\0') { + unsigned char c = OFASCIIToUpper(*UTF8String++); + + if (c >= '0' && c <= '9') + c -= '0'; + else if (c >= 'A' && c <= 'Z') + c -= ('A' - 10); + else if (OFASCIIIsSpace(c)) { + while (*UTF8String != '\0') + if (!OFASCIIIsSpace(*UTF8String++)) + @throw [OFInvalidFormatException + exception]; + + break; + } else + @throw [OFInvalidFormatException exception]; + + if (c >= base) + @throw [OFInvalidFormatException exception]; + + if (LLONG_MAX / base < value || LLONG_MAX - (value * base) < c) + @throw [OFOutOfRangeException exception]; + + value = (value * base) + c; + } + + if (negative) + value *= -1; objc_autoreleasePoolPop(pool); return value; } @@ -2360,32 +2366,68 @@ - (unsigned long long)unsignedLongLongValueWithBase: (int)base { void *pool = objc_autoreleasePoolPush(); const char *UTF8String = self.UTF8String; - char *endPointer = NULL; - unsigned long long value; - - /* Use isspace since strtoull uses the same. */ - while (isspace((unsigned char)*UTF8String)) - UTF8String++; - - if (*UTF8String == '-') - @throw [OFInvalidFormatException exception]; - - errno = 0; - value = strtoull(UTF8String, &endPointer, base); - - if (value == ULLONG_MAX && errno == ERANGE) - @throw [OFOutOfRangeException exception]; - - /* Check if there are any invalid chars left */ - if (endPointer != NULL) - for (; *endPointer != '\0'; endPointer++) - /* Use isspace since strtoull uses the same. */ - if (!isspace((unsigned char)*endPointer)) - @throw [OFInvalidFormatException exception]; + unsigned long long value = 0; + + while (OFASCIIIsSpace(*UTF8String)) + UTF8String++; + + switch (*UTF8String) { + case '-': + @throw [OFInvalidFormatException exception]; + case '+': + UTF8String++; + } + + if (UTF8String[0] == '0') { + if (UTF8String[1] == 'x') { + if (base == 0) + base = 16; + + if (base != 16 || UTF8String[2] == '\0') + @throw [OFInvalidFormatException exception]; + + UTF8String += 2; + } else { + if (base == 0) + base = 8; + + UTF8String++; + } + } + + if (base == 0) + base = 10; + + while (*UTF8String != '\0') { + unsigned char c = OFASCIIToUpper(*UTF8String++); + + if (c >= '0' && c <= '9') + c -= '0'; + else if (c >= 'A' && c <= 'Z') + c -= ('A' - 10); + else if (OFASCIIIsSpace(c)) { + while (*UTF8String != '\0') + if (!OFASCIIIsSpace(*UTF8String++)) + @throw [OFInvalidFormatException + exception]; + + break; + } else + @throw [OFInvalidFormatException exception]; + + if (c >= base) + @throw [OFInvalidFormatException exception]; + + if (ULLONG_MAX / base < value || + ULLONG_MAX - (value * base) < c) + @throw [OFOutOfRangeException exception]; + + value = (value * base) + c; + } objc_autoreleasePoolPop(pool); return value; } @@ -2393,16 +2435,20 @@ - (float)floatValue { void *pool = objc_autoreleasePoolPush(); OFString *stripped = self.stringByDeletingEnclosingWhitespaces; - if ([stripped caseInsensitiveCompare: @"INF"] == OF_ORDERED_SAME || - [stripped caseInsensitiveCompare: @"INFINITY"] == OF_ORDERED_SAME) + if ([stripped caseInsensitiveCompare: @"INF"] == OFOrderedSame || + [stripped caseInsensitiveCompare: @"INFINITY"] == OFOrderedSame) return INFINITY; - if ([stripped caseInsensitiveCompare: @"-INF"] == OF_ORDERED_SAME || - [stripped caseInsensitiveCompare: @"-INFINITY"] == OF_ORDERED_SAME) + if ([stripped caseInsensitiveCompare: @"-INF"] == OFOrderedSame || + [stripped caseInsensitiveCompare: @"-INFINITY"] == OFOrderedSame) return -INFINITY; + if ([stripped caseInsensitiveCompare: @"NAN"] == OFOrderedSame) + return NAN; + if ([stripped caseInsensitiveCompare: @"-NAN"] == OFOrderedSame) + return -NAN; #ifdef HAVE_STRTOF_L const char *UTF8String = self.UTF8String; #else /* @@ -2412,28 +2458,28 @@ OFString *decimalPoint = [OFLocale decimalPoint]; const char *UTF8String = [self stringByReplacingOccurrencesOfString: @"." withString: decimalPoint].UTF8String; #endif - char *endPointer = NULL; + char *endPtr = NULL; float value; errno = 0; #ifdef HAVE_STRTOF_L - value = strtof_l(UTF8String, &endPointer, cLocale); + value = strtof_l(UTF8String, &endPtr, cLocale); #else - value = strtof(UTF8String, &endPointer); + value = strtof(UTF8String, &endPtr); #endif if (value == HUGE_VALF && errno == ERANGE) @throw [OFOutOfRangeException exception]; /* Check if there are any invalid chars left */ - if (endPointer != NULL) - for (; *endPointer != '\0'; endPointer++) + if (endPtr != NULL) + for (; *endPtr != '\0'; endPtr++) /* Use isspace since strtof uses the same. */ - if (!isspace((unsigned char)*endPointer)) + if (!isspace((unsigned char)*endPtr)) @throw [OFInvalidFormatException exception]; objc_autoreleasePoolPop(pool); return value; @@ -2442,16 +2488,20 @@ - (double)doubleValue { void *pool = objc_autoreleasePoolPush(); OFString *stripped = self.stringByDeletingEnclosingWhitespaces; - if ([stripped caseInsensitiveCompare: @"INF"] == OF_ORDERED_SAME || - [stripped caseInsensitiveCompare: @"INFINITY"] == OF_ORDERED_SAME) + if ([stripped caseInsensitiveCompare: @"INF"] == OFOrderedSame || + [stripped caseInsensitiveCompare: @"INFINITY"] == OFOrderedSame) return INFINITY; - if ([stripped caseInsensitiveCompare: @"-INF"] == OF_ORDERED_SAME || - [stripped caseInsensitiveCompare: @"-INFINITY"] == OF_ORDERED_SAME) + if ([stripped caseInsensitiveCompare: @"-INF"] == OFOrderedSame || + [stripped caseInsensitiveCompare: @"-INFINITY"] == OFOrderedSame) return -INFINITY; + if ([stripped caseInsensitiveCompare: @"NAN"] == OFOrderedSame) + return NAN; + if ([stripped caseInsensitiveCompare: @"-NAN"] == OFOrderedSame) + return -NAN; #ifdef HAVE_STRTOD_L const char *UTF8String = self.UTF8String; #else /* @@ -2461,109 +2511,127 @@ OFString *decimalPoint = [OFLocale decimalPoint]; const char *UTF8String = [self stringByReplacingOccurrencesOfString: @"." withString: decimalPoint].UTF8String; #endif - char *endPointer = NULL; + char *endPtr = NULL; double value; errno = 0; #ifdef HAVE_STRTOD_L - value = strtod_l(UTF8String, &endPointer, cLocale); + value = strtod_l(UTF8String, &endPtr, cLocale); #else - value = strtod(UTF8String, &endPointer); + value = strtod(UTF8String, &endPtr); #endif if (value == HUGE_VAL && errno == ERANGE) @throw [OFOutOfRangeException exception]; /* Check if there are any invalid chars left */ - if (endPointer != NULL) - for (; *endPointer != '\0'; endPointer++) + if (endPtr != NULL) + for (; *endPtr != '\0'; endPtr++) /* Use isspace since strtod uses the same. */ - if (!isspace((unsigned char)*endPointer)) + if (!isspace((unsigned char)*endPtr)) @throw [OFInvalidFormatException exception]; objc_autoreleasePoolPop(pool); return value; } -- (const of_unichar_t *)characters +- (const OFUnichar *)characters { - OFObject *object = [[[OFObject alloc] init] autorelease]; size_t length = self.length; - of_unichar_t *ret; + OFUnichar *buffer; + const OFUnichar *ret; + + buffer = OFAllocMemory(length, sizeof(OFUnichar)); + @try { + [self getCharacters: buffer inRange: OFRangeMake(0, length)]; - ret = [object allocMemoryWithSize: sizeof(of_unichar_t) - count: length]; - [self getCharacters: ret - inRange: of_range(0, length)]; + ret = [[OFData dataWithItemsNoCopy: buffer + count: length + itemSize: sizeof(OFUnichar) + freeWhenDone: true] items]; + } @catch (id e) { + OFFreeMemory(buffer); + @throw e; + } return ret; } -- (const of_char16_t *)UTF16String +- (const OFChar16 *)UTF16String { - return [self UTF16StringWithByteOrder: OF_BYTE_ORDER_NATIVE]; + return [self UTF16StringWithByteOrder: OFByteOrderNative]; } -- (const of_char16_t *)UTF16StringWithByteOrder: (of_byte_order_t)byteOrder +- (const OFChar16 *)UTF16StringWithByteOrder: (OFByteOrder)byteOrder { - OFObject *object = [[[OFObject alloc] init] autorelease]; void *pool = objc_autoreleasePoolPush(); - const of_unichar_t *characters = self.characters; + const OFUnichar *characters = self.characters; size_t length = self.length; - of_char16_t *ret; + OFChar16 *buffer; size_t j; - bool swap = (byteOrder != OF_BYTE_ORDER_NATIVE); + bool swap = (byteOrder != OFByteOrderNative); + const OFChar16 *ret; /* Allocate memory for the worst case */ - ret = [object allocMemoryWithSize: sizeof(of_char16_t) - count: (length + 1) * 2]; + buffer = OFAllocMemory((length + 1) * 2, sizeof(OFChar16)); j = 0; for (size_t i = 0; i < length; i++) { - of_unichar_t c = characters[i]; + OFUnichar c = characters[i]; - if (c > 0x10FFFF) + if (c > 0x10FFFF) { + OFFreeMemory(buffer); @throw [OFInvalidEncodingException exception]; + } if (swap) { if (c > 0xFFFF) { c -= 0x10000; - ret[j++] = OF_BSWAP16(0xD800 | (c >> 10)); - ret[j++] = OF_BSWAP16(0xDC00 | (c & 0x3FF)); + buffer[j++] = OFByteSwap16(0xD800 | (c >> 10)); + buffer[j++] = + OFByteSwap16(0xDC00 | (c & 0x3FF)); } else - ret[j++] = OF_BSWAP16(c); + buffer[j++] = OFByteSwap16(c); } else { if (c > 0xFFFF) { c -= 0x10000; - ret[j++] = 0xD800 | (c >> 10); - ret[j++] = 0xDC00 | (c & 0x3FF); + buffer[j++] = 0xD800 | (c >> 10); + buffer[j++] = 0xDC00 | (c & 0x3FF); } else - ret[j++] = c; + buffer[j++] = c; } } - ret[j] = 0; + buffer[j] = 0; @try { - ret = [object resizeMemory: ret - size: sizeof(of_char16_t) - count: j + 1]; + buffer = OFResizeMemory(buffer, j + 1, sizeof(OFChar16)); } @catch (OFOutOfMemoryException *e) { /* We don't care, as we only tried to make it smaller */ } objc_autoreleasePoolPop(pool); + + @try { + ret = [[OFData dataWithItemsNoCopy: buffer + count: j + 1 + itemSize: sizeof(OFChar16) + freeWhenDone: true] items]; + } @catch (id e) { + OFFreeMemory(buffer); + @throw e; + } return ret; } - (size_t)UTF16StringLength { - const of_unichar_t *characters = self.characters; + const OFUnichar *characters = self.characters; size_t length, UTF16StringLength; length = UTF16StringLength = self.length; for (size_t i = 0; i < length; i++) @@ -2571,35 +2639,43 @@ UTF16StringLength++; return UTF16StringLength; } -- (const of_char32_t *)UTF32String +- (const OFChar32 *)UTF32String { - return [self UTF32StringWithByteOrder: OF_BYTE_ORDER_NATIVE]; + return [self UTF32StringWithByteOrder: OFByteOrderNative]; } -- (const of_char32_t *)UTF32StringWithByteOrder: (of_byte_order_t)byteOrder +- (const OFChar32 *)UTF32StringWithByteOrder: (OFByteOrder)byteOrder { - OFObject *object = [[[OFObject alloc] init] autorelease]; size_t length = self.length; - of_char32_t *ret; - - ret = [object allocMemoryWithSize: sizeof(of_char32_t) - count: length + 1]; - [self getCharacters: ret - inRange: of_range(0, length)]; - ret[length] = 0; - - if (byteOrder != OF_BYTE_ORDER_NATIVE) - for (size_t i = 0; i < length; i++) - ret[i] = OF_BSWAP32(ret[i]); + OFChar32 *buffer; + const OFChar32 *ret; + + buffer = OFAllocMemory(length + 1, sizeof(OFChar32)); + @try { + [self getCharacters: buffer inRange: OFRangeMake(0, length)]; + buffer[length] = 0; + + if (byteOrder != OFByteOrderNative) + for (size_t i = 0; i < length; i++) + buffer[i] = OFByteSwap32(buffer[i]); + + ret = [[OFData dataWithItemsNoCopy: buffer + count: length + 1 + itemSize: sizeof(OFChar32) + freeWhenDone: true] items]; + } @catch (id e) { + OFFreeMemory(buffer); + @throw e; + } return ret; } -- (OFData *)dataWithEncoding: (of_string_encoding_t)encoding +- (OFData *)dataWithEncoding: (OFStringEncoding)encoding { void *pool = objc_autoreleasePoolPush(); OFData *data = [OFData dataWithItems: [self cStringWithEncoding: encoding] count: [self cStringLengthWithEncoding: encoding]]; @@ -2612,18 +2688,18 @@ } #ifdef OF_HAVE_UNICODE_TABLES - (OFString *)decomposedStringWithCanonicalMapping { - return decomposedString(self, of_unicode_decomposition_table, - OF_UNICODE_DECOMPOSITION_TABLE_SIZE); + return decomposedString(self, OFUnicodeDecompositionTable, + OFUnicodeDecompositionTableSize); } - (OFString *)decomposedStringWithCompatibilityMapping { - return decomposedString(self, of_unicode_decomposition_compat_table, - OF_UNICODE_DECOMPOSITION_COMPAT_TABLE_SIZE); + return decomposedString(self, OFUnicodeDecompositionCompatTable, + OFUnicodeDecompositionCompatTableSize); } #endif #ifdef OF_WINDOWS - (OFString *)stringByExpandingWindowsEnvironmentStrings @@ -2637,11 +2713,11 @@ return self; return [OFString stringWithUTF16String: buffer length: length - 1]; } else { - of_string_encoding_t encoding = [OFLocale encoding]; + OFStringEncoding encoding = [OFLocale encoding]; char buffer[512]; size_t length; if ((length = ExpandEnvironmentStringsA( [self cStringWithEncoding: encoding], buffer, @@ -2656,58 +2732,47 @@ #endif #ifdef OF_HAVE_FILES - (void)writeToFile: (OFString *)path { - [self writeToFile: path - encoding: OF_STRING_ENCODING_UTF_8]; + [self writeToFile: path encoding: OFStringEncodingUTF8]; } -- (void)writeToFile: (OFString *)path - encoding: (of_string_encoding_t)encoding +- (void)writeToFile: (OFString *)path encoding: (OFStringEncoding)encoding { void *pool = objc_autoreleasePoolPush(); - OFFile *file; - - file = [OFFile fileWithPath: path - mode: @"w"]; - [file writeString: self - encoding: encoding]; - + OFFile *file = [OFFile fileWithPath: path mode: @"w"]; + [file writeString: self encoding: encoding]; objc_autoreleasePoolPop(pool); } #endif - (void)writeToURL: (OFURL *)URL { - [self writeToURL: URL - encoding: OF_STRING_ENCODING_UTF_8]; + [self writeToURL: URL encoding: OFStringEncodingUTF8]; } -- (void)writeToURL: (OFURL *)URL - encoding: (of_string_encoding_t)encoding +- (void)writeToURL: (OFURL *)URL encoding: (OFStringEncoding)encoding { void *pool = objc_autoreleasePoolPush(); OFURLHandler *URLHandler; OFStream *stream; if ((URLHandler = [OFURLHandler handlerForURL: URL]) == nil) @throw [OFUnsupportedProtocolException exceptionWithURL: URL]; - stream = [URLHandler openItemAtURL: URL - mode: @"w"]; - [stream writeString: self - encoding: encoding]; + stream = [URLHandler openItemAtURL: URL mode: @"w"]; + [stream writeString: self encoding: encoding]; objc_autoreleasePoolPop(pool); } #ifdef OF_HAVE_BLOCKS -- (void)enumerateLinesUsingBlock: (of_string_line_enumeration_block_t)block +- (void)enumerateLinesUsingBlock: (OFStringLineEnumerationBlock)block { void *pool = objc_autoreleasePoolPush(); - const of_unichar_t *characters = self.characters; + const OFUnichar *characters = self.characters; size_t i, last = 0, length = self.length; bool stop = false, lastCarriageReturn = false; for (i = 0; i < length && !stop; i++) { if (lastCarriageReturn && characters[i] == '\n') { @@ -2719,22 +2784,22 @@ if (characters[i] == '\n' || characters[i] == '\r') { void *pool2 = objc_autoreleasePoolPush(); block([self substringWithRange: - of_range(last, i - last)], &stop); + OFRangeMake(last, i - last)], &stop); last = i + 1; objc_autoreleasePoolPop(pool2); } lastCarriageReturn = (characters[i] == '\r'); } if (!stop) - block([self substringWithRange: of_range(last, i - last)], + block([self substringWithRange: OFRangeMake(last, i - last)], &stop); objc_autoreleasePoolPop(pool); } #endif @end Index: src/OFSubarray.h ================================================================== --- src/OFSubarray.h +++ src/OFSubarray.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -20,15 +18,13 @@ OF_ASSUME_NONNULL_BEGIN @interface OFSubarray: OFArray { OFArray *_array; - of_range_t _range; + OFRange _range; } -+ (instancetype)arrayWithArray: (OFArray *)array - range: (of_range_t)range; -- (instancetype)initWithArray: (OFArray *)array - range: (of_range_t)range; ++ (instancetype)arrayWithArray: (OFArray *)array range: (OFRange)range; +- (instancetype)initWithArray: (OFArray *)array range: (OFRange)range; @end OF_ASSUME_NONNULL_END Index: src/OFSubarray.m ================================================================== --- src/OFSubarray.m +++ src/OFSubarray.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -20,19 +18,16 @@ #import "OFSubarray.h" #import "OFOutOfRangeException.h" @implementation OFSubarray -+ (instancetype)arrayWithArray: (OFArray *)array - range: (of_range_t)range ++ (instancetype)arrayWithArray: (OFArray *)array range: (OFRange)range { - return [[[self alloc] initWithArray: array - range: range] autorelease]; + return [[[self alloc] initWithArray: array range: range] autorelease]; } -- (instancetype)initWithArray: (OFArray *)array - range: (of_range_t)range +- (instancetype)initWithArray: (OFArray *)array range: (OFRange)range { self = [super init]; @try { /* Should usually be retain, as it's useless with a copy */ @@ -64,54 +59,52 @@ @throw [OFOutOfRangeException exception]; return [_array objectAtIndex: idx + _range.location]; } -- (void)getObjects: (id *)buffer - inRange: (of_range_t)range +- (void)getObjects: (id *)buffer inRange: (OFRange)range { if (range.length > SIZE_MAX - range.location || range.location + range.length > _range.length) @throw [OFOutOfRangeException exception]; range.location += _range.location; - [_array getObjects: buffer - inRange: range]; + [_array getObjects: buffer inRange: range]; } - (size_t)indexOfObject: (id)object { size_t idx = [_array indexOfObject: object]; if (idx < _range.location) - return OF_NOT_FOUND; + return OFNotFound; idx -= _range.location; if (idx >= _range.length) - return OF_NOT_FOUND; + return OFNotFound; return idx; } - (size_t)indexOfObjectIdenticalTo: (id)object { size_t idx = [_array indexOfObjectIdenticalTo: object]; if (idx < _range.location) - return OF_NOT_FOUND; + return OFNotFound; idx -= _range.location; if (idx >= _range.length) - return OF_NOT_FOUND; + return OFNotFound; return idx; } -- (OFArray *)objectsInRange: (of_range_t)range +- (OFArray *)objectsInRange: (OFRange)range { if (range.length > SIZE_MAX - range.location || range.location + range.length > _range.length) @throw [OFOutOfRangeException exception]; ADDED src/OFSubprocess.h Index: src/OFSubprocess.h ================================================================== --- /dev/null +++ src/OFSubprocess.h @@ -0,0 +1,209 @@ +/* + * 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. + */ + +#ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS +#endif +#ifndef __STDC_CONSTANT_MACROS +# define __STDC_CONSTANT_MACROS +#endif + +#include "objfw-defs.h" + +#ifdef OF_HAVE_SYS_TYPES_H +# include +#endif + +#import "OFStream.h" +#import "OFKernelEventObserver.h" +#import "OFString.h" + +#ifdef OF_WINDOWS +# include +#endif + +OF_ASSUME_NONNULL_BEGIN + +@class OFArray OF_GENERIC(ObjectType); +@class OFDictionary OF_GENERIC(KeyType, ObjectType); + +/** + * @class OFSubprocess OFSubprocess.h ObjFW/OFSubprocess.h + * + * @brief A class for stream-like communication with a newly created subprocess. + */ +OF_SUBCLASSING_RESTRICTED +@interface OFSubprocess: OFStream +#ifndef OF_WINDOWS + +#endif +{ +#ifndef OF_WINDOWS + pid_t _pid; + int _readPipe[2], _writePipe[2]; +#else + HANDLE _handle, _readPipe[2], _writePipe[2]; +#endif + int _status; + bool _atEndOfStream; +} + +/** + * @brief Creates a new OFSubprocess with the specified program and invokes the + * program. + * + * @param program The program to execute. If it does not start with a slash, the + * search path specified in PATH is used. + * @return A new, autoreleased OFSubprocess. + */ ++ (instancetype)subprocessWithProgram: (OFString *)program; + +/** + * @brief Creates a new OFSubprocess with the specified program and arguments + * and invokes the program. + * + * @param program The program to execute. If it does not start with a slash, the + * search path specified in PATH is used. + * @param arguments The arguments to pass to the program, or `nil` + * @return A new, autoreleased OFSubprocess. + */ ++ (instancetype) + subprocessWithProgram: (OFString *)program + arguments: (nullable OFArray OF_GENERIC(OFString *) *)arguments; + +/** + * @brief Creates a new OFSubprocess with the specified program, program name + * and arguments and invokes the program. + * + * @param program The program to execute. If it does not start with a slash, the + * search path specified in PATH is used. + * @param programName The program name for the program to invoke (argv[0]). + * Usually, this is equal to program. + * @param arguments The arguments to pass to the program, or `nil` + * @return A new, autoreleased OFSubprocess. + */ ++ (instancetype) + subprocessWithProgram: (OFString *)program + programName: (OFString *)programName + arguments: (nullable OFArray OF_GENERIC(OFString *) *)arguments; + +/** + * @brief Creates a new OFSubprocess with the specified program, program name, + * arguments and environment and invokes the program. + * + * @param program The program to execute. If it does not start with a slash, the + * search path specified in PATH is used. + * @param programName The program name for the program to invoke (argv[0]). + * Usually, this is equal to program. + * @param arguments The arguments to pass to the program, or `nil` + * @param environment The environment to pass to the program, or `nil`. If it + * is not `nil`, the passed dictionary will be used to + * override the environment. If you want to add to the + * existing environment, you need to get the existing + * environment first, copy it, modify it and then pass it. + * @return A new, autoreleased OFSubprocess. + */ ++ (instancetype) + subprocessWithProgram: (OFString *)program + programName: (OFString *)programName + arguments: (nullable OFArray OF_GENERIC(OFString *) *)arguments + environment: (nullable OFDictionary + OF_GENERIC(OFString *, OFString *) *)environment; + +- (instancetype)init OF_UNAVAILABLE; + +/** + * @brief Initializes an already allocated OFSubprocess with the specified + * program and invokes the program. + * + * @param program The program to execute. If it does not start with a slash, the + * search path specified in PATH is used. + * @return An initialized OFSubprocess. + */ +- (instancetype)initWithProgram: (OFString *)program; + +/** + * @brief Initializes an already allocated OFSubprocess with the specified + * program and arguments and invokes the program. + * + * @param program The program to execute. If it does not start with a slash, the + * search path specified in PATH is used. + * @param arguments The arguments to pass to the program, or `nil` + * @return An initialized OFSubprocess. + */ +- (instancetype) + initWithProgram: (OFString *)program + arguments: (nullable OFArray OF_GENERIC(OFString *) *)arguments; + +/** + * @brief Initializes an already allocated OFSubprocess with the specified + * program, program name and arguments and invokes the program. + * + * @param program The program to execute. If it does not start with a slash, the + * search path specified in PATH is used. + * @param programName The program name for the program to invoke (argv[0]). + * Usually, this is equal to program. + * @param arguments The arguments to pass to the program, or `nil` + * @return An initialized OFSubprocess. + */ +- (instancetype) + initWithProgram: (OFString *)program + programName: (OFString *)programName + arguments: (nullable OFArray OF_GENERIC(OFString *) *)arguments; + +/** + * @brief Initializes an already allocated OFSubprocess with the specified + * program, program name, arguments and environment and invokes the + * program. + * + * @param program The program to execute. If it does not start with a slash, the + * search path specified in PATH is used. + * @param programName The program name for the program to invoke (argv[0]). + * Usually, this is equal to program. + * @param arguments The arguments to pass to the program, or `nil` + * @param environment The environment to pass to the program, or `nil`. If it + * is not `nil`, the passed dictionary will be used to + * override the environment. If you want to add to the + * existing environment, you need to get the existing + * environment first, copy it, modify it and then pass it. + * @return An initialized OFSubprocess. + */ +- (instancetype) + initWithProgram: (OFString *)program + programName: (OFString *)programName + arguments: (nullable OFArray OF_GENERIC(OFString *) *)arguments + environment: (nullable OFDictionary + OF_GENERIC(OFString *, OFString *) *)environment + OF_DESIGNATED_INITIALIZER; + +/** + * @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. + */ +- (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. + */ +- (int)waitForTermination; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFSubprocess.m Index: src/OFSubprocess.m ================================================================== --- /dev/null +++ src/OFSubprocess.m @@ -0,0 +1,24 @@ +/* + * 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" + +#ifdef OF_WINDOWS +# include "platform/Windows/OFSubprocess.m" +#else +# include "platform/POSIX/OFSubprocess.m" +#endif Index: src/OFSystemInfo.h ================================================================== --- src/OFSystemInfo.h +++ src/OFSystemInfo.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -29,12 +27,12 @@ @interface OFSystemInfo: OFObject #ifdef OF_HAVE_CLASS_PROPERTIES @property (class, readonly, nonatomic) size_t pageSize; @property (class, readonly, nonatomic) size_t numberOfCPUs; @property (class, readonly, nonatomic) OFString *ObjFWVersion; -@property (class, readonly, nonatomic) unsigned int ObjFWVersionMajor; -@property (class, readonly, nonatomic) unsigned int ObjFWVersionMinor; +@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; # ifdef OF_HAVE_FILES @property (class, readonly, nullable, nonatomic) OFString *userDataPath; @@ -89,18 +87,18 @@ /** * @brief The major version of ObjFW. * * @return The major version of ObjFW */ -+ (unsigned int)ObjFWVersionMajor; ++ (unsigned short)ObjFWVersionMajor; /** * @brief The minor version of ObjFW. * * @return The minor version of ObjFW */ -+ (unsigned int)ObjFWVersionMinor; ++ (unsigned short)ObjFWVersionMinor; /** * @brief Returns the name of the operating system the application is running * on. * @@ -118,32 +116,52 @@ #ifdef OF_HAVE_FILES /** * @brief Returns the path where user data for the application can be stored. * - * On Unix systems, this adheres to the XDG Base Directory specification.@n - * On Mac OS X and iOS, it uses the `NSApplicationSupportDirectory` directory.@n + * On UNIX systems, this adheres to the XDG Base Directory specification.@n + * On macOS and iOS, it uses the `NSApplicationSupportDirectory` directory.@n * On Windows, it uses the `APPDATA` environment variable.@n - * On Haiku, it uses the `B_USER_SETTINGS_DIRECTORY` directory. + * 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 OFString *)userDataPath; /** * @brief Returns the path where user configuration for the application can be * stored. * - * On Unix systems, this adheres to the XDG Base Directory specification.@n - * On Mac OS X and iOS, it uses the `Preferences` directory inside of + * On UNIX systems, this adheres to the XDG Base Directory specification.@n + * On macOS and iOS, it uses the `Preferences` directory inside of * `NSLibraryDirectory` directory.@n * On Windows, it uses the `APPDATA` environment variable.@n * 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 OFString *)userConfigPath; + +/** + * @brief Returns a path where temporary files for can be stored. + * + * If possible, returns a temporary directory for the user, otherwise returns a + * global temporary directory. + * + * On UNIX systems, this adheres to the XDG Base Directory specification and + * returns `/tmp` if `XDG_RUNTIME_DIR` is not set.@n + * On macOS and iOS, this uses `_CS_DARWIN_USER_TEMP_DIR`, falling back to + * `/tmp` if this fails.@n + * On Windows, it uses `GetTempPath`.@n + * 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 OFString *)temporaryDirectoryPath; #endif /** * @brief Returns the vendor of the CPU. * Index: src/OFSystemInfo.m ================================================================== --- src/OFSystemInfo.m +++ src/OFSystemInfo.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -26,33 +24,35 @@ #include "platform.h" #ifdef HAVE_SYS_UTSNAME_H # include #endif -#if defined(OF_MACOS) || defined(OF_NETBSD) +#if defined(OF_MACOS) || defined(OF_IOS) || defined(OF_NETBSD) # include #endif + +#ifdef OF_AMIGAOS +# include +# include +#endif #if defined(OF_AMIGAOS4) # include -# include #elif defined(OF_MORPHOS) # include -# include #endif #import "OFSystemInfo.h" #import "OFApplication.h" #import "OFArray.h" #import "OFDictionary.h" #import "OFLocale.h" +#import "OFOnce.h" #import "OFString.h" #import "OFNotImplementedException.h" -#import "once.h" - #if defined(OF_MACOS) || defined(OF_IOS) # ifdef HAVE_SYSDIR_H # include # endif #endif @@ -91,11 +91,11 @@ extern NSSearchPathEnumerationState NSGetNextSearchPathEnumeration( NSSearchPathEnumerationState, char *); #endif #if defined(OF_X86_64) || defined(OF_X86) -struct x86_regs { +struct X86Regs { uint32_t eax, ebx, ecx, edx; }; #endif static size_t pageSize = 4096; @@ -164,11 +164,11 @@ #elif defined(OF_WINDOWS) # ifdef OF_HAVE_FILES void *pool = objc_autoreleasePoolPush(); @try { - of_string_encoding_t encoding = [OFLocale encoding]; + OFStringEncoding encoding = [OFLocale encoding]; char systemDir[PATH_MAX]; UINT systemDirLen; OFString *systemDirString; const char *path; void *buffer; @@ -215,16 +215,14 @@ objc_autoreleasePoolPop(pool); } # endif #elif defined(OF_ANDROID) /* TODO */ -#elif defined(OF_MORPHOS) - /* TODO */ -#elif defined(OF_AMIGAOS4) - /* TODO */ -#elif defined(OF_AMIGAOS_M68K) - /* TODO */ +#elif defined(OF_AMIGAOS) + operatingSystemVersion = [[OFString alloc] + initWithFormat: @"Kickstart %u.%u", + SysBase->LibNode.lib_Version, SysBase->SoftVer]; #elif defined(OF_WII) || defined(NINTENDO_3DS) || defined(OF_NINTENDO_DS) || \ defined(OF_PSP) || defined(OF_MSDOS) /* Intentionally nothing */ #elif defined(HAVE_SYS_UTSNAME_H) && defined(HAVE_UNAME) struct utsname utsname; @@ -237,22 +235,22 @@ encoding: [OFLocale encoding]]; #endif } #if defined(OF_X86_64) || defined(OF_X86) -static OF_INLINE struct x86_regs OF_CONST_FUNC -x86_cpuid(uint32_t eax, uint32_t ecx) +static OF_INLINE struct X86Regs OF_CONST_FUNC +x86CPUID(uint32_t eax, uint32_t ecx) { - struct x86_regs regs; + struct X86Regs regs; -# if defined(OF_X86_64_ASM) +# if defined(OF_X86_64) && defined(__GNUC__) __asm__ ( "cpuid" : "=a"(regs.eax), "=b"(regs.ebx), "=c"(regs.ecx), "=d"(regs.edx) : "a"(eax), "c"(ecx) ); -# elif defined(OF_X86_ASM) +# elif defined(OF_X86) && defined(__GNUC__) /* * This workaround is required by older GCC versions when using -fPIC, * as ebx is a special register in PIC code. Yes, GCC is indeed not * able to just push a register onto the stack before the __asm__ block * and to pop it afterwards. @@ -321,32 +319,32 @@ + (OFString *)ObjFWVersion { return @PACKAGE_VERSION; } -+ (unsigned int)ObjFWVersionMajor ++ (unsigned short)ObjFWVersionMajor { return OBJFW_VERSION_MAJOR; } -+ (unsigned int)ObjFWVersionMinor ++ (unsigned short)ObjFWVersionMinor { return OBJFW_VERSION_MINOR; } + (OFString *)operatingSystemName { - static of_once_t onceControl = OF_ONCE_INIT; - of_once(&onceControl, initOperatingSystemName); + static OFOnceControl onceControl = OFOnceControlInitValue; + OFOnce(&onceControl, initOperatingSystemName); return operatingSystemName; } + (OFString *)operatingSystemVersion { - static of_once_t onceControl = OF_ONCE_INIT; - of_once(&onceControl, initOperatingSystemVersion); + static OFOnceControl onceControl = OFOnceControlInitValue; + OFOnce(&onceControl, initOperatingSystemVersion); return operatingSystemVersion; } #ifdef OF_HAVE_FILES @@ -355,12 +353,11 @@ # if defined(OF_MACOS) || defined(OF_IOS) char pathC[PATH_MAX]; OFMutableString *path; # ifdef HAVE_SYSDIR_START_SEARCH_PATH_ENUMERATION - /* (1) to disable dead code warning when it is not a weak symbol */ - if ((1) && &sysdir_start_search_path_enumeration != NULL) { + if (@available(macOS 10.12, iOS 10, *)) { sysdir_search_path_enumeration_state state; state = sysdir_start_search_path_enumeration( SYSDIR_DIRECTORY_APPLICATION_SUPPORT, SYSDIR_DOMAIN_MASK_USER); @@ -390,11 +387,11 @@ if ((home = [env objectForKey: @"HOME"]) == nil) @throw [OFNotImplementedException exceptionWithSelector: _cmd object: self]; - [path deleteCharactersInRange: of_range(0, 1)]; + [path deleteCharactersInRange: OFRangeMake(0, 1)]; [path prependString: home]; } [path makeImmutable]; @@ -448,12 +445,11 @@ # if defined(OF_MACOS) || defined(OF_IOS) char pathC[PATH_MAX]; OFMutableString *path; # ifdef HAVE_SYSDIR_START_SEARCH_PATH_ENUMERATION - /* (1) to disable dead code warning when it is not a weak symbol */ - if ((1) && &sysdir_start_search_path_enumeration != NULL) { + if (@available(macOS 10.12, iOS 10, *)) { sysdir_search_path_enumeration_state state; state = sysdir_start_search_path_enumeration( SYSDIR_DIRECTORY_LIBRARY, SYSDIR_DOMAIN_MASK_USER); if (sysdir_get_next_search_path_enumeration(state, pathC) == 0) @@ -482,16 +478,15 @@ if ((home = [env objectForKey: @"HOME"]) == nil) @throw [OFNotImplementedException exceptionWithSelector: _cmd object: self]; - [path deleteCharactersInRange: of_range(0, 1)]; + [path deleteCharactersInRange: OFRangeMake(0, 1)]; [path prependString: home]; } [path appendString: @"/Preferences"]; - [path makeImmutable]; return path; # elif defined(OF_WINDOWS) OFDictionary *env = [OFApplication environment]; @@ -526,16 +521,71 @@ object: self]; return [var stringByAppendingPathComponent: @".config"]; # endif } + ++ (OFString *)temporaryDirectoryPath +{ +# if defined(OF_MACOS) || defined(OF_IOS) + char buffer[PATH_MAX]; + size_t length; + + if ((length = confstr(_CS_DARWIN_USER_TEMP_DIR, buffer, PATH_MAX)) == 0) + return @"/tmp"; + + return [OFString stringWithCString: buffer + encoding: [OFLocale encoding] + length: length - 1]; +# elif defined(OF_WINDOWS) + if ([self isWindowsNT]) { + wchar_t buffer[PATH_MAX]; + + if (!GetTempPathW(PATH_MAX, buffer)) + return nil; + + return [OFString stringWithUTF16String: buffer]; + } else { + char buffer[PATH_MAX]; + + if (!GetTempPathA(PATH_MAX, buffer)) + return nil; + + return [OFString stringWithCString: buffer + encoding: [OFLocale encoding]]; + } +# elif defined(OF_HAIKU) + char pathC[PATH_MAX]; + + if (find_directory(B_SYSTEM_TEMP_DIRECTORY, 0, false, + pathC, PATH_MAX) != B_OK) + @throw [OFNotImplementedException exceptionWithSelector: _cmd + object: self]; + + return [OFString stringWithUTF8String: pathC]; +# elif defined(OF_AMIGAOS) + return @"T:"; +# elif defined(OF_MSDOS) + return [[OFApplication environment] objectForKey: @"TEMP"]; +# elif defined(OF_MINT) + return @"u:\\tmp"; +# else + OFString *path = + [[OFApplication environment] objectForKey: @"XDG_RUNTIME_DIR"]; + + if (path != nil) + return path; + + return @"/tmp"; +# endif +} #endif + (OFString *)CPUVendor { -#if defined(OF_X86_64_ASM) || defined(OF_X86_ASM) - struct x86_regs regs = x86_cpuid(0, 0); +#if (defined(OF_X86_64) || defined(OF_X86)) && defined(__GNUC__) + struct X86Regs regs = x86CPUID(0, 0); uint32_t buffer[3]; if (regs.eax == 0) return nil; @@ -542,35 +592,51 @@ buffer[0] = regs.ebx; buffer[1] = regs.edx; buffer[2] = regs.ecx; return [OFString stringWithCString: (char *)buffer - encoding: OF_STRING_ENCODING_ASCII + encoding: OFStringEncodingASCII length: 12]; +#elif defined(OF_M68K) + return @"Motorola"; #else return nil; #endif } + (OFString *)CPUModel { -#if defined(OF_X86_64_ASM) || defined(OF_X86_ASM) +#if (defined(OF_X86_64) || defined(OF_X86)) && defined(__GNUC__) + struct X86Regs regs = x86CPUID(0x80000000, 0); uint32_t buffer[12]; size_t i; + if (regs.eax < 0x80000004) + return nil; + i = 0; for (uint32_t eax = 0x80000002; eax <= 0x80000004; eax++) { - struct x86_regs regs = x86_cpuid(eax, 0); - + regs = x86CPUID(eax, 0); buffer[i++] = regs.eax; buffer[i++] = regs.ebx; buffer[i++] = regs.ecx; buffer[i++] = regs.edx; } return [OFString stringWithCString: (char *)buffer - encoding: OF_STRING_ENCODING_ASCII]; + encoding: OFStringEncodingASCII]; +#elif defined(OF_MACOS) || defined(OF_IOS) + char buffer[128]; + size_t length = sizeof(buffer); + + if (sysctlbyname("machdep.cpu.brand_string", &buffer, &length, + NULL, 0) != 0) + return nil; + + return [OFString stringWithCString: buffer + encoding: [OFLocale encoding] + length: length]; #elif defined(OF_AMIGAOS4) CONST_STRPTR model, version; GetCPUInfoTags(GCIT_ModelString, &model, GCIT_VersionString, &version, TAG_END); @@ -577,70 +643,83 @@ if (version != NULL) return [OFString stringWithFormat: @"%s V%s", model, version]; else return [OFString stringWithCString: model - encoding: OF_STRING_ENCODING_ASCII]; + encoding: OFStringEncodingASCII]; +#elif defined(OF_AMIGAOS_M68K) + if (SysBase->AttnFlags & AFF_68060) + return @"68060"; + if (SysBase->AttnFlags & AFF_68040) + return @"68040"; + if (SysBase->AttnFlags & AFF_68030) + return @"68030"; + if (SysBase->AttnFlags & AFF_68020) + return @"68020"; + if (SysBase->AttnFlags & AFF_68010) + return @"68010"; + else + return @"68000"; #else return nil; #endif } #if defined(OF_X86_64) || defined(OF_X86) + (bool)supportsMMX { - return (x86_cpuid(1, 0).edx & (1u << 23)); + return (x86CPUID(1, 0).edx & (1u << 23)); } + (bool)supportsSSE { - return (x86_cpuid(1, 0).edx & (1u << 25)); + return (x86CPUID(1, 0).edx & (1u << 25)); } + (bool)supportsSSE2 { - return (x86_cpuid(1, 0).edx & (1u << 26)); + return (x86CPUID(1, 0).edx & (1u << 26)); } + (bool)supportsSSE3 { - return (x86_cpuid(1, 0).ecx & (1u << 0)); + return (x86CPUID(1, 0).ecx & (1u << 0)); } + (bool)supportsSSSE3 { - return (x86_cpuid(1, 0).ecx & (1u << 9)); + return (x86CPUID(1, 0).ecx & (1u << 9)); } + (bool)supportsSSE41 { - return (x86_cpuid(1, 0).ecx & (1u << 19)); + return (x86CPUID(1, 0).ecx & (1u << 19)); } + (bool)supportsSSE42 { - return (x86_cpuid(1, 0).ecx & (1u << 20)); + return (x86CPUID(1, 0).ecx & (1u << 20)); } + (bool)supportsAVX { - return (x86_cpuid(1, 0).ecx & (1u << 28)); + return (x86CPUID(1, 0).ecx & (1u << 28)); } + (bool)supportsAVX2 { - return x86_cpuid(0, 0).eax >= 7 && (x86_cpuid(7, 0).ebx & (1u << 5)); + return x86CPUID(0, 0).eax >= 7 && (x86CPUID(7, 0).ebx & (1u << 5)); } + (bool)supportsAESNI { - return (x86_cpuid(1, 0).ecx & (1u << 25)); + return (x86CPUID(1, 0).ecx & (1u << 25)); } + (bool)supportsSHAExtensions { - return (x86_cpuid(7, 0).ebx & (1u << 29)); + return (x86CPUID(7, 0).ebx & (1u << 29)); } #endif #if defined(OF_POWERPC) || defined(OF_POWERPC64) + (bool)supportsAltiVec Index: src/OFTCPSocket.h ================================================================== --- src/OFTCPSocket.h +++ src/OFTCPSocket.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -30,11 +28,11 @@ * @brief A block which is called when the socket connected. * * @param exception An exception which occurred while connecting the socket or * `nil` on success */ -typedef void (^of_tcp_socket_async_connect_block_t)(id _Nullable exception); +typedef void (^OFTCPSocketAsyncConnectBlock)(id _Nullable exception); #endif /** * @protocol OFTCPSocketDelegate OFTCPSocket.h ObjFW/OFTCPSocket.h * @@ -146,81 +144,70 @@ * @return The port to use as a SOCKS5 proxy when creating a new socket */ + (uint16_t)SOCKS5Port; /** - * @brief Connect the OFTCPSocket to the specified destination. + * @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 */ -- (void)connectToHost: (OFString *)host - port: (uint16_t)port; +- (void)connectToHost: (OFString *)host port: (uint16_t)port; /** - * @brief Asynchronously connect the OFTCPSocket to the specified destination. + * @brief Asynchronously connects the OFTCPSocket to the specified destination. * * @param host The host to connect to * @param port The port on the host to connect to */ -- (void)asyncConnectToHost: (OFString *)host - port: (uint16_t)port; +- (void)asyncConnectToHost: (OFString *)host port: (uint16_t)port; /** - * @brief Asynchronously connect the OFTCPSocket to the specified destination. + * @brief Asynchronously connects the OFTCPSocket to the specified destination. * * @param host The host to connect to * @param port The port on the host to connect to * @param runLoopMode The run loop mode in which to perform the async connect */ - (void)asyncConnectToHost: (OFString *)host port: (uint16_t)port - runLoopMode: (of_run_loop_mode_t)runLoopMode; + runLoopMode: (OFRunLoopMode)runLoopMode; #ifdef OF_HAVE_BLOCKS /** - * @brief Asynchronously connect the OFTCPSocket to the specified destination. + * @brief Asynchronously connects the OFTCPSocket to the specified destination. * * @param host The host to connect to * @param port The port on the host to connect to * @param block The block to execute once the connection has been established */ - (void)asyncConnectToHost: (OFString *)host port: (uint16_t)port - block: (of_tcp_socket_async_connect_block_t)block; + block: (OFTCPSocketAsyncConnectBlock)block; /** - * @brief Asynchronously connect the OFTCPSocket to the specified destination. + * @brief Asynchronously connects the OFTCPSocket to the specified destination. * * @param host The host to connect to * @param port The port on the host to 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)asyncConnectToHost: (OFString *)host port: (uint16_t)port - runLoopMode: (of_run_loop_mode_t)runLoopMode - block: (of_tcp_socket_async_connect_block_t)block; + runLoopMode: (OFRunLoopMode)runLoopMode + block: (OFTCPSocketAsyncConnectBlock)block; #endif /** - * @brief Bind the socket to the specified host and port. + * @brief Binds the socket to the specified host and port. * * @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 */ -- (uint16_t)bindToHost: (OFString *)host - port: (uint16_t)port; +- (uint16_t)bindToHost: (OFString *)host port: (uint16_t)port; @end -#ifdef __cplusplus -extern "C" { -#endif -extern Class _Nullable of_tls_socket_class; -#ifdef __cplusplus -} -#endif - OF_ASSUME_NONNULL_END Index: src/OFTCPSocket.m ================================================================== --- src/OFTCPSocket.m +++ src/OFTCPSocket.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -13,14 +11,18 @@ * 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. */ -#define __NO_EXT_QNX - #include "config.h" +#ifndef _XOPEN_SOURCE_EXTENDED +# define _XOPEN_SOURCE_EXTENDED +#endif +#define __NO_EXT_QNX +#define _HPUX_ALT_XOPEN_SOCKET_API + #include #include #include #include @@ -33,10 +35,12 @@ #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" @@ -44,17 +48,12 @@ #import "OFGetOptionFailedException.h" #import "OFNotImplementedException.h" #import "OFNotOpenException.h" #import "OFSetOptionFailedException.h" -#import "socket.h" -#import "socket_helpers.h" - -static const of_run_loop_mode_t connectRunLoopMode = - @"of_tcp_socket_connect_mode"; - -Class of_tls_socket_class = Nil; +static const OFRunLoopMode connectRunLoopMode = + @"OFTCPSocketConnectRunLoopMode"; static OFString *defaultSOCKS5Host = nil; static uint16_t defaultSOCKS5Port = 1080; @interface OFTCPSocket () @@ -132,23 +131,23 @@ [_SOCKS5Host release]; [super dealloc]; } -- (bool)of_createSocketForAddress: (const of_socket_address_t *)address +- (bool)of_createSocketForAddress: (const OFSocketAddress *)address errNo: (int *)errNo { #if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) int flags; #endif - if (_socket != INVALID_SOCKET) + if (_socket != OFInvalidSocketHandle) @throw [OFAlreadyConnectedException exceptionWithSocket: self]; if ((_socket = socket(address->sockaddr.sockaddr.sa_family, - SOCK_STREAM | SOCK_CLOEXEC, 0)) == INVALID_SOCKET) { - *errNo = of_socket_errno(); + SOCK_STREAM | SOCK_CLOEXEC, 0)) == OFInvalidSocketHandle) { + *errNo = OFSocketErrNo(); return false; } #if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) if ((flags = fcntl(_socket, F_GETFD, 0)) != -1) @@ -156,78 +155,74 @@ #endif return true; } -- (bool)of_connectSocketToAddress: (const of_socket_address_t *)address +- (bool)of_connectSocketToAddress: (const OFSocketAddress *)address errNo: (int *)errNo { - if (_socket == INVALID_SOCKET) + if (_socket == OFInvalidSocketHandle) @throw [OFNotOpenException exceptionWithObject: self]; /* Cast needed for AmigaOS, where the argument is declared non-const */ if (connect(_socket, (struct sockaddr *)&address->sockaddr.sockaddr, address->length) != 0) { - *errNo = of_socket_errno(); + *errNo = OFSocketErrNo(); return false; } return true; } - (void)of_closeSocket { closesocket(_socket); - _socket = INVALID_SOCKET; + _socket = OFInvalidSocketHandle; } -- (void)connectToHost: (OFString *)host - port: (uint16_t)port +- (void)connectToHost: (OFString *)host port: (uint16_t)port { void *pool = objc_autoreleasePoolPush(); id delegate = _delegate; OFTCPSocketConnectDelegate *connectDelegate = [[[OFTCPSocketConnectDelegate alloc] init] autorelease]; OFRunLoop *runLoop = [OFRunLoop currentRunLoop]; - self.delegate = connectDelegate; + _delegate = connectDelegate; [self asyncConnectToHost: host port: port runLoopMode: connectRunLoopMode]; while (!connectDelegate->_done) - [runLoop runMode: connectRunLoopMode - beforeDate: nil]; - - /* Cleanup */ - [runLoop runMode: connectRunLoopMode - beforeDate: [OFDate date]]; - - if (connectDelegate->_exception != nil) - @throw connectDelegate->_exception; - - self.delegate = delegate; - - objc_autoreleasePoolPop(pool); -} - -- (void)asyncConnectToHost: (OFString *)host - port: (uint16_t)port -{ - [self asyncConnectToHost: host - port: port - runLoopMode: of_run_loop_mode_default]; -} - -- (void)asyncConnectToHost: (OFString *)host - port: (uint16_t)port - runLoopMode: (of_run_loop_mode_t)runLoopMode -{ - void *pool = objc_autoreleasePoolPush(); - id delegate; - - if (_socket != INVALID_SOCKET) + [runLoop runMode: connectRunLoopMode beforeDate: nil]; + + /* Cleanup */ + [runLoop runMode: connectRunLoopMode beforeDate: [OFDate date]]; + + _delegate = delegate; + + if (connectDelegate->_exception != nil) + @throw connectDelegate->_exception; + + objc_autoreleasePoolPop(pool); +} + +- (void)asyncConnectToHost: (OFString *)host port: (uint16_t)port +{ + [self asyncConnectToHost: host + port: port + runLoopMode: OFDefaultRunLoopMode]; +} + +- (void)asyncConnectToHost: (OFString *)host + port: (uint16_t)port + runLoopMode: (OFRunLoopMode)runLoopMode +{ + void *pool = objc_autoreleasePoolPush(); + id delegate; + + if (_socket != OFInvalidSocketHandle) @throw [OFAlreadyConnectedException exceptionWithSocket: self]; if (_SOCKS5Host != nil) { delegate = [[[OFTCPSocketSOCKS5Connector alloc] initWithSocket: self @@ -255,27 +250,27 @@ } #ifdef OF_HAVE_BLOCKS - (void)asyncConnectToHost: (OFString *)host port: (uint16_t)port - block: (of_tcp_socket_async_connect_block_t)block + block: (OFTCPSocketAsyncConnectBlock)block { [self asyncConnectToHost: host port: port - runLoopMode: of_run_loop_mode_default + runLoopMode: OFDefaultRunLoopMode block: block]; } - (void)asyncConnectToHost: (OFString *)host port: (uint16_t)port - runLoopMode: (of_run_loop_mode_t)runLoopMode - block: (of_tcp_socket_async_connect_block_t)block + runLoopMode: (OFRunLoopMode)runLoopMode + block: (OFTCPSocketAsyncConnectBlock)block { void *pool = objc_autoreleasePoolPush(); id delegate = nil; - if (_socket != INVALID_SOCKET) + if (_socket != OFInvalidSocketHandle) @throw [OFAlreadyConnectedException exceptionWithSocket: self]; if (_SOCKS5Host != nil) { delegate = [[[OFTCPSocketSOCKS5Connector alloc] initWithSocket: self @@ -297,42 +292,41 @@ objc_autoreleasePoolPop(pool); } #endif -- (uint16_t)bindToHost: (OFString *)host - port: (uint16_t)port +- (uint16_t)bindToHost: (OFString *)host port: (uint16_t)port { const int one = 1; void *pool = objc_autoreleasePoolPush(); OFData *socketAddresses; - of_socket_address_t address; + OFSocketAddress address; #if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) int flags; #endif - if (_socket != INVALID_SOCKET) + if (_socket != OFInvalidSocketHandle) @throw [OFAlreadyConnectedException exceptionWithSocket: self]; if (_SOCKS5Host != nil) @throw [OFNotImplementedException exceptionWithSelector: _cmd object: self]; socketAddresses = [[OFThread DNSResolver] resolveAddressesForHost: host - addressFamily: OF_SOCKET_ADDRESS_FAMILY_ANY]; + addressFamily: OFSocketAddressFamilyAny]; - address = *(of_socket_address_t *)[socketAddresses itemAtIndex: 0]; - of_socket_address_set_port(&address, port); + address = *(OFSocketAddress *)[socketAddresses itemAtIndex: 0]; + OFSocketAddressSetPort(&address, port); if ((_socket = socket(address.sockaddr.sockaddr.sa_family, - SOCK_STREAM | SOCK_CLOEXEC, 0)) == INVALID_SOCKET) + SOCK_STREAM | SOCK_CLOEXEC, 0)) == OFInvalidSocketHandle) @throw [OFBindFailedException exceptionWithHost: host port: port socket: self - errNo: of_socket_errno()]; + errNo: OFSocketErrNo()]; _canBlock = true; #if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) if ((flags = fcntl(_socket, F_GETFD, 0)) != -1) @@ -340,47 +334,47 @@ #endif setsockopt(_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&one, (socklen_t)sizeof(one)); -#if defined(OF_WII) || defined(OF_NINTENDO_3DS) +#if defined(OF_HPUX) || defined(OF_WII) || defined(OF_NINTENDO_3DS) if (port != 0) { #endif if (bind(_socket, &address.sockaddr.sockaddr, address.length) != 0) { - int errNo = of_socket_errno(); + int errNo = OFSocketErrNo(); closesocket(_socket); - _socket = INVALID_SOCKET; + _socket = OFInvalidSocketHandle; @throw [OFBindFailedException exceptionWithHost: host port: port socket: self errNo: errNo]; } -#if defined(OF_WII) || defined(OF_NINTENDO_3DS) +#if defined(OF_HPUX) || defined(OF_WII) || defined(OF_NINTENDO_3DS) } else { for (;;) { uint16_t rnd = 0; int ret; while (rnd < 1024) rnd = (uint16_t)rand(); - of_socket_address_set_port(&address, rnd); + OFSocketAddressSetPort(&address, rnd); if ((ret = bind(_socket, &address.sockaddr.sockaddr, address.length)) == 0) { port = rnd; break; } - if (of_socket_errno() != EADDRINUSE) { - int errNo = of_socket_errno(); + if (OFSocketErrNo() != EADDRINUSE) { + int errNo = OFSocketErrNo(); closesocket(_socket); - _socket = INVALID_SOCKET; + _socket = OFInvalidSocketHandle; @throw [OFBindFailedException exceptionWithHost: host port: port socket: self @@ -393,45 +387,45 @@ objc_autoreleasePoolPop(pool); if (port > 0) return port; -#if !defined(OF_WII) && !defined(OF_NINTENDO_3DS) +#if !defined(OF_HPUX) && !defined(OF_WII) && !defined(OF_NINTENDO_3DS) memset(&address, 0, sizeof(address)); address.length = (socklen_t)sizeof(address.sockaddr); - if (of_getsockname(_socket, &address.sockaddr.sockaddr, + if (OFGetSockName(_socket, &address.sockaddr.sockaddr, &address.length) != 0) { - int errNo = of_socket_errno(); + int errNo = OFSocketErrNo(); closesocket(_socket); - _socket = INVALID_SOCKET; + _socket = OFInvalidSocketHandle; @throw [OFBindFailedException exceptionWithHost: host port: port socket: self errNo: errNo]; } if (address.sockaddr.sockaddr.sa_family == AF_INET) - return OF_BSWAP16_IF_LE(address.sockaddr.in.sin_port); + return OFFromBigEndian16(address.sockaddr.in.sin_port); # ifdef OF_HAVE_IPV6 else if (address.sockaddr.sockaddr.sa_family == AF_INET6) - return OF_BSWAP16_IF_LE(address.sockaddr.in6.sin6_port); + return OFFromBigEndian16(address.sockaddr.in6.sin6_port); # endif else { closesocket(_socket); - _socket = INVALID_SOCKET; + _socket = OFInvalidSocketHandle; @throw [OFBindFailedException exceptionWithHost: host port: port socket: self errNo: EAFNOSUPPORT]; } #else closesocket(_socket); - _socket = INVALID_SOCKET; + _socket = OFInvalidSocketHandle; @throw [OFBindFailedException exceptionWithHost: host port: port socket: self errNo: EADDRNOTAVAIL]; #endif @@ -444,11 +438,11 @@ if (setsockopt(_socket, SOL_SOCKET, SO_KEEPALIVE, (char *)&v, (socklen_t)sizeof(v)) != 0) @throw [OFSetOptionFailedException exceptionWithObject: self - errNo: of_socket_errno()]; + errNo: OFSocketErrNo()]; } - (bool)sendsKeepAlives { int v; @@ -456,11 +450,11 @@ if (getsockopt(_socket, SOL_SOCKET, SO_KEEPALIVE, (char *)&v, &len) != 0 || len != sizeof(v)) @throw [OFGetOptionFailedException exceptionWithObject: self - errNo: of_socket_errno()]; + errNo: OFSocketErrNo()]; return v; } #endif @@ -471,11 +465,11 @@ if (setsockopt(_socket, IPPROTO_TCP, TCP_NODELAY, (char *)&v, (socklen_t)sizeof(v)) != 0) @throw [OFSetOptionFailedException exceptionWithObject: self - errNo: of_socket_errno()]; + errNo: OFSocketErrNo()]; } - (bool)canDelaySendingSegments { int v; @@ -483,11 +477,11 @@ if (getsockopt(_socket, IPPROTO_TCP, TCP_NODELAY, (char *)&v, &len) != 0 || len != sizeof(v)) @throw [OFGetOptionFailedException exceptionWithObject: self - errNo: of_socket_errno()]; + errNo: OFSocketErrNo()]; return !v; } #endif Index: src/OFTCPSocketSOCKS5Connector.h ================================================================== --- src/OFTCPSocketSOCKS5Connector.h +++ src/OFTCPSocketSOCKS5Connector.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -26,21 +24,14 @@ OFTCPSocket *_socket; OFString *_host; uint16_t _port; id _Nullable _delegate; #ifdef OF_HAVE_BLOCKS - of_tcp_socket_async_connect_block_t _Nullable _block; + OFTCPSocketAsyncConnectBlock _Nullable _block; #endif id _Nullable _exception; - enum { - OF_SOCKS5_STATE_SEND_AUTHENTICATION = 1, - OF_SOCKS5_STATE_READ_VERSION, - OF_SOCKS5_STATE_SEND_REQUEST, - OF_SOCKS5_STATE_READ_RESPONSE, - OF_SOCKS5_STATE_READ_ADDRESS, - OF_SOCKS5_STATE_READ_ADDRESS_LENGTH, - } _SOCKS5State; + uint_least8_t _SOCKS5State; /* Longest read is domain name (max 255 bytes) + port */ unsigned char _buffer[257]; OFMutableData *_Nullable _request; } @@ -47,13 +38,12 @@ - (instancetype)initWithSocket: (OFTCPSocket *)sock host: (OFString *)host port: (uint16_t)port delegate: (nullable id )delegate #ifdef OF_HAVE_BLOCKS - block: (nullable of_tcp_socket_async_connect_block_t) - block + block: (nullable OFTCPSocketAsyncConnectBlock)block #endif ; - (void)didConnect; @end OF_ASSUME_NONNULL_END Index: src/OFTCPSocketSOCKS5Connector.m ================================================================== --- src/OFTCPSocketSOCKS5Connector.m +++ src/OFTCPSocketSOCKS5Connector.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -24,18 +22,27 @@ #import "OFData.h" #import "OFRunLoop.h" #import "OFString.h" #import "OFConnectionFailedException.h" + +enum { + stateSendAuthentication = 1, + stateReadVersion, + stateSendRequest, + stateReadResponse, + stateReadAddress, + stateReadAddressLength, +}; @implementation OFTCPSocketSOCKS5Connector - (instancetype)initWithSocket: (OFTCPSocket *)sock host: (OFString *)host port: (uint16_t)port delegate: (id )delegate #ifdef OF_HAVE_BLOCKS - block: (of_tcp_socket_async_connect_block_t)block + block: (OFTCPSocketAsyncConnectBlock)block #endif { self = [super init]; @try { @@ -82,11 +89,11 @@ _block(_exception); else { #endif if ([_delegate respondsToSelector: @selector(socket:didConnectToHost:port:exception:)]) - [_delegate socket: _socket + [_delegate socket: _socket didConnectToHost: _host port: _port exception: _exception]; #ifdef OF_HAVE_BLOCKS } @@ -104,24 +111,23 @@ _exception = [exception retain]; [self didConnect]; return; } - data = [OFData dataWithItems: "\x05\x01\x00" - count: 3]; + data = [OFData dataWithItems: "\x05\x01\x00" count: 3]; - _SOCKS5State = OF_SOCKS5_STATE_SEND_AUTHENTICATION; + _SOCKS5State = stateSendAuthentication; [_socket asyncWriteData: data runLoopMode: [OFRunLoop currentRunLoop].currentMode]; } - (bool)stream: (OFStream *)sock didReadIntoBuffer: (void *)buffer length: (size_t)length exception: (id)exception { - of_run_loop_mode_t runLoopMode; + OFRunLoopMode runLoopMode; unsigned char *SOCKSVersion; uint8_t hostLength; unsigned char port[2]; unsigned char *response, *addressLength; @@ -132,11 +138,11 @@ } runLoopMode = [OFRunLoop currentRunLoop].currentMode; switch (_SOCKS5State) { - case OF_SOCKS5_STATE_READ_VERSION: + case stateReadVersion: SOCKSVersion = buffer; if (SOCKSVersion[0] != 5 || SOCKSVersion[1] != 0) { _exception = [[OFConnectionFailedException alloc] initWithHost: _host @@ -148,28 +154,24 @@ } [_request release]; _request = [[OFMutableData alloc] init]; - [_request addItems: "\x05\x01\x00\x03" - count: 4]; + [_request addItems: "\x05\x01\x00\x03" count: 4]; hostLength = (uint8_t)_host.UTF8StringLength; [_request addItem: &hostLength]; - [_request addItems: _host.UTF8String - count: hostLength]; + [_request addItems: _host.UTF8String count: hostLength]; port[0] = _port >> 8; port[1] = _port & 0xFF; - [_request addItems: port - count: 2]; + [_request addItems: port count: 2]; - _SOCKS5State = OF_SOCKS5_STATE_SEND_REQUEST; - [_socket asyncWriteData: _request - runLoopMode: runLoopMode]; + _SOCKS5State = stateSendRequest; + [_socket asyncWriteData: _request runLoopMode: runLoopMode]; return false; - case OF_SOCKS5_STATE_READ_RESPONSE: + case stateReadResponse: response = buffer; if (response[0] != 5 || response[2] != 0) { _exception = [[OFConnectionFailedException alloc] initWithHost: _host @@ -224,23 +226,23 @@ } /* Skip the rest of the response */ switch (response[3]) { case 1: /* IPv4 */ - _SOCKS5State = OF_SOCKS5_STATE_READ_ADDRESS; + _SOCKS5State = stateReadAddress; [_socket asyncReadIntoBuffer: _buffer exactLength: 4 + 2 runLoopMode: runLoopMode]; return false; case 3: /* Domain name */ - _SOCKS5State = OF_SOCKS5_STATE_READ_ADDRESS_LENGTH; + _SOCKS5State = stateReadAddressLength; [_socket asyncReadIntoBuffer: _buffer exactLength: 1 runLoopMode: runLoopMode]; return false; case 4: /* IPv6 */ - _SOCKS5State = OF_SOCKS5_STATE_READ_ADDRESS; + _SOCKS5State = stateReadAddress; [_socket asyncReadIntoBuffer: _buffer exactLength: 16 + 2 runLoopMode: runLoopMode]; return false; default: @@ -252,17 +254,17 @@ [self didConnect]; return false; } return false; - case OF_SOCKS5_STATE_READ_ADDRESS: + case stateReadAddress: [self didConnect]; return false; - case OF_SOCKS5_STATE_READ_ADDRESS_LENGTH: + case stateReadAddressLength: addressLength = buffer; - _SOCKS5State = OF_SOCKS5_STATE_READ_ADDRESS; + _SOCKS5State = stateReadAddress; [_socket asyncReadIntoBuffer: _buffer exactLength: addressLength[0] + 2 runLoopMode: runLoopMode]; return false; default: @@ -274,11 +276,11 @@ - (OFData *)stream: (OFStream *)sock didWriteData: (OFData *)data bytesWritten: (size_t)bytesWritten exception: (id)exception { - of_run_loop_mode_t runLoopMode; + OFRunLoopMode runLoopMode; if (exception != nil) { _exception = [exception retain]; [self didConnect]; return nil; @@ -285,21 +287,21 @@ } runLoopMode = [OFRunLoop currentRunLoop].currentMode; switch (_SOCKS5State) { - case OF_SOCKS5_STATE_SEND_AUTHENTICATION: - _SOCKS5State = OF_SOCKS5_STATE_READ_VERSION; + case stateSendAuthentication: + _SOCKS5State = stateReadVersion; [_socket asyncReadIntoBuffer: _buffer exactLength: 2 runLoopMode: runLoopMode]; return nil; - case OF_SOCKS5_STATE_SEND_REQUEST: + case stateSendRequest: [_request release]; _request = nil; - _SOCKS5State = OF_SOCKS5_STATE_READ_RESPONSE; + _SOCKS5State = stateReadResponse; [_socket asyncReadIntoBuffer: _buffer exactLength: 4 runLoopMode: runLoopMode]; return nil; default: ADDED src/OFTLSKey.h Index: src/OFTLSKey.h ================================================================== --- /dev/null +++ src/OFTLSKey.h @@ -0,0 +1,102 @@ +/* + * 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 "objfw-defs.h" + +#include + +#include "platform.h" + +#if !defined(OF_HAVE_THREADS) || \ + (!defined(OF_HAVE_PTHREADS) && !defined(OF_WINDOWS) && !defined(OF_AMIGAOS)) +# error No thread-local storage available! +#endif + +#import "macros.h" + +#if defined(OF_HAVE_PTHREADS) +# include +typedef pthread_key_t OFTLSKey; +#elif defined(OF_WINDOWS) +# include +typedef DWORD OFTLSKey; +#elif defined(OF_MORPHOS) +# include +typedef ULONG OFTLSKey; +#elif defined(OF_AMIGAOS) +typedef struct _OFTLSKey { + struct objc_hashtable *table; + struct _OFTLSKey *next, *previous; +} *OFTLSKey; +#endif + +#ifdef __cplusplus +extern "C" { +#endif +extern int OFTLSKeyNew(OFTLSKey *key); +extern int OFTLSKeyFree(OFTLSKey key); +#ifdef __cplusplus +} +#endif + +/* TLS keys are inlined for performance. */ + +#if defined(OF_HAVE_PTHREADS) +static OF_INLINE void * +OFTLSKeyGet(OFTLSKey key) +{ + return pthread_getspecific(key); +} + +static OF_INLINE int +OFTLSKeySet(OFTLSKey key, void *ptr) +{ + return pthread_setspecific(key, ptr); +} +#elif defined(OF_WINDOWS) +static OF_INLINE void * +OFTLSKeyGet(OFTLSKey key) +{ + return TlsGetValue(key); +} + +static OF_INLINE int +OFTLSKeySet(OFTLSKey key, void *ptr) +{ + return (TlsSetValue(key, ptr) ? 0 : EINVAL); +} +#elif defined(OF_MORPHOS) +static OF_INLINE void * +OFTLSKeyGet(OFTLSKey key) +{ + return (void *)TLSGetValue(key); +} + +static OF_INLINE int +OFTLSKeySet(OFTLSKey key, void *ptr) +{ + return (TLSSetValue(key, (APTR)ptr) ? 0 : EINVAL); +} +#elif defined(OF_AMIGAOS) +/* Those are too big too inline. */ +# ifdef __cplusplus +extern "C" { +# endif +extern void *OFTLSKeyGet(OFTLSKey key); +extern int OFTLSKeySet(OFTLSKey key, void *ptr); +# ifdef __cplusplus +} +# endif +#endif ADDED src/OFTLSKey.m Index: src/OFTLSKey.m ================================================================== --- /dev/null +++ src/OFTLSKey.m @@ -0,0 +1,28 @@ +/* + * 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" + +#if defined(OF_HAVE_PTHREADS) +# include "platform/POSIX/OFTLSKey.m" +#elif defined(OF_WINDOWS) +# include "platform/Windows/OFTLSKey.m" +#elif defined(OF_MORPHOS) +# include "platform/MorphOS/OFTLSKey.m" +#elif defined(OF_AMIGAOS) +# include "platform/AmigaOS/OFTLSKey.m" +#endif DELETED src/OFTLSSocket.h Index: src/OFTLSSocket.h ================================================================== --- src/OFTLSSocket.h +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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; -@class OFDictionary OF_GENERIC(KeyType, ObjectType); -@protocol OFTLSSocket; - -/** - * @protocol OFTLSSocketDelegate OFTLSSocket.h ObjFW/OFTLSSocket.h - * - * @brief A delegate for classes implementing the OFTLSSocket protocol. - */ -@protocol OFTLSSocketDelegate -@optional -/** - * @brief This callback is called when the TLS socket wants to know if it - * should accept the received certificate. - * - * @note This is only used to verify certain fields of a certificate to allow - * for protocol specific verification. The certificate chain is verified - * using the specified CAs, or the system's CAs if no CAs have been - * specified. - * - * @param socket The socket which wants to know if it should accept the received - * certificate - * @param certificate A dictionary with the fields of the received certificate - * @return Whether the TLS socket should accept the received certificate chain - */ -- (bool)socket: (id )socket - shouldAcceptCertificate: (OFDictionary *)certificate; -@end - -/** - * @protocol OFTLSSocket OFTLSSocket.h ObjFW/OFTLSSocket.h - * - * @brief A protocol that should be implemented by 3rd-party libraries - * implementing TLS. - */ -@protocol OFTLSSocket -/** - * @brief The delegate for the TLS socket. - */ -@property OF_NULLABLE_PROPERTY (assign, nonatomic) - id delegate; - -/** - * @brief The path to the X.509 certificate file to use. - */ -@property OF_NULLABLE_PROPERTY (copy, nonatomic) OFString *certificateFile; - -/** - * @brief The path to the PKCS#8 private key file to use. - */ -@property OF_NULLABLE_PROPERTY (copy, nonatomic) OFString *privateKeyFile; - -/** - * @brief The passphrase to decrypt the PKCS#8 private key file. - * - * @warning You have to ensure that this is in secure memory protected from - * swapping! This is also the reason why this is not an OFString. - */ -@property OF_NULLABLE_PROPERTY (assign, nonatomic) - const char *privateKeyPassphrase; - -/** - * @brief Whether certificates are verified. - * - * The default is enabled. - */ -@property (nonatomic) bool verifiesCertificates; - -/** - * @brief Initializes the TLS socket with the specified TCP socket as its - * underlying socket. - * - * @param socket The TCP socket to use as underlying socket - */ -- (instancetype)initWithSocket: (OFTCPSocket *)socket; - -/** - * @brief Initiates the TLS handshake. - * - * @note This is only useful if you used @ref initWithSocket: to start TLS on - * a TCP socket which is already connected! - * - * @param host The host to expect for certificate verification. - * May be `nil` if certificate verification is disabled. - */ -- (void)startTLSWithExpectedHost: (nullable OFString *)host; - -/** - * @brief Sets the path to the X.509 certificate file to use for the specified - * SNI host. - * - * @param SNIHost The SNI host for which the path of the X.509 certificate file - * should be set - * - * @param certificateFile The path to the X.509 certificate file - */ -- (void)setCertificateFile: (OFString *)certificateFile - forSNIHost: (OFString *)SNIHost; - -/** - * @brief Returns the path of the X.509 certificate file used by the TLS socket - * for the specified SNI host. - * - * @param SNIHost The SNI host for which the path of the X.509 certificate file - * should be returned - * - * @return The path of the X.509 certificate file used by the TLS socket for - * the specified SNI host - */ -- (nullable OFString *)certificateFileForSNIHost: (OFString *)SNIHost; - -/** - * @brief Sets the path to the PKCS#8 private key file to use for the specified - * SNI host. - * - * @param privateKeyFile The path to the PKCS#8 private key file - * @param SNIHost The SNI host for which the path to the PKCS#8 private key - * file should be set - */ -- (void)setPrivateKeyFile: (OFString *)privateKeyFile - forSNIHost: (OFString *)SNIHost; - -/** - * @brief Returns the path of the PKCS#8 private key file used by the TLS - * socket for the specified SNI host. - * - * @param SNIHost The SNI host for which the path of the PKCS#8 private key - * file should be returned - * - * @return The path of the PKCS#8 private key file used by the TLS socket for - * the specified SNI host - */ -- (nullable OFString *)privateKeyFileForSNIHost: (OFString *)SNIHost; - -/** - * @brief Sets the passphrase to decrypt the PKCS#8 private key file for the - * specified SNI host. - * - * @warning You have to ensure that this is in secure memory protected from - * swapping! This is also the reason why this is not an OFString. - * - * @param privateKeyPassphrase The passphrase to decrypt the PKCS#8 private - * key file for the specified SNI host - * @param SNIHost The SNI host for which the passphrase to decrypt the PKCS#8 - * private key file should be set - */ -- (void)setPrivateKeyPassphrase: (const char *)privateKeyPassphrase - forSNIHost: (OFString *)SNIHost; - -/** - * @brief Returns the passphrase to decrypt the PKCS#8 private key file for the - * specified SNI host. - * - * @warning You should not copy this to insecure memory which is swappable! - * - * @param SNIHost The SNI host for which the passphrase to decrypt the PKCS#8 - * private key file should be returned - * - * @return The passphrase to decrypt the PKCS#8 private key file for the - * specified SNI host - */ -- (nullable const char *)privateKeyPassphraseForSNIHost: (OFString *)SNIHost; -@end - -OF_ASSUME_NONNULL_END ADDED src/OFTLSStream.h Index: src/OFTLSStream.h ================================================================== --- /dev/null +++ src/OFTLSStream.h @@ -0,0 +1,176 @@ +/* + * 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 "OFStream.h" +#import "OFRunLoop.h" + +OF_ASSUME_NONNULL_BEGIN + +/** @file */ + +@class OFTLSStream; + +/** + * @brief An enum representing an error of an OFTLSStream. + */ +typedef enum { + /** @brief An unknown error. */ + OFTLSStreamErrorCodeUnknown, + /** @brief Initialization of the TLS context failed. */ + OFTLSStreamErrorCodeInitializationFailed +} OFTLSStreamErrorCode; + +/** + * @protocol OFTLSStreamDelegate OFTLSStream.h ObjFW/OFTLSStream.h + * + * A delegate for OFTLSStream. + */ +@protocol OFTLSStreamDelegate +/** + * @brief A method which is called when a TLS stream performed the client + * handshake. + * + * @param stream The TLS stream which performed the handshake + * @param host The host for which the handshake was performed + * @param exception An exception that occurred during the handshake, or nil on + * success + */ +- (void)stream: (OFTLSStream *)stream + didPerformClientHandshakeWithHost: (OFString *)host + exception: (nullable id)exception; +@end + +/** + * @class OFTLSStream OFTLSStream.h ObjFW/OFTLSStream.h + * + * @brief A class that provides Transport Layer Security on top of a stream. + * + * This class is a class cluster and returns a suitable OFTLSStream subclass, + * if available. + * + * Subclasses need to override @ref lowlevelReadIntoBuffer:length:, + * @ref lowlevelWriteBuffer:length: and + * @ref asyncPerformClientHandshakeWithHost:runLoopMode:. The method + * @ref hasDataInReadBuffer should be overridden to return `true` if the TLS + * stream has cached unprocessed data internally, while returning + * `self.underlyingStream.hasDataInReadBuffer` if it does not have any + * unprocessed data. In order to get access to the underlying stream, + * @ref underlyingStream can be used. + */ +@interface OFTLSStream: OFStream +{ + OFStream + *_underlyingStream; + bool _verifiesCertificates; + OF_RESERVE_IVARS(OFTLSStream, 4) +} + +/** + * @brief The underlying stream. + */ +@property (readonly, nonatomic) OFStream *underlyingStream; + +/** + * @brief The delegate for asynchronous operations on the stream. + * + * @note The delegate is retained for as long as asynchronous operations are + * still ongoing. + */ +@property OF_NULLABLE_PROPERTY (assign, nonatomic) + id delegate; + +/** + * @brief Whether certificates are verified. Default is true. + */ +@property (nonatomic) bool verifiesCertificates; + +- (instancetype)init OF_UNAVAILABLE; + +/** + * @brief Creates a new TLS stream with the specified stream as its underlying + * stream. + * + * @param stream The stream to use as underlying stream. Must not be closed + * before the TLS stream is closed. + * @return A new, autoreleased TLS stream + */ ++ (instancetype)streamWithStream: (OFStream *)stream; + +/** + * @brief Initializes the TLS stream with the specified stream as its + * underlying stream. + * + * @param stream The stream to use as underlying stream. Must not be closed + * before the TLS stream is closed. + * @return An initialized TLS stream + */ +- (instancetype)initWithStream: (OFStream *)stream + OF_DESIGNATED_INITIALIZER; + +/** + * @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 + */ +- (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 + */ +- (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 + */ +- (void)performClientHandshakeWithHost: (OFString *)host; +@end + +#ifdef __cplusplus +extern "C" { +#endif +/** + * @brief The implementation for OFTLSStream to use. + * + * This can be set to a class that is always used for OFTLSStream. This is + * useful to either force a specific implementation or use one that ObjFW does + * not know about. + */ +extern Class OFTLSStreamImplementation; + +/** + * @brief Returns a string description for the TLS stream error code. + * + * @param errorCode The error code to return the description for + * @return A string description for the TLS stream error code + */ +extern OFString *OFTLSStreamErrorCodeDescription( + OFTLSStreamErrorCode errorCode); +#ifdef __cplusplus +} +#endif + +OF_ASSUME_NONNULL_END ADDED src/OFTLSStream.m Index: src/OFTLSStream.m ================================================================== --- /dev/null +++ src/OFTLSStream.m @@ -0,0 +1,202 @@ +/* + * 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 "OFTLSStream.h" +#import "OFDate.h" + +#import "OFNotImplementedException.h" +#import "OFTLSHandshakeFailedException.h" + +@interface OFTLSStreamHandshakeDelegate: OFObject +{ +@public + bool _done; + id _exception; +} +@end + +Class OFTLSStreamImplementation = Nil; +static const OFRunLoopMode handshakeRunLoopMode = + @"OFTLSStreamHandshakeRunLoopMode"; + +/* + * References to exceptions. This is needed because they are only used by + * subclasses that are in a different library. + */ +void +_references_to_exceptions_of_OFTLSStream(void) +{ + _OFTLSHandshakeFailedException_reference = 1; +} + +OFString * +OFTLSStreamErrorCodeDescription(OFTLSStreamErrorCode errorCode) +{ + switch (errorCode) { + case OFTLSStreamErrorCodeInitializationFailed: + return @"Initialization of TLS context failed"; + default: + return @"Unknown error"; + } +} + +@implementation OFTLSStreamHandshakeDelegate +- (void)dealloc +{ + [_exception release]; + + [super dealloc]; +} + +- (void)stream: (OFTLSStream *)stream + didPerformClientHandshakeWithHost: (OFString *)host + exception: (id)exception +{ + _done = true; + _exception = [exception retain]; +} +@end + +@implementation OFTLSStream +@synthesize underlyingStream = _underlyingStream; +@dynamic delegate; +@synthesize verifiesCertificates = _verifiesCertificates; + ++ (instancetype)alloc +{ + if (self == [OFTLSStream class]) { + if (OFTLSStreamImplementation != Nil) + return [OFTLSStreamImplementation alloc]; + + @throw [OFNotImplementedException exceptionWithSelector: _cmd + object: self]; + } + + return [super alloc]; +} + ++ (instancetype)streamWithStream: (OFStream *)stream +{ + return [[[self alloc] initWithStream: stream] autorelease]; +} + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)initWithStream: (OFStream *)stream +{ + self = [super init]; + + @try { + _underlyingStream = [stream retain]; + _verifiesCertificates = true; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_underlyingStream release]; + + [super dealloc]; +} + +- (void)close +{ + [_underlyingStream release]; + _underlyingStream = nil; + + [super close]; +} + +- (size_t)lowlevelReadIntoBuffer: (void *)buffer length: (size_t)length +{ + OF_UNRECOGNIZED_SELECTOR +} + +- (size_t)lowlevelWriteBuffer: (const void *)buffer length: (size_t)length +{ + OF_UNRECOGNIZED_SELECTOR +} + +- (bool)hasDataInReadBuffer +{ + return (super.hasDataInReadBuffer || + _underlyingStream.hasDataInReadBuffer); +} + +- (bool)lowlevelIsAtEndOfStream +{ + return _underlyingStream.atEndOfStream; +} + +- (int)fileDescriptorForReading +{ + return _underlyingStream.fileDescriptorForReading; +} + +- (int)fileDescriptorForWriting +{ + return _underlyingStream.fileDescriptorForWriting; +} + +- (void)asyncPerformClientHandshakeWithHost: (OFString *)host +{ + [self asyncPerformClientHandshakeWithHost: host + runLoopMode: OFDefaultRunLoopMode]; +} + +- (void)asyncPerformClientHandshakeWithHost: (OFString *)host + runLoopMode: (OFRunLoopMode)runLoopMode +{ + OF_UNRECOGNIZED_SELECTOR +} + +- (void)performClientHandshakeWithHost: (OFString *)host +{ + void *pool = objc_autoreleasePoolPush(); + id delegate = _delegate; + OFTLSStreamHandshakeDelegate *handshakeDelegate = + [[[OFTLSStreamHandshakeDelegate alloc] init] autorelease]; + OFRunLoop *runLoop = [OFRunLoop currentRunLoop]; + + _delegate = handshakeDelegate; + [self asyncPerformClientHandshakeWithHost: host + runLoopMode: handshakeRunLoopMode]; + + while (!handshakeDelegate->_done) + [runLoop runMode: handshakeRunLoopMode beforeDate: nil]; + + /* Cleanup */ + [runLoop runMode: handshakeRunLoopMode beforeDate: [OFDate date]]; + + _delegate = delegate; + + if (handshakeDelegate->_exception != nil) + @throw handshakeDelegate->_exception; + + objc_autoreleasePoolPop(pool); +} +@end Index: src/OFTarArchive.h ================================================================== --- src/OFTarArchive.h +++ src/OFTarArchive.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -31,23 +29,23 @@ */ OF_SUBCLASSING_RESTRICTED @interface OFTarArchive: OFObject { OFStream *_stream; - enum { - OF_TAR_ARCHIVE_MODE_READ, - OF_TAR_ARCHIVE_MODE_WRITE, - OF_TAR_ARCHIVE_MODE_APPEND + enum OFTarArchiveMode { + OFTarArchiveModeRead, + OFTarArchiveModeWrite, + OFTarArchiveModeAppend } _mode; - of_string_encoding_t _encoding; + OFStringEncoding _encoding; OFStream *_Nullable _lastReturnedStream; } /** * @brief The encoding to use for the archive. Defaults to UTF-8. */ -@property (nonatomic) of_string_encoding_t encoding; +@property (nonatomic) OFStringEncoding encoding; /** * @brief A stream for reading the current entry. * * @note This is only available in read mode. @@ -65,12 +63,11 @@ * @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 */ -+ (instancetype)archiveWithStream: (OFStream *)stream - mode: (OFString *)mode; ++ (instancetype)archiveWithStream: (OFStream *)stream mode: (OFString *)mode; #ifdef OF_HAVE_FILES /** * @brief Creates a new OFTarArchive object with the specified file. * @@ -78,12 +75,11 @@ * @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 */ -+ (instancetype)archiveWithPath: (OFString *)path - mode: (OFString *)mode; ++ (instancetype)archiveWithPath: (OFString *)path mode: (OFString *)mode; #endif - (instancetype)init OF_UNAVAILABLE; /** @@ -109,12 +105,11 @@ * @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 */ -- (instancetype)initWithPath: (OFString *)path - mode: (OFString *)mode; +- (instancetype)initWithPath: (OFString *)path mode: (OFString *)mode; #endif /** * @brief Returns the next entry from the tar archive or `nil` if all entries * have been read. Index: src/OFTarArchive.m ================================================================== --- src/OFTarArchive.m +++ src/OFTarArchive.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -14,10 +12,12 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #include "config.h" + +#include #import "OFTarArchive.h" #import "OFTarArchiveEntry.h" #import "OFTarArchiveEntry+Private.h" #import "OFDate.h" @@ -61,59 +61,53 @@ @end @implementation OFTarArchive: OFObject @synthesize encoding = _encoding; -+ (instancetype)archiveWithStream: (OFStream *)stream - mode: (OFString *)mode ++ (instancetype)archiveWithStream: (OFStream *)stream mode: (OFString *)mode { - return [[[self alloc] initWithStream: stream - mode: mode] autorelease]; + return [[[self alloc] initWithStream: stream mode: mode] autorelease]; } #ifdef OF_HAVE_FILES -+ (instancetype)archiveWithPath: (OFString *)path - mode: (OFString *)mode ++ (instancetype)archiveWithPath: (OFString *)path mode: (OFString *)mode { - return [[[self alloc] initWithPath: path - mode: mode] autorelease]; + return [[[self alloc] initWithPath: path mode: mode] autorelease]; } #endif - (instancetype)init { OF_INVALID_INIT_METHOD } -- (instancetype)initWithStream: (OFStream *)stream - mode: (OFString *)mode +- (instancetype)initWithStream: (OFStream *)stream mode: (OFString *)mode { self = [super init]; @try { _stream = [stream retain]; if ([mode isEqual: @"r"]) - _mode = OF_TAR_ARCHIVE_MODE_READ; + _mode = OFTarArchiveModeRead; else if ([mode isEqual: @"w"]) - _mode = OF_TAR_ARCHIVE_MODE_WRITE; + _mode = OFTarArchiveModeWrite; else if ([mode isEqual: @"a"]) - _mode = OF_TAR_ARCHIVE_MODE_APPEND; + _mode = OFTarArchiveModeAppend; else @throw [OFInvalidArgumentException exception]; - if (_mode == OF_TAR_ARCHIVE_MODE_APPEND) { + if (_mode == OFTarArchiveModeAppend) { uint32_t buffer[1024 / sizeof(uint32_t)]; bool empty = true; if (![_stream isKindOfClass: [OFSeekableStream class]]) @throw [OFInvalidArgumentException exception]; [(OFSeekableStream *)_stream seekToOffset: -1024 whence: SEEK_END]; - [_stream readIntoBuffer: buffer - exactLength: 1024]; + [_stream readIntoBuffer: buffer exactLength: 1024]; for (size_t i = 0; i < 1024 / sizeof(uint32_t); i++) if (buffer[i] != 0) empty = false; @@ -122,35 +116,31 @@ [(OFSeekableStream *)stream seekToOffset: -1024 whence: SEEK_END]; } - _encoding = OF_STRING_ENCODING_UTF_8; + _encoding = OFStringEncodingUTF8; } @catch (id e) { [self release]; @throw e; } return self; } #ifdef OF_HAVE_FILES -- (instancetype)initWithPath: (OFString *)path - mode: (OFString *)mode +- (instancetype)initWithPath: (OFString *)path mode: (OFString *)mode { OFFile *file; if ([mode isEqual: @"a"]) - file = [[OFFile alloc] initWithPath: path - mode: @"r+"]; + file = [[OFFile alloc] initWithPath: path mode: @"r+"]; else - file = [[OFFile alloc] initWithPath: path - mode: mode]; + file = [[OFFile alloc] initWithPath: path mode: mode]; @try { - self = [self initWithStream: file - mode: mode]; + self = [self initWithStream: file mode: mode]; } @finally { [file release]; } return self; @@ -168,11 +158,11 @@ { OFTarArchiveEntry *entry; uint32_t buffer[512 / sizeof(uint32_t)]; bool empty = true; - if (_mode != OF_TAR_ARCHIVE_MODE_READ) + if (_mode != OFTarArchiveModeRead) @throw [OFInvalidArgumentException exception]; [(OFTarArchiveFileReadStream *)_lastReturnedStream of_skip]; @try { [_lastReturnedStream close]; @@ -183,20 +173,18 @@ _lastReturnedStream = nil; if (_stream.atEndOfStream) return nil; - [_stream readIntoBuffer: buffer - exactLength: 512]; + [_stream readIntoBuffer: buffer exactLength: 512]; for (size_t i = 0; i < 512 / sizeof(uint32_t); i++) if (buffer[i] != 0) empty = false; if (empty) { - [_stream readIntoBuffer: buffer - exactLength: 512]; + [_stream readIntoBuffer: buffer exactLength: 512]; for (size_t i = 0; i < 512 / sizeof(uint32_t); i++) if (buffer[i] != 0) @throw [OFInvalidFormatException exception]; @@ -214,11 +202,11 @@ return entry; } - (OFStream *)streamForReadingCurrentEntry { - if (_mode != OF_TAR_ARCHIVE_MODE_READ) + if (_mode != OFTarArchiveModeRead) @throw [OFInvalidArgumentException exception]; if (_lastReturnedStream == nil) @throw [OFInvalidArgumentException exception]; @@ -228,12 +216,11 @@ - (OFStream *)streamForWritingEntry: (OFTarArchiveEntry *)entry { void *pool; - if (_mode != OF_TAR_ARCHIVE_MODE_WRITE && - _mode != OF_TAR_ARCHIVE_MODE_APPEND) + if (_mode != OFTarArchiveModeWrite && _mode != OFTarArchiveModeAppend) @throw [OFInvalidArgumentException exception]; pool = objc_autoreleasePoolPush(); @try { @@ -242,12 +229,11 @@ /* Might have already been closed by the user - that's fine. */ } [_lastReturnedStream release]; _lastReturnedStream = nil; - [entry of_writeToStream: _stream - encoding: _encoding]; + [entry of_writeToStream: _stream encoding: _encoding]; _lastReturnedStream = [[OFTarArchiveFileWriteStream alloc] of_initWithStream: _stream entry: entry]; @@ -268,16 +254,14 @@ /* Might have already been closed by the user - that's fine. */ } [_lastReturnedStream release]; _lastReturnedStream = nil; - if (_mode == OF_TAR_ARCHIVE_MODE_WRITE || - _mode == OF_TAR_ARCHIVE_MODE_APPEND) { + if (_mode == OFTarArchiveModeWrite || _mode == OFTarArchiveModeAppend) { char buffer[1024]; memset(buffer, '\0', 1024); - [_stream writeBuffer: buffer - length: 1024]; + [_stream writeBuffer: buffer length: 1024]; } [_stream release]; _stream = nil; } @@ -328,13 +312,11 @@ #endif if ((uint64_t)length > _toRead) length = (size_t)_toRead; - ret = [_stream readIntoBuffer: buffer - length: length]; - + ret = [_stream readIntoBuffer: buffer length: length]; if (ret == 0) _atEndOfStream = true; _toRead -= ret; @@ -377,14 +359,14 @@ { if (_stream == nil || _skipped) return; if ([_stream isKindOfClass: [OFSeekableStream class]] && - _toRead <= INT64_MAX && (of_offset_t)_toRead == (int64_t)_toRead) { + _toRead <= INT64_MAX && (OFFileOffset)_toRead == (int64_t)_toRead) { uint64_t size; - [(OFSeekableStream *)_stream seekToOffset: (of_offset_t)_toRead + [(OFSeekableStream *)_stream seekToOffset: (OFFileOffset)_toRead whence: SEEK_CUR]; _toRead = 0; size = _entry.size; @@ -396,12 +378,11 @@ } else { char buffer[512]; uint64_t size; while (_toRead >= 512) { - [_stream readIntoBuffer: buffer - exactLength: 512]; + [_stream readIntoBuffer: buffer exactLength: 512]; _toRead -= 512; } if (_toRead > 0) { [_stream readIntoBuffer: buffer @@ -446,32 +427,34 @@ [_entry release]; [super dealloc]; } -- (size_t)lowlevelWriteBuffer: (const void *)buffer - length: (size_t)length +- (size_t)lowlevelWriteBuffer: (const void *)buffer length: (size_t)length { - size_t bytesWritten; - if (_stream == nil) @throw [OFNotOpenException exceptionWithObject: self]; if ((uint64_t)length > _toWrite) @throw [OFOutOfRangeException exception]; @try { - bytesWritten = [_stream writeBuffer: buffer - length: length]; + [_stream writeBuffer: buffer length: length]; } @catch (OFWriteFailedException *e) { + OFEnsure(e.bytesWritten <= length); + _toWrite -= e.bytesWritten; + + if (e.errNo == EWOULDBLOCK || e.errNo == EAGAIN) + return e.bytesWritten; + @throw e; } - _toWrite -= bytesWritten; + _toWrite -= length; - return bytesWritten; + return length; } - (bool)lowlevelIsAtEndOfStream { if (_stream == nil) Index: src/OFTarArchiveEntry+Private.h ================================================================== --- src/OFTarArchiveEntry+Private.h +++ src/OFTarArchiveEntry+Private.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -23,12 +21,12 @@ @class OFStream; OF_DIRECT_MEMBERS @interface OFTarArchiveEntry () - (instancetype)of_initWithHeader: (unsigned char [_Nonnull 512])header - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding OF_METHOD_FAMILY(init); - (void)of_writeToStream: (OFStream *)stream - encoding: (of_string_encoding_t)encoding; + encoding: (OFStringEncoding)encoding; @end OF_ASSUME_NONNULL_END Index: src/OFTarArchiveEntry.h ================================================================== --- src/OFTarArchiveEntry.h +++ src/OFTarArchiveEntry.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -24,28 +22,28 @@ @class OFDate; /** * @brief The type of the archive entry. */ -typedef enum of_tar_archive_entry_type_t { +typedef enum { /** Normal file */ - OF_TAR_ARCHIVE_ENTRY_TYPE_FILE = '0', + OFTarArchiveEntryTypeFile = '0', /** Hard link */ - OF_TAR_ARCHIVE_ENTRY_TYPE_LINK = '1', + OFTarArchiveEntryTypeLink = '1', /** Symbolic link */ - OF_TAR_ARCHIVE_ENTRY_TYPE_SYMLINK = '2', + OFTarArchiveEntryTypeSymlink = '2', /** Character device */ - OF_TAR_ARCHIVE_ENTRY_TYPE_CHARACTER_DEVICE = '3', + OFTarArchiveEntryTypeCharacterDevice = '3', /** Block device */ - OF_TAR_ARCHIVE_ENTRY_TYPE_BLOCK_DEVICE = '4', + OFTarArchiveEntryTypeBlockDevice = '4', /** Directory */ - OF_TAR_ARCHIVE_ENTRY_TYPE_DIRECTORY = '5', + OFTarArchiveEntryTypeDirectory = '5', /** FIFO */ - OF_TAR_ARCHIVE_ENTRY_TYPE_FIFO = '6', + OFTarArchiveEntryTypeFIFO = '6', /** Contiguous file */ - OF_TAR_ARCHIVE_ENTRY_TYPE_CONTIGUOUS_FILE = '7', -} of_tar_archive_entry_type_t; + OFTarArchiveEntryTypeContiguousFile = '7', +} OFTarArchiveEntryType; /** * @class OFTarArchiveEntry OFTarArchiveEntry.h ObjFW/OFTarArchiveEntry.h * * @brief A class which represents an entry of a tar archive. @@ -55,11 +53,11 @@ OFString *_fileName; unsigned long _mode; unsigned long long _size; unsigned long _UID, _GID; OFDate *_modificationDate; - of_tar_archive_entry_type_t _type; + OFTarArchiveEntryType _type; OFString *_Nullable _targetFileName; OFString *_Nullable _owner, *_Nullable _group; unsigned long _deviceMajor, _deviceMinor; OF_RESERVE_IVARS(OFTarArchiveEntry, 4) } @@ -95,13 +93,13 @@ @property (readonly, retain, nonatomic) OFDate *modificationDate; /** * @brief The type of the archive entry. * - * See @ref of_tar_archive_entry_type_t. + * See @ref OFTarArchiveEntryType. */ -@property (readonly, nonatomic) of_tar_archive_entry_type_t type; +@property (readonly, nonatomic) OFTarArchiveEntryType type; /** * @brief The file name of the target (for a hard link or symbolic link). */ @property OF_NULLABLE_PROPERTY (readonly, copy, nonatomic) Index: src/OFTarArchiveEntry.m ================================================================== --- src/OFTarArchiveEntry.m +++ src/OFTarArchiveEntry.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -25,11 +23,11 @@ #import "OFOutOfRangeException.h" static OFString * stringFromBuffer(const unsigned char *buffer, size_t length, - of_string_encoding_t encoding) + OFStringEncoding encoding) { for (size_t i = 0; i < length; i++) if (buffer[i] == '\0') length = i; @@ -38,11 +36,11 @@ length: length]; } static void stringToBuffer(unsigned char *buffer, OFString *string, size_t length, - of_string_encoding_t encoding) + OFStringEncoding encoding) { size_t cStringLength = [string cStringLengthWithEncoding: encoding]; if (cStringLength > length) @throw [OFOutOfRangeException exception]; @@ -65,11 +63,11 @@ if (buffer[0] == 0x80) { for (size_t i = 1; i < length; i++) value = (value << 8) | buffer[i]; } else value = [stringFromBuffer(buffer, length, - OF_STRING_ENCODING_ASCII) unsignedLongLongValueWithBase: 8]; + OFStringEncodingASCII) unsignedLongLongValueWithBase: 8]; if (value > max) @throw [OFOutOfRangeException exception]; return value; @@ -85,11 +83,11 @@ { OF_INVALID_INIT_METHOD } - (instancetype)of_initWithHeader: (unsigned char [512])header - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding { self = [super init]; @try { void *pool = objc_autoreleasePoolPush(); @@ -104,20 +102,20 @@ header + 116, 8, ULONG_MAX); _size = (unsigned long long)octalValueFromBuffer( header + 124, 12, ULLONG_MAX); _modificationDate = [[OFDate alloc] initWithTimeIntervalSince1970: - (of_time_interval_t)octalValueFromBuffer( + (OFTimeInterval)octalValueFromBuffer( header + 136, 12, ULLONG_MAX)]; _type = header[156]; targetFileName = stringFromBuffer(header + 157, 100, encoding); if (targetFileName.length > 0) _targetFileName = [targetFileName copy]; if (_type == '\0') - _type = OF_TAR_ARCHIVE_ENTRY_TYPE_FILE; + _type = OFTarArchiveEntryTypeFile; if (memcmp(header + 257, "ustar\0" "00", 8) == 0) { OFString *prefix; _owner = [stringFromBuffer(header + 265, 32, encoding) @@ -153,11 +151,11 @@ { self = [super init]; @try { _fileName = [fileName copy]; - _type = OF_TAR_ARCHIVE_ENTRY_TYPE_FILE; + _type = OFTarArchiveEntryTypeFile; _mode = 0644; } @catch (id e) { [self release]; @throw e; } @@ -232,11 +230,11 @@ - (OFDate *)modificationDate { return _modificationDate; } -- (of_tar_archive_entry_type_t)type +- (OFTarArchiveEntryType)type { return _type; } - (OFString *)targetFileName @@ -290,33 +288,33 @@ return [ret autorelease]; } - (void)of_writeToStream: (OFStream *)stream - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding { unsigned char buffer[512]; unsigned long long modificationDate; uint16_t checksum = 0; stringToBuffer(buffer, _fileName, 100, encoding); stringToBuffer(buffer + 100, [OFString stringWithFormat: @"%06" PRIo16 " ", _mode], 8, - OF_STRING_ENCODING_ASCII); + OFStringEncodingASCII); stringToBuffer(buffer + 108, [OFString stringWithFormat: @"%06" PRIo16 " ", _UID], 8, - OF_STRING_ENCODING_ASCII); + OFStringEncodingASCII); stringToBuffer(buffer + 116, [OFString stringWithFormat: @"%06" PRIo16 " ", _GID], 8, - OF_STRING_ENCODING_ASCII); + OFStringEncodingASCII); stringToBuffer(buffer + 124, [OFString stringWithFormat: @"%011" PRIo64 " ", _size], 12, - OF_STRING_ENCODING_ASCII); + OFStringEncodingASCII); modificationDate = _modificationDate.timeIntervalSince1970; stringToBuffer(buffer + 136, [OFString stringWithFormat: @"%011llo", modificationDate], - 12, OF_STRING_ENCODING_ASCII); + 12, OFStringEncodingASCII); /* * During checksumming, the checksum field is expected to be set to 8 * spaces. */ @@ -329,22 +327,21 @@ memcpy(buffer + 257, "ustar\0" "00", 8); stringToBuffer(buffer + 265, _owner, 32, encoding); stringToBuffer(buffer + 297, _group, 32, encoding); stringToBuffer(buffer + 329, [OFString stringWithFormat: @"%06" PRIo32 " ", _deviceMajor], 8, - OF_STRING_ENCODING_ASCII); + OFStringEncodingASCII); stringToBuffer(buffer + 337, [OFString stringWithFormat: @"%06" PRIo32 " ", _deviceMinor], 8, - OF_STRING_ENCODING_ASCII); + OFStringEncodingASCII); memset(buffer + 345, '\0', 155 + 12); /* Fill in the checksum */ for (size_t i = 0; i < 500; i++) checksum += buffer[i]; stringToBuffer(buffer + 148, [OFString stringWithFormat: @"%06" PRIo16, checksum], 7, - OF_STRING_ENCODING_ASCII); + OFStringEncodingASCII); - [stream writeBuffer: buffer - length: sizeof(buffer)]; + [stream writeBuffer: buffer length: sizeof(buffer)]; } @end Index: src/OFThread+Private.h ================================================================== --- src/OFThread+Private.h +++ src/OFThread+Private.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFThread.h ================================================================== --- src/OFThread.h +++ src/OFThread.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -16,13 +14,12 @@ */ #include #import "OFObject.h" - #ifdef OF_HAVE_THREADS -# import "thread.h" +# import "OFPlainThread.h" #endif OF_ASSUME_NONNULL_BEGIN /** @file */ @@ -38,11 +35,11 @@ /** * @brief A block to be executed in a new thread. * * @return The object which should be returned when the thread is joined */ -typedef id _Nullable (^of_thread_block_t)(void); +typedef id _Nullable (^OFThreadBlock)(void); #endif /** * @class OFThread OFThread.h ObjFW/OFThread.h * @@ -64,22 +61,22 @@ @interface OFThread: OFObject #ifdef OF_HAVE_THREADS { @private - of_thread_t _thread; - of_thread_attr_t _attr; - enum of_thread_running { - OF_THREAD_NOT_RUNNING, - OF_THREAD_RUNNING, - OF_THREAD_WAITING_FOR_JOIN + OFPlainThread _thread; + OFPlainThreadAttributes _attr; + enum OFThreadState { + OFThreadStateNotRunning, + OFThreadStateRunning, + OFThreadStateWaitingForJoin } _running; # ifndef OF_OBJFW_RUNTIME void *_pool; # endif # ifdef OF_HAVE_BLOCKS - of_thread_block_t _Nullable _threadBlock; + OFThreadBlock _Nullable _threadBlock; # endif jmp_buf _exitEnv; id _returnValue; bool _supportsSockets; OFRunLoop *_Nullable _runLoop; @@ -119,12 +116,11 @@ # ifdef OF_HAVE_BLOCKS /** * @brief The block to execute in the thread. */ -@property OF_NULLABLE_PROPERTY (readonly, nonatomic) - of_thread_block_t threadBlock; +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFThreadBlock threadBlock; # endif /** * @brief The run loop for the thread. */ @@ -169,11 +165,11 @@ * @brief Creates a new thread with the specified block. * * @param threadBlock A block which is executed by the thread * @return A new, autoreleased thread */ -+ (instancetype)threadWithThreadBlock: (of_thread_block_t)threadBlock; ++ (instancetype)threadWithThreadBlock: (OFThreadBlock)threadBlock; # endif /** * @brief Returns the current thread. * @@ -217,11 +213,11 @@ * @brief Suspends execution of the current thread for the specified time * interval. * * @param timeInterval The number of seconds to sleep */ -+ (void)sleepForTimeInterval: (of_time_interval_t)timeInterval; ++ (void)sleepForTimeInterval: (OFTimeInterval)timeInterval; /** * @brief Suspends execution of the current thread until the specified date. * * @param date The date to wait for @@ -269,11 +265,11 @@ * @brief Initializes an already allocated thread with the specified block. * * @param threadBlock A block which is executed by the thread * @return An initialized OFThread. */ -- (instancetype)initWithThreadBlock: (of_thread_block_t)threadBlock; +- (instancetype)initWithThreadBlock: (OFThreadBlock)threadBlock; # endif /** * @brief The main routine of the thread. You need to reimplement this! * Index: src/OFThread.m ================================================================== --- src/OFThread.m +++ src/OFThread.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -48,10 +46,13 @@ # include <3ds/svc.h> #endif #import "OFThread.h" #import "OFThread+Private.h" +#ifdef OF_HAVE_ATOMIC_OPS +# import "OFAtomic.h" +#endif #import "OFDate.h" #import "OFDictionary.h" #ifdef OF_HAVE_SOCKETS # import "OFDNSResolver.h" #endif @@ -77,21 +78,22 @@ # import "OFThreadJoinFailedException.h" # import "OFThreadStartFailedException.h" # import "OFThreadStillRunningException.h" #endif -#ifdef OF_HAVE_ATOMIC_OPS -# import "atomic.h" +#ifdef OF_MINT +/* freemint-gcc does not have trunc() */ +# define trunc(x) ((int64_t)(x)) #endif #if defined(OF_HAVE_THREADS) -# import "tlskey.h" +# import "OFTLSKey.h" # if defined(OF_AMIGAOS) && defined(OF_HAVE_SOCKETS) -# import "socket.h" +# import "OFSocket.h" # endif -static of_tlskey_t threadSelfKey; +static OFTLSKey threadSelfKey; static OFThread *mainThread; #elif defined(OF_HAVE_SOCKETS) static OFDNSResolver *DNSResolver; #endif @@ -101,28 +103,28 @@ callMain(id object) { OFThread *thread = (OFThread *)object; OFString *name; - if (!of_tlskey_set(threadSelfKey, thread)) + if (OFTLSKeySet(threadSelfKey, thread) != 0) @throw [OFInitializationFailedException exceptionWithClass: thread.class]; #ifndef OF_OBJFW_RUNTIME thread->_pool = objc_autoreleasePoolPush(); #endif name = thread.name; if (name != nil) - of_thread_set_name( + OFSetThreadName( [name cStringWithEncoding: [OFLocale encoding]]); else - of_thread_set_name(object_getClassName(thread)); + OFSetThreadName(object_getClassName(thread)); #if defined(OF_AMIGAOS) && defined(OF_HAVE_SOCKETS) if (thread.supportsSockets) - if (!of_socket_init()) + if (!OFSocketInit()) @throw [OFInitializationFailedException exceptionWithClass: thread.class]; #endif /* @@ -144,16 +146,16 @@ objc_autoreleasePoolPop((void *)(uintptr_t)-1); #else objc_autoreleasePoolPop(thread->_pool); #endif -#if defined(OF_AMIGAOS) && defined(OF_HAVE_SOCKETS) +#if defined(OF_AMIGAOS) && !defined(OF_MORPHOS) && defined(OF_HAVE_SOCKETS) if (thread.supportsSockets) - of_socket_deinit(); + OFSocketDeinit(); #endif - thread->_running = OF_THREAD_WAITING_FOR_JOIN; + thread->_running = OFThreadStateWaitingForJoin; [thread release]; } @synthesize name = _name; @@ -164,11 +166,11 @@ + (void)initialize { if (self != [OFThread class]) return; - if (!of_tlskey_new(&threadSelfKey)) + if (OFTLSKeyNew(&threadSelfKey) != 0) @throw [OFInitializationFailedException exceptionWithClass: self]; } + (instancetype)thread @@ -175,19 +177,19 @@ { return [[[self alloc] init] autorelease]; } # ifdef OF_HAVE_BLOCKS -+ (instancetype)threadWithThreadBlock: (of_thread_block_t)threadBlock ++ (instancetype)threadWithThreadBlock: (OFThreadBlock)threadBlock { return [[[self alloc] initWithThreadBlock: threadBlock] autorelease]; } # endif + (OFThread *)currentThread { - return of_tlskey_get(threadSelfKey); + return OFTLSKeyGet(threadSelfKey); } + (OFThread *)mainThread { return mainThread; @@ -196,16 +198,16 @@ + (bool)isMainThread { if (mainThread == nil) return false; - return (of_tlskey_get(threadSelfKey) == mainThread); + return (OFTLSKeyGet(threadSelfKey) == mainThread); } + (OFMutableDictionary *)threadDictionary { - OFThread *thread = of_tlskey_get(threadSelfKey); + OFThread *thread = OFTLSKeyGet(threadSelfKey); if (thread == nil) return nil; if (thread->_threadDictionary == nil) @@ -217,11 +219,11 @@ #ifdef OF_HAVE_SOCKETS + (OFDNSResolver *)DNSResolver { # ifdef OF_HAVE_THREADS - OFThread *thread = of_tlskey_get(threadSelfKey); + OFThread *thread = OFTLSKeyGet(threadSelfKey); if (thread == nil) return nil; if (thread->_DNSResolver == nil) @@ -235,11 +237,11 @@ return DNSResolver; # endif } #endif -+ (void)sleepForTimeInterval: (of_time_interval_t)timeInterval ++ (void)sleepForTimeInterval: (OFTimeInterval)timeInterval { if (timeInterval < 0) return; #if defined(OF_WINDOWS) @@ -250,10 +252,21 @@ #elif defined(OF_NINTENDO_3DS) if (timeInterval * 1000000000 > INT64_MAX) @throw [OFOutOfRangeException exception]; svcSleepThread((int64_t)(timeInterval * 1000000000)); +#elif defined(OF_AMIGAOS) + struct timerequest request = *DOSBase->dl_TimeReq; + + request.tr_node.io_Message.mn_ReplyPort = + &((struct Process *)FindTask(NULL))->pr_MsgPort; + request.tr_node.io_Command = TR_ADDREQUEST; + request.tr_time.tv_secs = (ULONG)timeInterval; + request.tr_time.tv_micro = (ULONG) + ((timeInterval - (unsigned int)timeInterval) * 1000000); + + DoIO((struct IORequest *)&request); #elif defined(HAVE_NANOSLEEP) struct timespec rqtp; rqtp.tv_sec = (time_t)timeInterval; rqtp.tv_nsec = (long)((timeInterval - rqtp.tv_sec) * 1000000000); @@ -260,15 +273,10 @@ if (rqtp.tv_sec != trunc(timeInterval)) @throw [OFOutOfRangeException exception]; nanosleep(&rqtp, NULL); -#elif defined(OF_AMIGAOS) - if (timeInterval * 50 > ULONG_MAX) - @throw [OFOutOfRangeException exception]; - - Delay(timeInterval * 50); #elif defined(OF_NINTENDO_DS) uint64_t counter; if (timeInterval > UINT64_MAX / 60) @throw [OFOutOfRangeException exception]; @@ -280,11 +288,11 @@ if (timeInterval > UINT_MAX) @throw [OFOutOfRangeException exception]; sleep((unsigned int)timeInterval); usleep((unsigned int) - (timeInterval - (unsigned int)timeInterval) * 1000000); + ((timeInterval - (unsigned int)timeInterval) * 1000000)); #endif } + (void)sleepUntilDate: (OFDate *)date { @@ -313,16 +321,16 @@ OF_UNREACHABLE } + (void)terminateWithObject: (id)object { - OFThread *thread = of_tlskey_get(threadSelfKey); + OFThread *thread = OFTLSKeyGet(threadSelfKey); if (thread == mainThread) @throw [OFInvalidArgumentException exception]; - OF_ENSURE(thread != nil); + OFEnsure(thread != nil); thread->_returnValue = [object retain]; longjmp(thread->_exitEnv, 1); OF_UNREACHABLE @@ -331,14 +339,14 @@ + (void)setName: (OFString *)name { [OFThread currentThread].name = name; if (name != nil) - of_thread_set_name( + OFSetThreadName( [name cStringWithEncoding: [OFLocale encoding]]); else - of_thread_set_name(class_getName([self class])); + OFSetThreadName(class_getName([self class])); } + (OFString *)name { return [OFThread currentThread].name; @@ -345,24 +353,24 @@ } + (void)of_createMainThread { mainThread = [[OFThread alloc] init]; - mainThread->_thread = of_thread_current(); - mainThread->_running = OF_THREAD_RUNNING; + mainThread->_thread = OFCurrentPlainThread(); + mainThread->_running = OFThreadStateRunning; - if (!of_tlskey_set(threadSelfKey, mainThread)) + if (OFTLSKeySet(threadSelfKey, mainThread) != 0) @throw [OFInitializationFailedException exceptionWithClass: self]; } - (instancetype)init { self = [super init]; @try { - if (!of_thread_attr_init(&_attr)) + if (OFPlainThreadAttributesInit(&_attr) != 0) @throw [OFInitializationFailedException exceptionWithClass: self.class]; } @catch (id e) { [self release]; @throw e; @@ -370,11 +378,11 @@ return self; } # ifdef OF_HAVE_BLOCKS -- (instancetype)initWithThreadBlock: (of_thread_block_t)threadBlock +- (instancetype)initWithThreadBlock: (OFThreadBlock)threadBlock { self = [self init]; @try { _threadBlock = [threadBlock copy]; @@ -409,45 +417,48 @@ # endif } - (void)start { - if (_running == OF_THREAD_RUNNING) + int error; + + if (_running == OFThreadStateRunning) @throw [OFThreadStillRunningException exceptionWithThread: self]; - if (_running == OF_THREAD_WAITING_FOR_JOIN) { - of_thread_detach(_thread); + if (_running == OFThreadStateWaitingForJoin) { + OFPlainThreadDetach(_thread); [_returnValue release]; } [self retain]; - _running = OF_THREAD_RUNNING; + _running = OFThreadStateRunning; - if (!of_thread_new(&_thread, - [_name cStringWithEncoding: [OFLocale encoding]], callMain, self, - &_attr)) { + if ((error = OFPlainThreadNew(&_thread, [_name cStringWithEncoding: + [OFLocale encoding]], callMain, self, &_attr)) != 0) { [self release]; @throw [OFThreadStartFailedException exceptionWithThread: self - errNo: errno]; + errNo: error]; } } - (id)join { - if (_running == OF_THREAD_NOT_RUNNING) + int error; + + if (_running == OFThreadStateNotRunning) @throw [OFThreadJoinFailedException exceptionWithThread: self errNo: EINVAL]; - if (!of_thread_join(_thread)) + if ((error = OFPlainThreadJoin(_thread)) != 0) @throw [OFThreadJoinFailedException exceptionWithThread: self - errNo: errno]; + errNo: error]; - _running = OF_THREAD_NOT_RUNNING; + _running = OFThreadStateNotRunning; return _returnValue; } - (id)copy @@ -459,11 +470,12 @@ { # if defined(OF_HAVE_ATOMIC_OPS) && !defined(__clang_analyzer__) if (_runLoop == nil) { OFRunLoop *tmp = [[OFRunLoop alloc] init]; - if (!of_atomic_ptr_cmpswap((void **)&_runLoop, nil, tmp)) + if (!OFAtomicPointerCompareAndSwap( + (void **)&_runLoop, nil, tmp)) [tmp release]; } # else @synchronized (self) { if (_runLoop == nil) @@ -479,11 +491,11 @@ return _attr.priority; } - (void)setPriority: (float)priority { - if (_running == OF_THREAD_RUNNING) + if (_running == OFThreadStateRunning) @throw [OFThreadStillRunningException exceptionWithThread: self]; _attr.priority = priority; } @@ -493,11 +505,11 @@ return _attr.stackSize; } - (void)setStackSize: (size_t)stackSize { - if (_running == OF_THREAD_RUNNING) + if (_running == OFThreadStateRunning) @throw [OFThreadStillRunningException exceptionWithThread: self]; _attr.stackSize = stackSize; } @@ -507,29 +519,29 @@ return _supportsSockets; } - (void)setSupportsSockets: (bool)supportsSockets { - if (_running == OF_THREAD_RUNNING) + if (_running == OFThreadStateRunning) @throw [OFThreadStillRunningException exceptionWithThread: self]; _supportsSockets = supportsSockets; } - (void)dealloc { - if (_running == OF_THREAD_RUNNING) + if (_running == OFThreadStateRunning) @throw [OFThreadStillRunningException exceptionWithThread: self]; /* * We should not be running anymore, but call detach in order to free * the resources. */ - if (_running == OF_THREAD_WAITING_FOR_JOIN) - of_thread_detach(_thread); + if (_running == OFThreadStateWaitingForJoin) + OFPlainThreadDetach(_thread); [_returnValue release]; # ifdef OF_HAVE_BLOCKS [_threadBlock release]; # endif DELETED src/OFThreadPool.h Index: src/OFThreadPool.h ================================================================== --- src/OFThreadPool.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 - -/** @file */ - -#ifdef OF_HAVE_BLOCKS -/** - * @brief A block for a job which should be executed in a thread pool. - */ -typedef void (^of_thread_pool_block_t)(void); -#endif - -@class OFCondition; -@class OFList OF_GENERIC(ObjectType); -@class OFMutableArray OF_GENERIC(ObjectType); -@class OFThreadPoolJob; - -/** - * @class OFThreadPool OFThreadPool.h ObjFW/OFThreadPool.h - * - * @brief A class providing a pool of reusable threads. - * - * @note When the thread pool is released, all threads will terminate after - * they finish the job they are currently processing. - */ -OF_SUBCLASSING_RESTRICTED -@interface OFThreadPool: OFObject -{ - size_t _size; - OFMutableArray *_threads; - volatile int _count; -#ifdef OF_THREAD_POOL_M -@public -#endif - OFList *_queue; - OFCondition *_queueCondition; - volatile int _doneCount; - OFCondition *_countCondition; -} - -/** - * @brief The size of the thread pool. - */ -@property (readonly, nonatomic) size_t size; - -/** - * @brief Returns a new thread pool with one thread for each core in the system. - * - * @warning If for some reason the number of cores in the system could not be - * determined, the pool will only have one thread! - * - * @return A new thread pool with one thread for each core in the system - */ -+ (instancetype)threadPool; - -/** - * @brief Returns a new thread pool with the specified number of threads. - * - * @param size The number of threads for the pool - * @return A new thread pool with the specified number of threads - */ -+ (instancetype)threadPoolWithSize: (size_t)size; - -/** - * @brief Initializes an already allocated OFThreadPool with the specified - * number of threads. - * - * @param size The number of threads for the pool - * @return An initialized OFThreadPool with the specified number of threads - */ -- (instancetype)initWithSize: (size_t)size OF_DESIGNATED_INITIALIZER; - -/** - * @brief Execute the specified selector on the specified target with the - * specified object as soon as a thread is ready. - * - * @param target The target on which to perform the selector - * @param selector The selector to perform on the target - * @param object The object with which the selector is performed on the target - */ -- (void)dispatchWithTarget: (id)target - selector: (SEL)selector - object: (nullable id)object; - -#ifdef OF_HAVE_BLOCKS -/** - * @brief Executes the specified block as soon as a thread is ready. - * - * @param block The block to execute - */ -- (void)dispatchWithBlock: (of_thread_pool_block_t)block; -#endif - -/** - * @brief Waits until all jobs are done. - */ -- (void)waitUntilDone; -@end - -OF_ASSUME_NONNULL_END DELETED src/OFThreadPool.m Index: src/OFThreadPool.m ================================================================== --- src/OFThreadPool.m +++ /dev/null @@ -1,363 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 OF_THREAD_POOL_M - -#import "OFThreadPool.h" -#import "OFArray.h" -#import "OFList.h" -#import "OFThread.h" -#import "OFCondition.h" -#import "OFSystemInfo.h" - -OF_DIRECT_MEMBERS -@interface OFThreadPoolJob: OFObject -{ - id _target; - SEL _selector; - id _object; -#ifdef OF_HAVE_BLOCKS - of_thread_pool_block_t _block; -#endif -} - -- (instancetype)initWithTarget: (id)target - selector: (SEL)selector - object: (id)object; -#ifdef OF_HAVE_BLOCKS -- (instancetype)initWithBlock: (of_thread_pool_block_t)block; -#endif -- (void)perform; -@end - -@implementation OFThreadPoolJob -- (instancetype)initWithTarget: (id)target - selector: (SEL)selector - object: (id)object -{ - self = [super init]; - - @try { - _target = [target retain]; - _selector = selector; - _object = [object retain]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -#ifdef OF_HAVE_BLOCKS -- (instancetype)initWithBlock: (of_thread_pool_block_t)block -{ - self = [super init]; - - @try { - _block = [block copy]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} -#endif - -- (void)dealloc -{ - [_target release]; - [_object release]; -#ifdef OF_HAVE_BLOCKS - [_block release]; -#endif - - [super dealloc]; -} - -- (void)perform -{ -#ifdef OF_HAVE_BLOCKS - if (_block != NULL) - _block(); - else -#endif - [_target performSelector: _selector - withObject: _object]; -} -@end - -OF_DIRECT_MEMBERS -@interface OFThreadPoolThread: OFThread -{ - OFList *_queue; - OFCondition *_queueCondition, *_countCondition; -@public - volatile bool _terminate; - volatile int *_doneCount; -} - -+ (instancetype)threadWithThreadPool: (OFThreadPool *)threadPool; -- (instancetype)initWithThreadPool: (OFThreadPool *)threadPool; -@end - -@implementation OFThreadPoolThread -+ (instancetype)threadWithThreadPool: (OFThreadPool *)threadPool -{ - return [[(OFThreadPoolThread *)[self alloc] - initWithThreadPool: threadPool] autorelease]; -} - -- (instancetype)initWithThreadPool: (OFThreadPool *)threadPool -{ - self = [super init]; - - @try { - _queue = [threadPool->_queue retain]; - _queueCondition = [threadPool->_queueCondition retain]; - _countCondition = [threadPool->_countCondition retain]; - _doneCount = &threadPool->_doneCount; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - [_queue release]; - [_queueCondition release]; - [_countCondition release]; - - [super dealloc]; -} - -- (id)main -{ - void *pool; - - if (_terminate) - return nil; - - pool = objc_autoreleasePoolPush(); - - for (;;) { - OFThreadPoolJob *job; - - [_queueCondition lock]; - @try { - of_list_object_t *listObject; - - if (_terminate) { - objc_autoreleasePoolPop(pool); - return nil; - } - - listObject = _queue.firstListObject; - - while (listObject == NULL) { - [_queueCondition wait]; - - if (_terminate) { - objc_autoreleasePoolPop(pool); - return nil; - } - - listObject = _queue.firstListObject; - } - - job = [[listObject->object retain] autorelease]; - [_queue removeListObject: listObject]; - } @finally { - [_queueCondition unlock]; - } - - if (_terminate) { - objc_autoreleasePoolPop(pool); - return nil; - } - - [job perform]; - - if (_terminate) { - objc_autoreleasePoolPop(pool); - return nil; - } - - objc_autoreleasePoolPop(pool); - pool = objc_autoreleasePoolPush(); - - [_countCondition lock]; - @try { - if (_terminate) { - objc_autoreleasePoolPop(pool); - return nil; - } - - (*_doneCount)++; - - [_countCondition signal]; - } @finally { - [_countCondition unlock]; - } - } -} -@end - -@implementation OFThreadPool -+ (instancetype)threadPool -{ - return [[[self alloc] init] autorelease]; -} - -+ (instancetype)threadPoolWithSize: (size_t)size -{ - return [[[self alloc] initWithSize: size] autorelease]; -} - -- (instancetype)init -{ - return [self initWithSize: [OFSystemInfo numberOfCPUs]]; -} - -- (instancetype)initWithSize: (size_t)size -{ - self = [super init]; - - @try { - _size = size; - _threads = [[OFMutableArray alloc] init]; - _queue = [[OFList alloc] init]; - _queueCondition = [[OFCondition alloc] init]; - _countCondition = [[OFCondition alloc] init]; - - for (size_t i = 0; i < size; i++) { - void *pool = objc_autoreleasePoolPush(); - - OFThreadPoolThread *thread = - [OFThreadPoolThread threadWithThreadPool: self]; - - [_threads addObject: thread]; - - objc_autoreleasePoolPop(pool); - } - - /* - * We need to start the threads in a separate loop to make sure - * _threads is not modified anymore to prevent a race condition. - */ - for (size_t i = 0; i < size; i++) - [[_threads objectAtIndex: i] start]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - [_queueCondition lock]; - @try { - [_countCondition lock]; - @try { - for (OFThreadPoolThread *thread in _threads) - thread->_terminate = true; - } @finally { - [_countCondition unlock]; - } - - [_queueCondition broadcast]; - } @finally { - [_queueCondition unlock]; - } - - [_threads release]; - [_queue release]; - [_queueCondition release]; - [_countCondition release]; - - [super dealloc]; -} - -- (void)of_dispatchJob: (OFThreadPoolJob *)job OF_DIRECT -{ - [_countCondition lock]; - _count++; - [_countCondition unlock]; - - [_queueCondition lock]; - @try { - [_queue appendObject: job]; - [_queueCondition signal]; - } @finally { - [_queueCondition unlock]; - } -} - -- (void)waitUntilDone -{ - for (;;) { - [_countCondition lock]; - @try { - if (_doneCount == _count) - return; - - [_countCondition wait]; - } @finally { - [_countCondition unlock]; - } - } -} - -- (void)dispatchWithTarget: (id)target - selector: (SEL)selector - object: (id)object -{ - OFThreadPoolJob *job = [[OFThreadPoolJob alloc] initWithTarget: target - selector: selector - object: object]; - @try { - [self of_dispatchJob: job]; - } @finally { - [job release]; - } -} - -#ifdef OF_HAVE_BLOCKS -- (void)dispatchWithBlock: (of_thread_pool_block_t)block -{ - OFThreadPoolJob *job = [[OFThreadPoolJob alloc] initWithBlock: block]; - @try { - [self of_dispatchJob: job]; - } @finally { - [job release]; - } -} -#endif - -- (size_t)size -{ - return _size; -} -@end Index: src/OFTimer+Private.h ================================================================== --- src/OFTimer+Private.h +++ src/OFTimer+Private.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -20,9 +18,9 @@ OF_ASSUME_NONNULL_BEGIN OF_DIRECT_MEMBERS @interface OFTimer () - (void)of_setInRunLoop: (nullable OFRunLoop *)runLoop - mode: (nullable of_run_loop_mode_t)mode; + mode: (nullable OFRunLoopMode)mode; @end OF_ASSUME_NONNULL_END Index: src/OFTimer.h ================================================================== --- src/OFTimer.h +++ src/OFTimer.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -32,11 +30,11 @@ /** * @brief A block to execute when a timer fires. * * @param timer The timer which fired */ -typedef void (^of_timer_block_t)(OFTimer *timer); +typedef void (^OFTimerBlock)(OFTimer *timer); #endif /** * @class OFTimer OFTimer.h ObjFW/OFTimer.h * @@ -44,38 +42,38 @@ */ OF_SUBCLASSING_RESTRICTED @interface OFTimer: OFObject { OFDate *_fireDate; - of_time_interval_t _interval; + OFTimeInterval _interval; id _target; id _Nullable _object1, _object2, _object3, _object4; SEL _selector; unsigned char _arguments; bool _repeats; #ifdef OF_HAVE_BLOCKS - of_timer_block_t _block; + OFTimerBlock _block; #endif bool _valid; #ifdef OF_HAVE_THREADS OFCondition *_condition; bool _done; #endif OFRunLoop *_Nullable _inRunLoop; - of_run_loop_mode_t _Nullable _inRunLoopMode; + OFRunLoopMode _Nullable _inRunLoopMode; } /** * @brief The time interval in which the timer will repeat, if it is a * repeating timer. */ -@property (readonly, nonatomic) of_time_interval_t timeInterval; +@property (readonly, nonatomic) OFTimeInterval timeInterval; /** - * @brief Whether the timer is repeating. + * @brief Whether the timer repeats. */ -@property (readonly, nonatomic, getter=isRepeating) bool repeating; +@property (readonly, nonatomic) bool repeats; /** * @brief Whether the timer is valid. */ @property (readonly, nonatomic, getter=isValid) bool valid; @@ -97,11 +95,11 @@ * @param target The target on which to call the selector * @param selector The selector to call on the target * @param repeats Whether the timer repeats after it has been executed * @return A new, autoreleased timer */ -+ (instancetype)scheduledTimerWithTimeInterval: (of_time_interval_t)timeInterval ++ (instancetype)scheduledTimerWithTimeInterval: (OFTimeInterval)timeInterval target: (id)target selector: (SEL)selector repeats: (bool)repeats; /** @@ -112,11 +110,11 @@ * @param selector The selector to call on the target * @param object An object to pass when calling the selector on the target * @param repeats Whether the timer repeats after it has been executed * @return A new, autoreleased timer */ -+ (instancetype)scheduledTimerWithTimeInterval: (of_time_interval_t)timeInterval ++ (instancetype)scheduledTimerWithTimeInterval: (OFTimeInterval)timeInterval target: (id)target selector: (SEL)selector object: (nullable id)object repeats: (bool)repeats; @@ -131,11 +129,11 @@ * @param object2 The second object to pass when calling the selector on the * target * @param repeats Whether the timer repeats after it has been executed * @return A new, autoreleased timer */ -+ (instancetype)scheduledTimerWithTimeInterval: (of_time_interval_t)timeInterval ++ (instancetype)scheduledTimerWithTimeInterval: (OFTimeInterval)timeInterval target: (id)target selector: (SEL)selector object: (nullable id)object1 object: (nullable id)object2 repeats: (bool)repeats; @@ -153,11 +151,11 @@ * @param object3 The third object to pass when calling the selector on the * target * @param repeats Whether the timer repeats after it has been executed * @return A new, autoreleased timer */ -+ (instancetype)scheduledTimerWithTimeInterval: (of_time_interval_t)timeInterval ++ (instancetype)scheduledTimerWithTimeInterval: (OFTimeInterval)timeInterval target: (id)target selector: (SEL)selector object: (nullable id)object1 object: (nullable id)object2 object: (nullable id)object3 @@ -178,11 +176,11 @@ * @param object4 The fourth object to pass when calling the selector on the * target * @param repeats Whether the timer repeats after it has been executed * @return A new, autoreleased timer */ -+ (instancetype)scheduledTimerWithTimeInterval: (of_time_interval_t)timeInterval ++ (instancetype)scheduledTimerWithTimeInterval: (OFTimeInterval)timeInterval target: (id)target selector: (SEL)selector object: (nullable id)object1 object: (nullable id)object2 object: (nullable id)object3 @@ -196,13 +194,13 @@ * @param timeInterval The time interval after which the timer should be fired * @param repeats Whether the timer repeats after it has been executed * @param block The block to invoke when the timer fires * @return A new, autoreleased timer */ -+ (instancetype)scheduledTimerWithTimeInterval: (of_time_interval_t)timeInterval ++ (instancetype)scheduledTimerWithTimeInterval: (OFTimeInterval)timeInterval repeats: (bool)repeats - block: (of_timer_block_t)block; + block: (OFTimerBlock)block; #endif /** * @brief Creates a new timer with the specified time interval. * @@ -210,11 +208,11 @@ * @param target The target on which to call the selector * @param selector The selector to call on the target * @param repeats Whether the timer repeats after it has been executed * @return A new, autoreleased timer */ -+ (instancetype)timerWithTimeInterval: (of_time_interval_t)timeInterval ++ (instancetype)timerWithTimeInterval: (OFTimeInterval)timeInterval target: (id)target selector: (SEL)selector repeats: (bool)repeats; /** @@ -225,11 +223,11 @@ * @param selector The selector to call on the target * @param object An object to pass when calling the selector on the target * @param repeats Whether the timer repeats after it has been executed * @return A new, autoreleased timer */ -+ (instancetype)timerWithTimeInterval: (of_time_interval_t)timeInterval ++ (instancetype)timerWithTimeInterval: (OFTimeInterval)timeInterval target: (id)target selector: (SEL)selector object: (nullable id)object repeats: (bool)repeats; @@ -244,11 +242,11 @@ * @param object2 The second object to pass when calling the selector on the * target * @param repeats Whether the timer repeats after it has been executed * @return A new, autoreleased timer */ -+ (instancetype)timerWithTimeInterval: (of_time_interval_t)timeInterval ++ (instancetype)timerWithTimeInterval: (OFTimeInterval)timeInterval target: (id)target selector: (SEL)selector object: (nullable id)object1 object: (nullable id)object2 repeats: (bool)repeats; @@ -266,11 +264,11 @@ * @param object3 The third object to pass when calling the selector on the * target * @param repeats Whether the timer repeats after it has been executed * @return A new, autoreleased timer */ -+ (instancetype)timerWithTimeInterval: (of_time_interval_t)timeInterval ++ (instancetype)timerWithTimeInterval: (OFTimeInterval)timeInterval target: (id)target selector: (SEL)selector object: (nullable id)object1 object: (nullable id)object2 object: (nullable id)object3 @@ -291,11 +289,11 @@ * @param object4 The fourth object to pass when calling the selector on the * target * @param repeats Whether the timer repeats after it has been executed * @return A new, autoreleased timer */ -+ (instancetype)timerWithTimeInterval: (of_time_interval_t)timeInterval ++ (instancetype)timerWithTimeInterval: (OFTimeInterval)timeInterval target: (id)target selector: (SEL)selector object: (nullable id)object1 object: (nullable id)object2 object: (nullable id)object3 @@ -309,13 +307,13 @@ * @param timeInterval The time interval after which the timer should be fired * @param repeats Whether the timer repeats after it has been executed * @param block The block to invoke when the timer fires * @return A new, autoreleased timer */ -+ (instancetype)timerWithTimeInterval: (of_time_interval_t)timeInterval ++ (instancetype)timerWithTimeInterval: (OFTimeInterval)timeInterval repeats: (bool)repeats - block: (of_timer_block_t)block; + block: (OFTimerBlock)block; #endif - (instancetype)init OF_UNAVAILABLE; /** @@ -329,11 +327,11 @@ * @param selector The selector to call on the target * @param repeats Whether the timer repeats after it has been executed * @return An initialized timer */ - (instancetype)initWithFireDate: (OFDate *)fireDate - interval: (of_time_interval_t)interval + interval: (OFTimeInterval)interval target: (id)target selector: (SEL)selector repeats: (bool)repeats; /** @@ -348,11 +346,11 @@ * @param object An object to pass when calling the selector on the target * @param repeats Whether the timer repeats after it has been executed * @return An initialized timer */ - (instancetype)initWithFireDate: (OFDate *)fireDate - interval: (of_time_interval_t)interval + interval: (OFTimeInterval)interval target: (id)target selector: (SEL)selector object: (nullable id)object repeats: (bool)repeats; @@ -371,11 +369,11 @@ * target * @param repeats Whether the timer repeats after it has been executed * @return An initialized timer */ - (instancetype)initWithFireDate: (OFDate *)fireDate - interval: (of_time_interval_t)interval + interval: (OFTimeInterval)interval target: (id)target selector: (SEL)selector object: (nullable id)object1 object: (nullable id)object2 repeats: (bool)repeats; @@ -397,11 +395,11 @@ * target * @param repeats Whether the timer repeats after it has been executed * @return An initialized timer */ - (instancetype)initWithFireDate: (OFDate *)fireDate - interval: (of_time_interval_t)interval + interval: (OFTimeInterval)interval target: (id)target selector: (SEL)selector object: (nullable id)object1 object: (nullable id)object2 object: (nullable id)object3 @@ -426,11 +424,11 @@ * target * @param repeats Whether the timer repeats after it has been executed * @return An initialized timer */ - (instancetype)initWithFireDate: (OFDate *)fireDate - interval: (of_time_interval_t)interval + interval: (OFTimeInterval)interval target: (id)target selector: (SEL)selector object: (nullable id)object1 object: (nullable id)object2 object: (nullable id)object3 @@ -448,15 +446,23 @@ * @param repeats Whether the timer repeats after it has been executed * @param block The block to invoke when the timer fires * @return An initialized timer */ - (instancetype)initWithFireDate: (OFDate *)fireDate - interval: (of_time_interval_t)interval + interval: (OFTimeInterval)interval repeats: (bool)repeats - block: (of_timer_block_t)block; + block: (OFTimerBlock)block; #endif +/** + * @brief Compares the timer to another timer. + * + * @param timer The timer to compare the string to + * @return The result of the comparison + */ +- (OFComparisonResult)compare: (OFTimer *)timer; + /** * @brief Fires the timer, meaning it will execute the specified selector on the * target. */ - (void)fire; Index: src/OFTimer.m ================================================================== --- src/OFTimer.m +++ src/OFTimer.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -31,13 +29,13 @@ #endif #import "OFInvalidArgumentException.h" @implementation OFTimer -@synthesize timeInterval = _interval, repeating = _repeats, valid = _valid; +@synthesize timeInterval = _interval, repeats = _repeats, valid = _valid; -+ (instancetype)scheduledTimerWithTimeInterval: (of_time_interval_t)timeInterval ++ (instancetype)scheduledTimerWithTimeInterval: (OFTimeInterval)timeInterval target: (id)target selector: (SEL)selector repeats: (bool)repeats { void *pool = objc_autoreleasePoolPush(); @@ -54,11 +52,11 @@ objc_autoreleasePoolPop(pool); return [timer autorelease]; } -+ (instancetype)scheduledTimerWithTimeInterval: (of_time_interval_t)timeInterval ++ (instancetype)scheduledTimerWithTimeInterval: (OFTimeInterval)timeInterval target: (id)target selector: (SEL)selector object: (id)object repeats: (bool)repeats { @@ -77,11 +75,11 @@ objc_autoreleasePoolPop(pool); return [timer autorelease]; } -+ (instancetype)scheduledTimerWithTimeInterval: (of_time_interval_t)timeInterval ++ (instancetype)scheduledTimerWithTimeInterval: (OFTimeInterval)timeInterval target: (id)target selector: (SEL)selector object: (id)object1 object: (id)object2 repeats: (bool)repeats @@ -102,11 +100,11 @@ objc_autoreleasePoolPop(pool); return [timer autorelease]; } -+ (instancetype)scheduledTimerWithTimeInterval: (of_time_interval_t)timeInterval ++ (instancetype)scheduledTimerWithTimeInterval: (OFTimeInterval)timeInterval target: (id)target selector: (SEL)selector object: (id)object1 object: (id)object2 object: (id)object3 @@ -129,11 +127,11 @@ objc_autoreleasePoolPop(pool); return [timer autorelease]; } -+ (instancetype)scheduledTimerWithTimeInterval: (of_time_interval_t)timeInterval ++ (instancetype)scheduledTimerWithTimeInterval: (OFTimeInterval)timeInterval target: (id)target selector: (SEL)selector object: (id)object1 object: (id)object2 object: (id)object3 @@ -159,13 +157,13 @@ return [timer autorelease]; } #ifdef OF_HAVE_BLOCKS -+ (instancetype)scheduledTimerWithTimeInterval: (of_time_interval_t)timeInterval ++ (instancetype)scheduledTimerWithTimeInterval: (OFTimeInterval)timeInterval repeats: (bool)repeats - block: (of_timer_block_t)block + block: (OFTimerBlock)block { void *pool = objc_autoreleasePoolPush(); OFDate *fireDate = [OFDate dateWithTimeIntervalSinceNow: timeInterval]; id timer = [[[self alloc] initWithFireDate: fireDate interval: timeInterval @@ -179,11 +177,11 @@ return [timer autorelease]; } #endif -+ (instancetype)timerWithTimeInterval: (of_time_interval_t)timeInterval ++ (instancetype)timerWithTimeInterval: (OFTimeInterval)timeInterval target: (id)target selector: (SEL)selector repeats: (bool)repeats { void *pool = objc_autoreleasePoolPush(); @@ -198,11 +196,11 @@ objc_autoreleasePoolPop(pool); return [timer autorelease]; } -+ (instancetype)timerWithTimeInterval: (of_time_interval_t)timeInterval ++ (instancetype)timerWithTimeInterval: (OFTimeInterval)timeInterval target: (id)target selector: (SEL)selector object: (id)object repeats: (bool)repeats { @@ -219,11 +217,11 @@ objc_autoreleasePoolPop(pool); return [timer autorelease]; } -+ (instancetype)timerWithTimeInterval: (of_time_interval_t)timeInterval ++ (instancetype)timerWithTimeInterval: (OFTimeInterval)timeInterval target: (id)target selector: (SEL)selector object: (id)object1 object: (id)object2 repeats: (bool)repeats @@ -242,11 +240,11 @@ objc_autoreleasePoolPop(pool); return [timer autorelease]; } -+ (instancetype)timerWithTimeInterval: (of_time_interval_t)timeInterval ++ (instancetype)timerWithTimeInterval: (OFTimeInterval)timeInterval target: (id)target selector: (SEL)selector object: (id)object1 object: (id)object2 object: (id)object3 @@ -267,11 +265,11 @@ objc_autoreleasePoolPop(pool); return [timer autorelease]; } -+ (instancetype)timerWithTimeInterval: (of_time_interval_t)timeInterval ++ (instancetype)timerWithTimeInterval: (OFTimeInterval)timeInterval target: (id)target selector: (SEL)selector object: (id)object1 object: (id)object2 object: (id)object3 @@ -295,13 +293,13 @@ return [timer autorelease]; } #ifdef OF_HAVE_BLOCKS -+ (instancetype)timerWithTimeInterval: (of_time_interval_t)timeInterval ++ (instancetype)timerWithTimeInterval: (OFTimeInterval)timeInterval repeats: (bool)repeats - block: (of_timer_block_t)block + block: (OFTimerBlock)block { void *pool = objc_autoreleasePoolPush(); OFDate *fireDate = [OFDate dateWithTimeIntervalSinceNow: timeInterval]; id timer = [[[self alloc] initWithFireDate: fireDate interval: timeInterval @@ -319,11 +317,11 @@ { OF_INVALID_INIT_METHOD } - (instancetype)of_initWithFireDate: (OFDate *)fireDate - interval: (of_time_interval_t)interval + interval: (OFTimeInterval)interval target: (id)target selector: (SEL)selector object: (id)object1 object: (id)object2 object: (id)object3 @@ -356,11 +354,11 @@ return self; } - (instancetype)initWithFireDate: (OFDate *)fireDate - interval: (of_time_interval_t)interval + interval: (OFTimeInterval)interval target: (id)target selector: (SEL)selector repeats: (bool)repeats { return [self of_initWithFireDate: fireDate @@ -374,11 +372,11 @@ arguments: 0 repeats: repeats]; } - (instancetype)initWithFireDate: (OFDate *)fireDate - interval: (of_time_interval_t)interval + interval: (OFTimeInterval)interval target: (id)target selector: (SEL)selector object: (id)object repeats: (bool)repeats { @@ -393,11 +391,11 @@ arguments: 1 repeats: repeats]; } - (instancetype)initWithFireDate: (OFDate *)fireDate - interval: (of_time_interval_t)interval + interval: (OFTimeInterval)interval target: (id)target selector: (SEL)selector object: (id)object1 object: (id)object2 repeats: (bool)repeats @@ -413,11 +411,11 @@ arguments: 2 repeats: repeats]; } - (instancetype)initWithFireDate: (OFDate *)fireDate - interval: (of_time_interval_t)interval + interval: (OFTimeInterval)interval target: (id)target selector: (SEL)selector object: (id)object1 object: (id)object2 object: (id)object3 @@ -434,11 +432,11 @@ arguments: 3 repeats: repeats]; } - (instancetype)initWithFireDate: (OFDate *)fireDate - interval: (of_time_interval_t)interval + interval: (OFTimeInterval)interval target: (id)target selector: (SEL)selector object: (id)object1 object: (id)object2 object: (id)object3 @@ -457,13 +455,13 @@ repeats: repeats]; } #ifdef OF_HAVE_BLOCKS - (instancetype)initWithFireDate: (OFDate *)fireDate - interval: (of_time_interval_t)interval + interval: (OFTimeInterval)interval repeats: (bool)repeats - block: (of_timer_block_t)block + block: (OFTimerBlock)block { self = [super init]; @try { _fireDate = [fireDate retain]; @@ -506,27 +504,22 @@ #endif [super dealloc]; } -- (of_comparison_result_t)compare: (id )object -{ - OFTimer *timer; - - if (![(id)object isKindOfClass: [OFTimer class]]) - @throw [OFInvalidArgumentException exception]; - - timer = (OFTimer *)object; +- (OFComparisonResult)compare: (OFTimer *)timer +{ + if (![timer isKindOfClass: [OFTimer class]]) + @throw [OFInvalidArgumentException exception]; return [_fireDate compare: timer->_fireDate]; } -- (void)of_setInRunLoop: (OFRunLoop *)runLoop - mode: (of_run_loop_mode_t)mode +- (void)of_setInRunLoop: (OFRunLoop *)runLoop mode: (OFRunLoopMode)mode { OFRunLoop *oldInRunLoop = _inRunLoop; - of_run_loop_mode_t oldInRunLoopMode = _inRunLoopMode; + OFRunLoopMode oldInRunLoopMode = _inRunLoopMode; _inRunLoop = [runLoop retain]; [oldInRunLoop release]; _inRunLoopMode = [mode copy]; @@ -540,16 +533,16 @@ id object1 = [[_object1 retain] autorelease]; id object2 = [[_object2 retain] autorelease]; id object3 = [[_object3 retain] autorelease]; id object4 = [[_object4 retain] autorelease]; - OF_ENSURE(_arguments <= 4); + OFEnsure(_arguments <= 4); if (_repeats && _valid) { int64_t missedIntervals = -_fireDate.timeIntervalSinceNow / _interval; - of_time_interval_t newFireDate; + OFTimeInterval newFireDate; OFRunLoop *runLoop; /* In case the clock was changed backwards */ if (missedIntervals < 0) missedIntervals = 0; @@ -560,12 +553,11 @@ [_fireDate release]; _fireDate = [[OFDate alloc] initWithTimeIntervalSince1970: newFireDate]; runLoop = [OFRunLoop currentRunLoop]; - [runLoop addTimer: self - forMode: runLoop.currentMode]; + [runLoop addTimer: self forMode: runLoop.currentMode]; } else [self invalidate]; #ifdef OF_HAVE_BLOCKS if (_block != NULL) @@ -575,12 +567,11 @@ switch (_arguments) { case 0: [target performSelector: _selector]; break; case 1: - [target performSelector: _selector - withObject: object1]; + [target performSelector: _selector withObject: object1]; break; case 2: [target performSelector: _selector withObject: object1 withObject: object2]; @@ -633,12 +624,11 @@ old = _fireDate; _fireDate = [fireDate copy]; [old release]; - [_inRunLoop addTimer: self - forMode: _inRunLoopMode]; + [_inRunLoop addTimer: self forMode: _inRunLoopMode]; } } @finally { [self release]; } } @@ -674,6 +664,35 @@ } @finally { [_condition unlock]; } } #endif + +- (OFString *)description +{ +#ifdef OF_HAVE_BLOCKS + if (_block != NULL) + return [OFString stringWithFormat: + @"<%@:\n" + @"\tFire date: %@\n" + @"\tInterval: %lf\n" + @"\tRepeats: %s\n" + @"\tBlock: %@\n" + @"\tValid: %s\n" + @">", + self.class, _fireDate, _interval, (_repeats ? "yes" : "no"), + _block, (_valid ? "yes" : "no")]; + else +#endif + return [OFString stringWithFormat: + @"<%@:\n" + @"\tFire date: %@\n" + @"\tInterval: %lf\n" + @"\tRepeats: %s\n" + @"\tTarget: %@\n" + @"\tSelector: %s\n" + @"\tValid: %s\n" + @">", + self.class, _fireDate, _interval, (_repeats ? "yes" : "no"), + _target, sel_getName(_selector), (_valid ? "yes" : "no")]; +} @end Index: src/OFTriple.h ================================================================== --- src/OFTriple.h +++ src/OFTriple.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFTriple.m ================================================================== --- src/OFTriple.m +++ src/OFTriple.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -99,19 +97,19 @@ return true; } - (unsigned long)hash { - uint32_t hash; - - OF_HASH_INIT(hash); - - OF_HASH_ADD_HASH(hash, [_firstObject hash]); - OF_HASH_ADD_HASH(hash, [_secondObject hash]); - OF_HASH_ADD_HASH(hash, [_thirdObject hash]); - - OF_HASH_FINALIZE(hash); + unsigned long hash; + + OFHashInit(&hash); + + OFHashAddHash(&hash, [_firstObject hash]); + OFHashAddHash(&hash, [_secondObject hash]); + OFHashAddHash(&hash, [_thirdObject hash]); + + OFHashFinalize(&hash); return hash; } - (id)copy Index: src/OFUDPSocket+Private.h ================================================================== --- src/OFUDPSocket+Private.h +++ src/OFUDPSocket+Private.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -19,10 +17,10 @@ OF_ASSUME_NONNULL_BEGIN OF_DIRECT_MEMBERS @interface OFUDPSocket () -- (uint16_t)of_bindToAddress: (of_socket_address_t *)address +- (uint16_t)of_bindToAddress: (OFSocketAddress *)address extraType: (int)extraType; @end OF_ASSUME_NONNULL_END Index: src/OFUDPSocket.h ================================================================== --- src/OFUDPSocket.h +++ src/OFUDPSocket.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -32,15 +30,16 @@ /** * @class OFUDPSocket OFUDPSocket.h ObjFW/OFUDPSocket.h * * @brief A class which provides methods to create and use UDP sockets. * - * Addresses are of type @ref of_socket_address_t. You can use the current - * thread's @ref OFDNSResolver to create an address for a host / port pair and - * @ref of_socket_address_ip_string to get the IP string / port pair for an - * address. If you want to compare two addresses, you can use @ref - * of_socket_address_equal and you can use @ref of_socket_address_hash to get a + * 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 + * 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* * 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, @@ -72,10 +71,9 @@ * 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 */ -- (uint16_t)bindToHost: (OFString *)host - port: (uint16_t)port; +- (uint16_t)bindToHost: (OFString *)host port: (uint16_t)port; @end OF_ASSUME_NONNULL_END Index: src/OFUDPSocket.m ================================================================== --- src/OFUDPSocket.m +++ src/OFUDPSocket.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -15,10 +13,15 @@ * file. */ #include "config.h" +#ifndef _XOPEN_SOURCE_EXTENDED +# define _XOPEN_SOURCE_EXTENDED +#endif +#define _HPUX_ALT_XOPEN_SOCKET_API + #include #ifdef HAVE_FCNTL_H # include #endif @@ -25,40 +28,36 @@ #import "OFUDPSocket.h" #import "OFUDPSocket+Private.h" #import "OFDNSResolver.h" #import "OFData.h" +#import "OFSocket.h" +#import "OFSocket+Private.h" #import "OFThread.h" #import "OFAlreadyConnectedException.h" #import "OFBindFailedException.h" -#import "socket.h" -#import "socket_helpers.h" - @implementation OFUDPSocket @dynamic delegate; -- (uint16_t)of_bindToAddress: (of_socket_address_t *)address +- (uint16_t)of_bindToAddress: (OFSocketAddress *)address extraType: (int)extraType OF_DIRECT { void *pool = objc_autoreleasePoolPush(); - OFString *host; uint16_t port; #if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) int flags; #endif if ((_socket = socket(address->sockaddr.sockaddr.sa_family, - SOCK_DGRAM | SOCK_CLOEXEC | extraType, 0)) == INVALID_SOCKET) { - host = of_socket_address_ip_string(address, &port); + SOCK_DGRAM | SOCK_CLOEXEC | extraType, 0)) == OFInvalidSocketHandle) @throw [OFBindFailedException - exceptionWithHost: host - port: port + exceptionWithHost: OFSocketAddressString(address) + port: OFSocketAddressPort(address) socket: self - errNo: of_socket_errno()]; - } + errNo: OFSocketErrNo()]; _canBlock = true; #if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) /* {} needed to avoid warning with Clang 10 if next #if is false. */ @@ -65,51 +64,49 @@ if ((flags = fcntl(_socket, F_GETFD, 0)) != -1) { fcntl(_socket, F_SETFD, flags | FD_CLOEXEC); } #endif -#if defined(OF_WII) || defined(OF_NINTENDO_3DS) - if (of_socket_address_get_port(address) != 0) { +#if defined(OF_HPUX) || defined(OF_WII) || defined(OF_NINTENDO_3DS) + if (OFSocketAddressPort(address) != 0) { #endif if (bind(_socket, &address->sockaddr.sockaddr, address->length) != 0) { - int errNo = of_socket_errno(); + int errNo = OFSocketErrNo(); closesocket(_socket); - _socket = INVALID_SOCKET; - - host = of_socket_address_ip_string(address, &port); - @throw [OFBindFailedException exceptionWithHost: host - port: port - socket: self - errNo: errNo]; - } -#if defined(OF_WII) || defined(OF_NINTENDO_3DS) + _socket = OFInvalidSocketHandle; + + @throw [OFBindFailedException + exceptionWithHost: OFSocketAddressString(address) + port: OFSocketAddressPort(address) + socket: self + errNo: errNo]; + } +#if defined(OF_HPUX) || defined(OF_WII) || defined(OF_NINTENDO_3DS) } else { for (;;) { uint16_t rnd = 0; int ret; while (rnd < 1024) rnd = (uint16_t)rand(); - of_socket_address_set_port(address, rnd); + OFSocketAddressSetPort(address, rnd); if ((ret = bind(_socket, &address->sockaddr.sockaddr, - address->length)) == 0) { - port = rnd; + address->length)) == 0) break; - } - if (of_socket_errno() != EADDRINUSE) { - int errNo = of_socket_errno(); + if (OFSocketErrNo() != EADDRINUSE) { + int errNo = OFSocketErrNo(); + OFString *host = OFSocketAddressString(address); + port = OFSocketAddressPort(address); closesocket(_socket); - _socket = INVALID_SOCKET; + _socket = OFInvalidSocketHandle; - host = of_socket_address_ip_string( - address, &port); @throw [OFBindFailedException exceptionWithHost: host port: port socket: self errNo: errNo]; @@ -118,79 +115,77 @@ } #endif objc_autoreleasePoolPop(pool); - if ((port = of_socket_address_get_port(address)) > 0) + if ((port = OFSocketAddressPort(address)) > 0) return port; -#if !defined(OF_WII) && !defined(OF_NINTENDO_3DS) +#if !defined(OF_HPUX) && !defined(OF_WII) && !defined(OF_NINTENDO_3DS) memset(address, 0, sizeof(*address)); address->length = (socklen_t)sizeof(address->sockaddr); - if (of_getsockname(_socket, &address->sockaddr.sockaddr, + if (OFGetSockName(_socket, &address->sockaddr.sockaddr, &address->length) != 0) { - int errNo = of_socket_errno(); + int errNo = OFSocketErrNo(); closesocket(_socket); - _socket = INVALID_SOCKET; + _socket = OFInvalidSocketHandle; - host = of_socket_address_ip_string(address, &port); - @throw [OFBindFailedException exceptionWithHost: host - port: port - socket: self - errNo: errNo]; + @throw [OFBindFailedException + exceptionWithHost: OFSocketAddressString(address) + port: OFSocketAddressPort(address) + socket: self + errNo: errNo]; } if (address->sockaddr.sockaddr.sa_family == AF_INET) - return OF_BSWAP16_IF_LE(address->sockaddr.in.sin_port); + return OFFromBigEndian16(address->sockaddr.in.sin_port); # ifdef OF_HAVE_IPV6 else if (address->sockaddr.sockaddr.sa_family == AF_INET6) - return OF_BSWAP16_IF_LE(address->sockaddr.in6.sin6_port); + return OFFromBigEndian16(address->sockaddr.in6.sin6_port); # endif else { closesocket(_socket); - _socket = INVALID_SOCKET; + _socket = OFInvalidSocketHandle; - host = of_socket_address_ip_string(address, &port); - @throw [OFBindFailedException exceptionWithHost: host - port: port - socket: self - errNo: EAFNOSUPPORT]; + @throw [OFBindFailedException + exceptionWithHost: OFSocketAddressString(address) + port: OFSocketAddressPort(address) + socket: self + errNo: EAFNOSUPPORT]; } #else closesocket(_socket); - _socket = INVALID_SOCKET; + _socket = OFInvalidSocketHandle; - host = of_socket_address_ip_string(address, &port); - @throw [OFBindFailedException exceptionWithHost: host - port: port - socket: self - errNo: EADDRNOTAVAIL]; + @throw [OFBindFailedException + exceptionWithHost: OFSocketAddressString(address) + port: OFSocketAddressPort(address) + socket: self + errNo: EADDRNOTAVAIL]; #endif } -- (uint16_t)bindToHost: (OFString *)host - port: (uint16_t)port +- (uint16_t)bindToHost: (OFString *)host port: (uint16_t)port { void *pool = objc_autoreleasePoolPush(); OFData *socketAddresses; - of_socket_address_t address; + OFSocketAddress address; - if (_socket != INVALID_SOCKET) + if (_socket != OFInvalidSocketHandle) @throw [OFAlreadyConnectedException exceptionWithSocket: self]; socketAddresses = [[OFThread DNSResolver] resolveAddressesForHost: host - addressFamily: OF_SOCKET_ADDRESS_FAMILY_ANY]; + addressFamily: OFSocketAddressFamilyAny]; - address = *(of_socket_address_t *)[socketAddresses itemAtIndex: 0]; - of_socket_address_set_port(&address, port); + address = *(OFSocketAddress *)[socketAddresses itemAtIndex: 0]; + OFSocketAddressSetPort(&address, port); - port = [self of_bindToAddress: &address - extraType: 0]; + port = [self of_bindToAddress: &address extraType: 0]; objc_autoreleasePoolPop(pool); return port; } @end ADDED src/OFUNIXDatagramSocket.h Index: src/OFUNIXDatagramSocket.h ================================================================== --- /dev/null +++ src/OFUNIXDatagramSocket.h @@ -0,0 +1,72 @@ +/* + * 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 "OFDatagramSocket.h" + +OF_ASSUME_NONNULL_BEGIN + +@class OFString; + +/** + * @protocol OFUNIXDatagramSocketDelegate OFUNIXDatagramSocket.h \ + * ObjFW/OFUNIXDatagramSocket.h + * + * @brief A delegate for OFUNIXDatagramSocket. + */ +@protocol OFUNIXDatagramSocketDelegate +@end + +/** + * @class OFUNIXDatagramSocket OFUNIXDatagramSocket.h \ + * ObjFW/OFUNIXDatagramSocket.h + * + * @brief A class which provides methods to create and use UNIX datagram + * sockets. + * + * Addresses are of type @ref OFSocketAddress. You can use + * @ref OFSocketAddressMakeUNIX to create an address or + * @ref OFSocketAddressUNIXPath to get the socket path. + * + * @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 OFUNIXDatagramSocket: OFDatagramSocket +{ + OF_RESERVE_IVARS(OFUNIXDatagramSocket, 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 path. + * + * @param path The path to bind to + * @return The address on which this socket can be reached + */ +- (OFSocketAddress)bindToPath: (OFString *)path; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFUNIXDatagramSocket.m Index: src/OFUNIXDatagramSocket.m ================================================================== --- /dev/null +++ src/OFUNIXDatagramSocket.m @@ -0,0 +1,72 @@ +/* + * 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" + +#ifdef HAVE_FCNTL_H +# include +#endif + +#import "OFUNIXDatagramSocket.h" +#import "OFSocket.h" +#import "OFSocket+Private.h" +#import "OFString.h" + +#import "OFAlreadyConnectedException.h" +#import "OFBindFailedException.h" + +@implementation OFUNIXDatagramSocket +@dynamic delegate; + +- (OFSocketAddress)bindToPath: (OFString *)path +{ + OFSocketAddress address; +#if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL_H) && defined(FD_CLOEXEC) + int flags; +#endif + + if (_socket != OFInvalidSocketHandle) + @throw [OFAlreadyConnectedException exceptionWithSocket: self]; + + address = OFSocketAddressMakeUNIX(path); + + if ((_socket = socket(address.sockaddr.sockaddr.sa_family, + SOCK_DGRAM | SOCK_CLOEXEC, 0)) == OFInvalidSocketHandle) + @throw [OFBindFailedException + exceptionWithPath: path + 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, &address.sockaddr.sockaddr, address.length) != 0) { + int errNo = OFSocketErrNo(); + + closesocket(_socket); + _socket = OFInvalidSocketHandle; + + @throw [OFBindFailedException exceptionWithPath: path + socket: self + errNo: errNo]; + } + + return address; +} +@end ADDED src/OFUNIXStreamSocket.h Index: src/OFUNIXStreamSocket.h ================================================================== --- /dev/null +++ src/OFUNIXStreamSocket.h @@ -0,0 +1,68 @@ +/* + * 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 "OFStreamSocket.h" + +OF_ASSUME_NONNULL_BEGIN + +@class OFString; + +/** + * @protocol OFUNIXStreamSocketDelegate OFUNIXStreamSocket.h \ + * ObjFW/OFUNIXStreamSocket.h + * + * A delegate for OFUNIXStreamSocket. + */ +@protocol OFUNIXStreamSocketDelegate +@end + +/** + * @class OFUNIXStreamSocket OFUNIXStreamSocket.h ObjFW/OFUNIXStreamSocket.h + * + * @brief A class which provides methods to create and use UNIX stream sockets. + * + * To connect to a server, create a socket and connect it. + * To create a server, create a socket, bind it and listen on it. + */ +@interface OFUNIXStreamSocket: OFStreamSocket +{ + OF_RESERVE_IVARS(OFUNIXStreamSocket, 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 Connects the OFUNIXStreamSocket to the specified destination. + * + * @param path The path to connect to + */ +- (void)connectToPath: (OFString *)path; + +/** + * @brief Binds the socket to the specified host and port. + * + * @param path The path to bind to + */ +- (void)bindToPath: (OFString *)path; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFUNIXStreamSocket.m Index: src/OFUNIXStreamSocket.m ================================================================== --- /dev/null +++ src/OFUNIXStreamSocket.m @@ -0,0 +1,109 @@ +/* + * 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" + +#ifdef HAVE_FCNTL_H +# include +#endif + +#import "OFUNIXStreamSocket.h" +#import "OFSocket.h" +#import "OFSocket+Private.h" +#import "OFString.h" + +#import "OFAlreadyConnectedException.h" +#import "OFBindFailedException.h" +#import "OFConnectionFailedException.h" + +@implementation OFUNIXStreamSocket +@dynamic delegate; + +- (void)connectToPath: (OFString *)path +{ + OFSocketAddress address; +#if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) + int flags; +#endif + + if (_socket != OFInvalidSocketHandle) + @throw [OFAlreadyConnectedException exceptionWithSocket: self]; + + address = OFSocketAddressMakeUNIX(path); + + if ((_socket = socket(address.sockaddr.sockaddr.sa_family, + SOCK_STREAM | SOCK_CLOEXEC, 0)) == OFInvalidSocketHandle) + @throw [OFConnectionFailedException + exceptionWithPath: path + socket: self + errNo: OFSocketErrNo()]; + + _canBlock = true; + +#if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) + if ((flags = fcntl(_socket, F_GETFD, 0)) != -1) + fcntl(_socket, F_SETFD, flags | FD_CLOEXEC); +#endif + + if (connect(_socket, &address.sockaddr.sockaddr, address.length) != 0) { + int errNo = OFSocketErrNo(); + + closesocket(_socket); + _socket = OFInvalidSocketHandle; + + @throw [OFConnectionFailedException exceptionWithPath: path + socket: self + errNo: errNo]; + } +} + +- (void)bindToPath: (OFString *)path +{ + OFSocketAddress address; +#if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) + int flags; +#endif + + if (_socket != OFInvalidSocketHandle) + @throw [OFAlreadyConnectedException exceptionWithSocket: self]; + + address = OFSocketAddressMakeUNIX(path); + + if ((_socket = socket(address.sockaddr.sockaddr.sa_family, + SOCK_STREAM | SOCK_CLOEXEC, 0)) == OFInvalidSocketHandle) + @throw [OFBindFailedException + exceptionWithPath: path + socket: self + errNo: OFSocketErrNo()]; + + _canBlock = true; + +#if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) + if ((flags = fcntl(_socket, F_GETFD, 0)) != -1) + fcntl(_socket, F_SETFD, flags | FD_CLOEXEC); +#endif + + if (bind(_socket, &address.sockaddr.sockaddr, address.length) != 0) { + int errNo = OFSocketErrNo(); + + closesocket(_socket); + _socket = OFInvalidSocketHandle; + + @throw [OFBindFailedException exceptionWithPath: path + socket: self + errNo: errNo]; + } +} +@end Index: src/OFURL.h ================================================================== --- src/OFURL.h +++ src/OFURL.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -133,12 +131,12 @@ * * For example, a query like `key1=value1&key2=value2` would correspond to the * following dictionary: * * @{ - * @"key1": "value1", - * @"key2": "value2" + * @"key1": @"value1", + * @"key2": @"value2" * } */ @property OF_NULLABLE_PROPERTY (readonly, copy, nonatomic) OFDictionary OF_GENERIC(OFString *, OFString *) *queryDictionary; @@ -157,11 +155,11 @@ * @brief The URL as a string. */ @property (readonly, nonatomic) OFString *string; /** - * @brief The URL with relative sub paths resolved. + * @brief The URL with relative subpaths resolved. */ @property (readonly, nonatomic) OFURL *URLByStandardizingPath; #ifdef OF_HAVE_FILES /** @@ -189,12 +187,11 @@ * * @param string A string describing a URL * @param URL An URL to which the string is relative * @return A new, autoreleased OFURL */ -+ (instancetype)URLWithString: (OFString *)string - relativeToURL: (OFURL *)URL; ++ (instancetype)URLWithString: (OFString *)string relativeToURL: (OFURL *)URL; #ifdef OF_HAVE_FILES /** * @brief Creates a new URL with the specified local file path. * @@ -232,12 +229,11 @@ * * @param string A string describing a URL * @param URL A URL to which the string is relative * @return An initialized OFURL */ -- (instancetype)initWithString: (OFString *)string - relativeToURL: (OFURL *)URL; +- (instancetype)initWithString: (OFString *)string relativeToURL: (OFURL *)URL; #ifdef OF_HAVE_FILES /** * @brief Initializes an already allocated OFURL with the specified local file * path. @@ -369,13 +365,14 @@ @end #ifdef __cplusplus extern "C" { #endif -extern bool of_url_is_ipv6_host(OFString *host); +extern bool OFURLIsIPv6Host(OFString *host); +extern void OFURLVerifyIsEscaped(OFString *, OFCharacterSet *); #ifdef __cplusplus } #endif OF_ASSUME_NONNULL_END #import "OFMutableURL.h" Index: src/OFURL.m ================================================================== --- src/OFURL.m +++ src/OFURL.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -21,25 +19,23 @@ #include #import "OFURL.h" #import "OFArray.h" #import "OFDictionary.h" -#import "OFNumber.h" -#import "OFString.h" -#import "OFXMLElement.h" - #ifdef OF_HAVE_FILES # import "OFFileManager.h" # import "OFFileURLHandler.h" #endif +#import "OFNumber.h" +#import "OFOnce.h" +#import "OFString.h" +#import "OFXMLElement.h" #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFOutOfMemoryException.h" -#import "once.h" - @interface OFURLAllowedCharacterSetBase: OFCharacterSet @end @interface OFURLAllowedCharacterSet: OFURLAllowedCharacterSetBase @end @@ -60,12 +56,13 @@ static OFCharacterSet *URLSchemeAllowedCharacterSet = nil; static OFCharacterSet *URLPathAllowedCharacterSet = nil; static OFCharacterSet *URLQueryOrFragmentAllowedCharacterSet = nil; static OFCharacterSet *URLQueryKeyValueAllowedCharacterSet = nil; -static of_once_t URLAllowedCharacterSetOnce = OF_ONCE_INIT; -static of_once_t URLQueryOrFragmentAllowedCharacterSetOnce = OF_ONCE_INIT; +static OFOnceControl URLAllowedCharacterSetOnce = OFOnceControlInitValue; +static OFOnceControl URLQueryOrFragmentAllowedCharacterSetOnce = + OFOnceControlInitValue; static void initURLAllowedCharacterSet(void) { URLAllowedCharacterSet = [[OFURLAllowedCharacterSet alloc] init]; @@ -101,24 +98,24 @@ OF_DIRECT_MEMBERS @interface OFInvertedCharacterSetWithoutPercent: OFCharacterSet { OFCharacterSet *_characterSet; - bool (*_characterIsMember)(id, SEL, of_unichar_t); + bool (*_characterIsMember)(id, SEL, OFUnichar); } - (instancetype)initWithCharacterSet: (OFCharacterSet *)characterSet; @end bool -of_url_is_ipv6_host(OFString *host) +OFURLIsIPv6Host(OFString *host) { const char *UTF8String = host.UTF8String; bool hasColon = false; while (*UTF8String != '\0') { - if (!of_ascii_isdigit(*UTF8String) && *UTF8String != ':' && + if (!OFASCIIIsDigit(*UTF8String) && *UTF8String != ':' && (*UTF8String < 'a' || *UTF8String > 'f') && (*UTF8String < 'A' || *UTF8String > 'F')) return false; if (*UTF8String == ':') @@ -145,18 +142,18 @@ { } - (unsigned int)retainCount { - return OF_RETAIN_COUNT_MAX; + return OFMaxRetainCount; } @end @implementation OFURLAllowedCharacterSet -- (bool)characterIsMember: (of_unichar_t)character +- (bool)characterIsMember: (OFUnichar)character { - if (character < CHAR_MAX && of_ascii_isalnum(character)) + if (character < CHAR_MAX && OFASCIIIsAlnum(character)) return true; switch (character) { case '-': case '.': @@ -179,13 +176,13 @@ } } @end @implementation OFURLSchemeAllowedCharacterSet -- (bool)characterIsMember: (of_unichar_t)character +- (bool)characterIsMember: (OFUnichar)character { - if (character < CHAR_MAX && of_ascii_isalnum(character)) + if (character < CHAR_MAX && OFASCIIIsAlnum(character)) return true; switch (character) { case '+': case '-': @@ -196,13 +193,13 @@ } } @end @implementation OFURLPathAllowedCharacterSet -- (bool)characterIsMember: (of_unichar_t)character +- (bool)characterIsMember: (OFUnichar)character { - if (character < CHAR_MAX && of_ascii_isalnum(character)) + if (character < CHAR_MAX && OFASCIIIsAlnum(character)) return true; switch (character) { case '-': case '.': @@ -228,13 +225,13 @@ } } @end @implementation OFURLQueryOrFragmentAllowedCharacterSet -- (bool)characterIsMember: (of_unichar_t)character +- (bool)characterIsMember: (OFUnichar)character { - if (character < CHAR_MAX && of_ascii_isalnum(character)) + if (character < CHAR_MAX && OFASCIIIsAlnum(character)) return true; switch (character) { case '-': case '.': @@ -261,13 +258,13 @@ } } @end @implementation OFURLQueryKeyValueAllowedCharacterSet -- (bool)characterIsMember: (of_unichar_t)character +- (bool)characterIsMember: (OFUnichar)character { - if (character < CHAR_MAX && of_ascii_isalnum(character)) + if (character < CHAR_MAX && OFASCIIIsAlnum(character)) return true; switch (character) { case '-': case '.': @@ -298,11 +295,11 @@ { self = [super init]; @try { _characterSet = [characterSet retain]; - _characterIsMember = (bool (*)(id, SEL, of_unichar_t)) + _characterIsMember = (bool (*)(id, SEL, OFUnichar)) [_characterSet methodForSelector: @selector(characterIsMember:)]; } @catch (id e) { [self release]; @throw e; @@ -316,88 +313,88 @@ [_characterSet release]; [super dealloc]; } -- (bool)characterIsMember: (of_unichar_t)character +- (bool)characterIsMember: (OFUnichar)character { return (character != '%' && !_characterIsMember(_characterSet, @selector(characterIsMember:), character)); } @end void -of_url_verify_escaped(OFString *string, OFCharacterSet *characterSet) +OFURLVerifyIsEscaped(OFString *string, OFCharacterSet *characterSet) { void *pool = objc_autoreleasePoolPush(); characterSet = [[[OFInvertedCharacterSetWithoutPercent alloc] initWithCharacterSet: characterSet] autorelease]; - if ([string indexOfCharacterFromSet: characterSet] != OF_NOT_FOUND) + if ([string indexOfCharacterFromSet: characterSet] != OFNotFound) @throw [OFInvalidFormatException exception]; objc_autoreleasePoolPop(pool); } @implementation OFCharacterSet (URLCharacterSets) + (OFCharacterSet *)URLSchemeAllowedCharacterSet { - static of_once_t onceControl = OF_ONCE_INIT; - of_once(&onceControl, initURLSchemeAllowedCharacterSet); + static OFOnceControl onceControl = OFOnceControlInitValue; + OFOnce(&onceControl, initURLSchemeAllowedCharacterSet); return URLSchemeAllowedCharacterSet; } + (OFCharacterSet *)URLHostAllowedCharacterSet { - of_once(&URLAllowedCharacterSetOnce, initURLAllowedCharacterSet); + OFOnce(&URLAllowedCharacterSetOnce, initURLAllowedCharacterSet); return URLAllowedCharacterSet; } + (OFCharacterSet *)URLUserAllowedCharacterSet { - of_once(&URLAllowedCharacterSetOnce, initURLAllowedCharacterSet); + OFOnce(&URLAllowedCharacterSetOnce, initURLAllowedCharacterSet); return URLAllowedCharacterSet; } + (OFCharacterSet *)URLPasswordAllowedCharacterSet { - of_once(&URLAllowedCharacterSetOnce, initURLAllowedCharacterSet); + OFOnce(&URLAllowedCharacterSetOnce, initURLAllowedCharacterSet); return URLAllowedCharacterSet; } + (OFCharacterSet *)URLPathAllowedCharacterSet { - static of_once_t onceControl = OF_ONCE_INIT; - of_once(&onceControl, initURLPathAllowedCharacterSet); + static OFOnceControl onceControl = OFOnceControlInitValue; + OFOnce(&onceControl, initURLPathAllowedCharacterSet); return URLPathAllowedCharacterSet; } + (OFCharacterSet *)URLQueryAllowedCharacterSet { - of_once(&URLQueryOrFragmentAllowedCharacterSetOnce, + OFOnce(&URLQueryOrFragmentAllowedCharacterSetOnce, initURLQueryOrFragmentAllowedCharacterSet); return URLQueryOrFragmentAllowedCharacterSet; } + (OFCharacterSet *)URLQueryKeyValueAllowedCharacterSet { - static of_once_t onceControl = OF_ONCE_INIT; - of_once(&onceControl, initURLQueryKeyValueAllowedCharacterSet); + static OFOnceControl onceControl = OFOnceControlInitValue; + OFOnce(&onceControl, initURLQueryKeyValueAllowedCharacterSet); return URLQueryKeyValueAllowedCharacterSet; } + (OFCharacterSet *)URLFragmentAllowedCharacterSet { - of_once(&URLQueryOrFragmentAllowedCharacterSetOnce, + OFOnce(&URLQueryOrFragmentAllowedCharacterSetOnce, initURLQueryOrFragmentAllowedCharacterSet); return URLQueryOrFragmentAllowedCharacterSet; } @end @@ -443,31 +440,26 @@ @try { void *pool = objc_autoreleasePoolPush(); char *tmp, *tmp2; bool isIPv6Host = false; - if ((UTF8String2 = of_strdup(string.UTF8String)) == NULL) - @throw [OFOutOfMemoryException - exceptionWithRequestedSize: - string.UTF8StringLength]; - - UTF8String = UTF8String2; + UTF8String = UTF8String2 = OFStrDup(string.UTF8String); if ((tmp = strchr(UTF8String, ':')) == NULL) @throw [OFInvalidFormatException exception]; if (strncmp(tmp, "://", 3) != 0) @throw [OFInvalidFormatException exception]; for (tmp2 = UTF8String; tmp2 < tmp; tmp2++) - *tmp2 = of_ascii_tolower(*tmp2); + *tmp2 = OFASCIIToLower(*tmp2); _URLEncodedScheme = [[OFString alloc] initWithUTF8String: UTF8String length: tmp - UTF8String]; - of_url_verify_escaped(_URLEncodedScheme, + OFURLVerifyIsEscaped(_URLEncodedScheme, [OFCharacterSet URLSchemeAllowedCharacterSet]); UTF8String = tmp + 3; if ((tmp = strchr(UTF8String, '/')) != NULL) { @@ -488,27 +480,27 @@ _URLEncodedUser = [[OFString alloc] initWithUTF8String: UTF8String]; _URLEncodedPassword = [[OFString alloc] initWithUTF8String: tmp3]; - of_url_verify_escaped(_URLEncodedPassword, + OFURLVerifyIsEscaped(_URLEncodedPassword, [OFCharacterSet URLPasswordAllowedCharacterSet]); } else _URLEncodedUser = [[OFString alloc] initWithUTF8String: UTF8String]; - of_url_verify_escaped(_URLEncodedUser, + OFURLVerifyIsEscaped(_URLEncodedUser, [OFCharacterSet URLUserAllowedCharacterSet]); UTF8String = tmp2; } if (UTF8String[0] == '[') { tmp2 = UTF8String++; - while (of_ascii_isdigit(*UTF8String) || + while (OFASCIIIsDigit(*UTF8String) || *UTF8String == ':' || (*UTF8String >= 'a' && *UTF8String <= 'f') || (*UTF8String >= 'A' && *UTF8String <= 'F')) UTF8String++; @@ -525,11 +517,11 @@ OFString *portString; tmp2 = ++UTF8String; while (*UTF8String != '\0') { - if (!of_ascii_isdigit(*UTF8String)) + if (!OFASCIIIsDigit(*UTF8String)) @throw [OFInvalidFormatException exception]; UTF8String++; } @@ -568,21 +560,21 @@ } else _URLEncodedHost = [[OFString alloc] initWithUTF8String: UTF8String]; if (!isIPv6Host) - of_url_verify_escaped(_URLEncodedHost, + OFURLVerifyIsEscaped(_URLEncodedHost, [OFCharacterSet URLHostAllowedCharacterSet]); if ((UTF8String = tmp) != NULL) { if ((tmp = strchr(UTF8String, '#')) != NULL) { *tmp = '\0'; _URLEncodedFragment = [[OFString alloc] initWithUTF8String: tmp + 1]; - of_url_verify_escaped(_URLEncodedFragment, + OFURLVerifyIsEscaped(_URLEncodedFragment, [OFCharacterSet URLFragmentAllowedCharacterSet]); } if ((tmp = strchr(UTF8String, '?')) != NULL) { @@ -589,38 +581,54 @@ *tmp = '\0'; _URLEncodedQuery = [[OFString alloc] initWithUTF8String: tmp + 1]; - of_url_verify_escaped(_URLEncodedQuery, + OFURLVerifyIsEscaped(_URLEncodedQuery, [OFCharacterSet URLQueryAllowedCharacterSet]); } + /* + * Some versions of GCC issue a false-positive warning + * (turned error) about a string overflow. This is a + * false positive because UTF8String is set to tmp + * above and tmp is either NULL or points *after* the + * slash for the path. So all we do here is go back to + * that slash and restore it. + */ +#if OF_GCC_VERSION >= 402 +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wpragmas" +# pragma GCC diagnostic ignored "-Wunknown-warning-option" +# pragma GCC diagnostic ignored "-Wstringop-overflow" +#endif UTF8String--; *UTF8String = '/'; +#if OF_GCC_VERSION >= 402 +# pragma GCC diagnostic pop +#endif _URLEncodedPath = [[OFString alloc] initWithUTF8String: UTF8String]; - of_url_verify_escaped(_URLEncodedPath, + OFURLVerifyIsEscaped(_URLEncodedPath, [OFCharacterSet URLPathAllowedCharacterSet]); } objc_autoreleasePoolPop(pool); } @catch (id e) { [self release]; @throw e; } @finally { - free(UTF8String2); + OFFreeMemory(UTF8String2); } return self; } -- (instancetype)initWithString: (OFString *)string - relativeToURL: (OFURL *)URL +- (instancetype)initWithString: (OFString *)string relativeToURL: (OFURL *)URL { char *UTF8String, *UTF8String2 = NULL; if ([string containsString: @"://"]) return [self initWithString: string]; @@ -635,32 +643,27 @@ _URLEncodedHost = [URL->_URLEncodedHost copy]; _port = [URL->_port copy]; _URLEncodedUser = [URL->_URLEncodedUser copy]; _URLEncodedPassword = [URL->_URLEncodedPassword copy]; - if ((UTF8String2 = of_strdup(string.UTF8String)) == NULL) - @throw [OFOutOfMemoryException - exceptionWithRequestedSize: - string.UTF8StringLength]; - - UTF8String = UTF8String2; + UTF8String = UTF8String2 = OFStrDup(string.UTF8String); if ((tmp = strchr(UTF8String, '#')) != NULL) { *tmp = '\0'; _URLEncodedFragment = [[OFString alloc] initWithUTF8String: tmp + 1]; - of_url_verify_escaped(_URLEncodedFragment, + OFURLVerifyIsEscaped(_URLEncodedFragment, [OFCharacterSet URLFragmentAllowedCharacterSet]); } if ((tmp = strchr(UTF8String, '?')) != NULL) { *tmp = '\0'; _URLEncodedQuery = [[OFString alloc] initWithUTF8String: tmp + 1]; - of_url_verify_escaped(_URLEncodedQuery, + OFURLVerifyIsEscaped(_URLEncodedQuery, [OFCharacterSet URLQueryAllowedCharacterSet]); } if (*UTF8String == '/') _URLEncodedPath = [[OFString alloc] @@ -677,15 +680,15 @@ OFMutableString *path = [OFMutableString stringWithString: (URL->_URLEncodedPath != nil ? URL->_URLEncodedPath : @"/")]; - of_range_t range = [path + OFRange range = [path rangeOfString: @"/" - options: OF_STRING_SEARCH_BACKWARDS]; + options: OFStringSearchBackwards]; - if (range.location == OF_NOT_FOUND) + if (range.location == OFNotFound) @throw [OFInvalidFormatException exception]; range.location++; range.length = path.length - range.location; @@ -696,19 +699,19 @@ _URLEncodedPath = [path copy]; } } - of_url_verify_escaped(_URLEncodedPath, + OFURLVerifyIsEscaped(_URLEncodedPath, [OFCharacterSet URLPathAllowedCharacterSet]); objc_autoreleasePoolPop(pool); } @catch (id e) { [self release]; @throw e; } @finally { - free(UTF8String2); + OFFreeMemory(UTF8String2); } return self; } @@ -717,21 +720,18 @@ { bool isDirectory; @try { void *pool = objc_autoreleasePoolPush(); - isDirectory = [path of_isDirectoryPath]; - objc_autoreleasePoolPop(pool); } @catch (id e) { [self release]; @throw e; } - self = [self initFileURLWithPath: path - isDirectory: isDirectory]; + self = [self initFileURLWithPath: path isDirectory: isDirectory]; return self; } - (instancetype)initFileURLWithPath: (OFString *)path @@ -779,11 +779,11 @@ void *pool = objc_autoreleasePoolPush(); OFString *stringValue; @try { if (![element.name isEqual: self.className] || - ![element.namespace isEqual: OF_SERIALIZATION_NS]) + ![element.namespace isEqual: OFSerializationNS]) @throw [OFInvalidArgumentException exception]; stringValue = element.stringValue; } @catch (id e) { [self release]; @@ -850,24 +850,24 @@ return true; } - (unsigned long)hash { - uint32_t hash; - - OF_HASH_INIT(hash); - - OF_HASH_ADD_HASH(hash, _URLEncodedScheme.hash); - OF_HASH_ADD_HASH(hash, _URLEncodedHost.hash); - OF_HASH_ADD_HASH(hash, _port.hash); - OF_HASH_ADD_HASH(hash, _URLEncodedUser.hash); - OF_HASH_ADD_HASH(hash, _URLEncodedPassword.hash); - OF_HASH_ADD_HASH(hash, _URLEncodedPath.hash); - OF_HASH_ADD_HASH(hash, _URLEncodedQuery.hash); - OF_HASH_ADD_HASH(hash, _URLEncodedFragment.hash); - - OF_HASH_FINALIZE(hash); + unsigned long hash; + + OFHashInit(&hash); + + OFHashAddHash(&hash, _URLEncodedScheme.hash); + OFHashAddHash(&hash, _URLEncodedHost.hash); + OFHashAddHash(&hash, _port.hash); + OFHashAddHash(&hash, _URLEncodedUser.hash); + OFHashAddHash(&hash, _URLEncodedPassword.hash); + OFHashAddHash(&hash, _URLEncodedPath.hash); + OFHashAddHash(&hash, _URLEncodedQuery.hash); + OFHashAddHash(&hash, _URLEncodedFragment.hash); + + OFHashFinalize(&hash); return hash; } - (OFString *)scheme @@ -883,13 +883,13 @@ - (OFString *)host { if ([_URLEncodedHost hasPrefix: @"["] && [_URLEncodedHost hasSuffix: @"]"]) { OFString *host = [_URLEncodedHost substringWithRange: - of_range(1, _URLEncodedHost.length - 2)]; + OFRangeMake(1, _URLEncodedHost.length - 2)]; - if (!of_url_is_ipv6_host(host)) + if (!OFURLIsIPv6Host(host)) @throw [OFInvalidArgumentException exception]; return host; } @@ -950,22 +950,20 @@ OFString *path = [_URLEncodedPath of_URLPathToPathWithURLEncodedHost: nil]; ret = [[path.pathComponents mutableCopy] autorelease]; if (![ret.firstObject isEqual: @"/"]) - [ret insertObject: @"/" - atIndex: 0]; + [ret insertObject: @"/" atIndex: 0]; } else #endif ret = [[[_URLEncodedPath componentsSeparatedByString: @"/"] mutableCopy] autorelease]; count = ret.count; if (count > 0 && [ret.firstObject length] == 0) - [ret replaceObjectAtIndex: 0 - withObject: @"/"]; + [ret replaceObjectAtIndex: 0 withObject: @"/"]; for (size_t i = 0; i < count; i++) { OFString *component = [ret objectAtIndex: i]; #ifdef OF_HAVE_FILES @@ -1162,36 +1160,29 @@ #endif - (OFURL *)URLByAppendingPathComponent: (OFString *)component { OFMutableURL *URL = [[self mutableCopy] autorelease]; - [URL appendPathComponent: component]; [URL makeImmutable]; - return URL; } - (OFURL *)URLByAppendingPathComponent: (OFString *)component isDirectory: (bool)isDirectory { OFMutableURL *URL = [[self mutableCopy] autorelease]; - - [URL appendPathComponent: component - isDirectory: isDirectory]; + [URL appendPathComponent: component isDirectory: isDirectory]; [URL makeImmutable]; - return URL; } - (OFURL *)URLByStandardizingPath { OFMutableURL *URL = [[self mutableCopy] autorelease]; - [URL standardizePath]; [URL makeImmutable]; - return URL; } - (OFString *)description { @@ -1203,15 +1194,15 @@ { void *pool = objc_autoreleasePoolPush(); OFXMLElement *element; element = [OFXMLElement elementWithName: self.className - namespace: OF_SERIALIZATION_NS + namespace: OFSerializationNS stringValue: self.string]; [element retain]; objc_autoreleasePoolPop(pool); return [element autorelease]; } @end Index: src/OFURLHandler.h ================================================================== --- src/OFURLHandler.h +++ src/OFURLHandler.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -51,12 +49,11 @@ * @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; ++ (bool)registerClass: (Class)class_ forScheme: (OFString *)scheme; /** * @brief Returns the handler for the specified URL. * * @return The handler for the specified URL. @@ -92,32 +89,30 @@ * `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. */ -- (OFStream *)openItemAtURL: (OFURL *)URL - mode: (OFString *)mode; +- (OFStream *)openItemAtURL: (OFURL *)URL mode: (OFString *)mode; /** * @brief Returns the attributes for the item at the specified URL. * * @param URL The URL to return the attributes for * @return A dictionary of attributes for the specified URL, with the keys of - * type @ref of_file_attribute_key_t + * type @ref OFFileAttributeKey */ -- (of_file_attributes_t)attributesOfItemAtURL: (OFURL *)URL; +- (OFFileAttributes)attributesOfItemAtURL: (OFURL *)URL; /** * @brief Sets the attributes for the item at the specified URL. * * All attributes not part of the dictionary are left unchanged. * * @param attributes The attributes to set for the specified URL * @param URL The URL of the item to set the attributes for */ -- (void)setAttributes: (of_file_attributes_t)attributes - ofItemAtURL: (OFURL *)URL; +- (void)setAttributes: (OFFileAttributes)attributes ofItemAtURL: (OFURL *)URL; /** * @brief Checks whether a file exists at the specified URL. * * @param URL The URL to check @@ -139,18 +134,19 @@ * @param URL The URL of the directory to create */ - (void)createDirectoryAtURL: (OFURL *)URL; /** - * @brief Returns an array with the items in the specified directory. + * @brief Returns an array with the URLs of the items in the specified + * directory. * * @note `.` and `..` are not part of the returned array. * * @param URL The URL to the directory whose items should be returned - * @return An array of OFString with the items in the specified directory + * @return An array with the URLs of the items in the specified directory */ -- (OFArray OF_GENERIC(OFString *) *)contentsOfDirectoryAtURL: (OFURL *)URL; +- (OFArray OF_GENERIC(OFURL *) *)contentsOfDirectoryAtURL: (OFURL *)URL; /** * @brief Removes the item at the specified URL. * * If the item at the specified URL is a directory, it is removed recursively. @@ -168,12 +164,11 @@ * This method is not available for all URLs. * * @param source The URL to the item for which a link should be created * @param destination The URL to the item which should link to the source */ -- (void)linkItemAtURL: (OFURL *)source - toURL: (OFURL *)destination; +- (void)linkItemAtURL: (OFURL *)source toURL: (OFURL *)destination; /** * @brief Creates a symbolic link for an item. * * The destination uRL must have a full path, which means it must include the @@ -205,12 +200,11 @@ * @param destination The destination URL * @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)copyItemAtURL: (OFURL *)source - toURL: (OFURL *)destination; +- (bool)copyItemAtURL: (OFURL *)source toURL: (OFURL *)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. * @@ -224,10 +218,9 @@ * @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)moveItemAtURL: (OFURL *)source - toURL: (OFURL *)destination; +- (bool)moveItemAtURL: (OFURL *)source toURL: (OFURL *)destination; @end OF_ASSUME_NONNULL_END Index: src/OFURLHandler.m ================================================================== --- src/OFURLHandler.m +++ src/OFURLHandler.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -34,10 +32,16 @@ #endif static OFMutableDictionary OF_GENERIC(OFString *, OFURLHandler *) *handlers; #ifdef OF_HAVE_THREADS static OFMutex *mutex; + +static void +releaseMutex(void) +{ + [mutex release]; +} #endif @implementation OFURLHandler @synthesize scheme = _scheme; @@ -47,26 +51,23 @@ return; handlers = [[OFMutableDictionary alloc] init]; #ifdef OF_HAVE_THREADS mutex = [[OFMutex alloc] init]; + atexit(releaseMutex); #endif #ifdef OF_HAVE_FILES - [self registerClass: [OFFileURLHandler class] - forScheme: @"file"]; + [self registerClass: [OFFileURLHandler class] forScheme: @"file"]; #endif #if defined(OF_HAVE_SOCKETS) && defined(OF_HAVE_THREADS) - [self registerClass: [OFHTTPURLHandler class] - forScheme: @"http"]; - [self registerClass: [OFHTTPURLHandler class] - forScheme: @"https"]; + [self registerClass: [OFHTTPURLHandler class] forScheme: @"http"]; + [self registerClass: [OFHTTPURLHandler class] forScheme: @"https"]; #endif } -+ (bool)registerClass: (Class)class - forScheme: (OFString *)scheme ++ (bool)registerClass: (Class)class forScheme: (OFString *)scheme { #ifdef OF_HAVE_THREADS [mutex lock]; @try { #endif @@ -75,12 +76,11 @@ if ([handlers objectForKey: scheme] != nil) return false; handler = [[class alloc] initWithScheme: scheme]; @try { - [handlers setObject: handler - forKey: scheme]; + [handlers setObject: handler forKey: scheme]; } @finally { [handler release]; } #ifdef OF_HAVE_THREADS } @finally { @@ -133,23 +133,21 @@ [_scheme release]; [super dealloc]; } -- (OFStream *)openItemAtURL: (OFURL *)URL - mode: (OFString *)mode +- (OFStream *)openItemAtURL: (OFURL *)URL mode: (OFString *)mode { OF_UNRECOGNIZED_SELECTOR } -- (of_file_attributes_t)attributesOfItemAtURL: (OFURL *)URL +- (OFFileAttributes)attributesOfItemAtURL: (OFURL *)URL { OF_UNRECOGNIZED_SELECTOR } -- (void)setAttributes: (of_file_attributes_t)attributes - ofItemAtURL: (OFURL *)URL +- (void)setAttributes: (OFFileAttributes)attributes ofItemAtURL: (OFURL *)URL { OF_UNRECOGNIZED_SELECTOR } - (bool)fileExistsAtURL: (OFURL *)URL @@ -165,22 +163,21 @@ - (void)createDirectoryAtURL: (OFURL *)URL { OF_UNRECOGNIZED_SELECTOR } -- (OFArray OF_GENERIC(OFString *) *)contentsOfDirectoryAtURL: (OFURL *)URL +- (OFArray OF_GENERIC(OFURL *) *)contentsOfDirectoryAtURL: (OFURL *)URL { OF_UNRECOGNIZED_SELECTOR } - (void)removeItemAtURL: (OFURL *)URL { OF_UNRECOGNIZED_SELECTOR } -- (void)linkItemAtURL: (OFURL *)source - toURL: (OFURL *)destination +- (void)linkItemAtURL: (OFURL *)source toURL: (OFURL *)destination { OF_UNRECOGNIZED_SELECTOR } - (void)createSymbolicLinkAtURL: (OFURL *)destination @@ -187,17 +184,15 @@ withDestinationPath: (OFString *)source { OF_UNRECOGNIZED_SELECTOR } -- (bool)copyItemAtURL: (OFURL *)source - toURL: (OFURL *)destination +- (bool)copyItemAtURL: (OFURL *)source toURL: (OFURL *)destination { return false; } -- (bool)moveItemAtURL: (OFURL *)source - toURL: (OFURL *)destination +- (bool)moveItemAtURL: (OFURL *)source toURL: (OFURL *)destination { return false; } @end Index: src/OFUTF8String+Private.h ================================================================== --- src/OFUTF8String+Private.h +++ src/OFUTF8String+Private.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFUTF8String.h ================================================================== --- src/OFUTF8String.h +++ src/OFUTF8String.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -26,29 +24,28 @@ * * Since constant strings don't have `_storage`, they have to allocate * it on the first access. Strings created at runtime just set the * pointer to `&_storage`. */ - struct of_string_utf8_ivars { + struct OFUTF8StringIvars { char *cString; size_t cStringLength; bool isUTF8; size_t length; - bool hashed; + bool hasHash; unsigned long hash; - char *_Nullable freeWhenDone; + bool freeWhenDone; } *restrict _s; - struct of_string_utf8_ivars _storage; + struct OFUTF8StringIvars _storage; } @end #ifdef __cplusplus extern "C" { #endif -extern int of_string_utf8_check(const char *, size_t, size_t *); -extern size_t of_string_utf8_get_index(const char *, size_t); -extern size_t of_string_utf8_get_position(const char *, size_t, size_t); +extern int OFUTF8StringCheck(const char *, size_t, size_t *); +extern size_t OFUTF8StringIndexToPosition(const char *, size_t, size_t); #ifdef __cplusplus } #endif OF_ASSUME_NONNULL_END Index: src/OFUTF8String.m ================================================================== --- src/OFUTF8String.m +++ src/OFUTF8String.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -25,67 +23,68 @@ # include #endif #import "OFUTF8String.h" #import "OFUTF8String+Private.h" +#import "OFASPrintF.h" #import "OFArray.h" +#import "OFData.h" #import "OFMutableUTF8String.h" #import "OFInitializationFailedException.h" #import "OFInvalidArgumentException.h" #import "OFInvalidEncodingException.h" #import "OFInvalidFormatException.h" #import "OFOutOfMemoryException.h" #import "OFOutOfRangeException.h" -#import "of_asprintf.h" #import "unicode.h" -extern const of_char16_t of_iso_8859_2_table[]; -extern const size_t of_iso_8859_2_table_offset; -extern const of_char16_t of_iso_8859_3_table[]; -extern const size_t of_iso_8859_3_table_offset; -extern const of_char16_t of_iso_8859_15_table[]; -extern const size_t of_iso_8859_15_table_offset; -extern const of_char16_t of_windows_1251_table[]; -extern const size_t of_windows_1251_table_offset; -extern const of_char16_t of_windows_1252_table[]; -extern const size_t of_windows_1252_table_offset; -extern const of_char16_t of_codepage_437_table[]; -extern const size_t of_codepage_437_table_offset; -extern const of_char16_t of_codepage_850_table[]; -extern const size_t of_codepage_850_table_offset; -extern const of_char16_t of_codepage_858_table[]; -extern const size_t of_codepage_858_table_offset; -extern const of_char16_t of_mac_roman_table[]; -extern const size_t of_mac_roman_table_offset; -extern const of_char16_t of_koi8_r_table[]; -extern const size_t of_koi8_r_table_offset; -extern const of_char16_t of_koi8_u_table[]; -extern const size_t of_koi8_u_table_offset; +extern const OFChar16 OFISO8859_2Table[]; +extern const size_t OFISO8859_2TableOffset; +extern const OFChar16 OFISO8859_3Table[]; +extern const size_t OFISO8859_3TableOffset; +extern const OFChar16 OFISO8859_15Table[]; +extern const size_t OFISO8859_15TableOffset; +extern const OFChar16 OFWindows1251Table[]; +extern const size_t OFWindows1251TableOffset; +extern const OFChar16 OFWindows1252Table[]; +extern const size_t OFWindows1252TableOffset; +extern const OFChar16 OFCodepage437Table[]; +extern const size_t OFCodepage437TableOffset; +extern const OFChar16 OFCodepage850Table[]; +extern const size_t OFCodepage850TableOffset; +extern const OFChar16 OFCodepage858Table[]; +extern const size_t OFCodepage858TableOffset; +extern const OFChar16 OFMacRomanTable[]; +extern const size_t OFMacRomanTableOffset; +extern const OFChar16 OFKOI8RTable[]; +extern const size_t OFKOI8RTableOffset; +extern const OFChar16 OFKOI8UTable[]; +extern const size_t OFKOI8UTableOffset; static inline int memcasecmp(const char *first, const char *second, size_t length) { for (size_t i = 0; i < length; i++) { unsigned char f = first[i]; unsigned char s = second[i]; - f = of_ascii_toupper(f); - s = of_ascii_toupper(s); + f = OFASCIIToUpper(f); + s = OFASCIIToUpper(s); if (f > s) - return OF_ORDERED_DESCENDING; + return OFOrderedDescending; if (f < s) - return OF_ORDERED_ASCENDING; + return OFOrderedAscending; } - return OF_ORDERED_SAME; + return OFOrderedSame; } int -of_string_utf8_check(const char *UTF8String, size_t UTF8Length, size_t *length) +OFUTF8StringCheck(const char *UTF8String, size_t UTF8Length, size_t *length) { size_t tmpLength = UTF8Length; int isUTF8 = 0; for (size_t i = 0; i < UTF8Length; i++) { @@ -148,11 +147,11 @@ return isUTF8; } size_t -of_string_utf8_get_index(const char *string, size_t position) +positionToIndex(const char *string, size_t position) { size_t idx = position; for (size_t i = 0; i < position; i++) if OF_UNLIKELY ((string[i] & 0xC0) == 0x80) @@ -160,11 +159,11 @@ return idx; } size_t -of_string_utf8_get_position(const char *string, size_t idx, size_t length) +OFUTF8StringIndexToPosition(const char *string, size_t idx, size_t length) { for (size_t i = 0; i <= idx; i++) if OF_UNLIKELY ((string[i] & 0xC0) == 0x80) if (++idx > length) @throw [OFInvalidFormatException exception]; @@ -178,12 +177,12 @@ self = [super init]; @try { _s = &_storage; - _s->cString = [self allocMemoryWithSize: 1]; - _s->cString[0] = '\0'; + _s->cString = OFAllocZeroedMemory(1, 1); + _s->freeWhenDone = true; } @catch (id e) { [self release]; @throw e; } @@ -206,11 +205,11 @@ _s = &_storage; _s->cString = storage; _s->cStringLength = UTF8StringLength; - switch (of_string_utf8_check(UTF8String, UTF8StringLength, + switch (OFUTF8StringCheck(UTF8String, UTF8StringLength, &_s->length)) { case 1: _s->isUTF8 = true; break; case -1: @@ -226,37 +225,38 @@ return self; } - (instancetype)initWithCString: (const char *)cString - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding length: (size_t)cStringLength { self = [super init]; @try { - const of_char16_t *table; + const OFChar16 *table; size_t tableOffset, j; - if (encoding == OF_STRING_ENCODING_UTF_8 && + if (encoding == OFStringEncodingUTF8 && cStringLength >= 3 && memcmp(cString, "\xEF\xBB\xBF", 3) == 0) { cString += 3; cStringLength -= 3; } _s = &_storage; - _s->cString = [self allocMemoryWithSize: cStringLength + 1]; + _s->cString = OFAllocMemory(cStringLength + 1, 1); _s->cStringLength = cStringLength; + _s->freeWhenDone = true; - if (encoding == OF_STRING_ENCODING_UTF_8 || - encoding == OF_STRING_ENCODING_ASCII) { - switch (of_string_utf8_check(cString, cStringLength, + if (encoding == OFStringEncodingUTF8 || + encoding == OFStringEncodingASCII) { + switch (OFUTF8StringCheck(cString, cStringLength, &_s->length)) { case 1: - if (encoding == OF_STRING_ENCODING_ASCII) + if (encoding == OFStringEncodingASCII) @throw [OFInvalidEncodingException exception]; _s->isUTF8 = true; break; @@ -271,11 +271,11 @@ } /* All other encodings we support are single byte encodings */ _s->length = cStringLength; - if (encoding == OF_STRING_ENCODING_ISO_8859_1) { + if (encoding == OFStringEncodingISO8859_1) { j = 0; for (size_t i = 0; i < cStringLength; i++) { char buffer[4]; size_t bytes; @@ -283,21 +283,20 @@ _s->cString[j++] = cString[i]; continue; } _s->isUTF8 = true; - bytes = of_string_utf8_encode( + bytes = OFUTF8StringEncode( (uint8_t)cString[i], buffer); if (bytes == 0) @throw [OFInvalidEncodingException exception]; _s->cStringLength += bytes - 1; - _s->cString = [self - resizeMemory: _s->cString - size: _s->cStringLength + 1]; + _s->cString = OFResizeMemory(_s->cString, + _s->cStringLength + 1, 1); memcpy(_s->cString + j, buffer, bytes); j += bytes; } @@ -305,57 +304,57 @@ return self; } switch (encoding) { -#define CASE(encoding, var) \ - case encoding: \ - table = var; \ - tableOffset = var##_offset; \ - break; +#define CASE(encoding, var) \ + case encoding: \ + table = var; \ + tableOffset = var##Offset; \ + break; #ifdef HAVE_ISO_8859_2 - CASE(OF_STRING_ENCODING_ISO_8859_2, of_iso_8859_2_table) + CASE(OFStringEncodingISO8859_2, OFISO8859_2Table) #endif #ifdef HAVE_ISO_8859_3 - CASE(OF_STRING_ENCODING_ISO_8859_3, of_iso_8859_3_table) + CASE(OFStringEncodingISO8859_3, OFISO8859_3Table) #endif #ifdef HAVE_ISO_8859_15 - CASE(OF_STRING_ENCODING_ISO_8859_15, of_iso_8859_15_table) + CASE(OFStringEncodingISO8859_15, OFISO8859_15Table) #endif #ifdef HAVE_WINDOWS_1251 - CASE(OF_STRING_ENCODING_WINDOWS_1251, of_windows_1251_table) + CASE(OFStringEncodingWindows1251, OFWindows1251Table) #endif #ifdef HAVE_WINDOWS_1252 - CASE(OF_STRING_ENCODING_WINDOWS_1252, of_windows_1252_table) + CASE(OFStringEncodingWindows1252, OFWindows1252Table) #endif #ifdef HAVE_CODEPAGE_437 - CASE(OF_STRING_ENCODING_CODEPAGE_437, of_codepage_437_table) + CASE(OFStringEncodingCodepage437, OFCodepage437Table) #endif #ifdef HAVE_CODEPAGE_850 - CASE(OF_STRING_ENCODING_CODEPAGE_850, of_codepage_850_table) + CASE(OFStringEncodingCodepage850, OFCodepage850Table) #endif #ifdef HAVE_CODEPAGE_858 - CASE(OF_STRING_ENCODING_CODEPAGE_858, of_codepage_858_table) + CASE(OFStringEncodingCodepage858, OFCodepage858Table) #endif #ifdef HAVE_MAC_ROMAN - CASE(OF_STRING_ENCODING_MAC_ROMAN, of_mac_roman_table) + CASE(OFStringEncodingMacRoman, OFMacRomanTable) #endif #ifdef HAVE_KOI8_R - CASE(OF_STRING_ENCODING_KOI8_R, of_koi8_r_table) + CASE(OFStringEncodingKOI8R, OFKOI8RTable) #endif #ifdef HAVE_KOI8_U - CASE(OF_STRING_ENCODING_KOI8_U, of_koi8_u_table) + CASE(OFStringEncodingKOI8U, OFKOI8UTable) #endif #undef CASE default: @throw [OFInvalidEncodingException exception]; } j = 0; for (size_t i = 0; i < cStringLength; i++) { unsigned char character = (unsigned char)cString[i]; - of_unichar_t unichar; + OFUnichar unichar; char buffer[4]; size_t byteLength; if (character < tableOffset) { _s->cString[j++] = cString[i]; @@ -366,19 +365,18 @@ if (unichar == 0xFFFF) @throw [OFInvalidEncodingException exception]; _s->isUTF8 = true; - byteLength = of_string_utf8_encode(unichar, buffer); + byteLength = OFUTF8StringEncode(unichar, buffer); if (byteLength == 0) @throw [OFInvalidEncodingException exception]; _s->cStringLength += byteLength - 1; - _s->cString = [self - resizeMemory: _s->cString - size: _s->cStringLength + 1]; + _s->cString = OFResizeMemory(_s->cString, + _s->cStringLength + 1, 1); memcpy(_s->cString + j, buffer, byteLength); j += byteLength; } @@ -402,41 +400,33 @@ - (instancetype)initWithUTF8StringNoCopy: (char *)UTF8String length: (size_t)UTF8StringLength freeWhenDone: (bool)freeWhenDone { - @try { - self = [super init]; - } @catch (id e) { - if (freeWhenDone) - free(UTF8String); - @throw e; - } + self = [super init]; @try { _s = &_storage; - if (freeWhenDone) - _s->freeWhenDone = UTF8String; - if (UTF8StringLength >= 3 && memcmp(UTF8String, "\xEF\xBB\xBF", 3) == 0) { UTF8String += 3; UTF8StringLength -= 3; } - _s->cString = (char *)UTF8String; - _s->cStringLength = UTF8StringLength; - - switch (of_string_utf8_check(UTF8String, UTF8StringLength, + switch (OFUTF8StringCheck(UTF8String, UTF8StringLength, &_s->length)) { case 1: _s->isUTF8 = true; break; case -1: @throw [OFInvalidEncodingException exception]; } + + _s->cString = (char *)UTF8String; + _s->cStringLength = UTF8StringLength; + _s->freeWhenDone = freeWhenDone; } @catch (id e) { [self release]; @throw e; } @@ -458,36 +448,38 @@ else _s->isUTF8 = true; _s->length = string.length; - _s->cString = [self allocMemoryWithSize: _s->cStringLength + 1]; + _s->cString = OFAllocMemory(_s->cStringLength + 1, 1); memcpy(_s->cString, string.UTF8String, _s->cStringLength + 1); + _s->freeWhenDone = true; } @catch (id e) { [self release]; @throw e; } return self; } -- (instancetype)initWithCharacters: (const of_unichar_t *)characters +- (instancetype)initWithCharacters: (const OFUnichar *)characters length: (size_t)length { self = [super init]; @try { size_t j; _s = &_storage; - _s->cString = [self allocMemoryWithSize: (length * 4) + 1]; + _s->cString = OFAllocMemory((length * 4) + 1, 1); _s->length = length; + _s->freeWhenDone = true; j = 0; for (size_t i = 0; i < length; i++) { - size_t len = of_string_utf8_encode(characters[i], + size_t len = OFUTF8StringEncode(characters[i], _s->cString + j); if (len == 0) @throw [OFInvalidEncodingException exception]; @@ -499,12 +491,11 @@ _s->cString[j] = '\0'; _s->cStringLength = j; @try { - _s->cString = [self resizeMemory: _s->cString - size: j + 1]; + _s->cString = OFResizeMemory(_s->cString, j + 1, 1); } @catch (OFOutOfMemoryException *e) { /* We don't care, as we only tried to make it smaller */ } } @catch (id e) { [self release]; @@ -512,13 +503,13 @@ } return self; } -- (instancetype)initWithUTF16String: (const of_char16_t *)string +- (instancetype)initWithUTF16String: (const OFChar16 *)string length: (size_t)length - byteOrder: (of_byte_order_t)byteOrder + byteOrder: (OFByteOrder)byteOrder { self = [super init]; @try { size_t j; @@ -529,37 +520,38 @@ length--; } else if (length > 0 && *string == 0xFFFE) { swap = true; string++; length--; - } else if (byteOrder != OF_BYTE_ORDER_NATIVE) + } else if (byteOrder != OFByteOrderNative) swap = true; _s = &_storage; - _s->cString = [self allocMemoryWithSize: (length * 4) + 1]; + _s->cString = OFAllocMemory((length * 4) + 1, 1); _s->length = length; + _s->freeWhenDone = true; j = 0; for (size_t i = 0; i < length; i++) { - of_unichar_t character = - (swap ? OF_BSWAP16(string[i]) : string[i]); + OFUnichar character = + (swap ? OFByteSwap16(string[i]) : string[i]); size_t len; /* Missing high surrogate */ if ((character & 0xFC00) == 0xDC00) @throw [OFInvalidEncodingException exception]; if ((character & 0xFC00) == 0xD800) { - of_char16_t nextCharacter; + OFChar16 nextCharacter; if (length <= i + 1) @throw [OFInvalidEncodingException exception]; nextCharacter = (swap - ? OF_BSWAP16(string[i + 1]) + ? OFByteSwap16(string[i + 1]) : string[i + 1]); if ((nextCharacter & 0xFC00) != 0xDC00) @throw [OFInvalidEncodingException exception]; @@ -569,11 +561,11 @@ i++; _s->length--; } - len = of_string_utf8_encode(character, _s->cString + j); + len = OFUTF8StringEncode(character, _s->cString + j); if (len == 0) @throw [OFInvalidEncodingException exception]; if (len > 1) @@ -584,12 +576,11 @@ _s->cString[j] = '\0'; _s->cStringLength = j; @try { - _s->cString = [self resizeMemory: _s->cString - size: j + 1]; + _s->cString = OFResizeMemory(_s->cString, j + 1, 1); } @catch (OFOutOfMemoryException *e) { /* We don't care, as we only tried to make it smaller */ } } @catch (id e) { [self release]; @@ -597,13 +588,13 @@ } return self; } -- (instancetype)initWithUTF32String: (const of_char32_t *)characters +- (instancetype)initWithUTF32String: (const OFChar32 *)characters length: (size_t)length - byteOrder: (of_byte_order_t)byteOrder + byteOrder: (OFByteOrder)byteOrder { self = [super init]; @try { size_t j; @@ -614,23 +605,25 @@ length--; } else if (length > 0 && *characters == 0xFFFE0000) { swap = true; characters++; length--; - } else if (byteOrder != OF_BYTE_ORDER_NATIVE) + } else if (byteOrder != OFByteOrderNative) swap = true; _s = &_storage; - _s->cString = [self allocMemoryWithSize: (length * 4) + 1]; + _s->cString = OFAllocMemory((length * 4) + 1, 1); _s->length = length; + _s->freeWhenDone = true; j = 0; for (size_t i = 0; i < length; i++) { char buffer[4]; - size_t len = of_string_utf8_encode( - (swap ? OF_BSWAP32(characters[i]) : characters[i]), + size_t len = OFUTF8StringEncode((swap + ? OFByteSwap32(characters[i]) + : characters[i]), buffer); switch (len) { case 1: _s->cString[j++] = buffer[0]; @@ -651,12 +644,11 @@ _s->cString[j] = '\0'; _s->cStringLength = j; @try { - _s->cString = [self resizeMemory: _s->cString - size: j + 1]; + _s->cString = OFResizeMemory(_s->cString, j + 1, 1); } @catch (OFOutOfMemoryException *e) { /* We don't care, as we only tried to make it smaller */ } } @catch (id e) { [self release]; @@ -678,31 +670,31 @@ if (format == nil) @throw [OFInvalidArgumentException exception]; _s = &_storage; - if ((cStringLength = of_vasprintf(&tmp, format.UTF8String, + if ((cStringLength = OFVASPrintF(&tmp, format.UTF8String, arguments)) == -1) @throw [OFInvalidFormatException exception]; _s->cStringLength = cStringLength; @try { - switch (of_string_utf8_check(tmp, cStringLength, + switch (OFUTF8StringCheck(tmp, cStringLength, &_s->length)) { case 1: _s->isUTF8 = true; break; case -1: @throw [OFInvalidEncodingException exception]; } - _s->cString = [self - allocMemoryWithSize: cStringLength + 1]; + _s->cString = OFAllocMemory(cStringLength + 1, 1); memcpy(_s->cString, tmp, cStringLength + 1); + _s->freeWhenDone = true; } @finally { - free(tmp); + OFFreeMemory(tmp); } } @catch (id e) { [self release]; @throw e; } @@ -710,26 +702,26 @@ return self; } - (void)dealloc { - if (_s != NULL && _s->freeWhenDone != NULL) - free(_s->freeWhenDone); + if (_s != NULL && _s->freeWhenDone) + OFFreeMemory(_s->cString); [super dealloc]; } - (size_t)getCString: (char *)cString maxLength: (size_t)maxLength - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding { switch (encoding) { - case OF_STRING_ENCODING_ASCII: + case OFStringEncodingASCII: if (_s->isUTF8) @throw [OFInvalidEncodingException exception]; /* intentional fall-through */ - case OF_STRING_ENCODING_UTF_8: + case OFStringEncodingUTF8: if (_s->cStringLength + 1 > maxLength) @throw [OFOutOfRangeException exception]; memcpy(cString, _s->cString, _s->cStringLength + 1); @@ -739,18 +731,18 @@ maxLength: maxLength encoding: encoding]; } } -- (const char *)cStringWithEncoding: (of_string_encoding_t)encoding +- (const char *)cStringWithEncoding: (OFStringEncoding)encoding { switch (encoding) { - case OF_STRING_ENCODING_ASCII: + case OFStringEncodingASCII: if (_s->isUTF8) @throw [OFInvalidEncodingException exception]; /* intentional fall-through */ - case OF_STRING_ENCODING_UTF_8: + case OFStringEncodingUTF8: return _s->cString; default: return [super cStringWithEncoding: encoding]; } } @@ -763,15 +755,15 @@ - (size_t)length { return _s->length; } -- (size_t)cStringLengthWithEncoding: (of_string_encoding_t)encoding +- (size_t)cStringLengthWithEncoding: (OFStringEncoding)encoding { switch (encoding) { - case OF_STRING_ENCODING_UTF_8: - case OF_STRING_ENCODING_ASCII: + case OFStringEncodingUTF8: + case OFStringEncodingASCII: return _s->cStringLength; default: return [super cStringLengthWithEncoding: encoding]; } } @@ -781,85 +773,79 @@ return _s->cStringLength; } - (bool)isEqual: (id)object { - OFUTF8String *otherString; + OFUTF8String *string; if (object == self) return true; if (![object isKindOfClass: [OFString class]]) return false; - otherString = object; + string = object; - if (otherString.UTF8StringLength != _s->cStringLength || - otherString.length != _s->length) + if (string.UTF8StringLength != _s->cStringLength || + string.length != _s->length) + return false; + + if (([string isKindOfClass: [OFUTF8String class]] || + [string isKindOfClass: [OFMutableUTF8String class]]) && + _s->hasHash && string->_s->hasHash && _s->hash != string->_s->hash) return false; - if (([otherString isKindOfClass: [OFUTF8String class]] || - [otherString isKindOfClass: [OFMutableUTF8String class]]) && - _s->hashed && otherString->_s->hashed && - _s->hash != otherString->_s->hash) - return false; - - if (strcmp(_s->cString, otherString.UTF8String) != 0) + if (strcmp(_s->cString, string.UTF8String) != 0) return false; return true; } -- (of_comparison_result_t)compare: (id )object +- (OFComparisonResult)compare: (OFString *)string { - OFString *otherString; size_t otherCStringLength, minimumCStringLength; int compare; - if (object == self) - return OF_ORDERED_SAME; + if (string == self) + return OFOrderedSame; - if (![(id)object isKindOfClass: [OFString class]]) + if (![string isKindOfClass: [OFString class]]) @throw [OFInvalidArgumentException exception]; - otherString = (OFString *)object; - otherCStringLength = otherString.UTF8StringLength; + otherCStringLength = string.UTF8StringLength; minimumCStringLength = (_s->cStringLength > otherCStringLength ? otherCStringLength : _s->cStringLength); - if ((compare = memcmp(_s->cString, otherString.UTF8String, + if ((compare = memcmp(_s->cString, string.UTF8String, minimumCStringLength)) == 0) { if (_s->cStringLength > otherCStringLength) - return OF_ORDERED_DESCENDING; + return OFOrderedDescending; if (_s->cStringLength < otherCStringLength) - return OF_ORDERED_ASCENDING; - return OF_ORDERED_SAME; + return OFOrderedAscending; + return OFOrderedSame; } if (compare > 0) - return OF_ORDERED_DESCENDING; + return OFOrderedDescending; else - return OF_ORDERED_ASCENDING; + return OFOrderedAscending; } -- (of_comparison_result_t)caseInsensitiveCompare: (OFString *)otherString +- (OFComparisonResult)caseInsensitiveCompare: (OFString *)string { const char *otherCString; size_t otherCStringLength, minimumCStringLength; #ifdef OF_HAVE_UNICODE_TABLES size_t i, j; #endif int compare; - if (otherString == self) - return OF_ORDERED_SAME; - - if (![otherString isKindOfClass: [OFString class]]) - @throw [OFInvalidArgumentException exception]; - - otherCString = otherString.UTF8String; - otherCStringLength = otherString.UTF8StringLength; + if (string == self) + return OFOrderedSame; + + otherCString = string.UTF8String; + otherCStringLength = string.UTF8StringLength; #ifdef OF_HAVE_UNICODE_TABLES if (!_s->isUTF8) { #endif minimumCStringLength = (_s->cStringLength > otherCStringLength @@ -866,142 +852,141 @@ ? otherCStringLength : _s->cStringLength); if ((compare = memcasecmp(_s->cString, otherCString, minimumCStringLength)) == 0) { if (_s->cStringLength > otherCStringLength) - return OF_ORDERED_DESCENDING; + return OFOrderedDescending; if (_s->cStringLength < otherCStringLength) - return OF_ORDERED_ASCENDING; - return OF_ORDERED_SAME; + return OFOrderedAscending; + return OFOrderedSame; } if (compare > 0) - return OF_ORDERED_DESCENDING; + return OFOrderedDescending; else - return OF_ORDERED_ASCENDING; + return OFOrderedAscending; #ifdef OF_HAVE_UNICODE_TABLES } i = j = 0; while (i < _s->cStringLength && j < otherCStringLength) { - of_unichar_t c1, c2; + OFUnichar c1, c2; ssize_t l1, l2; - l1 = of_string_utf8_decode(_s->cString + i, + l1 = OFUTF8StringDecode(_s->cString + i, _s->cStringLength - i, &c1); - l2 = of_string_utf8_decode(otherCString + j, + l2 = OFUTF8StringDecode(otherCString + j, otherCStringLength - j, &c2); if (l1 <= 0 || l2 <= 0 || c1 > 0x10FFFF || c2 > 0x10FFFF) @throw [OFInvalidEncodingException exception]; - if (c1 >> 8 < OF_UNICODE_CASEFOLDING_TABLE_SIZE) { - of_unichar_t tc = - of_unicode_casefolding_table[c1 >> 8][c1 & 0xFF]; + if (c1 >> 8 < OFUnicodeCaseFoldingTableSize) { + OFUnichar tc = + OFUnicodeCaseFoldingTable[c1 >> 8][c1 & 0xFF]; if (tc) c1 = tc; } - if (c2 >> 8 < OF_UNICODE_CASEFOLDING_TABLE_SIZE) { - of_unichar_t tc = - of_unicode_casefolding_table[c2 >> 8][c2 & 0xFF]; + if (c2 >> 8 < OFUnicodeCaseFoldingTableSize) { + OFUnichar tc = + OFUnicodeCaseFoldingTable[c2 >> 8][c2 & 0xFF]; if (tc) c2 = tc; } if (c1 > c2) - return OF_ORDERED_DESCENDING; + return OFOrderedDescending; if (c1 < c2) - return OF_ORDERED_ASCENDING; + return OFOrderedAscending; i += l1; j += l2; } if (_s->cStringLength - i > otherCStringLength - j) - return OF_ORDERED_DESCENDING; + return OFOrderedDescending; else if (_s->cStringLength - i < otherCStringLength - j) - return OF_ORDERED_ASCENDING; + return OFOrderedAscending; #endif - return OF_ORDERED_SAME; + return OFOrderedSame; } - (unsigned long)hash { - uint32_t hash; + unsigned long hash; - if (_s->hashed) + if (_s->hasHash) return _s->hash; - OF_HASH_INIT(hash); + OFHashInit(&hash); for (size_t i = 0; i < _s->cStringLength; i++) { - of_unichar_t c; + OFUnichar c; ssize_t length; - if ((length = of_string_utf8_decode(_s->cString + i, + if ((length = OFUTF8StringDecode(_s->cString + i, _s->cStringLength - i, &c)) <= 0) @throw [OFInvalidEncodingException exception]; - OF_HASH_ADD(hash, (c & 0xFF0000) >> 16); - OF_HASH_ADD(hash, (c & 0x00FF00) >> 8); - OF_HASH_ADD(hash, c & 0x0000FF); + OFHashAdd(&hash, (c & 0xFF0000) >> 16); + OFHashAdd(&hash, (c & 0x00FF00) >> 8); + OFHashAdd(&hash, c & 0x0000FF); i += length - 1; } - OF_HASH_FINALIZE(hash); + OFHashFinalize(&hash); _s->hash = hash; - _s->hashed = true; + _s->hasHash = true; return hash; } -- (of_unichar_t)characterAtIndex: (size_t)idx +- (OFUnichar)characterAtIndex: (size_t)idx { - of_unichar_t character; + OFUnichar character; if (idx >= _s->length) @throw [OFOutOfRangeException exception]; if (!_s->isUTF8) return _s->cString[idx]; - idx = of_string_utf8_get_position(_s->cString, idx, _s->cStringLength); + idx = OFUTF8StringIndexToPosition(_s->cString, idx, _s->cStringLength); - if (of_string_utf8_decode(_s->cString + idx, - _s->cStringLength - idx, &character) <= 0) + if (OFUTF8StringDecode(_s->cString + idx, _s->cStringLength - idx, + &character) <= 0) @throw [OFInvalidEncodingException exception]; return character; } -- (void)getCharacters: (of_unichar_t *)buffer - inRange: (of_range_t)range +- (void)getCharacters: (OFUnichar *)buffer inRange: (OFRange)range { /* TODO: Could be slightly optimized */ void *pool = objc_autoreleasePoolPush(); - const of_unichar_t *characters = self.characters; + const OFUnichar *characters = self.characters; if (range.length > SIZE_MAX - range.location || range.location + range.length > _s->length) @throw [OFOutOfRangeException exception]; memcpy(buffer, characters + range.location, - range.length * sizeof(of_unichar_t)); + range.length * sizeof(OFUnichar)); objc_autoreleasePoolPop(pool); } -- (of_range_t)rangeOfString: (OFString *)string - options: (int)options - range: (of_range_t)range +- (OFRange)rangeOfString: (OFString *)string + options: (OFStringSearchOptions)options + range: (OFRange)range { const char *cString = string.UTF8String; size_t cStringLength = string.UTF8StringLength; size_t rangeLocation, rangeLength; @@ -1008,55 +993,55 @@ if (range.length > SIZE_MAX - range.location || range.location + range.length > _s->length) @throw [OFOutOfRangeException exception]; if (_s->isUTF8) { - rangeLocation = of_string_utf8_get_position( + rangeLocation = OFUTF8StringIndexToPosition( _s->cString, range.location, _s->cStringLength); - rangeLength = of_string_utf8_get_position( + rangeLength = OFUTF8StringIndexToPosition( _s->cString + rangeLocation, range.length, _s->cStringLength - rangeLocation); } else { rangeLocation = range.location; rangeLength = range.length; } if (cStringLength == 0) - return of_range(0, 0); + return OFRangeMake(0, 0); if (cStringLength > rangeLength) - return of_range(OF_NOT_FOUND, 0); + return OFRangeMake(OFNotFound, 0); - if (options & OF_STRING_SEARCH_BACKWARDS) { + if (options & OFStringSearchBackwards) { for (size_t i = rangeLength - cStringLength;; i--) { if (memcmp(_s->cString + rangeLocation + i, cString, cStringLength) == 0) { - range.location += of_string_utf8_get_index( + range.location += positionToIndex( _s->cString + rangeLocation, i); range.length = string.length; return range; } /* Did not match and we're at the last char */ if (i == 0) - return of_range(OF_NOT_FOUND, 0); + return OFRangeMake(OFNotFound, 0); } } else { for (size_t i = 0; i <= rangeLength - cStringLength; i++) { if (memcmp(_s->cString + rangeLocation + i, cString, cStringLength) == 0) { - range.location += of_string_utf8_get_index( + range.location += positionToIndex( _s->cString + rangeLocation, i); range.length = string.length; return range; } } } - return of_range(OF_NOT_FOUND, 0); + return OFRangeMake(OFNotFound, 0); } - (bool)containsString: (OFString *)string { const char *cString = string.UTF8String; @@ -1073,22 +1058,22 @@ return true; return false; } -- (OFString *)substringWithRange: (of_range_t)range +- (OFString *)substringWithRange: (OFRange)range { size_t start = range.location; size_t end = range.location + range.length; if (range.length > SIZE_MAX - range.location || end > _s->length) @throw [OFOutOfRangeException exception]; if (_s->isUTF8) { - start = of_string_utf8_get_position(_s->cString, start, + start = OFUTF8StringIndexToPosition(_s->cString, start, _s->cStringLength); - end = of_string_utf8_get_position(_s->cString, end, + end = OFUTF8StringIndexToPosition(_s->cString, end, _s->cStringLength); } return [OFString stringWithUTF8String: _s->cString + start length: end - start]; @@ -1114,22 +1099,30 @@ return (memcmp(_s->cString + (_s->cStringLength - cStringLength), suffix.UTF8String, cStringLength) == 0); } - (OFArray *)componentsSeparatedByString: (OFString *)delimiter - options: (int)options + options: (OFStringSeparationOptions)options { void *pool; OFMutableArray *array; - const char *cString = delimiter.UTF8String; - size_t cStringLength = delimiter.UTF8StringLength; - bool skipEmpty = (options & OF_STRING_SKIP_EMPTY); + const char *cString; + size_t cStringLength; + bool skipEmpty = (options & OFStringSkipEmptyComponents); size_t last; OFString *component; + if (delimiter == nil) + @throw [OFInvalidArgumentException exception]; + + if (delimiter.length == 0) + return [OFArray arrayWithObject: self]; + array = [OFMutableArray array]; pool = objc_autoreleasePoolPush(); + cString = delimiter.UTF8String; + cStringLength = delimiter.UTF8StringLength; if (cStringLength > _s->cStringLength) { [array addObject: [[self copy] autorelease]]; objc_autoreleasePoolPop(pool); @@ -1158,73 +1151,87 @@ objc_autoreleasePoolPop(pool); return array; } -- (const of_unichar_t *)characters -{ - OFObject *object = [[[OFObject alloc] init] autorelease]; - of_unichar_t *ret; - size_t i, j; - - ret = [object allocMemoryWithSize: sizeof(of_unichar_t) - count: _s->length]; - - i = j = 0; +- (const OFUnichar *)characters +{ + OFUnichar *buffer = OFAllocMemory(_s->length, sizeof(OFUnichar)); + size_t i = 0, j = 0; + const OFUnichar *ret; while (i < _s->cStringLength) { - of_unichar_t c; + OFUnichar c; ssize_t cLen; - cLen = of_string_utf8_decode(_s->cString + i, + cLen = OFUTF8StringDecode(_s->cString + i, _s->cStringLength - i, &c); - if (cLen <= 0 || c > 0x10FFFF) + if (cLen <= 0 || c > 0x10FFFF) { + OFFreeMemory(buffer); @throw [OFInvalidEncodingException exception]; + } - ret[j++] = c; + buffer[j++] = c; i += cLen; } + + @try { + ret = [[OFData dataWithItemsNoCopy: buffer + count: _s->length + itemSize: sizeof(OFUnichar) + freeWhenDone: true] items]; + } @catch (id e) { + OFFreeMemory(buffer); + @throw e; + } return ret; } -- (const of_char32_t *)UTF32StringWithByteOrder: (of_byte_order_t)byteOrder -{ - OFObject *object = [[[OFObject alloc] init] autorelease]; - of_char32_t *ret; - size_t i, j; - - ret = [object allocMemoryWithSize: sizeof(of_unichar_t) - count: _s->length + 1]; - - i = j = 0; +- (const OFChar32 *)UTF32StringWithByteOrder: (OFByteOrder)byteOrder +{ + OFChar32 *buffer = OFAllocMemory(_s->length + 1, sizeof(OFChar32)); + size_t i = 0, j = 0; + const OFChar32 *ret; while (i < _s->cStringLength) { - of_unichar_t c; + OFChar32 c; ssize_t cLen; - cLen = of_string_utf8_decode(_s->cString + i, + cLen = OFUTF8StringDecode(_s->cString + i, _s->cStringLength - i, &c); - if (cLen <= 0 || c > 0x10FFFF) + if (cLen <= 0 || c > 0x10FFFF) { + OFFreeMemory(buffer); @throw [OFInvalidEncodingException exception]; + } - if (byteOrder != OF_BYTE_ORDER_NATIVE) - ret[j++] = OF_BSWAP32(c); + if (byteOrder != OFByteOrderNative) + buffer[j++] = OFByteSwap32(c); else - ret[j++] = c; + buffer[j++] = c; i += cLen; } - ret[j] = 0; + buffer[j] = 0; + + @try { + ret = [[OFData dataWithItemsNoCopy: buffer + count: _s->length + 1 + itemSize: sizeof(OFChar32) + freeWhenDone: true] items]; + } @catch (id e) { + OFFreeMemory(buffer); + @throw e; + } return ret; } #ifdef OF_HAVE_BLOCKS -- (void)enumerateLinesUsingBlock: (of_string_line_enumeration_block_t)block +- (void)enumerateLinesUsingBlock: (OFStringLineEnumerationBlock)block { void *pool; const char *cString = _s->cString; const char *last = cString; bool stop = false, lastCarriageReturn = false; @@ -1240,13 +1247,13 @@ } if (*cString == '\n' || *cString == '\r') { pool = objc_autoreleasePoolPush(); - block([OFString - stringWithUTF8String: last - length: cString - last], &stop); + block([OFString stringWithUTF8String: last + length: cString - last], + &stop); last = cString + 1; objc_autoreleasePoolPop(pool); } ADDED src/OFUUID.h Index: src/OFUUID.h ================================================================== --- /dev/null +++ src/OFUUID.h @@ -0,0 +1,103 @@ +/* + * 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 "OFSerialization.h" + +OF_ASSUME_NONNULL_BEGIN + +@class OFString; + +/** + * @class OFUUID OFUUID.h ObjFW/OFUUID.h + * + * @brief A UUID conforming to RFC 4122. + */ +OF_SUBCLASSING_RESTRICTED +@interface OFUUID: OFObject +{ + unsigned char _bytes[16]; +} + +/** + * @brief The UUID as a string. + */ +@property (readonly, nonatomic) OFString *UUIDString; + +/** + * @brief Creates a new random UUID as per RFC 4122 version 4. + * + * @return A new, autoreleased OFUUID + */ ++ (instancetype)UUID; + +/** + * @brief Creates a new UUID with the specified bytes. + * + * @param bytes The bytes for the UUID + * @return A new, autoreleased OFUUID + */ ++ (instancetype)UUIDWithUUIDBytes: (const unsigned char [_Nonnull 16])bytes; + +/** + * @brief Creates a new UUID with the specified UUID string. + * + * @param string The UUID string for the UUID + * @return A new, autoreleased OFUUID + */ ++ (instancetype)UUIDWithUUIDString: (OFString *)string; + +/** + * @brief Initializes an already allocated OFUUID as a new random UUID as per + * RFC 4122 version 4. + * + * @return An initialized OFUUID + */ +- (instancetype)init; + +/** + * @brief Initializes an already allocated OFUUID with the specified bytes. + * + * @param bytes The bytes to initialize the OFUUID with + * @return An initialized OFUUID + */ +- (instancetype)initWithUUIDBytes: (const unsigned char [_Nonnull 16])bytes; + +/** + * @brief Initializes an already allocated OFUUID with the specified UUID + * string. + * + * @param string The UUID string to initialize the OFUUID with + * @return An initialized OFUUID + */ +- (instancetype)initWithUUIDString: (OFString *)string; + +/** + * @brief Compares the UUID to another UUID. + * + * @param UUID The UUID to compare to + * @return The result of the comparison + */ +- (OFComparisonResult)compare: (OFUUID *)UUID; + +/** + * @brief Gets the bytes of the UUID. + * + * @param bytes An array of 16 bytes into which to write the UUID + */ +- (void)getUUIDBytes: (unsigned char [_Nonnull 16])bytes; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFUUID.m Index: src/OFUUID.m ================================================================== --- /dev/null +++ src/OFUUID.m @@ -0,0 +1,252 @@ +/* + * 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 "OFUUID.h" +#import "OFArray.h" +#import "OFString.h" +#import "OFXMLElement.h" + +#import "OFInvalidArgumentException.h" +#import "OFInvalidFormatException.h" +#import "OFOutOfRangeException.h" + +#define bytesSize 16 + +@implementation OFUUID ++ (instancetype)UUID +{ + return [[[self alloc] init] autorelease]; +} + ++ (instancetype)UUIDWithUUIDBytes: (const unsigned char [16])bytes +{ + return [[[self alloc] initWithUUIDBytes: bytes] autorelease]; +} + ++ (instancetype)UUIDWithUUIDString: (OFString *)string +{ + return [[[self alloc] initWithUUIDString: string] autorelease]; +} + +- (instancetype)init +{ + uint64_t r; + + self = [super init]; + + r = OFRandom64(); + memcpy(_bytes, &r, 8); + r = OFRandom64(); + memcpy(_bytes + 8, &r, 8); + + _bytes[6] &= ~((1 << 7) | (1 << 5) | (1 << 4)); + _bytes[6] |= (1 << 6); + _bytes[8] &= ~(1 << 6); + _bytes[8] |= (1 << 7); + + return self; +} + +- (instancetype)initWithUUIDBytes: (const unsigned char [16])bytes +{ + self = [super init]; + + memcpy(_bytes, bytes, sizeof(_bytes)); + + return self; +} + +static void +decode(OFArray OF_GENERIC(OFString *) *components, size_t componentIndex, + size_t componentLength, unsigned char *bytes, size_t *i) +{ + void *pool = objc_autoreleasePoolPush(); + OFString *component = [components objectAtIndex: componentIndex]; + const char *cString; + + if (component.UTF8StringLength != componentLength) + @throw [OFInvalidFormatException exception]; + + if (*i + componentLength / 2 > bytesSize) + @throw [OFOutOfRangeException exception]; + + cString = component.UTF8String; + + for (size_t j = 0; j < componentLength; j += 2) { + uint8_t value; + + if (cString[j] >= '0' && cString[j] <= '9') + value = cString[j] - '0'; + else if (cString[j] >= 'a' && cString[j] <= 'f') + value = cString[j] - 'a' + 10; + else if (cString[j] >= 'A' && cString[j] <= 'F') + value = cString[j] - 'A' + 10; + else + @throw [OFInvalidFormatException exception]; + + value <<= 4; + + if (cString[j + 1] >= '0' && cString[j + 1] <= '9') + value |= cString[j + 1] - '0'; + else if (cString[j + 1] >= 'a' && cString[j + 1] <= 'f') + value |= cString[j + 1] - 'a' + 10; + else if (cString[j + 1] >= 'A' && cString[j + 1] <= 'F') + value |= cString[j + 1] - 'A' + 10; + else + @throw [OFInvalidFormatException exception]; + + bytes[(*i)++] = value; + } + + objc_autoreleasePoolPop(pool); +} + +- (instancetype)initWithUUIDString: (OFString *)string +{ + self = [super init]; + + @try { + void *pool = objc_autoreleasePoolPush(); + size_t i = 0; + OFArray OF_GENERIC(OFString *) *components = + [string componentsSeparatedByString: @"-"]; + + if (components.count != 5) + @throw [OFInvalidFormatException exception]; + + decode(components, 0, 8, _bytes, &i); + decode(components, 1, 4, _bytes, &i); + decode(components, 2, 4, _bytes, &i); + decode(components, 3, 4, _bytes, &i); + decode(components, 4, 12, _bytes, &i); + + OFEnsure(i == 16); + + objc_autoreleasePoolPop(pool); + } @catch (id e) { + [self release]; + @throw e; + } + + 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]]) + return false; + + UUID = object; + + return (memcmp(_bytes, UUID->_bytes, sizeof(_bytes)) == 0); +} + +- (unsigned long)hash +{ + unsigned long hash; + + OFHashInit(&hash); + + for (size_t i = 0; i < sizeof(_bytes); i++) + OFHashAdd(&hash, _bytes[i]); + + OFHashFinalize(&hash); + + return hash; +} + +- (id)copy +{ + return [self retain]; +} + +- (OFComparisonResult)compare: (OFUUID *)UUID +{ + int comparison; + + if (![UUID isKindOfClass: [OFUUID class]]) + @throw [OFInvalidArgumentException exception]; + + if ((comparison = memcmp(_bytes, UUID->_bytes, sizeof(_bytes))) == 0) + return OFOrderedSame; + + if (comparison > 0) + return OFOrderedDescending; + else + return OFOrderedAscending; +} + +- (void)getUUIDBytes: (unsigned char [16])bytes +{ + memcpy(bytes, _bytes, sizeof(_bytes)); +} + +- (OFString *)UUIDString +{ + return [OFString stringWithFormat: + @"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-" + @"%02x%02x%02x%02x%02x%02x", + _bytes[0], _bytes[1], _bytes[2], _bytes[3], + _bytes[4], _bytes[5], _bytes[6], _bytes[7], + _bytes[8], _bytes[9], _bytes[10], _bytes[11], + _bytes[12], _bytes[13], _bytes[14], _bytes[15]]; +} + +- (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,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -47,36 +45,36 @@ * If the value is not pointer-sized, @ref OFOutOfRangeException is thrown. */ @property (readonly, nonatomic) id nonretainedObjectValue; /** - * @brief The value as a range. - * - * If the value is not range-sized, @ref OFOutOfRangeException is thrown. - */ -@property (readonly, nonatomic) of_range_t rangeValue; - -/** - * @brief The value as a point. - * - * If the value is not point-sized, @ref OFOutOfRangeException is thrown. - */ -@property (readonly, nonatomic) of_point_t pointValue; - -/** - * @brief The value as a dimension. - * - * If the value is not dimension-sized, @ref OFOutOfRangeException is thrown. - */ -@property (readonly, nonatomic) of_dimension_t dimensionValue; - -/** - * @brief The value as a rectangle. - * - * If the value is not rectangle-sized, @ref OFOutOfRangeException is thrown. - */ -@property (readonly, nonatomic) of_rectangle_t rectangleValue; + * @brief The value as an OFRange. + * + * If the value is not OFRange-sized, @ref OFOutOfRangeException is thrown. + */ +@property (readonly, nonatomic) OFRange rangeValue; + +/** + * @brief The value as an OFPoint. + * + * If the value is not OFPoint-sized, @ref OFOutOfRangeException is thrown. + */ +@property (readonly, nonatomic) OFPoint pointValue; + +/** + * @brief The value as an OFSize. + * + * If the value is not OFSize-sized, @ref OFOutOfRangeException is thrown. + */ +@property (readonly, nonatomic) OFSize sizeValue; + +/** + * @brief The value as a OFRect. + * + * If the value is not OFRect-sized, @ref OFOutOfRangeException is thrown. + */ +@property (readonly, nonatomic) OFRect rectValue; /** * @brief Creates a new, autorelease OFValue with the specified bytes of the * specified type. * @@ -113,37 +111,36 @@ * @brief Creates a new, autoreleased OFValue containing the specified range. * * @param range The range the OFValue should contain * @return A new, autoreleased OFValue */ -+ (instancetype)valueWithRange: (of_range_t)range; ++ (instancetype)valueWithRange: (OFRange)range; /** * @brief Creates a new, autoreleased OFValue containing the specified point. * * @param point The point the OFValue should contain * @return A new, autoreleased OFValue */ -+ (instancetype)valueWithPoint: (of_point_t)point; ++ (instancetype)valueWithPoint: (OFPoint)point; /** - * @brief Creates a new, autoreleased OFValue containing the specified - * dimension. + * @brief Creates a new, autoreleased OFValue containing the specified size. * - * @param dimension The dimension the OFValue should contain + * @param size The size the OFValue should contain * @return A new, autoreleased OFValue */ -+ (instancetype)valueWithDimension: (of_dimension_t)dimension; ++ (instancetype)valueWithSize: (OFSize)size; /** * @brief Creates a new, autoreleased OFValue containing the specified * rectangle. * - * @param rectangle The rectangle the OFValue should contain + * @param rect The rectangle the OFValue should contain * @return A new, autoreleased OFValue */ -+ (instancetype)valueWithRectangle: (of_rectangle_t)rectangle; ++ (instancetype)valueWithRect: (OFRect)rect; /** * @brief Initializes an already allocated OFValue with the specified bytes of * the specified type. * @@ -152,83 +149,23 @@ * @return An initialized OFValue */ - (instancetype)initWithBytes: (const void *)bytes objCType: (const char *)objCType; -/** - * @brief Initializes an already allocated OFValue containing the specified - * pointer. - * - * Only the raw value of the pointer is stored and no data will be copied. - * - * @param pointer The pointer the OFValue should contain - * @return An initialized OFValue - */ -- (instancetype)initWithPointer: (const void *)pointer; - -/** - * @brief Initializes an already allocated OFValue containing the specified - * non-retained object. - * - * The object is not retained, which makes this useful for storing objects in - * collections without retaining them. - * - * @param object The object the OFValue should contain without retaining it - * @return An initialized OFValue - */ -- (instancetype)initWithNonretainedObject: (id)object; - -/** - * @brief Initializes an already allocated OFValue containing the specified - * range. - * - * @param range The range the OFValue should contain - * @return An initialized OFValue - */ -- (instancetype)initWithRange: (of_range_t)range; - -/** - * @brief Initializes an already allocated OFValue containing the specified - * point. - * - * @param point The point the OFValue should contain - * @return An initialized OFValue - */ -- (instancetype)initWithPoint: (of_point_t)point; - -/** - * @brief Initializes an already allocated OFValue containing the specified - * dimension. - * - * @param dimension The dimension the OFValue should contain - * @return An initialized OFValue - */ -- (instancetype)initWithDimension: (of_dimension_t)dimension; - -/** - * @brief Initializes an already allocated OFValue containing the specified - * rectangle. - * - * @param rectangle The rectangle the OFValue should contain - * @return An initialized OFValue - */ -- (instancetype)initWithRectangle: (of_rectangle_t)rectangle; - /** * @brief Gets the value. * * If the specified size does not match, this raises an * @ref OFOutOfRangeException. * * @param value The buffer to copy the value into * @param size The size of the value */ -- (void)getValue: (void *)value - size: (size_t)size; +- (void)getValue: (void *)value size: (size_t)size; @end OF_ASSUME_NONNULL_END #if !defined(NSINTEGER_DEFINED) && !__has_feature(modules) /* Required for array literals to work */ @compatibility_alias NSValue OFValue; #endif Index: src/OFValue.m ================================================================== --- src/OFValue.m +++ src/OFValue.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -15,153 +13,71 @@ * file. */ #import "OFValue.h" #import "OFBytesValue.h" -#import "OFDimensionValue.h" #import "OFMethodSignature.h" #import "OFNonretainedObjectValue.h" #import "OFPointValue.h" #import "OFPointerValue.h" #import "OFRangeValue.h" -#import "OFRectangleValue.h" +#import "OFRectValue.h" +#import "OFSizeValue.h" #import "OFString.h" #import "OFOutOfMemoryException.h" -static struct { - Class isa; -} placeholder; - -@interface OFValuePlaceholder: OFValue -@end - -@implementation OFValuePlaceholder -- (instancetype)initWithBytes: (const void *)bytes - objCType: (const char *)objCType -{ - return (id)[[OFBytesValue alloc] initWithBytes: bytes - objCType: objCType]; -} - -- (instancetype)initWithPointer: (const void *)pointer -{ - return (id)[[OFPointerValue alloc] initWithPointer: pointer]; -} - -- (instancetype)initWithNonretainedObject: (id)object -{ - return (id)[[OFNonretainedObjectValue alloc] - initWithNonretainedObject: object]; -} - -- (instancetype)initWithRange: (of_range_t)range -{ - return (id)[[OFRangeValue alloc] initWithRange: range]; -} - -- (instancetype)initWithPoint: (of_point_t)point -{ - return (id)[[OFPointValue alloc] initWithPoint: point]; -} - -- (instancetype)initWithDimension: (of_dimension_t)dimension -{ - return (id)[[OFDimensionValue alloc] initWithDimension: dimension]; -} - -- (instancetype)initWithRectangle: (of_rectangle_t)rectangle -{ - return (id)[[OFRectangleValue alloc] initWithRectangle: rectangle]; -} -@end - @implementation OFValue -+ (void)initialize -{ - if (self == [OFValue class]) - placeholder.isa = [OFValuePlaceholder class]; -} - + (instancetype)alloc { if (self == [OFValue class]) - return (id)&placeholder; + return [OFBytesValue alloc]; return [super alloc]; } + (instancetype)valueWithBytes: (const void *)bytes objCType: (const char *)objCType { - return [[[self alloc] initWithBytes: bytes - objCType: objCType] autorelease]; + return [[[OFBytesValue alloc] initWithBytes: bytes + objCType: objCType] autorelease]; } + (instancetype)valueWithPointer: (const void *)pointer { - return [[[self alloc] initWithPointer: pointer] autorelease]; + return [[[OFPointerValue alloc] initWithPointer: pointer] autorelease]; } + (instancetype)valueWithNonretainedObject: (id)object { - return [[[self alloc] initWithNonretainedObject: object] autorelease]; -} - -+ (instancetype)valueWithRange: (of_range_t)range -{ - return [[[self alloc] initWithRange: range] autorelease]; -} - -+ (instancetype)valueWithPoint: (of_point_t)point -{ - return [[[self alloc] initWithPoint: point] autorelease]; -} - -+ (instancetype)valueWithDimension: (of_dimension_t)dimension -{ - return [[[self alloc] initWithDimension: dimension] autorelease]; -} - -+ (instancetype)valueWithRectangle: (of_rectangle_t)rectangle -{ - return [[[self alloc] initWithRectangle: rectangle] autorelease]; + return [[[OFNonretainedObjectValue alloc] + initWithNonretainedObject: object] autorelease]; +} + ++ (instancetype)valueWithRange: (OFRange)range +{ + return [[[OFRangeValue alloc] initWithRange: range] autorelease]; +} + ++ (instancetype)valueWithPoint: (OFPoint)point +{ + return [[[OFPointValue alloc] initWithPoint: point] autorelease]; +} + ++ (instancetype)valueWithSize: (OFSize)size +{ + return [[[OFSizeValue alloc] initWithSize: size] autorelease]; +} + ++ (instancetype)valueWithRect: (OFRect)rect +{ + return [[[OFRectValue alloc] initWithRect: rect] autorelease]; } - (instancetype)initWithBytes: (const void *)bytes objCType: (const char *)objCType { - OF_INVALID_INIT_METHOD -} - -- (instancetype)initWithPointer: (const void *)pointer -{ - OF_INVALID_INIT_METHOD -} - -- (instancetype)initWithNonretainedObject: (id)object -{ - OF_INVALID_INIT_METHOD -} - -- (instancetype)initWithRange: (of_range_t)range -{ - OF_INVALID_INIT_METHOD -} - -- (instancetype)initWithPoint: (of_point_t)point -{ - OF_INVALID_INIT_METHOD -} - -- (instancetype)initWithDimension: (of_dimension_t)dimension -{ - OF_INVALID_INIT_METHOD -} - -- (instancetype)initWithRectangle: (of_rectangle_t)rectangle -{ OF_INVALID_INIT_METHOD } - (bool)isEqual: (id)object { @@ -179,54 +95,50 @@ objCType = self.objCType; if (strcmp([object objCType], objCType) != 0) return false; - size = of_sizeof_type_encoding(objCType); + size = OFSizeOfTypeEncoding(objCType); - value = of_malloc(1, size); + value = OFAllocMemory(1, size); @try { - otherValue = of_malloc(1, size); + otherValue = OFAllocMemory(1, size); } @catch (id e) { - of_free(value); + OFFreeMemory(value); @throw e; } @try { - [self getValue: value - size: size]; - [object getValue: otherValue - size: size]; - + [self getValue: value size: size]; + [object getValue: otherValue size: size]; ret = (memcmp(value, otherValue, size) == 0); } @finally { - of_free(value); - of_free(otherValue); + OFFreeMemory(value); + OFFreeMemory(otherValue); } return ret; } - (unsigned long)hash { - size_t size = of_sizeof_type_encoding(self.objCType); + size_t size = OFSizeOfTypeEncoding(self.objCType); unsigned char *value; - uint32_t hash; + unsigned long hash; - value = of_malloc(1, size); + value = OFAllocMemory(1, size); @try { - [self getValue: value - size: size]; + [self getValue: value size: size]; - OF_HASH_INIT(hash); + OFHashInit(&hash); for (size_t i = 0; i < size; i++) - OF_HASH_ADD(hash, value[i]); + OFHashAdd(&hash, value[i]); - OF_HASH_FINALIZE(hash); + OFHashFinalize(&hash); } @finally { - of_free(value); + OFFreeMemory(value); } return hash; } @@ -238,99 +150,79 @@ - (const char *)objCType { OF_UNRECOGNIZED_SELECTOR } -- (void)getValue: (void *)value - size: (size_t)size +- (void)getValue: (void *)value size: (size_t)size { OF_UNRECOGNIZED_SELECTOR } - (void *)pointerValue { void *ret; - - [self getValue: &ret - size: sizeof(ret)]; - + [self getValue: &ret size: sizeof(ret)]; return ret; } - (id)nonretainedObjectValue { id ret; - - [self getValue: &ret - size: sizeof(ret)]; - - return ret; -} - -- (of_range_t)rangeValue -{ - of_range_t ret; - - [self getValue: &ret - size: sizeof(ret)]; - - return ret; -} - -- (of_point_t)pointValue -{ - of_point_t ret; - - [self getValue: &ret - size: sizeof(ret)]; - - return ret; -} - -- (of_dimension_t)dimensionValue -{ - of_dimension_t ret; - - [self getValue: &ret - size: sizeof(ret)]; - - return ret; -} - -- (of_rectangle_t)rectangleValue -{ - of_rectangle_t ret; - - [self getValue: &ret - size: sizeof(ret)]; - + [self getValue: &ret size: sizeof(ret)]; + return ret; +} + +- (OFRange)rangeValue +{ + OFRange ret; + [self getValue: &ret size: sizeof(ret)]; + return ret; +} + +- (OFPoint)pointValue +{ + OFPoint ret; + [self getValue: &ret size: sizeof(ret)]; + return ret; +} + +- (OFSize)sizeValue +{ + OFSize ret; + [self getValue: &ret size: sizeof(ret)]; + return ret; +} + +- (OFRect)rectValue +{ + OFRect ret; + [self getValue: &ret size: sizeof(ret)]; return ret; } - (OFString *)description { OFMutableString *ret = [OFMutableString stringWithString: @" 0) [ret appendString: @" "]; [ret appendFormat: @"%02x", value[i]]; } } @finally { - of_free(value); + OFFreeMemory(value); } [ret appendString: @">"]; [ret makeImmutable]; return ret; } @end Index: src/OFWin32ConsoleStdIOStream.h ================================================================== --- src/OFWin32ConsoleStdIOStream.h +++ src/OFWin32ConsoleStdIOStream.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -13,22 +11,20 @@ * 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. */ -#define OF_STDIO_STREAM_WIN32CONSOLE_H - #import "OFStdIOStream.h" OF_ASSUME_NONNULL_BEGIN @interface OFWin32ConsoleStdIOStream: OFStdIOStream { HANDLE _handle; WORD _attributes; - of_char16_t _incompleteUTF16Surrogate; + OFChar16 _incompleteUTF16Surrogate; char _incompleteUTF8Surrogate[4]; size_t _incompleteUTF8SurrogateLen; } @end OF_ASSUME_NONNULL_END Index: src/OFWin32ConsoleStdIOStream.m ================================================================== --- src/OFWin32ConsoleStdIOStream.m +++ src/OFWin32ConsoleStdIOStream.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -26,11 +24,11 @@ * write() suddenly returns the number of characters - instead of bytes - * written and read() just returns 0 as soon as a Unicode character is being * read. * * Therefore, instead of just using the UTF-8 codepage, this captures all reads - * and writes to of_std{in,out,err} on the low level, interprets the buffer as + * and writes to OFStd{In,Out,Err} on the low level, interprets the buffer as * UTF-8 and converts to / from UTF-16 to use ReadConsoleW() / WriteConsoleW(). * Doing so is safe, as the console only supports text anyway and thus it does * not matter if binary gets garbled by the conversion (e.g. because invalid * UTF-8 gets converted to U+FFFD). * @@ -37,12 +35,10 @@ * In order to not do this when redirecting input / output to a file (as the * file would then be read / written in the wrong encoding and break reading / * writing binary), it checks that the handle is indeed a console. */ -#define OF_STDIO_STREAM_WIN32_CONSOLE_M - #include "config.h" #include #include #include @@ -60,24 +56,24 @@ #import "OFReadFailedException.h" #import "OFWriteFailedException.h" #include -static of_string_encoding_t +static OFStringEncoding codepageToEncoding(UINT codepage) { switch (codepage) { case 437: - return OF_STRING_ENCODING_CODEPAGE_437; + return OFStringEncodingCodepage437; case 850: - return OF_STRING_ENCODING_CODEPAGE_850; + return OFStringEncodingCodepage850; case 858: - return OF_STRING_ENCODING_CODEPAGE_858; + return OFStringEncodingCodepage858; case 1251: - return OF_STRING_ENCODING_WINDOWS_1251; + return OFStringEncodingWindows1251; case 1252: - return OF_STRING_ENCODING_WINDOWS_1252; + return OFStringEncodingWindows1252; default: @throw [OFInvalidEncodingException exception]; } } @@ -88,17 +84,17 @@ if (self != [OFWin32ConsoleStdIOStream class]) return; if ((fd = _fileno(stdin)) >= 0) - of_stdin = [[OFWin32ConsoleStdIOStream alloc] + OFStdIn = [[OFWin32ConsoleStdIOStream alloc] of_initWithFileDescriptor: fd]; if ((fd = _fileno(stdout)) >= 0) - of_stdout = [[OFWin32ConsoleStdIOStream alloc] + OFStdOut = [[OFWin32ConsoleStdIOStream alloc] of_initWithFileDescriptor: fd]; if ((fd = _fileno(stderr)) >= 0) - of_stderr = [[OFWin32ConsoleStdIOStream alloc] + OFStdErr = [[OFWin32ConsoleStdIOStream alloc] of_initWithFileDescriptor: fd]; } - (instancetype)of_initWithFileDescriptor: (int)fd { @@ -124,23 +120,21 @@ } return self; } -- (size_t)lowlevelReadIntoBuffer: (void *)buffer_ - length: (size_t)length +- (size_t)lowlevelReadIntoBuffer: (void *)buffer_ length: (size_t)length { void *pool = objc_autoreleasePoolPush(); char *buffer = buffer_; - of_char16_t *UTF16; + OFChar16 *UTF16; size_t j = 0; if (length > UINT32_MAX) @throw [OFOutOfRangeException exception]; - UTF16 = [self allocMemoryWithSize: sizeof(of_char16_t) - count: length]; + UTF16 = OFAllocMemory(length, sizeof(OFChar16)); @try { DWORD UTF16Len; OFMutableData *rest = nil; size_t i = 0; @@ -150,11 +144,11 @@ @throw [OFReadFailedException exceptionWithObject: self requestedLength: length * 2 errNo: EIO]; } else { - of_string_encoding_t encoding; + OFStringEncoding encoding; OFString *string; size_t stringLen; if (!ReadConsoleA(_handle, (char *)UTF16, (DWORD)length, &UTF16Len, NULL)) @@ -175,45 +169,44 @@ UTF16Len = (DWORD)stringLen; memcpy(UTF16, string.UTF16String, stringLen); } if (UTF16Len > 0 && _incompleteUTF16Surrogate != 0) { - of_unichar_t c = + OFUnichar c = (((_incompleteUTF16Surrogate & 0x3FF) << 10) | (UTF16[0] & 0x3FF)) + 0x10000; char UTF8[4]; size_t UTF8Len; - if ((UTF8Len = of_string_utf8_encode(c, UTF8)) == 0) + if ((UTF8Len = OFUTF8StringEncode(c, UTF8)) == 0) @throw [OFInvalidEncodingException exception]; if (UTF8Len <= length) { memcpy(buffer, UTF8, UTF8Len); j += UTF8Len; } else { if (rest == nil) rest = [OFMutableData data]; - [rest addItems: UTF8 - count: UTF8Len]; + [rest addItems: UTF8 count: UTF8Len]; } _incompleteUTF16Surrogate = 0; i++; } for (; i < UTF16Len; i++) { - of_unichar_t c = UTF16[i]; + OFUnichar c = UTF16[i]; char UTF8[4]; size_t UTF8Len; /* Missing high surrogate */ if ((c & 0xFC00) == 0xDC00) @throw [OFInvalidEncodingException exception]; if ((c & 0xFC00) == 0xD800) { - of_char16_t next; + OFChar16 next; if (UTF16Len <= i + 1) { _incompleteUTF16Surrogate = c; if (rest != nil) { @@ -239,58 +232,55 @@ 0x10000; i++; } - if ((UTF8Len = of_string_utf8_encode(c, UTF8)) == 0) + if ((UTF8Len = OFUTF8StringEncode(c, UTF8)) == 0) @throw [OFInvalidEncodingException exception]; if (j + UTF8Len <= length) { memcpy(buffer + j, UTF8, UTF8Len); j += UTF8Len; } else { if (rest == nil) rest = [OFMutableData data]; - [rest addItems: UTF8 - count: UTF8Len]; + [rest addItems: UTF8 count: UTF8Len]; } } if (rest != nil) - [self unreadFromBuffer: rest.items - length: rest.count]; + [self unreadFromBuffer: rest.items length: rest.count]; } @finally { - [self freeMemory: UTF16]; + OFFreeMemory(UTF16); } objc_autoreleasePoolPop(pool); return j; } -- (size_t)lowlevelWriteBuffer: (const void *)buffer_ - length: (size_t)length +- (size_t)lowlevelWriteBuffer: (const void *)buffer_ length: (size_t)length { const char *buffer = buffer_; - of_char16_t *tmp; + OFChar16 *tmp; size_t i = 0, j = 0; if (length > SIZE_MAX / 2) @throw [OFOutOfRangeException exception]; if (_incompleteUTF8SurrogateLen > 0) { - of_unichar_t c; - of_char16_t UTF16[2]; + OFUnichar c; + OFChar16 UTF16[2]; ssize_t UTF8Len; size_t toCopy; DWORD UTF16Len, bytesWritten; - UTF8Len = -of_string_utf8_decode( + UTF8Len = -OFUTF8StringDecode( _incompleteUTF8Surrogate, _incompleteUTF8SurrogateLen, &c); - OF_ENSURE(UTF8Len > 0); + OFEnsure(UTF8Len > 0); toCopy = UTF8Len - _incompleteUTF8SurrogateLen; if (toCopy > length) toCopy = length; @@ -299,11 +289,11 @@ _incompleteUTF8SurrogateLen += toCopy; if (_incompleteUTF8SurrogateLen < (size_t)UTF8Len) return 0; - UTF8Len = of_string_utf8_decode( + UTF8Len = OFUTF8StringDecode( _incompleteUTF8Surrogate, _incompleteUTF8SurrogateLen, &c); if (UTF8Len <= 0 || c > 0x10FFFF) { assert(UTF8Len == 0 || UTF8Len < -4); @@ -332,11 +322,11 @@ } else { void *pool = objc_autoreleasePoolPush(); OFString *string = [OFString stringWithUTF16String: UTF16 length: UTF16Len]; - of_string_encoding_t encoding = + OFStringEncoding encoding = codepageToEncoding(GetConsoleOutputCP()); size_t nativeLen = [string cStringLengthWithEncoding: encoding]; if (nativeLen > UINT32_MAX) @@ -363,24 +353,23 @@ _incompleteUTF8SurrogateLen = 0; i += toCopy; } - tmp = [self allocMemoryWithSize: sizeof(of_char16_t) - count: length * 2]; + tmp = OFAllocMemory(length * 2, sizeof(OFChar16)); @try { DWORD bytesWritten; while (i < length) { - of_unichar_t c; + OFUnichar c; ssize_t UTF8Len; - UTF8Len = of_string_utf8_decode(buffer + i, length - i, + UTF8Len = OFUTF8StringDecode(buffer + i, length - i, &c); if (UTF8Len < 0 && UTF8Len >= -4) { - OF_ENSURE(length - i < 4); + OFEnsure(length - i < 4); memcpy(_incompleteUTF8Surrogate, buffer + i, length - i); _incompleteUTF8SurrogateLen = length - i; @@ -416,11 +405,11 @@ errNo: EIO]; } else { void *pool = objc_autoreleasePoolPush(); OFString *string = [OFString stringWithUTF16String: tmp length: j]; - of_string_encoding_t encoding = + OFStringEncoding encoding = codepageToEncoding(GetConsoleOutputCP()); size_t nativeLen = [string cStringLengthWithEncoding: encoding]; if (nativeLen > UINT32_MAX) @@ -443,11 +432,11 @@ exceptionWithObject: self requestedLength: j * 2 bytesWritten: bytesWritten * 2 errNo: 0]; } @finally { - [self freeMemory: tmp]; + OFFreeMemory(tmp); } /* * We do not count in bytes when writing to the Win32 console. But * since any incomplete write is an exception here anyway, we can just @@ -493,14 +482,11 @@ return; csbi.wAttributes &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY); - [color getRed: &red - green: &green - blue: &blue - alpha: NULL]; + [color getRed: &red green: &green blue: &blue alpha: NULL]; if (red >= 0.25) csbi.wAttributes |= FOREGROUND_RED; if (green >= 0.25) csbi.wAttributes |= FOREGROUND_GREEN; @@ -522,14 +508,11 @@ return; csbi.wAttributes &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY); - [color getRed: &red - green: &green - blue: &blue - alpha: NULL]; + [color getRed: &red green: &green blue: &blue alpha: NULL]; if (red >= 0.25) csbi.wAttributes |= BACKGROUND_RED; if (green >= 0.25) csbi.wAttributes |= BACKGROUND_GREEN; @@ -595,19 +578,19 @@ csbi.dwCursorPosition.X = column; SetConsoleCursorPosition(_handle, csbi.dwCursorPosition); } -- (void)setCursorPosition: (of_point_t)position +- (void)setCursorPosition: (OFPoint)position { if (position.x < 0 || position.y < 0) @throw [OFInvalidArgumentException exception]; SetConsoleCursorPosition(_handle, (COORD){ position.x, position.y }); } -- (void)setRelativeCursorPosition: (of_point_t)position +- (void)setRelativeCursorPosition: (OFPoint)position { CONSOLE_SCREEN_BUFFER_INFO csbi; if (!GetConsoleScreenBufferInfo(_handle, &csbi)) return; Index: src/OFWindowsRegistryKey.h ================================================================== --- src/OFWindowsRegistryKey.h +++ src/OFWindowsRegistryKey.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -76,30 +74,28 @@ * @brief Opens the subkey at the specified path. * * @param path The path of the subkey to open * @param securityAndAccessRights Please refer to the `RegOpenKeyEx()` * documentation for `samDesired` - * @return The subkey with the specified path, or nil if it does not exist + * @return The subkey with the specified path */ -- (nullable OFWindowsRegistryKey *) - openSubkeyAtPath: (OFString *)path - securityAndAccessRights: (REGSAM)securityAndAccessRights; +- (OFWindowsRegistryKey *)openSubkeyAtPath: (OFString *)path + securityAndAccessRights: (REGSAM)securityAndAccessRights; /** * @brief Opens the subkey at the specified path. * * @param path The path of the subkey to open * @param options Please refer to the `RegOpenKeyEx()` documentation for * `ulOptions`. Usually 0. * @param securityAndAccessRights Please refer to the `RegOpenKeyEx()` * documentation for `samDesired` - * @return The subkey with the specified path, or nil if it does not exist + * @return The subkey with the specified path */ -- (nullable OFWindowsRegistryKey *) - openSubkeyAtPath: (OFString *)path - options: (DWORD)options - securityAndAccessRights: (REGSAM)securityAndAccessRights; +- (OFWindowsRegistryKey *)openSubkeyAtPath: (OFString *)path + options: (DWORD)options + securityAndAccessRights: (REGSAM)securityAndAccessRights; /** * @brief Creates a subkey at the specified path or opens it if it already * exists. * @@ -136,72 +132,104 @@ disposition: (nullable DWORD *)disposition; /** * @brief Returns the data for the specified value at the specified path. * - * @param value 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 - */ -- (nullable OFData *)dataForValue: (nullable OFString *)value - type: (nullable DWORD *)type; - -/** - * @brief Sets the data for the specified value. - * - * @param data The data to set the value to - * @param value The name of the value to set - * @param type The type for the value - */ -- (void)setData: (nullable OFData *)data - forValue: (nullable OFString *)value - type: (DWORD)type; - -/** - * @brief Returns the string for the specified value at the specified path. - * - * @param value The name of the value to return - * @return The string for the specified value - */ -- (nullable OFString *)stringForValue: (nullable OFString *)value; - -/** - * @brief Returns the string for the specified value at the specified path. - * - * @param value 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 - */ -- (nullable OFString *)stringForValue: (nullable OFString *)value - type: (nullable DWORD *)type; - -/** - * @brief Sets the string for the specified value. - * - * @param string The string to set the value to - * @param value The name of the value to set - */ -- (void)setString: (nullable OFString *)string - forValue: (nullable OFString *)value; - -/** - * @brief Sets the string for the specified value. - * - * @param string The string to set the value to - * @param value The name of the value to set - * @param type The type for the value - */ -- (void)setString: (nullable OFString *)string - forValue: (nullable OFString *)value - type: (DWORD)type; - -/** - * @brief Deletes the specified value. - * - * @param value The value to delete - */ -- (void)deleteValue: (nullable OFString *)value; + * @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 + */ +- (nullable OFData *)dataForValueNamed: (nullable OFString *)name + type: (nullable DWORD *)type; + +/** + * @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 + */ +- (void)setData: (nullable OFData *)data + forValueNamed: (nullable OFString *)name + type: (DWORD)type; + +/** + * @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 + */ +- (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 + */ +- (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 + */ +- (void)setString: (nullable OFString *)string + forValueNamed: (nullable OFString *)name; + +/** + * @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 + */ +- (void)setString: (nullable OFString *)string + forValueNamed: (nullable OFString *)name + type: (DWORD)type; + +/** + * @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 + */ +- (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 + */ +- (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 + */ +- (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 + */ +- (void)setQWORD: (uint64_t)qword forValueNamed: (nullable OFString *)name; + +/** + * @brief Deletes the specified value. + * + * @param name The value to delete + */ +- (void)deleteValueNamed: (nullable OFString *)name; /** * @brief Deletes the specified subkey. * * @param subkeyPath The path of the subkey to delete Index: src/OFWindowsRegistryKey.m ================================================================== --- src/OFWindowsRegistryKey.m +++ src/OFWindowsRegistryKey.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -31,15 +29,15 @@ #import "OFInvalidEncodingException.h" #import "OFInvalidFormatException.h" #import "OFOpenWindowsRegistryKeyFailedException.h" #import "OFOutOfRangeException.h" #import "OFSetWindowsRegistryValueFailedException.h" +#import "OFUndefinedKeyException.h" OF_DIRECT_MEMBERS @interface OFWindowsRegistryKey () -- (instancetype)of_initWithHKey: (HKEY)hKey - close: (bool)close; +- (instancetype)of_initWithHKey: (HKEY)hKey close: (bool)close; @end @implementation OFWindowsRegistryKey + (instancetype)classesRootKey { @@ -69,12 +67,11 @@ { return [[[self alloc] of_initWithHKey: HKEY_USERS close: false] autorelease]; } -- (instancetype)of_initWithHKey: (HKEY)hKey - close: (bool)close +- (instancetype)of_initWithHKey: (HKEY)hKey close: (bool)close { self = [super init]; _hKey = hKey; _close = close; @@ -117,23 +114,17 @@ else status = RegOpenKeyExA(_hKey, [path cStringWithEncoding: [OFLocale encoding]], options, securityAndAccessRights, &subKey); - if (status != ERROR_SUCCESS) { - if (status == ERROR_FILE_NOT_FOUND) { - objc_autoreleasePoolPop(pool); - return nil; - } - + if (status != ERROR_SUCCESS) @throw [OFOpenWindowsRegistryKeyFailedException exceptionWithRegistryKey: self path: path options: options securityAndAccessRights: securityAndAccessRights status: status]; - } objc_autoreleasePoolPop(pool); return [[[OFWindowsRegistryKey alloc] of_initWithHKey: subKey close: true] @@ -185,12 +176,11 @@ return [[[OFWindowsRegistryKey alloc] of_initWithHKey: subKey close: true] autorelease]; } -- (OFData *)dataForValue: (OFString *)value - type: (DWORD *)type +- (OFData *)dataForValueNamed: (OFString *)name type: (DWORD *)type { void *pool = objc_autoreleasePoolPush(); BYTE stackBuffer[256], *buffer = stackBuffer; DWORD length = sizeof(stackBuffer); OFMutableData *ret = nil; @@ -197,15 +187,15 @@ bool winNT = [OFSystemInfo isWindowsNT]; LSTATUS status; for (;;) { if (winNT) - status = RegQueryValueExW(_hKey, value.UTF16String, + status = RegQueryValueExW(_hKey, name.UTF16String, NULL, type, buffer, &length); else status = RegQueryValueExA(_hKey, - [value cStringWithEncoding: [OFLocale encoding]], + [name cStringWithEncoding: [OFLocale encoding]], NULL, type, buffer, &length); switch (status) { case ERROR_SUCCESS: if (buffer == stackBuffer) { @@ -235,56 +225,53 @@ continue; default: @throw [OFGetWindowsRegistryValueFailedException exceptionWithRegistryKey: self - value: value + valueName: name status: status]; } } } - (void)setData: (OFData *)data - forValue: (OFString *)value + forValueNamed: (OFString *)name type: (DWORD)type { size_t length = data.count * data.itemSize; LSTATUS status; if (length > UINT32_MAX) @throw [OFOutOfRangeException exception]; if ([OFSystemInfo isWindowsNT]) - status = RegSetValueExW(_hKey, value.UTF16String, 0, type, + status = RegSetValueExW(_hKey, name.UTF16String, 0, type, data.items, (DWORD)length); else status = RegSetValueExA(_hKey, - [value cStringWithEncoding: [OFLocale encoding]], 0, type, + [name cStringWithEncoding: [OFLocale encoding]], 0, type, data.items, (DWORD)length); if (status != ERROR_SUCCESS) @throw [OFSetWindowsRegistryValueFailedException exceptionWithRegistryKey: self - value: value + valueName: name data: data type: type status: status]; } -- (OFString *)stringForValue: (OFString *)value +- (OFString *)stringForValueNamed: (OFString *)name { - return [self stringForValue: value - type: NULL]; + return [self stringForValueNamed: name type: NULL]; } -- (OFString *)stringForValue: (OFString *)value - type: (DWORD *)typeOut +- (OFString *)stringForValueNamed: (OFString *)name type: (DWORD *)typeOut { void *pool = objc_autoreleasePoolPush(); DWORD type; - OFData *data = [self dataForValue: value - type: &type]; + OFData *data = [self dataForValueNamed: name type: &type]; OFString *ret; if (data == nil) return nil; @@ -293,11 +280,11 @@ if (data.itemSize != 1) @throw [OFInvalidFormatException exception]; if ([OFSystemInfo isWindowsNT]) { - const of_char16_t *UTF16String = data.items; + const OFChar16 *UTF16String = data.items; size_t length = data.count; if (length % 2 == 1) @throw [OFInvalidFormatException exception]; @@ -342,60 +329,119 @@ objc_autoreleasePoolPop(pool); return [ret autorelease]; } -- (void)setString: (OFString *)string - forValue: (OFString *)value +- (void)setString: (OFString *)string forValueNamed: (OFString *)name { - [self setString: string - forValue: value - type: REG_SZ]; + [self setString: string forValueNamed: name type: REG_SZ]; } - (void)setString: (OFString *)string - forValue: (OFString *)value + forValueNamed: (OFString *)name type: (DWORD)type { void *pool = objc_autoreleasePoolPush(); OFData *data; if ([OFSystemInfo isWindowsNT]) data = [OFData dataWithItems: string.UTF16String - itemSize: sizeof(of_char16_t) - count: string.UTF16StringLength + 1]; + count: string.UTF16StringLength + 1 + itemSize: sizeof(OFChar16)]; else { - of_string_encoding_t encoding = [OFLocale encoding]; + OFStringEncoding encoding = [OFLocale encoding]; const char *cString = [string cStringWithEncoding: encoding]; size_t length = [string cStringLengthWithEncoding: encoding]; - data = [OFData dataWithItems: cString - count: length + 1]; + data = [OFData dataWithItems: cString count: length + 1]; } - [self setData: data - forValue: value - type: type]; + [self setData: data forValueNamed: name type: type]; + + objc_autoreleasePoolPop(pool); +} + +- (uint32_t)DWORDForValueNamed: (OFString *)name +{ + void *pool = objc_autoreleasePoolPush(); + DWORD type, ret; + OFData *data = [self dataForValueNamed: name type: &type]; + + if (data == nil) + @throw [OFUndefinedKeyException exceptionWithObject: self + key: name + value: nil]; + + if (type != REG_DWORD) + @throw [OFInvalidEncodingException exception]; + + if (data.count != sizeof(ret) || data.itemSize != 1) + @throw [OFInvalidFormatException exception]; + + memcpy(&ret, data.items, sizeof(ret)); + + objc_autoreleasePoolPop(pool); + + return ret; +} + +- (void)setDWORD: (uint32_t)dword forValueNamed: (OFString *)name +{ + void *pool = objc_autoreleasePoolPush(); + OFData *data = [OFData dataWithItems: &dword count: sizeof(dword)]; + [self setData: data forValueNamed: name type: REG_DWORD]; + objc_autoreleasePoolPop(pool); +} + +- (uint64_t)QWORDForValueNamed: (OFString *)name +{ + void *pool = objc_autoreleasePoolPush(); + DWORD type; + uint64_t ret; + OFData *data = [self dataForValueNamed: name type: &type]; + + if (data == nil) + @throw [OFUndefinedKeyException exceptionWithObject: self + key: name + value: nil]; + + if (type != REG_QWORD) + @throw [OFInvalidEncodingException exception]; + + if (data.count != sizeof(ret) || data.itemSize != 1) + @throw [OFInvalidFormatException exception]; + + memcpy(&ret, data.items, sizeof(ret)); + + objc_autoreleasePoolPop(pool); + + return ret; +} +- (void)setQWORD: (uint64_t)qword forValueNamed: (OFString *)name +{ + void *pool = objc_autoreleasePoolPush(); + OFData *data = [OFData dataWithItems: &qword count: sizeof(qword)]; + [self setData: data forValueNamed: name type: REG_QWORD]; objc_autoreleasePoolPop(pool); } -- (void)deleteValue: (OFString *)value +- (void)deleteValueNamed: (OFString *)name { void *pool = objc_autoreleasePoolPush(); LSTATUS status; if ([OFSystemInfo isWindowsNT]) - status = RegDeleteValueW(_hKey, value.UTF16String); + status = RegDeleteValueW(_hKey, name.UTF16String); else status = RegDeleteValueA(_hKey, - [value cStringWithEncoding: [OFLocale encoding]]); + [name cStringWithEncoding: [OFLocale encoding]]); if (status != ERROR_SUCCESS) @throw [OFDeleteWindowsRegistryValueFailedException exceptionWithRegistryKey: self - value: value + valueName: name status: status]; objc_autoreleasePoolPop(pool); } Index: src/OFXMLAttribute.h ================================================================== --- src/OFXMLAttribute.h +++ src/OFXMLAttribute.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -46,11 +44,11 @@ */ #ifndef __cplusplus @property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFString *namespace; #else @property OF_NULLABLE_PROPERTY (readonly, nonatomic, getter=namespace) - OFString *namespace_; + OFString *nameSpace; #endif /** * @brief Creates a new XML attribute. * @@ -63,16 +61,16 @@ /** * @brief Creates a new XML attribute. * * @param name The name of the attribute - * @param namespace_ The namespace of the attribute + * @param nameSpace The namespace of the attribute * @param stringValue The string value of the attribute * @return A new autoreleased OFXMLAttribute with the specified parameters */ + (instancetype)attributeWithName: (OFString *)name - namespace: (nullable OFString *)namespace_ + namespace: (nullable OFString *)nameSpace stringValue: (OFString *)stringValue; /** * @brief Initializes an already allocated OFXMLAttribute. * @@ -85,17 +83,17 @@ /** * @brief Initializes an already allocated OFXMLAttribute. * * @param name The name of the attribute - * @param namespace_ The namespace of the attribute + * @param nameSpace The namespace of the attribute * @param stringValue The string value of the attribute * @return An initialized OFXMLAttribute with the specified parameters */ - (instancetype)initWithName: (OFString *)name - namespace: (nullable OFString *)namespace_ + namespace: (nullable OFString *)nameSpace stringValue: (OFString *)stringValue; - (instancetype)initWithSerialization: (OFXMLElement *)element; @end OF_ASSUME_NONNULL_END Index: src/OFXMLAttribute.m ================================================================== --- src/OFXMLAttribute.m +++ src/OFXMLAttribute.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -76,11 +74,11 @@ @try { void *pool = objc_autoreleasePoolPush(); if (![element.name isEqual: self.className] || - ![element.namespace isEqual: OF_SERIALIZATION_NS]) + ![element.namespace isEqual: OFSerializationNS]) @throw [OFInvalidArgumentException exception]; _name = [[element attributeForName: @"name"].stringValue copy]; _namespace = [[element attributeForName: @"namespace"] .stringValue copy]; @@ -140,19 +138,19 @@ return true; } - (unsigned long)hash { - uint32_t hash; - - OF_HASH_INIT(hash); - - OF_HASH_ADD_HASH(hash, _name.hash); - OF_HASH_ADD_HASH(hash, _namespace.hash); - OF_HASH_ADD_HASH(hash, _stringValue.hash); - - OF_HASH_FINALIZE(hash); + unsigned long hash; + + OFHashInit(&hash); + + OFHashAddHash(&hash, _name.hash); + OFHashAddHash(&hash, _namespace.hash); + OFHashAddHash(&hash, _stringValue.hash); + + OFHashFinalize(&hash); return hash; } - (OFXMLElement *)XMLElementBySerializing @@ -159,14 +157,12 @@ { void *pool = objc_autoreleasePoolPush(); OFXMLElement *element; element = [OFXMLElement elementWithName: self.className - namespace: OF_SERIALIZATION_NS]; - - [element addAttributeWithName: @"name" - stringValue: _name]; + namespace: OFSerializationNS]; + [element addAttributeWithName: @"name" stringValue: _name]; if (_namespace != nil) [element addAttributeWithName: @"namespace" stringValue: _namespace]; Index: src/OFXMLCDATA.h ================================================================== --- src/OFXMLCDATA.h +++ src/OFXMLCDATA.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFXMLCDATA.m ================================================================== --- src/OFXMLCDATA.m +++ src/OFXMLCDATA.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -50,11 +48,11 @@ @try { void *pool = objc_autoreleasePoolPush(); if (![element.name isEqual: self.className] || - ![element.namespace isEqual: OF_SERIALIZATION_NS]) + ![element.namespace isEqual: OFSerializationNS]) @throw [OFInvalidArgumentException exception]; _CDATA = [element.stringValue copy]; objc_autoreleasePoolPop(pool); @@ -122,11 +120,11 @@ { return self.XMLString; } - (OFString *)XMLStringWithIndentation: (unsigned int)indentation - level: (unsigned int)level + level: (unsigned int)level { return self.XMLString; } - (OFString *)description @@ -136,11 +134,11 @@ - (OFXMLElement *)XMLElementBySerializing { OFXMLElement *element = [OFXMLElement elementWithName: self.className - namespace: OF_SERIALIZATION_NS]; + namespace: OFSerializationNS]; [element addChild: self]; return element; } @end Index: src/OFXMLCharacters.h ================================================================== --- src/OFXMLCharacters.h +++ src/OFXMLCharacters.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFXMLCharacters.m ================================================================== --- src/OFXMLCharacters.m +++ src/OFXMLCharacters.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -50,11 +48,11 @@ @try { void *pool = objc_autoreleasePoolPush(); if (![element.name isEqual: self.className] || - ![element.namespace isEqual: OF_SERIALIZATION_NS]) + ![element.namespace isEqual: OFSerializationNS]) @throw [OFInvalidArgumentException exception]; _characters = [element.stringValue copy]; objc_autoreleasePoolPop(pool); @@ -127,9 +125,9 @@ } - (OFXMLElement *)XMLElementBySerializing { return [OFXMLElement elementWithName: self.className - namespace: OF_SERIALIZATION_NS + namespace: OFSerializationNS stringValue: _characters]; } @end Index: src/OFXMLComment.h ================================================================== --- src/OFXMLComment.h +++ src/OFXMLComment.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -24,30 +22,35 @@ * * @brief A class for representing XML comments. */ @interface OFXMLComment: OFXMLNode { - OFString *_comment; + OFString *_text; OF_RESERVE_IVARS(OFXMLComment, 4) } /** - * @brief Creates a new OFXMLComment with the specified string. + * @brief The comment text. + */ +@property (readonly, nonatomic) OFString *text; + +/** + * @brief Creates a new OFXMLComment with the specified text. * - * @param string The string for the comment + * @param text The text for the comment * @return A new OFXMLComment */ -+ (instancetype)commentWithString: (OFString *)string; ++ (instancetype)commentWithText: (OFString *)text; /** * @brief Initializes an already allocated OFXMLComment with the specified - * string. + * text. * - * @param string The string for the comment + * @param text The text for the comment * @return An initialized OFXMLComment */ -- (instancetype)initWithString: (OFString *)string; +- (instancetype)initWithText: (OFString *)text; - (instancetype)initWithSerialization: (OFXMLElement *)element; @end OF_ASSUME_NONNULL_END Index: src/OFXMLComment.m ================================================================== --- src/OFXMLComment.m +++ src/OFXMLComment.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -25,21 +23,23 @@ #import "OFXMLElement.h" #import "OFInvalidArgumentException.h" @implementation OFXMLComment -+ (instancetype)commentWithString: (OFString *)string +@synthesize text = _text; + ++ (instancetype)commentWithText: (OFString *)text { - return [[[self alloc] initWithString: string] autorelease]; + return [[[self alloc] initWithText: text] autorelease]; } -- (instancetype)initWithString: (OFString *)string +- (instancetype)initWithText: (OFString *)text { self = [super of_init]; @try { - _comment = [string copy]; + _text = [text copy]; } @catch (id e) { [self release]; @throw e; } @@ -52,14 +52,14 @@ @try { void *pool = objc_autoreleasePoolPush(); if (![element.name isEqual: self.className] || - ![element.namespace isEqual: OF_SERIALIZATION_NS]) + ![element.namespace isEqual: OFSerializationNS]) @throw [OFInvalidArgumentException exception]; - _comment = [element.stringValue copy]; + _text = [element.stringValue copy]; objc_autoreleasePoolPop(pool); } @catch (id e) { [self release]; @throw e; @@ -68,11 +68,11 @@ return self; } - (void)dealloc { - [_comment release]; + [_text release]; [super dealloc]; } - (bool)isEqual: (id)object @@ -85,64 +85,62 @@ if (![object isKindOfClass: [OFXMLComment class]]) return false; comment = object; - return ([comment->_comment isEqual: _comment]); + return ([comment->_text isEqual: _text]); } - (unsigned long)hash { - return _comment.hash; + return _text.hash; } - (OFString *)stringValue { return @""; } - (OFString *)XMLString { - return [OFString stringWithFormat: @"", _comment]; + return [OFString stringWithFormat: @"", _text]; } - (OFString *)XMLStringWithIndentation: (unsigned int)indentation { - return [OFString stringWithFormat: @"", _comment]; + return [OFString stringWithFormat: @"", _text]; } - (OFString *)XMLStringWithIndentation: (unsigned int)indentation level: (unsigned int)level { OFString *ret; if (indentation > 0 && level > 0) { - char *whitespaces = [self allocMemoryWithSize: - (level * indentation) + 1]; + char *whitespaces = OFAllocMemory((level * indentation) + 1, 1); memset(whitespaces, ' ', level * indentation); whitespaces[level * indentation] = 0; @try { ret = [OFString stringWithFormat: @"%s", - whitespaces, - _comment]; + whitespaces, _text]; } @finally { - [self freeMemory: whitespaces]; + OFFreeMemory(whitespaces); } } else - ret = [OFString stringWithFormat: @"", _comment]; + ret = [OFString stringWithFormat: @"", _text]; return ret; } - (OFString *)description { - return [OFString stringWithFormat: @"", _comment]; + return [OFString stringWithFormat: @"", _text]; } - (OFXMLElement *)XMLElementBySerializing { return [OFXMLElement elementWithName: self.className - namespace: OF_SERIALIZATION_NS - stringValue: _comment]; + namespace: OFSerializationNS + stringValue: _text]; } @end Index: src/OFXMLElement+Serialization.h ================================================================== --- src/OFXMLElement+Serialization.h +++ src/OFXMLElement+Serialization.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFXMLElement+Serialization.m ================================================================== --- src/OFXMLElement+Serialization.m +++ src/OFXMLElement+Serialization.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -32,11 +30,11 @@ void *pool = objc_autoreleasePoolPush(); Class class; id object; if ((class = objc_getClass([_name cStringWithEncoding: - OF_STRING_ENCODING_ASCII])) == Nil) + OFStringEncodingASCII])) == Nil) @throw [OFInvalidArgumentException exception]; if (![class conformsToProtocol: @protocol(OFSerialization)]) @throw [OFInvalidArgumentException exception]; Index: src/OFXMLElement.h ================================================================== --- src/OFXMLElement.h +++ src/OFXMLElement.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -21,10 +19,11 @@ @class OFArray OF_GENERIC(ObjectType); @class OFMutableArray OF_GENERIC(ObjectType); @class OFMutableDictionary OF_GENERIC(KeyType, ObjectType); @class OFMutableString; +@class OFStream; @class OFString; @class OFXMLAttribute; /** * @class OFXMLElement OFXMLElement.h ObjFW/OFXMLElement.h @@ -51,11 +50,11 @@ */ #ifndef __cplusplus @property OF_NULLABLE_PROPERTY (copy, nonatomic) OFString *namespace; #else @property OF_NULLABLE_PROPERTY (copy, nonatomic, - getter=namespace, setter=setNamespace:) OFString *namespace_; + getter=namespace, setter=setNamespace:) OFString *nameSpace; #endif /** * @brief The default namespace for the element to be used if there is no * parent. @@ -100,29 +99,29 @@ /** * @brief Creates a new XML element with the specified name and namespace. * * @param name The name for the element - * @param namespace_ The namespace for the element + * @param nameSpace The namespace for the element * @return A new autoreleased OFXMLElement with the specified element name and * namespace */ + (instancetype)elementWithName: (OFString *)name - namespace: (nullable OFString *)namespace_; + namespace: (nullable OFString *)nameSpace; /** * @brief Creates a new XML element with the specified name, namespace and * string value. * * @param name The name for the element - * @param namespace_ The namespace for the element + * @param nameSpace The namespace for the element * @param stringValue The value for the element * @return A new autoreleased OFXMLElement with the specified element name, * namespace and value */ + (instancetype)elementWithName: (OFString *)name - namespace: (nullable OFString *)namespace_ + namespace: (nullable OFString *)nameSpace stringValue: (nullable OFString *)stringValue; /** * @brief Creates a new element with the specified element. * @@ -138,20 +137,18 @@ * @param string The string to parse * @return A new autoreleased OFXMLElement with the contents of the string */ + (instancetype)elementWithXMLString: (OFString *)string; -#ifdef OF_HAVE_FILES /** - * @brief Parses the specified file and returns an OFXMLElement for it. + * @brief Parses the specified stream and returns an OFXMLElement for it. * - * @param path The path to the file + * @param stream The stream to parse * @return A new autoreleased OFXMLElement with the contents of the specified - * file + * stream */ -+ (instancetype)elementWithFile: (OFString *)path; -#endif ++ (instancetype)elementWithStream: (OFStream *)stream; - (instancetype)init OF_UNAVAILABLE; /** * @brief Initializes an already allocated OFXMLElement with the specified name. @@ -176,29 +173,29 @@ /** * @brief Initializes an already allocated OFXMLElement with the specified name * and namespace. * * @param name The name for the element - * @param namespace_ The namespace for the element + * @param nameSpace The namespace for the element * @return An initialized OFXMLElement with the specified element name and * namespace */ - (instancetype)initWithName: (OFString *)name - namespace: (nullable OFString *)namespace_; + namespace: (nullable OFString *)nameSpace; /** * @brief Initializes an already allocated OFXMLElement with the specified name, * namespace and value. * * @param name The name for the element - * @param namespace_ The namespace for the element + * @param nameSpace The namespace for the element * @param stringValue The value for the element * @return An initialized OFXMLElement with the specified element name, * namespace and value */ - (instancetype)initWithName: (OFString *)name - namespace: (nullable OFString *)namespace_ + namespace: (nullable OFString *)nameSpace stringValue: (nullable OFString *)stringValue; /** * @brief Initializes an already allocated OFXMLElement with the specified * element. @@ -216,40 +213,36 @@ * @param string The string to parse * @return An initialized OFXMLElement with the contents of the string */ - (instancetype)initWithXMLString: (OFString *)string; -#ifdef OF_HAVE_FILES /** - * @brief Parses the specified file and initializes an already allocated + * @brief Parses the specified stream and initializes an already allocated * OFXMLElement with it. * - * @param path The path to the file - * @return An initialized OFXMLElement with the contents of the specified file + * @param stream The stream to parse + * @return An initialized OFXMLElement with the contents of the specified stream */ -- (instancetype)initWithFile: (OFString *)path; -#endif +- (instancetype)initWithStream: (OFStream *)stream; - (instancetype)initWithSerialization: (OFXMLElement *)element; /** * @brief Sets a prefix for a namespace. * * @param prefix The prefix for the namespace - * @param namespace_ The namespace for which the prefix is set + * @param nameSpace The namespace for which the prefix is set */ -- (void)setPrefix: (OFString *)prefix - forNamespace: (OFString *)namespace_; +- (void)setPrefix: (OFString *)prefix forNamespace: (OFString *)nameSpace; /** * @brief Binds a prefix for a namespace. * * @param prefix The prefix for the namespace - * @param namespace_ The namespace for which the prefix is bound + * @param nameSpace The namespace for which the prefix is bound */ -- (void)bindPrefix: (OFString *)prefix - forNamespace: (OFString *)namespace_; +- (void)bindPrefix: (OFString *)prefix forNamespace: (OFString *)nameSpace; /** * @brief Adds the specified attribute. * * If an attribute with the same name and namespace already exists, it is not @@ -277,15 +270,15 @@ * * If an attribute with the same name and namespace already exists, it is not * added. * * @param name The name of the attribute - * @param namespace_ The namespace of the attribute + * @param nameSpace The namespace of the attribute * @param stringValue The value of the attribute */ - (void)addAttributeWithName: (OFString *)name - namespace: (nullable OFString *)namespace_ + namespace: (nullable OFString *)nameSpace stringValue: (OFString *)stringValue; /** * @brief Returns the attribute with the specified name. * @@ -331,12 +324,11 @@ * @brief Inserts a child at the specified index. * * @param child An OFXMLNode which is added as a child * @param index The index where the child is added */ -- (void)insertChild: (OFXMLNode *)child - atIndex: (size_t)index; +- (void)insertChild: (OFXMLNode *)child atIndex: (size_t)index; /** * @brief Inserts the specified children at the specified index. * * @param children An array of OFXMLNodes which are added as children @@ -364,21 +356,19 @@ * with the specified node. * * @param child The child to replace * @param node The node to replace the child with */ -- (void)replaceChild: (OFXMLNode *)child - withNode: (OFXMLNode *)node; +- (void)replaceChild: (OFXMLNode *)child withNode: (OFXMLNode *)node; /** * @brief Replaces the child at the specified index with the specified node. * * @param index The index of the child to replace * @param node The node to replace the child with */ -- (void)replaceChildAtIndex: (size_t)index - withNode: (OFXMLNode *)node; +- (void)replaceChildAtIndex: (size_t)index withNode: (OFXMLNode *)node; /** * @brief Returns all children that have the specified namespace. * * @return All children that have the specified namespace Index: src/OFXMLElement.m ================================================================== --- src/OFXMLElement.m +++ src/OFXMLElement.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -23,20 +21,21 @@ #include #include #import "OFXMLElement.h" -#import "OFXMLNode+Private.h" -#import "OFString.h" #import "OFArray.h" -#import "OFDictionary.h" #import "OFData.h" +#import "OFDictionary.h" +#import "OFStream.h" +#import "OFString.h" #import "OFXMLAttribute.h" -#import "OFXMLCharacters.h" #import "OFXMLCDATA.h" -#import "OFXMLParser.h" +#import "OFXMLCharacters.h" #import "OFXMLElementBuilder.h" +#import "OFXMLNode+Private.h" +#import "OFXMLParser.h" #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFMalformedXMLException.h" #import "OFUnboundNamespaceException.h" @@ -46,13 +45,10 @@ _references_to_categories_of_OFXMLElement(void) { _OFXMLElement_Serialization_reference = 1; } -static Class charactersClass = Nil; -static Class CDATAClass = Nil; - @interface OFXMLElementElementBuilderDelegate: OFObject { @public OFXMLElement *_element; @@ -77,18 +73,10 @@ @implementation OFXMLElement @synthesize name = _name, namespace = _namespace; @synthesize defaultNamespace = _defaultNamespace; -+ (void)initialize -{ - if (self == [OFXMLElement class]) { - charactersClass = [OFXMLCharacters class]; - CDATAClass = [OFXMLCDATA class]; - } -} - + (instancetype)elementWithName: (OFString *)name { return [[[self alloc] initWithName: name] autorelease]; } @@ -123,27 +111,23 @@ + (instancetype)elementWithXMLString: (OFString *)string { return [[[self alloc] initWithXMLString: string] autorelease]; } -#ifdef OF_HAVE_FILES -+ (instancetype)elementWithFile: (OFString *)path ++ (instancetype)elementWithStream: (OFStream *)stream { - return [[[self alloc] initWithFile: path] autorelease]; + return [[[self alloc] initWithStream: stream] autorelease]; } -#endif - (instancetype)init { OF_INVALID_INIT_METHOD } - (instancetype)initWithName: (OFString *)name { - return [self initWithName: name - namespace: nil - stringValue: nil]; + return [self initWithName: name namespace: nil stringValue: nil]; } - (instancetype)initWithName: (OFString *)name stringValue: (OFString *)stringValue { @@ -153,13 +137,11 @@ } - (instancetype)initWithName: (OFString *)name namespace: (OFString *)namespace { - return [self initWithName: name - namespace: namespace - stringValue: nil]; + return [self initWithName: name namespace: namespace stringValue: nil]; } - (instancetype)initWithName: (OFString *)name namespace: (OFString *)namespace stringValue: (OFString *)stringValue @@ -224,11 +206,11 @@ @throw [OFInvalidArgumentException exception]; pool = objc_autoreleasePoolPush(); parser = [OFXMLParser parser]; - builder = [OFXMLElementBuilder elementBuilder]; + builder = [OFXMLElementBuilder builder]; delegate = [[[OFXMLElementElementBuilderDelegate alloc] init] autorelease]; parser.delegate = builder; builder.delegate = delegate; @@ -243,12 +225,11 @@ objc_autoreleasePoolPop(pool); return self; } -#ifdef OF_HAVE_FILES -- (instancetype)initWithFile: (OFString *)path +- (instancetype)initWithStream: (OFStream *)stream { void *pool; OFXMLParser *parser; OFXMLElementBuilder *builder; OFXMLElementElementBuilderDelegate *delegate; @@ -256,18 +237,18 @@ [self release]; pool = objc_autoreleasePoolPush(); parser = [OFXMLParser parser]; - builder = [OFXMLElementBuilder elementBuilder]; + builder = [OFXMLElementBuilder builder]; delegate = [[[OFXMLElementElementBuilderDelegate alloc] init] autorelease]; parser.delegate = builder; builder.delegate = delegate; - [parser parseFile: path]; + [parser parseStream: stream]; if (!parser.hasFinishedParsing) @throw [OFMalformedXMLException exceptionWithParser: parser]; self = [delegate->_element retain]; @@ -274,11 +255,10 @@ objc_autoreleasePoolPop(pool); return self; } -#endif - (instancetype)initWithSerialization: (OFXMLElement *)element { self = [super of_init]; @@ -288,11 +268,11 @@ OFXMLElement *childrenElement; OFEnumerator *keyEnumerator, *objectEnumerator; OFString *key, *object; if (![element.name isEqual: self.className] || - ![element.namespace isEqual: OF_SERIALIZATION_NS]) + ![element.namespace isEqual: OFSerializationNS]) @throw [OFInvalidArgumentException exception]; _name = [[element attributeForName: @"name"].stringValue copy]; _namespace = [[element attributeForName: @"namespace"] .stringValue copy]; @@ -299,20 +279,20 @@ _defaultNamespace = [[element attributeForName: @"defaultNamespace"].stringValue copy]; attributesElement = [[element elementForName: @"attributes" - namespace: OF_SERIALIZATION_NS] elementsForNamespace: - OF_SERIALIZATION_NS].firstObject; + namespace: OFSerializationNS] elementsForNamespace: + OFSerializationNS].firstObject; namespacesElement = [[element elementForName: @"namespaces" - namespace: OF_SERIALIZATION_NS] elementsForNamespace: - OF_SERIALIZATION_NS].firstObject; + namespace: OFSerializationNS] elementsForNamespace: + OFSerializationNS].firstObject; childrenElement = [[element elementForName: @"children" - namespace: OF_SERIALIZATION_NS] elementsForNamespace: - OF_SERIALIZATION_NS].firstObject; + namespace: OFSerializationNS] elementsForNamespace: + OFSerializationNS].firstObject; _attributes = [attributesElement.objectByDeserializing mutableCopy]; _namespaces = [namespacesElement.objectByDeserializing mutableCopy]; @@ -424,11 +404,11 @@ return ret; } - (OFString *)of_XMLStringWithParent: (OFXMLElement *)parent - namespaces: (OFDictionary *)allNamespaces + namespaces: (OFDictionary *)allNS indentation: (unsigned int)indentation level: (unsigned int)level OF_DIRECT { void *pool; char *cString; @@ -437,33 +417,32 @@ OFString *ret; OFString *defaultNS; pool = objc_autoreleasePoolPush(); - parentPrefix = [allNamespaces objectForKey: + parentPrefix = [allNS objectForKey: (parent != nil && parent->_namespace != nil ? parent->_namespace : (OFString *)@"")]; /* Add the namespaces of the current element */ - if (allNamespaces != nil) { + if (allNS != nil) { OFEnumerator *keyEnumerator = [_namespaces keyEnumerator]; OFEnumerator *objectEnumerator = [_namespaces objectEnumerator]; OFMutableDictionary *tmp; OFString *key, *object; - tmp = [[allNamespaces mutableCopy] autorelease]; + tmp = [[allNS mutableCopy] autorelease]; while ((key = [keyEnumerator nextObject]) != nil && (object = [objectEnumerator nextObject]) != nil) - [tmp setObject: object - forKey: key]; + [tmp setObject: object forKey: key]; - allNamespaces = tmp; + allNS = tmp; } else - allNamespaces = _namespaces; + allNS = _namespaces; - prefix = [allNamespaces objectForKey: + prefix = [allNS objectForKey: (_namespace != nil ? _namespace : (OFString *)@"")]; if (parent != nil && parent->_namespace != nil && parentPrefix == nil) defaultNS = parent->_namespace; else if (parent != nil && parent->_defaultNamespace != nil) @@ -471,198 +450,178 @@ else defaultNS = _defaultNamespace; i = 0; length = _name.UTF8StringLength + 3 + (level * indentation); - cString = [self allocMemoryWithSize: length]; - - memset(cString + i, ' ', level * indentation); - i += level * indentation; - - /* Start of tag */ - cString[i++] = '<'; - - if (prefix != nil && ![_namespace isEqual: defaultNS]) { - length += prefix.UTF8StringLength + 1; - @try { - cString = [self resizeMemory: cString - size: length]; - } @catch (id e) { - [self freeMemory: cString]; - @throw e; - } - - memcpy(cString + i, prefix.UTF8String, prefix.UTF8StringLength); - i += prefix.UTF8StringLength; - cString[i++] = ':'; - } - - memcpy(cString + i, _name.UTF8String, _name.UTF8StringLength); - i += _name.UTF8StringLength; - - /* xmlns if necessary */ - if (prefix == nil && ((_namespace != nil && - ![_namespace isEqual: defaultNS]) || - (_namespace == nil && defaultNS != nil))) { - length += _namespace.UTF8StringLength + 9; - @try { - cString = [self resizeMemory: cString - size: length]; - } @catch (id e) { - [self freeMemory: cString]; - @throw e; - } - - memcpy(cString + i, " xmlns='", 8); - i += 8; - memcpy(cString + i, _namespace.UTF8String, - _namespace.UTF8StringLength); - i += _namespace.UTF8StringLength; - cString[i++] = '\''; - } - - /* Attributes */ - for (OFXMLAttribute *attribute in _attributes) { - void *pool2 = objc_autoreleasePoolPush(); - const char *attributeNameCString = attribute->_name.UTF8String; - size_t attributeNameLength = attribute->_name.UTF8StringLength; - OFString *attributePrefix = nil; - OFString *tmp = attribute.stringValue.stringByXMLEscaping; - char delimiter = (attribute->_useDoubleQuotes ? '"' : '\''); - - if (attribute->_namespace != nil && - (attributePrefix = [allNamespaces objectForKey: - attribute->_namespace]) == nil) - @throw [OFUnboundNamespaceException - exceptionWithNamespace: [attribute namespace] - element: self]; - - length += attributeNameLength + (attributePrefix != nil - ? attributePrefix.UTF8StringLength + 1 : 0) + - tmp.UTF8StringLength + 4; - - @try { - cString = [self resizeMemory: cString - size: length]; - } @catch (id e) { - [self freeMemory: cString]; - @throw e; - } - - cString[i++] = ' '; - if (attributePrefix != nil) { - memcpy(cString + i, attributePrefix.UTF8String, - attributePrefix.UTF8StringLength); - i += attributePrefix.UTF8StringLength; - cString[i++] = ':'; - } - memcpy(cString + i, attributeNameCString, attributeNameLength); - i += attributeNameLength; - cString[i++] = '='; - cString[i++] = delimiter; - memcpy(cString + i, tmp.UTF8String, tmp.UTF8StringLength); - i += tmp.UTF8StringLength; - cString[i++] = delimiter; - - objc_autoreleasePoolPop(pool2); - } - - /* Children */ - if (_children != nil) { - OFMutableData *tmp = [OFMutableData data]; - bool indent; - - if (indentation > 0) { - indent = true; - - for (OFXMLNode *child in _children) { - if ([child isKindOfClass: charactersClass] || - [child isKindOfClass: CDATAClass]) { - indent = false; - break; - } - } - } else - indent = false; - - for (OFXMLNode *child in _children) { - OFString *childString; - unsigned int ind = (indent ? indentation : 0); - - if (ind) - [tmp addItem: "\n"]; - - if ([child isKindOfClass: [OFXMLElement class]]) - childString = [(OFXMLElement *)child - of_XMLStringWithParent: self - namespaces: allNamespaces - indentation: ind - level: level + 1]; - else - childString = [child - XMLStringWithIndentation: ind - level: level + 1]; - - [tmp addItems: childString.UTF8String - count: childString.UTF8StringLength]; - } - - if (indent) - [tmp addItem: "\n"]; - - length += tmp.count + _name.UTF8StringLength + 2 + - (indent ? level * indentation : 0); - @try { - cString = [self resizeMemory: cString - size: length]; - } @catch (id e) { - [self freeMemory: cString]; - @throw e; - } - - cString[i++] = '>'; - - memcpy(cString + i, tmp.items, tmp.count); - i += tmp.count; - - if (indent) { - memset(cString + i, ' ', level * indentation); - i += level * indentation; - } - - cString[i++] = '<'; - cString[i++] = '/'; - if (prefix != nil) { - length += prefix.UTF8StringLength + 1; - @try { - cString = [self resizeMemory: cString - size: length]; - } @catch (id e) { - [self freeMemory: cString]; - @throw e; - } + cString = OFAllocMemory(length, 1); + + @try { + memset(cString + i, ' ', level * indentation); + i += level * indentation; + + /* Start of tag */ + cString[i++] = '<'; + + if (prefix != nil && ![_namespace isEqual: defaultNS]) { + length += prefix.UTF8StringLength + 1; + cString = OFResizeMemory(cString, length, 1); memcpy(cString + i, prefix.UTF8String, prefix.UTF8StringLength); i += prefix.UTF8StringLength; cString[i++] = ':'; } + memcpy(cString + i, _name.UTF8String, _name.UTF8StringLength); i += _name.UTF8StringLength; - } else - cString[i++] = '/'; - - cString[i++] = '>'; - assert(i == length); - - objc_autoreleasePoolPop(pool); - - @try { + + /* xmlns if necessary */ + if (prefix == nil && ((_namespace != nil && + ![_namespace isEqual: defaultNS]) || + (_namespace == nil && defaultNS != nil))) { + length += _namespace.UTF8StringLength + 9; + cString = OFResizeMemory(cString, length, 1); + + memcpy(cString + i, " xmlns='", 8); + i += 8; + memcpy(cString + i, _namespace.UTF8String, + _namespace.UTF8StringLength); + i += _namespace.UTF8StringLength; + cString[i++] = '\''; + } + + /* Attributes */ + for (OFXMLAttribute *attribute in _attributes) { + void *pool2 = objc_autoreleasePoolPush(); + const char *attributeNameCString = + attribute->_name.UTF8String; + size_t attributeNameLength = + attribute->_name.UTF8StringLength; + OFString *attributePrefix = nil; + OFString *tmp = + attribute.stringValue.stringByXMLEscaping; + char delimiter = (attribute->_useDoubleQuotes + ? '"' : '\''); + + if (attribute->_namespace != nil && + (attributePrefix = [allNS objectForKey: + attribute->_namespace]) == nil) + @throw [OFUnboundNamespaceException + exceptionWithNamespace: attribute.namespace + element: self]; + + length += attributeNameLength + (attributePrefix != nil + ? attributePrefix.UTF8StringLength + 1 : 0) + + tmp.UTF8StringLength + 4; + cString = OFResizeMemory(cString, length, 1); + + cString[i++] = ' '; + if (attributePrefix != nil) { + memcpy(cString + i, attributePrefix.UTF8String, + attributePrefix.UTF8StringLength); + i += attributePrefix.UTF8StringLength; + cString[i++] = ':'; + } + memcpy(cString + i, attributeNameCString, + attributeNameLength); + i += attributeNameLength; + cString[i++] = '='; + cString[i++] = delimiter; + memcpy(cString + i, tmp.UTF8String, + tmp.UTF8StringLength); + i += tmp.UTF8StringLength; + cString[i++] = delimiter; + + objc_autoreleasePoolPop(pool2); + } + + /* Children */ + if (_children != nil) { + OFMutableData *tmp = [OFMutableData data]; + bool indent; + + if (indentation > 0) { + indent = true; + + for (OFXMLNode *child in _children) { + if ([child isKindOfClass: + [OFXMLCharacters class]] || + [child isKindOfClass: + [OFXMLCDATA class]]) { + indent = false; + break; + } + } + } else + indent = false; + + for (OFXMLNode *child in _children) { + OFString *childString; + unsigned int ind = (indent ? indentation : 0); + + if (ind) + [tmp addItem: "\n"]; + + if ([child isKindOfClass: [OFXMLElement class]]) + childString = [(OFXMLElement *)child + of_XMLStringWithParent: self + namespaces: allNS + indentation: ind + level: level + 1]; + else + childString = [child + XMLStringWithIndentation: ind + level: level + + 1]; + + [tmp addItems: childString.UTF8String + count: childString.UTF8StringLength]; + } + + if (indent) + [tmp addItem: "\n"]; + + length += tmp.count + _name.UTF8StringLength + 2 + + (indent ? level * indentation : 0); + cString = OFResizeMemory(cString, length, 1); + + cString[i++] = '>'; + + memcpy(cString + i, tmp.items, tmp.count); + i += tmp.count; + + if (indent) { + memset(cString + i, ' ', level * indentation); + i += level * indentation; + } + + cString[i++] = '<'; + cString[i++] = '/'; + if (prefix != nil) { + length += prefix.UTF8StringLength + 1; + cString = OFResizeMemory(cString, length, 1); + + memcpy(cString + i, prefix.UTF8String, + prefix.UTF8StringLength); + i += prefix.UTF8StringLength; + cString[i++] = ':'; + } + memcpy(cString + i, _name.UTF8String, + _name.UTF8StringLength); + i += _name.UTF8StringLength; + } else + cString[i++] = '/'; + + cString[i++] = '>'; + assert(i == length); + + objc_autoreleasePoolPop(pool); + ret = [OFString stringWithUTF8String: cString length: length]; } @finally { - [self freeMemory: cString]; + OFFreeMemory(cString); } return ret; } - (OFString *)XMLString @@ -694,15 +653,14 @@ { void *pool = objc_autoreleasePoolPush(); OFXMLElement *element; element = [OFXMLElement elementWithName: self.className - namespace: OF_SERIALIZATION_NS]; + namespace: OFSerializationNS]; if (_name != nil) - [element addAttributeWithName: @"name" - stringValue: _name]; + [element addAttributeWithName: @"name" stringValue: _name]; if (_namespace != nil) [element addAttributeWithName: @"namespace" stringValue: _namespace]; @@ -713,11 +671,11 @@ if (_attributes != nil) { OFXMLElement *attributesElement; attributesElement = [OFXMLElement elementWithName: @"attributes" - namespace: OF_SERIALIZATION_NS]; + namespace: OFSerializationNS]; [attributesElement addChild: _attributes.XMLElementBySerializing]; [element addChild: attributesElement]; } @@ -732,11 +690,11 @@ @"http://www.w3.org/2000/xmlns/"]; if (namespacesCopy.count > 0) { namespacesElement = [OFXMLElement elementWithName: @"namespaces" - namespace: OF_SERIALIZATION_NS]; + namespace: OFSerializationNS]; [namespacesElement addChild: namespacesCopy.XMLElementBySerializing]; [element addChild: namespacesElement]; } } @@ -744,11 +702,11 @@ if (_children != nil) { OFXMLElement *childrenElement; childrenElement = [OFXMLElement elementWithName: @"children" - namespace: OF_SERIALIZATION_NS]; + namespace: OFSerializationNS]; [childrenElement addChild: _children.XMLElementBySerializing]; [element addChild: childrenElement]; } [element retain]; @@ -852,27 +810,23 @@ return; } } } -- (void)setPrefix: (OFString *)prefix - forNamespace: (OFString *)namespace +- (void)setPrefix: (OFString *)prefix forNamespace: (OFString *)namespace { if (prefix.length == 0) @throw [OFInvalidArgumentException exception]; if (namespace == nil) namespace = @""; - [_namespaces setObject: prefix - forKey: namespace]; + [_namespaces setObject: prefix forKey: namespace]; } -- (void)bindPrefix: (OFString *)prefix - forNamespace: (OFString *)namespace +- (void)bindPrefix: (OFString *)prefix forNamespace: (OFString *)namespace { - [self setPrefix: prefix - forNamespace: namespace]; + [self setPrefix: prefix forNamespace: namespace]; [self addAttributeWithName: prefix namespace: @"http://www.w3.org/2000/xmlns/" stringValue: namespace]; } @@ -885,32 +839,28 @@ _children = [[OFMutableArray alloc] init]; [_children addObject: child]; } -- (void)insertChild: (OFXMLNode *)child - atIndex: (size_t)idx +- (void)insertChild: (OFXMLNode *)child atIndex: (size_t)idx { if ([child isKindOfClass: [OFXMLAttribute class]]) @throw [OFInvalidArgumentException exception]; if (_children == nil) _children = [[OFMutableArray alloc] init]; - [_children insertObject: child - atIndex: idx]; + [_children insertObject: child atIndex: idx]; } -- (void)insertChildren: (OFArray *)children - atIndex: (size_t)idx +- (void)insertChildren: (OFArray *)children atIndex: (size_t)idx { for (OFXMLNode *node in children) if ([node isKindOfClass: [OFXMLAttribute class]]) @throw [OFInvalidArgumentException exception]; - [_children insertObjectsFromArray: children - atIndex: idx]; + [_children insertObjectsFromArray: children atIndex: idx]; } - (void)removeChild: (OFXMLNode *)child { if ([child isKindOfClass: [OFXMLAttribute class]]) @@ -922,29 +872,25 @@ - (void)removeChildAtIndex: (size_t)idx { [_children removeObjectAtIndex: idx]; } -- (void)replaceChild: (OFXMLNode *)child - withNode: (OFXMLNode *)node +- (void)replaceChild: (OFXMLNode *)child withNode: (OFXMLNode *)node { if ([node isKindOfClass: [OFXMLAttribute class]] || [child isKindOfClass: [OFXMLAttribute class]]) @throw [OFInvalidArgumentException exception]; - [_children replaceObject: child - withObject: node]; + [_children replaceObject: child withObject: node]; } -- (void)replaceChildAtIndex: (size_t)idx - withNode: (OFXMLNode *)node +- (void)replaceChildAtIndex: (size_t)idx withNode: (OFXMLNode *)node { if ([node isKindOfClass: [OFXMLAttribute class]]) @throw [OFInvalidArgumentException exception]; - [_children replaceObjectAtIndex: idx - withObject: node]; + [_children replaceObjectAtIndex: idx withObject: node]; } - (OFXMLElement *)elementForName: (OFString *)elementName { return [self elementsForName: elementName].firstObject; @@ -1066,26 +1012,26 @@ return true; } - (unsigned long)hash { - uint32_t hash; - - OF_HASH_INIT(hash); - - OF_HASH_ADD_HASH(hash, _name.hash); - OF_HASH_ADD_HASH(hash, _namespace.hash); - OF_HASH_ADD_HASH(hash, _defaultNamespace.hash); - OF_HASH_ADD_HASH(hash, _attributes.hash); - OF_HASH_ADD_HASH(hash, _namespaces.hash); - OF_HASH_ADD_HASH(hash, _children.hash); - - OF_HASH_FINALIZE(hash); + unsigned long hash; + + OFHashInit(&hash); + + OFHashAddHash(&hash, _name.hash); + OFHashAddHash(&hash, _namespace.hash); + OFHashAddHash(&hash, _defaultNamespace.hash); + OFHashAddHash(&hash, _attributes.hash); + OFHashAddHash(&hash, _namespaces.hash); + OFHashAddHash(&hash, _children.hash); + + OFHashFinalize(&hash); return hash; } - (id)copy { return [[[self class] alloc] initWithElement: self]; } @end Index: src/OFXMLElementBuilder.h ================================================================== --- src/OFXMLElementBuilder.h +++ src/OFXMLElementBuilder.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -73,16 +71,16 @@ * an OFMalformedXMLException. * * @param builder The builder which did not expect the close tag * @param name The name of the close tag * @param prefix The prefix of the close tag - * @param namespace_ The namespace of the close tag + * @param nameSpace The namespace of the close tag */ - (void)elementBuilder: (OFXMLElementBuilder *)builder didNotExpectCloseTag: (OFString *)name prefix: (nullable OFString *)prefix - namespace: (nullable OFString *)namespace_; + namespace: (nullable OFString *)nameSpace; /** * @brief This callback is called when the XML parser for the element builder * found an unknown entity. * @@ -120,9 +118,9 @@ /** * @brief Creates a new element builder. * * @return A new, autoreleased OFXMLElementBuilder */ -+ (instancetype)elementBuilder; ++ (instancetype)builder; @end OF_ASSUME_NONNULL_END Index: src/OFXMLElementBuilder.m ================================================================== --- src/OFXMLElementBuilder.m +++ src/OFXMLElementBuilder.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -16,25 +14,25 @@ */ #include "config.h" #import "OFXMLElementBuilder.h" -#import "OFXMLElement.h" +#import "OFArray.h" #import "OFXMLAttribute.h" -#import "OFXMLCharacters.h" #import "OFXMLCDATA.h" +#import "OFXMLCharacters.h" #import "OFXMLComment.h" -#import "OFXMLProcessingInstructions.h" +#import "OFXMLElement.h" #import "OFXMLParser.h" -#import "OFArray.h" +#import "OFXMLProcessingInstruction.h" #import "OFMalformedXMLException.h" @implementation OFXMLElementBuilder @synthesize delegate = _delegate; -+ (instancetype)elementBuilder ++ (instancetype)builder { return [[[self alloc] init] autorelease]; } - (instancetype)init @@ -56,23 +54,24 @@ [_stack release]; [super dealloc]; } -- (void)parser: (OFXMLParser *)parser - foundProcessingInstructions: (OFString *)pi +- (void)parser: (OFXMLParser *)parser + foundProcessingInstructionWithTarget: (OFString *)target + data: (OFString *)data { - OFXMLProcessingInstructions *node = [OFXMLProcessingInstructions - processingInstructionsWithString: pi]; + OFXMLProcessingInstruction *node = [OFXMLProcessingInstruction + processingInstructionWithTarget: target + data: data]; OFXMLElement *parent = _stack.lastObject; if (parent != nil) [parent addChild: node]; else if ([_delegate respondsToSelector: @selector(elementBuilder:didBuildParentlessNode:)]) - [_delegate elementBuilder: self - didBuildParentlessNode: node]; + [_delegate elementBuilder: self didBuildParentlessNode: node]; } - (void)parser: (OFXMLParser *)parser didStartElement: (OFString *)name prefix: (OFString *)prefix @@ -136,12 +135,11 @@ if (parent != nil) [parent addChild: node]; else if ([_delegate respondsToSelector: @selector(elementBuilder:didBuildParentlessNode:)]) - [_delegate elementBuilder: self - didBuildParentlessNode: node]; + [_delegate elementBuilder: self didBuildParentlessNode: node]; } - (void)parser: (OFXMLParser *)parser foundCDATA: (OFString *)CDATA { @@ -150,26 +148,24 @@ if (parent != nil) [parent addChild: node]; else if ([_delegate respondsToSelector: @selector(elementBuilder:didBuildParentlessNode:)]) - [_delegate elementBuilder: self - didBuildParentlessNode: node]; + [_delegate elementBuilder: self didBuildParentlessNode: node]; } - (void)parser: (OFXMLParser *)parser foundComment: (OFString *)comment { - OFXMLComment *node = [OFXMLComment commentWithString: comment]; + OFXMLComment *node = [OFXMLComment commentWithText: comment]; OFXMLElement *parent = _stack.lastObject; if (parent != nil) [parent addChild: node]; else if ([_delegate respondsToSelector: @selector(elementBuilder:didBuildParentlessNode:)]) - [_delegate elementBuilder: self - didBuildParentlessNode: node]; + [_delegate elementBuilder: self didBuildParentlessNode: node]; } - (OFString *)parser: (OFXMLParser *)parser foundUnknownEntityNamed: (OFString *)entity { Index: src/OFXMLNode+Private.h ================================================================== --- src/OFXMLNode+Private.h +++ src/OFXMLNode+Private.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFXMLNode.h ================================================================== --- src/OFXMLNode.h +++ src/OFXMLNode.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFXMLNode.m ================================================================== --- src/OFXMLNode.m +++ src/OFXMLNode.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -76,18 +74,16 @@ return self.stringValue.doubleValue; } - (OFString *)XMLString { - return [self XMLStringWithIndentation: 0 - level: 0]; + return [self XMLStringWithIndentation: 0 level: 0]; } - (OFString *)XMLStringWithIndentation: (unsigned int)indentation { - return [self XMLStringWithIndentation: 0 - level: 0]; + return [self XMLStringWithIndentation: 0 level: 0]; } - (OFString *)XMLStringWithIndentation: (unsigned int)indentation level: (unsigned int)level { @@ -94,11 +90,11 @@ OF_UNRECOGNIZED_SELECTOR } - (OFString *)description { - return [self XMLStringWithIndentation: 2]; + return [self XMLStringWithIndentation: 2 level: 0]; } - (OFXMLElement *)XMLElementBySerializing { OF_UNRECOGNIZED_SELECTOR Index: src/OFXMLParser.h ================================================================== --- src/OFXMLParser.h +++ src/OFXMLParser.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -34,18 +32,20 @@ * @brief A protocol that needs to be implemented by delegates for OFXMLParser. */ @protocol OFXMLParserDelegate @optional /** - * @brief This callback is called when the XML parser found processing - * instructions. - * - * @param parser The parser which found processing instructions - * @param processingInstructions The processing instructions - */ -- (void)parser: (OFXMLParser *)parser - foundProcessingInstructions: (OFString *)processingInstructions; + * @brief This callback is called when the XML parser found a processing + * instruction. + * + * @param parser The parser which found a processing instruction + * @param target The target of the processing instruction + * @param data The data of the processing instruction + */ +- (void)parser: (OFXMLParser *)parser + foundProcessingInstructionWithTarget: (OFString *)target + data: (OFString *)data; /** * @brief This callback is called when the XML parser found the start of a new * tag. * @@ -82,30 +82,27 @@ * called multiple times in a row. * * @param parser The parser which found a string * @param characters The characters the XML parser found */ -- (void)parser: (OFXMLParser *)parser - foundCharacters: (OFString *)characters; +- (void)parser: (OFXMLParser *)parser foundCharacters: (OFString *)characters; /** * @brief This callback is called when the XML parser found CDATA. * * @param parser The parser which found a string * @param CDATA The CDATA the XML parser found */ -- (void)parser: (OFXMLParser *)parser - foundCDATA: (OFString *)CDATA; +- (void)parser: (OFXMLParser *)parser foundCDATA: (OFString *)CDATA; /** * @brief This callback is called when the XML parser found a comment. * * @param parser The parser which found a comment * @param comment The comment the XML parser found */ -- (void)parser: (OFXMLParser *)parser - foundComment: (OFString *)comment; +- (void)parser: (OFXMLParser *)parser foundComment: (OFString *)comment; /** * @brief This callback is called when the XML parser found an entity it * doesn't know. * @@ -131,32 +128,11 @@ */ OF_SUBCLASSING_RESTRICTED @interface OFXMLParser: OFObject { id _Nullable _delegate; - enum of_xml_parser_state { - OF_XMLPARSER_IN_BYTE_ORDER_MARK, - OF_XMLPARSER_OUTSIDE_TAG, - OF_XMLPARSER_TAG_OPENED, - OF_XMLPARSER_IN_PROCESSING_INSTRUCTIONS, - OF_XMLPARSER_IN_TAG_NAME, - OF_XMLPARSER_IN_CLOSE_TAG_NAME, - OF_XMLPARSER_IN_TAG, - OF_XMLPARSER_IN_ATTRIBUTE_NAME, - OF_XMLPARSER_EXPECT_ATTRIBUTE_EQUAL_SIGN, - OF_XMLPARSER_EXPECT_ATTRIBUTE_DELIMITER, - OF_XMLPARSER_IN_ATTRIBUTE_VALUE, - OF_XMLPARSER_EXPECT_TAG_CLOSE, - OF_XMLPARSER_EXPECT_SPACE_OR_TAG_CLOSE, - OF_XMLPARSER_IN_EXCLAMATION_MARK, - OF_XMLPARSER_IN_CDATA_OPENING, - OF_XMLPARSER_IN_CDATA, - OF_XMLPARSER_IN_COMMENT_OPENING, - OF_XMLPARSER_IN_COMMENT_1, - OF_XMLPARSER_IN_COMMENT_2, - OF_XMLPARSER_IN_DOCTYPE - } _state; + uint_least8_t _state; size_t _i, _last; const char *_Nullable _data; OFMutableData *_buffer; OFString *_Nullable _name, *_Nullable _prefix; OFMutableArray @@ -168,11 +144,11 @@ OFMutableArray OF_GENERIC(OFString *) *_previous; size_t _level; bool _acceptProlog; size_t _lineNumber; bool _lastCarriageReturn, _finishedParsing; - of_string_encoding_t _encoding; + OFStringEncoding _encoding; size_t _depthLimit; } /** * @brief The delegate that is used by the XML parser. @@ -186,11 +162,11 @@ @property (readonly, nonatomic) size_t lineNumber; /** * @brief Whether the XML parser has finished parsing. */ -@property (readonly, nonatomic) bool hasFinishedParsing; +@property (readonly, nonatomic, getter=hasFinishedParsing) bool finishedParsing; /** * @brief The depth limit for the XML parser. * * If the depth limit is exceeded, an OFMalformedXMLException is thrown. @@ -210,12 +186,11 @@ * @brief Parses the specified buffer with the specified size. * * @param buffer The buffer to parse * @param length The length of the buffer */ -- (void)parseBuffer: (const char *)buffer - length: (size_t)length; +- (void)parseBuffer: (const char *)buffer length: (size_t)length; /** * @brief Parses the specified string. * * @param string The string to parse @@ -226,17 +201,8 @@ * @brief Parses the specified stream. * * @param stream The stream to parse */ - (void)parseStream: (OFStream *)stream; - -#ifdef OF_HAVE_FILES -/** - * @brief Parses the specified file. - * - * @param path The path to the file to parse -*/ -- (void)parseFile: (OFString *)path; -#endif @end OF_ASSUME_NONNULL_END Index: src/OFXMLParser.m ================================================================== --- src/OFXMLParser.m +++ src/OFXMLParser.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -20,36 +18,60 @@ #define OF_XML_PARSER_M #include #import "OFXMLParser.h" -#import "OFString.h" #import "OFArray.h" -#import "OFDictionary.h" +#import "OFCharacterSet.h" #import "OFData.h" -#import "OFXMLAttribute.h" -#import "OFStream.h" +#import "OFDictionary.h" #ifdef OF_HAVE_FILES # import "OFFile.h" #endif +#import "OFStream.h" +#import "OFString.h" #import "OFSystemInfo.h" +#import "OFXMLAttribute.h" #import "OFInitializationFailedException.h" #import "OFInvalidArgumentException.h" #import "OFInvalidEncodingException.h" #import "OFInvalidFormatException.h" #import "OFMalformedXMLException.h" #import "OFOutOfRangeException.h" #import "OFUnboundPrefixException.h" + +enum { + stateInByteOrderMark, + stateOutsideTag, + stateTagOpened, + stateInProcessingInstruction, + stateInTagName, + stateInCloseTagName, + stateInTag, + stateInAttributeName, + stateExpectAttributeEqualSign, + stateExpectAttributeDelimiter, + stateInAttributeValue, + stateExpectTagClose, + stateExpectSpaceOrTagClose, + stateInExclamationMark, + stateInCDATAOpening, + stateInCDATA, + stateInCommentOpening, + stateInComment1, + stateInComment2, + stateInDOCTYPE +}; @interface OFXMLParser () @end static void inByteOrderMarkState(OFXMLParser *); static void outsideTagState(OFXMLParser *); static void tagOpenedState(OFXMLParser *); -static void inProcessingInstructionsState(OFXMLParser *); +static void inProcessingInstructionState(OFXMLParser *); static void inTagNameState(OFXMLParser *); static void inCloseTagNameState(OFXMLParser *); static void inTagState(OFXMLParser *); static void inAttributeNameState(OFXMLParser *); static void expectAttributeEqualSignState(OFXMLParser *); @@ -62,51 +84,46 @@ static void inCDATAState(OFXMLParser *); static void inCommentOpeningState(OFXMLParser *); static void inCommentState1(OFXMLParser *); static void inCommentState2(OFXMLParser *); static void inDOCTYPEState(OFXMLParser *); -typedef void (*state_function_t)(OFXMLParser *); -static state_function_t lookupTable[] = { - [OF_XMLPARSER_IN_BYTE_ORDER_MARK] = inByteOrderMarkState, - [OF_XMLPARSER_OUTSIDE_TAG] = outsideTagState, - [OF_XMLPARSER_TAG_OPENED] = tagOpenedState, - [OF_XMLPARSER_IN_PROCESSING_INSTRUCTIONS] = - inProcessingInstructionsState, - [OF_XMLPARSER_IN_TAG_NAME] = inTagNameState, - [OF_XMLPARSER_IN_CLOSE_TAG_NAME] = inCloseTagNameState, - [OF_XMLPARSER_IN_TAG] = inTagState, - [OF_XMLPARSER_IN_ATTRIBUTE_NAME] = inAttributeNameState, - [OF_XMLPARSER_EXPECT_ATTRIBUTE_EQUAL_SIGN] = - expectAttributeEqualSignState, - [OF_XMLPARSER_EXPECT_ATTRIBUTE_DELIMITER] = - expectAttributeDelimiterState, - [OF_XMLPARSER_IN_ATTRIBUTE_VALUE] = inAttributeValueState, - [OF_XMLPARSER_EXPECT_TAG_CLOSE] = expectTagCloseState, - [OF_XMLPARSER_EXPECT_SPACE_OR_TAG_CLOSE] = expectSpaceOrTagCloseState, - [OF_XMLPARSER_IN_EXCLAMATION_MARK] = inExclamationMarkState, - [OF_XMLPARSER_IN_CDATA_OPENING] = inCDATAOpeningState, - [OF_XMLPARSER_IN_CDATA] = inCDATAState, - [OF_XMLPARSER_IN_COMMENT_OPENING] = inCommentOpeningState, - [OF_XMLPARSER_IN_COMMENT_1] = inCommentState1, - [OF_XMLPARSER_IN_COMMENT_2] = inCommentState2, - [OF_XMLPARSER_IN_DOCTYPE] = inDOCTYPEState +typedef void (*StateFunction)(OFXMLParser *); +static StateFunction lookupTable[] = { + [stateInByteOrderMark] = inByteOrderMarkState, + [stateOutsideTag] = outsideTagState, + [stateTagOpened] = tagOpenedState, + [stateInProcessingInstruction] = inProcessingInstructionState, + [stateInTagName] = inTagNameState, + [stateInCloseTagName] = inCloseTagNameState, + [stateInTag] = inTagState, + [stateInAttributeName] = inAttributeNameState, + [stateExpectAttributeEqualSign] = expectAttributeEqualSignState, + [stateExpectAttributeDelimiter] = expectAttributeDelimiterState, + [stateInAttributeValue] = inAttributeValueState, + [stateExpectTagClose] = expectTagCloseState, + [stateExpectSpaceOrTagClose] = expectSpaceOrTagCloseState, + [stateInExclamationMark] = inExclamationMarkState, + [stateInCDATAOpening] = inCDATAOpeningState, + [stateInCDATA] = inCDATAState, + [stateInCommentOpening] = inCommentOpeningState, + [stateInComment1] = inCommentState1, + [stateInComment2] = inCommentState2, + [stateInDOCTYPE] = inDOCTYPEState }; static OF_INLINE void appendToBuffer(OFMutableData *buffer, const char *string, - of_string_encoding_t encoding, size_t length) + OFStringEncoding encoding, size_t length) { - if (OF_LIKELY(encoding == OF_STRING_ENCODING_UTF_8)) - [buffer addItems: string - count: length]; + if OF_LIKELY(encoding == OFStringEncodingUTF8) + [buffer addItems: string count: length]; else { void *pool = objc_autoreleasePoolPush(); OFString *tmp = [OFString stringWithCString: string encoding: encoding length: length]; - [buffer addItems: tmp.UTF8String - count: tmp.UTF8StringLength]; + [buffer addItems: tmp.UTF8String count: tmp.UTF8StringLength]; objc_autoreleasePoolPop(pool); } } static OFString * @@ -130,12 +147,11 @@ items[i] = '\n'; } else if (items[i] == '&') hasEntities = true; } - ret = [OFString stringWithUTF8String: items - length: length]; + ret = [OFString stringWithUTF8String: items length: length]; if (unescape && hasEntities) { @try { return [ret stringByXMLUnescapingWithDelegate: parser]; } @catch (OFInvalidFormatException *e) { @@ -214,11 +230,11 @@ @"xmlns", @"http://www.w3.org/2000/xmlns/", nil]; [_namespaces addObject: dict]; _acceptProlog = true; _lineNumber = 1; - _encoding = OF_STRING_ENCODING_UTF_8; + _encoding = OFStringEncodingUTF8; _depthLimit = 32; objc_autoreleasePoolPop(pool); } @catch (id e) { [self release]; @@ -240,12 +256,11 @@ [_previous release]; [super dealloc]; } -- (void)parseBuffer: (const char *)buffer - length: (size_t)length +- (void)parseBuffer: (const char *)buffer length: (size_t)length { _data = buffer; for (_i = _last = 0; _i < length; _i++) { size_t j = _i; @@ -261,68 +276,52 @@ _lineNumber++; _lastCarriageReturn = (_data[_i] == '\r'); } - /* In OF_XMLPARSER_IN_TAG, there can be only spaces */ - if (length - _last > 0 && _state != OF_XMLPARSER_IN_TAG) + /* In stateInTag, there can be only spaces */ + if (length - _last > 0 && _state != stateInTag) appendToBuffer(_buffer, _data + _last, _encoding, length - _last); } - (void)parseString: (OFString *)string { - [self parseBuffer: string.UTF8String - length: string.UTF8StringLength]; + [self parseBuffer: string.UTF8String length: string.UTF8StringLength]; } - (void)parseStream: (OFStream *)stream { size_t pageSize = [OFSystemInfo pageSize]; - char *buffer = [self allocMemoryWithSize: pageSize]; + char *buffer = OFAllocMemory(1, pageSize); @try { while (!stream.atEndOfStream) { size_t length = [stream readIntoBuffer: buffer length: pageSize]; - - [self parseBuffer: buffer - length: length]; - } - } @finally { - [self freeMemory: buffer]; - } -} - -#ifdef OF_HAVE_FILES -- (void)parseFile: (OFString *)path -{ - OFFile *file = [[OFFile alloc] initWithPath: path - mode: @"r"]; - @try { - [self parseStream: file]; - } @finally { - [file release]; - } -} -#endif + [self parseBuffer: buffer length: length]; + } + } @finally { + OFFreeMemory(buffer); + } +} static void inByteOrderMarkState(OFXMLParser *self) { if (self->_data[self->_i] != "\xEF\xBB\xBF"[self->_level]) { if (self->_level == 0) { - self->_state = OF_XMLPARSER_OUTSIDE_TAG; + self->_state = stateOutsideTag; self->_i--; return; } @throw [OFMalformedXMLException exceptionWithParser: self]; } if (self->_level++ == 2) - self->_state = OF_XMLPARSER_OUTSIDE_TAG; + self->_state = stateOutsideTag; self->_last = self->_i + 1; } /* Not in a tag */ @@ -358,11 +357,11 @@ } [self->_buffer removeAllItems]; self->_last = self->_i + 1; - self->_state = OF_XMLPARSER_TAG_OPENED; + self->_state = stateTagOpened; } /* Tag was just opened */ static void tagOpenedState(OFXMLParser *self) @@ -372,38 +371,38 @@ @throw [OFMalformedXMLException exceptionWithParser: self]; switch (self->_data[self->_i]) { case '?': self->_last = self->_i + 1; - self->_state = OF_XMLPARSER_IN_PROCESSING_INSTRUCTIONS; + self->_state = stateInProcessingInstruction; self->_level = 0; break; case '/': self->_last = self->_i + 1; - self->_state = OF_XMLPARSER_IN_CLOSE_TAG_NAME; + self->_state = stateInCloseTagName; self->_acceptProlog = false; break; case '!': self->_last = self->_i + 1; - self->_state = OF_XMLPARSER_IN_EXCLAMATION_MARK; + self->_state = stateInExclamationMark; self->_acceptProlog = false; break; default: if (self->_depthLimit > 0 && self->_previous.count >= self->_depthLimit) @throw [OFOutOfRangeException exception]; - self->_state = OF_XMLPARSER_IN_TAG_NAME; + self->_state = stateInTagName; self->_acceptProlog = false; self->_i--; break; } } /* */ static bool -parseXMLProcessingInstructions(OFXMLParser *self, OFString *pi) +parseXMLProcessingInstruction(OFXMLParser *self, OFString *data) { const char *cString; size_t length, last; int PIState = 0; OFString *attribute = nil; @@ -414,15 +413,12 @@ if (!self->_acceptProlog) return false; self->_acceptProlog = false; - pi = [pi substringFromIndex: 3]; - pi = pi.stringByDeletingEnclosingWhitespaces; - - cString = pi.UTF8String; - length = pi.UTF8StringLength; + cString = data.UTF8String; + length = data.UTF8StringLength; last = 0; for (size_t i = 0; i < length; i++) { switch (PIState) { case 0: @@ -473,11 +469,11 @@ } if ([attribute isEqual: @"encoding"]) { @try { self->_encoding = - of_string_parse_encoding(value); + OFStringEncodingParseName(value); } @catch (OFInvalidArgumentException *e) { @throw [OFInvalidEncodingException exception]; } } @@ -493,42 +489,56 @@ return false; return true; } -/* Inside processing instructions */ +/* Inside processing instruction */ static void -inProcessingInstructionsState(OFXMLParser *self) +inProcessingInstructionState(OFXMLParser *self) { if (self->_data[self->_i] == '?') self->_level = 1; else if (self->_level == 1 && self->_data[self->_i] == '>') { void *pool = objc_autoreleasePoolPush(); - OFString *PI; + OFString *PI, *target, *data = nil; + OFCharacterSet *whitespaceCS; + size_t pos; appendToBuffer(self->_buffer, self->_data + self->_last, self->_encoding, self->_i - self->_last); PI = transformString(self, self->_buffer, 1, false); - if ([PI isEqual: @"xml"] || [PI hasPrefix: @"xml "] || - [PI hasPrefix: @"xml\t"] || [PI hasPrefix: @"xml\r"] || - [PI hasPrefix: @"xml\n"]) - if (!parseXMLProcessingInstructions(self, PI)) + whitespaceCS = [OFCharacterSet + characterSetWithCharactersInString: @" \r\n\r"]; + pos = [PI indexOfCharacterFromSet: whitespaceCS]; + if (pos != OFNotFound) { + target = [PI substringToIndex: pos]; + data = [[PI substringFromIndex: pos + 1] + stringByDeletingEnclosingWhitespaces]; + + if (data.length == 0) + data = nil; + } else + target = PI; + + if ([target caseInsensitiveCompare: @"xml"] == OFOrderedSame) + if (!parseXMLProcessingInstruction(self, data)) @throw [OFMalformedXMLException exceptionWithParser: self]; - if ([self->_delegate respondsToSelector: - @selector(parser:foundProcessingInstructions:)]) - [self->_delegate parser: self - foundProcessingInstructions: PI]; + if ([self->_delegate respondsToSelector: @selector( + parser:foundProcessingInstructionWithTarget:data:)]) + [self->_delegate parser: self + foundProcessingInstructionWithTarget: target + data: data]; objc_autoreleasePoolPop(pool); [self->_buffer removeAllItems]; self->_last = self->_i + 1; - self->_state = OF_XMLPARSER_OUTSIDE_TAG; + self->_state = stateOutsideTag; } else self->_level = 0; } /* Inside a tag, no name yet */ @@ -568,13 +578,11 @@ self->_name = [bufferString copy]; self->_prefix = nil; } if (self->_data[self->_i] == '>' || self->_data[self->_i] == '/') { - OFString *namespace; - - namespace = namespaceForPrefix(self->_prefix, + OFString *namespace = namespaceForPrefix(self->_prefix, self->_namespaces); if (self->_prefix != nil && namespace == nil) @throw [OFUnboundPrefixException exceptionWithPrefix: self->_prefix @@ -604,14 +612,13 @@ [self->_name release]; [self->_prefix release]; self->_name = self->_prefix = nil; self->_state = (self->_data[self->_i] == '/' - ? OF_XMLPARSER_EXPECT_TAG_CLOSE - : OF_XMLPARSER_OUTSIDE_TAG); + ? stateExpectTagClose : stateOutsideTag); } else - self->_state = OF_XMLPARSER_IN_TAG; + self->_state = stateInTag; if (self->_data[self->_i] != '/') [self->_namespaces addObject: [OFMutableDictionary dictionary]]; objc_autoreleasePoolPop(pool); @@ -685,12 +692,11 @@ [self->_prefix release]; self->_name = self->_prefix = nil; self->_last = self->_i + 1; self->_state = (self->_data[self->_i] == '>' - ? OF_XMLPARSER_OUTSIDE_TAG - : OF_XMLPARSER_EXPECT_SPACE_OR_TAG_CLOSE); + ? stateOutsideTag : stateExpectSpaceOrTagClose); if (self->_previous.count == 0) self->_finishedParsing = true; } @@ -707,11 +713,11 @@ if (self->_data[self->_i] != ' ' && self->_data[self->_i] != '\t' && self->_data[self->_i] != '\n' && self->_data[self->_i] != '\r') { self->_last = self->_i; - self->_state = OF_XMLPARSER_IN_ATTRIBUTE_NAME; + self->_state = stateInAttributeName; self->_i--; } return; } @@ -766,12 +772,11 @@ [self->_attributes removeAllObjects]; self->_name = self->_prefix = nil; self->_last = self->_i + 1; self->_state = (self->_data[self->_i] == '/' - ? OF_XMLPARSER_EXPECT_TAG_CLOSE - : OF_XMLPARSER_OUTSIDE_TAG); + ? stateExpectTagClose : stateOutsideTag); } /* Looking for attribute name */ static void inAttributeNameState(OFXMLParser *self) @@ -815,21 +820,20 @@ [self->_buffer removeAllItems]; self->_last = self->_i + 1; self->_state = (self->_data[self->_i] == '=' - ? OF_XMLPARSER_EXPECT_ATTRIBUTE_DELIMITER - : OF_XMLPARSER_EXPECT_ATTRIBUTE_EQUAL_SIGN); + ? stateExpectAttributeDelimiter : stateExpectAttributeEqualSign); } /* Expecting equal sign of an attribute */ static void expectAttributeEqualSignState(OFXMLParser *self) { if (self->_data[self->_i] == '=') { self->_last = self->_i + 1; - self->_state = OF_XMLPARSER_EXPECT_ATTRIBUTE_DELIMITER; + self->_state = stateExpectAttributeDelimiter; return; } if (self->_data[self->_i] != ' ' && self->_data[self->_i] != '\t' && self->_data[self->_i] != '\n' && self->_data[self->_i] != '\r') @@ -848,11 +852,11 @@ if (self->_data[self->_i] != '\'' && self->_data[self->_i] != '"') @throw [OFMalformedXMLException exceptionWithParser: self]; self->_delimiter = self->_data[self->_i]; - self->_state = OF_XMLPARSER_IN_ATTRIBUTE_VALUE; + self->_state = stateInAttributeValue; } /* Looking for attribute value */ static void inAttributeValueState(OFXMLParser *self) @@ -892,20 +896,20 @@ [self->_attributeName release]; [self->_attributePrefix release]; self->_attributeName = self->_attributePrefix = nil; self->_last = self->_i + 1; - self->_state = OF_XMLPARSER_IN_TAG; + self->_state = stateInTag; } /* Expecting closing '>' */ static void expectTagCloseState(OFXMLParser *self) { if (self->_data[self->_i] == '>') { self->_last = self->_i + 1; - self->_state = OF_XMLPARSER_OUTSIDE_TAG; + self->_state = stateOutsideTag; } else @throw [OFMalformedXMLException exceptionWithParser: self]; } /* Expecting closing '>' or space */ @@ -912,11 +916,11 @@ static void expectSpaceOrTagCloseState(OFXMLParser *self) { if (self->_data[self->_i] == '>') { self->_last = self->_i + 1; - self->_state = OF_XMLPARSER_OUTSIDE_TAG; + self->_state = stateOutsideTag; } else if (self->_data[self->_i] != ' ' && self->_data[self->_i] != '\t' && self->_data[self->_i] != '\n' && self->_data[self->_i] != '\r') @throw [OFMalformedXMLException exceptionWithParser: self]; } @@ -927,16 +931,16 @@ { if (self->_finishedParsing && self->_data[self->_i] != '-') @throw [OFMalformedXMLException exceptionWithParser: self]; if (self->_data[self->_i] == '-') - self->_state = OF_XMLPARSER_IN_COMMENT_OPENING; + self->_state = stateInCommentOpening; else if (self->_data[self->_i] == '[') { - self->_state = OF_XMLPARSER_IN_CDATA_OPENING; + self->_state = stateInCDATAOpening; self->_level = 0; } else if (self->_data[self->_i] == 'D') { - self->_state = OF_XMLPARSER_IN_DOCTYPE; + self->_state = stateInDOCTYPE; self->_level = 0; } else @throw [OFMalformedXMLException exceptionWithParser: self]; self->_last = self->_i + 1; @@ -948,11 +952,11 @@ { if (self->_data[self->_i] != "CDATA["[self->_level]) @throw [OFMalformedXMLException exceptionWithParser: self]; if (++self->_level == 6) { - self->_state = OF_XMLPARSER_IN_CDATA; + self->_state = stateInCDATA; self->_level = 0; } self->_last = self->_i + 1; } @@ -970,19 +974,18 @@ self->_encoding, self->_i - self->_last); CDATA = transformString(self, self->_buffer, 2, false); if ([self->_delegate respondsToSelector: @selector(parser:foundCDATA:)]) - [self->_delegate parser: self - foundCDATA: CDATA]; + [self->_delegate parser: self foundCDATA: CDATA]; objc_autoreleasePoolPop(pool); [self->_buffer removeAllItems]; self->_last = self->_i + 1; - self->_state = OF_XMLPARSER_OUTSIDE_TAG; + self->_state = stateOutsideTag; } else self->_level = 0; } /* Comment */ @@ -991,11 +994,11 @@ { if (self->_data[self->_i] != '-') @throw [OFMalformedXMLException exceptionWithParser: self]; self->_last = self->_i + 1; - self->_state = OF_XMLPARSER_IN_COMMENT_1; + self->_state = stateInComment1; self->_level = 0; } static void inCommentState1(OFXMLParser *self) @@ -1004,11 +1007,11 @@ self->_level++; else self->_level = 0; if (self->_level == 2) - self->_state = OF_XMLPARSER_IN_COMMENT_2; + self->_state = stateInComment2; } static void inCommentState2(OFXMLParser *self) { @@ -1024,19 +1027,18 @@ self->_encoding, self->_i - self->_last); comment = transformString(self, self->_buffer, 2, false); if ([self->_delegate respondsToSelector: @selector(parser:foundComment:)]) - [self->_delegate parser: self - foundComment: comment]; + [self->_delegate parser: self foundComment: comment]; objc_autoreleasePoolPop(pool); [self->_buffer removeAllItems]; self->_last = self->_i + 1; - self->_state = OF_XMLPARSER_OUTSIDE_TAG; + self->_state = stateOutsideTag; } /* In */ static void inDOCTYPEState(OFXMLParser *self) @@ -1049,11 +1051,11 @@ @throw [OFMalformedXMLException exceptionWithParser: self]; self->_level++; if (self->_level > 6 && self->_data[self->_i] == '>') - self->_state = OF_XMLPARSER_OUTSIDE_TAG; + self->_state = stateOutsideTag; self->_last = self->_i + 1; } - (size_t)lineNumber @@ -1069,11 +1071,10 @@ - (OFString *)string: (OFString *)string containsUnknownEntityNamed: (OFString *)entity { if ([_delegate respondsToSelector: @selector(parser:foundUnknownEntityNamed:)]) - return [_delegate parser: self - foundUnknownEntityNamed: entity]; + return [_delegate parser: self foundUnknownEntityNamed: entity]; return nil; } @end ADDED src/OFXMLProcessingInstruction.h Index: src/OFXMLProcessingInstruction.h ================================================================== --- /dev/null +++ src/OFXMLProcessingInstruction.h @@ -0,0 +1,67 @@ +/* + * 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 "OFXMLNode.h" + +OF_ASSUME_NONNULL_BEGIN + +/** + * @class OFXMLProcessingInstruction \ + * OFXMLProcessingInstruction.h ObjFW/OFXMLProcessingInstruction.h + * + * @brief A class for representing an XML processing instruction. + */ +@interface OFXMLProcessingInstruction: OFXMLNode +{ + OFString *_target, *_data; + OF_RESERVE_IVARS(OFXMLProcessingInstruction, 4) +} + +/** + * @brief The target of the processing instruction. + */ +@property (readonly, nonatomic) OFString *target; + +/** + * @brief The data of the processing instruction. + */ +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFString *data; + +/** + * @brief Creates a new OFXMLProcessingInstruction with the specified target + * and data. + * + * @param target The target for the processing instruction + * @param data The data for the processing instruction + * @return A new OFXMLProcessingInstruction + */ ++ (instancetype)processingInstructionWithTarget: (OFString *)target + data: (OFString *)data; + +/** + * @brief Initializes an already allocated OFXMLProcessingInstruction with the + * specified target and data. + * + * @param target The target for the processing instruction + * @param data The data for the processing instruction + * @return An initialized OFXMLProcessingInstruction + */ +- (instancetype)initWithTarget: (OFString *)target + data: (OFString *)data OF_DESIGNATED_INITIALIZER; + +- (instancetype)initWithSerialization: (OFXMLElement *)element; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFXMLProcessingInstruction.m Index: src/OFXMLProcessingInstruction.m ================================================================== --- /dev/null +++ src/OFXMLProcessingInstruction.m @@ -0,0 +1,187 @@ +/* + * 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 "OFXMLProcessingInstruction.h" +#import "OFString.h" +#import "OFXMLAttribute.h" +#import "OFXMLElement.h" +#import "OFXMLNode+Private.h" + +#import "OFInvalidArgumentException.h" + +@implementation OFXMLProcessingInstruction +@synthesize target = _target, data = _data; + ++ (instancetype)processingInstructionWithTarget: (OFString *)target + data: (OFString *)data +{ + return [[[self alloc] initWithTarget: target + data: data] autorelease]; +} + +- (instancetype)initWithTarget: (OFString *)target + data: (OFString *)data +{ + self = [super of_init]; + + @try { + _target = [target copy]; + _data = [data copy]; + } @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 + data: element.stringValue]; + + objc_autoreleasePoolPop(pool); + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_target release]; + [_data release]; + + [super dealloc]; +} + +- (bool)isEqual: (id)object +{ + OFXMLProcessingInstruction *processingInstruction; + + if (object == self) + return true; + + if (![object isKindOfClass: [OFXMLProcessingInstruction class]]) + return false; + + processingInstruction = object; + + if (![processingInstruction->_target isEqual: _target]) + return false; + + if (processingInstruction->_data != _data && + ![processingInstruction->_data isEqual: _data]) + return false; + + return true; +} + +- (unsigned long)hash +{ + unsigned long hash; + + OFHashInit(&hash); + OFHashAddHash(&hash, _target.hash); + OFHashAddHash(&hash, _data.hash); + OFHashFinalize(&hash); + + return hash; +} + +- (OFString *)stringValue +{ + return @""; +} + +- (OFString *)XMLString +{ + if (_data.length > 0) + return [OFString stringWithFormat: @"", + _target, _data]; + else + return [OFString stringWithFormat: @"", _target]; +} + +- (OFString *)XMLStringWithIndentation: (unsigned int)indentation +{ + return self.XMLString; +} + +- (OFString *)XMLStringWithIndentation: (unsigned int)indentation + level: (unsigned int)level +{ + if (indentation > 0 && level > 0) { + OFString *ret; + char *whitespaces = OFAllocMemory((level * indentation) + 1, 1); + memset(whitespaces, ' ', level * indentation); + whitespaces[level * indentation] = 0; + + @try { + if (_data.length > 0) + ret = [OFString stringWithFormat: + @"%s", whitespaces, + _target, _data]; + else + ret = [OFString stringWithFormat: + @"%s", whitespaces, _target]; + } @finally { + OFFreeMemory(whitespaces); + } + + return ret; + } else + return self.XMLString; +} + +- (OFString *)description +{ + return self.XMLString; +} + +- (OFXMLElement *)XMLElementBySerializing +{ + OFXMLElement *ret = [OFXMLElement elementWithName: self.className + namespace: OFSerializationNS + stringValue: _data]; + void *pool = objc_autoreleasePoolPush(); + + [ret addAttribute: [OFXMLAttribute attributeWithName: @"target" + stringValue: _target]]; + + objc_autoreleasePoolPop(pool); + + return ret; +} +@end DELETED src/OFXMLProcessingInstructions.h Index: src/OFXMLProcessingInstructions.h ================================================================== --- src/OFXMLProcessingInstructions.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "OFXMLNode.h" - -OF_ASSUME_NONNULL_BEGIN - -/** - * @class OFXMLProcessingInstructions \ - * OFXMLProcessingInstructions.h ObjFW/OFXMLProcessingInstructions.h - * - * @brief A class for representing XML processing instructions. - */ -@interface OFXMLProcessingInstructions: OFXMLNode -{ - OFString *_processingInstructions; - OF_RESERVE_IVARS(OFXMLProcessingInstructions, 4) -} - -/** - * @brief Creates a new OFXMLProcessingInstructions with the specified string. - * - * @param string The string for the processing instructions - * @return A new OFXMLProcessingInstructions - */ -+ (instancetype)processingInstructionsWithString: (OFString *)string; - -/** - * @brief Initializes an already allocated OFXMLProcessingInstructions with the - * specified string. - * - * @param string The string for the processing instructions - * @return An initialized OFXMLProcessingInstructions - */ -- (instancetype)initWithString: (OFString *)string; - -- (instancetype)initWithSerialization: (OFXMLElement *)element; -@end - -OF_ASSUME_NONNULL_END DELETED src/OFXMLProcessingInstructions.m Index: src/OFXMLProcessingInstructions.m ================================================================== --- src/OFXMLProcessingInstructions.m +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "OFXMLProcessingInstructions.h" -#import "OFXMLNode+Private.h" -#import "OFString.h" -#import "OFXMLElement.h" - -#import "OFInvalidArgumentException.h" - -@implementation OFXMLProcessingInstructions -+ (instancetype)processingInstructionsWithString: (OFString *)string -{ - return [[[self alloc] initWithString: string] autorelease]; -} - -- (instancetype)initWithString: (OFString *)string -{ - self = [super of_init]; - - @try { - _processingInstructions = [string copy]; - } @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: OF_SERIALIZATION_NS]) - @throw [OFInvalidArgumentException exception]; - - _processingInstructions = [element.stringValue copy]; - - objc_autoreleasePoolPop(pool); - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - [_processingInstructions release]; - - [super dealloc]; -} - -- (bool)isEqual: (id)object -{ - OFXMLProcessingInstructions *processingInstructions; - - if (object == self) - return true; - - if (![object isKindOfClass: [OFXMLProcessingInstructions class]]) - return false; - - processingInstructions = object; - - return [processingInstructions->_processingInstructions - isEqual: _processingInstructions]; -} - -- (unsigned long)hash -{ - return _processingInstructions.hash; -} - -- (OFString *)stringValue -{ - return @""; -} - -- (OFString *)XMLString -{ - return [OFString stringWithFormat: @"", _processingInstructions]; -} - -- (OFString *)XMLStringWithIndentation: (unsigned int)indentation -{ - return [OFString stringWithFormat: @"", _processingInstructions]; -} - -- (OFString *)XMLStringWithIndentation: (unsigned int)indentation - level: (unsigned int)level -{ - OFString *ret; - - if (indentation > 0 && level > 0) { - char *whitespaces = [self allocMemoryWithSize: - (level * indentation) + 1]; - memset(whitespaces, ' ', level * indentation); - whitespaces[level * indentation] = 0; - - @try { - ret = [OFString stringWithFormat: - @"%s", whitespaces, _processingInstructions]; - } @finally { - [self freeMemory: whitespaces]; - } - } else - ret = [OFString stringWithFormat: @"", - _processingInstructions]; - - return ret; -} - -- (OFString *)description -{ - return [OFString stringWithFormat: @"", _processingInstructions]; -} - -- (OFXMLElement *)XMLElementBySerializing -{ - return [OFXMLElement elementWithName: self.className - namespace: OF_SERIALIZATION_NS - stringValue: _processingInstructions]; -} -@end Index: src/OFZIPArchive.h ================================================================== --- src/OFZIPArchive.h +++ src/OFZIPArchive.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -34,15 +32,11 @@ OF_SUBCLASSING_RESTRICTED @interface OFZIPArchive: OFObject { OFStream *_stream; int64_t _offset; - enum { - OF_ZIP_ARCHIVE_MODE_READ, - OF_ZIP_ARCHIVE_MODE_WRITE, - OF_ZIP_ARCHIVE_MODE_APPEND - } _mode; + uint_least8_t _mode; uint32_t _diskNumber, _centralDirectoryDisk; uint64_t _centralDirectoryEntriesInDisk, _centralDirectoryEntries; uint64_t _centralDirectorySize; int64_t _centralDirectoryOffset; OFString *_Nullable _archiveComment; @@ -76,12 +70,11 @@ * @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 */ -+ (instancetype)archiveWithStream: (OFStream *)stream - mode: (OFString *)mode; ++ (instancetype)archiveWithStream: (OFStream *)stream mode: (OFString *)mode; #ifdef OF_HAVE_FILES /** * @brief Creates a new OFZIPArchive object with the specified file. * @@ -89,12 +82,11 @@ * @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 */ -+ (instancetype)archiveWithPath: (OFString *)path - mode: (OFString *)mode; ++ (instancetype)archiveWithPath: (OFString *)path mode: (OFString *)mode; #endif - (instancetype)init OF_UNAVAILABLE; /** @@ -120,12 +112,11 @@ * @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 */ -- (instancetype)initWithPath: (OFString *)path - mode: (OFString *)mode; +- (instancetype)initWithPath: (OFString *)path mode: (OFString *)mode; #endif /** * @brief Returns a stream for reading the specified file from the archive. * @@ -174,7 +165,18 @@ /** * @brief Closes the OFZIPArchive. */ - (void)close; @end + +#ifdef __cplusplus +extern "C" { +#endif +extern uint32_t OFZIPArchiveReadField32(const uint8_t *_Nonnull *_Nonnull, + uint16_t *_Nonnull); +extern uint64_t OFZIPArchiveReadField64(const uint8_t *_Nonnull *_Nonnull, + uint16_t *_Nonnull); +#ifdef __cplusplus +} +#endif OF_ASSUME_NONNULL_END Index: src/OFZIPArchive.m ================================================================== --- src/OFZIPArchive.m +++ src/OFZIPArchive.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -20,10 +18,11 @@ #include #import "OFZIPArchive.h" #import "OFZIPArchiveEntry.h" #import "OFZIPArchiveEntry+Private.h" +#import "OFCRC32.h" #import "OFData.h" #import "OFArray.h" #import "OFDictionary.h" #import "OFStream.h" #import "OFSeekableStream.h" @@ -31,12 +30,10 @@ # import "OFFile.h" #endif #import "OFInflateStream.h" #import "OFInflate64Stream.h" -#import "crc32.h" - #import "OFChecksumMismatchException.h" #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFNotImplementedException.h" #import "OFNotOpenException.h" @@ -43,16 +40,23 @@ #import "OFOpenItemFailedException.h" #import "OFOutOfRangeException.h" #import "OFSeekFailedException.h" #import "OFTruncatedDataException.h" #import "OFUnsupportedVersionException.h" +#import "OFWriteFailedException.h" /* * FIXME: Current limitations: * - Split archives are not supported. * - Encrypted files cannot be read. */ + +enum { + modeRead, + modeWrite, + modeAppend +}; OF_DIRECT_MEMBERS @interface OFZIPArchive () - (void)of_readZIPInfo; - (void)of_readEntries; @@ -103,11 +107,11 @@ - (instancetype)initWithStream: (OFStream *)stream entry: (OFMutableZIPArchiveEntry *)entry; @end uint32_t -of_zip_archive_read_field32(const uint8_t **data, uint16_t *size) +OFZIPArchiveReadField32(const uint8_t **data, uint16_t *size) { uint32_t field = 0; if (*size < 4) @throw [OFInvalidFormatException exception]; @@ -120,11 +124,11 @@ return field; } uint64_t -of_zip_archive_read_field64(const uint8_t **data, uint16_t *size) +OFZIPArchiveReadField64(const uint8_t **data, uint16_t *size) { uint64_t field = 0; if (*size < 8) @throw [OFInvalidFormatException exception]; @@ -138,15 +142,14 @@ return field; } static void seekOrThrowInvalidFormat(OFSeekableStream *stream, - of_offset_t offset, int whence) + OFFileOffset offset, int whence) { @try { - [stream seekToOffset: offset - whence: whence]; + [stream seekToOffset: offset whence: whence]; } @catch (OFSeekFailedException *e) { if (e.errNo == EINVAL) @throw [OFInvalidFormatException exception]; @throw e; @@ -154,63 +157,57 @@ } @implementation OFZIPArchive @synthesize archiveComment = _archiveComment; -+ (instancetype)archiveWithStream: (OFStream *)stream - mode: (OFString *)mode ++ (instancetype)archiveWithStream: (OFStream *)stream mode: (OFString *)mode { - return [[[self alloc] initWithStream: stream - mode: mode] autorelease]; + return [[[self alloc] initWithStream: stream mode: mode] autorelease]; } #ifdef OF_HAVE_FILES -+ (instancetype)archiveWithPath: (OFString *)path - mode: (OFString *)mode ++ (instancetype)archiveWithPath: (OFString *)path mode: (OFString *)mode { - return [[[self alloc] initWithPath: path - mode: mode] autorelease]; + return [[[self alloc] initWithPath: path mode: mode] autorelease]; } #endif - (instancetype)init { OF_INVALID_INIT_METHOD } -- (instancetype)initWithStream: (OFStream *)stream - mode: (OFString *)mode +- (instancetype)initWithStream: (OFStream *)stream mode: (OFString *)mode { self = [super init]; @try { if ([mode isEqual: @"r"]) - _mode = OF_ZIP_ARCHIVE_MODE_READ; + _mode = modeRead; else if ([mode isEqual: @"w"]) - _mode = OF_ZIP_ARCHIVE_MODE_WRITE; + _mode = modeWrite; else if ([mode isEqual: @"a"]) - _mode = OF_ZIP_ARCHIVE_MODE_APPEND; + _mode = modeAppend; else @throw [OFInvalidArgumentException exception]; _stream = [stream retain]; _entries = [[OFMutableArray alloc] init]; _pathToEntryMap = [[OFMutableDictionary alloc] init]; - if (_mode == OF_ZIP_ARCHIVE_MODE_READ || - _mode == OF_ZIP_ARCHIVE_MODE_APPEND) { + if (_mode == modeRead || _mode == modeAppend) { if (![stream isKindOfClass: [OFSeekableStream class]]) @throw [OFInvalidArgumentException exception]; [self of_readZIPInfo]; [self of_readEntries]; } - if (_mode == OF_ZIP_ARCHIVE_MODE_APPEND) { + if (_mode == modeAppend) { _offset = _centralDirectoryOffset; seekOrThrowInvalidFormat((OFSeekableStream *)_stream, - (of_offset_t)_offset, SEEK_SET); + (OFFileOffset)_offset, SEEK_SET); } } @catch (id e) { /* * If we are in write or append mode, we do not want -[close] * to write anything to it on error - after all, it might not @@ -225,25 +222,21 @@ return self; } #ifdef OF_HAVE_FILES -- (instancetype)initWithPath: (OFString *)path - mode: (OFString *)mode +- (instancetype)initWithPath: (OFString *)path mode: (OFString *)mode { OFFile *file; if ([mode isEqual: @"a"]) - file = [[OFFile alloc] initWithPath: path - mode: @"r+"]; + file = [[OFFile alloc] initWithPath: path mode: @"r+"]; else - file = [[OFFile alloc] initWithPath: path - mode: mode]; + file = [[OFFile alloc] initWithPath: path mode: mode]; @try { - self = [self initWithStream: file - mode: mode]; + self = [self initWithStream: file mode: mode]; } @finally { [file release]; } return self; @@ -266,11 +259,11 @@ - (void)of_readZIPInfo { void *pool = objc_autoreleasePoolPush(); uint16_t commentLength; - of_offset_t offset = -22; + OFFileOffset offset = -22; bool valid = false; do { seekOrThrowInvalidFormat((OFSeekableStream *)_stream, offset, SEEK_END); @@ -292,11 +285,11 @@ _centralDirectoryOffset = [_stream readLittleEndianInt32]; commentLength = [_stream readLittleEndianInt16]; _archiveComment = [[_stream readStringWithLength: commentLength - encoding: OF_STRING_ENCODING_CODEPAGE_437] copy]; + encoding: OFStringEncodingCodepage437] copy]; if (_diskNumber == 0xFFFF || _centralDirectoryDisk == 0xFFFF || _centralDirectoryEntriesInDisk == 0xFFFF || _centralDirectoryEntries == 0xFFFF || @@ -318,15 +311,15 @@ * central directory record. */ [_stream readLittleEndianInt32]; offset64 = [_stream readLittleEndianInt64]; - if (offset64 < 0 || (of_offset_t)offset64 != offset64) + if (offset64 < 0 || (OFFileOffset)offset64 != offset64) @throw [OFOutOfRangeException exception]; seekOrThrowInvalidFormat((OFSeekableStream *)_stream, - (of_offset_t)offset64, SEEK_SET); + (OFFileOffset)offset64, SEEK_SET); if ([_stream readLittleEndianInt32] != 0x06064B50) @throw [OFInvalidFormatException exception]; size = [_stream readLittleEndianInt64]; @@ -345,11 +338,11 @@ _centralDirectoryEntries = [_stream readLittleEndianInt64]; _centralDirectorySize = [_stream readLittleEndianInt64]; _centralDirectoryOffset = [_stream readLittleEndianInt64]; if (_centralDirectoryOffset < 0 || - (of_offset_t)_centralDirectoryOffset != + (OFFileOffset)_centralDirectoryOffset != _centralDirectoryOffset) @throw [OFOutOfRangeException exception]; } objc_autoreleasePoolPop(pool); @@ -358,26 +351,25 @@ - (void)of_readEntries { void *pool = objc_autoreleasePoolPush(); if (_centralDirectoryOffset < 0 || - (of_offset_t)_centralDirectoryOffset != _centralDirectoryOffset) + (OFFileOffset)_centralDirectoryOffset != _centralDirectoryOffset) @throw [OFOutOfRangeException exception]; seekOrThrowInvalidFormat((OFSeekableStream *)_stream, - (of_offset_t)_centralDirectoryOffset, SEEK_SET); + (OFFileOffset)_centralDirectoryOffset, SEEK_SET); for (size_t i = 0; i < _centralDirectoryEntries; i++) { OFZIPArchiveEntry *entry = [[[OFZIPArchiveEntry alloc] of_initWithStream: _stream] autorelease]; if ([_pathToEntryMap objectForKey: entry.fileName] != nil) @throw [OFInvalidFormatException exception]; [_entries addObject: entry]; - [_pathToEntryMap setObject: entry - forKey: entry.fileName]; + [_pathToEntryMap setObject: entry forKey: entry.fileName]; } objc_autoreleasePoolPop(pool); } @@ -412,12 +404,11 @@ [_lastReturnedStream close]; } @catch (OFNotOpenException *e) { /* Might have already been closed by the user - that's fine. */ } - if ((_mode == OF_ZIP_ARCHIVE_MODE_WRITE || - _mode == OF_ZIP_ARCHIVE_MODE_APPEND) && + if ((_mode == modeWrite || _mode == modeAppend) && [_lastReturnedStream isKindOfClass: [OFZIPArchiveFileWriteStream class]]) { OFZIPArchiveFileWriteStream *stream = (OFZIPArchiveFileWriteStream *)_lastReturnedStream; @@ -442,11 +433,14 @@ void *pool = objc_autoreleasePoolPush(); OFZIPArchiveEntry *entry; OFZIPArchiveLocalFileHeader *localFileHeader; int64_t offset64; - if (_mode != OF_ZIP_ARCHIVE_MODE_READ) + if (_stream == nil) + @throw [OFNotOpenException exceptionWithObject: self]; + + if (_mode != modeRead) @throw [OFInvalidArgumentException exception]; if ((entry = [_pathToEntryMap objectForKey: path]) == nil) @throw [OFOpenItemFailedException exceptionWithPath: path mode: @"r" @@ -453,15 +447,15 @@ errNo: ENOENT]; [self of_closeLastReturnedStream]; offset64 = entry.of_localFileHeaderOffset; - if (offset64 < 0 || (of_offset_t)offset64 != offset64) + if (offset64 < 0 || (OFFileOffset)offset64 != offset64) @throw [OFOutOfRangeException exception]; seekOrThrowInvalidFormat((OFSeekableStream *)_stream, - (of_offset_t)offset64, SEEK_SET); + (OFFileOffset)offset64, SEEK_SET); localFileHeader = [[[OFZIPArchiveLocalFileHeader alloc] initWithStream: _stream] autorelease]; if (![localFileHeader matchesEntry: entry]) @throw [OFInvalidFormatException exception]; @@ -492,12 +486,14 @@ OFMutableZIPArchiveEntry *entry; OFString *fileName; OFData *extraField; uint16_t fileNameLength, extraFieldLength; - if (_mode != OF_ZIP_ARCHIVE_MODE_WRITE && - _mode != OF_ZIP_ARCHIVE_MODE_APPEND) + if (_stream == nil) + @throw [OFNotOpenException exceptionWithObject: self]; + + if (_mode != modeWrite && _mode != modeAppend) @throw [OFInvalidArgumentException exception]; pool = objc_autoreleasePoolPush(); entry = [[entry_ mutableCopy] autorelease]; @@ -505,12 +501,11 @@ @throw [OFOpenItemFailedException exceptionWithPath: entry.fileName mode: @"w" errNo: EEXIST]; - if (entry.compressionMethod != - OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_NONE) + if (entry.compressionMethod != OFZIPArchiveEntryCompressionMethodNone) @throw [OFNotImplementedException exceptionWithSelector: _cmd object: self]; [self of_closeLastReturnedStream]; @@ -546,12 +541,11 @@ offsetAdd += 4 + (5 * 2) + (3 * 4) + (2 * 2); [_stream writeString: fileName]; offsetAdd += fileNameLength; - [_stream writeLittleEndianInt16: - OF_ZIP_ARCHIVE_ENTRY_EXTRA_FIELD_ZIP64]; + [_stream writeLittleEndianInt16: OFZIPArchiveEntryExtraFieldTagZIP64]; [_stream writeLittleEndianInt16: 16]; /* We use the data descriptor */ [_stream writeLittleEndianInt64: 0]; [_stream writeLittleEndianInt64: 0]; offsetAdd += (2 * 2) + (2 * 8); @@ -628,12 +622,11 @@ if (_stream == nil) @throw [OFNotOpenException exceptionWithObject: self]; [self of_closeLastReturnedStream]; - if (_mode == OF_ZIP_ARCHIVE_MODE_WRITE || - _mode == OF_ZIP_ARCHIVE_MODE_APPEND) + if (_mode == modeWrite || _mode == modeAppend) [self of_writeCentralDirectory]; [_stream release]; _stream = nil; } @@ -646,11 +639,11 @@ @try { void *pool = objc_autoreleasePoolPush(); OFMutableData *extraField = nil; uint16_t fileNameLength, extraFieldLength; - of_string_encoding_t encoding; + OFStringEncoding encoding; size_t ZIP64Index; uint16_t ZIP64Size; if ([stream readLittleEndianInt32] != 0x04034B50) @throw [OFInvalidFormatException exception]; @@ -664,33 +657,32 @@ _compressedSize = [stream readLittleEndianInt32]; _uncompressedSize = [stream readLittleEndianInt32]; fileNameLength = [stream readLittleEndianInt16]; extraFieldLength = [stream readLittleEndianInt16]; encoding = (_generalPurposeBitFlag & (1u << 11) - ? OF_STRING_ENCODING_UTF_8 - : OF_STRING_ENCODING_CODEPAGE_437); + ? OFStringEncodingUTF8 : OFStringEncodingCodepage437); _fileName = [[stream readStringWithLength: fileNameLength encoding: encoding] copy]; if (extraFieldLength > 0) extraField = [[[stream readDataWithCount: extraFieldLength] mutableCopy] autorelease]; - ZIP64Index = of_zip_archive_entry_extra_field_find(extraField, - OF_ZIP_ARCHIVE_ENTRY_EXTRA_FIELD_ZIP64, &ZIP64Size); + ZIP64Index = OFZIPArchiveEntryExtraFieldFind(extraField, + OFZIPArchiveEntryExtraFieldTagZIP64, &ZIP64Size); - if (ZIP64Index != OF_NOT_FOUND) { + if (ZIP64Index != OFNotFound) { const uint8_t *ZIP64 = [extraField itemAtIndex: ZIP64Index]; - of_range_t range = - of_range(ZIP64Index - 4, ZIP64Size + 4); + OFRange range = + OFRangeMake(ZIP64Index - 4, ZIP64Size + 4); if (_uncompressedSize == 0xFFFFFFFF) - _uncompressedSize = of_zip_archive_read_field64( + _uncompressedSize = OFZIPArchiveReadField64( &ZIP64, &ZIP64Size); if (_compressedSize == 0xFFFFFFFF) - _compressedSize = of_zip_archive_read_field64( + _compressedSize = OFZIPArchiveReadField64( &ZIP64, &ZIP64Size); if (ZIP64Size > 0) @throw [OFInvalidFormatException exception]; @@ -747,18 +739,18 @@ @try { _stream = [stream retain]; switch (entry.compressionMethod) { - case OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_NONE: + case OFZIPArchiveEntryCompressionMethodNone: _decompressedStream = [stream retain]; break; - case OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_DEFLATE: + case OFZIPArchiveEntryCompressionMethodDeflate: _decompressedStream = [[OFInflateStream alloc] initWithStream: stream]; break; - case OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_DEFLATE64: + case OFZIPArchiveEntryCompressionMethodDeflate64: _decompressedStream = [[OFInflate64Stream alloc] initWithStream: stream]; break; default: @throw [OFNotImplementedException @@ -793,12 +785,11 @@ @throw [OFNotOpenException exceptionWithObject: self]; return _atEndOfStream; } -- (size_t)lowlevelReadIntoBuffer: (void *)buffer - length: (size_t)length +- (size_t)lowlevelReadIntoBuffer: (void *)buffer length: (size_t)length { size_t ret; if (_stream == nil) @throw [OFNotOpenException exceptionWithObject: self]; @@ -815,15 +806,14 @@ #endif if ((uint64_t)length > _toRead) length = (size_t)_toRead; - ret = [_decompressedStream readIntoBuffer: buffer - length: length]; + ret = [_decompressedStream readIntoBuffer: buffer length: length]; _toRead -= ret; - _CRC32 = of_crc32(_CRC32, buffer, ret); + _CRC32 = OFCRC32(_CRC32, buffer, ret); if (_toRead == 0) { _atEndOfStream = true; if (~_CRC32 != _entry.CRC32) { @@ -889,30 +879,38 @@ [_entry release]; [super dealloc]; } -- (size_t)lowlevelWriteBuffer: (const void *)buffer - length: (size_t)length +- (size_t)lowlevelWriteBuffer: (const void *)buffer length: (size_t)length { - size_t bytesWritten; - #if SIZE_MAX >= INT64_MAX if (length > INT64_MAX) @throw [OFOutOfRangeException exception]; #endif if (INT64_MAX - _bytesWritten < (int64_t)length) @throw [OFOutOfRangeException exception]; - bytesWritten = [_stream writeBuffer: buffer - length: length]; + @try { + [_stream writeBuffer: buffer length: length]; + } @catch (OFWriteFailedException *e) { + OFEnsure(e.bytesWritten <= length); + + _bytesWritten += (int64_t)e.bytesWritten; + _CRC32 = OFCRC32(_CRC32, buffer, e.bytesWritten); + + if (e.errNo == EWOULDBLOCK || e.errNo == EAGAIN) + return e.bytesWritten; + + @throw e; + } - _bytesWritten += (int64_t)bytesWritten; - _CRC32 = of_crc32(_CRC32, buffer, length); + _bytesWritten += (int64_t)length; + _CRC32 = OFCRC32(_CRC32, buffer, length); - return bytesWritten; + return length; } - (void)close { if (_stream == nil) Index: src/OFZIPArchiveEntry+Private.h ================================================================== --- src/OFZIPArchiveEntry+Private.h +++ src/OFZIPArchiveEntry+Private.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/OFZIPArchiveEntry.h ================================================================== --- src/OFZIPArchiveEntry.h +++ src/OFZIPArchiveEntry.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -19,75 +17,79 @@ OF_ASSUME_NONNULL_BEGIN /** @file */ -enum { - OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_NONE = 0, - OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_SHRINK = 1, - OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_REDUCE_FACTOR_1 = 2, - OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_REDUCE_FACTOR_2 = 3, - OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_REDUCE_FACTOR_3 = 4, - OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_REDUCE_FACTOR_4 = 5, - OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_IMPLODE = 6, - OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_DEFLATE = 8, - OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_DEFLATE64 = 9, - OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_BZIP2 = 12, - OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_LZMA = 14, - OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_WAVPACK = 97, - OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_PPMD = 98 -}; +typedef enum { + OFZIPArchiveEntryCompressionMethodNone = 0, + OFZIPArchiveEntryCompressionMethodShrink = 1, + OFZIPArchiveEntryCompressionMethodReduceFactor1 = 2, + OFZIPArchiveEntryCompressionMethodReduceFactor2 = 3, + OFZIPArchiveEntryCompressionMethodReduceFactor3 = 4, + OFZIPArchiveEntryCompressionMethodReduceFactor4 = 5, + OFZIPArchiveEntryCompressionMethodImplode = 6, + OFZIPArchiveEntryCompressionMethodDeflate = 8, + OFZIPArchiveEntryCompressionMethodDeflate64 = 9, + OFZIPArchiveEntryCompressionMethodBZIP2 = 12, + OFZIPArchiveEntryCompressionMethodLZMA = 14, + OFZIPArchiveEntryCompressionMethodWavPack = 97, + OFZIPArchiveEntryCompressionMethodPPMd = 98 +} OFZIPArchiveEntryCompressionMethod; /** * @brief Attribute compatibility part of ZIP versions. */ -enum of_zip_archive_entry_attribute_compatibility { +typedef enum { /** MS-DOS and OS/2 */ - OF_ZIP_ARCHIVE_ENTRY_ATTR_COMPAT_MSDOS = 0, + OFZIPArchiveEntryAttributeCompatibilityMSDOS = 0, /** Amiga */ - OF_ZIP_ARCHIVE_ENTRY_ATTR_COMPAT_AMIGA = 1, + OFZIPArchiveEntryAttributeCompatibilityAmiga = 1, /** OpenVMS */ - OF_ZIP_ARCHIVE_ENTRY_ATTR_COMPAT_OPENVMS = 2, + OFZIPArchiveEntryAttributeCompatibilityOpenVMS = 2, /** UNIX */ - OF_ZIP_ARCHIVE_ENTRY_ATTR_COMPAT_UNIX = 3, + OFZIPArchiveEntryAttributeCompatibilityUNIX = 3, /** VM/CMS */ - OF_ZIP_ARCHIVE_ENTRY_ATTR_COMPAT_VM_CMS = 4, + OFZIPArchiveEntryAttributeCompatibilityVM_CMS = 4, /** Atari ST */ - OF_ZIP_ARCHIVE_ENTRY_ATTR_COMPAT_ATARI_ST = 5, + OFZIPArchiveEntryAttributeCompatibilityAtariST = 5, /** OS/2 HPFS */ - OF_ZIP_ARCHIVE_ENTRY_ATTR_COMPAT_OS2_HPFS = 6, + OFZIPArchiveEntryAttributeCompatibilityOS2HPFS = 6, /** Macintosh */ - OF_ZIP_ARCHIVE_ENTRY_ATTR_COMPAT_MACINTOSH = 7, + OFZIPArchiveEntryAttributeCompatibilityMacintosh = 7, /** Z-System */ - OF_ZIP_ARCHIVE_ENTRY_ATTR_COMPAT_Z_SYSTEM = 8, + OFZIPArchiveEntryAttributeCompatibilityZSystem = 8, /** CP/M */ - OF_ZIP_ARCHIVE_ENTRY_ATTR_COMPAT_CP_M = 9, + OFZIPArchiveEntryAttributeCompatibilityCPM = 9, /** Windows NTFS */ - OF_ZIP_ARCHIVE_ENTRY_ATTR_COMPAT_WINDOWS_NTFS = 10, + OFZIPArchiveEntryAttributeCompatibilityWindowsNTFS = 10, /** MVS (OS/390 - Z/OS) */ - OF_ZIP_ARCHIVE_ENTRY_ATTR_COMPAT_MVS = 11, + OFZIPArchiveEntryAttributeCompatibilityMVS = 11, /** VSE */ - OF_ZIP_ARCHIVE_ENTRY_ATTR_COMPAT_VSE = 12, + OFZIPArchiveEntryAttributeCompatibilityVSE = 12, /** Acorn RISC OS */ - OF_ZIP_ARCHIVE_ENTRY_ATTR_COMPAT_ACORN_RISC_OS = 13, + OFZIPArchiveEntryAttributeCompatibilityAcornRISCOS = 13, /** VFAT */ - OF_ZIP_ARCHIVE_ENTRY_ATTR_COMPAT_VFAT = 14, + OFZIPArchiveEntryAttributeCompatibilityVFAT = 14, /** Alternate MVS */ - OF_ZIP_ARCHIVE_ENTRY_ATTR_COMPAT_ALTERNATE_MVS = 15, + OFZIPArchiveEntryAttributeCompatibilityAlternateMVS = 15, /** BeOS */ - OF_ZIP_ARCHIVE_ENTRY_ATTR_COMPAT_BEOS = 16, + OFZIPArchiveEntryAttributeCompatibilityBeOS = 16, /** Tandem */ - OF_ZIP_ARCHIVE_ENTRY_ATTR_COMPAT_TANDEM = 17, + OFZIPArchiveEntryAttributeCompatibilityTandem = 17, /** OS/400 */ - OF_ZIP_ARCHIVE_ENTRY_ATTR_COMPAT_OS_400 = 18, + OFZIPArchiveEntryAttributeCompatibilityOS400 = 18, /** OS X (Darwin) */ - OF_ZIP_ARCHIVE_ENTRY_ATTR_COMPAT_OS_X = 19 -}; + OFZIPArchiveEntryAttributeCompatibilityOSX = 19 +} OFZIPArchiveEntryAttributeCompatibility; -enum { - OF_ZIP_ARCHIVE_ENTRY_EXTRA_FIELD_ZIP64 = 0x0001 -}; +/** + * @brief Tags for the extra field. + */ +typedef enum { + /** ZIP64 extra field tag */ + OFZIPArchiveEntryExtraFieldTagZIP64 = 0x0001 +} OFZIPArchiveEntryExtraFieldTag; @class OFString; @class OFData; @class OFFile; @class OFDate; @@ -98,12 +100,14 @@ * @brief A class which represents an entry in the central directory of a ZIP * archive. */ @interface OFZIPArchiveEntry: OFObject { - uint16_t _versionMadeBy, _minVersionNeeded, _generalPurposeBitFlag; - uint16_t _compressionMethod; + OFZIPArchiveEntryAttributeCompatibility _versionMadeBy; + OFZIPArchiveEntryAttributeCompatibility _minVersionNeeded; + uint16_t _generalPurposeBitFlag; + OFZIPArchiveEntryCompressionMethod _compressionMethod; uint16_t _lastModifiedFileTime, _lastModifiedFileDate; uint32_t _CRC32; uint64_t _compressedSize, _uncompressedSize; OFString *_fileName; OFData *_Nullable _extraField; @@ -136,22 +140,24 @@ /** * @brief The version which made the entry. * * The lower 8 bits are the ZIP specification version.@n * The upper 8 bits are the attribute compatibility. - * See @ref of_zip_archive_entry_attribute_compatibility. + * See @ref OFZIPArchiveEntryAttributeCompatibility. */ -@property (readonly, nonatomic) uint16_t versionMadeBy; +@property (readonly, nonatomic) + OFZIPArchiveEntryAttributeCompatibility versionMadeBy; /** * @brief The minimum version required to extract the file. * * The lower 8 bits are the ZIP specification version.@n * The upper 8 bits are the attribute compatibility. - * See @ref of_zip_archive_entry_attribute_compatibility. + * See @ref OFZIPArchiveEntryAttributeCompatibility. */ -@property (readonly, nonatomic) uint16_t minVersionNeeded; +@property (readonly, nonatomic) + OFZIPArchiveEntryAttributeCompatibility minVersionNeeded; /** * @brief The last modification date of the entry's file. * * @note Due to limitations of the ZIP format, this has only 2 second precision. @@ -160,19 +166,20 @@ /** * @brief The compression method of the entry. * * Supported values are: - * Value | Description - * --------------------------------------------------|--------------- - * OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_NONE | No compression - * OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_DEFLATE | Deflate - * OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_DEFLATE64 | Deflate64 + * Value | Description + * --------------------------------------------|--------------- + * OFZIPArchiveEntryCompressionMethodNone | No compression + * OFZIPArchiveEntryCompressionMethodDeflate | Deflate + * OFZIPArchiveEntryCompressionMethodDeflate64 | Deflate64 * * Other values may be returned, but the file cannot be extracted then. */ -@property (readonly, nonatomic) uint16_t compressionMethod; +@property (readonly, nonatomic) + OFZIPArchiveEntryCompressionMethod compressionMethod; /** * @brief The compressed size of the entry's file. */ @property (readonly, nonatomic) uint64_t compressedSize; @@ -229,21 +236,21 @@ * @brief Converts the ZIP entry version to a string. * * @param version The ZIP entry version to convert to a string * @return The ZIP entry version as a string */ -extern OFString *of_zip_archive_entry_version_to_string(uint16_t version); +extern OFString *OFZIPArchiveEntryVersionToString(uint16_t version); /** * @brief Convers the ZIP entry compression method to a string. * * @param compressionMethod The ZIP entry compression method to convert to a * string * @return The ZIP entry compression method as a string */ -extern OFString *of_zip_archive_entry_compression_method_to_string( - uint16_t compressionMethod); +extern OFString *OFZIPArchiveEntryCompressionMethodName( + OFZIPArchiveEntryCompressionMethod compressionMethod); /** * @brief Gets a pointer to and the size of the extensible data field with the * specified tag. * @@ -250,16 +257,16 @@ * @param extraField The extra field to search for an extensible data field with * the specified tag * @param tag The tag to look for * @param size A pointer to an uint16_t that should be set to the size * @return The index at which the extra field content starts in the OFData, or - * OF_NOT_FOUND + * `OFNotFound` */ -extern size_t of_zip_archive_entry_extra_field_find(OFData *extraField, - uint16_t tag, uint16_t *size); +extern size_t OFZIPArchiveEntryExtraFieldFind(OFData *extraField, + OFZIPArchiveEntryExtraFieldTag tag, uint16_t *size); #ifdef __cplusplus } #endif OF_ASSUME_NONNULL_END #import "OFMutableZIPArchiveEntry.h" Index: src/OFZIPArchiveEntry.m ================================================================== --- src/OFZIPArchiveEntry.m +++ src/OFZIPArchiveEntry.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -26,77 +24,74 @@ #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFOutOfRangeException.h" -extern uint32_t of_zip_archive_read_field32(const uint8_t **, uint16_t *); -extern uint64_t of_zip_archive_read_field64(const uint8_t **, uint16_t *); - OFString * -of_zip_archive_entry_version_to_string(uint16_t version) +OFZIPArchiveEntryVersionToString(uint16_t version) { const char *attrCompat = NULL; switch (version >> 8) { - case OF_ZIP_ARCHIVE_ENTRY_ATTR_COMPAT_MSDOS: + case OFZIPArchiveEntryAttributeCompatibilityMSDOS: attrCompat = "MS-DOS or OS/2"; break; - case OF_ZIP_ARCHIVE_ENTRY_ATTR_COMPAT_AMIGA: + case OFZIPArchiveEntryAttributeCompatibilityAmiga: attrCompat = "Amiga"; break; - case OF_ZIP_ARCHIVE_ENTRY_ATTR_COMPAT_OPENVMS: + case OFZIPArchiveEntryAttributeCompatibilityOpenVMS: attrCompat = "OpenVMS"; break; - case OF_ZIP_ARCHIVE_ENTRY_ATTR_COMPAT_UNIX: + case OFZIPArchiveEntryAttributeCompatibilityUNIX: attrCompat = "UNIX"; break; - case OF_ZIP_ARCHIVE_ENTRY_ATTR_COMPAT_VM_CMS: + case OFZIPArchiveEntryAttributeCompatibilityVM_CMS: attrCompat = "VM/CMS"; break; - case OF_ZIP_ARCHIVE_ENTRY_ATTR_COMPAT_ATARI_ST: + case OFZIPArchiveEntryAttributeCompatibilityAtariST: attrCompat = "Atari ST"; break; - case OF_ZIP_ARCHIVE_ENTRY_ATTR_COMPAT_OS2_HPFS: + case OFZIPArchiveEntryAttributeCompatibilityOS2HPFS: attrCompat = "OS/2 HPFS"; break; - case OF_ZIP_ARCHIVE_ENTRY_ATTR_COMPAT_MACINTOSH: + case OFZIPArchiveEntryAttributeCompatibilityMacintosh: attrCompat = "Macintosh"; break; - case OF_ZIP_ARCHIVE_ENTRY_ATTR_COMPAT_Z_SYSTEM: + case OFZIPArchiveEntryAttributeCompatibilityZSystem: attrCompat = "Z-System"; break; - case OF_ZIP_ARCHIVE_ENTRY_ATTR_COMPAT_CP_M: + case OFZIPArchiveEntryAttributeCompatibilityCPM: attrCompat = "CP/M"; break; - case OF_ZIP_ARCHIVE_ENTRY_ATTR_COMPAT_WINDOWS_NTFS: + case OFZIPArchiveEntryAttributeCompatibilityWindowsNTFS: attrCompat = "Windows NTFS"; break; - case OF_ZIP_ARCHIVE_ENTRY_ATTR_COMPAT_MVS: + case OFZIPArchiveEntryAttributeCompatibilityMVS: attrCompat = "MVS (OS/390 - Z/OS)"; break; - case OF_ZIP_ARCHIVE_ENTRY_ATTR_COMPAT_VSE: + case OFZIPArchiveEntryAttributeCompatibilityVSE: attrCompat = "VSE"; break; - case OF_ZIP_ARCHIVE_ENTRY_ATTR_COMPAT_ACORN_RISC_OS: + case OFZIPArchiveEntryAttributeCompatibilityAcornRISCOS: attrCompat = "Acorn RISC OS"; break; - case OF_ZIP_ARCHIVE_ENTRY_ATTR_COMPAT_VFAT: + case OFZIPArchiveEntryAttributeCompatibilityVFAT: attrCompat = "VFAT"; break; - case OF_ZIP_ARCHIVE_ENTRY_ATTR_COMPAT_ALTERNATE_MVS: + case OFZIPArchiveEntryAttributeCompatibilityAlternateMVS: attrCompat = "Alternate MVS"; break; - case OF_ZIP_ARCHIVE_ENTRY_ATTR_COMPAT_BEOS: + case OFZIPArchiveEntryAttributeCompatibilityBeOS: attrCompat = "BeOS"; break; - case OF_ZIP_ARCHIVE_ENTRY_ATTR_COMPAT_TANDEM: + case OFZIPArchiveEntryAttributeCompatibilityTandem: attrCompat = "Tandem"; break; - case OF_ZIP_ARCHIVE_ENTRY_ATTR_COMPAT_OS_400: + case OFZIPArchiveEntryAttributeCompatibilityOS400: attrCompat = "OS/400"; break; - case OF_ZIP_ARCHIVE_ENTRY_ATTR_COMPAT_OS_X: + case OFZIPArchiveEntryAttributeCompatibilityOSX: attrCompat = "OS X (Darwin)"; break; } if (attrCompat != NULL) @@ -108,47 +103,48 @@ @"%u.%u, unknown %02X", (version % 0xFF) / 10, (version & 0xFF) % 10, version >> 8]; } OFString * -of_zip_archive_entry_compression_method_to_string(uint16_t compressionMethod) +OFZIPArchiveEntryCompressionMethodName( + OFZIPArchiveEntryCompressionMethod compressionMethod) { switch (compressionMethod) { - case OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_NONE: + case OFZIPArchiveEntryCompressionMethodNone: return @"none"; - case OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_SHRINK: + case OFZIPArchiveEntryCompressionMethodShrink: return @"Shrink"; - case OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_REDUCE_FACTOR_1: + case OFZIPArchiveEntryCompressionMethodReduceFactor1: return @"Reduce (factor 1)"; - case OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_REDUCE_FACTOR_2: + case OFZIPArchiveEntryCompressionMethodReduceFactor2: return @"Reduce (factor 2)"; - case OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_REDUCE_FACTOR_3: + case OFZIPArchiveEntryCompressionMethodReduceFactor3: return @"Reduce (factor 3)"; - case OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_REDUCE_FACTOR_4: + case OFZIPArchiveEntryCompressionMethodReduceFactor4: return @"Reduce (factor 4)"; - case OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_IMPLODE: + case OFZIPArchiveEntryCompressionMethodImplode: return @"Implode"; - case OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_DEFLATE: + case OFZIPArchiveEntryCompressionMethodDeflate: return @"Deflate"; - case OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_DEFLATE64: + case OFZIPArchiveEntryCompressionMethodDeflate64: return @"Deflate64"; - case OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_BZIP2: + case OFZIPArchiveEntryCompressionMethodBZIP2: return @"BZip2"; - case OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_LZMA: + case OFZIPArchiveEntryCompressionMethodLZMA: return @"LZMA"; - case OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_WAVPACK: + case OFZIPArchiveEntryCompressionMethodWavPack: return @"WavPack"; - case OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_PPMD: + case OFZIPArchiveEntryCompressionMethodPPMd: return @"PPMd"; default: return @"unknown"; } } size_t -of_zip_archive_entry_extra_field_find(OFData *extraField, uint16_t tag, - uint16_t *size) +OFZIPArchiveEntryExtraFieldFind(OFData *extraField, + OFZIPArchiveEntryExtraFieldTag tag, uint16_t *size) { const uint8_t *bytes = extraField.items; size_t count = extraField.count; for (size_t i = 0; i < count;) { @@ -170,11 +166,11 @@ i += 4 + currentSize; } *size = 0; - return OF_NOT_FOUND; + return OFNotFound; } @implementation OFZIPArchiveEntry + (instancetype)entryWithFileName: (OFString *)fileName { @@ -213,11 +209,11 @@ @try { void *pool = objc_autoreleasePoolPush(); OFMutableData *extraField = nil; uint16_t fileNameLength, extraFieldLength, fileCommentLength; - of_string_encoding_t encoding; + OFStringEncoding encoding; size_t ZIP64Index; uint16_t ZIP64Size; if ([stream readLittleEndianInt32] != 0x02014B50) @throw [OFInvalidFormatException exception]; @@ -238,12 +234,11 @@ _internalAttributes = [stream readLittleEndianInt16]; _versionSpecificAttributes = [stream readLittleEndianInt32]; _localFileHeaderOffset = [stream readLittleEndianInt32]; encoding = (_generalPurposeBitFlag & (1u << 11) - ? OF_STRING_ENCODING_UTF_8 - : OF_STRING_ENCODING_CODEPAGE_437); + ? OFStringEncodingUTF8 : OFStringEncodingCodepage437); _fileName = [[stream readStringWithLength: fileNameLength encoding: encoding] copy]; if (extraFieldLength > 0) extraField = [[[stream readDataWithCount: @@ -251,31 +246,30 @@ if (fileCommentLength > 0) _fileComment = [[stream readStringWithLength: fileCommentLength encoding: encoding] copy]; - ZIP64Index = of_zip_archive_entry_extra_field_find(extraField, - OF_ZIP_ARCHIVE_ENTRY_EXTRA_FIELD_ZIP64, &ZIP64Size); + ZIP64Index = OFZIPArchiveEntryExtraFieldFind(extraField, + OFZIPArchiveEntryExtraFieldTagZIP64, &ZIP64Size); - if (ZIP64Index != OF_NOT_FOUND) { + if (ZIP64Index != OFNotFound) { const uint8_t *ZIP64 = [extraField itemAtIndex: ZIP64Index]; - of_range_t range = - of_range(ZIP64Index - 4, ZIP64Size + 4); + OFRange range = + OFRangeMake(ZIP64Index - 4, ZIP64Size + 4); if (_uncompressedSize == 0xFFFFFFFF) - _uncompressedSize = of_zip_archive_read_field64( + _uncompressedSize = OFZIPArchiveReadField64( &ZIP64, &ZIP64Size); if (_compressedSize == 0xFFFFFFFF) - _compressedSize = of_zip_archive_read_field64( + _compressedSize = OFZIPArchiveReadField64( &ZIP64, &ZIP64Size); if (_localFileHeaderOffset == 0xFFFFFFFF) _localFileHeaderOffset = - of_zip_archive_read_field64(&ZIP64, - &ZIP64Size); + OFZIPArchiveReadField64(&ZIP64, &ZIP64Size); if (_startDiskNumber == 0xFFFF) - _startDiskNumber = of_zip_archive_read_field32( + _startDiskNumber = OFZIPArchiveReadField32( &ZIP64, &ZIP64Size); if (ZIP64Size > 0 || _localFileHeaderOffset < 0) @throw [OFInvalidFormatException exception]; @@ -352,16 +346,16 @@ - (OFData *)extraField { return _extraField; } -- (uint16_t)versionMadeBy +- (OFZIPArchiveEntryAttributeCompatibility)versionMadeBy { return _versionMadeBy; } -- (uint16_t)minVersionNeeded +- (OFZIPArchiveEntryAttributeCompatibility)minVersionNeeded { return _minVersionNeeded; } - (OFDate *)modificationDate @@ -386,11 +380,11 @@ objc_autoreleasePoolPop(pool); return [date autorelease]; } -- (uint16_t)compressionMethod +- (OFZIPArchiveEntryCompressionMethod)compressionMethod { return _compressionMethod; } - (uint64_t)compressedSize @@ -435,12 +429,11 @@ - (OFString *)description { void *pool = objc_autoreleasePoolPush(); OFString *compressionMethod = - of_zip_archive_entry_compression_method_to_string( - _compressionMethod); + OFZIPArchiveEntryCompressionMethodName(_compressionMethod); OFString *ret = [OFString stringWithFormat: @"<%@:\n" @"\tFile name = %@\n" @"\tFile comment = %@\n" @"\tGeneral purpose bit flag = %u\n" @@ -491,11 +484,11 @@ size += (4 + (6 * 2) + (3 * 4) + (5 * 2) + (2 * 4)); [stream writeString: _fileName]; size += (uint64_t)_fileName.UTF8StringLength; - [stream writeLittleEndianInt16: OF_ZIP_ARCHIVE_ENTRY_EXTRA_FIELD_ZIP64]; + [stream writeLittleEndianInt16: OFZIPArchiveEntryExtraFieldTagZIP64]; [stream writeLittleEndianInt16: 28]; [stream writeLittleEndianInt64: _uncompressedSize]; [stream writeLittleEndianInt64: _compressedSize]; [stream writeLittleEndianInt64: _localFileHeaderOffset]; [stream writeLittleEndianInt32: _startDiskNumber]; Index: src/ObjFW.h ================================================================== --- src/ObjFW.h +++ src/ObjFW.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -45,14 +43,18 @@ #import "OFMethodSignature.h" #import "OFInvocation.h" #import "OFNumber.h" #import "OFDate.h" +#import "OFUUID.h" #import "OFURL.h" #import "OFURLHandler.h" #import "OFColor.h" +#import "OFNotification.h" +#import "OFNotificationCenter.h" + #import "OFStream.h" #import "OFStdIOStream.h" #import "OFInflateStream.h" #import "OFInflate64Stream.h" #import "OFGZIPStream.h" @@ -72,11 +74,11 @@ # import "OFStreamSocket.h" # import "OFDatagramSocket.h" # import "OFSequencedPacketSocket.h" # import "OFTCPSocket.h" # import "OFUDPSocket.h" -# import "OFTLSSocket.h" +# import "OFTLSStream.h" # import "OFKernelEventObserver.h" # import "OFDNSQuery.h" # import "OFDNSResourceRecord.h" # import "OFDNSResponse.h" # import "OFDNSResolver.h" @@ -83,12 +85,13 @@ # ifdef OF_HAVE_IPX # import "OFIPXSocket.h" # import "OFSPXSocket.h" # import "OFSPXStreamSocket.h" # endif -# ifdef OF_HAVE_SCTP -# import "OFSCTPSocket.h" +# ifdef OF_HAVE_UNIX_SOCKETS +# import "OFUNIXDatagramSocket.h" +# import "OFUNIXStreamSocket.h" # endif #endif #ifdef OF_HAVE_SOCKETS # ifdef OF_HAVE_THREADS # import "OFHTTPClient.h" @@ -98,15 +101,15 @@ # import "OFHTTPRequest.h" # import "OFHTTPResponse.h" # import "OFHTTPServer.h" #endif -#ifdef OF_HAVE_PROCESSES -# import "OFProcess.h" +#ifdef OF_HAVE_SUBPROCESSES +# import "OFSubprocess.h" #endif -#import "OFCryptoHash.h" +#import "OFCryptographicHash.h" #import "OFMD5Hash.h" #import "OFRIPEMD160Hash.h" #import "OFSHA1Hash.h" #import "OFSHA224Hash.h" #import "OFSHA256Hash.h" @@ -119,11 +122,11 @@ #import "OFXMLElement.h" #import "OFXMLAttribute.h" #import "OFXMLCharacters.h" #import "OFXMLCDATA.h" #import "OFXMLComment.h" -#import "OFXMLProcessingInstructions.h" +#import "OFXMLProcessingInstruction.h" #import "OFXMLParser.h" #import "OFXMLElementBuilder.h" #import "OFMessagePackExtension.h" @@ -131,28 +134,15 @@ #import "OFSystemInfo.h" #import "OFLocale.h" #import "OFOptionsParser.h" #import "OFTimer.h" #import "OFRunLoop.h" -#import "OFSandbox.h" #ifdef OF_WINDOWS # import "OFWindowsRegistryKey.h" #endif -#import "OFASN1BitString.h" -#import "OFASN1Boolean.h" -#import "OFASN1Enumerated.h" -#import "OFASN1IA5String.h" -#import "OFASN1Integer.h" -#import "OFASN1NumericString.h" -#import "OFASN1ObjectIdentifier.h" -#import "OFASN1OctetString.h" -#import "OFASN1PrintableString.h" -#import "OFASN1UTF8String.h" -#import "OFASN1Value.h" - #import "OFAllocFailedException.h" #import "OFException.h" #ifdef OF_HAVE_SOCKETS # import "OFAcceptFailedException.h" # import "OFAlreadyConnectedException.h" @@ -189,10 +179,11 @@ #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" @@ -207,11 +198,10 @@ #ifdef OF_HAVE_PLUGINS # import "OFLoadPluginFailedException.h" #endif #import "OFLockFailedException.h" #import "OFMalformedXMLException.h" -#import "OFMemoryNotPartOfObjectException.h" #import "OFMoveItemFailedException.h" #import "OFNotImplementedException.h" #import "OFNotOpenException.h" #ifdef OF_HAVE_SOCKETS # import "OFObserveFailedException.h" @@ -227,11 +217,10 @@ #import "OFRemoveItemFailedException.h" #ifdef OF_HAVE_SOCKETS # import "OFResolveHostFailedException.h" #endif #import "OFRetrieveItemAttributesFailedException.h" -#import "OFSandboxActivationFailedException.h" #import "OFSeekFailedException.h" #import "OFSetItemAttributesFailedException.h" #import "OFSetOptionFailedException.h" #ifdef OF_WINDOWS # import "OFSetWindowsRegistryValueFailedException.h" @@ -240,10 +229,13 @@ #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" @@ -255,33 +247,22 @@ #ifdef OF_HAVE_PLUGINS # import "OFPlugin.h" #endif #ifdef OF_HAVE_ATOMIC_OPS -# import "atomic.h" -#endif - -#import "OFLocking.h" -#import "OFThread.h" -#import "once.h" -#ifdef OF_HAVE_THREADS -# import "thread.h" -# import "tlskey.h" -# import "mutex.h" -# import "condition.h" -# import "OFThreadPool.h" -# import "OFMutex.h" -# import "OFRecursiveMutex.h" -# import "OFCondition.h" -#endif - -#import "base64.h" -#import "crc16.h" -#import "crc32.h" -#import "huffman_tree.h" -#import "of_asprintf.h" -#import "of_strptime.h" -#import "pbkdf2.h" -#import "scrypt.h" -#ifdef OF_HAVE_UNICODE_TABLES -# import "unicode.h" -#endif +# import "OFAtomic.h" +#endif +#import "OFLocking.h" +#import "OFOnce.h" +#import "OFThread.h" +#ifdef OF_HAVE_THREADS +# import "OFCondition.h" +# import "OFMutex.h" +# import "OFPlainCondition.h" +# import "OFPlainMutex.h" +# import "OFPlainThread.h" +# import "OFRecursiveMutex.h" +# import "OFTLSKey.h" +#endif + +#import "OFPBKDF2.h" +#import "OFScrypt.h" DELETED src/atomic.h Index: src/atomic.h ================================================================== --- src/atomic.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 - -#import "macros.h" - -#ifndef OF_HAVE_ATOMIC_OPS -# error No atomic operations available! -#endif - -#if !defined(OF_HAVE_THREADS) -# import "atomic_no_threads.h" -#elif defined(OF_X86_64_ASM) || defined(OF_X86_ASM) -# import "atomic_x86.h" -#elif defined(OF_POWERPC_ASM) && !defined(__APPLE_CC__) && !defined(OF_AIX) -# import "atomic_powerpc.h" -#elif defined(OF_HAVE_ATOMIC_BUILTINS) -# import "atomic_builtins.h" -#elif defined(OF_HAVE_SYNC_BUILTINS) -# import "atomic_sync_builtins.h" -#elif defined(OF_HAVE_OSATOMIC) -# import "atomic_osatomic.h" -#else -# error No atomic operations available! -#endif DELETED src/atomic_builtins.h Index: src/atomic_builtins.h ================================================================== --- src/atomic_builtins.h +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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. - */ - -static OF_INLINE int -of_atomic_int_add(volatile int *_Nonnull p, int i) -{ - return __atomic_add_fetch(p, i, __ATOMIC_RELAXED); -} - -static OF_INLINE int32_t -of_atomic_int32_add(volatile int32_t *_Nonnull p, int32_t i) -{ - return __atomic_add_fetch(p, i, __ATOMIC_RELAXED); -} - -static OF_INLINE void *_Nullable -of_atomic_ptr_add(void *volatile _Nullable *_Nonnull p, intptr_t i) -{ - return __atomic_add_fetch(p, i, __ATOMIC_RELAXED); -} - -static OF_INLINE int -of_atomic_int_sub(volatile int *_Nonnull p, int i) -{ - return __atomic_sub_fetch(p, i, __ATOMIC_RELAXED); -} - -static OF_INLINE int32_t -of_atomic_int32_sub(volatile int32_t *_Nonnull p, int32_t i) -{ - return __atomic_sub_fetch(p, i, __ATOMIC_RELAXED); -} - -static OF_INLINE void *_Nullable -of_atomic_ptr_sub(void *volatile _Nullable *_Nonnull p, intptr_t i) -{ - return __atomic_sub_fetch(p, i, __ATOMIC_RELAXED); -} - -static OF_INLINE int -of_atomic_int_inc(volatile int *_Nonnull p) -{ - return __atomic_add_fetch(p, 1, __ATOMIC_RELAXED); -} - -static OF_INLINE int32_t -of_atomic_int32_inc(volatile int32_t *_Nonnull p) -{ - return __atomic_add_fetch(p, 1, __ATOMIC_RELAXED); -} - -static OF_INLINE int -of_atomic_int_dec(volatile int *_Nonnull p) -{ - return __atomic_sub_fetch(p, 1, __ATOMIC_RELAXED); -} - -static OF_INLINE int32_t -of_atomic_int32_dec(volatile int32_t *_Nonnull p) -{ - return __atomic_sub_fetch(p, 1, __ATOMIC_RELAXED); -} - -static OF_INLINE unsigned int -of_atomic_int_or(volatile unsigned int *_Nonnull p, unsigned int i) -{ - return __atomic_or_fetch(p, i, __ATOMIC_RELAXED); -} - -static OF_INLINE uint32_t -of_atomic_int32_or(volatile uint32_t *_Nonnull p, uint32_t i) -{ - return __atomic_or_fetch(p, i, __ATOMIC_RELAXED); -} - -static OF_INLINE unsigned int -of_atomic_int_and(volatile unsigned int *_Nonnull p, unsigned int i) -{ - return __atomic_and_fetch(p, i, __ATOMIC_RELAXED); -} - -static OF_INLINE uint32_t -of_atomic_int32_and(volatile uint32_t *_Nonnull p, uint32_t i) -{ - return __atomic_and_fetch(p, i, __ATOMIC_RELAXED); -} - -static OF_INLINE unsigned int -of_atomic_int_xor(volatile unsigned int *_Nonnull p, unsigned int i) -{ - return __atomic_xor_fetch(p, i, __ATOMIC_RELAXED); -} - -static OF_INLINE uint32_t -of_atomic_int32_xor(volatile uint32_t *_Nonnull p, uint32_t i) -{ - return __atomic_xor_fetch(p, i, __ATOMIC_RELAXED); -} - -static OF_INLINE bool -of_atomic_int_cmpswap(volatile int *_Nonnull p, int o, int n) -{ - return __atomic_compare_exchange(p, &o, &n, false, - __ATOMIC_RELAXED, __ATOMIC_RELAXED); -} - -static OF_INLINE bool -of_atomic_int32_cmpswap(volatile int32_t *_Nonnull p, int32_t o, int32_t n) -{ - return __atomic_compare_exchange(p, &o, &n, false, - __ATOMIC_RELAXED, __ATOMIC_RELAXED); -} - -static OF_INLINE bool -of_atomic_ptr_cmpswap(void *volatile _Nullable *_Nonnull p, - void *_Nullable o, void *_Nullable n) -{ - return __atomic_compare_exchange(p, &o, &n, false, - __ATOMIC_RELAXED, __ATOMIC_RELAXED); -} - -static OF_INLINE void -of_memory_barrier_full(void) -{ - __atomic_thread_fence(__ATOMIC_SEQ_CST); -} - -static OF_INLINE void -of_memory_barrier_acquire(void) -{ - __atomic_thread_fence(__ATOMIC_ACQUIRE); -} - -static OF_INLINE void -of_memory_barrier_release(void) -{ - __atomic_thread_fence(__ATOMIC_RELEASE); -} DELETED src/atomic_no_threads.h Index: src/atomic_no_threads.h ================================================================== --- src/atomic_no_threads.h +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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. - */ - -static OF_INLINE int -of_atomic_int_add(volatile int *_Nonnull p, int i) -{ - return (*p += i); -} - -static OF_INLINE int32_t -of_atomic_int32_add(volatile int32_t *_Nonnull p, int32_t i) -{ - return (*p += i); -} - -static OF_INLINE void *_Nullable -of_atomic_ptr_add(void *volatile _Nullable *_Nonnull p, intptr_t i) -{ - return (*(char *volatile *)p += i); -} - -static OF_INLINE int -of_atomic_int_sub(volatile int *_Nonnull p, int i) -{ - return (*p -= i); -} - -static OF_INLINE int32_t -of_atomic_int32_sub(volatile int32_t *_Nonnull p, int32_t i) -{ - return (*p -= i); -} - -static OF_INLINE void *_Nullable -of_atomic_ptr_sub(void *volatile _Nullable *_Nonnull p, intptr_t i) -{ - return (*(char *volatile *)p -= i); -} - -static OF_INLINE int -of_atomic_int_inc(volatile int *_Nonnull p) -{ - return ++*p; -} - -static OF_INLINE int32_t -of_atomic_int32_inc(volatile int32_t *_Nonnull p) -{ - return ++*p; -} - -static OF_INLINE int -of_atomic_int_dec(volatile int *_Nonnull p) -{ - return --*p; -} - -static OF_INLINE int32_t -of_atomic_int32_dec(volatile int32_t *_Nonnull p) -{ - return --*p; -} - -static OF_INLINE unsigned int -of_atomic_int_or(volatile unsigned int *_Nonnull p, unsigned int i) -{ - return (*p |= i); -} - -static OF_INLINE uint32_t -of_atomic_int32_or(volatile uint32_t *_Nonnull p, uint32_t i) -{ - return (*p |= i); -} - -static OF_INLINE unsigned int -of_atomic_int_and(volatile unsigned int *_Nonnull p, unsigned int i) -{ - return (*p &= i); -} - -static OF_INLINE uint32_t -of_atomic_int32_and(volatile uint32_t *_Nonnull p, uint32_t i) -{ - return (*p &= i); -} - -static OF_INLINE unsigned int -of_atomic_int_xor(volatile unsigned int *_Nonnull p, unsigned int i) -{ - return (*p ^= i); -} - -static OF_INLINE uint32_t -of_atomic_int32_xor(volatile uint32_t *_Nonnull p, uint32_t i) -{ - return (*p ^= i); -} - -static OF_INLINE bool -of_atomic_int_cmpswap(volatile int *_Nonnull p, int o, int n) -{ - if (*p == o) { - *p = n; - return true; - } - - return false; -} - -static OF_INLINE bool -of_atomic_int32_cmpswap(volatile int32_t *_Nonnull p, int32_t o, int32_t n) -{ - if (*p == o) { - *p = n; - return true; - } - - return false; -} - -static OF_INLINE bool -of_atomic_ptr_cmpswap(void *volatile _Nullable *_Nonnull p, - void *_Nullable o, void *_Nullable n) -{ - if (*p == o) { - *p = n; - return true; - } - - return false; -} - -static OF_INLINE void -of_memory_barrier(void) -{ - /* nop */ -} - -static OF_INLINE void -of_memory_barrier_acquire(void) -{ - /* nop */ -} - -static OF_INLINE void -of_memory_barrier_release(void) -{ - /* nop */ -} DELETED src/atomic_osatomic.h Index: src/atomic_osatomic.h ================================================================== --- src/atomic_osatomic.h +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 - -static OF_INLINE int -of_atomic_int_add(volatile int *_Nonnull p, int i) -{ - return OSAtomicAdd32(i, p); -} - -static OF_INLINE int32_t -of_atomic_int32_add(volatile int32_t *_Nonnull p, int32_t i) -{ - return OSAtomicAdd32(i, p); -} - -static OF_INLINE void *_Nullable -of_atomic_ptr_add(void *volatile _Nullable *_Nonnull p, intptr_t i) -{ -#ifdef __LP64__ - return (void *)OSAtomicAdd64(i, (int64_t *)p); -#else - return (void *)OSAtomicAdd32(i, (int32_t *)p); -#endif -} - -static OF_INLINE int -of_atomic_int_sub(volatile int *_Nonnull p, int i) -{ - return OSAtomicAdd32(-i, p); -} - -static OF_INLINE int32_t -of_atomic_int32_sub(volatile int32_t *_Nonnull p, int32_t i) -{ - return OSAtomicAdd32(-i, p); -} - -static OF_INLINE void *_Nullable -of_atomic_ptr_sub(void *volatile _Nullable *_Nonnull p, intptr_t i) -{ -#ifdef __LP64__ - return (void *)OSAtomicAdd64(-i, (int64_t *)p); -#else - return (void *)OSAtomicAdd32(-i, (int32_t *)p); -#endif -} - -static OF_INLINE int -of_atomic_int_inc(volatile int *_Nonnull p) -{ - return OSAtomicIncrement32(p); -} - -static OF_INLINE int32_t -of_atomic_int32_inc(volatile int32_t *_Nonnull p) -{ - return OSAtomicIncrement32(p); -} - -static OF_INLINE int -of_atomic_int_dec(volatile int *_Nonnull p) -{ - return OSAtomicDecrement32(p); -} - -static OF_INLINE int32_t -of_atomic_int32_dec(volatile int32_t *_Nonnull p) -{ - return OSAtomicDecrement32(p); -} - -static OF_INLINE unsigned int -of_atomic_int_or(volatile unsigned int *_Nonnull p, unsigned int i) -{ - return OSAtomicOr32(i, p); -} - -static OF_INLINE uint32_t -of_atomic_int32_or(volatile uint32_t *_Nonnull p, uint32_t i) -{ - return OSAtomicOr32(i, p); -} - -static OF_INLINE unsigned int -of_atomic_int_and(volatile unsigned int *_Nonnull p, unsigned int i) -{ - return OSAtomicAnd32(i, p); -} - -static OF_INLINE uint32_t -of_atomic_int32_and(volatile uint32_t *_Nonnull p, uint32_t i) -{ - return OSAtomicAnd32(i, p); -} - -static OF_INLINE unsigned int -of_atomic_int_xor(volatile unsigned int *_Nonnull p, unsigned int i) -{ - return OSAtomicXor32(i, p); -} - -static OF_INLINE uint32_t -of_atomic_int32_xor(volatile uint32_t *_Nonnull p, uint32_t i) -{ - return OSAtomicXor32(i, p); -} - -static OF_INLINE bool -of_atomic_int_cmpswap(volatile int *_Nonnull p, int o, int n) -{ - return OSAtomicCompareAndSwapInt(o, n, p); -} - -static OF_INLINE bool -of_atomic_int32_cmpswap(volatile int32_t *_Nonnull p, int32_t o, int32_t n) -{ - return OSAtomicCompareAndSwap32(o, n, p); -} - -static OF_INLINE bool -of_atomic_ptr_cmpswap(void *volatile _Nullable *_Nonnull p, - void *_Nullable o, void *_Nullable n) -{ - return OSAtomicCompareAndSwapPtr(o, n, p); -} - -static OF_INLINE void -of_memory_barrier(void) -{ - OSMemoryBarrier(); -} - -static OF_INLINE void -of_memory_barrier_acquire(void) -{ - OSMemoryBarrier(); -} - -static OF_INLINE void -of_memory_barrier_release(void) -{ - OSMemoryBarrier(); -} DELETED src/atomic_powerpc.h Index: src/atomic_powerpc.h ================================================================== --- src/atomic_powerpc.h +++ /dev/null @@ -1,399 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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. - */ - -static OF_INLINE int -of_atomic_int_add(volatile int *_Nonnull p, int i) -{ - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %2\n\t" - "add %0, %0, %1\n\t" - "stwcx. %0, 0, %2\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(i), "r"(p) - : "cc", "memory" - ); - - return i; -} - -static OF_INLINE int32_t -of_atomic_int32_add(volatile int32_t *_Nonnull p, int32_t i) -{ - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %2\n\t" - "add %0, %0, %1\n\t" - "stwcx. %0, 0, %2\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(i), "r"(p) - : "cc", "memory" - ); - - return i; -} - -static OF_INLINE void *_Nullable -of_atomic_ptr_add(void *volatile _Nullable *_Nonnull p, intptr_t i) -{ - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %2\n\t" - "add %0, %0, %1\n\t" - "stwcx. %0, 0, %2\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(i), "r"(p) - : "cc", "memory" - ); - - return (void *)i; -} - -static OF_INLINE int -of_atomic_int_sub(volatile int *_Nonnull p, int i) -{ - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %2\n\t" - "sub %0, %0, %1\n\t" - "stwcx. %0, 0, %2\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(i), "r"(p) - : "cc", "memory" - ); - - return i; -} - -static OF_INLINE int32_t -of_atomic_int32_sub(volatile int32_t *_Nonnull p, int32_t i) -{ - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %2\n\t" - "sub %0, %0, %1\n\t" - "stwcx. %0, 0, %2\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(i), "r"(p) - : "cc", "memory" - ); - - return i; -} - -static OF_INLINE void *_Nullable -of_atomic_ptr_sub(void *volatile _Nullable *_Nonnull p, intptr_t i) -{ - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %2\n\t" - "sub %0, %0, %1\n\t" - "stwcx. %0, 0, %2\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(i), "r"(p) - : "cc", "memory" - ); - - return (void *)i; -} - -static OF_INLINE int -of_atomic_int_inc(volatile int *_Nonnull p) -{ - int i; - - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %1\n\t" - "addi %0, %0, 1\n\t" - "stwcx. %0, 0, %1\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(p) - : "cc", "memory" - ); - - return i; -} - -static OF_INLINE int32_t -of_atomic_int32_inc(volatile int32_t *_Nonnull p) -{ - int32_t i; - - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %1\n\t" - "addi %0, %0, 1\n\t" - "stwcx. %0, 0, %1\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(p) - : "cc", "memory" - ); - - return i; -} - -static OF_INLINE int -of_atomic_int_dec(volatile int *_Nonnull p) -{ - int i; - - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %1\n\t" - "subi %0, %0, 1\n\t" - "stwcx. %0, 0, %1\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(p) - : "cc", "memory" - ); - - return i; -} - -static OF_INLINE int32_t -of_atomic_int32_dec(volatile int32_t *_Nonnull p) -{ - int32_t i; - - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %1\n\t" - "subi %0, %0, 1\n\t" - "stwcx. %0, 0, %1\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(p) - : "cc", "memory" - ); - - return i; -} - -static OF_INLINE unsigned int -of_atomic_int_or(volatile unsigned int *_Nonnull p, unsigned int i) -{ - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %2\n\t" - "or %0, %0, %1\n\t" - "stwcx. %0, 0, %2\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(i), "r"(p) - : "cc", "memory" - ); - - return i; -} - -static OF_INLINE uint32_t -of_atomic_int32_or(volatile uint32_t *_Nonnull p, uint32_t i) -{ - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %2\n\t" - "or %0, %0, %1\n\t" - "stwcx. %0, 0, %2\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(i), "r"(p) - : "cc", "memory" - ); - - return i; -} - -static OF_INLINE unsigned int -of_atomic_int_and(volatile unsigned int *_Nonnull p, unsigned int i) -{ - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %2\n\t" - "and %0, %0, %1\n\t" - "stwcx. %0, 0, %2\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(i), "r"(p) - : "cc", "memory" - ); - - return i; -} - -static OF_INLINE uint32_t -of_atomic_int32_and(volatile uint32_t *_Nonnull p, uint32_t i) -{ - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %2\n\t" - "and %0, %0, %1\n\t" - "stwcx. %0, 0, %2\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(i), "r"(p) - : "cc", "memory" - ); - - return i; -} - -static OF_INLINE unsigned int -of_atomic_int_xor(volatile unsigned int *_Nonnull p, unsigned int i) -{ - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %2\n\t" - "xor %0, %0, %1\n\t" - "stwcx. %0, 0, %2\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(i), "r"(p) - : "cc", "memory" - ); - - return i; -} - -static OF_INLINE uint32_t -of_atomic_int32_xor(volatile uint32_t *_Nonnull p, uint32_t i) -{ - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %2\n\t" - "xor %0, %0, %1\n\t" - "stwcx. %0, 0, %2\n\t" - "bne- 0b" - : "=&r"(i) - : "r"(i), "r"(p) - : "cc", "memory" - ); - - return i; -} - -static OF_INLINE bool -of_atomic_int_cmpswap(volatile int *_Nonnull p, int o, int n) -{ - int r; - - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %3\n\t" - "cmpw %0, %1\n\t" - "bne 1f\n\t" - "stwcx. %2, 0, %3\n\t" - "bne- 0b\n\t" - "li %0, 1\n\t" - "b 2f\n\t" - "1:\n\t" - "stwcx. %0, 0, %3\n\t" - "li %0, 0\n\t" - "2:" - : "=&r"(r) - : "r"(o), "r"(n), "r"(p) - : "cc", "memory" - ); - - return r; -} - -static OF_INLINE bool -of_atomic_int32_cmpswap(volatile int32_t *_Nonnull p, int32_t o, int32_t n) -{ - int r; - - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %3\n\t" - "cmpw %0, %1\n\t" - "bne 1f\n\t" - "stwcx. %2, 0, %3\n\t" - "bne- 0b\n\t" - "li %0, 1\n\t" - "b 2f\n\t" - "1:\n\t" - "stwcx. %0, 0, %3\n\t" - "li %0, 0\n\t" - "2:" - : "=&r"(r) - : "r"(o), "r"(n), "r"(p) - : "cc", "memory" - ); - - return r; -} - -static OF_INLINE bool -of_atomic_ptr_cmpswap(void *volatile _Nullable *_Nonnull p, - void *_Nullable o, void *_Nullable n) -{ - int r; - - __asm__ __volatile__ ( - "0:\n\t" - "lwarx %0, 0, %3\n\t" - "cmpw %0, %1\n\t" - "bne 1f\n\t" - "stwcx. %2, 0, %3\n\t" - "bne- 0b\n\t" - "li %0, 1\n\t" - "b 2f\n\t" - "1:\n\t" - "stwcx. %0, 0, %3\n\t" - "li %0, 0\n\t" - "2:" - : "=&r"(r) - : "r"(o), "r"(n), "r"(p) - : "cc", "memory" - ); - - return r; -} - -static OF_INLINE void -of_memory_barrier(void) -{ - __asm__ __volatile__ ( - ".long 0x7C2004AC /* lwsync */" ::: "memory" - ); -} - -static OF_INLINE void -of_memory_barrier_acquire(void) -{ - __asm__ __volatile__ ( - ".long 0x7C2004AC /* lwsync */" ::: "memory" - ); -} - -static OF_INLINE void -of_memory_barrier_release(void) -{ - __asm__ __volatile__ ( - ".long 0x7C2004AC /* lwsync */" ::: "memory" - ); -} DELETED src/atomic_sync_builtins.h Index: src/atomic_sync_builtins.h ================================================================== --- src/atomic_sync_builtins.h +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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. - */ - -static OF_INLINE int -of_atomic_int_add(volatile int *_Nonnull p, int i) -{ - return __sync_add_and_fetch(p, i); -} - -static OF_INLINE int32_t -of_atomic_int32_add(volatile int32_t *_Nonnull p, int32_t i) -{ - return __sync_add_and_fetch(p, i); -} - -static OF_INLINE void *_Nullable -of_atomic_ptr_add(void *volatile _Nullable *_Nonnull p, intptr_t i) -{ - return __sync_add_and_fetch(p, (void *)i); -} - -static OF_INLINE int -of_atomic_int_sub(volatile int *_Nonnull p, int i) -{ - return __sync_sub_and_fetch(p, i); -} - -static OF_INLINE int32_t -of_atomic_int32_sub(volatile int32_t *_Nonnull p, int32_t i) -{ - return __sync_sub_and_fetch(p, i); -} - -static OF_INLINE void *_Nullable -of_atomic_ptr_sub(void *volatile _Nullable *_Nonnull p, intptr_t i) -{ - return __sync_sub_and_fetch(p, (void *)i); -} - -static OF_INLINE int -of_atomic_int_inc(volatile int *_Nonnull p) -{ - return __sync_add_and_fetch(p, 1); -} - -static OF_INLINE int32_t -of_atomic_int32_inc(volatile int32_t *_Nonnull p) -{ - return __sync_add_and_fetch(p, 1); -} - -static OF_INLINE int -of_atomic_int_dec(volatile int *_Nonnull p) -{ - return __sync_sub_and_fetch(p, 1); -} - -static OF_INLINE int32_t -of_atomic_int32_dec(volatile int32_t *_Nonnull p) -{ - return __sync_sub_and_fetch(p, 1); -} - -static OF_INLINE unsigned int -of_atomic_int_or(volatile unsigned int *_Nonnull p, unsigned int i) -{ - return __sync_or_and_fetch(p, i); -} - -static OF_INLINE uint32_t -of_atomic_int32_or(volatile uint32_t *_Nonnull p, uint32_t i) -{ - return __sync_or_and_fetch(p, i); -} - -static OF_INLINE unsigned int -of_atomic_int_and(volatile unsigned int *_Nonnull p, unsigned int i) -{ - return __sync_and_and_fetch(p, i); -} - -static OF_INLINE uint32_t -of_atomic_int32_and(volatile uint32_t *_Nonnull p, uint32_t i) -{ - return __sync_and_and_fetch(p, i); -} - -static OF_INLINE unsigned int -of_atomic_int_xor(volatile unsigned int *_Nonnull p, unsigned int i) -{ - return __sync_xor_and_fetch(p, i); -} - -static OF_INLINE uint32_t -of_atomic_int32_xor(volatile uint32_t *_Nonnull p, uint32_t i) -{ - return __sync_xor_and_fetch(p, i); -} - -static OF_INLINE bool -of_atomic_int_cmpswap(volatile int *_Nonnull p, int o, int n) -{ - return __sync_bool_compare_and_swap(p, o, n); -} - -static OF_INLINE bool -of_atomic_int32_cmpswap(volatile int32_t *_Nonnull p, int32_t o, int32_t n) -{ - return __sync_bool_compare_and_swap(p, o, n); -} - -static OF_INLINE bool -of_atomic_ptr_cmpswap(void *volatile _Nullable *_Nonnull p, - void *_Nullable o, void *_Nullable n) -{ - return __sync_bool_compare_and_swap(p, o, n); -} - -static OF_INLINE void -of_memory_barrier(void) -{ - __sync_synchronize(); -} - -static OF_INLINE void -of_memory_barrier_acquire(void) -{ - __sync_synchronize(); -} - -static OF_INLINE void -of_memory_barrier_release(void) -{ - __sync_synchronize(); -} DELETED src/atomic_x86.h Index: src/atomic_x86.h ================================================================== --- src/atomic_x86.h +++ /dev/null @@ -1,504 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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. - */ - -OF_ASSUME_NONNULL_BEGIN - -static OF_INLINE int -of_atomic_int_add(volatile int *_Nonnull p, int i) -{ - if (sizeof(int) == 4) - __asm__ __volatile__ ( - "lock\n\t" - "xaddl %0, %2\n\t" - "addl %1, %0" - : "+&r"(i) - : "r"(i), "m"(*p) - ); -#ifdef OF_X86_64_ASM - else if (sizeof(int) == 8) - __asm__ __volatile__ ( - "lock\n\t" - "xaddq %0, %2\n\t" - "addq %1, %0" - : "+&r"(i) - : "r"(i), "m"(*p) - ); -#endif - else - abort(); - - return i; -} - -static OF_INLINE int32_t -of_atomic_int32_add(volatile int32_t *_Nonnull p, int32_t i) -{ - __asm__ __volatile__ ( - "lock\n\t" - "xaddl %0, %2\n\t" - "addl %1, %0" - : "+&r"(i) - : "r"(i), "m"(*p) - ); - - return i; -} - -static OF_INLINE void *_Nullable -of_atomic_ptr_add(void *volatile _Nullable *_Nonnull p, intptr_t i) -{ -#if defined(OF_X86_64_ASM) - __asm__ __volatile__ ( - "lock\n\t" - "xaddq %0, %2\n\t" - "addq %1, %0" - : "+&r"(i) - : "r"(i), "m"(*p) - ); - - return (void *)i; -#elif defined(OF_X86_ASM) - __asm__ __volatile__ ( - "lock\n\t" - "xaddl %0, %2\n\t" - "addl %1, %0" - : "+&r"(i) - : "r"(i), "m"(*p) - ); - - return (void *)i; -#endif -} - -static OF_INLINE int -of_atomic_int_sub(volatile int *_Nonnull p, int i) -{ - if (sizeof(int) == 4) - __asm__ __volatile__ ( - "negl %0\n\t" - "lock\n\t" - "xaddl %0, %2\n\t" - "subl %1, %0" - : "+&r"(i) - : "r"(i), "m"(*p) - ); -#ifdef OF_X86_64_ASM - else if (sizeof(int) == 8) - __asm__ __volatile__ ( - "negq %0\n\t" - "lock\n\t" - "xaddq %0, %2\n\t" - "subq %1, %0" - : "+&r"(i) - : "r"(i), "m"(*p) - ); -#endif - else - abort(); - - return i; -} - -static OF_INLINE int32_t -of_atomic_int32_sub(volatile int32_t *_Nonnull p, int32_t i) -{ - __asm__ __volatile__ ( - "negl %0\n\t" - "lock\n\t" - "xaddl %0, %2\n\t" - "subl %1, %0" - : "+&r"(i) - : "r"(i), "m"(*p) - ); - - return i; -} - -static OF_INLINE void *_Nullable -of_atomic_ptr_sub(void *volatile _Nullable *_Nonnull p, intptr_t i) -{ -#if defined(OF_X86_64_ASM) - __asm__ __volatile__ ( - "negq %0\n\t" - "lock\n\t" - "xaddq %0, %2\n\t" - "subq %1, %0" - : "+&r"(i) - : "r"(i), "m"(*p) - ); - - return (void *)i; -#elif defined(OF_X86_ASM) - __asm__ __volatile__ ( - "negl %0\n\t" - "lock\n\t" - "xaddl %0, %2\n\t" - "subl %1, %0" - : "+&r"(i) - : "r"(i), "m"(*p) - ); - - return (void *)i; -#endif -} - -static OF_INLINE int -of_atomic_int_inc(volatile int *_Nonnull p) -{ - int i; - - if (sizeof(int) == 4) - __asm__ __volatile__ ( - "xorl %0, %0\n\t" - "incl %0\n\t" - "lock\n\t" - "xaddl %0, %1\n\t" - "incl %0" - : "=&r"(i) - : "m"(*p) - ); -#ifdef OF_X86_64_ASM - else if (sizeof(int) == 8) - __asm__ __volatile__ ( - "xorq %0, %0\n\t" - "incq %0\n\t" - "lock\n\t" - "xaddq %0, %1\n\t" - "incq %0" - : "=&r"(i) - : "m"(*p) - ); -#endif - else - abort(); - - return i; -} - -static OF_INLINE int32_t -of_atomic_int32_inc(volatile int32_t *_Nonnull p) -{ - int32_t i; - - __asm__ __volatile__ ( - "xorl %0, %0\n\t" - "incl %0\n\t" - "lock\n\t" - "xaddl %0, %1\n\t" - "incl %0" - : "=&r"(i) - : "m"(*p) - ); - - return i; -} - -static OF_INLINE int -of_atomic_int_dec(volatile int *_Nonnull p) -{ - int i; - - if (sizeof(int) == 4) - __asm__ __volatile__ ( - "xorl %0, %0\n\t" - "decl %0\n\t" - "lock\n\t" - "xaddl %0, %1\n\t" - "decl %0" - : "=&r"(i) - : "m"(*p) - ); -#ifdef OF_X86_64_ASM - else if (sizeof(int) == 8) - __asm__ __volatile__ ( - "xorq %0, %0\n\t" - "decq %0\n\t" - "lock\n\t" - "xaddq %0, %1\n\t" - "decq %0" - : "=&r"(i) - : "m"(*p) - ); -#endif - else - abort(); - - return i; -} - -static OF_INLINE int32_t -of_atomic_int32_dec(volatile int32_t *_Nonnull p) -{ - int32_t i; - - __asm__ __volatile__ ( - "xorl %0, %0\n\t" - "decl %0\n\t" - "lock\n\t" - "xaddl %0, %1\n\t" - "decl %0" - : "=&r"(i) - : "m"(*p) - ); - - return i; -} - -static OF_INLINE unsigned int -of_atomic_int_or(volatile unsigned int *_Nonnull p, unsigned int i) -{ - if (sizeof(int) == 4) - __asm__ __volatile__ ( - "0:\n\t" - "movl %2, %0\n\t" - "movl %0, %%eax\n\t" - "orl %1, %0\n\t" - "lock\n\t" - "cmpxchg %0, %2\n\t" - "jne 0b" - : "=&r"(i) - : "r"(i), "m"(*p) - : "eax", "cc" - ); -#ifdef OF_X86_64_ASM - else if (sizeof(int) == 8) - __asm__ __volatile__ ( - "0:\n\t" - "movq %2, %0\n\t" - "movq %0, %%rax\n\t" - "orq %1, %0\n\t" - "lock\n\t" - "cmpxchg %0, %2\n\t" - "jne 0b" - : "=&r"(i) - : "r"(i), "m"(*p) - : "rax", "cc" - ); -#endif - else - abort(); - - return i; -} - -static OF_INLINE uint32_t -of_atomic_int32_or(volatile uint32_t *_Nonnull p, uint32_t i) -{ - __asm__ __volatile__ ( - "0:\n\t" - "movl %2, %0\n\t" - "movl %0, %%eax\n\t" - "orl %1, %0\n\t" - "lock\n\t" - "cmpxchg %0, %2\n\t" - "jne 0b" - : "=&r"(i) - : "r"(i), "m"(*p) - : "eax", "cc" - ); - - return i; -} - -static OF_INLINE unsigned int -of_atomic_int_and(volatile unsigned int *_Nonnull p, unsigned int i) -{ - if (sizeof(int) == 4) - __asm__ __volatile__ ( - "0:\n\t" - "movl %2, %0\n\t" - "movl %0, %%eax\n\t" - "andl %1, %0\n\t" - "lock\n\t" - "cmpxchg %0, %2\n\t" - "jne 0b" - : "=&r"(i) - : "r"(i), "m"(*p) - : "eax", "cc" - ); -#ifdef OF_X86_64_ASM - else if (sizeof(int) == 8) - __asm__ __volatile__ ( - "0:\n\t" - "movq %2, %0\n\t" - "movq %0, %%rax\n\t" - "andq %1, %0\n\t" - "lock\n\t" - "cmpxchg %0, %2\n\t" - "jne 0b" - : "=&r"(i) - : "r"(i), "m"(*p) - : "rax", "cc" - ); -#endif - else - abort(); - - return i; -} - -static OF_INLINE uint32_t -of_atomic_int32_and(volatile uint32_t *_Nonnull p, uint32_t i) -{ - __asm__ __volatile__ ( - "0:\n\t" - "movl %2, %0\n\t" - "movl %0, %%eax\n\t" - "andl %1, %0\n\t" - "lock\n\t" - "cmpxchg %0, %2\n\t" - "jne 0b" - : "=&r"(i) - : "r"(i), "m"(*p) - : "eax", "cc" - ); - - return i; -} - -static OF_INLINE unsigned int -of_atomic_int_xor(volatile unsigned int *_Nonnull p, unsigned int i) -{ - if (sizeof(int) == 4) - __asm__ __volatile__ ( - "0:\n\t" - "movl %2, %0\n\t" - "movl %0, %%eax\n\t" - "xorl %1, %0\n\t" - "lock\n\t" - "cmpxchg %0, %2\n\t" - "jne 0b" - : "=&r"(i) - : "r"(i), "m"(*p) - : "eax", "cc" - ); -#ifdef OF_X86_64_ASM - else if (sizeof(int) == 8) - __asm__ __volatile__ ( - "0:\n\t" - "movq %2, %0\n\t" - "movq %0, %%rax\n\t" - "xorq %1, %0\n\t" - "lock\n\t" - "cmpxchg %0, %2\n\t" - "jne 0b" - : "=&r"(i) - : "r"(i), "m"(*p) - : "rax", "cc" - ); -#endif - else - abort(); - - return i; -} - -static OF_INLINE uint32_t -of_atomic_int32_xor(volatile uint32_t *_Nonnull p, uint32_t i) -{ - __asm__ __volatile__ ( - "0:\n\t" - "movl %2, %0\n\t" - "movl %0, %%eax\n\t" - "xorl %1, %0\n\t" - "lock\n\t" - "cmpxchgl %0, %2\n\t" - "jne 0b" - : "=&r"(i) - : "r"(i), "m"(*p) - : "eax", "cc" - ); - - return i; -} - -static OF_INLINE bool -of_atomic_int_cmpswap(volatile int *_Nonnull p, int o, int n) -{ - int r; - - __asm__ __volatile__ ( - "lock\n\t" - "cmpxchg %2, %3\n\t" - "sete %b0\n\t" - "movzbl %b0, %0" - : "=&d"(r), "+a"(o) /* use d instead of r to avoid a gcc bug */ - : "r"(n), "m"(*p) - : "cc" - ); - - return r; -} - -static OF_INLINE bool -of_atomic_int32_cmpswap(volatile int32_t *_Nonnull p, int32_t o, int32_t n) -{ - int r; - - __asm__ __volatile__ ( - "lock\n\t" - "cmpxchg %2, %3\n\t" - "sete %b0\n\t" - "movzbl %b0, %0" - : "=&d"(r), "+a"(o) /* use d instead of r to avoid a gcc bug */ - : "r"(n), "m"(*p) - : "cc" - ); - - return r; -} - -static OF_INLINE bool -of_atomic_ptr_cmpswap(void *volatile _Nullable *_Nonnull p, - void *_Nullable o, void *_Nullable n) -{ - int r; - - __asm__ __volatile__ ( - "lock\n\t" - "cmpxchg %2, %3\n\t" - "sete %b0\n\t" - "movzbl %b0, %0" - : "=&d"(r), "+a"(o) /* use d instead of r to avoid a gcc bug */ - : "r"(n), "m"(*p) - : "cc" - ); - - return r; -} - -static OF_INLINE void -of_memory_barrier(void) -{ - __asm__ __volatile__ ( - "mfence" ::: "memory" - ); -} - -static OF_INLINE void -of_memory_barrier_acquire(void) -{ - __asm__ __volatile__ ("" ::: "memory"); -} - -static OF_INLINE void -of_memory_barrier_release(void) -{ - __asm__ __volatile__ ("" ::: "memory"); -} - -OF_ASSUME_NONNULL_END DELETED src/base64.h Index: src/base64.h ================================================================== --- src/base64.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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. - */ - -#ifndef __STDC_LIMIT_MACROS -# define __STDC_LIMIT_MACROS -#endif -#ifndef __STDC_CONSTANT_MACROS -# define __STDC_CONSTANT_MACROS -#endif - -#import "macros.h" - -OF_ASSUME_NONNULL_BEGIN - -@class OFString; -@class OFMutableData; - -#ifdef __cplusplus -extern "C" { -#endif -extern OFString *of_base64_encode(const void *, size_t); -extern bool of_base64_decode(OFMutableData *, const char *, size_t); -#ifdef __cplusplus -} -#endif - -OF_ASSUME_NONNULL_END DELETED src/base64.m Index: src/base64.m ================================================================== --- src/base64.m +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "OFData.h" -#import "base64.h" - -const uint8_t of_base64_encode_table[64] = { - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', - 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', - 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', - 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', - '4', '5', '6', '7', '8', '9', '+', '/' -}; - -const int8_t of_base64_decode_table[128] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, - 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, 0, -1, -1, -1, 0, 1, 2, - 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, - 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, -1, -1, -1, -1, -1 -}; - -OFString * -of_base64_encode(const void *data, size_t length) -{ - OFMutableString *ret = [OFMutableString string]; - uint8_t *buffer = (uint8_t *)data; - size_t i; - uint8_t rest; - char tb[4]; - uint32_t sb; - - rest = length % 3; - - for (i = 0; i < length - rest; i += 3) { - sb = (buffer[i] << 16) | (buffer[i + 1] << 8) | buffer[i + 2]; - - tb[0] = of_base64_encode_table[(sb & 0xFC0000) >> 18]; - tb[1] = of_base64_encode_table[(sb & 0x03F000) >> 12]; - tb[2] = of_base64_encode_table[(sb & 0x000FC0) >> 6]; - tb[3] = of_base64_encode_table[sb & 0x00003F]; - - [ret appendCString: tb - encoding: OF_STRING_ENCODING_ASCII - length: 4]; - } - - switch (rest) { - case 1: - tb[0] = of_base64_encode_table[buffer[i] >> 2]; - tb[1] = of_base64_encode_table[(buffer[i] & 3) << 4]; - tb[2] = tb[3] = '='; - - [ret appendCString: tb - encoding: OF_STRING_ENCODING_ASCII - length: 4]; - - break; - case 2: - sb = (buffer[i] << 16) | (buffer[i + 1] << 8); - - tb[0] = of_base64_encode_table[(sb & 0xFC0000) >> 18]; - tb[1] = of_base64_encode_table[(sb & 0x03F000) >> 12]; - tb[2] = of_base64_encode_table[(sb & 0x000FC0) >> 6]; - tb[3] = '='; - - [ret appendCString: tb - encoding: OF_STRING_ENCODING_ASCII - length: 4]; - - break; - } - - [ret makeImmutable]; - - return ret; -} - -bool -of_base64_decode(OFMutableData *data, const char *string, size_t length) -{ - const uint8_t *buffer = (const uint8_t *)string; - size_t i; - - if ((length & 3) != 0) - return false; - - if (data.itemSize != 1) - return false; - - for (i = 0; i < length; i += 4) { - uint32_t sb = 0; - uint8_t count = 3; - char db[3]; - int8_t tmp; - - if (buffer[i] > 0x7F || buffer[i + 1] > 0x7F || - buffer[i + 2] > 0x7F || buffer[i + 3] > 0x7F) - return false; - - if (buffer[i] == '=' || buffer[i + 1] == '=' || - (buffer[i + 2] == '=' && buffer[i + 3] != '=')) - return false; - - if (buffer[i + 2] == '=') - count--; - if (buffer[i + 3] == '=') - count--; - - if ((tmp = of_base64_decode_table[buffer[i]]) == -1) - return false; - - sb |= tmp << 18; - - if ((tmp = of_base64_decode_table[buffer[i + 1]]) == -1) - return false; - - sb |= tmp << 12; - - if ((tmp = of_base64_decode_table[buffer[i + 2]]) == -1) - return false; - - sb |= tmp << 6; - - if ((tmp = of_base64_decode_table[buffer[i + 3]]) == -1) - return false; - - sb |= tmp; - - db[0] = (sb & 0xFF0000) >> 16; - db[1] = (sb & 0x00FF00) >> 8; - db[2] = sb & 0x0000FF; - - [data addItems: db - count: count]; - } - - return true; -} DELETED src/block.h Index: src/block.h ================================================================== --- src/block.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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. - */ - -#ifndef OBJFW_BLOCK_H -#define OBJFW_BLOCK_H - -#include "macros.h" - -OF_ASSUME_NONNULL_BEGIN - -typedef struct of_block_literal_t { -#ifdef __OBJC__ - Class isa; -#else - void *isa; -#endif - int flags; - int reserved; - void (*invoke)(void *block, ...); - struct of_block_descriptor_t { - unsigned long reserved; - unsigned long size; - void (*_Nullable copy_helper)(void *dest, void *src); - void (*_Nullable dispose_helper)(void *src); - const char *signature; - } *descriptor; -} of_block_literal_t; - -#ifdef __cplusplus -extern "C" { -#endif -extern void *_Block_copy(const void *); -extern void _Block_release(const void *); - -# if defined(OF_WINDOWS) && \ - (defined(OF_NO_SHARED) || defined(OF_COMPILING_OBJFW)) -/* - * Clang has implicit declarations for these, but they are dllimport. When - * compiling ObjFW itself or using it as a static library, these need to be - * dllexport. Interestingly, this still works when using it as a shared library. - */ -extern __declspec(dllexport) struct objc_class _NSConcreteStackBlock; -extern __declspec(dllexport) struct objc_class _NSConcreteGlobalBlock; -extern __declspec(dllexport) void _Block_object_assign(void *, const void *, - const int); -extern __declspec(dllexport) void _Block_object_dispose(const void *, - const int); -# endif -#ifdef __cplusplus -} -#endif - -#ifndef Block_copy -# define Block_copy(...) \ - ((__typeof__(__VA_ARGS__))_Block_copy((const void *)(__VA_ARGS__))) -#endif -#ifndef Block_release -# define Block_release(...) _Block_release((const void *)(__VA_ARGS__)) -#endif - -OF_ASSUME_NONNULL_END - -#endif Index: src/bridge/NSArray+OFObject.h ================================================================== --- src/bridge/NSArray+OFObject.h +++ src/bridge/NSArray+OFObject.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/bridge/NSArray+OFObject.m ================================================================== --- src/bridge/NSArray+OFObject.m +++ src/bridge/NSArray+OFObject.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/bridge/NSBridging.h ================================================================== --- src/bridge/NSBridging.h +++ src/bridge/NSBridging.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/bridge/NSDictionary+OFObject.h ================================================================== --- src/bridge/NSDictionary+OFObject.h +++ src/bridge/NSDictionary+OFObject.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/bridge/NSDictionary+OFObject.m ================================================================== --- src/bridge/NSDictionary+OFObject.m +++ src/bridge/NSDictionary+OFObject.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/bridge/NSEnumerator+OFObject.h ================================================================== --- src/bridge/NSEnumerator+OFObject.h +++ src/bridge/NSEnumerator+OFObject.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/bridge/NSEnumerator+OFObject.m ================================================================== --- src/bridge/NSEnumerator+OFObject.m +++ src/bridge/NSEnumerator+OFObject.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/bridge/NSNumber+OFObject.h ================================================================== --- src/bridge/NSNumber+OFObject.h +++ src/bridge/NSNumber+OFObject.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/bridge/NSNumber+OFObject.m ================================================================== --- src/bridge/NSNumber+OFObject.m +++ src/bridge/NSNumber+OFObject.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/bridge/NSOFArray.h ================================================================== --- src/bridge/NSOFArray.h +++ src/bridge/NSOFArray.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/bridge/NSOFArray.m ================================================================== --- src/bridge/NSOFArray.m +++ src/bridge/NSOFArray.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/bridge/NSOFDictionary.h ================================================================== --- src/bridge/NSOFDictionary.h +++ src/bridge/NSOFDictionary.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/bridge/NSOFDictionary.m ================================================================== --- src/bridge/NSOFDictionary.m +++ src/bridge/NSOFDictionary.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/bridge/NSOFEnumerator.h ================================================================== --- src/bridge/NSOFEnumerator.h +++ src/bridge/NSOFEnumerator.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/bridge/NSOFEnumerator.m ================================================================== --- src/bridge/NSOFEnumerator.m +++ src/bridge/NSOFEnumerator.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/bridge/NSOFSet.h ================================================================== --- src/bridge/NSOFSet.h +++ src/bridge/NSOFSet.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/bridge/NSOFSet.m ================================================================== --- src/bridge/NSOFSet.m +++ src/bridge/NSOFSet.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/bridge/NSSet+OFObject.h ================================================================== --- src/bridge/NSSet+OFObject.h +++ src/bridge/NSSet+OFObject.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/bridge/NSSet+OFObject.m ================================================================== --- src/bridge/NSSet+OFObject.m +++ src/bridge/NSSet+OFObject.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/bridge/NSString+OFObject.h ================================================================== --- src/bridge/NSString+OFObject.h +++ src/bridge/NSString+OFObject.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/bridge/NSString+OFObject.m ================================================================== --- src/bridge/NSString+OFObject.m +++ src/bridge/NSString+OFObject.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/bridge/OFArray+NSObject.h ================================================================== --- src/bridge/OFArray+NSObject.h +++ src/bridge/OFArray+NSObject.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/bridge/OFArray+NSObject.m ================================================================== --- src/bridge/OFArray+NSObject.m +++ src/bridge/OFArray+NSObject.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/bridge/OFBridging.h ================================================================== --- src/bridge/OFBridging.h +++ src/bridge/OFBridging.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/bridge/OFDictionary+NSObject.h ================================================================== --- src/bridge/OFDictionary+NSObject.h +++ src/bridge/OFDictionary+NSObject.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/bridge/OFDictionary+NSObject.m ================================================================== --- src/bridge/OFDictionary+NSObject.m +++ src/bridge/OFDictionary+NSObject.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/bridge/OFEnumerator+NSObject.h ================================================================== --- src/bridge/OFEnumerator+NSObject.h +++ src/bridge/OFEnumerator+NSObject.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/bridge/OFEnumerator+NSObject.m ================================================================== --- src/bridge/OFEnumerator+NSObject.m +++ src/bridge/OFEnumerator+NSObject.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/bridge/OFException+Swift.h ================================================================== --- src/bridge/OFException+Swift.h +++ src/bridge/OFException+Swift.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -47,12 +45,11 @@ * @note This is only useful for Swift. * * @param try The try block to execute * @param finally The finally block to call at the end */ -+ (void)try: (void (^)(void))try - finally: (void (^)(void))finally; ++ (void)try: (void (^)(void))try finally: (void (^)(void))finally; /** * @brief Execute the specified try block and call the catch block if an * OFException occurred and finally call the finally block. * Index: src/bridge/OFException+Swift.m ================================================================== --- src/bridge/OFException+Swift.m +++ src/bridge/OFException+Swift.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/bridge/OFNSArray.h ================================================================== --- src/bridge/OFNSArray.h +++ src/bridge/OFNSArray.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/bridge/OFNSArray.m ================================================================== --- src/bridge/OFNSArray.m +++ src/bridge/OFNSArray.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/bridge/OFNSDictionary.h ================================================================== --- src/bridge/OFNSDictionary.h +++ src/bridge/OFNSDictionary.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/bridge/OFNSDictionary.m ================================================================== --- src/bridge/OFNSDictionary.m +++ src/bridge/OFNSDictionary.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/bridge/OFNSEnumerator.h ================================================================== --- src/bridge/OFNSEnumerator.h +++ src/bridge/OFNSEnumerator.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/bridge/OFNSEnumerator.m ================================================================== --- src/bridge/OFNSEnumerator.m +++ src/bridge/OFNSEnumerator.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/bridge/OFNSSet.h ================================================================== --- src/bridge/OFNSSet.h +++ src/bridge/OFNSSet.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/bridge/OFNSSet.m ================================================================== --- src/bridge/OFNSSet.m +++ src/bridge/OFNSSet.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/bridge/OFNumber+NSObject.h ================================================================== --- src/bridge/OFNumber+NSObject.h +++ src/bridge/OFNumber+NSObject.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/bridge/OFNumber+NSObject.m ================================================================== --- src/bridge/OFNumber+NSObject.m +++ src/bridge/OFNumber+NSObject.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/bridge/OFSet+NSObject.h ================================================================== --- src/bridge/OFSet+NSObject.h +++ src/bridge/OFSet+NSObject.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/bridge/OFSet+NSObject.m ================================================================== --- src/bridge/OFSet+NSObject.m +++ src/bridge/OFSet+NSObject.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/bridge/OFString+NSObject.h ================================================================== --- src/bridge/OFString+NSObject.h +++ src/bridge/OFString+NSObject.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/bridge/OFString+NSObject.m ================================================================== --- src/bridge/OFString+NSObject.m +++ src/bridge/OFString+NSObject.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/bridge/ObjFWBridge.h ================================================================== --- src/bridge/ObjFWBridge.h +++ src/bridge/ObjFWBridge.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 DELETED src/condition.h Index: src/condition.h ================================================================== --- src/condition.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "objfw-defs.h" - -#include "platform.h" - -#if !defined(OF_HAVE_THREADS) || \ - (!defined(OF_HAVE_PTHREADS) && !defined(OF_WINDOWS) && !defined(OF_AMIGAOS)) -# error No conditions available! -#endif - -/* For of_time_interval_t */ -#import "OFObject.h" - -#import "mutex.h" - -#if defined(OF_HAVE_PTHREADS) -# include -typedef pthread_cond_t of_condition_t; -#elif defined(OF_WINDOWS) -# include -typedef struct { - HANDLE event; - volatile int count; -} of_condition_t; -#elif defined(OF_AMIGAOS) -# include -typedef struct { - struct of_condition_waiting_task { - struct Task *task; - unsigned char sigBit; - struct of_condition_waiting_task *next; - } *waitingTasks; -} of_condition_t; -#endif - -#ifdef __cplusplus -extern "C" { -#endif -extern bool of_condition_new(of_condition_t *condition); -extern bool of_condition_signal(of_condition_t *condition); -extern bool of_condition_broadcast(of_condition_t *condition); -extern bool of_condition_wait(of_condition_t *condition, of_mutex_t *mutex); -extern bool of_condition_timed_wait(of_condition_t *condition, - of_mutex_t *mutex, of_time_interval_t timeout); -#ifdef OF_AMIGAOS -extern bool of_condition_wait_or_signal(of_condition_t *condition, - of_mutex_t *mutex, ULONG *signalMask); -extern bool of_condition_timed_wait_or_signal(of_condition_t *condition, - of_mutex_t *mutex, of_time_interval_t timeout, ULONG *signalMask); -#endif -extern bool of_condition_free(of_condition_t *condition); -#ifdef __cplusplus -} -#endif DELETED src/condition.m Index: src/condition.m ================================================================== --- src/condition.m +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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" - -#if defined(OF_HAVE_PTHREADS) -# include "platform/posix/condition.m" -#elif defined(OF_WINDOWS) -# include "platform/windows/condition.m" -#elif defined(OF_AMIGAOS) -# include "platform/amiga/condition.m" -#endif DELETED src/crc16.h Index: src/crc16.h ================================================================== --- src/crc16.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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. - */ - -#ifndef __STDC_LIMIT_MACROS -# define __STDC_LIMIT_MACROS -#endif -#ifndef __STDC_CONSTANT_MACROS -# define __STDC_CONSTANT_MACROS -#endif - -#import "macros.h" - -#ifdef __cplusplus -extern "C" { -#endif -extern uint16_t of_crc16(uint16_t crc, const void *_Nonnull bytes, - size_t length); -#ifdef __cplusplus -} -#endif DELETED src/crc16.m Index: src/crc16.m ================================================================== --- src/crc16.m +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "crc16.h" - -#define CRC16_MAGIC 0xA001 - -uint16_t -of_crc16(uint16_t crc, const void *bytes_, size_t length) -{ - const unsigned char *bytes = bytes_; - - for (size_t i = 0; i < length; i++) { - crc ^= bytes[i]; - - for (uint8_t j = 0; j < 8; j++) - crc = (crc >> 1) ^ (CRC16_MAGIC & (~(crc & 1) + 1)); - } - - return crc; -} DELETED src/crc32.h Index: src/crc32.h ================================================================== --- src/crc32.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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. - */ - -#ifndef __STDC_LIMIT_MACROS -# define __STDC_LIMIT_MACROS -#endif -#ifndef __STDC_CONSTANT_MACROS -# define __STDC_CONSTANT_MACROS -#endif - -#import "macros.h" - -#ifdef __cplusplus -extern "C" { -#endif -extern uint32_t of_crc32(uint32_t crc, const void *_Nonnull bytes, - size_t length); -#ifdef __cplusplus -} -#endif DELETED src/crc32.m Index: src/crc32.m ================================================================== --- src/crc32.m +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "crc32.h" - -#define CRC32_MAGIC 0xEDB88320 - -uint32_t -of_crc32(uint32_t crc, const void *bytes_, size_t length) -{ - const unsigned char *bytes = bytes_; - - for (size_t i = 0; i < length; i++) { - crc ^= bytes[i]; - - for (uint8_t j = 0; j < 8; j++) - crc = (crc >> 1) ^ (CRC32_MAGIC & (~(crc & 1) + 1)); - } - - return crc; -} ADDED src/encodings/codepage-437.m Index: src/encodings/codepage-437.m ================================================================== --- /dev/null +++ src/encodings/codepage-437.m @@ -0,0 +1,169 @@ +/* + * 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 "common.h" + +const OFChar16 OFCodepage437Table[] = { + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, + 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, + 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, + 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, + 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, + 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, + 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, + 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, + 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 +}; +const size_t OFCodepage437TableOffset = + 256 - (sizeof(OFCodepage437Table) / sizeof(*OFCodepage437Table)); + +static const unsigned char page0[] = { + 0xFF, 0xAD, 0x9B, 0x9C, 0x00, 0x9D, 0x00, 0x00, + 0x00, 0x00, 0xA6, 0xAE, 0xAA, 0x00, 0x00, 0x00, + 0xF8, 0xF1, 0xFD, 0x00, 0x00, 0xE6, 0x00, 0xFA, + 0x00, 0x00, 0xA7, 0xAF, 0xAC, 0xAB, 0x00, 0xA8, + 0x00, 0x00, 0x00, 0x00, 0x8E, 0x8F, 0x92, 0x80, + 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xA5, 0x00, 0x00, 0x00, 0x00, 0x99, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x9A, 0x00, 0x00, 0xE1, + 0x85, 0xA0, 0x83, 0x00, 0x84, 0x86, 0x91, 0x87, + 0x8A, 0x82, 0x88, 0x89, 0x8D, 0xA1, 0x8C, 0x8B, + 0x00, 0xA4, 0x95, 0xA2, 0x93, 0x00, 0x94, 0xF6, + 0x00, 0x97, 0xA3, 0x96, 0x81, 0x00, 0x00, 0x98 +}; +static const uint8_t page0Start = 0xA0; + +static const unsigned char page1[] = { + 0x9F +}; +static const uint8_t page1Start = 0x92; + +static const unsigned char page3[] = { + 0xE2, 0x00, 0x00, 0x00, 0x00, 0xE9, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xE4, 0x00, 0x00, 0xE8, 0x00, 0x00, 0xEA, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, + 0x00, 0xEB, 0xEE, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xE3, 0x00, 0x00, + 0xE5, 0xE7, 0x00, 0xED +}; +static const uint8_t page3Start = 0x93; + +static const unsigned char page20[] = { + 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9E +}; +static const uint8_t page20Start = 0x7F; + +static const unsigned char page22[] = { + 0xF9, 0xFB, 0x00, 0x00, 0x00, 0xEC, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xEF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF7, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF0, 0x00, 0x00, 0xF3, 0xF2 +}; +static const uint8_t page22Start = 0x19; + +static const unsigned char page23[] = { + 0xA9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF4, 0xF5 +}; +static const uint8_t page23Start = 0x10; + +static const unsigned char page25[] = { + 0xC4, 0x00, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDA, 0x00, 0x00, 0x00, + 0xBF, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, + 0xD9, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xB4, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xC2, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xC5, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xCD, 0xBA, 0xD5, 0xD6, 0xC9, 0xB8, 0xB7, 0xBB, + 0xD4, 0xD3, 0xC8, 0xBE, 0xBD, 0xBC, 0xC6, 0xC7, + 0xCC, 0xB5, 0xB6, 0xB9, 0xD1, 0xD2, 0xCB, 0xCF, + 0xD0, 0xCA, 0xD8, 0xD7, 0xCE, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xDF, 0x00, 0x00, 0x00, 0xDC, 0x00, 0x00, 0x00, + 0xDB, 0x00, 0x00, 0x00, 0xDD, 0x00, 0x00, 0x00, + 0xDE, 0xB0, 0xB1, 0xB2, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFE +}; +static const uint8_t page25Start = 0x00; + +bool +OFUnicodeToCodepage437(const OFUnichar *input, unsigned char *output, + size_t length, bool lossy) +{ + for (size_t i = 0; i < length; i++) { + OFUnichar c = input[i]; + + if OF_UNLIKELY (c > 0x7F) { + uint8_t idx; + + if OF_UNLIKELY (c > 0xFFFF) { + if (lossy) { + output[i] = '?'; + continue; + } else + return false; + } + + switch (c >> 8) { + CASE_MISSING_IS_ERROR(0) + CASE_MISSING_IS_ERROR(1) + CASE_MISSING_IS_ERROR(3) + CASE_MISSING_IS_ERROR(20) + CASE_MISSING_IS_ERROR(22) + CASE_MISSING_IS_ERROR(23) + CASE_MISSING_IS_ERROR(25) + default: + if (lossy) { + output[i] = '?'; + continue; + } else + return false; + } + } else + output[i] = (unsigned char)c; + } + + return true; +} ADDED src/encodings/codepage-850.m Index: src/encodings/codepage-850.m ================================================================== --- /dev/null +++ src/encodings/codepage-850.m @@ -0,0 +1,142 @@ +/* + * 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 "common.h" + +const OFChar16 OFCodepage850Table[] = { + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, + 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, + 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, + 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, + 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, + 0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x0131, 0x00CD, 0x00CE, + 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580, + 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE, + 0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4, + 0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, + 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 +}; +const size_t OFCodepage850TableOffset = + 256 - (sizeof(OFCodepage850Table) / sizeof(*OFCodepage850Table)); + + +static const unsigned char page0[] = { + 0xFF, 0xAD, 0xBD, 0x9C, 0xCF, 0xBE, 0xDD, 0xF5, + 0xF9, 0xB8, 0xA6, 0xAE, 0xAA, 0xF0, 0xA9, 0xEE, + 0xF8, 0xF1, 0xFD, 0xFC, 0xEF, 0xE6, 0xF4, 0xFA, + 0xF7, 0xFB, 0xA7, 0xAF, 0xAC, 0xAB, 0xF3, 0xA8, + 0xB7, 0xB5, 0xB6, 0xC7, 0x8E, 0x8F, 0x92, 0x80, + 0xD4, 0x90, 0xD2, 0xD3, 0xDE, 0xD6, 0xD7, 0xD8, + 0xD1, 0xA5, 0xE3, 0xE0, 0xE2, 0xE5, 0x99, 0x9E, + 0x9D, 0xEB, 0xE9, 0xEA, 0x9A, 0xED, 0xE8, 0xE1, + 0x85, 0xA0, 0x83, 0xC6, 0x84, 0x86, 0x91, 0x87, + 0x8A, 0x82, 0x88, 0x89, 0x8D, 0xA1, 0x8C, 0x8B, + 0xD0, 0xA4, 0x95, 0xA2, 0x93, 0xE4, 0x94, 0xF6, + 0x9B, 0x97, 0xA3, 0x96, 0x81, 0xEC, 0xE7, 0x98 +}; +static const uint8_t page0Start = 0xA0; + +static const unsigned char page1[] = { + 0xD5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x9F +}; +static const uint8_t page1Start = 0x31; + +static const unsigned char page20[] = { + 0xF2 +}; +static const uint8_t page20Start = 0x17; + +static const unsigned char page25[] = { + 0xC4, 0x00, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDA, 0x00, 0x00, 0x00, + 0xBF, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, + 0xD9, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xB4, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xC2, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xC5, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xCD, 0xBA, 0x00, 0x00, 0xC9, 0x00, 0x00, 0xBB, + 0x00, 0x00, 0xC8, 0x00, 0x00, 0xBC, 0x00, 0x00, + 0xCC, 0x00, 0x00, 0xB9, 0x00, 0x00, 0xCB, 0x00, + 0x00, 0xCA, 0x00, 0x00, 0xCE, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xDF, 0x00, 0x00, 0x00, 0xDC, 0x00, 0x00, 0x00, + 0xDB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xB0, 0xB1, 0xB2, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFE +}; +static const uint8_t page25Start = 0x00; + +bool +OFUnicodeToCodepage850(const OFUnichar *input, unsigned char *output, + size_t length, bool lossy) +{ + for (size_t i = 0; i < length; i++) { + OFUnichar c = input[i]; + + if OF_UNLIKELY (c > 0x7F) { + uint8_t idx; + + if OF_UNLIKELY (c > 0xFFFF) { + if (lossy) { + output[i] = '?'; + continue; + } else + return false; + } + + switch (c >> 8) { + CASE_MISSING_IS_ERROR(0) + CASE_MISSING_IS_ERROR(1) + CASE_MISSING_IS_ERROR(20) + CASE_MISSING_IS_ERROR(25) + default: + if (lossy) { + output[i] = '?'; + continue; + } else + return false; + } + } else + output[i] = (unsigned char)c; + } + + return true; +} ADDED src/encodings/codepage-858.m Index: src/encodings/codepage-858.m ================================================================== --- /dev/null +++ src/encodings/codepage-858.m @@ -0,0 +1,148 @@ +/* + * 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 "common.h" + +const OFChar16 OFCodepage858Table[] = { + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, + 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, + 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, + 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, + 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, + 0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x20AC, 0x00CD, 0x00CE, + 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580, + 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE, + 0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4, + 0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, + 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 +}; +const size_t OFCodepage858TableOffset = + 256 - (sizeof(OFCodepage858Table) / sizeof(*OFCodepage858Table)); + + +static const unsigned char page0[] = { + 0xFF, 0xAD, 0xBD, 0x9C, 0xCF, 0xBE, 0xDD, 0xF5, + 0xF9, 0xB8, 0xA6, 0xAE, 0xAA, 0xF0, 0xA9, 0xEE, + 0xF8, 0xF1, 0xFD, 0xFC, 0xEF, 0xE6, 0xF4, 0xFA, + 0xF7, 0xFB, 0xA7, 0xAF, 0xAC, 0xAB, 0xF3, 0xA8, + 0xB7, 0xB5, 0xB6, 0xC7, 0x8E, 0x8F, 0x92, 0x80, + 0xD4, 0x90, 0xD2, 0xD3, 0xDE, 0xD6, 0xD7, 0xD8, + 0xD1, 0xA5, 0xE3, 0xE0, 0xE2, 0xE5, 0x99, 0x9E, + 0x9D, 0xEB, 0xE9, 0xEA, 0x9A, 0xED, 0xE8, 0xE1, + 0x85, 0xA0, 0x83, 0xC6, 0x84, 0x86, 0x91, 0x87, + 0x8A, 0x82, 0x88, 0x89, 0x8D, 0xA1, 0x8C, 0x8B, + 0xD0, 0xA4, 0x95, 0xA2, 0x93, 0xE4, 0x94, 0xF6, + 0x9B, 0x97, 0xA3, 0x96, 0x81, 0xEC, 0xE7, 0x98 +}; +static const uint8_t page0Start = 0xA0; + +static const unsigned char page1[] = { + 0x9F +}; +static const uint8_t page1Start = 0x92; + +static const unsigned char page20[] = { + 0xF2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xD5 +}; +static const uint8_t page20Start = 0x17; + +static const unsigned char page25[] = { + 0xC4, 0x00, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDA, 0x00, 0x00, 0x00, + 0xBF, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, + 0xD9, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xB4, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xC2, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xC5, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xCD, 0xBA, 0x00, 0x00, 0xC9, 0x00, 0x00, 0xBB, + 0x00, 0x00, 0xC8, 0x00, 0x00, 0xBC, 0x00, 0x00, + 0xCC, 0x00, 0x00, 0xB9, 0x00, 0x00, 0xCB, 0x00, + 0x00, 0xCA, 0x00, 0x00, 0xCE, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xDF, 0x00, 0x00, 0x00, 0xDC, 0x00, 0x00, 0x00, + 0xDB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xB0, 0xB1, 0xB2, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFE +}; +static const uint8_t page25Start = 0x00; + +bool +OFUnicodeToCodepage858(const OFUnichar *input, unsigned char *output, + size_t length, bool lossy) +{ + for (size_t i = 0; i < length; i++) { + OFUnichar c = input[i]; + + if OF_UNLIKELY (c > 0x7F) { + uint8_t idx; + + if OF_UNLIKELY (c > 0xFFFF) { + if (lossy) { + output[i] = '?'; + continue; + } else + return false; + } + + switch (c >> 8) { + CASE_MISSING_IS_ERROR(0) + CASE_MISSING_IS_ERROR(1) + CASE_MISSING_IS_ERROR(20) + CASE_MISSING_IS_ERROR(25) + default: + if (lossy) { + output[i] = '?'; + continue; + } else + return false; + } + } else + output[i] = (unsigned char)c; + } + + return true; +} DELETED src/encodings/codepage_437.m Index: src/encodings/codepage_437.m ================================================================== --- src/encodings/codepage_437.m +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "common.h" - -const of_char16_t of_codepage_437_table[] = { - 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, - 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, - 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, - 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192, - 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, - 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, - 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, - 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, - 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, - 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, - 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, - 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, - 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, - 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, - 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, - 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 -}; -const size_t of_codepage_437_table_offset = - 256 - (sizeof(of_codepage_437_table) / sizeof(*of_codepage_437_table)); - -static const unsigned char page0[] = { - 0xFF, 0xAD, 0x9B, 0x9C, 0x00, 0x9D, 0x00, 0x00, - 0x00, 0x00, 0xA6, 0xAE, 0xAA, 0x00, 0x00, 0x00, - 0xF8, 0xF1, 0xFD, 0x00, 0x00, 0xE6, 0x00, 0xFA, - 0x00, 0x00, 0xA7, 0xAF, 0xAC, 0xAB, 0x00, 0xA8, - 0x00, 0x00, 0x00, 0x00, 0x8E, 0x8F, 0x92, 0x80, - 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xA5, 0x00, 0x00, 0x00, 0x00, 0x99, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x9A, 0x00, 0x00, 0xE1, - 0x85, 0xA0, 0x83, 0x00, 0x84, 0x86, 0x91, 0x87, - 0x8A, 0x82, 0x88, 0x89, 0x8D, 0xA1, 0x8C, 0x8B, - 0x00, 0xA4, 0x95, 0xA2, 0x93, 0x00, 0x94, 0xF6, - 0x00, 0x97, 0xA3, 0x96, 0x81, 0x00, 0x00, 0x98 -}; -static const uint8_t page0Start = 0xA0; - -static const unsigned char page1[] = { - 0x9F -}; -static const uint8_t page1Start = 0x92; - -static const unsigned char page3[] = { - 0xE2, 0x00, 0x00, 0x00, 0x00, 0xE9, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xE4, 0x00, 0x00, 0xE8, 0x00, 0x00, 0xEA, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, - 0x00, 0xEB, 0xEE, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xE3, 0x00, 0x00, - 0xE5, 0xE7, 0x00, 0xED -}; -static const uint8_t page3Start = 0x93; - -static const unsigned char page20[] = { - 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x9E -}; -static const uint8_t page20Start = 0x7F; - -static const unsigned char page22[] = { - 0xF9, 0xFB, 0x00, 0x00, 0x00, 0xEC, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xEF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF7, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xF0, 0x00, 0x00, 0xF3, 0xF2 -}; -static const uint8_t page22Start = 0x19; - -static const unsigned char page23[] = { - 0xA9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xF4, 0xF5 -}; -static const uint8_t page23Start = 0x10; - -static const unsigned char page25[] = { - 0xC4, 0x00, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xDA, 0x00, 0x00, 0x00, - 0xBF, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, - 0xD9, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xB4, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xC2, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xC5, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xCD, 0xBA, 0xD5, 0xD6, 0xC9, 0xB8, 0xB7, 0xBB, - 0xD4, 0xD3, 0xC8, 0xBE, 0xBD, 0xBC, 0xC6, 0xC7, - 0xCC, 0xB5, 0xB6, 0xB9, 0xD1, 0xD2, 0xCB, 0xCF, - 0xD0, 0xCA, 0xD8, 0xD7, 0xCE, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xDF, 0x00, 0x00, 0x00, 0xDC, 0x00, 0x00, 0x00, - 0xDB, 0x00, 0x00, 0x00, 0xDD, 0x00, 0x00, 0x00, - 0xDE, 0xB0, 0xB1, 0xB2, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFE -}; -static const uint8_t page25Start = 0x00; - -bool -of_unicode_to_codepage_437(const of_unichar_t *input, unsigned char *output, - size_t length, bool lossy) -{ - for (size_t i = 0; i < length; i++) { - of_unichar_t c = input[i]; - - if OF_UNLIKELY (c > 0x7F) { - uint8_t idx; - - if OF_UNLIKELY (c > 0xFFFF) { - if (lossy) { - output[i] = '?'; - continue; - } else - return false; - } - - switch (c >> 8) { - CASE_MISSING_IS_ERROR(0) - CASE_MISSING_IS_ERROR(1) - CASE_MISSING_IS_ERROR(3) - CASE_MISSING_IS_ERROR(20) - CASE_MISSING_IS_ERROR(22) - CASE_MISSING_IS_ERROR(23) - CASE_MISSING_IS_ERROR(25) - default: - if (lossy) { - output[i] = '?'; - continue; - } else - return false; - } - } else - output[i] = (unsigned char)c; - } - - return true; -} DELETED src/encodings/codepage_850.m Index: src/encodings/codepage_850.m ================================================================== --- src/encodings/codepage_850.m +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "common.h" - -const of_char16_t of_codepage_850_table[] = { - 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, - 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, - 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, - 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192, - 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, - 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, - 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, - 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510, - 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, - 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, - 0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x0131, 0x00CD, 0x00CE, - 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580, - 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE, - 0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4, - 0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, - 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 -}; -const size_t of_codepage_850_table_offset = - 256 - (sizeof(of_codepage_850_table) / sizeof(*of_codepage_850_table)); - - -static const unsigned char page0[] = { - 0xFF, 0xAD, 0xBD, 0x9C, 0xCF, 0xBE, 0xDD, 0xF5, - 0xF9, 0xB8, 0xA6, 0xAE, 0xAA, 0xF0, 0xA9, 0xEE, - 0xF8, 0xF1, 0xFD, 0xFC, 0xEF, 0xE6, 0xF4, 0xFA, - 0xF7, 0xFB, 0xA7, 0xAF, 0xAC, 0xAB, 0xF3, 0xA8, - 0xB7, 0xB5, 0xB6, 0xC7, 0x8E, 0x8F, 0x92, 0x80, - 0xD4, 0x90, 0xD2, 0xD3, 0xDE, 0xD6, 0xD7, 0xD8, - 0xD1, 0xA5, 0xE3, 0xE0, 0xE2, 0xE5, 0x99, 0x9E, - 0x9D, 0xEB, 0xE9, 0xEA, 0x9A, 0xED, 0xE8, 0xE1, - 0x85, 0xA0, 0x83, 0xC6, 0x84, 0x86, 0x91, 0x87, - 0x8A, 0x82, 0x88, 0x89, 0x8D, 0xA1, 0x8C, 0x8B, - 0xD0, 0xA4, 0x95, 0xA2, 0x93, 0xE4, 0x94, 0xF6, - 0x9B, 0x97, 0xA3, 0x96, 0x81, 0xEC, 0xE7, 0x98 -}; -static const uint8_t page0Start = 0xA0; - -static const unsigned char page1[] = { - 0xD5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x9F -}; -static const uint8_t page1Start = 0x31; - -static const unsigned char page20[] = { - 0xF2 -}; -static const uint8_t page20Start = 0x17; - -static const unsigned char page25[] = { - 0xC4, 0x00, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xDA, 0x00, 0x00, 0x00, - 0xBF, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, - 0xD9, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xB4, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xC2, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xC5, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xCD, 0xBA, 0x00, 0x00, 0xC9, 0x00, 0x00, 0xBB, - 0x00, 0x00, 0xC8, 0x00, 0x00, 0xBC, 0x00, 0x00, - 0xCC, 0x00, 0x00, 0xB9, 0x00, 0x00, 0xCB, 0x00, - 0x00, 0xCA, 0x00, 0x00, 0xCE, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xDF, 0x00, 0x00, 0x00, 0xDC, 0x00, 0x00, 0x00, - 0xDB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xB0, 0xB1, 0xB2, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFE -}; -static const uint8_t page25Start = 0x00; - -bool -of_unicode_to_codepage_850(const of_unichar_t *input, unsigned char *output, - size_t length, bool lossy) -{ - for (size_t i = 0; i < length; i++) { - of_unichar_t c = input[i]; - - if OF_UNLIKELY (c > 0x7F) { - uint8_t idx; - - if OF_UNLIKELY (c > 0xFFFF) { - if (lossy) { - output[i] = '?'; - continue; - } else - return false; - } - - switch (c >> 8) { - CASE_MISSING_IS_ERROR(0) - CASE_MISSING_IS_ERROR(1) - CASE_MISSING_IS_ERROR(20) - CASE_MISSING_IS_ERROR(25) - default: - if (lossy) { - output[i] = '?'; - continue; - } else - return false; - } - } else - output[i] = (unsigned char)c; - } - - return true; -} DELETED src/encodings/codepage_858.m Index: src/encodings/codepage_858.m ================================================================== --- src/encodings/codepage_858.m +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "common.h" - -const of_char16_t of_codepage_858_table[] = { - 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, - 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, - 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, - 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192, - 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, - 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, - 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, - 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510, - 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, - 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, - 0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x20AC, 0x00CD, 0x00CE, - 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580, - 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE, - 0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4, - 0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, - 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 -}; -const size_t of_codepage_858_table_offset = - 256 - (sizeof(of_codepage_858_table) / sizeof(*of_codepage_858_table)); - - -static const unsigned char page0[] = { - 0xFF, 0xAD, 0xBD, 0x9C, 0xCF, 0xBE, 0xDD, 0xF5, - 0xF9, 0xB8, 0xA6, 0xAE, 0xAA, 0xF0, 0xA9, 0xEE, - 0xF8, 0xF1, 0xFD, 0xFC, 0xEF, 0xE6, 0xF4, 0xFA, - 0xF7, 0xFB, 0xA7, 0xAF, 0xAC, 0xAB, 0xF3, 0xA8, - 0xB7, 0xB5, 0xB6, 0xC7, 0x8E, 0x8F, 0x92, 0x80, - 0xD4, 0x90, 0xD2, 0xD3, 0xDE, 0xD6, 0xD7, 0xD8, - 0xD1, 0xA5, 0xE3, 0xE0, 0xE2, 0xE5, 0x99, 0x9E, - 0x9D, 0xEB, 0xE9, 0xEA, 0x9A, 0xED, 0xE8, 0xE1, - 0x85, 0xA0, 0x83, 0xC6, 0x84, 0x86, 0x91, 0x87, - 0x8A, 0x82, 0x88, 0x89, 0x8D, 0xA1, 0x8C, 0x8B, - 0xD0, 0xA4, 0x95, 0xA2, 0x93, 0xE4, 0x94, 0xF6, - 0x9B, 0x97, 0xA3, 0x96, 0x81, 0xEC, 0xE7, 0x98 -}; -static const uint8_t page0Start = 0xA0; - -static const unsigned char page1[] = { - 0x9F -}; -static const uint8_t page1Start = 0x92; - -static const unsigned char page20[] = { - 0xF2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xD5 -}; -static const uint8_t page20Start = 0x17; - -static const unsigned char page25[] = { - 0xC4, 0x00, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xDA, 0x00, 0x00, 0x00, - 0xBF, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, - 0xD9, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xB4, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xC2, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xC5, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xCD, 0xBA, 0x00, 0x00, 0xC9, 0x00, 0x00, 0xBB, - 0x00, 0x00, 0xC8, 0x00, 0x00, 0xBC, 0x00, 0x00, - 0xCC, 0x00, 0x00, 0xB9, 0x00, 0x00, 0xCB, 0x00, - 0x00, 0xCA, 0x00, 0x00, 0xCE, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xDF, 0x00, 0x00, 0x00, 0xDC, 0x00, 0x00, 0x00, - 0xDB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xB0, 0xB1, 0xB2, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFE -}; -static const uint8_t page25Start = 0x00; - -bool -of_unicode_to_codepage_858(const of_unichar_t *input, unsigned char *output, - size_t length, bool lossy) -{ - for (size_t i = 0; i < length; i++) { - of_unichar_t c = input[i]; - - if OF_UNLIKELY (c > 0x7F) { - uint8_t idx; - - if OF_UNLIKELY (c > 0xFFFF) { - if (lossy) { - output[i] = '?'; - continue; - } else - return false; - } - - switch (c >> 8) { - CASE_MISSING_IS_ERROR(0) - CASE_MISSING_IS_ERROR(1) - CASE_MISSING_IS_ERROR(20) - CASE_MISSING_IS_ERROR(25) - default: - if (lossy) { - output[i] = '?'; - continue; - } else - return false; - } - } else - output[i] = (unsigned char)c; - } - - return true; -} Index: src/encodings/common.h ================================================================== --- src/encodings/common.h +++ src/encodings/common.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 ADDED src/encodings/iso-8859-15.m Index: src/encodings/iso-8859-15.m ================================================================== --- /dev/null +++ src/encodings/iso-8859-15.m @@ -0,0 +1,96 @@ +/* + * 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 "common.h" + +const OFChar16 OFISO8859_15Table[] = { + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x20AC, 0x00A5, 0x0160, 0x00A7, + 0x0161, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x017D, 0x00B5, 0x00B6, 0x00B7, + 0x017E, 0x00B9, 0x00BA, 0x00BB, 0x0152, 0x0153, 0x0178, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF +}; +const size_t OFISO8859_15TableOffset = + 256 - (sizeof(OFISO8859_15Table) / sizeof(*OFISO8859_15Table)); + +static const unsigned char page0[] = { + 0x00, 0xA5, 0x00, 0xA7, 0x00, 0xA9, 0xAA, 0xAB, + 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, + 0x00, 0xB5, 0xB6, 0xB7, 0x00, 0xB9, 0xBA, 0xBB, + 0x00, 0x00, 0x00 +}; +static const uint8_t page0Start = 0xA4; + +static const unsigned char page1[] = { + 0xBC, 0xBD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA6, 0xA8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBE, 0x00, + 0x00, 0x00, 0x00, 0xB4, 0xB8 +}; +static const uint8_t page1Start = 0x52; + +static const unsigned char page20[] = { + 0xA4 +}; +static const uint8_t page20Start = 0xAC; + +bool +OFUnicodeToISO8859_15(const OFUnichar *input, unsigned char *output, + size_t length, bool lossy) +{ + for (size_t i = 0; i < length; i++) { + OFUnichar c = input[i]; + + if OF_UNLIKELY (c > 0x7F) { + uint8_t idx; + + if OF_UNLIKELY (c > 0xFFFF) { + if (lossy) { + output[i] = '?'; + continue; + } else + return false; + } + + switch (c >> 8) { + CASE_MISSING_IS_KEEP(0) + CASE_MISSING_IS_ERROR(1) + CASE_MISSING_IS_ERROR(20) + default: + if (lossy) { + output[i] = '?'; + continue; + } else + return false; + } + } else + output[i] = (unsigned char)c; + } + + return true; +} ADDED src/encodings/iso-8859-2.m Index: src/encodings/iso-8859-2.m ================================================================== --- /dev/null +++ src/encodings/iso-8859-2.m @@ -0,0 +1,116 @@ +/* + * 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 "common.h" + +const OFChar16 OFISO8859_2Table[] = { + 0x00A0, 0x0104, 0x02D8, 0x0141, 0x00A4, 0x013D, 0x015A, 0x00A7, + 0x00A8, 0x0160, 0x015E, 0x0164, 0x0179, 0x00AD, 0x017D, 0x017B, + 0x00B0, 0x0105, 0x02DB, 0x0142, 0x00B4, 0x013E, 0x015B, 0x02C7, + 0x00B8, 0x0161, 0x015F, 0x0165, 0x017A, 0x02DD, 0x017E, 0x017C, + 0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7, + 0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E, + 0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7, + 0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF, + 0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7, + 0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F, + 0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7, + 0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9 +}; +const size_t OFISO8859_2TableOffset = + 256 - (sizeof(OFISO8859_2Table) / sizeof(*OFISO8859_2Table)); + +static const unsigned char page0[] = { + 0xA0, 0x00, 0x00, 0x00, 0xA4, 0x00, 0x00, 0xA7, + 0xA8, 0x00, 0x00, 0x00, 0x00, 0xAD, 0x00, 0x00, + 0xB0, 0x00, 0x00, 0x00, 0xB4, 0x00, 0x00, 0x00, + 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xC1, 0xC2, 0x00, 0xC4, 0x00, 0x00, 0xC7, + 0x00, 0xC9, 0x00, 0xCB, 0x00, 0xCD, 0xCE, 0x00, + 0x00, 0x00, 0x00, 0xD3, 0xD4, 0x00, 0xD6, 0xD7, + 0x00, 0x00, 0xDA, 0x00, 0xDC, 0xDD, 0x00, 0xDF, + 0x00, 0xE1, 0xE2, 0x00, 0xE4, 0x00, 0x00, 0xE7, + 0x00, 0xE9, 0x00, 0xEB, 0x00, 0xED, 0xEE, 0x00, + 0x00, 0x00, 0x00, 0xF3, 0xF4, 0x00, 0xF6, 0xF7, + 0x00, 0x00, 0xFA, 0x00, 0xFC, 0xFD, 0x00, 0x00 +}; +static const uint8_t page0Start = 0xA0; + +static const unsigned char page1[] = { + 0xC3, 0xE3, 0xA1, 0xB1, 0xC6, 0xE6, 0x00, 0x00, + 0x00, 0x00, 0xC8, 0xE8, 0xCF, 0xEF, 0xD0, 0xF0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCA, 0xEA, + 0xCC, 0xEC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC5, + 0xE5, 0x00, 0x00, 0xA5, 0xB5, 0x00, 0x00, 0xA3, + 0xB3, 0xD1, 0xF1, 0x00, 0x00, 0xD2, 0xF2, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD5, 0xF5, + 0x00, 0x00, 0xC0, 0xE0, 0x00, 0x00, 0xD8, 0xF8, + 0xA6, 0xB6, 0x00, 0x00, 0xAA, 0xBA, 0xA9, 0xB9, + 0xDE, 0xFE, 0xAB, 0xBB, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xD9, 0xF9, 0xDB, 0xFB, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAC, + 0xBC, 0xAF, 0xBF, 0xAE, 0xBE +}; +static const uint8_t page1Start = 0x02; + +static const unsigned char page2[] = { + 0xB7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xA2, 0xFF, 0x00, 0xB2, 0x00, 0xBD +}; +static const uint8_t page2Start = 0xC7; + +bool +OFUnicodeToISO8859_2(const OFUnichar *input, unsigned char *output, + size_t length, bool lossy) +{ + for (size_t i = 0; i < length; i++) { + OFUnichar c = input[i]; + + if OF_UNLIKELY (c > 0x7F) { + uint8_t idx; + + if OF_UNLIKELY (c > 0xFFFF) { + if (lossy) { + output[i] = '?'; + continue; + } else + return false; + } + + switch (c >> 8) { + CASE_MISSING_IS_KEEP(0) + CASE_MISSING_IS_ERROR(1) + CASE_MISSING_IS_ERROR(2) + default: + if (lossy) { + output[i] = '?'; + continue; + } else + return false; + } + } else + output[i] = (unsigned char)c; + } + + return true; +} ADDED src/encodings/iso-8859-3.m Index: src/encodings/iso-8859-3.m ================================================================== --- /dev/null +++ src/encodings/iso-8859-3.m @@ -0,0 +1,113 @@ +/* + * 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 "common.h" + +const OFChar16 OFISO8859_3Table[] = { + 0x00A0, 0x0126, 0x02D8, 0x00A3, 0x00A4, 0xFFFF, 0x0124, 0x00A7, + 0x00A8, 0x0130, 0x015E, 0x011E, 0x0134, 0x00AD, 0xFFFF, 0x017B, + 0x00B0, 0x0127, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x0125, 0x00B7, + 0x00B8, 0x0131, 0x015F, 0x011F, 0x0135, 0x00BD, 0xFFFF, 0x017C, + 0x00C0, 0x00C1, 0x00C2, 0xFFFF, 0x00C4, 0x010A, 0x0108, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0xFFFF, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x0120, 0x00D6, 0x00D7, + 0x011C, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x016C, 0x015C, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0xFFFF, 0x00E4, 0x010B, 0x0109, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0xFFFF, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x0121, 0x00F6, 0x00F7, + 0x011D, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x016D, 0x015D, 0x02D9 +}; +const size_t OFISO8859_3TableOffset = + 256 - (sizeof(OFISO8859_3Table) / sizeof(*OFISO8859_3Table)); + +static const unsigned char page0[] = { + 0xA0, 0x00, 0x00, 0xA3, 0xA4, 0x00, 0x00, 0xA7, + 0xA8, 0x00, 0x00, 0x00, 0x00, 0xAD, 0x00, 0x00, + 0xB0, 0x00, 0xB2, 0xB3, 0xB4, 0xB5, 0x00, 0xB7, + 0xB8, 0x00, 0x00, 0x00, 0x00, 0xBD, 0x00, 0x00, + 0xC0, 0xC1, 0xC2, 0x00, 0xC4, 0x00, 0x00, 0xC7, + 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, + 0x00, 0xD1, 0xD2, 0xD3, 0xD4, 0x00, 0xD6, 0xD7, + 0x00, 0xD9, 0xDA, 0xDB, 0xDC, 0x00, 0x00, 0xDF, + 0xE0, 0xE1, 0xE2, 0x00, 0xE4, 0x00, 0x00, 0xE7, + 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, + 0x00, 0xF1, 0xF2, 0xF3, 0xF4, 0x00, 0xF6, 0xF7, + 0x00, 0xF9, 0xFA, 0xFB, 0xFC, 0x00, 0x00, 0x00 +}; +static const uint8_t page0Start = 0xA0; + +static const unsigned char page1[] = { + 0xC6, 0xE6, 0xC5, 0xE5, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xD8, 0xF8, 0xAB, 0xBB, + 0xD5, 0xF5, 0x00, 0x00, 0xA6, 0xB6, 0xA1, 0xB1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xA9, 0xB9, 0x00, 0x00, 0xAC, 0xBC, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDE, 0xFE, 0xAA, 0xBA, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDD, 0xFD, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xAF, 0xBF +}; +static const uint8_t page1Start = 0x08; + +static const unsigned char page2[] = { + 0xA2, 0xFF +}; +static const uint8_t page2Start = 0xD8; + +bool +OFUnicodeToISO8859_3(const OFUnichar *input, unsigned char *output, + size_t length, bool lossy) +{ + for (size_t i = 0; i < length; i++) { + OFUnichar c = input[i]; + + if OF_UNLIKELY (c > 0x7F) { + uint8_t idx; + + if OF_UNLIKELY (c > 0xFFFF) { + if (lossy) { + output[i] = '?'; + continue; + } else + return false; + } + + switch (c >> 8) { + CASE_MISSING_IS_KEEP(0) + CASE_MISSING_IS_ERROR(1) + CASE_MISSING_IS_ERROR(2) + default: + if (lossy) { + output[i] = '?'; + continue; + } else + return false; + } + } else + output[i] = (unsigned char)c; + } + + return true; +} DELETED src/encodings/iso_8859-15.m Index: src/encodings/iso_8859-15.m ================================================================== --- src/encodings/iso_8859-15.m +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "common.h" - -const of_char16_t of_iso_8859_15_table[] = { - 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x20AC, 0x00A5, 0x0160, 0x00A7, - 0x0161, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, - 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x017D, 0x00B5, 0x00B6, 0x00B7, - 0x017E, 0x00B9, 0x00BA, 0x00BB, 0x0152, 0x0153, 0x0178, 0x00BF, - 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, - 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, - 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, - 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, - 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, - 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, - 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, - 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF -}; -const size_t of_iso_8859_15_table_offset = - 256 - (sizeof(of_iso_8859_15_table) / sizeof(*of_iso_8859_15_table)); - -static const unsigned char page0[] = { - 0x00, 0xA5, 0x00, 0xA7, 0x00, 0xA9, 0xAA, 0xAB, - 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, - 0x00, 0xB5, 0xB6, 0xB7, 0x00, 0xB9, 0xBA, 0xBB, - 0x00, 0x00, 0x00 -}; -static const uint8_t page0Start = 0xA4; - -static const unsigned char page1[] = { - 0xBC, 0xBD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA6, 0xA8, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBE, 0x00, - 0x00, 0x00, 0x00, 0xB4, 0xB8 -}; -static const uint8_t page1Start = 0x52; - -static const unsigned char page20[] = { - 0xA4 -}; -static const uint8_t page20Start = 0xAC; - -bool -of_unicode_to_iso_8859_15(const of_unichar_t *input, unsigned char *output, - size_t length, bool lossy) -{ - for (size_t i = 0; i < length; i++) { - of_unichar_t c = input[i]; - - if OF_UNLIKELY (c > 0x7F) { - uint8_t idx; - - if OF_UNLIKELY (c > 0xFFFF) { - if (lossy) { - output[i] = '?'; - continue; - } else - return false; - } - - switch (c >> 8) { - CASE_MISSING_IS_KEEP(0) - CASE_MISSING_IS_ERROR(1) - CASE_MISSING_IS_ERROR(20) - default: - if (lossy) { - output[i] = '?'; - continue; - } else - return false; - } - } else - output[i] = (unsigned char)c; - } - - return true; -} DELETED src/encodings/iso_8859-2.m Index: src/encodings/iso_8859-2.m ================================================================== --- src/encodings/iso_8859-2.m +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "common.h" - -const of_char16_t of_iso_8859_2_table[] = { - 0x00A0, 0x0104, 0x02D8, 0x0141, 0x00A4, 0x013D, 0x015A, 0x00A7, - 0x00A8, 0x0160, 0x015E, 0x0164, 0x0179, 0x00AD, 0x017D, 0x017B, - 0x00B0, 0x0105, 0x02DB, 0x0142, 0x00B4, 0x013E, 0x015B, 0x02C7, - 0x00B8, 0x0161, 0x015F, 0x0165, 0x017A, 0x02DD, 0x017E, 0x017C, - 0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7, - 0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E, - 0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7, - 0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF, - 0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7, - 0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F, - 0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7, - 0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9 -}; -const size_t of_iso_8859_2_table_offset = - 256 - (sizeof(of_iso_8859_2_table) / sizeof(*of_iso_8859_2_table)); - -static const unsigned char page0[] = { - 0xA0, 0x00, 0x00, 0x00, 0xA4, 0x00, 0x00, 0xA7, - 0xA8, 0x00, 0x00, 0x00, 0x00, 0xAD, 0x00, 0x00, - 0xB0, 0x00, 0x00, 0x00, 0xB4, 0x00, 0x00, 0x00, - 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xC1, 0xC2, 0x00, 0xC4, 0x00, 0x00, 0xC7, - 0x00, 0xC9, 0x00, 0xCB, 0x00, 0xCD, 0xCE, 0x00, - 0x00, 0x00, 0x00, 0xD3, 0xD4, 0x00, 0xD6, 0xD7, - 0x00, 0x00, 0xDA, 0x00, 0xDC, 0xDD, 0x00, 0xDF, - 0x00, 0xE1, 0xE2, 0x00, 0xE4, 0x00, 0x00, 0xE7, - 0x00, 0xE9, 0x00, 0xEB, 0x00, 0xED, 0xEE, 0x00, - 0x00, 0x00, 0x00, 0xF3, 0xF4, 0x00, 0xF6, 0xF7, - 0x00, 0x00, 0xFA, 0x00, 0xFC, 0xFD, 0x00, 0x00 -}; -static const uint8_t page0Start = 0xA0; - -static const unsigned char page1[] = { - 0xC3, 0xE3, 0xA1, 0xB1, 0xC6, 0xE6, 0x00, 0x00, - 0x00, 0x00, 0xC8, 0xE8, 0xCF, 0xEF, 0xD0, 0xF0, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCA, 0xEA, - 0xCC, 0xEC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC5, - 0xE5, 0x00, 0x00, 0xA5, 0xB5, 0x00, 0x00, 0xA3, - 0xB3, 0xD1, 0xF1, 0x00, 0x00, 0xD2, 0xF2, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD5, 0xF5, - 0x00, 0x00, 0xC0, 0xE0, 0x00, 0x00, 0xD8, 0xF8, - 0xA6, 0xB6, 0x00, 0x00, 0xAA, 0xBA, 0xA9, 0xB9, - 0xDE, 0xFE, 0xAB, 0xBB, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xD9, 0xF9, 0xDB, 0xFB, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAC, - 0xBC, 0xAF, 0xBF, 0xAE, 0xBE -}; -static const uint8_t page1Start = 0x02; - -static const unsigned char page2[] = { - 0xB7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xA2, 0xFF, 0x00, 0xB2, 0x00, 0xBD -}; -static const uint8_t page2Start = 0xC7; - -bool -of_unicode_to_iso_8859_2(const of_unichar_t *input, unsigned char *output, - size_t length, bool lossy) -{ - for (size_t i = 0; i < length; i++) { - of_unichar_t c = input[i]; - - if OF_UNLIKELY (c > 0x7F) { - uint8_t idx; - - if OF_UNLIKELY (c > 0xFFFF) { - if (lossy) { - output[i] = '?'; - continue; - } else - return false; - } - - switch (c >> 8) { - CASE_MISSING_IS_KEEP(0) - CASE_MISSING_IS_ERROR(1) - CASE_MISSING_IS_ERROR(2) - default: - if (lossy) { - output[i] = '?'; - continue; - } else - return false; - } - } else - output[i] = (unsigned char)c; - } - - return true; -} DELETED src/encodings/iso_8859-3.m Index: src/encodings/iso_8859-3.m ================================================================== --- src/encodings/iso_8859-3.m +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "common.h" - -const of_char16_t of_iso_8859_3_table[] = { - 0x00A0, 0x0126, 0x02D8, 0x00A3, 0x00A4, 0xFFFF, 0x0124, 0x00A7, - 0x00A8, 0x0130, 0x015E, 0x011E, 0x0134, 0x00AD, 0xFFFF, 0x017B, - 0x00B0, 0x0127, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x0125, 0x00B7, - 0x00B8, 0x0131, 0x015F, 0x011F, 0x0135, 0x00BD, 0xFFFF, 0x017C, - 0x00C0, 0x00C1, 0x00C2, 0xFFFF, 0x00C4, 0x010A, 0x0108, 0x00C7, - 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, - 0xFFFF, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x0120, 0x00D6, 0x00D7, - 0x011C, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x016C, 0x015C, 0x00DF, - 0x00E0, 0x00E1, 0x00E2, 0xFFFF, 0x00E4, 0x010B, 0x0109, 0x00E7, - 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, - 0xFFFF, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x0121, 0x00F6, 0x00F7, - 0x011D, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x016D, 0x015D, 0x02D9 -}; -const size_t of_iso_8859_3_table_offset = - 256 - (sizeof(of_iso_8859_3_table) / sizeof(*of_iso_8859_3_table)); - -static const unsigned char page0[] = { - 0xA0, 0x00, 0x00, 0xA3, 0xA4, 0x00, 0x00, 0xA7, - 0xA8, 0x00, 0x00, 0x00, 0x00, 0xAD, 0x00, 0x00, - 0xB0, 0x00, 0xB2, 0xB3, 0xB4, 0xB5, 0x00, 0xB7, - 0xB8, 0x00, 0x00, 0x00, 0x00, 0xBD, 0x00, 0x00, - 0xC0, 0xC1, 0xC2, 0x00, 0xC4, 0x00, 0x00, 0xC7, - 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, - 0x00, 0xD1, 0xD2, 0xD3, 0xD4, 0x00, 0xD6, 0xD7, - 0x00, 0xD9, 0xDA, 0xDB, 0xDC, 0x00, 0x00, 0xDF, - 0xE0, 0xE1, 0xE2, 0x00, 0xE4, 0x00, 0x00, 0xE7, - 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, - 0x00, 0xF1, 0xF2, 0xF3, 0xF4, 0x00, 0xF6, 0xF7, - 0x00, 0xF9, 0xFA, 0xFB, 0xFC, 0x00, 0x00, 0x00 -}; -static const uint8_t page0Start = 0xA0; - -static const unsigned char page1[] = { - 0xC6, 0xE6, 0xC5, 0xE5, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xD8, 0xF8, 0xAB, 0xBB, - 0xD5, 0xF5, 0x00, 0x00, 0xA6, 0xB6, 0xA1, 0xB1, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xA9, 0xB9, 0x00, 0x00, 0xAC, 0xBC, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xDE, 0xFE, 0xAA, 0xBA, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xDD, 0xFD, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xAF, 0xBF -}; -static const uint8_t page1Start = 0x08; - -static const unsigned char page2[] = { - 0xA2, 0xFF -}; -static const uint8_t page2Start = 0xD8; - -bool -of_unicode_to_iso_8859_3(const of_unichar_t *input, unsigned char *output, - size_t length, bool lossy) -{ - for (size_t i = 0; i < length; i++) { - of_unichar_t c = input[i]; - - if OF_UNLIKELY (c > 0x7F) { - uint8_t idx; - - if OF_UNLIKELY (c > 0xFFFF) { - if (lossy) { - output[i] = '?'; - continue; - } else - return false; - } - - switch (c >> 8) { - CASE_MISSING_IS_KEEP(0) - CASE_MISSING_IS_ERROR(1) - CASE_MISSING_IS_ERROR(2) - default: - if (lossy) { - output[i] = '?'; - continue; - } else - return false; - } - } else - output[i] = (unsigned char)c; - } - - return true; -} Index: src/encodings/koi8-r.m ================================================================== --- src/encodings/koi8-r.m +++ src/encodings/koi8-r.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -19,11 +17,11 @@ #import "OFString.h" #import "common.h" -const of_char16_t of_koi8_r_table[] = { +const OFChar16 OFKOI8RTable[] = { 0x2500, 0x2502, 0x250C, 0x2510, 0x2514, 0x2518, 0x251C, 0x2524, 0x252C, 0x2534, 0x253C, 0x2580, 0x2584, 0x2588, 0x258C, 0x2590, 0x2591, 0x2592, 0x2593, 0x2320, 0x25A0, 0x2219, 0x221A, 0x2248, 0x2264, 0x2265, 0x00A0, 0x2321, 0x00B0, 0x00B2, 0x00B7, 0x00F7, 0x2550, 0x2551, 0x2552, 0x0451, 0x2553, 0x2554, 0x2555, 0x2556, @@ -37,12 +35,12 @@ 0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, 0x0425, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, 0x042C, 0x042B, 0x0417, 0x0428, 0x042D, 0x0429, 0x0427, 0x042A }; -const size_t of_koi8_r_table_offset = - 256 - (sizeof(of_koi8_r_table) / sizeof(*of_koi8_r_table)); +const size_t OFKOI8RTableOffset = + 256 - (sizeof(OFKOI8RTable) / sizeof(*OFKOI8RTable)); static const unsigned char page0[] = { 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9C, 0x00, 0x9D, 0x00, 0x00, 0x00, 0x00, 0x9E, @@ -115,15 +113,15 @@ 0x94 }; static const uint8_t page25Start = 0x00; bool -of_unicode_to_koi8_r(const of_unichar_t *input, unsigned char *output, - size_t length, bool lossy) +OFUnicodeToKOI8R(const OFUnichar *input, unsigned char *output, size_t length, + bool lossy) { for (size_t i = 0; i < length; i++) { - of_unichar_t c = input[i]; + OFUnichar c = input[i]; if OF_UNLIKELY (c > 0x7F) { uint8_t idx; if OF_UNLIKELY (c > 0xFFFF) { Index: src/encodings/koi8-u.m ================================================================== --- src/encodings/koi8-u.m +++ src/encodings/koi8-u.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -19,11 +17,11 @@ #import "OFString.h" #import "common.h" -const of_char16_t of_koi8_u_table[] = { +const OFChar16 OFKOI8UTable[] = { 0x2500, 0x2502, 0x250C, 0x2510, 0x2514, 0x2518, 0x251C, 0x2524, 0x252C, 0x2534, 0x253C, 0x2580, 0x2584, 0x2588, 0x258C, 0x2590, 0x2591, 0x2592, 0x2593, 0x2320, 0x25A0, 0x2219, 0x221A, 0x2248, 0x2264, 0x2265, 0x00A0, 0x2321, 0x00B0, 0x00B2, 0x00B7, 0x00F7, 0x2550, 0x2551, 0x2552, 0x0451, 0x0454, 0x2554, 0x0456, 0x0457, @@ -37,12 +35,12 @@ 0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, 0x0425, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, 0x042C, 0x042B, 0x0417, 0x0428, 0x042D, 0x0429, 0x0427, 0x042A }; -const size_t of_koi8_u_table_offset = - 256 - (sizeof(of_koi8_u_table) / sizeof(*of_koi8_u_table)); +const size_t OFKOI8UTableOffset = + 256 - (sizeof(OFKOI8UTable) / sizeof(*OFKOI8UTable)); static const unsigned char page0[] = { 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9C, 0x00, 0x9D, 0x00, 0x00, 0x00, 0x00, 0x9E, @@ -123,15 +121,15 @@ 0x94 }; static const uint8_t page25Start = 0x00; bool -of_unicode_to_koi8_u(const of_unichar_t *input, unsigned char *output, - size_t length, bool lossy) +OFUnicodeToKOI8U(const OFUnichar *input, unsigned char *output, size_t length, + bool lossy) { for (size_t i = 0; i < length; i++) { - of_unichar_t c = input[i]; + OFUnichar c = input[i]; if OF_UNLIKELY (c > 0x7F) { uint8_t idx; if OF_UNLIKELY (c > 0xFFFF) { ADDED src/encodings/mac-roman.m Index: src/encodings/mac-roman.m ================================================================== --- /dev/null +++ src/encodings/mac-roman.m @@ -0,0 +1,192 @@ +/* + * 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 "common.h" + +const OFChar16 OFMacRomanTable[] = { + 0x00C4, 0x00C5, 0x00C7, 0x00C9, 0x00D1, 0x00D6, 0x00DC, 0x00E1, + 0x00E0, 0x00E2, 0x00E4, 0x00E3, 0x00E5, 0x00E7, 0x00E9, 0x00E8, + 0x00EA, 0x00EB, 0x00ED, 0x00EC, 0x00EE, 0x00EF, 0x00F1, 0x00F3, + 0x00F2, 0x00F4, 0x00F6, 0x00F5, 0x00FA, 0x00F9, 0x00FB, 0x00FC, + 0x2020, 0x00B0, 0x00A2, 0x00A3, 0x00A7, 0x2022, 0x00B6, 0x00DF, + 0x00AE, 0x00A9, 0x2122, 0x00B4, 0x00A8, 0x2260, 0x00C6, 0x00D8, + 0x221E, 0x00B1, 0x2264, 0x2265, 0x00A5, 0x00B5, 0x2202, 0x2211, + 0x220F, 0x03C0, 0x222B, 0x00AA, 0x00BA, 0x03A9, 0x00E6, 0x00F8, + 0x00BF, 0x00A1, 0x00AC, 0x221A, 0x0192, 0x2248, 0x2206, 0x00AB, + 0x00BB, 0x2026, 0x00A0, 0x00C0, 0x00C3, 0x00D5, 0x0152, 0x0153, + 0x2013, 0x2014, 0x201C, 0x201D, 0x2018, 0x2019, 0x00F7, 0x25CA, + 0x00FF, 0x0178, 0x2044, 0x20AC, 0x2039, 0x203A, 0xFB01, 0xFB02, + 0x2021, 0x00B7, 0x201A, 0x201E, 0x2030, 0x00C2, 0x00CA, 0x00C1, + 0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF, 0x00CC, 0x00D3, 0x00D4, + 0xF8FF, 0x00D2, 0x00DA, 0x00DB, 0x00D9, 0x0131, 0x02C6, 0x02DC, + 0x00AF, 0x02D8, 0x02D9, 0x02DA, 0x00B8, 0x02DD, 0x02DB, 0x02C7 +}; +const size_t OFMacRomanTableOffset = + 256 - (sizeof(OFMacRomanTable) / sizeof(*OFMacRomanTable)); + +static const unsigned char page0[] = { + 0xCA, 0xC1, 0xA2, 0xA3, 0x00, 0xB4, 0x00, 0xA4, + 0xAC, 0xA9, 0xBB, 0xC7, 0xC2, 0x00, 0xA8, 0xF8, + 0xA1, 0xB1, 0x00, 0x00, 0xAB, 0xB5, 0xA6, 0xE1, + 0xFC, 0x00, 0xBC, 0xC8, 0x00, 0x00, 0x00, 0xC0, + 0xCB, 0xE7, 0xE5, 0xCC, 0x80, 0x81, 0xAE, 0x82, + 0xE9, 0x83, 0xE6, 0xE8, 0xED, 0xEA, 0xEB, 0xEC, + 0x00, 0x84, 0xF1, 0xEE, 0xEF, 0xCD, 0x85, 0x00, + 0xAF, 0xF4, 0xF2, 0xF3, 0x86, 0x00, 0x00, 0xA7, + 0x88, 0x87, 0x89, 0x8B, 0x8A, 0x8C, 0xBE, 0x8D, + 0x8F, 0x8E, 0x90, 0x91, 0x93, 0x92, 0x94, 0x95, + 0x00, 0x96, 0x98, 0x97, 0x99, 0x9B, 0x9A, 0xD6, + 0xBF, 0x9D, 0x9C, 0x9E, 0x9F, 0x00, 0x00, 0xD8 +}; +static const uint8_t page0Start = 0xA0; + +static const unsigned char page1[] = { + 0xF5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xCE, 0xCF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD9, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xC4 +}; +static const uint8_t page1Start = 0x31; + +static const unsigned char page2[] = { + 0xF6, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xF9, 0xFA, 0xFB, 0xFE, 0xF7, 0xFD +}; +static const uint8_t page2Start = 0xC6; + +static const unsigned char page3[] = { + 0xBD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB9 +}; +static const uint8_t page3Start = 0xA9; + +static const unsigned char page20[] = { + 0xD0, 0xD1, 0x00, 0x00, 0x00, 0xD4, 0xD5, 0xE2, + 0x00, 0xD2, 0xD3, 0xE3, 0x00, 0xA0, 0xE0, 0xA5, + 0x00, 0x00, 0x00, 0xC9, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0xDD, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xDA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xDB +}; +static const uint8_t page20Start = 0x13; + +static const unsigned char page21[] = { + 0xAA +}; +static const uint8_t page21Start = 0x22; + +static const unsigned char page22[] = { + 0xB6, 0x00, 0x00, 0x00, 0xC6, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xB8, 0x00, 0xB7, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC3, 0x00, 0x00, 0x00, 0xB0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xBA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC5, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAD, 0x00, + 0x00, 0x00, 0xB2, 0xB3 +}; +static const uint8_t page22Start = 0x02; + +static const unsigned char page25[] = { + 0xD7 +}; +static const uint8_t page25Start = 0xCA; + +static const unsigned char pageF8[] = { + 0xF0 +}; +static const uint8_t pageF8Start = 0xFF; + +static const unsigned char pageFB[] = { + 0xDE, 0xDF +}; +static const uint8_t pageFBStart = 0x01; + +bool +OFUnicodeToMacRoman(const OFUnichar *input, unsigned char *output, + size_t length, bool lossy) +{ + for (size_t i = 0; i < length; i++) { + OFUnichar c = input[i]; + + if OF_UNLIKELY (c > 0x7F) { + uint8_t idx; + + if OF_UNLIKELY (c > 0xFFFF) { + if (lossy) { + output[i] = '?'; + continue; + } else + return false; + } + + switch (c >> 8) { + CASE_MISSING_IS_ERROR(0) + CASE_MISSING_IS_ERROR(1) + CASE_MISSING_IS_ERROR(2) + CASE_MISSING_IS_ERROR(3) + CASE_MISSING_IS_ERROR(20) + CASE_MISSING_IS_ERROR(21) + CASE_MISSING_IS_ERROR(22) + CASE_MISSING_IS_ERROR(25) + CASE_MISSING_IS_ERROR(F8) + CASE_MISSING_IS_ERROR(FB) + default: + if (lossy) { + output[i] = '?'; + continue; + } else + return false; + } + } else + output[i] = (unsigned char)c; + } + + return true; +} DELETED src/encodings/mac_roman.m Index: src/encodings/mac_roman.m ================================================================== --- src/encodings/mac_roman.m +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "common.h" - -const of_char16_t of_mac_roman_table[] = { - 0x00C4, 0x00C5, 0x00C7, 0x00C9, 0x00D1, 0x00D6, 0x00DC, 0x00E1, - 0x00E0, 0x00E2, 0x00E4, 0x00E3, 0x00E5, 0x00E7, 0x00E9, 0x00E8, - 0x00EA, 0x00EB, 0x00ED, 0x00EC, 0x00EE, 0x00EF, 0x00F1, 0x00F3, - 0x00F2, 0x00F4, 0x00F6, 0x00F5, 0x00FA, 0x00F9, 0x00FB, 0x00FC, - 0x2020, 0x00B0, 0x00A2, 0x00A3, 0x00A7, 0x2022, 0x00B6, 0x00DF, - 0x00AE, 0x00A9, 0x2122, 0x00B4, 0x00A8, 0x2260, 0x00C6, 0x00D8, - 0x221E, 0x00B1, 0x2264, 0x2265, 0x00A5, 0x00B5, 0x2202, 0x2211, - 0x220F, 0x03C0, 0x222B, 0x00AA, 0x00BA, 0x03A9, 0x00E6, 0x00F8, - 0x00BF, 0x00A1, 0x00AC, 0x221A, 0x0192, 0x2248, 0x2206, 0x00AB, - 0x00BB, 0x2026, 0x00A0, 0x00C0, 0x00C3, 0x00D5, 0x0152, 0x0153, - 0x2013, 0x2014, 0x201C, 0x201D, 0x2018, 0x2019, 0x00F7, 0x25CA, - 0x00FF, 0x0178, 0x2044, 0x20AC, 0x2039, 0x203A, 0xFB01, 0xFB02, - 0x2021, 0x00B7, 0x201A, 0x201E, 0x2030, 0x00C2, 0x00CA, 0x00C1, - 0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF, 0x00CC, 0x00D3, 0x00D4, - 0xF8FF, 0x00D2, 0x00DA, 0x00DB, 0x00D9, 0x0131, 0x02C6, 0x02DC, - 0x00AF, 0x02D8, 0x02D9, 0x02DA, 0x00B8, 0x02DD, 0x02DB, 0x02C7 -}; -const size_t of_mac_roman_table_offset = - 256 - (sizeof(of_mac_roman_table) / sizeof(*of_mac_roman_table)); - -static const unsigned char page0[] = { - 0xCA, 0xC1, 0xA2, 0xA3, 0x00, 0xB4, 0x00, 0xA4, - 0xAC, 0xA9, 0xBB, 0xC7, 0xC2, 0x00, 0xA8, 0xF8, - 0xA1, 0xB1, 0x00, 0x00, 0xAB, 0xB5, 0xA6, 0xE1, - 0xFC, 0x00, 0xBC, 0xC8, 0x00, 0x00, 0x00, 0xC0, - 0xCB, 0xE7, 0xE5, 0xCC, 0x80, 0x81, 0xAE, 0x82, - 0xE9, 0x83, 0xE6, 0xE8, 0xED, 0xEA, 0xEB, 0xEC, - 0x00, 0x84, 0xF1, 0xEE, 0xEF, 0xCD, 0x85, 0x00, - 0xAF, 0xF4, 0xF2, 0xF3, 0x86, 0x00, 0x00, 0xA7, - 0x88, 0x87, 0x89, 0x8B, 0x8A, 0x8C, 0xBE, 0x8D, - 0x8F, 0x8E, 0x90, 0x91, 0x93, 0x92, 0x94, 0x95, - 0x00, 0x96, 0x98, 0x97, 0x99, 0x9B, 0x9A, 0xD6, - 0xBF, 0x9D, 0x9C, 0x9E, 0x9F, 0x00, 0x00, 0xD8 -}; -static const uint8_t page0Start = 0xA0; - -static const unsigned char page1[] = { - 0xF5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xCE, 0xCF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD9, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xC4 -}; -static const uint8_t page1Start = 0x31; - -static const unsigned char page2[] = { - 0xF6, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xF9, 0xFA, 0xFB, 0xFE, 0xF7, 0xFD -}; -static const uint8_t page2Start = 0xC6; - -static const unsigned char page3[] = { - 0xBD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB9 -}; -static const uint8_t page3Start = 0xA9; - -static const unsigned char page20[] = { - 0xD0, 0xD1, 0x00, 0x00, 0x00, 0xD4, 0xD5, 0xE2, - 0x00, 0xD2, 0xD3, 0xE3, 0x00, 0xA0, 0xE0, 0xA5, - 0x00, 0x00, 0x00, 0xC9, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0xDD, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xDA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xDB -}; -static const uint8_t page20Start = 0x13; - -static const unsigned char page21[] = { - 0xAA -}; -static const uint8_t page21Start = 0x22; - -static const unsigned char page22[] = { - 0xB6, 0x00, 0x00, 0x00, 0xC6, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xB8, 0x00, 0xB7, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC3, 0x00, 0x00, 0x00, 0xB0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xBA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC5, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAD, 0x00, - 0x00, 0x00, 0xB2, 0xB3 -}; -static const uint8_t page22Start = 0x02; - -static const unsigned char page25[] = { - 0xD7 -}; -static const uint8_t page25Start = 0xCA; - -static const unsigned char pageF8[] = { - 0xF0 -}; -static const uint8_t pageF8Start = 0xFF; - -static const unsigned char pageFB[] = { - 0xDE, 0xDF -}; -static const uint8_t pageFBStart = 0x01; - -bool -of_unicode_to_mac_roman(const of_unichar_t *input, unsigned char *output, - size_t length, bool lossy) -{ - for (size_t i = 0; i < length; i++) { - of_unichar_t c = input[i]; - - if OF_UNLIKELY (c > 0x7F) { - uint8_t idx; - - if OF_UNLIKELY (c > 0xFFFF) { - if (lossy) { - output[i] = '?'; - continue; - } else - return false; - } - - switch (c >> 8) { - CASE_MISSING_IS_ERROR(0) - CASE_MISSING_IS_ERROR(1) - CASE_MISSING_IS_ERROR(2) - CASE_MISSING_IS_ERROR(3) - CASE_MISSING_IS_ERROR(20) - CASE_MISSING_IS_ERROR(21) - CASE_MISSING_IS_ERROR(22) - CASE_MISSING_IS_ERROR(25) - CASE_MISSING_IS_ERROR(F8) - CASE_MISSING_IS_ERROR(FB) - default: - if (lossy) { - output[i] = '?'; - continue; - } else - return false; - } - } else - output[i] = (unsigned char)c; - } - - return true; -} Index: src/encodings/windows-1251.m ================================================================== --- src/encodings/windows-1251.m +++ src/encodings/windows-1251.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -19,11 +17,11 @@ #import "OFString.h" #import "common.h" -const of_char16_t of_windows_1251_table[] = { +const OFChar16 OFWindows1251Table[] = { 0x0402, 0x0403, 0x201A, 0x0453, 0x201E, 0x2026, 0x2020, 0x2021, 0x20AC, 0x2030, 0x0409, 0x2039, 0x040A, 0x040C, 0x040B, 0x040F, 0x0452, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 0xFFFF, 0x2122, 0x0459, 0x203A, 0x045A, 0x045C, 0x045B, 0x045F, 0x00A0, 0x040E, 0x045E, 0x0408, 0x00A4, 0x0490, 0x00A6, 0x00A7, @@ -37,12 +35,12 @@ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F }; -const size_t of_windows_1251_table_offset = - 256 - (sizeof(of_windows_1251_table) / sizeof(*of_windows_1251_table)); +const size_t OFWindows1251TableOffset = + 256 - (sizeof(OFWindows1251Table) / sizeof(*OFWindows1251Table)); static const unsigned char page0[] = { 0xA0, 0x00, 0x00, 0x00, 0xA4, 0x00, 0xA6, 0xA7, 0x00, 0xA9, 0x00, 0xAB, 0xAC, 0xAD, 0xAE, 0x00, 0xB0, 0xB1, 0x00, 0x00, 0x00, 0xB5, 0xB6, 0xB7, @@ -102,15 +100,15 @@ 0x00, 0x00, 0x00, 0x00, 0x99 }; static const uint8_t page21Start = 0x16; bool -of_unicode_to_windows_1251(const of_unichar_t *input, unsigned char *output, +OFUnicodeToWindows1251(const OFUnichar *input, unsigned char *output, size_t length, bool lossy) { for (size_t i = 0; i < length; i++) { - of_unichar_t c = input[i]; + OFUnichar c = input[i]; if OF_UNLIKELY (c > 0x7F) { uint8_t idx; if OF_UNLIKELY (c > 0xFFFF) { Index: src/encodings/windows-1252.m ================================================================== --- src/encodings/windows-1252.m +++ src/encodings/windows-1252.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -19,11 +17,11 @@ #import "OFString.h" #import "common.h" -const of_char16_t of_windows_1252_table[] = { +const OFChar16 OFWindows1252Table[] = { 0x20AC, 0xFFFF, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0xFFFF, 0x017D, 0xFFFF, 0xFFFF, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0xFFFF, 0x017E, 0x0178, 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, @@ -37,12 +35,12 @@ 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF }; -const size_t of_windows_1252_table_offset = - 256 - (sizeof(of_windows_1252_table) / sizeof(*of_windows_1252_table)); +const size_t OFWindows1252TableOffset = + 256 - (sizeof(OFWindows1252Table) / sizeof(*OFWindows1252Table)); static const unsigned char page0[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -98,15 +96,15 @@ 0x99 }; static const uint8_t page21Start = 0x22; bool -of_unicode_to_windows_1252(const of_unichar_t *input, unsigned char *output, +OFUnicodeToWindows1252(const OFUnichar *input, unsigned char *output, size_t length, bool lossy) { for (size_t i = 0; i < length; i++) { - of_unichar_t c = input[i]; + OFUnichar c = input[i]; if OF_UNLIKELY (c > 0x7F) { uint8_t idx; if OF_UNLIKELY (c > 0xFFFF) { Index: src/exceptions/Makefile ================================================================== --- src/exceptions/Makefile +++ src/exceptions/Makefile @@ -11,20 +11,20 @@ OFCreateSymbolicLinkFailedException.m \ OFEnumerationMutationException.m \ OFException.m \ OFGetOptionFailedException.m \ OFHashAlreadyCalculatedException.m \ + OFHashNotCalculatedException.m \ OFInitializationFailedException.m \ OFInvalidArgumentException.m \ OFInvalidEncodingException.m \ OFInvalidFormatException.m \ OFInvalidJSONException.m \ OFInvalidServerReplyException.m \ OFLinkFailedException.m \ OFLockFailedException.m \ OFMalformedXMLException.m \ - OFMemoryNotPartOfObjectException.m \ OFMoveItemFailedException.m \ OFNotImplementedException.m \ OFNotOpenException.m \ OFOpenItemFailedException.m \ OFOutOfMemoryException.m \ @@ -31,11 +31,10 @@ OFOutOfRangeException.m \ OFReadFailedException.m \ OFReadOrWriteFailedException.m \ OFRemoveItemFailedException.m \ OFRetrieveItemAttributesFailedException.m \ - OFSandboxActivationFailedException.m \ OFSeekFailedException.m \ OFSetItemAttributesFailedException.m \ OFSetOptionFailedException.m \ OFStillLockedException.m \ OFTruncatedDataException.m \ @@ -60,11 +59,12 @@ OFConnectionFailedException.m \ OFDNSQueryFailedException.m \ OFHTTPRequestFailedException.m \ OFListenFailedException.m \ OFObserveFailedException.m \ - OFResolveHostFailedException.m + OFResolveHostFailedException.m \ + OFTLSHandshakeFailedException.m SRCS_THREADS = OFConditionBroadcastFailedException.m \ OFConditionSignalFailedException.m \ OFConditionStillWaitingException.m \ OFConditionWaitFailedException.m \ OFThreadJoinFailedException.m \ @@ -75,10 +75,12 @@ OFDeleteWindowsRegistryValueFailedException.m \ OFGetWindowsRegistryValueFailedException.m \ OFOpenWindowsRegistryKeyFailedException.m \ OFSetWindowsRegistryValueFailedException.m -INCLUDES = ${SRCS:.m=.h} +INCLUDES := ${SRCS:.m=.h} + +SRCS += OFSandboxActivationFailedException.m include ../../buildsys.mk CPPFLAGS += -I. -I.. -I../.. -I../runtime Index: src/exceptions/OFAcceptFailedException.h ================================================================== --- src/exceptions/OFAcceptFailedException.h +++ src/exceptions/OFAcceptFailedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -52,12 +50,11 @@ * * @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)exceptionWithSocket: (id)socket errNo: (int)errNo; - (instancetype)init OF_UNAVAILABLE; /** * @brief Initializes an already allocated accept failed exception. Index: src/exceptions/OFAcceptFailedException.m ================================================================== --- src/exceptions/OFAcceptFailedException.m +++ src/exceptions/OFAcceptFailedException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -26,24 +24,21 @@ + (instancetype)exception { OF_UNRECOGNIZED_SELECTOR } -+ (instancetype)exceptionWithSocket: (id)socket - errNo: (int)errNo ++ (instancetype)exceptionWithSocket: (id)socket errNo: (int)errNo { - return [[[self alloc] initWithSocket: socket - errNo: errNo] autorelease]; + return [[[self alloc] initWithSocket: socket errNo: errNo] autorelease]; } - (instancetype)init { OF_INVALID_INIT_METHOD } -- (instancetype)initWithSocket: (id)socket - errNo: (int)errNo +- (instancetype)initWithSocket: (id)socket errNo: (int)errNo { self = [super init]; _socket = [socket retain]; _errNo = errNo; @@ -60,8 +55,8 @@ - (OFString *)description { return [OFString stringWithFormat: @"Failed to accept connection in socket of class %@: %@", - [_socket class], of_strerror(_errNo)]; + [_socket class], OFStrError(_errNo)]; } @end Index: src/exceptions/OFAllocFailedException.h ================================================================== --- src/exceptions/OFAllocFailedException.h +++ src/exceptions/OFAllocFailedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/exceptions/OFAllocFailedException.m ================================================================== --- src/exceptions/OFAllocFailedException.m +++ src/exceptions/OFAllocFailedException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -34,39 +32,10 @@ - (instancetype)init { OF_INVALID_INIT_METHOD } -- (void *)allocMemoryWithSize: (size_t)size -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (void *)allocMemoryForNItems: (size_t)nitems - withSize: (size_t)size -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (void *)resizeMemory: (void *)ptr - toSize: (size_t)size -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (void *)resizeMemory: (void *)ptr - toNItems: (size_t)nitems - withSize: (size_t)size -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (void)freeMemory: (void *)ptr -{ - OF_UNRECOGNIZED_SELECTOR -} - - (instancetype)retain { return self; } @@ -75,11 +44,11 @@ return self; } - (unsigned int)retainCount { - return OF_RETAIN_COUNT_MAX; + return OFMaxRetainCount; } - (void)release { } Index: src/exceptions/OFAlreadyConnectedException.h ================================================================== --- src/exceptions/OFAlreadyConnectedException.h +++ src/exceptions/OFAlreadyConnectedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/exceptions/OFAlreadyConnectedException.m ================================================================== --- src/exceptions/OFAlreadyConnectedException.m +++ src/exceptions/OFAlreadyConnectedException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/exceptions/OFBindFailedException.h ================================================================== --- src/exceptions/OFBindFailedException.h +++ src/exceptions/OFBindFailedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -19,11 +17,11 @@ #ifndef OF_HAVE_SOCKETS # error No sockets available! #endif -#import "socket.h" +#import "OFSocket.h" OF_ASSUME_NONNULL_BEGIN /** * @class OFBindFailedException \ @@ -31,23 +29,25 @@ * * @brief An exception indicating that binding a socket failed. */ @interface OFBindFailedException: OFException { - id _socket; /* IP */ - OFString *_host; + OFString *_Nullable _host; uint16_t _port; /* IPX */ uint8_t _packetType; + /* UNIX socket */ + OFString *_Nullable _path; + id _socket; int _errNo; } /** * @brief The host on which binding failed. */ -@property (readonly, nonatomic) OFString *host; +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFString *host; /** * @brief The port on which binding failed. */ @property (readonly, nonatomic) uint16_t port; @@ -55,10 +55,15 @@ /** * @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; @@ -65,12 +70,10 @@ /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased bind failed exception. * * @param host The host on which binding failed * @param port The port on which binding failed @@ -81,10 +84,12 @@ + (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 @@ -95,11 +100,21 @@ + (instancetype)exceptionWithPort: (uint16_t)port packetType: (uint8_t)packetType socket: (id)socket errNo: (int)errNo; -- (instancetype)init OF_UNAVAILABLE; +/** + * @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 @@ -124,8 +139,21 @@ */ - (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 Index: src/exceptions/OFBindFailedException.m ================================================================== --- src/exceptions/OFBindFailedException.m +++ src/exceptions/OFBindFailedException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -19,11 +17,11 @@ #import "OFBindFailedException.h" #import "OFString.h" @implementation OFBindFailedException -@synthesize host = _host, port = _port, packetType = _packetType; +@synthesize host = _host, port = _port, packetType = _packetType, path = _path; @synthesize socket = _socket, errNo = _errNo; + (instancetype)exception { OF_UNRECOGNIZED_SELECTOR @@ -48,10 +46,19 @@ 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 } @@ -93,28 +100,51 @@ @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 (_host != nil) + 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], of_strerror(_errNo)]; + _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], of_strerror(_errNo)]; + _port, _packetType, [_socket class], OFStrError(_errNo)]; } @end Index: src/exceptions/OFChangeCurrentDirectoryPathFailedException.h ================================================================== --- src/exceptions/OFChangeCurrentDirectoryPathFailedException.h +++ src/exceptions/OFChangeCurrentDirectoryPathFailedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -42,25 +40,22 @@ /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased change current directory path failed * exception. * * @param path The path of the directory to which the current path could not be * changed * @param errNo The errno of the error that occurred * @return A new, autoreleased change current directory path failed exception */ -+ (instancetype)exceptionWithPath: (OFString *)path - errNo: (int)errNo; ++ (instancetype)exceptionWithPath: (OFString *)path errNo: (int)errNo; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated change directory failed exception. * * @param path The path of the directory to which the current path could not be @@ -68,8 +63,10 @@ * @param errNo The errno of the error that occurred * @return An initialized change current directory path failed exception */ - (instancetype)initWithPath: (OFString *)path errNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFChangeCurrentDirectoryPathFailedException.m ================================================================== --- src/exceptions/OFChangeCurrentDirectoryPathFailedException.m +++ src/exceptions/OFChangeCurrentDirectoryPathFailedException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -20,30 +18,22 @@ #import "OFChangeCurrentDirectoryPathFailedException.h" #import "OFString.h" @implementation OFChangeCurrentDirectoryPathFailedException @synthesize path = _path, errNo = _errNo; + ++ (instancetype)exceptionWithPath: (OFString *)path errNo: (int)errNo +{ + return [[[self alloc] initWithPath: path errNo: errNo] autorelease]; +} + (instancetype)exception { OF_UNRECOGNIZED_SELECTOR } -+ (instancetype)exceptionWithPath: (OFString *)path - errNo: (int)errNo -{ - return [[[self alloc] initWithPath: path - errNo: errNo] autorelease]; -} - -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - -- (instancetype)initWithPath: (OFString *)path - errNo: (int)errNo +- (instancetype)initWithPath: (OFString *)path errNo: (int)errNo { self = [super init]; @try { _path = [path copy]; @@ -53,10 +43,15 @@ @throw e; } return self; } + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} - (void)dealloc { [_path release]; @@ -65,8 +60,8 @@ - (OFString *)description { return [OFString stringWithFormat: @"Failed to change the current directory path to %@: %@", - _path, of_strerror(_errNo)]; + _path, OFStrError(_errNo)]; } @end Index: src/exceptions/OFChecksumMismatchException.h ================================================================== --- src/exceptions/OFChecksumMismatchException.h +++ src/exceptions/OFChecksumMismatchException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/exceptions/OFChecksumMismatchException.m ================================================================== --- src/exceptions/OFChecksumMismatchException.m +++ src/exceptions/OFChecksumMismatchException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/exceptions/OFConditionBroadcastFailedException.h ================================================================== --- src/exceptions/OFConditionBroadcastFailedException.h +++ src/exceptions/OFConditionBroadcastFailedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -39,11 +37,11 @@ } /** * @brief The condition which could not be broadcasted. */ -@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFCondition *condition; +@property (readonly, nonatomic) OFCondition *condition; /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; @@ -53,22 +51,24 @@ * * @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: (nullable OFCondition *)condition ++ (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: (nullable OFCondition *)condition +- (instancetype)initWithCondition: (OFCondition *)condition errNo: (int)errNo OF_DESIGNATED_INITIALIZER; - (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFConditionBroadcastFailedException.m ================================================================== --- src/exceptions/OFConditionBroadcastFailedException.m +++ src/exceptions/OFConditionBroadcastFailedException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -31,12 +29,16 @@ { return [[[self alloc] initWithCondition: condition errNo: errNo] autorelease]; } -- (instancetype)initWithCondition: (OFCondition *)condition - errNo: (int)errNo ++ (instancetype)exception +{ + OF_UNRECOGNIZED_SELECTOR +} + +- (instancetype)initWithCondition: (OFCondition *)condition errNo: (int)errNo { self = [super init]; _condition = [condition retain]; _errNo = errNo; Index: src/exceptions/OFConditionSignalFailedException.h ================================================================== --- src/exceptions/OFConditionSignalFailedException.h +++ src/exceptions/OFConditionSignalFailedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -39,11 +37,11 @@ } /** * @brief The condition which could not be signaled. */ -@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFCondition *condition; +@property (readonly, nonatomic) OFCondition *condition; /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; @@ -53,22 +51,24 @@ * * @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: (nullable OFCondition *)condition ++ (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: (nullable OFCondition *)condition +- (instancetype)initWithCondition: (OFCondition *)condition errNo: (int)errNo OF_DESIGNATED_INITIALIZER; - (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFConditionSignalFailedException.m ================================================================== --- src/exceptions/OFConditionSignalFailedException.m +++ src/exceptions/OFConditionSignalFailedException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -31,12 +29,16 @@ { return [[[self alloc] initWithCondition: condition errNo: errNo] autorelease]; } -- (instancetype)initWithCondition: (OFCondition *)condition - errNo: (int)errNo ++ (instancetype)exception +{ + OF_UNRECOGNIZED_SELECTOR +} + +- (instancetype)initWithCondition: (OFCondition *)condition errNo: (int)errNo { self = [super init]; _condition = [condition retain]; _errNo = errNo; Index: src/exceptions/OFConditionStillWaitingException.h ================================================================== --- src/exceptions/OFConditionStillWaitingException.h +++ src/exceptions/OFConditionStillWaitingException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -39,26 +37,30 @@ } /** * @brief The condition for which is still being waited. */ -@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFCondition *condition; +@property (readonly, nonatomic) OFCondition *condition; /** * @brief Creates a new, autoreleased condition still waiting exception. * * @param condition The condition for which is still being waited * @return A new, autoreleased condition still waiting exception */ -+ (instancetype)exceptionWithCondition: (nullable OFCondition *)condition; ++ (instancetype)exceptionWithCondition: (OFCondition *)condition; + ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated condition still waiting exception. * * @param condition The condition for which is still being waited * @return An initialized condition still waiting exception */ -- (instancetype)initWithCondition: (nullable OFCondition *)condition +- (instancetype)initWithCondition: (OFCondition *)condition OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFConditionStillWaitingException.m ================================================================== --- src/exceptions/OFConditionStillWaitingException.m +++ src/exceptions/OFConditionStillWaitingException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -27,13 +25,13 @@ + (instancetype)exceptionWithCondition: (OFCondition *)condition { return [[[self alloc] initWithCondition: condition] autorelease]; } -- (instancetype)init ++ (instancetype)exception { - return [self initWithCondition: nil]; + OF_UNRECOGNIZED_SELECTOR } - (instancetype)initWithCondition: (OFCondition *)condition { self = [super init]; @@ -40,10 +38,15 @@ _condition = [condition retain]; return self; } + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} - (void)dealloc { [_condition release]; @@ -50,15 +53,11 @@ [super dealloc]; } - (OFString *)description { - if (_condition != nil) - return [OFString stringWithFormat: - @"Deallocation of a condition of type %@ was tried, even " - "though a thread was still waiting for it!", - _condition.class]; - else - return @"Deallocation of a condition was tried, even though a " - "thread was still waiting for it!"; + return [OFString stringWithFormat: + @"Deallocation of a condition of type %@ was tried, even though " + "a thread was still waiting for it!", + _condition.class]; } @end Index: src/exceptions/OFConditionWaitFailedException.h ================================================================== --- src/exceptions/OFConditionWaitFailedException.h +++ src/exceptions/OFConditionWaitFailedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -39,11 +37,11 @@ } /** * @brief The condition for which could not be waited. */ -@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFCondition *condition; +@property (readonly, nonatomic) OFCondition *condition; /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; @@ -53,22 +51,24 @@ * * @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: (nullable OFCondition *)condition ++ (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: (nullable OFCondition *)condition +- (instancetype)initWithCondition: (OFCondition *)condition errNo: (int)errNo OF_DESIGNATED_INITIALIZER; - (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFConditionWaitFailedException.m ================================================================== --- src/exceptions/OFConditionWaitFailedException.m +++ src/exceptions/OFConditionWaitFailedException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -31,12 +29,16 @@ { return [[[self alloc] initWithCondition: condition errNo: errNo] autorelease]; } -- (instancetype)initWithCondition: (OFCondition *)condition - errNo: (int)errNo ++ (instancetype)exception +{ + OF_UNRECOGNIZED_SELECTOR +} + +- (instancetype)initWithCondition: (OFCondition *)condition errNo: (int)errNo { self = [super init]; _condition = [condition retain]; _errNo = errNo; Index: src/exceptions/OFConnectionFailedException.h ================================================================== --- src/exceptions/OFConnectionFailedException.h +++ src/exceptions/OFConnectionFailedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -19,11 +17,11 @@ #ifndef OF_HAVE_SOCKETS # error No sockets available! #endif -#import "socket.h" +#import "OFSocket.h" OF_ASSUME_NONNULL_BEGIN /** * @class OFConnectionFailedException \ @@ -31,23 +29,19 @@ * * @brief An exception indicating that a connection could not be established. */ @interface OFConnectionFailedException: OFException { - id _socket; - OFString *_host; + OFString *_Nullable _host; uint16_t _port; unsigned char _node[IPX_NODE_LEN]; uint32_t _network; + OFString *_Nullable _path; + id _socket; int _errNo; } -/** - * @brief The socket which could not connect. - */ -@property (readonly, nonatomic) id socket; - /** * @brief The host to which the connection failed. */ @property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFString *host; @@ -64,27 +58,35 @@ /** * @brief The IPX network of the node to which the connection failed. */ @property (readonly, nonatomic) uint32_t network; +/** + * @brief The path to which the connection failed. + */ +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFString *path; + +/** + * @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; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @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: (nullable OFString *)host ++ (instancetype)exceptionWithHost: (OFString *)host port: (uint16_t)port socket: (id)socket errNo: (int)errNo; /** @@ -101,11 +103,23 @@ network: (uint32_t)network port: (uint16_t)port socket: (id)socket errNo: (int)errNo; -- (instancetype)init OF_UNAVAILABLE; +/** + * @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; + ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated connection failed exception. * * @param host The host to which the connection failed @@ -112,11 +126,11 @@ * @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: (nullable OFString *)host +- (instancetype)initWithHost: (OFString *)host port: (uint16_t)port socket: (id)socket errNo: (int)errNo; /** @@ -132,8 +146,22 @@ - (instancetype)initWithNode: (unsigned char [_Nullable IPX_NODE_LEN])node network: (uint32_t)network 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; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFConnectionFailedException.m ================================================================== --- src/exceptions/OFConnectionFailedException.m +++ src/exceptions/OFConnectionFailedException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -19,17 +17,12 @@ #import "OFConnectionFailedException.h" #import "OFString.h" @implementation OFConnectionFailedException -@synthesize host = _host, port = _port, network = _network, socket = _socket; -@synthesize errNo = _errNo; - -+ (instancetype)exception -{ - OF_UNRECOGNIZED_SELECTOR -} +@synthesize host = _host, port = _port, network = _network, path = _path; +@synthesize socket = _socket, errNo = _errNo; + (instancetype)exceptionWithHost: (OFString *)host port: (uint16_t)port socket: (id)sock errNo: (int)errNo @@ -37,10 +30,15 @@ return [[[self alloc] initWithHost: host port: port socket: sock errNo: errNo] autorelease]; } + ++ (instancetype)exception +{ + OF_UNRECOGNIZED_SELECTOR +} + (instancetype)exceptionWithNode: (unsigned char [IPX_NODE_LEN])node network: (uint32_t)network port: (uint16_t)port socket: (id)sock @@ -51,13 +49,17 @@ port: port socket: sock errNo: errNo] autorelease]; } -- (instancetype)init ++ (instancetype)exceptionWithPath: (OFString *)path + socket: (id)sock + errNo: (int)errNo { - OF_INVALID_INIT_METHOD + return [[[self alloc] initWithPath: path + socket: sock + errNo: errNo] autorelease]; } - (instancetype)initWithHost: (OFString *)host port: (uint16_t)port socket: (id)sock @@ -97,14 +99,38 @@ @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)init +{ + OF_INVALID_INIT_METHOD +} - (void)dealloc { [_host release]; + [_path release]; [_socket release]; [super dealloc]; } @@ -113,24 +139,29 @@ return _node; } - (OFString *)description { - if (_host != nil) + 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], of_strerror(_errNo)]; + _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], of_strerror(_errNo)]; + _port, _network, [_socket class], OFStrError(_errNo)]; else return [OFString stringWithFormat: @"A connection could not be established in socket of " @"type %@: %@", - [_socket class], of_strerror(_errNo)]; + [_socket class], OFStrError(_errNo)]; } @end Index: src/exceptions/OFCopyItemFailedException.h ================================================================== --- src/exceptions/OFCopyItemFailedException.h +++ src/exceptions/OFCopyItemFailedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -32,49 +30,49 @@ OFURL *_sourceURL, *_destinationURL; int _errNo; } /** - * @brief The path of the source item. + * @brief The URL of the source item. */ @property (readonly, nonatomic) OFURL *sourceURL; /** - * @brief The destination path. + * @brief The destination URL. */ @property (readonly, nonatomic) OFURL *destinationURL; /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased copy item failed exception. * - * @param sourceURL The original path - * @param destinationURL The new path + * @param sourceURL The URL of the source item + * @param destinationURL The destination URL * @param errNo The errno of the error that occurred * @return A new, autoreleased copy item failed exception */ + (instancetype)exceptionWithSourceURL: (OFURL *)sourceURL destinationURL: (OFURL *)destinationURL errNo: (int)errNo; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated copy item failed exception. * - * @param sourceURL The original path - * @param destinationURL The new path + * @param sourceURL The URL of the source item + * @param destinationURL The destination URL * @param errNo The errno of the error that occurred * @return An initialized copy item failed exception */ - (instancetype)initWithSourceURL: (OFURL *)sourceURL destinationURL: (OFURL *)destinationURL 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,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -71,8 +69,8 @@ } - (OFString *)description { return [OFString stringWithFormat: @"Failed to copy item %@ to %@: %@", - _sourceURL, _destinationURL, of_strerror(_errNo)]; + _sourceURL, _destinationURL, OFStrError(_errNo)]; } @end Index: src/exceptions/OFCreateDirectoryFailedException.h ================================================================== --- src/exceptions/OFCreateDirectoryFailedException.h +++ src/exceptions/OFCreateDirectoryFailedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -42,23 +40,20 @@ /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased create directory failed exception. * * @param URL The URL 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)exceptionWithURL: (OFURL *)URL - errNo: (int)errNo; ++ (instancetype)exceptionWithURL: (OFURL *)URL errNo: (int)errNo; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated create directory failed exception. * * @param URL The URL of the directory which could not be created @@ -65,8 +60,10 @@ * @param errNo The errno of the error that occurred * @return An initialized create directory failed exception */ - (instancetype)initWithURL: (OFURL *)URL 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,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -27,24 +25,21 @@ + (instancetype)exception { OF_UNRECOGNIZED_SELECTOR } -+ (instancetype)exceptionWithURL: (OFURL *)URL - errNo: (int)errNo ++ (instancetype)exceptionWithURL: (OFURL *)URL errNo: (int)errNo { - return [[[self alloc] initWithURL: URL - errNo: errNo] autorelease]; + return [[[self alloc] initWithURL: URL errNo: errNo] autorelease]; } - (instancetype)init { OF_INVALID_INIT_METHOD } -- (instancetype)initWithURL: (OFURL *)URL - errNo: (int)errNo +- (instancetype)initWithURL: (OFURL *)URL errNo: (int)errNo { self = [super init]; @try { _URL = [URL copy]; @@ -65,8 +60,8 @@ } - (OFString *)description { return [OFString stringWithFormat: - @"Failed to create directory %@: %@", _URL, of_strerror(_errNo)]; + @"Failed to create directory %@: %@", _URL, OFStrError(_errNo)]; } @end Index: src/exceptions/OFCreateSymbolicLinkFailedException.h ================================================================== --- src/exceptions/OFCreateSymbolicLinkFailedException.h +++ src/exceptions/OFCreateSymbolicLinkFailedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -48,12 +46,10 @@ /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased create symbolic link failed exception. * * @param URL The URL where the symlink should have been created * @param target The target for the symbolic link @@ -62,11 +58,11 @@ */ + (instancetype)exceptionWithURL: (OFURL *)URL target: (OFString *)target errNo: (int)errNo; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated create symbolic link failed * exception. * @@ -76,8 +72,10 @@ * @return An initialized create symbolic link failed exception */ - (instancetype)initWithURL: (OFURL *)URL 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,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -71,8 +69,8 @@ - (OFString *)description { return [OFString stringWithFormat: @"Failed to create symbolic link %@ with target %@: %@", - _URL, _target, of_strerror(_errNo)]; + _URL, _target, OFStrError(_errNo)]; } @end Index: src/exceptions/OFCreateWindowsRegistryKeyFailedException.h ================================================================== --- src/exceptions/OFCreateWindowsRegistryKeyFailedException.h +++ src/exceptions/OFCreateWindowsRegistryKeyFailedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/exceptions/OFCreateWindowsRegistryKeyFailedException.m ================================================================== --- src/exceptions/OFCreateWindowsRegistryKeyFailedException.m +++ src/exceptions/OFCreateWindowsRegistryKeyFailedException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -80,8 +78,8 @@ - (OFString *)description { return [OFString stringWithFormat: @"Failed to create subkey at path %@: %@", - _path, of_windows_status_to_string(_status)]; + _path, OFWindowsStatusToString(_status)]; } @end Index: src/exceptions/OFDNSQueryFailedException.h ================================================================== --- src/exceptions/OFDNSQueryFailedException.h +++ src/exceptions/OFDNSQueryFailedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -29,48 +27,53 @@ * @brief An exception indicating that a DNS query failed. */ @interface OFDNSQueryFailedException: OFException { OFDNSQuery *_query; - of_dns_resolver_error_t _error; + OFDNSResolverErrorCode _errorCode; } /** * @brief The query which could not be performed. */ @property (readonly, nonatomic) OFDNSQuery *query; /** - * @brief The error from the resolver. + * @brief The error code from the resolver. */ -@property (readonly, nonatomic) of_dns_resolver_error_t error; +@property (readonly, nonatomic) OFDNSResolverErrorCode errorCode; /** * @brief Creates a new, autoreleased DNS query failed exception. * * @param query The query which could not be performed - * @param error The error from the resolver + * @param errorCode The error from the resolver * @return A new, autoreleased address translation failed exception */ + (instancetype)exceptionWithQuery: (OFDNSQuery *)query - error: (of_dns_resolver_error_t)error; + errorCode: (OFDNSResolverErrorCode)errorCode; + ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated DNS query failed exception. * * @param query The query which could not be performed - * @param error The error from the resolver + * @param errorCode The error from the resolver * @return An initialized address translation failed exception */ - (instancetype)initWithQuery: (OFDNSQuery *)query - error: (of_dns_resolver_error_t)error; + errorCode: (OFDNSResolverErrorCode)errorCode; + +- (instancetype)init OF_UNAVAILABLE; @end #ifdef __cplusplus extern "C" { #endif -extern OFString *of_dns_resolver_error_to_string(of_dns_resolver_error_t error); +extern OFString *OFDNSResolverErrorCodeDescription( + OFDNSResolverErrorCode errorCode); #ifdef __cplusplus } #endif OF_ASSUME_NONNULL_END Index: src/exceptions/OFDNSQueryFailedException.m ================================================================== --- src/exceptions/OFDNSQueryFailedException.m +++ src/exceptions/OFDNSQueryFailedException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -19,65 +17,75 @@ #import "OFDNSQueryFailedException.h" #import "OFString.h" OFString * -of_dns_resolver_error_to_string(of_dns_resolver_error_t error) +OFDNSResolverErrorCodeDescription(OFDNSResolverErrorCode errorCode) { - switch (error) { - case OF_DNS_RESOLVER_ERROR_TIMEOUT: + switch (errorCode) { + case OFDNSResolverErrorCodeTimeout: return @"The query timed out."; - case OF_DNS_RESOLVER_ERROR_CANCELED: + case OFDNSResolverErrorCodeCanceled: return @"The query was canceled."; - case OF_DNS_RESOLVER_ERROR_NO_RESULT: + case OFDNSResolverErrorCodeNoResult: return @"No result for the specified host with the specified " @"type and class."; - case OF_DNS_RESOLVER_ERROR_SERVER_INVALID_FORMAT: + case OFDNSResolverErrorCodeServerInvalidFormat: return @"The server considered the query to be malformed."; - case OF_DNS_RESOLVER_ERROR_SERVER_FAILURE: + case OFDNSResolverErrorCodeServerFailure: return @"The server was unable to process due to an internal " @"error."; - case OF_DNS_RESOLVER_ERROR_SERVER_NAME_ERROR: + case OFDNSResolverErrorCodeServerNameError: return @"The server returned an error that the domain does not " @"exist."; - case OF_DNS_RESOLVER_ERROR_SERVER_NOT_IMPLEMENTED: + case OFDNSResolverErrorCodeServerNotImplemented: return @"The server does not have support for the requested " @"query."; - case OF_DNS_RESOLVER_ERROR_SERVER_REFUSED: + case OFDNSResolverErrorCodeServerRefused: return @"The server refused the query."; - case OF_DNS_RESOLVER_ERROR_NO_NAME_SERVER: + case OFDNSResolverErrorCodeNoNameServer: return @"There was no name server to query."; default: return @"Unknown error."; } } @implementation OFDNSQueryFailedException -@synthesize query = _query, error = _error; +@synthesize query = _query, errorCode = _errorCode; + (instancetype)exceptionWithQuery: (OFDNSQuery *)query - error: (of_dns_resolver_error_t)error + errorCode: (OFDNSResolverErrorCode)errorCode { return [[[self alloc] initWithQuery: query - error: error] autorelease]; + errorCode: errorCode] autorelease]; +} + ++ (instancetype)exception +{ + OF_UNRECOGNIZED_SELECTOR } - (instancetype)initWithQuery: (OFDNSQuery *)query - error: (of_dns_resolver_error_t)error + errorCode: (OFDNSResolverErrorCode)errorCode { self = [super init]; @try { _query = [query copy]; - _error = error; + _errorCode = errorCode; } @catch (id e) { [self release]; @throw e; } return self; } + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} - (void)dealloc { [_query release]; @@ -86,8 +94,8 @@ - (OFString *)description { return [OFString stringWithFormat: @"DNS query %@ could not be performed: %@", - _query, of_dns_resolver_error_to_string(_error)]; + _query, OFDNSResolverErrorCodeDescription(_errorCode)]; } @end Index: src/exceptions/OFDeleteWindowsRegistryKeyFailedException.h ================================================================== --- src/exceptions/OFDeleteWindowsRegistryKeyFailedException.h +++ src/exceptions/OFDeleteWindowsRegistryKeyFailedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/exceptions/OFDeleteWindowsRegistryKeyFailedException.m ================================================================== --- src/exceptions/OFDeleteWindowsRegistryKeyFailedException.m +++ src/exceptions/OFDeleteWindowsRegistryKeyFailedException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -67,8 +65,8 @@ - (OFString *)description { return [OFString stringWithFormat: @"Failed to delete subkey at path %@: %@", - _subkeyPath, of_windows_status_to_string(_status)]; + _subkeyPath, OFWindowsStatusToString(_status)]; } @end Index: src/exceptions/OFDeleteWindowsRegistryValueFailedException.h ================================================================== --- src/exceptions/OFDeleteWindowsRegistryValueFailedException.h +++ src/exceptions/OFDeleteWindowsRegistryValueFailedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -30,23 +28,23 @@ * @brief An exception indicating that deleting a Windows registry value failed. */ @interface OFDeleteWindowsRegistryValueFailedException: OFException { OFWindowsRegistryKey *_registryKey; - OFString *_Nullable _value; + OFString *_Nullable _valueName; LSTATUS _status; } /** * @brief The registry key on which deleting the value failed. */ @property (readonly, nonatomic) OFWindowsRegistryKey *registryKey; /** - * @brief The value which could not be deleted. + * @brief The name of the value which could not be deleted. */ -@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFString *value; +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFString *valueName; /** * @brief The status returned by RegDeleteValueEx(). */ @property (readonly, nonatomic) LSTATUS status; @@ -54,30 +52,30 @@ /** * @brief Creates a new, autoreleased delete Windows registry value failed * exception. * * @param registryKey The registry key on which deleting the value failed - * @param value The value which could not be deleted + * @param valueName The name of the value which could not be deleted * @param status The status returned by RegDeleteValueEx() * @return A new, autoreleased delete Windows registry value failed exception */ + (instancetype)exceptionWithRegistryKey: (OFWindowsRegistryKey *)registryKey - value: (nullable OFString *)value + valueName: (nullable OFString *)valueName status: (LSTATUS)status; - (instancetype)init OF_UNAVAILABLE; /** * @brief Initializes an already allocated delete Windows registry value failed * exception. * * @param registryKey The registry key on which deleting the value failed - * @param value The value which could not be deleted + * @param valueName The name of the value which could not be deleted * @param status The status returned by RegDeleteValueEx() * @return An initialized delete Windows registry value failed exception */ - (instancetype)initWithRegistryKey: (OFWindowsRegistryKey *)registryKey - value: (nullable OFString *)value + valueName: (nullable OFString *)valueName status: (LSTATUS)status OF_DESIGNATED_INITIALIZER; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFDeleteWindowsRegistryValueFailedException.m ================================================================== --- src/exceptions/OFDeleteWindowsRegistryValueFailedException.m +++ src/exceptions/OFDeleteWindowsRegistryValueFailedException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -20,35 +18,36 @@ #import "OFDeleteWindowsRegistryValueFailedException.h" #import "OFData.h" @implementation OFDeleteWindowsRegistryValueFailedException -@synthesize registryKey = _registryKey, value = _value, status = _status; +@synthesize registryKey = _registryKey, valueName = _valueName; +@synthesize status = _status; + (instancetype)exceptionWithRegistryKey: (OFWindowsRegistryKey *)registryKey - value: (OFString *)value + valueName: (OFString *)valueName status: (LSTATUS)status { return [[[self alloc] initWithRegistryKey: registryKey - value: value + valueName: valueName status: status] autorelease]; } - (instancetype)init { OF_INVALID_INIT_METHOD } - (instancetype)initWithRegistryKey: (OFWindowsRegistryKey *)registryKey - value: (OFString *)value + valueName: (OFString *)valueName status: (LSTATUS)status { self = [super init]; @try { _registryKey = [registryKey retain]; - _value = [value copy]; + _valueName = [valueName copy]; _status = status; } @catch (id e) { [self release]; @throw e; } @@ -57,17 +56,17 @@ } - (void)dealloc { [_registryKey release]; - [_value release]; + [_valueName release]; [super dealloc]; } - (OFString *)description { return [OFString stringWithFormat: - @"Failed to delete value %@: %@", - _value, of_windows_status_to_string(_status)]; + @"Failed to delete value named %@: %@", + _valueName, OFWindowsStatusToString(_status)]; } @end Index: src/exceptions/OFEnumerationMutationException.h ================================================================== --- src/exceptions/OFEnumerationMutationException.h +++ src/exceptions/OFEnumerationMutationException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -35,27 +33,27 @@ /** * @brief The object which was mutated during enumeration. */ @property (readonly, nonatomic) id object; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased enumeration mutation exception. * * @param object The object which was mutated during enumeration * @return A new, autoreleased enumeration mutation exception */ + (instancetype)exceptionWithObject: (id)object; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated enumeration mutation exception. * * @param object The object which was mutated during enumeration * @return An initialized enumeration mutation exception */ - (instancetype)initWithObject: (id)object OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFEnumerationMutationException.m ================================================================== --- src/exceptions/OFEnumerationMutationException.m +++ src/exceptions/OFEnumerationMutationException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/exceptions/OFException.h ================================================================== --- src/exceptions/OFException.h +++ src/exceptions/OFException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -25,11 +23,11 @@ @class OFArray OF_GENERIC(ObjectType); @class OFMutableArray OF_GENERIC(ObjectType); @class OFString; -#define OF_BACKTRACE_SIZE 16 +#define OFBacktraceSize 16 #if defined(OF_WINDOWS) && defined(OF_HAVE_SOCKETS) # ifndef EADDRINUSE # define EADDRINUSE WSAEADDRINUSE # endif @@ -135,10 +133,14 @@ # ifndef EWOULDBLOCK # define EWOULDBLOCK WSAEWOULDBLOCK # endif #endif +#ifndef EWOULDBLOCK +# define EWOULDBLOCK EAGAIN +#endif + /** * @class OFException OFException.h ObjFW/OFException.h * * @brief The base class for all exceptions in ObjFW * @@ -145,11 +147,11 @@ * The OFException class is the base class for all exceptions in ObjFW, except * the OFAllocFailedException. */ @interface OFException: OFObject { - void *_backtrace[OF_BACKTRACE_SIZE]; + void *_backtrace[OFBacktraceSize]; } /** * @brief Creates a new, autoreleased exception. * @@ -174,14 +176,14 @@ @end #ifdef __cplusplus extern "C" { #endif -extern OFString *of_strerror(int errNo); +extern OFString *OFStrError(int errNo); #ifdef OF_WINDOWS -extern OFString *of_windows_status_to_string(LSTATUS status); +extern OFString *OFWindowsStatusToString(LSTATUS status); #endif #ifdef __cplusplus } #endif OF_ASSUME_NONNULL_END Index: src/exceptions/OFException.m ================================================================== --- src/exceptions/OFException.m +++ src/exceptions/OFException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -27,21 +25,20 @@ #endif #import "OFException.h" #import "OFArray.h" #import "OFLocale.h" +#ifdef OF_HAVE_THREADS +# import "OFPlainMutex.h" +#endif #import "OFString.h" #import "OFSystemInfo.h" #import "OFInitializationFailedException.h" #import "OFLockFailedException.h" #import "OFUnlockFailedException.h" -#if !defined(HAVE_STRERROR_R) && defined(OF_HAVE_THREADS) -# import "mutex.h" -#endif - #if defined(OF_WINDOWS) && defined(OF_HAVE_SOCKETS) # include #endif #if defined(OF_ARM) && !defined(__ARM_DWARF_EH__) @@ -50,13 +47,13 @@ struct _Unwind_Context; typedef enum { _URC_OK = 0, _URC_END_OF_STACK = 5 -}_Unwind_Reason_Code; +} _Unwind_Reason_Code; -struct backtrace_ctx { +struct BacktraceCtx { void **backtrace; uint8_t i; }; #ifdef HAVE__UNWIND_BACKTRACE @@ -69,21 +66,25 @@ extern int _Unwind_VRS_Get(struct _Unwind_Context *, int, uint32_t, int, void *); #endif #if !defined(HAVE_STRERROR_R) && defined(OF_HAVE_THREADS) -static of_mutex_t mutex; +static OFPlainMutex mutex; OF_CONSTRUCTOR() { - if (!of_mutex_new(&mutex)) - @throw [OFInitializationFailedException exception]; + OFEnsure(OFPlainMutexNew(&mutex) == 0); +} + +OF_DESTRUCTOR() +{ + OFPlainMutexFree(&mutex); } #endif OFString * -of_strerror(int errNo) +OFStrError(int errNo) { OFString *ret; #ifdef HAVE_STRERROR_R char buffer[256]; #endif @@ -187,21 +188,21 @@ ret = [OFString stringWithCString: buffer encoding: [OFLocale encoding]]; #else # ifdef OF_HAVE_THREADS - if (!of_mutex_lock(&mutex)) + if (OFPlainMutexLock(&mutex) != 0) @throw [OFLockFailedException exception]; @try { # endif ret = [OFString stringWithCString: strerror(errNo) encoding: [OFLocale encoding]]; # ifdef OF_HAVE_THREADS } @finally { - if (!of_mutex_unlock(&mutex)) + if (OFPlainMutexUnlock(&mutex) != 0) @throw [OFUnlockFailedException exception]; } # endif #endif @@ -208,11 +209,11 @@ return ret; } #ifdef OF_WINDOWS OFString * -of_windows_status_to_string(LSTATUS status) +OFWindowsStatusToString(LSTATUS status) { OFString *string = nil; void *buffer; if ([OFSystemInfo isWindowsNT]) { @@ -251,15 +252,15 @@ } #endif #ifdef HAVE__UNWIND_BACKTRACE static _Unwind_Reason_Code -backtrace_callback(struct _Unwind_Context *ctx, void *data) +backtraceCallback(struct _Unwind_Context *ctx, void *data) { - struct backtrace_ctx *bt = data; + struct BacktraceCtx *bt = data; - if (bt->i < OF_BACKTRACE_SIZE) { + if (bt->i < OFBacktraceSize) { # ifndef HAVE_ARM_EHABI_EXCEPTIONS bt->backtrace[bt->i++] = (void *)_Unwind_GetIP(ctx); # else uintptr_t ip; @@ -280,17 +281,17 @@ } #ifdef HAVE__UNWIND_BACKTRACE - (instancetype)init { - struct backtrace_ctx ctx; + struct BacktraceCtx ctx; self = [super init]; ctx.backtrace = _backtrace; ctx.i = 0; - _Unwind_Backtrace(backtrace_callback, &ctx); + _Unwind_Backtrace(backtraceCallback, &ctx); return self; } #endif @@ -305,12 +306,11 @@ #ifdef HAVE__UNWIND_BACKTRACE OFMutableArray OF_GENERIC(OFString *) *backtrace = [OFMutableArray array]; void *pool = objc_autoreleasePoolPush(); - for (uint8_t i = 0; - i < OF_BACKTRACE_SIZE && _backtrace[i] != NULL; i++) { + for (uint8_t i = 0; i < OFBacktraceSize && _backtrace[i] != NULL; i++) { # ifdef HAVE_DLADDR Dl_info info; if (dladdr(_backtrace[i], &info)) { OFString *frame; Index: src/exceptions/OFGetCurrentDirectoryPathFailedException.h ================================================================== --- src/exceptions/OFGetCurrentDirectoryPathFailedException.h +++ src/exceptions/OFGetCurrentDirectoryPathFailedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -35,29 +33,29 @@ /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased get current directory path failed * exception. * * @param errNo The errno of the error that occurred * @return A new, autoreleased get current directory failed exception */ + (instancetype)exceptionWithErrNo: (int)errNo; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated get current directory path failed * exception. * * @param errNo The errno of the error that occurred * @return An initialized get current directory path failed exception */ - (instancetype)initWithErrNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFGetCurrentDirectoryPathFailedException.m ================================================================== --- src/exceptions/OFGetCurrentDirectoryPathFailedException.m +++ src/exceptions/OFGetCurrentDirectoryPathFailedException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -21,23 +19,18 @@ #import "OFString.h" @implementation OFGetCurrentDirectoryPathFailedException @synthesize errNo = _errNo; -+ (instancetype)exception -{ - OF_UNRECOGNIZED_SELECTOR -} - + (instancetype)exceptionWithErrNo: (int)errNo { return [[[self alloc] initWithErrNo: errNo] autorelease]; } -- (instancetype)init ++ (instancetype)exception { - OF_INVALID_INIT_METHOD + OF_UNRECOGNIZED_SELECTOR } - (instancetype)initWithErrNo: (int)errNo { self = [super init]; @@ -44,13 +37,18 @@ _errNo = errNo; return self; } + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} - (OFString *)description { return [OFString stringWithFormat: @"Getting the current directory path failed: %@", - of_strerror(_errNo)]; + OFStrError(_errNo)]; } @end Index: src/exceptions/OFGetOptionFailedException.h ================================================================== --- src/exceptions/OFGetOptionFailedException.h +++ src/exceptions/OFGetOptionFailedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -39,23 +37,20 @@ /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased get option failed exception. * * @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: (id)object errNo: (int)errNo; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated get option failed exception. * * @param object The object for which the option could not be retrieved @@ -62,8 +57,10 @@ * @param errNo The errno of the error that occurred * @return An initialized get option failed exception */ - (instancetype)initWithObject: (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,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -26,24 +24,21 @@ + (instancetype)exception { OF_UNRECOGNIZED_SELECTOR } -+ (instancetype)exceptionWithObject: (id)object - errNo: (int)errNo ++ (instancetype)exceptionWithObject: (id)object errNo: (int)errNo { - return [[[self alloc] initWithObject: object - errNo: errNo] autorelease]; + return [[[self alloc] initWithObject: object errNo: errNo] autorelease]; } - (instancetype)init { OF_INVALID_INIT_METHOD } -- (instancetype)initWithObject: (id)object - errNo: (int)errNo +- (instancetype)initWithObject: (id)object errNo: (int)errNo { self = [super init]; _object = [object retain]; _errNo = errNo; @@ -60,8 +55,8 @@ - (OFString *)description { return [OFString stringWithFormat: @"Getting an option in an object of type %@ failed: %@", - [_object class], of_strerror(_errNo)]; + [_object class], OFStrError(_errNo)]; } @end Index: src/exceptions/OFGetWindowsRegistryValueFailedException.h ================================================================== --- src/exceptions/OFGetWindowsRegistryValueFailedException.h +++ src/exceptions/OFGetWindowsRegistryValueFailedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -30,11 +28,11 @@ * @brief An exception indicating that getting a Windows registry value failed. */ @interface OFGetWindowsRegistryValueFailedException: OFException { OFWindowsRegistryKey *_registryKey; - OFString *_Nullable _value; + OFString *_Nullable _valueName; DWORD _flags; LSTATUS _status; } /** @@ -41,13 +39,13 @@ * @brief The registry key on which getting the value at the key path failed. */ @property (readonly, nonatomic) OFWindowsRegistryKey *registryKey; /** - * @brief The value which could not be retrieved. + * @brief The name of the value which could not be retrieved. */ -@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFString *value; +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFString *valueName; /** * @brief The status returned by RegGetValueEx(). */ @property (readonly, nonatomic) LSTATUS status; @@ -56,31 +54,33 @@ * @brief Creates a new, autoreleased get Windows registry value failed * exception. * * @param registryKey The registry key on which getting the value at the sub * key path failed - * @param value The value which could not be retrieved + * @param valueName The name of the value which could not be retrieved * @param status The status returned by RegGetValueEx() * @return A new, autoreleased get Windows registry value failed exception */ + (instancetype)exceptionWithRegistryKey: (OFWindowsRegistryKey *)registryKey - value: (nullable OFString *)value + valueName: (nullable OFString *)valueName status: (LSTATUS)status; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated get Windows registry value failed * exception. * * @param registryKey The registry key on which getting the value at the sub * key path failed - * @param value The value which could not be retrieved + * @param valueName The name of the value which could not be retrieved * @param status The status returned by RegGetValueEx() * @return An initialized get Windows registry value failed exception */ - (instancetype)initWithRegistryKey: (OFWindowsRegistryKey *)registryKey - value: (nullable OFString *)value + valueName: (nullable OFString *)valueName status: (LSTATUS)status OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFGetWindowsRegistryValueFailedException.m ================================================================== --- src/exceptions/OFGetWindowsRegistryValueFailedException.m +++ src/exceptions/OFGetWindowsRegistryValueFailedException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -18,54 +16,60 @@ #include "config.h" #import "OFGetWindowsRegistryValueFailedException.h" @implementation OFGetWindowsRegistryValueFailedException -@synthesize registryKey = _registryKey, value = _value, status = _status; +@synthesize registryKey = _registryKey, valueName = _valueName; +@synthesize status = _status; + (instancetype)exceptionWithRegistryKey: (OFWindowsRegistryKey *)registryKey - value: (OFString *)value + valueName: (OFString *)valueName status: (LSTATUS)status { return [[[self alloc] initWithRegistryKey: registryKey - value: value + valueName: valueName status: status] autorelease]; } -- (instancetype)init ++ (instancetype)exception { - OF_INVALID_INIT_METHOD + OF_UNRECOGNIZED_SELECTOR } - (instancetype)initWithRegistryKey: (OFWindowsRegistryKey *)registryKey - value: (OFString *)value + valueName: (OFString *)valueName status: (LSTATUS)status { self = [super init]; @try { _registryKey = [registryKey retain]; - _value = [value copy]; + _valueName = [valueName copy]; _status = status; } @catch (id e) { [self release]; @throw e; } return self; } + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} - (void)dealloc { [_registryKey release]; - [_value release]; + [_valueName release]; [super dealloc]; } - (OFString *)description { return [OFString stringWithFormat: - @"Failed to get value %@: %@", - _value, of_windows_status_to_string(_status)]; + @"Failed to get value named %@: %@", + _valueName, OFWindowsStatusToString(_status)]; } @end Index: src/exceptions/OFHTTPRequestFailedException.h ================================================================== --- src/exceptions/OFHTTPRequestFailedException.h +++ src/exceptions/OFHTTPRequestFailedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -47,12 +45,10 @@ /** * @brief The response for the failed HTTP request. */ @property (readonly, nonatomic) OFHTTPResponse *response; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased HTTP request failed exception. * * @param request The HTTP request which failed * @param response The response for the failed HTTP request @@ -59,11 +55,11 @@ * @return A new, autoreleased HTTP request failed exception */ + (instancetype)exceptionWithRequest: (OFHTTPRequest *)request response: (OFHTTPResponse *)response; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated HTTP request failed exception. * * @param request The HTTP request which failed @@ -71,8 +67,10 @@ * @return A new HTTP request failed exception */ - (instancetype)initWithRequest: (OFHTTPRequest *)request response: (OFHTTPResponse *)response OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFHTTPRequestFailedException.m ================================================================== --- src/exceptions/OFHTTPRequestFailedException.m +++ src/exceptions/OFHTTPRequestFailedException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -23,25 +21,20 @@ #import "OFHTTPResponse.h" @implementation OFHTTPRequestFailedException @synthesize request = _request, response = _response; -+ (instancetype)exception -{ - OF_UNRECOGNIZED_SELECTOR -} - + (instancetype)exceptionWithRequest: (OFHTTPRequest *)request response: (OFHTTPResponse *)response { return [[[self alloc] initWithRequest: request response: response] autorelease]; } -- (instancetype)init ++ (instancetype)exception { - OF_INVALID_INIT_METHOD + OF_UNRECOGNIZED_SELECTOR } - (instancetype)initWithRequest: (OFHTTPRequest *)request response: (OFHTTPResponse *)response { @@ -50,10 +43,15 @@ _request = [request retain]; _response = [response retain]; return self; } + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} - (void)dealloc { [_request release]; [_response release]; @@ -61,12 +59,12 @@ [super dealloc]; } - (OFString *)description { - const char *method = of_http_request_method_to_string(_request.method); + const char *method = OFHTTPRequestMethodName(_request.method); return [OFString stringWithFormat: @"An HTTP %s request with URL %@ failed with code %hd!", method, _request.URL, _response.statusCode]; } @end Index: src/exceptions/OFHashAlreadyCalculatedException.h ================================================================== --- src/exceptions/OFHashAlreadyCalculatedException.h +++ src/exceptions/OFHashAlreadyCalculatedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -34,27 +32,27 @@ /** * @brief The hash which has already been calculated. */ @property (readonly, nonatomic) id object; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased hash already calculated exception. * * @param object The hash which has already been calculated * @return A new, autoreleased hash already calculated exception */ + (instancetype)exceptionWithObject: (id)object; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated hash already calculated exception. * * @param object The hash which has already been calculated * @return An initialized hash already calculated exception */ - (instancetype)initWithObject: (id)object OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFHashAlreadyCalculatedException.m ================================================================== --- src/exceptions/OFHashAlreadyCalculatedException.m +++ src/exceptions/OFHashAlreadyCalculatedException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 ADDED src/exceptions/OFHashNotCalculatedException.h Index: src/exceptions/OFHashNotCalculatedException.h ================================================================== --- /dev/null +++ src/exceptions/OFHashNotCalculatedException.h @@ -0,0 +1,57 @@ +/* + * 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 OFHashNotCalculatedException OFHashNotCalculatedException.h \ + * ObjFW/OFHashNotCalculatedException.h + * + * @brief An exception indicating that the hash has not been calculated yet. + */ +@interface OFHashNotCalculatedException: OFException +{ + id _object; +} + +/** + * @brief The hash which has not been calculated yet. + */ +@property (readonly, nonatomic) id object; + +/** + * @brief Creates a new, autoreleased hash not calculated exception. + * + * @param object The hash which has not been calculated yet + * @return A new, autoreleased hash not calculated exception + */ ++ (instancetype)exceptionWithObject: (id)object; + ++ (instancetype)exception OF_UNAVAILABLE; + +/** + * @brief Initializes an already allocated hash not calculated exception. + * + * @param object The hash which has not been calculated yet + * @return An initialized hash not calculated exception + */ +- (instancetype)initWithObject: (id)object OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; +@end + +OF_ASSUME_NONNULL_END ADDED src/exceptions/OFHashNotCalculatedException.m Index: src/exceptions/OFHashNotCalculatedException.m ================================================================== --- /dev/null +++ src/exceptions/OFHashNotCalculatedException.m @@ -0,0 +1,61 @@ +/* + * 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 "OFHashNotCalculatedException.h" +#import "OFString.h" + +@implementation OFHashNotCalculatedException +@synthesize object = _object; + ++ (instancetype)exception +{ + OF_UNRECOGNIZED_SELECTOR +} + ++ (instancetype)exceptionWithObject: (id)object +{ + return [[[self alloc] initWithObject: object] autorelease]; +} + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)initWithObject: (id)object +{ + self = [super init]; + + _object = [object retain]; + + return self; +} + +- (void)dealloc +{ + [_object release]; + + [super dealloc]; +} + +- (OFString *)description +{ + return [OFString stringWithFormat: + @"The hash of type %@ has not been calculated yet!", + [_object class]]; +} +@end Index: src/exceptions/OFInitializationFailedException.h ================================================================== --- src/exceptions/OFInitializationFailedException.h +++ src/exceptions/OFInitializationFailedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/exceptions/OFInitializationFailedException.m ================================================================== --- src/exceptions/OFInitializationFailedException.m +++ src/exceptions/OFInitializationFailedException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/exceptions/OFInvalidArgumentException.h ================================================================== --- src/exceptions/OFInvalidArgumentException.h +++ src/exceptions/OFInvalidArgumentException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/exceptions/OFInvalidArgumentException.m ================================================================== --- src/exceptions/OFInvalidArgumentException.m +++ src/exceptions/OFInvalidArgumentException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/exceptions/OFInvalidEncodingException.h ================================================================== --- src/exceptions/OFInvalidEncodingException.h +++ src/exceptions/OFInvalidEncodingException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/exceptions/OFInvalidEncodingException.m ================================================================== --- src/exceptions/OFInvalidEncodingException.m +++ src/exceptions/OFInvalidEncodingException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/exceptions/OFInvalidFormatException.h ================================================================== --- src/exceptions/OFInvalidFormatException.h +++ src/exceptions/OFInvalidFormatException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/exceptions/OFInvalidFormatException.m ================================================================== --- src/exceptions/OFInvalidFormatException.m +++ src/exceptions/OFInvalidFormatException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/exceptions/OFInvalidJSONException.h ================================================================== --- src/exceptions/OFInvalidJSONException.h +++ src/exceptions/OFInvalidJSONException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -39,12 +37,10 @@ /** * @brief The line in which parsing the JSON representation failed. */ @property (readonly, nonatomic) size_t line; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased invalid JSON exception. * * @param string The string containing the invalid JSON representation * @param line The line in which the parsing error was encountered @@ -51,11 +47,11 @@ * @return A new, autoreleased invalid JSON exception */ + (instancetype)exceptionWithString: (nullable OFString *)string line: (size_t)line; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated invalid JSON exception. * * @param string The string containing the invalid JSON representation @@ -62,8 +58,10 @@ * @param line The line in which the parsing error was encountered * @return An initialized invalid JSON exception */ - (instancetype)initWithString: (nullable OFString *)string line: (size_t)line OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFInvalidJSONException.m ================================================================== --- src/exceptions/OFInvalidJSONException.m +++ src/exceptions/OFInvalidJSONException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -26,24 +24,21 @@ + (instancetype)exception { OF_UNRECOGNIZED_SELECTOR } -+ (instancetype)exceptionWithString: (OFString *)string - line: (size_t)line ++ (instancetype)exceptionWithString: (OFString *)string line: (size_t)line { - return [[[self alloc] initWithString: string - line: line] autorelease]; + return [[[self alloc] initWithString: string line: line] autorelease]; } - (instancetype)init { OF_INVALID_INIT_METHOD } -- (instancetype)initWithString: (OFString *)string - line: (size_t)line +- (instancetype)initWithString: (OFString *)string line: (size_t)line { self = [super init]; @try { _string = [string copy]; Index: src/exceptions/OFInvalidServerReplyException.h ================================================================== --- src/exceptions/OFInvalidServerReplyException.h +++ src/exceptions/OFInvalidServerReplyException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/exceptions/OFInvalidServerReplyException.m ================================================================== --- src/exceptions/OFInvalidServerReplyException.m +++ src/exceptions/OFInvalidServerReplyException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/exceptions/OFLinkFailedException.h ================================================================== --- src/exceptions/OFLinkFailedException.h +++ src/exceptions/OFLinkFailedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -46,12 +44,10 @@ /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased link failed exception. * * @param sourceURL The source for the link * @param destinationURL The destination for the link @@ -60,11 +56,11 @@ */ + (instancetype)exceptionWithSourceURL: (OFURL *)sourceURL destinationURL: (OFURL *)destinationURL errNo: (int)errNo; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated link failed exception. * * @param sourceURL The source for the link @@ -73,8 +69,10 @@ * @return An initialized link failed exception */ - (instancetype)initWithSourceURL: (OFURL*)sourceURL destinationURL: (OFURL *)destinationURL errNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFLinkFailedException.m ================================================================== --- src/exceptions/OFLinkFailedException.m +++ src/exceptions/OFLinkFailedException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -71,8 +69,8 @@ } - (OFString *)description { return [OFString stringWithFormat: @"Failed to link file %@ to %@: %@", - _sourceURL, _destinationURL, of_strerror(_errNo)]; + _sourceURL, _destinationURL, OFStrError(_errNo)]; } @end Index: src/exceptions/OFListenFailedException.h ================================================================== --- src/exceptions/OFListenFailedException.h +++ src/exceptions/OFListenFailedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -48,12 +46,10 @@ /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @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 @@ -62,21 +58,23 @@ */ + (instancetype)exceptionWithSocket: (id)socket backlog: (int)backlog errNo: (int)errNo; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** - * @brief Initializes an already allocated listen failed exception + * @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 Index: src/exceptions/OFListenFailedException.m ================================================================== --- src/exceptions/OFListenFailedException.m +++ src/exceptions/OFListenFailedException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -64,8 +62,8 @@ - (OFString *)description { return [OFString stringWithFormat: @"Failed to listen in socket of type %@ with a back log of %d: %@", - [_socket class], _backlog, of_strerror(_errNo)]; + [_socket class], _backlog, OFStrError(_errNo)]; } @end Index: src/exceptions/OFLoadPluginFailedException.h ================================================================== --- src/exceptions/OFLoadPluginFailedException.h +++ src/exceptions/OFLoadPluginFailedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -38,12 +36,10 @@ /** * @brief The error why the plugin could not be loaded, as a string */ @property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFString *error; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased load plugin failed exception. * * @param path The path of the plugin which could not be loaded * @param error The error why the plugin could not be loaded, as a string @@ -50,11 +46,11 @@ * @return A new, autoreleased load plugin failed exception */ + (instancetype)exceptionWithPath: (OFString *)path error: (nullable OFString *)error; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated load plugin failed exception. * * @param path The path of the plugin which could not be loaded @@ -62,8 +58,10 @@ * @return An initialized load plugin failed exception */ - (instancetype)initWithPath: (OFString *)path error: (nullable OFString *)error OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFLoadPluginFailedException.m ================================================================== --- src/exceptions/OFLoadPluginFailedException.m +++ src/exceptions/OFLoadPluginFailedException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -20,30 +18,22 @@ #import "OFLoadPluginFailedException.h" #import "OFString.h" @implementation OFLoadPluginFailedException @synthesize path = _path, error = _error; + ++ (instancetype)exceptionWithPath: (OFString *)path error: (OFString *)error +{ + return [[[self alloc] initWithPath: path error: error] autorelease]; +} + (instancetype)exception { OF_UNRECOGNIZED_SELECTOR } -+ (instancetype)exceptionWithPath: (OFString *)path - error: (OFString *)error -{ - return [[[self alloc] initWithPath: path - error: error] autorelease]; -} - -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - -- (instancetype)initWithPath: (OFString *)path - error: (OFString *)error +- (instancetype)initWithPath: (OFString *)path error: (OFString *)error { self = [super init]; @try { _path = [path copy]; @@ -53,10 +43,15 @@ @throw e; } return self; } + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} - (void)dealloc { [_path release]; [_error release]; Index: src/exceptions/OFLockFailedException.h ================================================================== --- src/exceptions/OFLockFailedException.h +++ src/exceptions/OFLockFailedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -26,11 +24,11 @@ * * @brief An exception indicating that locking a lock failed. */ @interface OFLockFailedException: OFException { - id _lock; + id _Nullable _lock; int _errNo; } /** * @brief The lock which could not be locked. @@ -59,10 +57,8 @@ * @param errNo The errno of the error that occurred * @return An initialized lock failed exception */ - (instancetype)initWithLock: (nullable id )lock errNo: (int)errNo OF_DESIGNATED_INITIALIZER; - -- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFLockFailedException.m ================================================================== --- src/exceptions/OFLockFailedException.m +++ src/exceptions/OFLockFailedException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -23,42 +21,37 @@ #import "OFString.h" @implementation OFLockFailedException @synthesize lock = _lock, errNo = _errNo; -+ (instancetype)exceptionWithLock: (id )lock - errNo: (int)errNo ++ (instancetype)exceptionWithLock: (id )lock errNo: (int)errNo { - return [[[self alloc] initWithLock: lock - errNo: errNo] autorelease]; + return [[[self alloc] initWithLock: lock errNo: errNo] autorelease]; } -- (instancetype)initWithLock: (id )lock - errNo: (int)errNo +- (instancetype)initWithLock: (id )lock errNo: (int)errNo { self = [super init]; _lock = [lock retain]; _errNo = errNo; return self; } -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - - (void)dealloc { [_lock release]; [super dealloc]; } - (OFString *)description { - return [OFString stringWithFormat: - @"A lock of type %@ could not be locked: %s", - [_lock class], strerror(_errNo)]; + if (_lock != nil) + return [OFString stringWithFormat: + @"A lock of type %@ could not be locked: %s", + [_lock class], strerror(_errNo)]; + else + return @"A lock could not be locked!"; } @end Index: src/exceptions/OFMalformedXMLException.h ================================================================== --- src/exceptions/OFMalformedXMLException.h +++ src/exceptions/OFMalformedXMLException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/exceptions/OFMalformedXMLException.m ================================================================== --- src/exceptions/OFMalformedXMLException.m +++ src/exceptions/OFMalformedXMLException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 DELETED src/exceptions/OFMemoryNotPartOfObjectException.h Index: src/exceptions/OFMemoryNotPartOfObjectException.h ================================================================== --- src/exceptions/OFMemoryNotPartOfObjectException.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 OFMemoryNotPartOfObjectException \ - * OFMemoryNotPartOfObjectException.h \ - * ObjFW/OFMemoryNotPartOfObjectException.h - * - * @brief An exception indicating the given memory is not part of the object. - */ -@interface OFMemoryNotPartOfObjectException: OFException -{ - void *_Nullable _pointer; - id _object; -} - -/** - * @brief A pointer to the memory which is not part of the object. - */ -@property OF_NULLABLE_PROPERTY (readonly, nonatomic) void *pointer; - -/** - * @brief The object which the memory is not part of. - */ -@property (readonly, nonatomic) id object; - -+ (instancetype)exception OF_UNAVAILABLE; - -/** - * @brief Creates a new, autoreleased memory not part of object exception. - * - * @param pointer A pointer to the memory that is not part of the object - * @param object The object which the memory is not part of - * @return A new, autoreleased memory not part of object exception - */ -+ (instancetype)exceptionWithPointer: (nullable void *)pointer - object: (id)object; - -- (instancetype)init OF_UNAVAILABLE; - -/** - * @brief Initializes an already allocated memory not part of object exception. - * - * @param pointer A pointer to the memory that is not part of the object - * @param object The object which the memory is not part of - * @return An initialized memory not part of object exception - */ -- (instancetype)initWithPointer: (nullable void *)pointer - object: (id)object OF_DESIGNATED_INITIALIZER; -@end - -OF_ASSUME_NONNULL_END DELETED src/exceptions/OFMemoryNotPartOfObjectException.m Index: src/exceptions/OFMemoryNotPartOfObjectException.m ================================================================== --- src/exceptions/OFMemoryNotPartOfObjectException.m +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "OFMemoryNotPartOfObjectException.h" -#import "OFString.h" - -@implementation OFMemoryNotPartOfObjectException -@synthesize pointer = _pointer, object = _object; - -+ (instancetype)exception -{ - OF_UNRECOGNIZED_SELECTOR -} - -+ (instancetype)exceptionWithPointer: (void *)pointer - object: (id)object -{ - return [[[self alloc] initWithPointer: pointer - object: object] autorelease]; -} - -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - -- (instancetype)initWithPointer: (void *)pointer - object: (id)object -{ - self = [super init]; - - _pointer = pointer; - _object = [object retain]; - - return self; -} - -- (void)dealloc -{ - [_object release]; - - [super dealloc]; -} - -- (OFString *)description -{ - return [OFString stringWithFormat: - @"Deallocation or reallocation of memory not allocated as part of " - @"object of type %@ was attempted! It is also possible that there " - @"was an attempt to free the same memory twice.", - [_object class]]; -} -@end Index: src/exceptions/OFMoveItemFailedException.h ================================================================== --- src/exceptions/OFMoveItemFailedException.h +++ src/exceptions/OFMoveItemFailedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -46,12 +44,10 @@ /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased move item failed exception. * * @param sourceURL The original URL * @param destinationURL The new URL @@ -60,11 +56,11 @@ */ + (instancetype)exceptionWithSourceURL: (OFURL *)sourceURL destinationURL: (OFURL *)destinationURL errNo: (int)errNo; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated move item failed exception. * * @param sourceURL The original URL @@ -73,8 +69,10 @@ * @return An initialized move item failed exception */ - (instancetype)initWithSourceURL: (OFURL *)sourceURL destinationURL: (OFURL *)destinationURL 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,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -30,11 +28,11 @@ OF_UNRECOGNIZED_SELECTOR } + (instancetype)exceptionWithSourceURL: (OFURL *)sourceURL destinationURL: (OFURL *)destinationURL - errNo: (int)errNo + errNo: (int)errNo { return [[[self alloc] initWithSourceURL: sourceURL destinationURL: destinationURL errNo: errNo] autorelease]; } @@ -72,8 +70,8 @@ - (OFString *)description { return [OFString stringWithFormat: @"Failed to move item at %@ to %@: %@", - _sourceURL, _destinationURL, of_strerror(_errNo)]; + _sourceURL, _destinationURL, OFStrError(_errNo)]; } @end Index: src/exceptions/OFNotImplementedException.h ================================================================== --- src/exceptions/OFNotImplementedException.h +++ src/exceptions/OFNotImplementedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -38,13 +36,11 @@ @property (readonly, nonatomic) SEL selector; /** * @brief The object which does not (fully) implement the selector. */ -@property (readonly, nonatomic) id object; - -+ (instancetype)exception OF_UNAVAILABLE; +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) id object; /** * @brief Creates a new, autoreleased not implemented exception. * * @param selector The selector which is not or not fully implemented @@ -52,11 +48,11 @@ * @return A new, autoreleased not implemented exception */ + (instancetype)exceptionWithSelector: (SEL)selector object: (nullable id)object; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated not implemented exception. * * @param selector The selector which is not or not fully implemented @@ -63,8 +59,10 @@ * @param object The object which does not (fully) implement the selector * @return An initialized not implemented exception */ - (instancetype)initWithSelector: (SEL)selector object: (nullable id)object OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFNotImplementedException.m ================================================================== --- src/exceptions/OFNotImplementedException.m +++ src/exceptions/OFNotImplementedException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -26,12 +24,11 @@ + (instancetype)exception { OF_UNRECOGNIZED_SELECTOR } -+ (instancetype)exceptionWithSelector: (SEL)selector - object: (id)object ++ (instancetype)exceptionWithSelector: (SEL)selector object: (id)object { return [[[self alloc] initWithSelector: selector object: object] autorelease]; } @@ -38,12 +35,11 @@ - (instancetype)init { OF_INVALID_INIT_METHOD } -- (instancetype)initWithSelector: (SEL)selector - object: (id)object +- (instancetype)initWithSelector: (SEL)selector object: (id)object { self = [super init]; _selector = selector; _object = [object retain]; Index: src/exceptions/OFNotOpenException.h ================================================================== --- src/exceptions/OFNotOpenException.h +++ src/exceptions/OFNotOpenException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -32,27 +30,27 @@ /** * @brief The object which is not open, connected or bound. */ @property (readonly, nonatomic) id object; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased not open exception. * * @param object The object which is not open, connected or bound * @return A new, autoreleased not open exception */ + (instancetype)exceptionWithObject: (id)object; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated not open exception. * * @param object The object which is not open, connected or bound * @return An initialized not open exception */ - (instancetype)initWithObject: (id)object OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFNotOpenException.m ================================================================== --- src/exceptions/OFNotOpenException.m +++ src/exceptions/OFNotOpenException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/exceptions/OFObserveFailedException.h ================================================================== --- src/exceptions/OFObserveFailedException.h +++ src/exceptions/OFObserveFailedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -41,12 +39,10 @@ /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased observe failed exception. * * @param observer The observer which failed to observe * @param errNo The errno of the error that occurred @@ -53,11 +49,11 @@ * @return A new, autoreleased observe failed exception */ + (instancetype)exceptionWithObserver: (OFKernelEventObserver *)observer errNo: (int)errNo; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated observe failed exception. * * @param observer The observer which failed to observe @@ -64,8 +60,10 @@ * @param errNo The errno of the error that occurred * @return An initialized observe failed exception */ - (instancetype)initWithObserver: (OFKernelEventObserver *)observer errNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFObserveFailedException.m ================================================================== --- src/exceptions/OFObserveFailedException.m +++ src/exceptions/OFObserveFailedException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -66,8 +64,8 @@ - (OFString *)description { return [OFString stringWithFormat: @"An observer of class %@ failed to observe: %@", - _observer.class, of_strerror(_errNo)]; + _observer.class, OFStrError(_errNo)]; } @end Index: src/exceptions/OFOpenItemFailedException.h ================================================================== --- src/exceptions/OFOpenItemFailedException.h +++ src/exceptions/OFOpenItemFailedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -53,12 +51,10 @@ /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased open item failed exception. * * @param URL The URL of the item which could not be opened * @param mode A string with the mode in which the item should have been opened @@ -79,11 +75,11 @@ */ + (instancetype)exceptionWithPath: (OFString *)path mode: (nullable OFString *)mode errNo: (int)errNo; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated open item failed exception. * * @param URL The URL of the item which could not be opened @@ -104,8 +100,10 @@ * @return An initialized open item failed exception */ - (instancetype)initWithPath: (OFString *)path mode: (nullable OFString *)mode errNo: (int)errNo; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFOpenItemFailedException.m ================================================================== --- src/exceptions/OFOpenItemFailedException.m +++ src/exceptions/OFOpenItemFailedException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -22,15 +20,10 @@ #import "OFURL.h" @implementation OFOpenItemFailedException @synthesize URL = _URL, path = _path, mode = _mode, errNo = _errNo; -+ (instancetype)exception -{ - OF_UNRECOGNIZED_SELECTOR -} - + (instancetype)exceptionWithURL: (OFURL *)URL mode: (OFString *)mode errNo: (int)errNo { return [[[self alloc] initWithURL: URL @@ -45,13 +38,13 @@ return [[[self alloc] initWithPath: path mode: mode errNo: errNo] autorelease]; } -- (instancetype)init ++ (instancetype)exception { - OF_INVALID_INIT_METHOD + OF_UNRECOGNIZED_SELECTOR } - (instancetype)initWithURL: (OFURL *)URL mode: (OFString *)mode errNo: (int)errNo @@ -85,10 +78,15 @@ @throw e; } return self; } + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} - (void)dealloc { [_URL release]; [_path release]; @@ -107,11 +105,11 @@ item = _path; if (_mode != nil) return [OFString stringWithFormat: @"Failed to open item %@ with mode %@: %@", - item, _mode, of_strerror(_errNo)]; + item, _mode, OFStrError(_errNo)]; else return [OFString stringWithFormat: - @"Failed to open item %@: %@", item, of_strerror(_errNo)]; + @"Failed to open item %@: %@", item, OFStrError(_errNo)]; } @end Index: src/exceptions/OFOpenWindowsRegistryKeyFailedException.h ================================================================== --- src/exceptions/OFOpenWindowsRegistryKeyFailedException.h +++ src/exceptions/OFOpenWindowsRegistryKeyFailedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -82,11 +80,11 @@ path: (OFString *)path options: (DWORD)options securityAndAccessRights: (REGSAM)securityAndAccessRights status: (LSTATUS)status; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated open Windows registry key failed * exception. * @@ -102,8 +100,10 @@ initWithRegistryKey: (OFWindowsRegistryKey *)registryKey path: (OFString *)path options: (DWORD)options securityAndAccessRights: (REGSAM)securityAndAccessRights status: (LSTATUS)status OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFOpenWindowsRegistryKeyFailedException.m ================================================================== --- src/exceptions/OFOpenWindowsRegistryKeyFailedException.m +++ src/exceptions/OFOpenWindowsRegistryKeyFailedException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -36,13 +34,13 @@ options: options securityAndAccessRights: securityAndAccessRights status: status] autorelease]; } -- (instancetype)init ++ (instancetype)exception { - OF_INVALID_INIT_METHOD + OF_UNRECOGNIZED_SELECTOR } - (instancetype) initWithRegistryKey: (OFWindowsRegistryKey *)registryKey path: (OFString *)path @@ -63,10 +61,15 @@ @throw e; } return self; } + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} - (void)dealloc { [_registryKey release]; [_path release]; @@ -76,8 +79,8 @@ - (OFString *)description { return [OFString stringWithFormat: @"Failed to open subkey at path %@: %@", - _path, of_windows_status_to_string(_status)]; + _path, OFWindowsStatusToString(_status)]; } @end Index: src/exceptions/OFOutOfMemoryException.h ================================================================== --- src/exceptions/OFOutOfMemoryException.h +++ src/exceptions/OFOutOfMemoryException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/exceptions/OFOutOfMemoryException.m ================================================================== --- src/exceptions/OFOutOfMemoryException.m +++ src/exceptions/OFOutOfMemoryException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/exceptions/OFOutOfRangeException.h ================================================================== --- src/exceptions/OFOutOfRangeException.h +++ src/exceptions/OFOutOfRangeException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/exceptions/OFOutOfRangeException.m ================================================================== --- src/exceptions/OFOutOfRangeException.m +++ src/exceptions/OFOutOfRangeException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/exceptions/OFReadFailedException.h ================================================================== --- src/exceptions/OFReadFailedException.h +++ src/exceptions/OFReadFailedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/exceptions/OFReadFailedException.m ================================================================== --- src/exceptions/OFReadFailedException.m +++ src/exceptions/OFReadFailedException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -21,10 +19,15 @@ #import "OFString.h" @implementation OFReadFailedException - (OFString *)description { - return [OFString stringWithFormat: - @"Failed to read %zu bytes from an object of type %@: %@", - _requestedLength, [_object class], of_strerror(_errNo)]; + if (_errNo != 0) + return [OFString stringWithFormat: + @"Failed to read %zu bytes from an object of type %@: %@", + _requestedLength, [_object class], OFStrError(_errNo)]; + else + return [OFString stringWithFormat: + @"Failed to read %zu bytes from an object of type %@", + _requestedLength, [_object class]]; } @end Index: src/exceptions/OFReadOrWriteFailedException.h ================================================================== --- src/exceptions/OFReadOrWriteFailedException.h +++ src/exceptions/OFReadOrWriteFailedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/exceptions/OFReadOrWriteFailedException.m ================================================================== --- src/exceptions/OFReadOrWriteFailedException.m +++ src/exceptions/OFReadOrWriteFailedException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -63,11 +61,17 @@ [super dealloc]; } - (OFString *)description { - return [OFString stringWithFormat: - @"Failed to read or write %zu bytes from / to an object of type " - @"%@: %@", - _requestedLength, [_object class], of_strerror(_errNo)]; + if (_errNo != 0) + return [OFString stringWithFormat: + @"Failed to read or write %zu bytes from / to an object of " + @"type %@: %@", + _requestedLength, [_object class], OFStrError(_errNo)]; + else + return [OFString stringWithFormat: + @"Failed to read or write %zu bytes from / to an object of " + @"type %@", + _requestedLength, [_object class]]; } @end Index: src/exceptions/OFRemoveItemFailedException.h ================================================================== --- src/exceptions/OFRemoveItemFailedException.h +++ src/exceptions/OFRemoveItemFailedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -41,23 +39,20 @@ /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased remove failed exception. * * @param URL The URL 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)exceptionWithURL: (OFURL *)URL - errNo: (int)errNo; ++ (instancetype)exceptionWithURL: (OFURL *)URL errNo: (int)errNo; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated remove failed exception. * * @param URL The URL of the item which could not be removed @@ -64,8 +59,10 @@ * @param errNo The errno of the error that occurred * @return An initialized remove item failed exception */ - (instancetype)initWithURL: (OFURL *)URL 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,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -27,24 +25,21 @@ + (instancetype)exception { OF_UNRECOGNIZED_SELECTOR } -+ (instancetype)exceptionWithURL: (OFURL *)URL - errNo: (int)errNo ++ (instancetype)exceptionWithURL: (OFURL *)URL errNo: (int)errNo { - return [[[self alloc] initWithURL: URL - errNo: errNo] autorelease]; + return [[[self alloc] initWithURL: URL errNo: errNo] autorelease]; } - (instancetype)init { OF_INVALID_INIT_METHOD } -- (instancetype)initWithURL: (OFURL *)URL - errNo: (int)errNo +- (instancetype)initWithURL: (OFURL *)URL errNo: (int)errNo { self = [super init]; @try { _URL = [URL copy]; @@ -65,8 +60,8 @@ } - (OFString *)description { return [OFString stringWithFormat: - @"Failed to remove item at URL %@: %@", _URL, of_strerror(_errNo)]; + @"Failed to remove item at URL %@: %@", _URL, OFStrError(_errNo)]; } @end Index: src/exceptions/OFResolveHostFailedException.h ================================================================== --- src/exceptions/OFResolveHostFailedException.h +++ src/exceptions/OFResolveHostFailedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -27,12 +25,12 @@ * @brief An exception indicating that resolving a host failed. */ @interface OFResolveHostFailedException: OFException { OFString *_host; - of_socket_address_family_t _addressFamily; - of_dns_resolver_error_t _error; + OFSocketAddressFamily _addressFamily; + OFDNSResolverErrorCode _errorCode; } /** * @brief The host which could not be resolved. */ @@ -39,40 +37,44 @@ @property (readonly, nonatomic) OFString *host; /** * @brief The address family for which the host could not be resolved. */ -@property (readonly, nonatomic) of_socket_address_family_t addressFamily; +@property (readonly, nonatomic) OFSocketAddressFamily addressFamily; /** - * @brief The error from the resolver. + * @brief The error code from the resolver. */ -@property (readonly, nonatomic) of_dns_resolver_error_t error; +@property (readonly, nonatomic) OFDNSResolverErrorCode errorCode; /** * @brief Creates a new, autoreleased resolve host failed exception. * * @param host The host which could not be resolved * @param addressFamily The address family for which the host could not be * resolved - * @param error The error from the resolver + * @param errorCode The error code from the resolver * @return A new, autoreleased address translation failed exception */ + (instancetype)exceptionWithHost: (OFString *)host - addressFamily: (of_socket_address_family_t)addressFamily - error: (of_dns_resolver_error_t)error; + addressFamily: (OFSocketAddressFamily)addressFamily + errorCode: (OFDNSResolverErrorCode)errorCode; + ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated resolve host failed exception. * * @param host The host which could not be resolved * @param addressFamily The address family for which the host could not be * resolved - * @param error The error from the resolver + * @param errorCode The error code from the resolver * @return An initialized address translation failed exception */ - (instancetype)initWithHost: (OFString *)host - addressFamily: (of_socket_address_family_t)addressFamily - error: (of_dns_resolver_error_t)error; + addressFamily: (OFSocketAddressFamily)addressFamily + errorCode: (OFDNSResolverErrorCode)errorCode; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFResolveHostFailedException.m ================================================================== --- src/exceptions/OFResolveHostFailedException.m +++ src/exceptions/OFResolveHostFailedException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -20,38 +18,49 @@ #import "OFResolveHostFailedException.h" #import "OFDNSQueryFailedException.h" #import "OFString.h" @implementation OFResolveHostFailedException -@synthesize host = _host, addressFamily = _addressFamily, error = _error; +@synthesize host = _host, addressFamily = _addressFamily; +@synthesize errorCode = _errorCode; + (instancetype)exceptionWithHost: (OFString *)host - addressFamily: (of_socket_address_family_t)addressFamily - error: (of_dns_resolver_error_t)error + addressFamily: (OFSocketAddressFamily)addressFamily + errorCode: (OFDNSResolverErrorCode)errorCode { return [[[self alloc] initWithHost: host addressFamily: addressFamily - error: error] autorelease]; + errorCode: errorCode] autorelease]; +} + ++ (instancetype)exception +{ + OF_UNRECOGNIZED_SELECTOR } - (instancetype)initWithHost: (OFString *)host - addressFamily: (of_socket_address_family_t)addressFamily - error: (of_dns_resolver_error_t)error + addressFamily: (OFSocketAddressFamily)addressFamily + errorCode: (OFDNSResolverErrorCode)errorCode { self = [super init]; @try { _host = [host copy]; _addressFamily = addressFamily; - _error = error; + _errorCode = errorCode; } @catch (id e) { [self release]; @throw e; } return self; } + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} - (void)dealloc { [_host release]; @@ -60,8 +69,8 @@ - (OFString *)description { return [OFString stringWithFormat: @"The host %@ could not be resolved: %@", - _host, of_dns_resolver_error_to_string(_error)]; + _host, OFDNSResolverErrorCodeDescription(_errorCode)]; } @end Index: src/exceptions/OFRetrieveItemAttributesFailedException.h ================================================================== --- src/exceptions/OFRetrieveItemAttributesFailedException.h +++ src/exceptions/OFRetrieveItemAttributesFailedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -42,23 +40,20 @@ /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased retrieve item attributes failed exception. * * @param URL The URL 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)exceptionWithURL: (OFURL *)URL - errNo: (int)errNo; ++ (instancetype)exceptionWithURL: (OFURL *)URL errNo: (int)errNo; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated retrieve item attributes failed * exception. * @@ -66,8 +61,10 @@ * @param errNo The errno of the error that occurred * @return An initialized retrieve item attributes failed exception */ - (instancetype)initWithURL: (OFURL *)URL errNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFRetrieveItemAttributesFailedException.m ================================================================== --- src/exceptions/OFRetrieveItemAttributesFailedException.m +++ src/exceptions/OFRetrieveItemAttributesFailedException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -27,24 +25,21 @@ + (instancetype)exception { OF_UNRECOGNIZED_SELECTOR } -+ (instancetype)exceptionWithURL: (OFURL *)URL - errNo: (int)errNo ++ (instancetype)exceptionWithURL: (OFURL *)URL errNo: (int)errNo { - return [[[self alloc] initWithURL: URL - errNo: errNo] autorelease]; + return [[[self alloc] initWithURL: URL errNo: errNo] autorelease]; } - (instancetype)init { OF_INVALID_INIT_METHOD } -- (instancetype)initWithURL: (OFURL *)URL - errNo: (int)errNo +- (instancetype)initWithURL: (OFURL *)URL errNo: (int)errNo { self = [super init]; @try { _URL = [URL copy]; @@ -66,8 +61,8 @@ - (OFString *)description { return [OFString stringWithFormat: @"Failed to retrieve attributes for item %@: %@", - _URL, of_strerror(_errNo)]; + _URL, OFStrError(_errNo)]; } @end Index: src/exceptions/OFSandboxActivationFailedException.h ================================================================== --- src/exceptions/OFSandboxActivationFailedException.h +++ src/exceptions/OFSandboxActivationFailedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -19,54 +17,22 @@ OF_ASSUME_NONNULL_BEGIN @class OFSandbox; -/** - * @class OFSandboxActivationFailedException \ - * OFSandboxActivationFailedException.h \ - * ObjFW/OFSandboxActivationFailedException.h - * - * @brief An exception indicating that sandboxing the process failed. - */ @interface OFSandboxActivationFailedException: OFException { OFSandbox *_sandbox; int _errNo; } -/** - * @brief The sandbox which could not be activated. - */ @property (readonly, nonatomic) OFSandbox *sandbox; - -/** - * @brief The errno of the error that occurred. - */ @property (readonly, nonatomic) int errNo; + (instancetype)exception OF_UNAVAILABLE; - -/** - * @brief Creates a new, autoreleased sandboxing failed exception. - * - * @param sandbox The sandbox which could not be activated - * @param errNo The errno of the error that occurred - * @return A new, autoreleased sandboxing failed exception - */ -+ (instancetype)exceptionWithSandbox: (OFSandbox *)sandbox - errNo: (int)errNo; - ++ (instancetype)exceptionWithSandbox: (OFSandbox *)sandbox errNo: (int)errNo; - (instancetype)init OF_UNAVAILABLE; - -/** - * @brief Initializes an already allocated sandboxing failed exception. - * - * @param sandbox The sandbox which could not be activated - * @param errNo The errno of the error that occurred - * @return An initialized sandboxing failed exception - */ - (instancetype)initWithSandbox: (OFSandbox *)sandbox errNo: (int)errNo OF_DESIGNATED_INITIALIZER; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFSandboxActivationFailedException.m ================================================================== --- src/exceptions/OFSandboxActivationFailedException.m +++ src/exceptions/OFSandboxActivationFailedException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -27,12 +25,11 @@ + (instancetype)exception { OF_UNRECOGNIZED_SELECTOR } -+ (instancetype)exceptionWithSandbox: (OFSandbox *)sandbox - errNo: (int)errNo ++ (instancetype)exceptionWithSandbox: (OFSandbox *)sandbox errNo: (int)errNo { return [[[self alloc] initWithSandbox: sandbox errNo: errNo] autorelease]; } @@ -39,12 +36,11 @@ - (instancetype)init { OF_INVALID_INIT_METHOD } -- (instancetype)initWithSandbox: (OFSandbox *)sandbox - errNo: (int)errNo +- (instancetype)initWithSandbox: (OFSandbox *)sandbox errNo: (int)errNo { self = [super init]; _sandbox = [sandbox retain]; _errNo = errNo; @@ -60,8 +56,8 @@ } - (OFString *)description { return [OFString stringWithFormat: - @"The sandbox could not be applied: %@", of_strerror(_errNo)]; + @"The sandbox could not be applied: %@", OFStrError(_errNo)]; } @end Index: src/exceptions/OFSeekFailedException.h ================================================================== --- src/exceptions/OFSeekFailedException.h +++ src/exceptions/OFSeekFailedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -27,11 +25,11 @@ * @brief An exception indicating that seeking in a stream failed. */ @interface OFSeekFailedException: OFException { OFSeekableStream *_stream; - of_offset_t _offset; + OFFileOffset _offset; int _whence, _errNo; } /** * @brief The stream for which seeking failed. @@ -39,11 +37,11 @@ @property (readonly, nonatomic) OFSeekableStream *stream; /** * @brief The offset to which seeking failed. */ -@property (readonly, nonatomic) of_offset_t offset; +@property (readonly, nonatomic) OFFileOffset offset; /** * @brief To what the offset is relative. */ @property (readonly, nonatomic) int whence; @@ -51,12 +49,10 @@ /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased seek failed exception. * * @param stream The stream for which seeking failed * @param offset The offset to which seeking failed @@ -63,15 +59,15 @@ * @param whence To what the offset is relative * @param errNo The errno of the error that occurred * @return A new, autoreleased seek failed exception */ + (instancetype)exceptionWithStream: (OFSeekableStream *)stream - offset: (of_offset_t)offset + offset: (OFFileOffset)offset whence: (int)whence errNo: (int)errNo; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated seek failed exception. * * @param stream The stream for which seeking failed @@ -79,11 +75,13 @@ * @param whence To what the offset is relative * @param errNo The errno of the error that occurred * @return An initialized seek failed exception */ - (instancetype)initWithStream: (OFSeekableStream *)stream - offset: (of_offset_t)offset + offset: (OFFileOffset)offset whence: (int)whence errNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFSeekFailedException.m ================================================================== --- src/exceptions/OFSeekFailedException.m +++ src/exceptions/OFSeekFailedException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -29,11 +27,11 @@ { OF_UNRECOGNIZED_SELECTOR } + (instancetype)exceptionWithStream: (OFSeekableStream *)stream - offset: (of_offset_t)offset + offset: (OFFileOffset)offset whence: (int)whence errNo: (int)errNo { return [[[self alloc] initWithStream: stream offset: offset @@ -45,11 +43,11 @@ { OF_INVALID_INIT_METHOD } - (instancetype)initWithStream: (OFSeekableStream *)stream - offset: (of_offset_t)offset + offset: (OFFileOffset)offset whence: (int)whence errNo: (int)errNo { self = [super init]; @@ -70,8 +68,8 @@ - (OFString *)description { return [OFString stringWithFormat: @"Seeking failed in stream of type %@: %@", - _stream.class, of_strerror(_errNo)]; + _stream.class, OFStrError(_errNo)]; } @end Index: src/exceptions/OFSetItemAttributesFailedException.h ================================================================== --- src/exceptions/OFSetItemAttributesFailedException.h +++ src/exceptions/OFSetItemAttributesFailedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -30,12 +28,12 @@ * @brief An exception indicating an item's attributes could not be set. */ @interface OFSetItemAttributesFailedException: OFException { OFURL *_URL; - of_file_attributes_t _attributes; - of_file_attribute_key_t _failedAttribute; + OFFileAttributes _attributes; + OFFileAttributeKey _failedAttribute; int _errNo; } /** * @brief The URL of the item whose attributes could not be set. @@ -48,18 +46,16 @@ @property (readonly, nonatomic) int errNo; /** * @brief The attributes that should have been set. */ -@property (readonly, nonatomic) of_file_attributes_t attributes; +@property (readonly, nonatomic) OFFileAttributes attributes; /** * @brief The first attribute that could not be set. */ -@property (readonly, nonatomic) of_file_attribute_key_t failedAttribute; - -+ (instancetype)exception OF_UNAVAILABLE; +@property (readonly, nonatomic) OFFileAttributeKey failedAttribute; /** * @brief Creates a new, autoreleased set item attributes failed exception. * * @param URL The URL of the item whose attributes could not be set @@ -68,15 +64,15 @@ * @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)exceptionWithURL: (OFURL *)URL - attributes: (of_file_attributes_t)attributes - failedAttribute: (of_file_attribute_key_t)failedAttribute + attributes: (OFFileAttributes)attributes + failedAttribute: (OFFileAttributeKey)failedAttribute errNo: (int)errNo; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated set item attributes failed exception. * * @param URL The URL of the item whose attributes could not be set @@ -85,11 +81,13 @@ * @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)initWithURL: (OFURL *)URL - attributes: (of_file_attributes_t)attributes - failedAttribute: (of_file_attribute_key_t)failedAttribute + 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,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -29,12 +27,12 @@ { OF_UNRECOGNIZED_SELECTOR } + (instancetype)exceptionWithURL: (OFURL *)URL - attributes: (of_file_attributes_t)attributes - failedAttribute: (of_file_attribute_key_t)failedAttribute + attributes: (OFFileAttributes)attributes + failedAttribute: (OFFileAttributeKey)failedAttribute errNo: (int)errNo { return [[[self alloc] initWithURL: URL attributes: attributes failedAttribute: failedAttribute @@ -45,12 +43,12 @@ { OF_INVALID_INIT_METHOD } - (instancetype)initWithURL: (OFURL *)URL - attributes: (of_file_attributes_t)attributes - failedAttribute: (of_file_attribute_key_t)failedAttribute + attributes: (OFFileAttributes)attributes + failedAttribute: (OFFileAttributeKey)failedAttribute errNo: (int)errNo { self = [super init]; @try { @@ -77,8 +75,8 @@ - (OFString *)description { return [OFString stringWithFormat: @"Failed to set attribute %@ for item %@: %@", - _failedAttribute, _URL, of_strerror(_errNo)]; + _failedAttribute, _URL, OFStrError(_errNo)]; } @end Index: src/exceptions/OFSetOptionFailedException.h ================================================================== --- src/exceptions/OFSetOptionFailedException.h +++ src/exceptions/OFSetOptionFailedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -39,23 +37,20 @@ /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased set option failed exception. * * @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: (id)object errNo: (int)errNo; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated set option failed exception. * * @param object The object for which the option could not be set @@ -62,8 +57,10 @@ * @param errNo The errno of the error that occurred * @return An initialized set option failed exception */ - (instancetype)initWithObject: (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,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -26,24 +24,21 @@ + (instancetype)exception { OF_UNRECOGNIZED_SELECTOR } -+ (instancetype)exceptionWithObject: (id)object - errNo: (int)errNo ++ (instancetype)exceptionWithObject: (id)object errNo: (int)errNo { - return [[[self alloc] initWithObject: object - errNo: errNo] autorelease]; + return [[[self alloc] initWithObject: object errNo: errNo] autorelease]; } - (instancetype)init { OF_INVALID_INIT_METHOD } -- (instancetype)initWithObject: (id)object - errNo: (int)errNo +- (instancetype)initWithObject: (id)object errNo: (int)errNo { self = [super init]; _object = [object retain]; _errNo = errNo; @@ -60,8 +55,8 @@ - (OFString *)description { return [OFString stringWithFormat: @"Setting an option in an object of type %@ failed: %@", - [_object class], of_strerror(_errNo)]; + [_object class], OFStrError(_errNo)]; } @end Index: src/exceptions/OFSetWindowsRegistryValueFailedException.h ================================================================== --- src/exceptions/OFSetWindowsRegistryValueFailedException.h +++ src/exceptions/OFSetWindowsRegistryValueFailedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -30,11 +28,11 @@ * @brief An exception indicating that setting a Windows registry value failed. */ @interface OFSetWindowsRegistryValueFailedException: OFException { OFWindowsRegistryKey *_registryKey; - OFString *_Nullable _value; + OFString *_Nullable _valueName; OFData *_Nullable _data; DWORD _type; LSTATUS _status; } @@ -42,13 +40,13 @@ * @brief The registry key on which setting the value failed. */ @property (readonly, nonatomic) OFWindowsRegistryKey *registryKey; /** - * @brief The value which could not be set. + * @brief The name of the value which could not be set. */ -@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFString *value; +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFString *valueName; /** * @brief The data to which the value could not be set. */ @property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFData *data; @@ -66,18 +64,18 @@ /** * @brief Creates a new, autoreleased set Windows registry value failed * exception. * * @param registryKey The registry key on which setting the value failed - * @param value The value which could not be set + * @param valueName The name of the value which could not be set * @param data The data to which the value could not be set * @param type The type for the value that could not be set * @param status The status returned by RegSetValueEx() * @return A new, autoreleased set Windows registry value failed exception */ + (instancetype)exceptionWithRegistryKey: (OFWindowsRegistryKey *)registryKey - value: (nullable OFString *)value + valueName: (nullable OFString *)valueName data: (nullable OFData *)data type: (DWORD)type status: (LSTATUS)status; - (instancetype)init OF_UNAVAILABLE; @@ -85,19 +83,19 @@ /** * @brief Initializes an already allocated set Windows registry value failed * exception. * * @param registryKey The registry key on which setting the value failed - * @param value The value which could not be set + * @param valueName The name of the value which could not be set * @param data The data to which the value could not be set * @param type The type for the value that could not be set * @param status The status returned by RegSetValueEx() * @return An initialized set Windows registry value failed exception */ - (instancetype)initWithRegistryKey: (OFWindowsRegistryKey *)registryKey - value: (nullable OFString *)value + valueName: (nullable OFString *)valueName data: (nullable OFData *)data type: (DWORD)type status: (LSTATUS)status OF_DESIGNATED_INITIALIZER; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFSetWindowsRegistryValueFailedException.m ================================================================== --- src/exceptions/OFSetWindowsRegistryValueFailedException.m +++ src/exceptions/OFSetWindowsRegistryValueFailedException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -20,21 +18,21 @@ #import "OFSetWindowsRegistryValueFailedException.h" #import "OFData.h" @implementation OFSetWindowsRegistryValueFailedException -@synthesize registryKey = _registryKey, value = _value, data = _data; +@synthesize registryKey = _registryKey, valueName = _valueName, data = _data; @synthesize type = _type, status = _status; + (instancetype)exceptionWithRegistryKey: (OFWindowsRegistryKey *)registryKey - value: (OFString *)value + valueName: (OFString *)valueName data: (OFData *)data type: (DWORD)type status: (LSTATUS)status { return [[[self alloc] initWithRegistryKey: registryKey - value: value + valueName: valueName data: data type: type status: status] autorelease]; } @@ -42,20 +40,20 @@ { OF_INVALID_INIT_METHOD } - (instancetype)initWithRegistryKey: (OFWindowsRegistryKey *)registryKey - value: (OFString *)value + valueName: (OFString *)valueName data: (OFData *)data type: (DWORD)type status: (LSTATUS)status { self = [super init]; @try { _registryKey = [registryKey retain]; - _value = [value copy]; + _valueName = [valueName copy]; _data = [data copy]; _type = type; _status = status; } @catch (id e) { [self release]; @@ -66,18 +64,18 @@ } - (void)dealloc { [_registryKey release]; - [_value release]; + [_valueName release]; [_data release]; [super dealloc]; } - (OFString *)description { return [OFString stringWithFormat: - @"Failed to set value %@ of type %u: %@", - _value, _type, of_windows_status_to_string(_status)]; + @"Failed to set value named %@ of type %u: %@", + _valueName, _type, OFWindowsStatusToString(_status)]; } @end Index: src/exceptions/OFStillLockedException.h ================================================================== --- src/exceptions/OFStillLockedException.h +++ src/exceptions/OFStillLockedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -26,11 +24,11 @@ * * @brief An exception indicating that a lock is still locked. */ @interface OFStillLockedException: OFException { - id _lock; + id _Nullable _lock; } /** * @brief The lock which is still locked. */ Index: src/exceptions/OFStillLockedException.m ================================================================== --- src/exceptions/OFStillLockedException.m +++ src/exceptions/OFStillLockedException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 ADDED src/exceptions/OFTLSHandshakeFailedException.h Index: src/exceptions/OFTLSHandshakeFailedException.h ================================================================== --- /dev/null +++ src/exceptions/OFTLSHandshakeFailedException.h @@ -0,0 +1,92 @@ +/* + * 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 "OFTLSStream.h" + +OF_ASSUME_NONNULL_BEGIN + +#ifdef __cplusplus +extern "C" { +#endif +extern int _OFTLSHandshakeFailedException_reference; +#ifdef __cplusplus +} +#endif + +/** + * @class OFTLSHandshakeFailedException \ + * OFTLSHandshakeFailedException.h ObjFW/OFTLSHandshakeFailedException.h + * + * @brief An exception indicating that a TLS handshake. + */ +@interface OFTLSHandshakeFailedException: OFException +{ + OFTLSStream *_stream; + OFString *_Nullable _host; + OFTLSStreamErrorCode _errorCode; +} + +/** + * @brief The TLS stream which failed the handshake. + */ +@property (readonly, nonatomic) OFTLSStream *stream; + +/** + * @brief The host for the handshake. + */ +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFString *host; + +/** + * @brief The error code from the TLS stream. + */ +@property (readonly, nonatomic) OFTLSStreamErrorCode errorCode; + +/** + * @brief Creates a new, autoreleased TLS handshake failed exception. + * + * @param stream The TLS stream which failed the handshake + * @param host The host for the handshake + * @param errorCode The error code from the TLS stream + * @return A new, autoreleased TLS handshake failed exception + */ ++ (instancetype)exceptionWithStream: (OFTLSStream *)stream + host: (nullable OFString *)host + errorCode: (OFTLSStreamErrorCode)errorCode; + ++ (instancetype)exception OF_UNAVAILABLE; + +/** + * @brief Initializes an already allocated TLS handshake failed exception. + * + * @param stream The TLS stream which failed the handshake + * @param host The host for the handshake + * @param errorCode The error code from the TLS stream + * @return An initialized TLS handshake failed exception + */ +- (instancetype)initWithStream: (OFTLSStream *)stream + host: (nullable OFString *)host + errorCode: (OFTLSStreamErrorCode)errorCode + OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; +@end + +OF_ASSUME_NONNULL_END ADDED src/exceptions/OFTLSHandshakeFailedException.m Index: src/exceptions/OFTLSHandshakeFailedException.m ================================================================== --- /dev/null +++ src/exceptions/OFTLSHandshakeFailedException.m @@ -0,0 +1,83 @@ +/* + * 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 "OFTLSHandshakeFailedException.h" +#import "OFString.h" + +int _OFTLSHandshakeFailedException_reference; + +@implementation OFTLSHandshakeFailedException +@synthesize stream = _stream, host = _host, errorCode = _errorCode; + ++ (instancetype)exceptionWithStream: (OFTLSStream *)stream + host: (OFString *)host + errorCode: (OFTLSStreamErrorCode)errorCode +{ + return [[[self alloc] initWithStream: stream + host: host + errorCode: errorCode] autorelease]; +} + ++ (instancetype)exception +{ + OF_UNRECOGNIZED_SELECTOR +} + +- (instancetype)initWithStream: (OFTLSStream *)stream + host: (OFString *)host + errorCode: (OFTLSStreamErrorCode)errorCode +{ + self = [super init]; + + @try { + _stream = [stream retain]; + _host = [host copy]; + _errorCode = errorCode; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} + +- (void)dealloc +{ + [_stream release]; + [_host release]; + + [super dealloc]; +} + +- (OFString *)description +{ + if (_host != nil) + return [OFString stringWithFormat: + @"TLS handshake in class %@ with host %@ failed: %@", + _stream.class, _host, + OFTLSStreamErrorCodeDescription(_errorCode)]; + else + return [OFString stringWithFormat: + @"TLS handshake in class %@ failed: %@", + _stream.class, OFTLSStreamErrorCodeDescription(_errorCode)]; +} +@end Index: src/exceptions/OFThreadJoinFailedException.h ================================================================== --- src/exceptions/OFThreadJoinFailedException.h +++ src/exceptions/OFThreadJoinFailedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -31,11 +29,11 @@ * * @brief An exception indicating that joining a thread failed. */ @interface OFThreadJoinFailedException: OFException { - OFThread *_thread; + OFThread *_Nullable _thread; int _errNo; } /** * @brief The thread which could not be joined. @@ -54,10 +52,12 @@ * @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 Index: src/exceptions/OFThreadJoinFailedException.m ================================================================== --- src/exceptions/OFThreadJoinFailedException.m +++ src/exceptions/OFThreadJoinFailedException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -24,19 +22,21 @@ #import "OFThread.h" @implementation OFThreadJoinFailedException @synthesize thread = _thread, errNo = _errNo; -+ (instancetype)exceptionWithThread: (OFThread *)thread - errNo: (int)errNo ++ (instancetype)exceptionWithThread: (OFThread *)thread errNo: (int)errNo +{ + return [[[self alloc] initWithThread: thread errNo: errNo] autorelease]; +} + ++ (instancetype)exception { - return [[[self alloc] initWithThread: thread - errNo: errNo] autorelease]; + OF_UNRECOGNIZED_SELECTOR } -- (instancetype)initWithThread: (OFThread *)thread - errNo: (int)errNo +- (instancetype)initWithThread: (OFThread *)thread errNo: (int)errNo { self = [super init]; _thread = [thread retain]; _errNo = errNo; Index: src/exceptions/OFThreadStartFailedException.h ================================================================== --- src/exceptions/OFThreadStartFailedException.h +++ src/exceptions/OFThreadStartFailedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -31,11 +29,11 @@ * * @brief An exception indicating that starting a thread failed. */ @interface OFThreadStartFailedException: OFException { - OFThread *_thread; + OFThread *_Nullable _thread; int _errNo; } /** * @brief The thread which could not be started. @@ -54,10 +52,12 @@ * @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 Index: src/exceptions/OFThreadStartFailedException.m ================================================================== --- src/exceptions/OFThreadStartFailedException.m +++ src/exceptions/OFThreadStartFailedException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -24,19 +22,21 @@ #import "OFThread.h" @implementation OFThreadStartFailedException @synthesize thread = _thread, errNo = _errNo; -+ (instancetype)exceptionWithThread: (OFThread *)thread - errNo: (int)errNo ++ (instancetype)exceptionWithThread: (OFThread *)thread errNo: (int)errNo +{ + return [[[self alloc] initWithThread: thread errNo: errNo] autorelease]; +} + ++ (instancetype)exception { - return [[[self alloc] initWithThread: thread - errNo: errNo] autorelease]; + OF_UNRECOGNIZED_SELECTOR } -- (instancetype)initWithThread: (OFThread *)thread - errNo: (int)errNo +- (instancetype)initWithThread: (OFThread *)thread errNo: (int)errNo { self = [super init]; _thread = [thread retain]; _errNo = errNo; Index: src/exceptions/OFThreadStillRunningException.h ================================================================== --- src/exceptions/OFThreadStillRunningException.h +++ src/exceptions/OFThreadStillRunningException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -31,11 +29,11 @@ * * @brief An exception indicating that a thread is still running. */ @interface OFThreadStillRunningException: OFException { - OFThread *_thread; + OFThread *_Nullable _thread; } /** * @brief The thread which is still running. */ Index: src/exceptions/OFThreadStillRunningException.m ================================================================== --- src/exceptions/OFThreadStillRunningException.m +++ src/exceptions/OFThreadStillRunningException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/exceptions/OFTruncatedDataException.h ================================================================== --- src/exceptions/OFTruncatedDataException.h +++ src/exceptions/OFTruncatedDataException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/exceptions/OFTruncatedDataException.m ================================================================== --- src/exceptions/OFTruncatedDataException.m +++ src/exceptions/OFTruncatedDataException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/exceptions/OFUnboundNamespaceException.h ================================================================== --- src/exceptions/OFUnboundNamespaceException.h +++ src/exceptions/OFUnboundNamespaceException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -37,40 +35,40 @@ * @brief The unbound namespace. */ #ifndef __cplusplus @property (readonly, nonatomic) OFString *namespace; #else -@property (readonly, nonatomic, getter=namespace) OFString *namespace_; +@property (readonly, nonatomic, getter=namespace) OFString *nameSpace; #endif /** * @brief The element in which the namespace was not bound. */ @property (readonly, nonatomic) OFXMLElement *element; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased unbound namespace exception. * - * @param namespace_ The namespace which is unbound + * @param nameSpace The namespace which is unbound * @param element The element in which the namespace was not bound * @return A new, autoreleased unbound namespace exception */ -+ (instancetype)exceptionWithNamespace: (OFString *)namespace_ ++ (instancetype)exceptionWithNamespace: (OFString *)nameSpace element: (OFXMLElement *)element; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated unbound namespace exception. * - * @param namespace_ The namespace which is unbound + * @param nameSpace The namespace which is unbound * @param element The element in which the namespace was not bound * @return An initialized unbound namespace exception */ -- (instancetype)initWithNamespace: (OFString *)namespace_ +- (instancetype)initWithNamespace: (OFString *)nameSpace element: (OFXMLElement *)element OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFUnboundNamespaceException.m ================================================================== --- src/exceptions/OFUnboundNamespaceException.m +++ src/exceptions/OFUnboundNamespaceException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/exceptions/OFUnboundPrefixException.h ================================================================== --- src/exceptions/OFUnboundPrefixException.h +++ src/exceptions/OFUnboundPrefixException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -41,12 +39,10 @@ /** * @brief The parser which encountered the unbound prefix. */ @property (readonly, nonatomic) OFXMLParser *parser; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased unbound prefix exception. * * @param prefix The prefix which is unbound * @param parser The parser which encountered the unbound prefix @@ -53,11 +49,11 @@ * @return A new, autoreleased unbound prefix exception */ + (instancetype)exceptionWithPrefix: (OFString *)prefix parser: (OFXMLParser *)parser; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated unbound prefix exception. * * @param prefix The prefix which is unbound @@ -64,8 +60,10 @@ * @param parser The parser which encountered the unbound prefix * @return An initialized unbound prefix exception */ - (instancetype)initWithPrefix: (OFString *)prefix parser: (OFXMLParser *)parser OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFUnboundPrefixException.m ================================================================== --- src/exceptions/OFUnboundPrefixException.m +++ src/exceptions/OFUnboundPrefixException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -39,12 +37,11 @@ - (instancetype)init { OF_INVALID_INIT_METHOD } -- (instancetype)initWithPrefix: (OFString *)prefix - parser: (OFXMLParser *)parser +- (instancetype)initWithPrefix: (OFString *)prefix parser: (OFXMLParser *)parser { self = [super init]; @try { _prefix = [prefix copy]; Index: src/exceptions/OFUndefinedKeyException.h ================================================================== --- src/exceptions/OFUndefinedKeyException.h +++ src/exceptions/OFUndefinedKeyException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -27,11 +25,11 @@ * Coding). */ @interface OFUndefinedKeyException: OFException { id _object; - OFString *_key; + OFString *_Nullable _key; id _Nullable _value; } /** * @brief The object on which the key is undefined. @@ -39,29 +37,26 @@ @property (readonly, nonatomic) id object; /** * @brief The key which is undefined. */ -@property (readonly, nonatomic) OFString *key; +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFString *key; /** * @brief The value for the undefined key */ @property OF_NULLABLE_PROPERTY (readonly, nonatomic) id value; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased undefined key exception. * * @param object The object on which the key is undefined * @param key The key which is undefined * * @return A new, autoreleased undefined key exception */ -+ (instancetype)exceptionWithObject: (id)object - key: (OFString *)key; ++ (instancetype)exceptionWithObject: (id)object key: (OFString *)key; /** * @brief Creates a new, autoreleased undefined key exception. * * @param object The object on which the key is undefined @@ -69,25 +64,24 @@ * @param value The value for the undefined key * * @return A new, autoreleased undefined key exception */ + (instancetype)exceptionWithObject: (id)object - key: (OFString *)key + key: (nullable OFString *)key value: (nullable id)value; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated undefined key exception. * * @param object The object on which the key is undefined * @param key The key which is undefined * * @return An initialized undefined key exception */ -- (instancetype)initWithObject: (id)object - key: (OFString *)key; +- (instancetype)initWithObject: (id)object key: (OFString *)key; /** * @brief Initializes an already allocated undefined key exception. * * @param object The object on which the key is undefined @@ -95,10 +89,12 @@ * @param value The value for the undefined key * * @return An initialized undefined key exception */ - (instancetype)initWithObject: (id)object - key: (OFString *)key + key: (nullable OFString *)key value: (nullable id)value OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFUndefinedKeyException.m ================================================================== --- src/exceptions/OFUndefinedKeyException.m +++ src/exceptions/OFUndefinedKeyException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -26,15 +24,13 @@ + (instancetype)exception { OF_UNRECOGNIZED_SELECTOR } -+ (instancetype)exceptionWithObject: (id)object - key: (OFString *)key ++ (instancetype)exceptionWithObject: (id)object key: (OFString *)key { - return [[[self alloc] initWithObject: object - key: key] autorelease]; + return [[[self alloc] initWithObject: object key: key] autorelease]; } + (instancetype)exceptionWithObject: (id)object key: (OFString *)key value: (id)value @@ -47,21 +43,16 @@ - (instancetype)init { OF_INVALID_INIT_METHOD } -- (instancetype)initWithObject: (id)object - key: (OFString *)key +- (instancetype)initWithObject: (id)object key: (OFString *)key { - return [self initWithObject: object - key: key - value: nil]; + return [self initWithObject: object key: key value: nil]; } -- (instancetype)initWithObject: (id)object - key: (OFString *)key - value: (id)value +- (instancetype)initWithObject: (id)object key: (OFString *)key value: (id)value { self = [super init]; @try { _object = [object retain]; Index: src/exceptions/OFUnknownXMLEntityException.h ================================================================== --- src/exceptions/OFUnknownXMLEntityException.h +++ src/exceptions/OFUnknownXMLEntityException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -42,18 +40,20 @@ * @param entityName The name of the unknown XML entity * @return A new, autoreleased unknown XML entity exception */ + (instancetype)exceptionWithEntityName: (OFString *)entityName; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated unknown XML entity exception. * * @param entityName The name of the unknown XML entity * @return An initialized unknown XML entity exception */ - (instancetype)initWithEntityName: (OFString *)entityName OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFUnknownXMLEntityException.m ================================================================== --- src/exceptions/OFUnknownXMLEntityException.m +++ src/exceptions/OFUnknownXMLEntityException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -26,13 +24,13 @@ + (instancetype)exceptionWithEntityName: (OFString *)entityName { return [[[self alloc] initWithEntityName: entityName] autorelease]; } -- (instancetype)init ++ (instancetype)exception { - OF_INVALID_INIT_METHOD + OF_UNRECOGNIZED_SELECTOR } - (instancetype)initWithEntityName: (OFString *)entityName { self = [super init]; @@ -44,10 +42,15 @@ @throw e; } return self; } + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} - (void)dealloc { [_entityName release]; Index: src/exceptions/OFUnlockFailedException.h ================================================================== --- src/exceptions/OFUnlockFailedException.h +++ src/exceptions/OFUnlockFailedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -26,11 +24,11 @@ * * @brief An exception indicating that unlocking a lock failed. */ @interface OFUnlockFailedException: OFException { - id _lock; + id _Nullable _lock; int _errNo; } /** * @brief The lock which could not be unlocked. @@ -59,10 +57,8 @@ * @param errNo The errno of the error that occurred * @return An initialized unlock failed exception */ - (instancetype)initWithLock: (nullable id )lock errNo: (int)errNo OF_DESIGNATED_INITIALIZER; - -- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFUnlockFailedException.m ================================================================== --- src/exceptions/OFUnlockFailedException.m +++ src/exceptions/OFUnlockFailedException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -23,42 +21,37 @@ #import "OFString.h" @implementation OFUnlockFailedException @synthesize lock = _lock, errNo = _errNo; -+ (instancetype)exceptionWithLock: (id )lock - errNo: (int)errNo ++ (instancetype)exceptionWithLock: (id )lock errNo: (int)errNo { - return [[[self alloc] initWithLock: lock - errNo: errNo] autorelease]; + return [[[self alloc] initWithLock: lock errNo: errNo] autorelease]; } -- (instancetype)initWithLock: (id )lock - errNo: (int)errNo +- (instancetype)initWithLock: (id )lock errNo: (int)errNo { self = [super init]; _lock = [lock retain]; _errNo = errNo; return self; } -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - - (void)dealloc { [_lock release]; [super dealloc]; } - (OFString *)description { - return [OFString stringWithFormat: - @"A lock of type %@ could not be unlocked: %s", - [_lock class], strerror(_errNo)]; + if (_lock != nil) + return [OFString stringWithFormat: + @"A lock of type %@ could not be unlocked: %s", + [_lock class], strerror(_errNo)]; + else + return @"A lock could not be unlocked!"; } @end Index: src/exceptions/OFUnsupportedProtocolException.h ================================================================== --- src/exceptions/OFUnsupportedProtocolException.h +++ src/exceptions/OFUnsupportedProtocolException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -29,31 +27,31 @@ * @brief An exception indicating that the protocol specified by the URL is not * supported. */ @interface OFUnsupportedProtocolException: OFException { - OFURL *_URL; + OFURL *_Nullable _URL; } /** * @brief The URL whose protocol is unsupported. */ -@property (readonly, nonatomic) OFURL *URL; +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFURL *URL; /** * @brief Creates a new, autoreleased unsupported protocol exception. * * @param URL The URL whose protocol is unsupported * @return A new, autoreleased unsupported protocol exception */ -+ (instancetype)exceptionWithURL: (OFURL*)URL; ++ (instancetype)exceptionWithURL: (nullable OFURL*)URL; /** * @brief Initializes an already allocated unsupported protocol exception * * @param URL The URL whose protocol is unsupported * @return An initialized unsupported protocol exception */ -- (instancetype)initWithURL: (OFURL*)URL OF_DESIGNATED_INITIALIZER; +- (instancetype)initWithURL: (nullable OFURL*)URL OF_DESIGNATED_INITIALIZER; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFUnsupportedProtocolException.m ================================================================== --- src/exceptions/OFUnsupportedProtocolException.m +++ src/exceptions/OFUnsupportedProtocolException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/exceptions/OFUnsupportedVersionException.h ================================================================== --- src/exceptions/OFUnsupportedVersionException.h +++ src/exceptions/OFUnsupportedVersionException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -34,27 +32,27 @@ /** * @brief The version which is unsupported. */ @property (readonly, nonatomic) OFString *version; -+ (instancetype)exception OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased unsupported version exception. * * @param version The version which is unsupported * @return A new, autoreleased unsupported version exception */ + (instancetype)exceptionWithVersion: (OFString *)version; -- (instancetype)init OF_UNAVAILABLE; ++ (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated unsupported protocol exception. * * @param version The version which is unsupported * @return An initialized unsupported version exception */ - (instancetype)initWithVersion: (OFString *)version OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFUnsupportedVersionException.m ================================================================== --- src/exceptions/OFUnsupportedVersionException.m +++ src/exceptions/OFUnsupportedVersionException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/exceptions/OFWriteFailedException.h ================================================================== --- src/exceptions/OFWriteFailedException.h +++ src/exceptions/OFWriteFailedException.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -36,14 +34,10 @@ * This can be used to make sure that a retry does not write data already * written before. */ @property (readonly, nonatomic) size_t bytesWritten; -+ (instancetype)exceptionWithObject: (id)object - requestedLength: (size_t)requestedLength - errNo: (int)errNo OF_UNAVAILABLE; - /** * @brief Creates a new, autoreleased write failed exception. * * @param object The object from which reading or to which writing failed * @param requestedLength The requested length of the data that could not be @@ -56,13 +50,13 @@ + (instancetype)exceptionWithObject: (id)object requestedLength: (size_t)requestedLength bytesWritten: (size_t)bytesWritten errNo: (int)errNo; -- (instancetype)initWithObject: (id)object - requestedLength: (size_t)requestedLength - errNo: (int)errNo OF_UNAVAILABLE; ++ (instancetype)exceptionWithObject: (id)object + requestedLength: (size_t)requestedLength + errNo: (int)errNo OF_UNAVAILABLE; /** * @brief Initializes an already allocated write failed exception. * * @param object The object from which reading or to which writing failed @@ -75,8 +69,12 @@ */ - (instancetype)initWithObject: (id)object requestedLength: (size_t)requestedLength bytesWritten: (size_t)bytesWritten errNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)initWithObject: (id)object + requestedLength: (size_t)requestedLength + errNo: (int)errNo OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFWriteFailedException.m ================================================================== --- src/exceptions/OFWriteFailedException.m +++ src/exceptions/OFWriteFailedException.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -64,12 +62,18 @@ return self; } - (OFString *)description { - return [OFString stringWithFormat: - @"Failed to write %zu bytes (after %zu bytes written) to an " - @"object of type %@: %@", - _requestedLength, _bytesWritten, [_object class], - of_strerror(_errNo)]; + if (_errNo != 0) + return [OFString stringWithFormat: + @"Failed to write %zu bytes (after %zu bytes written) to " + @"an object of type %@: %@", + _requestedLength, _bytesWritten, [_object class], + OFStrError(_errNo)]; + else + return [OFString stringWithFormat: + @"Failed to write %zu bytes (after %zu bytes written) to " + @"an object of type %@", + _requestedLength, _bytesWritten, [_object class]]; } @end Index: src/forwarding/apple-forwarding-arm.S ================================================================== --- src/forwarding/apple-forwarding-arm.S +++ src/forwarding/apple-forwarding-arm.S @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -15,12 +13,12 @@ * file. */ #include "config.h" -.globl _of_forward -.globl _of_forward_stret +.globl _OFForward +.globl _OFForward_stret .section __TEXT, __objc_methname, cstring_literals str_forwardingTargetForSelector_: .asciz "forwardingTargetForSelector:" @@ -32,11 +30,11 @@ .long 0, 0 .section __TEXT, __text, regular, pure_instructions .arm .align 2 -_of_forward: +_OFForward: stmfd sp!, {r0-r4, lr} vstmdb sp!, {d0-d7} ldr r4, sel_forwardingTargetForSelector_$indirect_L0 L0: @@ -68,19 +66,19 @@ b _objc_msgSend 0: vldmia sp!, {d0-d7} ldmfd sp!, {r0-r4, lr} - b _of_method_not_found + b _OFMethodNotFound .data_region sel_forwardingTargetForSelector_$indirect_L0: .long sel_forwardingTargetForSelector_-(L0+8) .end_data_region .align 2 -_of_forward_stret: +_OFForward_stret: stmfd sp!, {r0-r4, lr} vstmdb sp!, {d0-d7} ldr r4, sel_forwardingTargetForSelector_$indirect_L1 L1: @@ -116,11 +114,11 @@ b _objc_msgSend_stret 0: vldmia sp!, {d0-d7} ldmfd sp!, {r0-r4, lr} - b _of_method_not_found_stret + b _OFMethodNotFound_stret .data_region sel_forwardingTargetForSelector_$indirect_L1: .long sel_forwardingTargetForSelector_-(L1+8) .end_data_region Index: src/forwarding/apple-forwarding-arm64.S ================================================================== --- src/forwarding/apple-forwarding-arm64.S +++ src/forwarding/apple-forwarding-arm64.S @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -15,12 +13,12 @@ * file. */ #include "config.h" -.globl _of_forward -.globl _of_forward_stret +.globl _OFForward +.globl _OFForward_stret .section __TEXT, __objc_methname, cstring_literals str_forwardingTargetForSelector_: .asciz "forwardingTargetForSelector:" @@ -31,12 +29,12 @@ .section __DATA, __objc_imageinfo, regular, no_dead_strip .long 0, 0 .section __TEXT, __text, regular, pure_instructions .align 2 -_of_forward: -_of_forward_stret: +_OFForward: +_OFForward_stret: stp fp, lr, [sp, #-208]! mov fp, sp sub sp, sp, #208 /* Save all arguments, x8 and x19 */ @@ -95,6 +93,6 @@ ldr x19, [sp, #72] mov sp, fp ldp fp, lr, [sp], #208 - b _of_method_not_found + b _OFMethodNotFound Index: src/forwarding/apple-forwarding-i386.S ================================================================== --- src/forwarding/apple-forwarding-i386.S +++ src/forwarding/apple-forwarding-i386.S @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -15,133 +13,123 @@ * file. */ #include "config.h" -.intel_syntax noprefix - -.globl _of_forward -.globl _of_forward_stret +.globl _OFForward +.globl _OFForward_stret .section __TEXT, __cstring, cstring_literals -Lstr_forwardingTargetForSelector_: +str_forwardingTargetForSelector_: .asciz "forwardingTargetForSelector:" .section __OBJC, __message_refs, literal_pointers, no_dead_strip -Lsel_forwardingTargetForSelector_: - .long Lstr_forwardingTargetForSelector_ +sel_forwardingTargetForSelector_: + .long str_forwardingTargetForSelector_ .section __OBJC, __image_info .long 0, 0 .section __TEXT, __text, regular, pure_instructions -_of_forward: - push ebp - mov ebp, esp - - push ebx - sub esp, 20 - - call get_eip -0: - - mov eax, [ebp+8] - mov [esp], eax - call _object_getClass - - mov [esp], eax - .att_syntax /* Next line is broken in Intel syntax */ - movl Lsel_forwardingTargetForSelector_-0b(%ebx), %eax - .intel_syntax noprefix - mov [esp+4], eax - call _class_respondsToSelector - - test eax, eax - jz 0f - - mov eax, [ebp+8] - mov [esp], eax - .att_syntax /* Next line is broken in Intel syntax */ - movl Lsel_forwardingTargetForSelector_-0b(%ebx), %eax - .intel_syntax noprefix - mov [esp+4], eax - mov eax, [ebp+12] - mov [esp+8], eax - call _objc_msgSend - - test eax, eax - jz 0f - cmp eax, [ebp+8] - je 0f - - mov [ebp+8], eax - - add esp, 20 - pop ebx - pop ebp - - jmp _objc_msgSend - -0: - add esp, 20 - pop ebx - pop ebp - - jmp _of_method_not_found - -_of_forward_stret: - push ebp - mov ebp, esp - - push ebx - sub esp, 20 - - call get_eip -0: - - mov eax, [ebp+12] - mov [esp], eax - call _object_getClass - - mov [esp], eax - .att_syntax /* Next line is broken in Intel syntax */ - movl Lsel_forwardingTargetForSelector_-0b(%ebx), %eax - .intel_syntax noprefix - mov [esp+4], eax - call _class_respondsToSelector - - test eax, eax - jz 0f - - mov eax, [ebp+12] - mov [esp], eax - .att_syntax /* Next line is broken in Intel syntax */ - movl Lsel_forwardingTargetForSelector_-0b(%ebx), %eax - .intel_syntax noprefix - mov [esp+4], eax - mov eax, [ebp+16] - mov [esp+8], eax - call _objc_msgSend - - test eax, eax - jz 0f - cmp eax, [ebp+12] - je 0f - - mov [ebp+12], eax - - add esp, 20 - pop ebx - pop ebp - - jmp _objc_msgSend_stret - -0: - add esp, 20 - pop ebx - pop ebp - - jmp _of_method_not_found_stret - -get_eip: - mov ebx, [esp] +_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,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -15,12 +13,12 @@ * file. */ #include "config.h" -.globl _of_forward -.globl _of_forward_stret +.globl _OFForward +.globl _OFForward_stret .section __TEXT, __cstring, cstring_literals str_forwardingTargetForSelector_: .asciz "forwardingTargetForSelector:" @@ -30,11 +28,11 @@ .section __OBJC, __image_info .long 0, 0 .section __TEXT, __text, regular, pure_instructions -_of_forward: +_OFForward: mflr r0 stw r0, 8(r1) stwu r1, -192(r1) /* @@ -130,13 +128,13 @@ addi r1, r1, 192 lwz r0, 8(r1) mtlr r0 - b _of_method_not_found + b _OFMethodNotFound -_of_forward_stret: +_OFForward_stret: mflr r0 stw r0, 8(r1) stwu r1, -184(r1) /* @@ -236,6 +234,6 @@ addi r1, r1, 184 lwz r0, 8(r1) mtlr r0 - b _of_method_not_found_stret + b _OFMethodNotFound_stret Index: src/forwarding/apple-forwarding-x86_64.S ================================================================== --- src/forwarding/apple-forwarding-x86_64.S +++ src/forwarding/apple-forwarding-x86_64.S @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -15,14 +13,12 @@ * file. */ #include "config.h" -.intel_syntax noprefix - -.globl _of_forward -.globl _of_forward_stret +.globl _OFForward +.globl _OFForward_stret .section __TEXT, __objc_methname, cstring_literals str_forwardingTargetForSelector_: .asciz "forwardingTargetForSelector:" @@ -32,151 +28,151 @@ .section __DATA, __objc_imageinfo, regular, no_dead_strip .long 0, 0 .section __TEXT, __text, regular, pure_instructions -_of_forward: - push rbp - mov rbp, rsp +_OFForward: + pushq %rbp + movq %rsp, %rbp /* Save all arguments */ - sub rsp, 0xC0 /* 16-byte alignment */ - mov [rbp-0x08], rax - mov [rbp-0x10], rdi - mov [rbp-0x18], rsi - mov [rbp-0x20], rdx - mov [rbp-0x28], rcx - mov [rbp-0x30], r8 - mov [rbp-0x38], r9 - movaps [rbp-0x50], xmm0 - movaps [rbp-0x60], xmm1 - movaps [rbp-0x70], xmm2 - movaps [rbp-0x80], xmm3 - movaps [rbp-0x90], xmm4 - movaps [rbp-0xA0], xmm5 - movaps [rbp-0xB0], xmm6 - movaps [rbp-0xC0], xmm7 + 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 - mov rdi, rax - mov rsi, [rip+sel_forwardingTargetForSelector_] + movq %rax, %rdi + movq sel_forwardingTargetForSelector_(%rip), %rsi call _class_respondsToSelector - test rax, rax + testq %rax, %rax jz 0f - mov rdi, [rbp-0x10] - mov rsi, [rip+sel_forwardingTargetForSelector_] - mov rdx, [rbp-0x18] + movq -0x10(%rbp), %rdi + movq sel_forwardingTargetForSelector_(%rip), %rsi + movq -0x18(%rbp), %rdx call _objc_msgSend - test rax, rax + testq %rax, %rax jz 0f - cmp rax, [rbp-0x10] + cmpq -0x10(%rbp), %rax je 0f - mov rdi, rax + movq %rax, %rdi /* Restore all arguments, except %rdi */ - movaps xmm7, [rbp-0xC0] - movaps xmm6, [rbp-0xB0] - movaps xmm5, [rbp-0xA0] - movaps xmm4, [rbp-0x90] - movaps xmm3, [rbp-0x80] - movaps xmm2, [rbp-0x70] - movaps xmm1, [rbp-0x60] - movaps xmm0, [rbp-0x50] - mov r9, [rbp-0x38] - mov r8, [rbp-0x30] - mov rcx, [rbp-0x28] - mov rdx, [rbp-0x20] - mov rsi, [rbp-0x18] - mov rax, [rbp-0x08] - - mov rsp, rbp - pop rbp + 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: - mov rdi, [rbp-0x10] - mov rsi, [rbp-0x18] - - mov rsp, rbp - pop rbp - - jmp _of_method_not_found - -_of_forward_stret: - push rbp - mov rbp, rsp + 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 */ - sub rsp, 0xC0 /* 16-byte alignment */ - mov [rbp-0x08], rax - mov [rbp-0x10], rdi - mov [rbp-0x18], rsi - mov [rbp-0x20], rdx - mov [rbp-0x28], rcx - mov [rbp-0x30], r8 - mov [rbp-0x38], r9 - movaps [rbp-0x50], xmm0 - movaps [rbp-0x60], xmm1 - movaps [rbp-0x70], xmm2 - movaps [rbp-0x80], xmm3 - movaps [rbp-0x90], xmm4 - movaps [rbp-0xA0], xmm5 - movaps [rbp-0xB0], xmm6 - movaps [rbp-0xC0], xmm7 - - mov rdi, rsi + 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 - mov rdi, rax - mov rsi, [rip+sel_forwardingTargetForSelector_] + movq %rax, %rdi + movq sel_forwardingTargetForSelector_(%rip), %rsi call _class_respondsToSelector - test rax, rax + testq %rax, %rax jz 0f - mov rdi, [rbp-0x18] - mov rsi, [rip+sel_forwardingTargetForSelector_] - mov rdx, [rbp-0x20] + movq -0x18(%rbp), %rdi + movq sel_forwardingTargetForSelector_(%rip), %rsi + movq -0x20(%rbp), %rdx call _objc_msgSend - test rax, rax + testq %rax, %rax jz 0f - cmp rax, [rbp-0x18] + cmpq -0x18(%rbp), %rax je 0f - mov rsi, rax + movq %rax, %rsi /* Restore all arguments, except %rsi */ - movaps xmm7, [rbp-0xC0] - movaps xmm6, [rbp-0xB0] - movaps xmm5, [rbp-0xA0] - movaps xmm4, [rbp-0x90] - movaps xmm3, [rbp-0x80] - movaps xmm2, [rbp-0x70] - movaps xmm1, [rbp-0x60] - movaps xmm0, [rbp-0x50] - mov r9, [rbp-0x38] - mov r8, [rbp-0x30] - mov rcx, [rbp-0x28] - mov rdx, [rbp-0x20] - mov rdi, [rbp-0x10] - mov rax, [rbp-0x08] - - mov rsp, rbp - pop rbp + 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: - mov rdi, [rbp-0x10] - mov rsi, [rbp-0x18] - mov rdx, [rbp-0x20] - - mov rsp, rbp - pop rbp - - jmp _of_method_not_found_stret + movq -0x10(%rbp), %rdi + movq -0x18(%rbp), %rsi + movq -0x20(%rbp), %rdx + + movq %rbp, %rsp + popq %rbp + + jmp _OFMethodNotFound_stret Index: src/forwarding/forwarding-arm-elf.S ================================================================== --- src/forwarding/forwarding-arm-elf.S +++ src/forwarding/forwarding-arm-elf.S @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -21,15 +19,15 @@ #ifdef HAVE_VFP2 .fpu vfp #endif -.globl of_forward -.globl of_forward_stret +.globl OFForward +.globl OFForward_stret .section .text -of_forward: +OFForward: #ifdef HAVE_VFP2 vstmdb sp!, {d0-d7} #endif stmfd sp!, {r0-r4, lr} @@ -76,15 +74,15 @@ 0: ldmfd sp!, {r0-r4, lr} #ifdef HAVE_VFP2 vldmia sp!, {d0-d7} #endif - b of_method_not_found(PLT) -.type of_forward, %function -.size of_forward, .-of_forward + b OFMethodNotFound(PLT) +.type OFForward, %function +.size OFForward, .-OFForward -of_forward_stret: +OFForward_stret: #ifdef HAVE_VFP2 vstmdb sp!, {d0-d7} #endif stmfd sp!, {r0-r4, lr} @@ -132,13 +130,13 @@ 0: ldmfd sp!, {r0-r4, lr} #ifdef HAVE_VFP2 vldmia sp!, {d0-d7} #endif - b of_method_not_found_stret(PLT) -.type of_forward_stret, %function -.size of_forward_stret, .-of_forward_stret + b OFMethodNotFound_stret(PLT) +.type OFForward_stret, %function +.size OFForward_stret, .-OFForward_stret init: ldr r0, module$indirect_.L2 .L2: add r0, pc Index: src/forwarding/forwarding-arm64-elf.S ================================================================== --- src/forwarding/forwarding-arm64-elf.S +++ src/forwarding/forwarding-arm64-elf.S @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -17,16 +15,16 @@ #include "config.h" #include "platform.h" -.globl of_forward -.globl of_forward_stret +.globl OFForward +.globl OFForward_stret .section .text -of_forward: -of_forward_stret: +OFForward: +OFForward_stret: stp fp, lr, [sp, #-208]! mov fp, sp sub sp, sp, #208 /* Save all arguments, x8 and x19 */ @@ -96,15 +94,15 @@ ldr x19, [sp, #72] mov sp, fp ldp fp, lr, [sp], #208 - b of_method_not_found -.type of_forward, %function -.size of_forward, .-of_forward -.type of_forward_stret, %function -.size of_forward_stret, .-of_forward_stret + b OFMethodNotFound +.type OFForward, %function +.size OFForward, .-OFForward +.type OFForward_stret, %function +.size OFForward_stret, .-OFForward_stret init: adrp x0, module add x0, x0, :lo12:module b __objc_exec_class Index: src/forwarding/forwarding-mips-elf.S ================================================================== --- src/forwarding/forwarding-mips-elf.S +++ src/forwarding/forwarding-mips-elf.S @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -17,12 +15,12 @@ #include "config.h" #include "platform.h" -.globl of_forward -.globl of_forward_stret +.globl OFForward +.globl OFForward_stret #ifdef OF_PIC .macro j_pic symbol lw $t9, %call16(\symbol)($gp) jr $t9 @@ -39,11 +37,11 @@ jal \symbol .endm #endif .section .text -of_forward: +OFForward: #ifdef OF_PIC lui $gp, %hi(_gp_disp) addiu $gp, $gp, %lo(_gp_disp) addu $gp, $gp, $t9 #endif @@ -160,14 +158,14 @@ lw $ra, 16($sp) addiu $sp, $sp, 96 j_pic of_method_not_found -.type of_forward, %function -.size of_forward, .-of_forward +.type OFForward, %function +.size OFForward, .-OFForward -of_forward_stret: +OFForward_stret: #ifdef OF_PIC lui $gp, %hi(_gp_disp) addiu $gp, $gp, %lo(_gp_disp) addu $gp, $gp, $t9 #endif @@ -286,12 +284,12 @@ lw $ra, 16($sp) addiu $sp, $sp, 96 j_pic of_method_not_found_stret -.type of_forward_stret, %function -.size of_forward_stret, .-of_forward_stret +.type OFForward_stret, %function +.size OFForward_stret, .-OFForward_stret init: #ifdef OF_PIC lui $gp, %hi(_gp_disp) addiu $gp, $gp, %lo(_gp_disp) Index: src/forwarding/forwarding-powerpc-elf.S ================================================================== --- src/forwarding/forwarding-powerpc-elf.S +++ src/forwarding/forwarding-powerpc-elf.S @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -17,25 +15,27 @@ #include "config.h" #include "platform.h" -.globl of_forward -.globl of_forward_stret +.globl OFForward +.globl OFForward_stret .section .text -of_forward: +OFForward: stwu %r1, -112(%r1) mflr %r0 stw %r0, 116(%r1) +#ifdef OF_PIC stw %r30, 104(%r1) bl 0f 0: mflr %r30 addis %r30, %r30, .Lbiased_got2-0b@ha addi %r30, %r30, .Lbiased_got2-0b@l +#endif /* Save all arguments */ stw %r3, 8(%r1) stw %r4, 12(%r1) stw %r5, 16(%r1) @@ -53,25 +53,44 @@ stfd %f5, 72(%r1) stfd %f6, 80(%r1) stfd %f7, 88(%r1) stfd %f8, 96(%r1) +#ifdef OF_PIC bl object_getClass+0x8000@plt lwz %r4, .Lgot_sel_forwardingTargetForSelector_-.Lbiased_got2(%r30) bl class_respondsToSelector+0x8000@plt +#else + bl object_getClass + + lis %r4, sel_forwardingTargetForSelector_@ha + la %r4, sel_forwardingTargetForSelector_@l(%r4) + bl class_respondsToSelector +#endif cmpwi %r3, 0 beq- 0f lwz %r3, 8(%r1) +#ifdef OF_PIC lwz %r4, .Lgot_sel_forwardingTargetForSelector_-.Lbiased_got2(%r30) bl objc_msg_lookup+0x8000@plt +#else + lis %r4, sel_forwardingTargetForSelector_@ha + la %r4, sel_forwardingTargetForSelector_@l(%r4) + bl objc_msg_lookup +#endif mtctr %r3 lwz %r3, 8(%r1) +#ifdef OF_PIC lwz %r4, .Lgot_sel_forwardingTargetForSelector_-.Lbiased_got2(%r30) +#else + lis %r4, sel_forwardingTargetForSelector_@ha + la %r4, sel_forwardingTargetForSelector_@l(%r4) +#endif lwz %r5, 12(%r1) bctrl cmpwi %r3, 0 beq- 0f @@ -80,11 +99,15 @@ beq- 0f stw %r3, 8(%r1) lwz %r4, 12(%r1) +#ifdef OF_PIC bl objc_msg_lookup+0x8000@plt +#else + bl objc_msg_lookup +#endif mtctr %r3 /* Restore all arguments */ lwz %r3, 8(%r1) lwz %r4, 12(%r1) @@ -103,42 +126,53 @@ lfd %f5, 72(%r1) lfd %f6, 80(%r1) lfd %f7, 88(%r1) lfd %f8, 96(%r1) +#ifdef OF_PIC lwz %r30, 104(%r1) +#endif lwz %r0, 116(%r1) mtlr %r0 addi %r1, %r1, 112 bctr 0: lwz %r3, 8(%r1) lwz %r4, 12(%r1) - lwz %r0, .Lgot_of_method_not_found-.Lbiased_got2(%r30) - mtctr %r0 +#ifdef OF_PIC + lwz %r0, .Lgot_OFMethodNotFound-.Lbiased_got2(%r30) + mtctr %r0 lwz %r30, 104(%r1) +#endif + lwz %r0, 116(%r1) mtlr %r0 addi %r1, %r1, 112 +#ifdef OF_PIC bctr -.type of_forward, @function -.size of_forward, .-of_forward +#else + b OFMethodNotFound +#endif +.type OFForward, @function +.size OFForward, .-OFForward -of_forward_stret: +OFForward_stret: stwu %r1, -112(%r1) mflr %r0 stw %r0, 116(%r1) +#ifdef OF_PIC stw %r30, 104(%r1) bl 0f 0: mflr %r30 addis %r30, %r30, .Lbiased_got2-0b@ha addi %r30, %r30, .Lbiased_got2-0b@l +#endif /* Save all arguments */ stw %r3, 8(%r1) stw %r4, 12(%r1) stw %r5, 16(%r1) @@ -157,25 +191,44 @@ stfd %f6, 80(%r1) stfd %f7, 88(%r1) stfd %f8, 96(%r1) mr %r3, %r4 - bl object_getClass+0x800@plt +#ifdef OF_PIC + bl object_getClass+0x8000@plt lwz %r4, .Lgot_sel_forwardingTargetForSelector_-.Lbiased_got2(%r30) bl class_respondsToSelector+0x8000@plt +#else + bl object_getClass + + lis %r4, sel_forwardingTargetForSelector_@ha + la %r4, sel_forwardingTargetForSelector_@l(%r4) + bl class_respondsToSelector +#endif cmpwi %r3, 0 beq- 0f lwz %r3, 12(%r1) +#ifdef OF_PIC lwz %r4, .Lgot_sel_forwardingTargetForSelector_-.Lbiased_got2(%r30) bl objc_msg_lookup+0x8000@plt +#else + lis %r4, sel_forwardingTargetForSelector_@ha + la %r4, sel_forwardingTargetForSelector_@l(%r4) + bl objc_msg_lookup +#endif mtctr %r3 lwz %r3, 12(%r1) +#ifdef OF_PIC lwz %r4, .Lgot_sel_forwardingTargetForSelector_-.Lbiased_got2(%r30) +#else + lis %r4, sel_forwardingTargetForSelector_@ha + la %r4, sel_forwardingTargetForSelector_@l(%r4) +#endif lwz %r5, 16(%r1) bctrl cmpwi %r3, 0 beq- 0f @@ -184,11 +237,15 @@ beq- 0f stw %r3, 12(%r1) lwz %r4, 16(%r1) +#ifdef OF_PIC bl objc_msg_lookup_stret+0x8000@plt +#else + bl objc_msg_lookup_stret +#endif mtctr %r3 /* Restore all arguments */ lwz %r3, 8(%r1) lwz %r4, 12(%r1) @@ -207,35 +264,46 @@ lfd %f5, 72(%r1) lfd %f6, 80(%r1) lfd %f7, 88(%r1) lfd %f8, 96(%r1) +#ifdef OF_PIC + lwz %r30, 104(%r1) +#endif lwz %r0, 116(%r1) mtlr %r0 addi %r1, %r1, 112 bctr 0: lwz %r3, 8(%r1) lwz %r4, 12(%r1) lwz %r5, 16(%r1) - lwz %r0, .Lgot_of_method_not_found_stret-.Lbiased_got2(%r30) - mtctr %r0 +#ifdef OF_PIC + lwz %r0, .Lgot_OFMethodNotFound_stret-.Lbiased_got2(%r30) + mtctr %r0 lwz %r30, 104(%r1) +#endif + lwz %r0, 116(%r1) mtlr %r0 addi %r1, %r1, 112 +#ifdef OF_PIC bctr -.type of_forward_stret, @function -.size of_forward_stret, .-of_forward_stret +#else + b OFMethodNotFound_stret +#endif +.type OFForward_stret, @function +.size OFForward_stret, .-OFForward_stret init: stwu %r1, -16(%r1) mflr %r0 stw %r0, 20(%r1) +#ifdef OF_PIC stw %r30, 8(%r1) bl 0f 0: mflr %r30 @@ -244,10 +312,16 @@ lwz %r3, .Lgot_module-.Lbiased_got2(%r30) bl __objc_exec_class+0x8000@plt lwz %r30, 8(%r1) +#else + lis %r3, module@ha + la %r3, module@l(%r3) + bl __objc_exec_class +#endif + lwz %r0, 20(%r1) addi %r1, %r1, 16 mtlr %r0 blr @@ -268,19 +342,21 @@ .long 0 .long 0 module: .long 8, 16, 0, symtab +#ifdef OF_PIC .section .got2, "aw" .Lbiased_got2 = .+0x8000 .Lgot_module: .long module .Lgot_sel_forwardingTargetForSelector_: .long sel_forwardingTargetForSelector_ -.Lgot_of_method_not_found: - .long of_method_not_found -.Lgot_of_method_not_found_stret: - .long of_method_not_found_stret +.Lgot_OFMethodNotFound: + .long OFMethodNotFound +.Lgot_OFMethodNotFound_stret: + .long OFMethodNotFound_stret +#endif #ifdef OF_LINUX .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,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -17,15 +15,15 @@ #include "config.h" #include "platform.h" -.globl of_forward -.globl of_forward_stret +.globl OFForward +.globl OFForward_stret .section .text -of_forward: +OFForward: save %sp, -96, %sp #ifdef OF_PIC sethi %hi(_GLOBAL_OFFSET_TABLE_ - 4), %l7 call add_pc @@ -77,16 +75,16 @@ jmpl %o0, %g0 restore 0: - call of_method_not_found + call OFMethodNotFound restore -.type of_forward, %function -.size of_forward, .-of_forward +.type OFForward, %function +.size OFForward, .-OFForward -of_forward_stret: +OFForward_stret: save %sp, -96, %sp #ifdef OF_PIC sethi %hi(_GLOBAL_OFFSET_TABLE_ - 4), %l7 call add_pc @@ -138,14 +136,14 @@ jmpl %o0, %g0 restore 0: - call of_method_not_found_stret + call OFMethodNotFound_stret restore -.type of_forward_stret, %function -.size of_forward_stret, .-of_forward_stret +.type OFForward_stret, %function +.size OFForward_stret, .-OFForward_stret init: save %sp, -96, %sp #ifdef OF_PIC Index: src/forwarding/forwarding-sparc64-elf.S ================================================================== --- src/forwarding/forwarding-sparc64-elf.S +++ src/forwarding/forwarding-sparc64-elf.S @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -17,17 +15,17 @@ #include "config.h" #include "platform.h" -.globl of_forward -.globl of_forward_stret +.globl OFForward +.globl OFForward_stret #define BIAS 2047 .section .text -of_forward: +OFForward: save %sp, -304, %sp /* * Save all floating point registers as they can be used for parameter * passing. @@ -111,16 +109,16 @@ jmpl %o0, %g0 restore 0: - call of_method_not_found + call OFMethodNotFound restore -.type of_forward, %function -.size of_forward, .-of_forward +.type OFForward, %function +.size OFForward, .-OFForward -of_forward_stret: +OFForward_stret: save %sp, -304, %sp /* * Save all floating point registers as they can be used for parameter * passing. @@ -204,14 +202,14 @@ jmpl %o0, %g0 restore 0: - call of_method_not_found_stret + call OFMethodNotFound_stret restore -.type of_forward_stret, %function -.size of_forward_stret, .-of_forward_stret +.type OFForward_stret, %function +.size OFForward_stret, .-OFForward_stret init: save %sp, -176, %sp sethi %hi(_GLOBAL_OFFSET_TABLE_ - 4), %l7 Index: src/forwarding/forwarding-x86-elf.S ================================================================== --- src/forwarding/forwarding-x86-elf.S +++ src/forwarding/forwarding-x86-elf.S @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -17,165 +15,163 @@ #include "config.h" #include "platform.h" -.intel_syntax noprefix - -.globl of_forward -.globl of_forward_stret - -.section .text -of_forward: - push ebp - mov ebp, esp - - push ebx - sub esp, 20 - - call get_eip - add ebx, offset _GLOBAL_OFFSET_TABLE_ - - mov eax, [ebp+8] - mov [esp], eax - call object_getClass@PLT - - mov [esp], eax - lea eax, [ebx+sel_forwardingTargetForSelector_@GOTOFF] - mov [esp+4], eax - call class_respondsToSelector@PLT - - test eax, eax - jz short 0f - - mov eax, [ebp+8] - mov [esp], eax - lea eax, [ebx+sel_forwardingTargetForSelector_@GOTOFF] - mov [esp+4], eax - call objc_msg_lookup@PLT - - mov edx, [ebp+8] - mov [esp], edx - lea edx, [ebx+sel_forwardingTargetForSelector_@GOTOFF] - mov [esp+4], edx - mov edx, [ebp+12] - mov [esp+8], edx - call eax - - test eax, eax - jz short 0f - cmp eax, [ebp+8] - je short 0f - - mov [ebp+8], eax - mov [esp], eax - mov eax, [ebp+12] - mov [esp+4], eax - call objc_msg_lookup@PLT - - add esp, 20 - pop ebx - pop ebp - - jmp eax - -0: - lea eax, [ebx+of_method_not_found@GOTOFF] - - add esp, 20 - pop ebx - pop ebp - - jmp eax -.type of_forward, %function -.size of_forward, .-of_forward - -of_forward_stret: - push ebp - mov ebp, esp - - push ebx - sub esp, 20 - - call get_eip - add ebx, offset _GLOBAL_OFFSET_TABLE_ - - mov eax, [ebp+12] - mov [esp], eax - call object_getClass@PLT - - mov [esp], eax - lea eax, [ebx+sel_forwardingTargetForSelector_@GOTOFF] - mov [esp+4], eax - call class_respondsToSelector@PLT - - test eax, eax - jz short 0f - - mov eax, [ebp+12] - mov [esp], eax - lea eax, [ebx+sel_forwardingTargetForSelector_@GOTOFF] - mov [esp+4], eax - call objc_msg_lookup@PLT - - mov edx, [ebp+12] - mov [esp], edx - lea edx, [ebx+sel_forwardingTargetForSelector_@GOTOFF] - mov [esp+4], edx - mov edx, [ebp+16] - mov [esp+8], edx - call eax - - test eax, eax - jz short 0f - cmp eax, [ebp+12] - je short 0f - - mov [ebp+12], eax - mov [esp], eax - mov eax, [ebp+16] - mov [esp+4], eax - call objc_msg_lookup_stret@PLT - - add esp, 20 - pop ebx - pop ebp - - jmp eax - -0: - lea eax, [ebx+of_method_not_found_stret@GOTOFF] - - add esp, 20 - pop ebx - pop ebp - - jmp eax -.type of_forward_stret, %function -.size of_forward_stret, .-of_forward_stret - -init: - push ebp - mov ebp, esp - - push ebx - sub esp, 4 - - call get_eip - add ebx, offset _GLOBAL_OFFSET_TABLE_ - - lea eax, [ebx+module@GOTOFF] - mov [esp], eax - call __objc_exec_class@PLT - - add esp, 4 - pop ebx - pop ebp +.globl OFForward +.globl OFForward_stret + +.section .text +OFForward: + pushl %ebp + movl %esp, %ebp + + pushl %ebx + subl $20, %esp + + call get_eip + addl $_GLOBAL_OFFSET_TABLE_, %ebx + + movl 8(%ebp), %eax + movl %eax, (%esp) + call object_getClass@PLT + + movl %eax, (%esp) + leal sel_forwardingTargetForSelector_@GOTOFF(%ebx), %eax + movl %eax, 4(%esp) + call class_respondsToSelector@PLT + + testl %eax, %eax + jz 0f + + movl 8(%ebp), %eax + movl %eax, (%esp) + leal sel_forwardingTargetForSelector_@GOTOFF(%ebx), %eax + movl %eax, 4(%esp) + call objc_msg_lookup@PLT + + movl 8(%ebp), %edx + movl %edx, (%esp) + leal sel_forwardingTargetForSelector_@GOTOFF(%ebx), %edx + movl %edx, 4(%esp) + movl 12(%ebp), %edx + movl %edx, 8(%esp) + call *%eax + + testl %eax, %eax + jz 0f + cmpl 8(%ebp), %eax + je 0f + + movl %eax, 8(%ebp) + movl %eax, (%esp) + movl 12(%ebp), %eax + movl %eax, 4(%esp) + call objc_msg_lookup@PLT + + addl $20, %esp + popl %ebx + popl %ebp + + jmp *%eax + +0: + leal OFMethodNotFound@GOTOFF(%ebx), %eax + + addl $20, %esp + popl %ebx + popl %ebp + + jmp *%eax +.type OFForward, %function +.size OFForward, .-OFForward + +OFForward_stret: + pushl %ebp + movl %esp, %ebp + + pushl %ebx + subl $20, %esp + + call get_eip + addl $_GLOBAL_OFFSET_TABLE_, %ebx + + movl 12(%ebp), %eax + movl %eax, (%esp) + call object_getClass@PLT + + movl %eax, (%esp) + leal sel_forwardingTargetForSelector_@GOTOFF(%ebx), %eax + movl %eax, 4(%esp) + call class_respondsToSelector@PLT + + testl %eax, %eax + jz 0f + + movl 12(%ebp), %eax + movl %eax, (%esp) + leal sel_forwardingTargetForSelector_@GOTOFF(%ebx), %eax + movl %eax, 4(%esp) + call objc_msg_lookup@PLT + + movl 12(%ebp), %edx + movl %edx, (%esp) + leal sel_forwardingTargetForSelector_@GOTOFF(%ebx), %edx + movl %edx, 4(%esp) + movl 16(%ebp), %edx + movl %edx, 8(%esp) + call *%eax + + testl %eax, %eax + jz 0f + cmpl 12(%ebp), %eax + je 0f + + movl %eax, 12(%ebp) + movl %eax, (%esp) + movl 16(%ebp), %eax + movl %eax, 4(%esp) + call objc_msg_lookup_stret@PLT + + addl $20, %esp + popl %ebx + popl %ebp + + jmp *%eax + +0: + leal OFMethodNotFound_stret@GOTOFF(%ebx), %eax + + addl $20, %esp + popl %ebx + popl %ebp + + jmp *%eax +.type OFForward_stret, %function +.size OFForward_stret, .-OFForward_stret + +init: + pushl %ebp + movl %esp, %ebp + + pushl %ebx + subl $4, %esp + + call get_eip + addl $_GLOBAL_OFFSET_TABLE_, %ebx + + leal module@GOTOFF(%ebx), %eax + movl %eax, (%esp) + call __objc_exec_class@PLT + + addl $4, %esp + popl %ebx + popl %ebp ret get_eip: - mov ebx, [esp] + movl (%esp), %ebx ret #ifdef OF_SOLARIS .section .init_array, "aw" #else Index: src/forwarding/forwarding-x86-win32.S ================================================================== --- src/forwarding/forwarding-x86-win32.S +++ src/forwarding/forwarding-x86-win32.S @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -15,144 +13,150 @@ * file. */ #include "config.h" -.intel_syntax noprefix - -.globl _of_forward -.globl _of_forward_stret - -.section .text -_of_forward: - push ebp - mov ebp, esp - - push ebx - sub esp, 20 - - mov eax, [ebp+8] - mov [esp], eax - call _object_getClass - - mov [esp], eax - mov eax, offset sel_forwardingTargetForSelector_ - mov [esp+4], eax - call _class_respondsToSelector - - test eax, eax - jz short 0f - - mov eax, [ebp+8] - mov [esp], eax - mov eax, offset sel_forwardingTargetForSelector_ - mov [esp+4], eax - call _objc_msg_lookup - - mov edx, [ebp+8] - mov [esp], edx - mov edx, offset sel_forwardingTargetForSelector_ - mov [esp+4], edx - mov edx, [ebp+12] - mov [esp+8], edx - call eax - - test eax, eax - jz short 0f - cmp eax, [ebp+8] - je short 0f - - mov [ebp+8], eax - mov [esp], eax - mov eax, [ebp+12] - mov [esp+4], eax - call _objc_msg_lookup - - add esp, 20 - pop ebx - pop ebp - - jmp eax - -0: - add esp, 20 - pop ebx - pop ebp - - jmp _of_method_not_found - -_of_forward_stret: - push ebp - mov ebp, esp - - push ebx - sub esp, 20 - - mov eax, [ebp+12] - mov [esp], eax - call _object_getClass - - mov [esp], eax - mov eax, offset sel_forwardingTargetForSelector_ - mov [esp+4], eax - call _class_respondsToSelector - - test eax, eax - jz short 0f - - mov eax, [ebp+12] - mov [esp], eax - mov eax, offset sel_forwardingTargetForSelector_ - mov [esp+4], eax - call _objc_msg_lookup - - mov edx, [ebp+12] - mov [esp], edx - mov edx, offset sel_forwardingTargetForSelector_ - mov [esp+4], edx - mov edx, [ebp+16] - mov [esp+8], edx - call eax - - test eax, eax - jz short 0f - cmp eax, [ebp+12] - je short 0f - - mov [ebp+12], eax - mov [esp], eax - mov eax, [ebp+16] - mov [esp+4], eax - call _objc_msg_lookup_stret - - add esp, 20 - pop ebx - pop ebp - - jmp eax - -0: - add esp, 20 - pop ebx - pop ebp - - jmp _of_method_not_found_stret - -init: - push ebp - mov ebp, esp - - push ebx - sub esp, 4 - - mov eax, offset module - mov [esp], eax - call ___objc_exec_class - - add esp, 4 - pop ebx - pop ebp +.globl _OFForward +.globl _OFForward_stret + +.section .text +_OFForward: + pushl %ebp + movl %esp, %ebp + + pushl %ebx + subl $20, %esp + + movl 8(%ebp), %eax + movl %eax, (%esp) + call _object_getClass + + movl %eax, (%esp) + movl $sel_forwardingTargetForSelector_, %eax + movl %eax, 4(%esp) + call _class_respondsToSelector + + testl %eax, %eax + jz 0f + + movl 8(%ebp), %eax + movl %eax, (%esp) + movl $sel_forwardingTargetForSelector_, %eax + movl %eax, 4(%esp) + call _objc_msg_lookup + + movl 8(%ebp), %edx + movl %edx, (%esp) + movl $sel_forwardingTargetForSelector_, %edx + movl %edx, 4(%esp) + movl 12(%ebp), %edx + movl %edx, 8(%esp) + call *%eax + + testl %eax, %eax + jz 0f + cmpl 8(%ebp), %eax + je 0f + + movl %eax, 8(%ebp) + movl %eax, (%esp) + movl 12(%ebp), %eax + movl %eax, 4(%esp) + call _objc_msg_lookup + + addl $20, %esp + popl %ebx + popl %ebp + + jmp *%eax + +0: + addl $20, %esp + popl %ebx + popl %ebp + + jmp _OFMethodNotFound +.def _OFForward +.scl 2 +.type 32 +.endef + +_OFForward_stret: + pushl %ebp + movl %esp, %ebp + + pushl %ebx + subl $20, %esp + + movl 12(%ebp), %eax + movl %eax, (%esp) + call _object_getClass + + movl %eax, (%esp) + movl $sel_forwardingTargetForSelector_, %eax + movl %eax, 4(%esp) + call _class_respondsToSelector + + testl %eax, %eax + jz 0f + + movl 12(%ebp), %eax + movl %eax, (%esp) + movl $sel_forwardingTargetForSelector_, %eax + movl %eax, 4(%esp) + call _objc_msg_lookup + + movl 12(%ebp), %edx + movl %edx, (%esp) + movl $sel_forwardingTargetForSelector_, %edx + movl %edx, 4(%esp) + movl 16(%ebp), %edx + movl %edx, 8(%esp) + call *%eax + + testl %eax, %eax + jz 0f + cmpl 12(%ebp), %eax + je 0f + + movl %eax, 12(%ebp) + movl %eax, (%esp) + movl 16(%ebp), %eax + movl %eax, 4(%esp) + call _objc_msg_lookup_stret + + addl $20, %esp + popl %ebx + popl %ebp + + jmp *%eax + +0: + addl $20, %esp + popl %ebx + popl %ebp + + jmp _OFMethodNotFound_stret +.def _OFForward_stret +.scl 2 +.type 32 +.endef + +init: + pushl %ebp + movl %esp, %ebp + + pushl %ebx + subl $4, %esp + + movl $module, %eax + movl %eax, (%esp) + call ___objc_exec_class + + addl $4, %esp + popl %ebx + popl %ebp ret .section .ctors, "aw" .long init Index: src/forwarding/forwarding-x86_64-elf.S ================================================================== --- src/forwarding/forwarding-x86_64-elf.S +++ src/forwarding/forwarding-x86_64-elf.S @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -17,190 +15,188 @@ #include "config.h" #include "platform.h" -.intel_syntax noprefix - -.globl of_forward -.globl of_forward_stret - -.section .text -of_forward: - push rbp - mov rbp, rsp - - /* Save all arguments */ - sub rsp, 0xC0 /* 16-byte alignment */ - mov [rbp-0x08], rax - mov [rbp-0x10], rdi - mov [rbp-0x18], rsi - mov [rbp-0x20], rdx - mov [rbp-0x28], rcx - mov [rbp-0x30], r8 - mov [rbp-0x38], r9 - movaps [rbp-0x50], xmm0 - movaps [rbp-0x60], xmm1 - movaps [rbp-0x70], xmm2 - movaps [rbp-0x80], xmm3 - movaps [rbp-0x90], xmm4 - movaps [rbp-0xA0], xmm5 - movaps [rbp-0xB0], xmm6 - movaps [rbp-0xC0], xmm7 - - call object_getClass@PLT - - mov rdi, rax - lea rsi, [rip+sel_forwardingTargetForSelector_] - call class_respondsToSelector@PLT - - test rax, rax - jz short 0f - - mov rdi, [rbp-0x10] - lea rsi, [rip+sel_forwardingTargetForSelector_] - call objc_msg_lookup@PLT - - mov rdi, [rbp-0x10] - lea rsi, [rip+sel_forwardingTargetForSelector_] - mov rdx, [rbp-0x18] - call rax - - test rax, rax - jz short 0f - cmp rax, [rbp-0x10] - je short 0f - - mov [rbp-0x10], rax - - mov rdi, rax - mov rsi, [rbp-0x18] - call objc_msg_lookup@PLT - mov r11, rax - - /* Restore all arguments */ - movaps xmm7, [rbp-0xC0] - movaps xmm6, [rbp-0xB0] - movaps xmm5, [rbp-0xA0] - movaps xmm4, [rbp-0x90] - movaps xmm3, [rbp-0x80] - movaps xmm2, [rbp-0x70] - movaps xmm1, [rbp-0x60] - movaps xmm0, [rbp-0x50] - mov r9, [rbp-0x38] - mov r8, [rbp-0x30] - mov rcx, [rbp-0x28] - mov rdx, [rbp-0x20] - mov rsi, [rbp-0x18] - mov rdi, [rbp-0x10] - mov rax, [rbp-0x08] - - mov rsp, rbp - pop rbp - - jmp r11 - -0: - mov rdi, [rbp-0x10] - mov rsi, [rbp-0x18] - - mov rsp, rbp - pop rbp - - jmp of_method_not_found@PLT -.type of_forward, %function -.size of_forward, .-of_forward - -of_forward_stret: - push rbp - mov rbp, rsp - - /* Save all arguments */ - sub rsp, 0xC0 /* 16-byte alignment */ - mov [rbp-0x08], rax - mov [rbp-0x10], rdi - mov [rbp-0x18], rsi - mov [rbp-0x20], rdx - mov [rbp-0x28], rcx - mov [rbp-0x30], r8 - mov [rbp-0x38], r9 - movaps [rbp-0x50], xmm0 - movaps [rbp-0x60], xmm1 - movaps [rbp-0x70], xmm2 - movaps [rbp-0x80], xmm3 - movaps [rbp-0x90], xmm4 - movaps [rbp-0xA0], xmm5 - movaps [rbp-0xB0], xmm6 - movaps [rbp-0xC0], xmm7 - - mov rdi, rsi - call object_getClass@PLT - - mov rdi, rax - lea rsi, [rip+sel_forwardingTargetForSelector_] - call class_respondsToSelector@PLT - - test rax, rax - jz short 0f - - mov rdi, [rbp-0x18] - lea rsi, [rip+sel_forwardingTargetForSelector_] - call objc_msg_lookup@PLT - - mov rdi, [rbp-0x18] - lea rsi, [rip+sel_forwardingTargetForSelector_] - mov rdx, [rbp-0x20] - call rax - - test rax, rax - jz short 0f - cmp rax, [rbp-0x18] - je short 0f - - mov [rbp-0x18], rax - - mov rdi, rax - mov rsi, [rbp-0x20] - call objc_msg_lookup_stret@PLT - mov r11, rax - - /* Restore all arguments */ - movaps xmm7, [rbp-0xC0] - movaps xmm6, [rbp-0xB0] - movaps xmm5, [rbp-0xA0] - movaps xmm4, [rbp-0x90] - movaps xmm3, [rbp-0x80] - movaps xmm2, [rbp-0x70] - movaps xmm1, [rbp-0x60] - movaps xmm0, [rbp-0x50] - mov r9, [rbp-0x38] - mov r8, [rbp-0x30] - mov rcx, [rbp-0x28] - mov rdx, [rbp-0x20] - mov rsi, [rbp-0x18] - mov rdi, [rbp-0x10] - mov rax, [rbp-0x08] - - mov rsp, rbp - pop rbp - - jmp r11 - -0: - mov rdi, [rbp-0x10] - mov rsi, [rbp-0x18] - mov rdx, [rbp-0x20] - - mov rsp, rbp - pop rbp - - jmp of_method_not_found_stret@PLT -.type of_forward_stret, %function -.size of_forward_stret, .-of_forward_stret - -init: - lea rdi, [rip+module] +.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 Index: src/forwarding/forwarding-x86_64-macho.S ================================================================== --- src/forwarding/forwarding-x86_64-macho.S +++ src/forwarding/forwarding-x86_64-macho.S @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -17,186 +15,184 @@ #include "config.h" #include "platform.h" -.intel_syntax noprefix - -.globl _of_forward -.globl _of_forward_stret - -.section __TEXT, __text, regular, pure_instructions -_of_forward: - push rbp - mov rbp, rsp - - /* Save all arguments */ - sub rsp, 0xC0 /* 16-byte alignment */ - mov [rbp-0x08], rax - mov [rbp-0x10], rdi - mov [rbp-0x18], rsi - mov [rbp-0x20], rdx - mov [rbp-0x28], rcx - mov [rbp-0x30], r8 - mov [rbp-0x38], r9 - movaps [rbp-0x50], xmm0 - movaps [rbp-0x60], xmm1 - movaps [rbp-0x70], xmm2 - movaps [rbp-0x80], xmm3 - movaps [rbp-0x90], xmm4 - movaps [rbp-0xA0], xmm5 - movaps [rbp-0xB0], xmm6 - movaps [rbp-0xC0], xmm7 - - call _object_getClass - - mov rdi, rax - lea rsi, [rip+sel_forwardingTargetForSelector_] - call _class_respondsToSelector - - test rax, rax - jz 0f - - mov rdi, [rbp-0x10] - lea rsi, [rip+sel_forwardingTargetForSelector_] - call _objc_msg_lookup - - mov rdi, [rbp-0x10] - lea rsi, [rip+sel_forwardingTargetForSelector_] - mov rdx, [rbp-0x18] - call rax - - test rax, rax - jz 0f - cmp rax, [rbp-0x10] - je 0f - - mov [rbp-0x10], rax - - mov rdi, rax - mov rsi, [rbp-0x18] - call _objc_msg_lookup - mov r11, rax - - /* Restore all arguments */ - movaps xmm7, [rbp-0xC0] - movaps xmm6, [rbp-0xB0] - movaps xmm5, [rbp-0xA0] - movaps xmm4, [rbp-0x90] - movaps xmm3, [rbp-0x80] - movaps xmm2, [rbp-0x70] - movaps xmm1, [rbp-0x60] - movaps xmm0, [rbp-0x50] - mov r9, [rbp-0x38] - mov r8, [rbp-0x30] - mov rcx, [rbp-0x28] - mov rdx, [rbp-0x20] - mov rsi, [rbp-0x18] - mov rdi, [rbp-0x10] - mov rax, [rbp-0x08] - - mov rsp, rbp - pop rbp - - jmp r11 - -0: - mov rdi, [rbp-0x10] - mov rsi, [rbp-0x18] - - mov rsp, rbp - pop rbp - - jmp _of_method_not_found - -_of_forward_stret: - push rbp - mov rbp, rsp - - /* Save all arguments */ - sub rsp, 0xC0 /* 16-byte alignment */ - mov [rbp-0x08], rax - mov [rbp-0x10], rdi - mov [rbp-0x18], rsi - mov [rbp-0x20], rdx - mov [rbp-0x28], rcx - mov [rbp-0x30], r8 - mov [rbp-0x38], r9 - movaps [rbp-0x50], xmm0 - movaps [rbp-0x60], xmm1 - movaps [rbp-0x70], xmm2 - movaps [rbp-0x80], xmm3 - movaps [rbp-0x90], xmm4 - movaps [rbp-0xA0], xmm5 - movaps [rbp-0xB0], xmm6 - movaps [rbp-0xC0], xmm7 - - mov rdi, rsi - call _object_getClass - - mov rdi, rax - lea rsi, [rip+sel_forwardingTargetForSelector_] - call _class_respondsToSelector - - test rax, rax - jz 0f - - mov rdi, [rbp-0x18] - lea rsi, [rip+sel_forwardingTargetForSelector_] - call _objc_msg_lookup - - mov rdi, [rbp-0x18] - lea rsi, [rip+sel_forwardingTargetForSelector_] - mov rdx, [rbp-0x20] - call rax - - test rax, rax - jz 0f - cmp rax, [rbp-0x18] - je 0f - - mov [rbp-0x18], rax - - mov rdi, rax - mov rsi, [rbp-0x20] - call _objc_msg_lookup_stret - mov r11, rax - - /* Restore all arguments */ - movaps xmm7, [rbp-0xC0] - movaps xmm6, [rbp-0xB0] - movaps xmm5, [rbp-0xA0] - movaps xmm4, [rbp-0x90] - movaps xmm3, [rbp-0x80] - movaps xmm2, [rbp-0x70] - movaps xmm1, [rbp-0x60] - movaps xmm0, [rbp-0x50] - mov r9, [rbp-0x38] - mov r8, [rbp-0x30] - mov rcx, [rbp-0x28] - mov rdx, [rbp-0x20] - mov rsi, [rbp-0x18] - mov rdi, [rbp-0x10] - mov rax, [rbp-0x08] - - mov rsp, rbp - pop rbp - - jmp r11 - -0: - mov rdi, [rbp-0x10] - mov rsi, [rbp-0x18] - mov rdx, [rbp-0x20] - - mov rsp, rbp - pop rbp - - jmp _of_method_not_found_stret - -init: - lea rdi, [rip+module] +.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 Index: src/forwarding/forwarding-x86_64-win64.S ================================================================== --- src/forwarding/forwarding-x86_64-win64.S +++ src/forwarding/forwarding-x86_64-win64.S @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -15,162 +13,168 @@ * file. */ #include "config.h" -.intel_syntax noprefix - -.globl of_forward -.globl of_forward_stret - -.section .text -of_forward: - push rbp - mov rbp, rsp - - /* Save all arguments */ - sub rsp, 0x90 /* 16-byte alignment */ - mov [rbp-0x28], rax - mov [rbp-0x30], rcx - mov [rbp-0x38], rdx - mov [rbp-0x40], r8 - mov [rbp-0x48], r9 - movaps [rbp-0x60], xmm0 - movaps [rbp-0x70], xmm1 - movaps [rbp-0x80], xmm2 - movaps [rbp-0x90], xmm3 - - call object_getClass - - mov rcx, rax - mov rdx, offset sel_forwardingTargetForSelector_ - call class_respondsToSelector - - test rax, rax - jz short 0f - - mov rcx, [rbp-0x30] - mov rdx, offset sel_forwardingTargetForSelector_ - call objc_msg_lookup - - mov rcx, [rbp-0x30] - mov rdx, offset sel_forwardingTargetForSelector_ - mov r8, [rbp-0x38] - call rax - - test rax, rax - jz short 0f - cmp rax, [rbp-0x30] - je short 0f - - mov [rbp-0x30], rax - - mov rcx, rax - mov rdx, [rbp-0x38] - call objc_msg_lookup - mov r11, rax - - /* Restore all arguments */ - movaps xmm3, [rbp-0x90] - movaps xmm2, [rbp-0x80] - movaps xmm1, [rbp-0x70] - movaps xmm0, [rbp-0x60] - mov r9, [rbp-0x48] - mov r8, [rbp-0x40] - mov rdx, [rbp-0x38] - mov rcx, [rbp-0x30] - mov rax, [rbp-0x28] - - mov rsp, rbp - pop rbp - - jmp r11 - -0: - mov rcx, [rbp-0x30] - mov rdx, [rbp-0x38] - - mov rsp, rbp - pop rbp - - jmp of_method_not_found - -of_forward_stret: - push rbp - mov rbp, rsp - - /* Save all arguments */ - sub rsp, 0x90 /* 16-byte alignment */ - mov [rbp-0x28], rax - mov [rbp-0x30], rcx - mov [rbp-0x38], rdx - mov [rbp-0x40], r8 - mov [rbp-0x48], r9 - movaps [rbp-0x60], xmm0 - movaps [rbp-0x70], xmm1 - movaps [rbp-0x80], xmm2 - movaps [rbp-0x90], xmm3 - - mov rcx, rdx - call object_getClass - - mov rcx, rax - mov rdx, offset sel_forwardingTargetForSelector_ - call class_respondsToSelector - - test rax, rax - jz short 0f - - mov rcx, [rbp-0x38] - mov rdx, offset sel_forwardingTargetForSelector_ - call objc_msg_lookup - - mov rcx, [rbp-0x38] - mov rdx, offset sel_forwardingTargetForSelector_ - mov r8, [rbp-0x40] - call rax - - test rax, rax - jz short 0f - cmp rax, [rbp-0x38] - je short 0f - - mov [rbp-0x38], rax - - mov rcx, rax - mov rdx, [rbp-0x40] - call objc_msg_lookup_stret - mov r11, rax - - /* Restore all arguments */ - movaps xmm3, [rbp-0x90] - movaps xmm2, [rbp-0x80] - movaps xmm1, [rbp-0x70] - movaps xmm0, [rbp-0x60] - mov r9, [rbp-0x48] - mov r8, [rbp-0x40] - mov rdx, [rbp-0x38] - mov rcx, [rbp-0x30] - mov rax, [rbp-0x28] - - mov rsp, rbp - pop rbp - - jmp r11 - -0: - mov rcx, [rbp-0x30] - mov rdx, [rbp-0x38] - mov r8, [rbp-0x40] - - mov rsp, rbp - pop rbp - - jmp of_method_not_found_stret - -init: - mov rcx, offset module +.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 Index: src/forwarding/forwarding.S ================================================================== --- src/forwarding/forwarding.S +++ src/forwarding/forwarding.S @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 DELETED src/huffman_tree.h Index: src/huffman_tree.h ================================================================== --- src/huffman_tree.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 -#include - -#import "macros.h" - -#import "OFInvalidFormatException.h" - -OF_ASSUME_NONNULL_BEGIN - -struct of_huffman_tree { - struct of_huffman_tree *_Nullable leaves[2]; - uint16_t value; -}; - -static OF_INLINE bool -of_huffman_tree_walk(id _Nullable stream, - bool (*bitReader)(id _Nullable, uint16_t *_Nonnull, uint8_t), - struct of_huffman_tree *_Nonnull *_Nonnull tree, uint16_t *_Nonnull value) -{ - struct of_huffman_tree *iter = *tree; - uint16_t bits; - - while (iter->value == 0xFFFF) { - if OF_UNLIKELY (!bitReader(stream, &bits, 1)) { - *tree = iter; - return false; - } - - if OF_UNLIKELY (iter->leaves[bits] == NULL) - @throw [OFInvalidFormatException exception]; - - iter = iter->leaves[bits]; - } - - *value = iter->value; - return true; -} - -#ifdef __cplusplus -extern "C" { -#endif -extern struct of_huffman_tree *_Nonnull of_huffman_tree_construct( - uint8_t lengths[_Nonnull], uint16_t count); -extern struct of_huffman_tree *_Nonnull of_huffman_tree_construct_single( - uint16_t value); -extern void of_huffman_tree_release(struct of_huffman_tree *_Nonnull tree); -#ifdef __cplusplus -} -#endif - -OF_ASSUME_NONNULL_END DELETED src/huffman_tree.m Index: src/huffman_tree.m ================================================================== --- src/huffman_tree.m +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "huffman_tree.h" - -#import "OFInvalidFormatException.h" -#import "OFOutOfMemoryException.h" - -static struct of_huffman_tree * -newTree(void) -{ - struct of_huffman_tree *tree; - - tree = of_malloc(1, sizeof(*tree)); - tree->leaves[0] = tree->leaves[1] = NULL; - tree->value = 0xFFFF; - - return tree; -} - -static void -insertTree(struct of_huffman_tree *tree, uint16_t code, uint8_t length, - uint16_t value) -{ - while (length > 0) { - uint8_t bit; - - length--; - bit = (code & (1u << length)) >> length; - - if (tree->leaves[bit] == NULL) - tree->leaves[bit] = newTree(); - - tree = tree->leaves[bit]; - } - - tree->value = value; -} - -struct of_huffman_tree * -of_huffman_tree_construct(uint8_t lengths[], uint16_t count) -{ - struct of_huffman_tree *tree; - uint16_t *lengthCount = NULL; - uint16_t code, maxCode = 0, *nextCode = NULL; - uint_fast8_t maxBit = 0; - - @try { - for (uint16_t i = 0; i < count; i++) { - uint_fast8_t length = lengths[i]; - - if OF_UNLIKELY (length > maxBit) { - lengthCount = of_realloc(lengthCount, - length + 1, sizeof(uint16_t)); - nextCode = of_realloc(nextCode, - length + 1, sizeof(uint16_t)); - - for (uint_fast8_t j = maxBit + 1; j <= length; - j++) { - lengthCount[j] = 0; - nextCode[j] = 0; - } - - maxBit = length; - } - - if (length > 0) { - lengthCount[length]++; - maxCode = i; - } - } - - code = 0; - for (size_t i = 1; i <= maxBit; i++) { - code = (code + lengthCount[i - 1]) << 1; - nextCode[i] = code; - } - - tree = newTree(); - - for (uint16_t i = 0; i <= maxCode; i++) { - uint8_t length = lengths[i]; - - if (length > 0) - insertTree(tree, nextCode[length]++, length, i); - } - } @finally { - of_free(lengthCount); - of_free(nextCode); - } - - return tree; -} - -struct of_huffman_tree * -of_huffman_tree_construct_single(uint16_t value) -{ - struct of_huffman_tree *tree = newTree(); - - tree->value = value; - - return tree; -} - -void -of_huffman_tree_release(struct of_huffman_tree *tree) -{ - for (uint_fast8_t i = 0; i < 2; i++) - if OF_LIKELY (tree->leaves[i] != NULL) - of_huffman_tree_release(tree->leaves[i]); - - of_free(tree); -} DELETED src/invocation/Makefile Index: src/invocation/Makefile ================================================================== --- src/invocation/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -include ../../extra.mk - -STATIC_PIC_LIB_NOINST = ${INVOCATION_LIB_A} -STATIC_LIB_NOINST = ${INVOCATION_A} - -SRCS = call.S \ - invoke.m - -include ../../buildsys.mk - -ASFLAGS += -I../.. -I.. -OBJCFLAGS += -I../.. -I.. -I../exceptions -I../runtime DELETED src/invocation/apple-call-x86_64.S Index: src/invocation/apple-call-x86_64.S ================================================================== --- src/invocation/apple-call-x86_64.S +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "invoke-x86_64.h" - -.intel_syntax noprefix - -.globl _of_invocation_call - -.section __TEXT, __text, regular, pure_instructions -_of_invocation_call: - push rbp - mov rbp, rsp - - sub rsp, 16 - and rsp, -16 - mov [rbp-8], rdi - - lea rdx, [rdi+OFFSET_STACK] - mov rcx, [rdi+OFFSET_STACK_SIZE] - - test rcx, 1 - jnz Lfix_align - -Lfill_stack: - test rcx, rcx - jz Lstack_filled - - dec rcx - mov r11, [rdx+rcx*8] - push r11 - - jmp Lfill_stack - -Lstack_filled: - mov al, [rdi+OFFSET_NUM_SSE_USED] - - movaps xmm7, [rdi+OFFSET_SSE_INOUT+112] - movaps xmm6, [rdi+OFFSET_SSE_INOUT+96] - movaps xmm5, [rdi+OFFSET_SSE_INOUT+80] - movaps xmm4, [rdi+OFFSET_SSE_INOUT+64] - movaps xmm3, [rdi+OFFSET_SSE_INOUT+48] - movaps xmm2, [rdi+OFFSET_SSE_INOUT+32] - movaps xmm1, [rdi+OFFSET_SSE_INOUT+16] - movaps xmm0, [rdi+OFFSET_SSE_INOUT] - - mov r9, [rdi+OFFSET_GPR_IN+40] - mov r8, [rdi+OFFSET_GPR_IN+32] - mov rcx, [rdi+OFFSET_GPR_IN+24] - mov rdx, [rdi+OFFSET_GPR_IN+16] - mov rsi, [rdi+OFFSET_GPR_IN+8] - - mov r11b, [rdi+OFFSET_RETURN_TYPE] - mov rdi, [rdi+OFFSET_GPR_IN] - - cmp r11b, RETURN_TYPE_STRET - je Lcall_send_stret - - cmp r11b, RETURN_TYPE_JMP - je _objc_msgSend - - cmp r11b, RETURN_TYPE_JMP_STRET - je _objc_msgSend_stret - - call _objc_msgSend - -Lafter_send: - mov rdi, [rbp-8] - mov [rdi+OFFSET_GPR_OUT], rax - mov [rdi+OFFSET_GPR_OUT+8], rdx - movaps [rdi+OFFSET_SSE_INOUT], xmm0 - movaps [rdi+OFFSET_SSE_INOUT+16], xmm1 - - mov r11b, [rdi+OFFSET_RETURN_TYPE] - - cmp r11b, RETURN_TYPE_X87 - je Lpop_long_double - - cmp r11b, RETURN_TYPE_COMPLEX_X87 - je Lpop_complex_long_double - -Lreturn: - mov rsp, rbp - pop rbp - - ret - -Lfix_align: - xor r11, r11 - push r11 - jmp Lfill_stack - -Lcall_send_stret: - call _objc_msgSend_stret - jmp Lafter_send - -Lpop_long_double: - fstp tbyte ptr [rdi+OFFSET_X87_OUT] - jmp Lreturn - -Lpop_complex_long_double: - fstp tbyte ptr [rdi+OFFSET_X87_OUT] - fstp tbyte ptr [rdi+OFFSET_X87_OUT+16] - jmp Lreturn DELETED src/invocation/call-x86_64-elf.S Index: src/invocation/call-x86_64-elf.S ================================================================== --- src/invocation/call-x86_64-elf.S +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "invoke-x86_64.h" - -.intel_syntax noprefix - -.globl of_invocation_call - -.section .text -of_invocation_call: - pushq rbp - mov rbp, rsp - - sub rsp, 16 - and rsp, -16 - mov [rbp-8], rdi - - mov r11b, [rdi+OFFSET_RETURN_TYPE] - cmp r11b, RETURN_TYPE_STRET - je short .Llookup_stret - cmp r11b, RETURN_TYPE_JMP_STRET - je short .Llookup_stret - - mov rsi, [rdi+OFFSET_GPR_IN+8] - mov rdi, [rdi+OFFSET_GPR_IN] - call objc_msg_lookup@PLT - -.Lafter_lookup: - mov [rbp-16], rax - mov rdi, [rbp-8] - - lea rdx, [rdi+OFFSET_STACK] - mov rcx, [rdi+OFFSET_STACK_SIZE] - - test rcx, 1 - jnz short .Lfix_align - -.Lfill_stack: - test rcx, rcx - jz short .Lstack_filled - - dec rcx - mov r11, [rdx+rcx*8] - push r11 - - jmp short .Lfill_stack - -.Lstack_filled: - mov al, [rdi+OFFSET_NUM_SSE_USED] - - movaps xmm7, [rdi+OFFSET_SSE_INOUT+112] - movaps xmm6, [rdi+OFFSET_SSE_INOUT+96] - movaps xmm5, [rdi+OFFSET_SSE_INOUT+80] - movaps xmm4, [rdi+OFFSET_SSE_INOUT+64] - movaps xmm3, [rdi+OFFSET_SSE_INOUT+48] - movaps xmm2, [rdi+OFFSET_SSE_INOUT+32] - movaps xmm1, [rdi+OFFSET_SSE_INOUT+16] - movaps xmm0, [rdi+OFFSET_SSE_INOUT] - - mov r9, [rdi+OFFSET_GPR_IN+40] - mov r8, [rdi+OFFSET_GPR_IN+32] - mov rcx, [rdi+OFFSET_GPR_IN+24] - mov rdx, [rdi+OFFSET_GPR_IN+16] - mov rsi, [rdi+OFFSET_GPR_IN+8] - - mov r11b, [rdi+OFFSET_RETURN_TYPE] - mov rdi, [rdi+OFFSET_GPR_IN] - - cmp r11b, RETURN_TYPE_JMP - je short .Ljmp_into_method - cmp r11b, RETURN_TYPE_JMP_STRET - je short .Ljmp_into_method - - mov r11, [rbp-16] - call r11 - -.Lafter_send: - mov rdi, [rbp-8] - mov [rdi+OFFSET_GPR_OUT], rax - mov [rdi+OFFSET_GPR_OUT+8], rdx - movaps [rdi+OFFSET_SSE_INOUT], xmm0 - movaps [rdi+OFFSET_SSE_INOUT+16], xmm1 - - mov r11b, [rdi+OFFSET_RETURN_TYPE] - - cmp r11b, RETURN_TYPE_X87 - je short .Lpop_long_double - - cmp r11b, RETURN_TYPE_COMPLEX_X87 - je short .Lpop_complex_long_double - -.Lreturn: - mov rsp, rbp - pop rbp - - ret - -.Lfix_align: - xor r11, r11 - push r11 - jmp short .Lfill_stack - -.Llookup_stret: - mov rsi, [rdi+OFFSET_GPR_IN+16] - mov rdi, [rdi+OFFSET_GPR_IN+8] - call objc_msg_lookup_stret@PLT - - jmp short .Lafter_lookup - -.Ljmp_into_method: - mov r11, [rbp-16] - jmp r11 - -.Lpop_long_double: - fstp tbyte ptr [rdi+OFFSET_X87_OUT] - jmp short .Lreturn - -.Lpop_complex_long_double: - fstp tbyte ptr [rdi+OFFSET_X87_OUT] - fstp tbyte ptr [rdi+OFFSET_X87_OUT+16] - jmp short .Lreturn - -#ifdef OF_LINUX -.section .note.GNU-stack, "", %progbits -#endif DELETED src/invocation/call.S Index: src/invocation/call.S ================================================================== --- src/invocation/call.S +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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" - -#ifdef OF_APPLE_RUNTIME -# ifdef OF_X86_64 -# include "apple-call-x86_64.S" -# endif -#else -# ifdef OF_ELF -# ifdef OF_X86_64 -# include "call-x86_64-elf.S" -# endif -# endif -#endif DELETED src/invocation/invoke-x86_64.h Index: src/invocation/invoke-x86_64.h ================================================================== --- src/invocation/invoke-x86_64.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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. - */ - -#define RETURN_TYPE_NORMAL 0 -#define RETURN_TYPE_STRET 1 -#define RETURN_TYPE_X87 2 -#define RETURN_TYPE_COMPLEX_X87 3 -#define RETURN_TYPE_JMP 4 -#define RETURN_TYPE_JMP_STRET 5 - -#define NUM_GPR_IN 6 -#define NUM_GPR_OUT 2 -#define NUM_SSE_INOUT 8 -#define NUM_X87_OUT 2 - -#define OFFSET_GPR_IN 0 -#define OFFSET_GPR_OUT (OFFSET_GPR_IN + NUM_GPR_IN * 8) -#define OFFSET_SSE_INOUT (OFFSET_GPR_OUT + NUM_GPR_OUT * 8) -#define OFFSET_X87_OUT (OFFSET_SSE_INOUT + NUM_SSE_INOUT * 16) -#define OFFSET_NUM_SSE_USED (OFFSET_X87_OUT + NUM_X87_OUT * 16) -#define OFFSET_RETURN_TYPE (OFFSET_NUM_SSE_USED + 1) -#define OFFSET_STACK_SIZE (OFFSET_RETURN_TYPE + 7) -#define OFFSET_STACK (OFFSET_STACK_SIZE + 8) DELETED src/invocation/invoke-x86_64.m Index: src/invocation/invoke-x86_64.m ================================================================== --- src/invocation/invoke-x86_64.m +++ /dev/null @@ -1,452 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "OFInvocation.h" -#import "OFMethodSignature.h" - -#import "OFInvalidFormatException.h" -#import "OFOutOfMemoryException.h" - -#import "invoke-x86_64.h" - -#import "macros.h" - -struct call_context { - uint64_t GPR[NUM_GPR_IN + NUM_GPR_OUT]; - __m128 SSE[NUM_SSE_INOUT]; - long double X87[NUM_X87_OUT]; - uint8_t numSSEUsed; - uint8_t returnType; - uint64_t stackSize; - uint64_t stack[]; -}; - -extern void of_invocation_call(struct call_context *); - -static void -pushGPR(struct call_context **context, uint_fast8_t *currentGPR, uint64_t value) -{ - struct call_context *newContext; - - if (*currentGPR < NUM_GPR_IN) { - (*context)->GPR[(*currentGPR)++] = value; - return; - } - - if ((newContext = realloc(*context, - sizeof(**context) + ((*context)->stackSize + 1) * 8)) == NULL) { - free(*context); - @throw [OFOutOfMemoryException exceptionWithRequestedSize: - sizeof(**context) + ((*context)->stackSize + 1) * 8]; - } - - newContext->stack[newContext->stackSize] = value; - newContext->stackSize++; - *context = newContext; -} - -static void -pushDouble(struct call_context **context, uint_fast8_t *currentSSE, - double value) -{ - struct call_context *newContext; - - if (*currentSSE < NUM_SSE_INOUT) { - (*context)->SSE[(*currentSSE)++] = (__m128)_mm_set_sd(value); - (*context)->numSSEUsed++; - return; - } - - if ((newContext = realloc(*context, - sizeof(**context) + ((*context)->stackSize + 1) * 8)) == NULL) { - free(*context); - @throw [OFOutOfMemoryException exceptionWithRequestedSize: - sizeof(**context) + ((*context)->stackSize + 1) * 8]; - } - - memcpy(&newContext->stack[newContext->stackSize], &value, 8); - newContext->stackSize++; - *context = newContext; -} - -static void -pushQuad(struct call_context **context, uint_fast8_t *currentSSE, - double low, double high) -{ - size_t stackSize; - struct call_context *newContext; - - if (*currentSSE + 1 < NUM_SSE_INOUT) { - (*context)->SSE[(*currentSSE)++] = (__m128)_mm_set_sd(low); - (*context)->SSE[(*currentSSE)++] = (__m128)_mm_set_sd(high); - (*context)->numSSEUsed += 2; - return; - } - - stackSize = (*context)->stackSize + 2; - - if ((newContext = realloc(*context, - sizeof(**context) + stackSize * 8)) == NULL) { - free(*context); - @throw [OFOutOfMemoryException exceptionWithRequestedSize: - sizeof(**context) + stackSize * 8]; - } - - memset(&newContext->stack[newContext->stackSize], '\0', - (stackSize - newContext->stackSize) * 8); - memcpy(&newContext->stack[stackSize - 2], &low, 8); - memcpy(&newContext->stack[stackSize - 1], &high, 8); - newContext->stackSize = stackSize; - *context = newContext; -} - -static void -pushLongDouble(struct call_context **context, long double value) -{ - struct call_context *newContext; - - if ((newContext = realloc(*context, - sizeof(**context) + ((*context)->stackSize + 2) * 8)) == NULL) { - free(*context); - @throw [OFOutOfMemoryException exceptionWithRequestedSize: - sizeof(**context) + ((*context)->stackSize + 2) * 8]; - } - - memcpy(&newContext->stack[newContext->stackSize], &value, 16); - newContext->stackSize += 2; - *context = newContext; -} - -static void -pushLongDoublePair(struct call_context **context, long double value[2]) -{ - size_t stackSize; - struct call_context *newContext; - - stackSize = OF_ROUND_UP_POW2(2UL, (*context)->stackSize) + 4; - - if ((newContext = realloc(*context, - sizeof(**context) + stackSize * 8)) == NULL) { - free(*context); - @throw [OFOutOfMemoryException exceptionWithRequestedSize: - sizeof(**context) + stackSize * 8]; - } - - memset(&newContext->stack[newContext->stackSize], '\0', - (stackSize - newContext->stackSize) * 8); - memcpy(&newContext->stack[stackSize - 4], value, 32); - newContext->stackSize = stackSize; - *context = newContext; -} - -#if defined(__SIZEOF_INT128__) && !defined(__clang__) -static void -pushInt128(struct call_context **context, uint_fast8_t *currentGPR, - uint64_t value[2]) -{ - size_t stackSize; - struct call_context *newContext; - - if (*currentGPR + 1 < NUM_GPR_IN) { - (*context)->GPR[(*currentGPR)++] = value[0]; - (*context)->GPR[(*currentGPR)++] = value[1]; - return; - } - - stackSize = OF_ROUND_UP_POW2(2, (*context)->stackSize) + 2; - - if ((newContext = realloc(*context, - sizeof(**context) + stackSize * 8)) == NULL) { - free(*context); - @throw [OFOutOfMemoryException exceptionWithRequestedSize: - sizeof(**context) + stackSize * 8]; - } - - memset(&newContext->stack[newContext->stackSize], '\0', - (stackSize - newContext->stackSize) * 8); - memcpy(&newContext->stack[stackSize - 2], value, 16); - newContext->stackSize = stackSize; - *context = newContext; -} -#endif - -void -of_invocation_invoke(OFInvocation *invocation) -{ - OFMethodSignature *methodSignature = invocation.methodSignature; - size_t numberOfArguments = methodSignature.numberOfArguments; - struct call_context *context; - const char *typeEncoding; - uint_fast8_t currentGPR = 0, currentSSE = 0; - - if ((context = calloc(sizeof(*context), 1)) == NULL) - @throw [OFOutOfMemoryException exception]; - - for (size_t i = 0; i < numberOfArguments; i++) { - typeEncoding = [methodSignature argumentTypeAtIndex: i]; - - if (*typeEncoding == 'r') - typeEncoding++; - - switch (*typeEncoding) { -#define CASE_GPR(encoding, type) \ - case encoding: \ - { \ - type tmp; \ - [invocation getArgument: &tmp \ - atIndex: i]; \ - pushGPR(&context, ¤tGPR, (uint64_t)tmp); \ - } \ - break; - CASE_GPR('c', char) - CASE_GPR('C', unsigned char) - CASE_GPR('i', int) - CASE_GPR('I', unsigned int) - CASE_GPR('s', short) - CASE_GPR('S', unsigned short) - CASE_GPR('l', long) - CASE_GPR('L', unsigned long) - CASE_GPR('q', long long) - CASE_GPR('Q', unsigned long long) - CASE_GPR('B', _Bool) - CASE_GPR('*', char *) - CASE_GPR('@', id) - CASE_GPR('#', Class) - /* - * Using SEL triggers a warning that casting a SEL to an - * integer is deprecated. - */ - CASE_GPR(':', void *) - CASE_GPR('^', void *) -#undef CASE_GPR -#ifdef __SIZEOF_INT128__ - case 't': - case 'T':; - uint64_t int128Tmp[2]; - [invocation getArgument: &int128Tmp - atIndex: i]; -# ifndef __clang__ - pushInt128(&context, ¤tGPR, int128Tmp); -# else - /* See https://bugs.llvm.org/show_bug.cgi?id=34646 */ - pushGPR(&context, ¤tGPR, int128Tmp[0]); - pushGPR(&context, ¤tGPR, int128Tmp[1]); -# endif - break; -#endif - case 'f':; - double floatTmp = 0; - [invocation getArgument: &floatTmp - atIndex: i]; - pushDouble(&context, ¤tSSE, floatTmp); - break; - case 'd':; - double doubleTmp; - [invocation getArgument: &doubleTmp - atIndex: i]; - pushDouble(&context, ¤tSSE, doubleTmp); - break; - case 'D':; - long double longDoubleTmp; - [invocation getArgument: &longDoubleTmp - atIndex: i]; - pushLongDouble(&context, longDoubleTmp); - break; - case 'j': - switch (typeEncoding[1]) { - case 'f':; - double complexFloatTmp; - [invocation getArgument: &complexFloatTmp - atIndex: i]; - pushDouble(&context, ¤tSSE, - complexFloatTmp); - break; - case 'd':; - double complexDoubleTmp[2]; - [invocation getArgument: &complexDoubleTmp - atIndex: i]; - pushQuad(&context, ¤tSSE, - complexDoubleTmp[0], complexDoubleTmp[1]); - break; - case 'D':; - long double complexLongDoubleTmp[2]; - [invocation getArgument: &complexLongDoubleTmp - atIndex: i]; - pushLongDoublePair(&context, - complexLongDoubleTmp); - break; - default: - free(context); - @throw [OFInvalidFormatException exception]; - } - - break; - /* TODO: '[' */ - /* TODO: '{' */ - /* TODO: '(' */ - default: - free(context); - @throw [OFInvalidFormatException exception]; - } - } - - typeEncoding = methodSignature.methodReturnType; - - if (*typeEncoding == 'r') - typeEncoding++; - - switch (*typeEncoding) { - case 'v': - case 'c': - case 'C': - case 'i': - case 'I': - case 's': - case 'S': - case 'l': - case 'L': - case 'q': - case 'Q': - case 'B': - case '*': - case '@': - case '#': - case ':': - case '^': -#ifdef __SIZEOF_INT128__ - case 't': - case 'T': -#endif - case 'f': - case 'd': - context->returnType = RETURN_TYPE_NORMAL; - break; - case 'D': - context->returnType = RETURN_TYPE_X87; - break; - case 'j': - switch (typeEncoding[1]) { - case 'f': - case 'd': - context->returnType = RETURN_TYPE_NORMAL; - break; - case 'D': - context->returnType = RETURN_TYPE_COMPLEX_X87; - break; - default: - free(context); - @throw [OFInvalidFormatException exception]; - } - - break; - /* TODO: '[' */ - /* TODO: '{' */ - /* TODO: '(' */ - default: - free(context); - @throw [OFInvalidFormatException exception]; - } - - of_invocation_call(context); - - switch (*typeEncoding) { - case 'v': - break; -#define CASE_GPR(encoding, type) \ - case encoding: \ - { \ - type tmp = (type)context->GPR[NUM_GPR_IN]; \ - [invocation setReturnValue: &tmp]; \ - } \ - break; - CASE_GPR('c', char) - CASE_GPR('C', unsigned char) - CASE_GPR('i', int) - CASE_GPR('I', unsigned int) - CASE_GPR('s', short) - CASE_GPR('S', unsigned short) - CASE_GPR('l', long) - CASE_GPR('L', unsigned long) - CASE_GPR('q', long long) - CASE_GPR('Q', unsigned long long) - CASE_GPR('B', _Bool) - CASE_GPR('*', char *) - CASE_GPR('@', id) - CASE_GPR('#', Class) - CASE_GPR(':', SEL) - CASE_GPR('^', void *) -#undef CASE_GPR -#ifdef __SIZEOF_INT128__ - case 't': - case 'T':; - [invocation setReturnValue: &context->GPR[NUM_GPR_IN]]; - break; -#endif - case 'f':; - float floatTmp; - _mm_store_ss(&floatTmp, context->SSE[0]); - [invocation setReturnValue: &floatTmp]; - break; - case 'd':; - double doubleTmp; - _mm_store_sd(&doubleTmp, (__m128d)context->SSE[0]); - [invocation setReturnValue: &doubleTmp]; - break; - case 'D': - [invocation setReturnValue: &context->X87[0]]; - break; - case 'j': - switch (typeEncoding[1]) { - case 'f':; - double complexFloatTmp; - _mm_store_sd(&complexFloatTmp, - (__m128d)context->SSE[0]); - [invocation setReturnValue: &complexFloatTmp]; - break; - case 'd':; - double complexDoubleTmp[2]; - _mm_store_sd(&complexDoubleTmp[0], - (__m128d)context->SSE[0]); - _mm_store_sd(&complexDoubleTmp[1], - (__m128d)context->SSE[1]); - [invocation setReturnValue: &complexDoubleTmp]; - break; - case 'D': - [invocation setReturnValue: context->X87]; - break; - default: - free(context); - @throw [OFInvalidFormatException exception]; - } - - break; - /* TODO: '[' */ - /* TODO: '{' */ - /* TODO: '(' */ - default: - free(context); - @throw [OFInvalidFormatException exception]; - } - - free(context); -} DELETED src/invocation/invoke.m Index: src/invocation/invoke.m ================================================================== --- src/invocation/invoke.m +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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" - -#if defined(OF_X86_64) && (defined(OF_APPLE_RUNTIME) || defined(OF_ELF)) -# include "invoke-x86_64.m" -#else -/* To not have an empty translation unit otherwise */ -int of_invocation_cannot_invoke; -#endif Index: src/libbases.m ================================================================== --- src/libbases.m +++ src/libbases.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: src/macros.h ================================================================== --- src/macros.h +++ src/macros.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -25,10 +23,11 @@ #endif #ifndef __STDC_CONSTANT_MACROS # define __STDC_CONSTANT_MACROS #endif +#include #include #include #include #include #include @@ -101,16 +100,10 @@ # define OF_CONST_FUNC # define OF_NO_RETURN_FUNC # define OF_WEAK_REF(sym) #endif -#ifdef OF_BIG_ENDIAN -# define OF_BYTE_ORDER_NATIVE OF_BYTE_ORDER_BIG_ENDIAN -#else -# define OF_BYTE_ORDER_NATIVE OF_BYTE_ORDER_LITTLE_ENDIAN -#endif - #if __STDC_VERSION__ >= 201112L # define OF_ALIGNOF(type) _Alignof(type) # define OF_ALIGNAS(type) _Alignas(type) #else # define OF_ALIGNOF(type) __alignof__(type) @@ -146,10 +139,13 @@ #ifdef __GNUC__ # define OF_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) #else # define OF_GCC_VERSION 0 #endif + +#define OF_STRINGIFY(s) OF_STRINGIFY2(s) +#define OF_STRINGIFY2(s) #s #ifndef __has_feature # define __has_feature(x) 0 #endif @@ -258,11 +254,10 @@ # define OF_WARN_UNUSED_RESULT #endif #if __has_attribute(__unavailable__) # define OF_UNAVAILABLE __attribute__((__unavailable__)) -# define OF_HAVE_UNAVAILABLE #else # define OF_UNAVAILABLE #endif #if __has_attribute(__objc_requires_super__) @@ -318,46 +313,10 @@ # define OF_DIRECT_MEMBERS __attribute__((__objc_direct_members__)) #else # define OF_DIRECT_MEMBERS #endif -#ifdef __GNUC__ -# ifdef OF_X86_64 -# define OF_X86_64_ASM -# endif -# ifdef OF_X86 -# define OF_X86_ASM -# endif -# ifdef OF_POWERPC -# define OF_POWERPC_ASM -# endif -# ifdef OF_ARM64 -# define OF_ARM64_ASM -# endif -# ifdef OF_ARM -# define OF_ARM_ASM -# endif -# ifdef OF_ARMV7 -# define OF_ARMV7_ASM -# endif -# ifdef OF_ARMV6 -# define OF_ARMV6_ASM -# endif -# ifdef OF_MIPS64 -# define OF_MIPS64_ASM -# endif -# ifdef OF_MIPS -# define OF_MIPS_ASM -# endif -# ifdef OF_PA_RISC -# define OF_PA_RISC_ASM -# endif -# ifdef OF_ITANIUM -# define OF_ITANIUM_ASM -# endif -#endif - #ifdef OF_APPLE_RUNTIME # if defined(OF_X86_64) || 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 @@ -387,30 +346,39 @@ # endif # endif # endif #endif -#define OF_RETAIN_COUNT_MAX UINT_MAX -#define OF_NOT_FOUND SIZE_MAX +#define OFMaxRetainCount UINT_MAX -#define OF_ENSURE(cond) \ +#ifdef OBJC_COMPILING_RUNTIME +# define OFEnsure(cond) \ + do { \ + if OF_UNLIKELY (!(cond)) \ + objc_error("ObjFWRT @ " __FILE__ ":" \ + OF_STRINGIFY(__LINE__), \ + "Failed to ensure condition:\n" #cond); \ + } while(0) +#else +# define OFEnsure(cond) \ do { \ - if (!(cond)) { \ + if OF_UNLIKELY (!(cond)) { \ fprintf(stderr, "Failed to ensure condition " \ "in " __FILE__ ":%d:\n" #cond "\n", \ __LINE__); \ abort(); \ } \ } while (0) +#endif -#define OF_UNRECOGNIZED_SELECTOR of_method_not_found(self, _cmd); +#define OF_UNRECOGNIZED_SELECTOR OFMethodNotFound(self, _cmd); #if __has_feature(objc_arc) -# define OF_INVALID_INIT_METHOD of_method_not_found(self, _cmd); +# define OF_INVALID_INIT_METHOD OFMethodNotFound(self, _cmd); #else # define OF_INVALID_INIT_METHOD \ @try { \ - of_method_not_found(self, _cmd); \ + OFMethodNotFound(self, _cmd); \ } @catch (id e) { \ [self release]; \ @throw e; \ } \ \ @@ -440,49 +408,55 @@ #define OF_DESTRUCTOR(prio) \ static void __attribute__((__destructor__(prio))) \ OF_PREPROCESSOR_CONCAT(destructor, __LINE__)(void) static OF_INLINE uint16_t OF_CONST_FUNC -OF_BSWAP16_CONST(uint16_t i) +OFByteSwap16Const(uint16_t i) { - return (i & 0xFF00) >> 8 | (i & 0x00FF) << 8; + return (i & UINT16_C(0xFF00)) >> 8 | (i & UINT16_C(0x00FF)) << 8; } static OF_INLINE uint32_t OF_CONST_FUNC -OF_BSWAP32_CONST(uint32_t i) +OFByteSwap32Const(uint32_t i) { - return (i & 0xFF000000) >> 24 | (i & 0x00FF0000) >> 8 | - (i & 0x0000FF00) << 8 | (i & 0x000000FF) << 24; + return (i & UINT32_C(0xFF000000)) >> 24 | + (i & UINT32_C(0x00FF0000)) >> 8 | + (i & UINT32_C(0x0000FF00)) << 8 | + (i & UINT32_C(0x000000FF)) << 24; } static OF_INLINE uint64_t OF_CONST_FUNC -OF_BSWAP64_CONST(uint64_t i) +OFByteSwap64Const(uint64_t i) { - return (i & 0xFF00000000000000) >> 56 | (i & 0x00FF000000000000) >> 40 | - (i & 0x0000FF0000000000) >> 24 | (i & 0x000000FF00000000) >> 8 | - (i & 0x00000000FF000000) << 8 | (i & 0x0000000000FF0000) << 24 | - (i & 0x000000000000FF00) << 40 | (i & 0x00000000000000FF) << 56; + return (i & UINT64_C(0xFF00000000000000)) >> 56 | + (i & UINT64_C(0x00FF000000000000)) >> 40 | + (i & UINT64_C(0x0000FF0000000000)) >> 24 | + (i & UINT64_C(0x000000FF00000000)) >> 8 | + (i & UINT64_C(0x00000000FF000000)) << 8 | + (i & UINT64_C(0x0000000000FF0000)) << 24 | + (i & UINT64_C(0x000000000000FF00)) << 40 | + (i & UINT64_C(0x00000000000000FF)) << 56; } static OF_INLINE uint16_t OF_CONST_FUNC -OF_BSWAP16_NONCONST(uint16_t i) +OFByteSwap16NonConst(uint16_t i) { #if defined(OF_HAVE_BUILTIN_BSWAP16) return __builtin_bswap16(i); -#elif defined(OF_X86_64_ASM) || defined(OF_X86_ASM) +#elif (defined(OF_X86_64) || defined(OF_X86)) && defined(__GNUC__) __asm__ ( "xchgb %h0, %b0" : "=Q"(i) : "0"(i) ); -#elif defined(OF_POWERPC_ASM) +#elif defined(OF_POWERPC) && defined(__GNUC__) __asm__ ( "lhbrx %0, 0, %1" : "=r"(i) : "r"(&i), "m"(i) ); -#elif defined(OF_ARMV6_ASM) +#elif defined(OF_ARMV6) && defined(__GNUC__) __asm__ ( "rev16 %0, %0" : "=r"(i) : "0"(i) ); @@ -492,27 +466,27 @@ #endif return i; } static OF_INLINE uint32_t OF_CONST_FUNC -OF_BSWAP32_NONCONST(uint32_t i) +OFByteSwap32NonConst(uint32_t i) { #if defined(OF_HAVE_BUILTIN_BSWAP32) return __builtin_bswap32(i); -#elif defined(OF_X86_64_ASM) || defined(OF_X86_ASM) +#elif (defined(OF_X86_64) || defined(OF_X86)) && defined(__GNUC__) __asm__ ( "bswap %0" : "=q"(i) : "0"(i) ); -#elif defined(OF_POWERPC_ASM) +#elif defined(OF_POWERPC) && defined(__GNUC__) __asm__ ( "lwbrx %0, 0, %1" : "=r"(i) : "r"(&i), "m"(i) ); -#elif defined(OF_ARMV6_ASM) +#elif defined(OF_ARMV6) && defined(__GNUC__) __asm__ ( "rev %0, %0" : "=r"(i) : "0"(i) ); @@ -524,378 +498,214 @@ #endif return i; } static OF_INLINE uint64_t OF_CONST_FUNC -OF_BSWAP64_NONCONST(uint64_t i) +OFByteSwap64NonConst(uint64_t i) { #if defined(OF_HAVE_BUILTIN_BSWAP64) return __builtin_bswap64(i); -#elif defined(OF_X86_64_ASM) +#elif defined(OF_X86_64) && defined(__GNUC__) __asm__ ( "bswap %0" : "=r"(i) : "0"(i) ); -#elif defined(OF_X86_ASM) +#elif defined(OF_X86) && defined(__GNUC__) __asm__ ( "bswap %%eax\n\t" "bswap %%edx\n\t" "xchgl %%eax, %%edx" : "=A"(i) : "0"(i) ); #else - i = (uint64_t)OF_BSWAP32_NONCONST((uint32_t)(i & 0xFFFFFFFF)) << 32 | - OF_BSWAP32_NONCONST((uint32_t)(i >> 32)); + i = (uint64_t)OFByteSwap32NonConst( + (uint32_t)(i & UINT32_C(0xFFFFFFFF))) << 32 | + OFByteSwap32NonConst((uint32_t)(i >> 32)); #endif return i; } #ifdef __GNUC__ -# define OF_BSWAP16(i) \ - (__builtin_constant_p(i) ? OF_BSWAP16_CONST(i) : OF_BSWAP16_NONCONST(i)) -# define OF_BSWAP32(i) \ - (__builtin_constant_p(i) ? OF_BSWAP32_CONST(i) : OF_BSWAP32_NONCONST(i)) -# define OF_BSWAP64(i) \ - (__builtin_constant_p(i) ? OF_BSWAP64_CONST(i) : OF_BSWAP64_NONCONST(i)) +# define OFByteSwap16(i) \ + (__builtin_constant_p(i) ? OFByteSwap16Const(i) : OFByteSwap16NonConst(i)) +# define OFByteSwap32(i) \ + (__builtin_constant_p(i) ? OFByteSwap32Const(i) : OFByteSwap32NonConst(i)) +# define OFByteSwap64(i) \ + (__builtin_constant_p(i) ? OFByteSwap64Const(i) : OFByteSwap64NonConst(i)) #else -# define OF_BSWAP16(i) OF_BSWAP16_CONST(i) -# define OF_BSWAP32(i) OF_BSWAP32_CONST(i) -# define OF_BSWAP64(i) OF_BSWAP64_CONST(i) +# define OFByteSwap16(i) OFByteSwap16Const(i) +# define OFByteSwap32(i) OFByteSwap32Const(i) +# define OFByteSwap64(i) OFByteSwap64Const(i) #endif static OF_INLINE uint32_t -OF_FLOAT_TO_INT_RAW(float f) +OFFloatToRawUInt32(float f) { uint32_t ret; memcpy(&ret, &f, 4); return ret; } static OF_INLINE float -OF_INT_TO_FLOAT_RAW(uint32_t uInt32) +OFRawUInt32ToFloat(uint32_t uInt32) { float ret; memcpy(&ret, &uInt32, 4); return ret; } static OF_INLINE uint64_t -OF_DOUBLE_TO_INT_RAW(double d) +OFDoubleToRawUInt64(double d) { uint64_t ret; memcpy(&ret, &d, 8); return ret; } static OF_INLINE double -OF_INT_TO_DOUBLE_RAW(uint64_t uInt64) +OFRawUInt64ToDouble(uint64_t uInt64) { double ret; memcpy(&ret, &uInt64, 8); return ret; } static OF_INLINE float OF_CONST_FUNC -OF_BSWAP_FLOAT(float f) +OFByteSwapFloat(float f) { - return OF_INT_TO_FLOAT_RAW(OF_BSWAP32(OF_FLOAT_TO_INT_RAW(f))); + return OFRawUInt32ToFloat(OFByteSwap32(OFFloatToRawUInt32(f))); } static OF_INLINE double OF_CONST_FUNC -OF_BSWAP_DOUBLE(double d) +OFByteSwapDouble(double d) { - return OF_INT_TO_DOUBLE_RAW(OF_BSWAP64(OF_DOUBLE_TO_INT_RAW(d))); + return OFRawUInt64ToDouble(OFByteSwap64(OFDoubleToRawUInt64(d))); } #ifdef OF_BIG_ENDIAN -# define OF_BSWAP16_IF_BE(i) OF_BSWAP16(i) -# define OF_BSWAP32_IF_BE(i) OF_BSWAP32(i) -# define OF_BSWAP64_IF_BE(i) OF_BSWAP64(i) -# define OF_BSWAP16_IF_LE(i) (i) -# define OF_BSWAP32_IF_LE(i) (i) -# define OF_BSWAP64_IF_LE(i) (i) +# define OFFromBigEndian16(i) (i) +# define OFFromBigEndian32(i) (i) +# define OFFromBigEndian64(i) (i) +# define OFFromLittleEndian16(i) OFByteSwap16(i) +# define OFFromLittleEndian32(i) OFByteSwap32(i) +# define OFFromLittleEndian64(i) OFByteSwap64(i) +# define OFToBigEndian16(i) (i) +# define OFToBigEndian32(i) (i) +# define OFToBigEndian64(i) (i) +# define OFToLittleEndian16(i) OFByteSwap16(i) +# define OFToLittleEndian32(i) OFByteSwap32(i) +# define OFToLittleEndian64(i) OFByteSwap64(i) #else -# define OF_BSWAP16_IF_BE(i) (i) -# define OF_BSWAP32_IF_BE(i) (i) -# define OF_BSWAP64_IF_BE(i) (i) -# define OF_BSWAP16_IF_LE(i) OF_BSWAP16(i) -# define OF_BSWAP32_IF_LE(i) OF_BSWAP32(i) -# define OF_BSWAP64_IF_LE(i) OF_BSWAP64(i) +# define OFFromBigEndian16(i) OFByteSwap16(i) +# define OFFromBigEndian32(i) OFByteSwap32(i) +# define OFFromBigEndian64(i) OFByteSwap64(i) +# define OFFromLittleEndian16(i) (i) +# define OFFromLittleEndian32(i) (i) +# define OFFromLittleEndian64(i) (i) +# define OFToBigEndian16(i) OFByteSwap16(i) +# define OFToBigEndian32(i) OFByteSwap32(i) +# define OFToBigEndian64(i) OFByteSwap64(i) +# define OFToLittleEndian16(i) (i) +# define OFToLittleEndian32(i) (i) +# define OFToLittleEndian64(i) (i) #endif #ifdef OF_FLOAT_BIG_ENDIAN -# define OF_BSWAP_FLOAT_IF_BE(i) OF_BSWAP_FLOAT(i) -# define OF_BSWAP_DOUBLE_IF_BE(i) OF_BSWAP_DOUBLE(i) -# define OF_BSWAP_FLOAT_IF_LE(i) (i) -# define OF_BSWAP_DOUBLE_IF_LE(i) (i) +# define OFFromBigEndianFloat(f) (f) +# define OFFromBigEndianDouble(d) (d) +# define OFFromLittleEndianFloat(f) OFByteSwapFloat(f) +# define OFFromLittleEndianDouble(d) OFByteSwapDouble(d) +# define OFToBigEndianFloat(f) (f) +# define OFToBigEndianDouble(d) (d) +# define OFToLittleEndianFloat(f) OFByteSwapFloat(f) +# define OFToLittleEndianDouble(d) OFByteSwapDouble(d) #else -# define OF_BSWAP_FLOAT_IF_BE(i) (i) -# define OF_BSWAP_DOUBLE_IF_BE(i) (i) -# define OF_BSWAP_FLOAT_IF_LE(i) OF_BSWAP_FLOAT(i) -# define OF_BSWAP_DOUBLE_IF_LE(i) OF_BSWAP_DOUBLE(i) +# define OFFromBigEndianFloat(f) OFByteSwapFloat(f) +# define OFFromBigEndianDouble(d) OFByteSwapDouble(d) +# define OFFromLittleEndianFloat(f) (f) +# define OFFromLittleEndianDouble(d) (d) +# define OFToBigEndianFloat(f) OFByteSwapFloat(f) +# define OFToBigEndianDouble(d) OFByteSwapDouble(d) +# define OFToLittleEndianFloat(f) (f) +# define OFToLittleEndianDouble(d) (d) #endif -static OF_INLINE uint16_t -of_be16_ptr_read(void *_Nonnull ptr) -{ - uint16_t value; - memcpy(&value, ptr, sizeof(value)); - return OF_BSWAP16_IF_LE(value); -} - -static OF_INLINE uint32_t -of_be32_ptr_read(void *_Nonnull ptr) -{ - uint32_t value; - memcpy(&value, ptr, sizeof(value)); - return OF_BSWAP32_IF_LE(value); -} - -static OF_INLINE uint64_t -of_be64_ptr_read(void *_Nonnull ptr) -{ - uint64_t value; - memcpy(&value, ptr, sizeof(value)); - return OF_BSWAP64_IF_LE(value); -} - -static OF_INLINE float -of_be_float_ptr_read(void *_Nonnull ptr) -{ - float value; - memcpy(&value, ptr, sizeof(value)); - return OF_BSWAP_FLOAT_IF_LE(value); -} - -static OF_INLINE double -of_be_double_ptr_read(void *_Nonnull ptr) -{ - double value; - memcpy(&value, ptr, sizeof(value)); - return OF_BSWAP_DOUBLE_IF_LE(value); -} - -static OF_INLINE uint16_t -of_le16_ptr_read(void *_Nonnull ptr) -{ - uint16_t value; - memcpy(&value, ptr, sizeof(value)); - return OF_BSWAP16_IF_BE(value); -} - -static OF_INLINE uint32_t -of_le32_ptr_read(void *_Nonnull ptr) -{ - uint32_t value; - memcpy(&value, ptr, sizeof(value)); - return OF_BSWAP32_IF_BE(value); -} - -static OF_INLINE uint64_t -of_le64_ptr_read(void *_Nonnull ptr) -{ - uint64_t value; - memcpy(&value, ptr, sizeof(value)); - return OF_BSWAP64_IF_BE(value); -} - -static OF_INLINE float -of_le_float_ptr_read(void *_Nonnull ptr) -{ - float value; - memcpy(&value, ptr, sizeof(value)); - return OF_BSWAP_FLOAT_IF_BE(value); -} - -static OF_INLINE double -of_le_double_ptr_read(void *_Nonnull ptr) -{ - double value; - memcpy(&value, ptr, sizeof(value)); - return OF_BSWAP_DOUBLE_IF_BE(value); -} - -static OF_INLINE void -of_be16_ptr_write(void *_Nonnull ptr, uint16_t value) -{ - value = OF_BSWAP16_IF_LE(value); - memcpy(ptr, &value, sizeof(value)); -} - -static OF_INLINE void -of_be32_ptr_write(void *_Nonnull ptr, uint32_t value) -{ - value = OF_BSWAP32_IF_LE(value); - memcpy(ptr, &value, sizeof(value)); -} - -static OF_INLINE void -of_be64_ptr_write(void *_Nonnull ptr, uint64_t value) -{ - value = OF_BSWAP64_IF_LE(value); - memcpy(ptr, &value, sizeof(value)); -} - -static OF_INLINE void -of_be_float_ptr_write(void *_Nonnull ptr, float value) -{ - value = OF_BSWAP_FLOAT_IF_LE(value); - memcpy(ptr, &value, sizeof(value)); -} - -static OF_INLINE void -of_be_double_ptr_write(void *_Nonnull ptr, double value) -{ - value = OF_BSWAP_DOUBLE_IF_LE(value); - memcpy(ptr, &value, sizeof(value)); -} - -static OF_INLINE void -of_le16_ptr_write(void *_Nonnull ptr, uint16_t value) -{ - value = OF_BSWAP16_IF_BE(value); - memcpy(ptr, &value, sizeof(value)); -} - -static OF_INLINE void -of_le32_ptr_write(void *_Nonnull ptr, uint32_t value) -{ - value = OF_BSWAP32_IF_BE(value); - memcpy(ptr, &value, sizeof(value)); -} - -static OF_INLINE void -of_le64_ptr_write(void *_Nonnull ptr, uint64_t value) -{ - value = OF_BSWAP64_IF_BE(value); - memcpy(ptr, &value, sizeof(value)); -} - -static OF_INLINE void -of_le_float_ptr_write(void *_Nonnull ptr, float value) -{ - value = OF_BSWAP_FLOAT_IF_BE(value); - memcpy(ptr, &value, sizeof(value)); -} - -static OF_INLINE void -of_le_double_ptr_write(void *_Nonnull ptr, double value) -{ - value = OF_BSWAP_DOUBLE_IF_BE(value); - memcpy(ptr, &value, sizeof(value)); -} - -#define OF_ROL(value, bits) \ +#define OFRotateLeft(value, bits) \ (((bits) % (sizeof(value) * 8)) > 0 \ ? ((value) << ((bits) % (sizeof(value) * 8))) | \ ((value) >> (sizeof(value) * 8 - ((bits) % (sizeof(value) * 8)))) \ : (value)) -#define OF_ROR(value, bits) \ +#define OFRotateRight(value, bits) \ (((bits) % (sizeof(value) * 8)) > 0 \ ? ((value) >> ((bits) % (sizeof(value) * 8))) | \ ((value) << (sizeof(value) * 8 - ((bits) % (sizeof(value) * 8)))) \ : (value)) -#define OF_ROUND_UP_POW2(pow2, value) (((value) + (pow2) - 1) & ~((pow2) - 1)) - -#define OF_HASH_INIT(hash) hash = of_hash_seed; -#define OF_HASH_ADD(hash, byte) \ - { \ - hash += (uint8_t)(byte); \ - hash += (hash << 10); \ - hash ^= (hash >> 6); \ - } -#define OF_HASH_FINALIZE(hash) \ - { \ - hash += (hash << 3); \ - hash ^= (hash >> 11); \ - hash += (hash << 15); \ - } -#define OF_HASH_ADD_HASH(hash, other) \ - { \ - uint32_t otherCopy = (uint32_t)other; \ - OF_HASH_ADD(hash, (otherCopy >> 24) & 0xFF); \ - OF_HASH_ADD(hash, (otherCopy >> 16) & 0xFF); \ - OF_HASH_ADD(hash, (otherCopy >> 8) & 0xFF); \ - OF_HASH_ADD(hash, otherCopy & 0xFF); \ - } - -static OF_INLINE bool -of_bitset_isset(unsigned char *_Nonnull storage, size_t idx) -{ - return storage[idx / 8] & (1u << (idx % 8)); -} - -static OF_INLINE void -of_bitset_set(unsigned char *_Nonnull storage, size_t idx) -{ - storage[idx / 8] |= (1u << (idx % 8)); -} - -static OF_INLINE void -of_bitset_clear(unsigned char *_Nonnull storage, size_t idx) -{ - storage[idx / 8] &= ~(1u << (idx % 8)); -} - -static OF_INLINE char *_Nullable -of_strdup(const char *_Nonnull string) -{ - char *copy; - size_t length = strlen(string); - - if ((copy = (char *)malloc(length + 1)) == NULL) - return NULL; - - memcpy(copy, string, length + 1); - - return copy; -} - -static OF_INLINE void -of_explicit_memset(void *_Nonnull buffer_, int character, size_t length) +#define OFRoundUpToPowerOf2(pow2, value) \ + (((value) + (pow2) - 1) & ~((pow2) - 1)) + +static OF_INLINE bool +OFBitsetIsSet(unsigned char *_Nonnull storage, size_t idx) +{ + return storage[idx / CHAR_BIT] & (1u << (idx % CHAR_BIT)); +} + +static OF_INLINE void +OFBitsetSet(unsigned char *_Nonnull storage, size_t idx) +{ + storage[idx / CHAR_BIT] |= (1u << (idx % CHAR_BIT)); +} + +static OF_INLINE void +OFBitsetClear(unsigned char *_Nonnull storage, size_t idx) +{ + storage[idx / CHAR_BIT] &= ~(1u << (idx % CHAR_BIT)); +} + +static OF_INLINE void +OFZeroMemory(void *_Nonnull buffer_, size_t length) { volatile unsigned char *buffer = (volatile unsigned char *)buffer_; while (buffer < (unsigned char *)buffer_ + length) - *buffer++ = character; + *buffer++ = '\0'; } static OF_INLINE bool -of_ascii_isalpha(char c) +OFASCIIIsAlpha(char c) { return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')); } static OF_INLINE bool -of_ascii_isdigit(char c) +OFASCIIIsDigit(char c) { return (c >= '0' && c <= '9'); } static OF_INLINE bool -of_ascii_isalnum(char c) +OFASCIIIsAlnum(char c) { - return (of_ascii_isalpha(c) || of_ascii_isdigit(c)); + return (OFASCIIIsAlpha(c) || OFASCIIIsDigit(c)); } static OF_INLINE bool -of_ascii_isspace(char c) +OFASCIIIsSpace(char c) { return (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v'); } static OF_INLINE char -of_ascii_toupper(char c) +OFASCIIToUpper(char c) { return (c >= 'a' && c <= 'z' ? 'A' + (c - 'a') : c); } static OF_INLINE char -of_ascii_tolower(char c) +OFASCIIToLower(char c) { return (c >= 'A' && c <= 'Z' ? 'a' + (c - 'A') : c); } #endif Index: src/module.modulemap ================================================================== --- src/module.modulemap +++ src/module.modulemap @@ -1,16 +1,15 @@ framework module ObjFW { umbrella header "ObjFW.h" /* - * These are included by atomic.h, but should never be included + * These are included by OFAtomic.h, but should never be included * directly. */ - exclude header "atomic_builtins.h" - exclude header "atomic_no_threads.h" - exclude header "atomic_osatomic.h" - exclude header "atomic_powerpc.h" - exclude header "atomic_sync_builtins.h" - exclude header "atomic_x86.h" + exclude header "platform/GCC4/OFAtomic.h" + exclude header "platform/GCC4.7/OFAtomic.h" + exclude header "platform/PowerPC/OFAtomic.h" + exclude header "platform/macOS/OFAtomic.h" + exclude header "platform/x86/OFAtomic.h" export * } DELETED src/mutex.h Index: src/mutex.h ================================================================== --- src/mutex.h +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "objfw-defs.h" - -#include "platform.h" - -#if !defined(OF_HAVE_THREADS) || \ - (!defined(OF_HAVE_PTHREADS) && !defined(OF_WINDOWS) && !defined(OF_AMIGAOS)) -# error No mutexes available! -#endif - -#import "macros.h" - -#if defined(OF_HAVE_PTHREADS) -# include -typedef pthread_mutex_t of_mutex_t; -#elif defined(OF_WINDOWS) -# include -typedef CRITICAL_SECTION of_mutex_t; -#elif defined(OF_AMIGAOS) -# include -typedef struct SignalSemaphore of_mutex_t; -#endif - -#if defined(OF_HAVE_ATOMIC_OPS) -# import "atomic.h" -typedef volatile int of_spinlock_t; -# define OF_SPINCOUNT 10 -#elif defined(OF_HAVE_PTHREAD_SPINLOCKS) -typedef pthread_spinlock_t of_spinlock_t; -#else -typedef of_mutex_t of_spinlock_t; -#endif - -#ifdef OF_HAVE_SCHED_YIELD -# include -#endif - -#if defined(OF_HAVE_RECURSIVE_PTHREAD_MUTEXES) || defined(OF_WINDOWS) || \ - defined(OF_AMIGAOS) -# define of_rmutex_t of_mutex_t -#else -# import "tlskey.h" -typedef struct { - of_mutex_t mutex; - of_tlskey_t count; -} of_rmutex_t; -#endif - -#ifdef __cplusplus -extern "C" { -#endif -extern bool of_mutex_new(of_mutex_t *mutex); -extern bool of_mutex_lock(of_mutex_t *mutex); -extern bool of_mutex_trylock(of_mutex_t *mutex); -extern bool of_mutex_unlock(of_mutex_t *mutex); -extern bool of_mutex_free(of_mutex_t *mutex); -extern bool of_rmutex_new(of_rmutex_t *rmutex); -extern bool of_rmutex_lock(of_rmutex_t *rmutex); -extern bool of_rmutex_trylock(of_rmutex_t *rmutex); -extern bool of_rmutex_unlock(of_rmutex_t *rmutex); -extern bool of_rmutex_free(of_rmutex_t *rmutex); -#ifdef __cplusplus -} -#endif - -/* Spinlocks are inlined for performance. */ - -static OF_INLINE void -of_thread_yield(void) -{ -#if defined(OF_HAVE_SCHED_YIELD) - sched_yield(); -#elif defined(OF_WINDOWS) - Sleep(0); -#endif -} - -static OF_INLINE bool -of_spinlock_new(of_spinlock_t *spinlock) -{ -#if defined(OF_HAVE_ATOMIC_OPS) - *spinlock = 0; - return true; -#elif defined(OF_HAVE_PTHREAD_SPINLOCKS) - return (pthread_spin_init(spinlock, 0) == 0); -#else - return of_mutex_new(spinlock); -#endif -} - -static OF_INLINE bool -of_spinlock_trylock(of_spinlock_t *spinlock) -{ -#if defined(OF_HAVE_ATOMIC_OPS) - if (of_atomic_int_cmpswap(spinlock, 0, 1)) { - of_memory_barrier_acquire(); - return true; - } - - return false; -#elif defined(OF_HAVE_PTHREAD_SPINLOCKS) - return (pthread_spin_trylock(spinlock) == 0); -#else - return of_mutex_trylock(spinlock); -#endif -} - -static OF_INLINE bool -of_spinlock_lock(of_spinlock_t *spinlock) -{ -#if defined(OF_HAVE_ATOMIC_OPS) - size_t i; - - for (i = 0; i < OF_SPINCOUNT; i++) - if (of_spinlock_trylock(spinlock)) - return true; - - while (!of_spinlock_trylock(spinlock)) - of_thread_yield(); - - return true; -#elif defined(OF_HAVE_PTHREAD_SPINLOCKS) - return (pthread_spin_lock(spinlock) == 0); -#else - return of_mutex_lock(spinlock); -#endif -} - -static OF_INLINE bool -of_spinlock_unlock(of_spinlock_t *spinlock) -{ -#if defined(OF_HAVE_ATOMIC_OPS) - bool ret = of_atomic_int_cmpswap(spinlock, 1, 0); - - of_memory_barrier_release(); - - return ret; -#elif defined(OF_HAVE_PTHREAD_SPINLOCKS) - return (pthread_spin_unlock(spinlock) == 0); -#else - return of_mutex_unlock(spinlock); -#endif -} - -static OF_INLINE bool -of_spinlock_free(of_spinlock_t *spinlock) -{ -#if defined(OF_HAVE_ATOMIC_OPS) - return true; -#elif defined(OF_HAVE_PTHREAD_SPINLOCKS) - return (pthread_spin_destroy(spinlock) == 0); -#else - return of_mutex_free(spinlock); -#endif -} DELETED src/mutex.m Index: src/mutex.m ================================================================== --- src/mutex.m +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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" - -#if defined(OF_HAVE_PTHREADS) -# include "platform/posix/mutex.m" -#elif defined(OF_WINDOWS) -# include "platform/windows/mutex.m" -#elif defined(OF_AMIGAOS) -# include "platform/amiga/mutex.m" -#endif Index: src/objfw-defs.h.in ================================================================== --- src/objfw-defs.h.in +++ src/objfw-defs.h.in @@ -1,11 +1,9 @@ -#undef INFINITY -#undef LLONG_MAX -#undef LLONG_MIN #undef OF_APPLE_RUNTIME #undef OF_BIG_ENDIAN #undef OF_FLOAT_BIG_ENDIAN +#undef OF_HAVE_AFUNIX_H #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 @@ -17,19 +15,18 @@ #undef OF_HAVE_IPX #undef OF_HAVE_LIMITS_H #undef OF_HAVE_LINK #undef OF_HAVE_MAX_ALIGN_T #undef OF_HAVE_NETINET_IN_H -#undef OF_HAVE_NETINET_SCTP_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_PROCESSES +#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_SOCKETS @@ -36,19 +33,17 @@ #undef OF_HAVE_STDNORETURN #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 #undef OF_HAVE_THREADS #undef OF_HAVE_UNICODE_TABLES +#undef OF_HAVE_UNIX_SOCKETS #undef OF_HAVE__THREAD_LOCAL #undef OF_HAVE___THREAD #undef OF_NINTENDO_3DS #undef OF_NINTENDO_DS #undef OF_NO_SHARED #undef OF_OBJFW_RUNTIME #undef OF_UNIVERSAL #undef OF_WII -#undef SIZE_MAX -#undef UINTPTR_MAX -#undef ULLONG_MAX -#undef __have_longlong64 DELETED src/of_asprintf.h Index: src/of_asprintf.h ================================================================== --- src/of_asprintf.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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. - */ - -#ifndef __STDC_LIMIT_MACROS -# define __STDC_LIMIT_MACROS -#endif -#ifndef __STDC_CONSTANT_MACROS -# define __STDC_CONSTANT_MACROS -#endif - -#include - -#import "macros.h" - -OF_ASSUME_NONNULL_BEGIN - -#ifdef __cplusplus -extern "C" { -#endif -extern int of_asprintf( - char *_Nullable *_Nonnull, const char *_Nonnull, ...); -extern int of_vasprintf( - char *_Nullable *_Nonnull, const char *_Nonnull, va_list); -#ifdef __cplusplus -} -#endif - -OF_ASSUME_NONNULL_END DELETED src/of_asprintf.m Index: src/of_asprintf.m ================================================================== --- src/of_asprintf.m +++ /dev/null @@ -1,801 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 -#include -#include - -#ifdef HAVE_WCHAR_H -# include -#endif - -#ifdef HAVE_ASPRINTF_L -# include -#endif -#ifdef HAVE_XLOCALE_H -# include -#endif - -#ifdef OF_HAVE_SYS_TYPES_H -# include -#endif - -#import "OFString.h" -#import "OFLocale.h" - -#import "OFInitializationFailedException.h" - -#define MAX_SUBFORMAT_LEN 64 - -#ifndef HAVE_ASPRINTF -/* - * (v)asprintf might be declared, but HAVE_ASPRINTF not defined because - * configure determined it is broken. In this case, we must make sure there is - * no name clash. - */ -# define asprintf asprintf_ -# define vasprintf vasprintf_ -#endif - -struct context { - const char *format; - size_t formatLen; - char subformat[MAX_SUBFORMAT_LEN + 1]; - size_t subformatLen; - va_list arguments; - char *buffer; - size_t bufferLen; - size_t i, last; - enum { - STATE_STRING, - STATE_FORMAT_FLAGS, - STATE_FORMAT_FIELD_WIDTH, - STATE_FORMAT_LENGTH_MODIFIER, - STATE_FORMAT_CONVERSION_SPECIFIER - } state; - enum { - LENGTH_MODIFIER_NONE, - LENGTH_MODIFIER_HH, - LENGTH_MODIFIER_H, - LENGTH_MODIFIER_L, - LENGTH_MODIFIER_LL, - LENGTH_MODIFIER_J, - LENGTH_MODIFIER_Z, - LENGTH_MODIFIER_T, - LENGTH_MODIFIER_CAPITAL_L - } lengthModifier; - bool useLocale; -}; - -#ifdef HAVE_ASPRINTF_L -static locale_t cLocale; - -OF_CONSTRUCTOR() -{ - if ((cLocale = newlocale(LC_ALL_MASK, "C", NULL)) == NULL) - @throw [OFInitializationFailedException exception]; -} -#endif - -#ifndef HAVE_ASPRINTF -static int -vasprintf(char **string, const char *format, va_list arguments) -{ - int expectedLength, length; - va_list argumentsCopy; - - va_copy(argumentsCopy, arguments); - - expectedLength = vsnprintf(NULL, 0, format, argumentsCopy); - if (expectedLength == -1) - /* - * We have no way to know how large it is. Let's try 64 KB and - * hope. - */ - expectedLength = 65535; - - if ((*string = malloc((size_t)expectedLength + 1)) == NULL) - return -1; - - length = vsnprintf(*string, (size_t)expectedLength + 1, - format, arguments); - - if (length == -1 || length > expectedLength) { - free(*string); - *string = NULL; - return -1; - } - - /* - * In case we could not determine the size, resize to the actual size - * needed, but ignore any failure to do so. - */ - if (length < expectedLength) { - char *resized; - - if ((resized = realloc(*string, length + 1)) != NULL) - *string = resized; - } - - return length; -} - -static int -asprintf(char **string, const char *format, ...) -{ - int ret; - va_list arguments; - - va_start(arguments, format); - ret = vasprintf(string, format, arguments); - va_end(arguments); - - return ret; -} -#endif - -static bool -appendString(struct context *ctx, const char *append, size_t appendLen) -{ - char *newBuf; - - if (appendLen == 0) - return true; - - if ((newBuf = realloc(ctx->buffer, - ctx->bufferLen + appendLen + 1)) == NULL) - return false; - - memcpy(newBuf + ctx->bufferLen, append, appendLen); - - ctx->buffer = newBuf; - ctx->bufferLen += appendLen; - - return true; -} - -static bool -appendSubformat(struct context *ctx, const char *subformat, - size_t subformatLen) -{ - if (ctx->subformatLen + subformatLen > MAX_SUBFORMAT_LEN) - return false; - - memcpy(ctx->subformat + ctx->subformatLen, subformat, subformatLen); - ctx->subformatLen += subformatLen; - ctx->subformat[ctx->subformatLen] = 0; - - return true; -} - -static bool -stringState(struct context *ctx) -{ - if (ctx->format[ctx->i] == '%') { - if (ctx->i > 0) - if (!appendString(ctx, ctx->format + ctx->last, - ctx->i - ctx->last)) - return false; - - if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) - return false; - - ctx->last = ctx->i + 1; - ctx->state = STATE_FORMAT_FLAGS; - } - - return true; -} - -static bool -formatFlagsState(struct context *ctx) -{ - switch (ctx->format[ctx->i]) { - case '-': - case '+': - case ' ': - case '#': - case '0': - if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) - return false; - - break; - case ',': - /* ObjFW extension: Use decimal point from locale */ - ctx->useLocale = true; - break; - default: - ctx->state = STATE_FORMAT_FIELD_WIDTH; - ctx->i--; - - break; - } - - return true; -} - -static bool -formatFieldWidthState(struct context *ctx) -{ - if ((ctx->format[ctx->i] >= '0' && ctx->format[ctx->i] <= '9') || - ctx->format[ctx->i] == '*' || ctx->format[ctx->i] == '.') { - if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) - return false; - } else { - ctx->state = STATE_FORMAT_LENGTH_MODIFIER; - ctx->i--; - } - - return true; -} - -static bool -formatLengthModifierState(struct context *ctx) -{ - /* Only one allowed */ - switch (ctx->format[ctx->i]) { - case 'h': /* and also hh */ - if (ctx->formatLen > ctx->i + 1 && - ctx->format[ctx->i + 1] == 'h') { - if (!appendSubformat(ctx, ctx->format + ctx->i, 2)) - return false; - - ctx->i++; - ctx->lengthModifier = LENGTH_MODIFIER_HH; - } else { - if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) - return false; - - ctx->lengthModifier = LENGTH_MODIFIER_H; - } - - break; - case 'l': /* and also ll */ - if (ctx->formatLen > ctx->i + 1 && - ctx->format[ctx->i + 1] == 'l') { -#ifndef OF_WINDOWS - if (!appendSubformat(ctx, ctx->format + ctx->i, 2)) - return false; -#else - if (!appendSubformat(ctx, "I64", 3)) - return false; -#endif - - ctx->i++; - ctx->lengthModifier = LENGTH_MODIFIER_LL; - } else { - if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) - return false; - - ctx->lengthModifier = LENGTH_MODIFIER_L; - } - - break; - case 'j': -#if defined(OF_WINDOWS) - if (!appendSubformat(ctx, "I64", 3)) - return false; -#elif defined(_NEWLIB_VERSION) - if (!appendSubformat(ctx, "ll", 2)) - return false; -#else - if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) - return false; -#endif - - ctx->lengthModifier = LENGTH_MODIFIER_J; - - break; - case 'z': -#if defined(OF_WINDOWS) - if (sizeof(size_t) == 8) - if (!appendSubformat(ctx, "I64", 3)) - return false; -#elif defined(_NEWLIB_VERSION) - if (!appendSubformat(ctx, "l", 1)) - return false; -#else - if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) - return false; -#endif - - ctx->lengthModifier = LENGTH_MODIFIER_Z; - - break; - case 't': -#if defined(OF_WINDOWS) - if (sizeof(ptrdiff_t) == 8) - if (!appendSubformat(ctx, "I64", 3)) - return false; -#elif defined(_NEWLIB_VERSION) - if (!appendSubformat(ctx, "l", 1)) - return false; -#else - if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) - return false; -#endif - - ctx->lengthModifier = LENGTH_MODIFIER_T; - - break; - case 'L': - if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) - return false; - - ctx->lengthModifier = LENGTH_MODIFIER_CAPITAL_L; - - break; -#ifdef OF_WINDOWS - case 'I': /* win32 strangeness (I64 instead of ll or j) */ - if (ctx->formatLen > ctx->i + 2 && - ctx->format[ctx->i + 1] == '6' && - ctx->format[ctx->i + 2] == '4') { - if (!appendSubformat(ctx, ctx->format + ctx->i, 3)) - return false; - - ctx->i += 2; - ctx->lengthModifier = LENGTH_MODIFIER_LL; - } else - ctx->i--; - - break; -#endif -#ifdef OF_IOS - case 'q': /* iOS uses this for PRI?64 */ - if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) - return false; - - ctx->lengthModifier = LENGTH_MODIFIER_LL; - - break; -#endif - default: - ctx->i--; - - break; - } - - ctx->state = STATE_FORMAT_CONVERSION_SPECIFIER; - return true; -} - -static bool -formatConversionSpecifierState(struct context *ctx) -{ - char *tmp = NULL; - int tmpLen = 0; -#ifndef HAVE_ASPRINTF_L - OFString *point; -#endif - - if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) - return false; - - switch (ctx->format[ctx->i]) { - case '@': - if (ctx->lengthModifier != LENGTH_MODIFIER_NONE) - return false; - - ctx->subformat[ctx->subformatLen - 1] = 's'; - - @try { - id object; - - if ((object = va_arg(ctx->arguments, id)) != nil) { - void *pool = objc_autoreleasePoolPush(); - - tmpLen = asprintf(&tmp, ctx->subformat, - [object description].UTF8String); - - objc_autoreleasePoolPop(pool); - } else - tmpLen = asprintf(&tmp, ctx->subformat, - "(nil)"); - } @catch (id e) { - free(ctx->buffer); - @throw e; - } - - break; - case 'C': - if (ctx->lengthModifier != LENGTH_MODIFIER_NONE) - return false; - - ctx->subformat[ctx->subformatLen - 1] = 's'; - - { - char buffer[5]; - size_t len = of_string_utf8_encode( - va_arg(ctx->arguments, of_unichar_t), buffer); - - if (len == 0) - return false; - - buffer[len] = 0; - tmpLen = asprintf(&tmp, ctx->subformat, buffer); - } - - break; - case 'S': - if (ctx->lengthModifier != LENGTH_MODIFIER_NONE) - return false; - - ctx->subformat[ctx->subformatLen - 1] = 's'; - - { - const of_unichar_t *arg = - va_arg(ctx->arguments, const of_unichar_t *); - size_t j, len = of_string_utf32_length(arg); - char *buffer; - - if (SIZE_MAX / 4 < len || (SIZE_MAX / 4) - len < 1) - return false; - - if ((buffer = malloc((len * 4) + 1)) == NULL) - return false; - - j = 0; - for (size_t i = 0; i < len; i++) { - size_t clen = of_string_utf8_encode(arg[i], - buffer + j); - - if (clen == 0) { - free(buffer); - return false; - } - - j += clen; - } - buffer[j] = 0; - - tmpLen = asprintf(&tmp, ctx->subformat, buffer); - - free(buffer); - } - - break; - case 'd': - case 'i': - switch (ctx->lengthModifier) { - case LENGTH_MODIFIER_NONE: - case LENGTH_MODIFIER_HH: - case LENGTH_MODIFIER_H: - tmpLen = asprintf(&tmp, ctx->subformat, - va_arg(ctx->arguments, int)); - break; - case LENGTH_MODIFIER_L: - tmpLen = asprintf(&tmp, ctx->subformat, - va_arg(ctx->arguments, long)); - break; - case LENGTH_MODIFIER_LL: - tmpLen = asprintf(&tmp, ctx->subformat, - va_arg(ctx->arguments, long long)); - break; - case LENGTH_MODIFIER_J: - tmpLen = asprintf(&tmp, ctx->subformat, - va_arg(ctx->arguments, intmax_t)); - break; - case LENGTH_MODIFIER_Z: - tmpLen = asprintf(&tmp, ctx->subformat, - va_arg(ctx->arguments, ssize_t)); - break; - case LENGTH_MODIFIER_T: - tmpLen = asprintf(&tmp, ctx->subformat, - va_arg(ctx->arguments, ptrdiff_t)); - break; - default: - return false; - } - - break; - case 'o': - case 'u': - case 'x': - case 'X': - switch (ctx->lengthModifier) { - case LENGTH_MODIFIER_NONE: - case LENGTH_MODIFIER_HH: - case LENGTH_MODIFIER_H: - tmpLen = asprintf(&tmp, ctx->subformat, - va_arg(ctx->arguments, unsigned int)); - break; - case LENGTH_MODIFIER_L: - tmpLen = asprintf(&tmp, ctx->subformat, - va_arg(ctx->arguments, unsigned long)); - break; - case LENGTH_MODIFIER_LL: - tmpLen = asprintf(&tmp, ctx->subformat, - va_arg(ctx->arguments, unsigned long long)); - break; - case LENGTH_MODIFIER_J: - tmpLen = asprintf(&tmp, ctx->subformat, - va_arg(ctx->arguments, uintmax_t)); - break; - case LENGTH_MODIFIER_Z: - tmpLen = asprintf(&tmp, ctx->subformat, - va_arg(ctx->arguments, size_t)); - break; - case LENGTH_MODIFIER_T: - tmpLen = asprintf(&tmp, ctx->subformat, - va_arg(ctx->arguments, ptrdiff_t)); - break; - default: - return false; - } - - break; - case 'f': - case 'F': - case 'e': - case 'E': - case 'g': - case 'G': - case 'a': - case 'A': - switch (ctx->lengthModifier) { - case LENGTH_MODIFIER_NONE: - case LENGTH_MODIFIER_L: -#ifdef HAVE_ASPRINTF_L - if (!ctx->useLocale) - tmpLen = asprintf_l(&tmp, cLocale, - ctx->subformat, - va_arg(ctx->arguments, double)); - else -#endif - tmpLen = asprintf(&tmp, ctx->subformat, - va_arg(ctx->arguments, double)); - break; - case LENGTH_MODIFIER_CAPITAL_L: -#ifdef HAVE_ASPRINTF_L - if (!ctx->useLocale) - tmpLen = asprintf_l(&tmp, cLocale, - ctx->subformat, - va_arg(ctx->arguments, long double)); - else -#endif - tmpLen = asprintf(&tmp, ctx->subformat, - va_arg(ctx->arguments, long double)); - break; - default: - return false; - } - -#ifndef HAVE_ASPRINTF_L - 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 ".". - */ - point = [OFLocale decimalPoint]; - - if (!ctx->useLocale && point != nil && ![point isEqual: @"."]) { - void *pool = objc_autoreleasePoolPush(); - char *tmp2; - - @try { - OFMutableString *tmpStr = [OFMutableString - stringWithUTF8String: tmp - length: tmpLen]; - [tmpStr replaceOccurrencesOfString: point - withString: @"."]; - - if (tmpStr.UTF8StringLength > INT_MAX) - return false; - - tmpLen = (int)tmpStr.UTF8StringLength; - tmp2 = malloc(tmpLen); - memcpy(tmp2, tmpStr.UTF8String, tmpLen); - } @finally { - free(tmp); - objc_autoreleasePoolPop(pool); - } - - tmp = tmp2; - } -#endif - - break; - case 'c': - switch (ctx->lengthModifier) { - case LENGTH_MODIFIER_NONE: - tmpLen = asprintf(&tmp, ctx->subformat, - va_arg(ctx->arguments, int)); - break; - case LENGTH_MODIFIER_L: -#ifdef HAVE_WCHAR_H -# if WINT_MAX >= INT_MAX - tmpLen = asprintf(&tmp, ctx->subformat, - va_arg(ctx->arguments, wint_t)); -# else - tmpLen = asprintf(&tmp, ctx->subformat, - va_arg(ctx->arguments, int)); -# endif - break; -#endif - default: - return false; - } - - break; - case 's': - switch (ctx->lengthModifier) { - case LENGTH_MODIFIER_NONE: - tmpLen = asprintf(&tmp, ctx->subformat, - va_arg(ctx->arguments, const char *)); - break; -#ifdef HAVE_WCHAR_T - case LENGTH_MODIFIER_L: - tmpLen = asprintf(&tmp, ctx->subformat, - va_arg(ctx->arguments, const wchar_t *)); - break; -#endif - default: - return false; - } - - break; - case 'p': - if (ctx->lengthModifier != LENGTH_MODIFIER_NONE) - return false; - - tmpLen = asprintf(&tmp, ctx->subformat, - va_arg(ctx->arguments, void *)); - - break; - case 'n': - switch (ctx->lengthModifier) { - case LENGTH_MODIFIER_NONE: - *va_arg(ctx->arguments, int *) = (int)ctx->bufferLen; - break; - case LENGTH_MODIFIER_HH: - *va_arg(ctx->arguments, signed char *) = - (signed char)ctx->bufferLen; - break; - case LENGTH_MODIFIER_H: - *va_arg(ctx->arguments, short *) = - (short)ctx->bufferLen; - break; - case LENGTH_MODIFIER_L: - *va_arg(ctx->arguments, long *) = - (long)ctx->bufferLen; - break; - case LENGTH_MODIFIER_LL: - *va_arg(ctx->arguments, long long *) = - (long long)ctx->bufferLen; - break; - case LENGTH_MODIFIER_J: - *va_arg(ctx->arguments, intmax_t *) = - (intmax_t)ctx->bufferLen; - break; - case LENGTH_MODIFIER_Z: - *va_arg(ctx->arguments, size_t *) = - (size_t)ctx->bufferLen; - break; - case LENGTH_MODIFIER_T: - *va_arg(ctx->arguments, ptrdiff_t *) = - (ptrdiff_t)ctx->bufferLen; - break; - default: - return false; - } - - break; - case '%': - if (ctx->lengthModifier != LENGTH_MODIFIER_NONE) - return false; - - if (!appendString(ctx, "%", 1)) - return false; - - break; - default: - return false; - } - - if (tmpLen == -1) - return false; - - if (tmp != NULL) { - if (!appendString(ctx, tmp, tmpLen)) { - free(tmp); - return false; - } - - free(tmp); - } - - memset(ctx->subformat, 0, MAX_SUBFORMAT_LEN); - ctx->subformatLen = 0; - ctx->lengthModifier = LENGTH_MODIFIER_NONE; - ctx->useLocale = false; - - ctx->last = ctx->i + 1; - ctx->state = STATE_STRING; - - return true; -} - -static bool (*states[])(struct context *) = { - stringState, - formatFlagsState, - formatFieldWidthState, - formatLengthModifierState, - formatConversionSpecifierState -}; - -int -of_vasprintf(char **string, const char *format, va_list arguments) -{ - struct context ctx; - - ctx.format = format; - ctx.formatLen = strlen(format); - memset(ctx.subformat, 0, MAX_SUBFORMAT_LEN + 1); - ctx.subformatLen = 0; - va_copy(ctx.arguments, arguments); - ctx.bufferLen = 0; - ctx.last = 0; - ctx.state = STATE_STRING; - ctx.lengthModifier = LENGTH_MODIFIER_NONE; - ctx.useLocale = false; - - if ((ctx.buffer = malloc(1)) == NULL) - return -1; - - for (ctx.i = 0; ctx.i < ctx.formatLen; ctx.i++) { - if (!states[ctx.state](&ctx)) { - free(ctx.buffer); - return -1; - } - } - - if (ctx.state != STATE_STRING) { - free(ctx.buffer); - return -1; - } - - if (!appendString(&ctx, ctx.format + ctx.last, - ctx.formatLen - ctx.last)) { - free(ctx.buffer); - return -1; - } - - ctx.buffer[ctx.bufferLen] = 0; - - *string = ctx.buffer; - return (ctx.bufferLen <= INT_MAX ? (int)ctx.bufferLen : -1); -} - -int -of_asprintf(char **string, const char *format, ...) -{ - va_list arguments; - int ret; - - va_start(arguments, format); - ret = of_vasprintf(string, format, arguments); - va_end(arguments); - - return ret; -} DELETED src/of_strptime.h Index: src/of_strptime.h ================================================================== --- src/of_strptime.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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. - */ - -#ifndef __STDC_LIMIT_MACROS -# define __STDC_LIMIT_MACROS -#endif -#ifndef __STDC_CONSTANT_MACROS -# define __STDC_CONSTANT_MACROS -#endif - -#include - -#import "macros.h" - -OF_ASSUME_NONNULL_BEGIN - -#ifdef __cplusplus -extern "C" { -#endif -extern const char *of_strptime(const char *buf, const char *fmt, struct tm *tm, - short *tz); -#ifdef __cplusplus -} -#endif - -OF_ASSUME_NONNULL_END DELETED src/of_strptime.m Index: src/of_strptime.m ================================================================== --- src/of_strptime.m +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "macros.h" - -const char * -of_strptime(const char *buffer, const char *format, struct tm *tm, short *tz) -{ - enum { - SEARCH_CONVERSION_SPECIFIER, - IN_CONVERSION_SPECIFIER - } state = SEARCH_CONVERSION_SPECIFIER; - size_t j, bufferLen, formatLen; - - bufferLen = strlen(buffer); - formatLen = strlen(format); - - j = 0; - for (size_t i = 0; i < formatLen; i++) { - if (j >= bufferLen) - return NULL; - - switch (state) { - case SEARCH_CONVERSION_SPECIFIER: - if (format[i] == '%') - state = IN_CONVERSION_SPECIFIER; - else if (format[i] != buffer[j++]) - return NULL; - - break; - - case IN_CONVERSION_SPECIFIER:; - int k, maxLen, number = 0; - - switch (format[i]) { - case 'd': - case 'e': - case 'H': - case 'm': - case 'M': - case 'S': - case 'y': - maxLen = 2; - break; - case 'Y': - maxLen = 4; - break; - case '%': - case 'a': - case 'b': - case 'n': - case 't': - case 'z': - maxLen = 0; - break; - default: - return NULL; - } - - if (maxLen > 0 && (buffer[j] < '0' || buffer[j] > '9')) - return NULL; - - for (k = 0; k < maxLen && j < bufferLen && - buffer[j] >= '0' && buffer[j] <= '9'; k++, j++) { - number *= 10; - number += buffer[j] - '0'; - } - - switch (format[i]) { - case 'a': - if (bufferLen < j + 3) - return NULL; - - if (memcmp(buffer + j, "Sun", 3) == 0) - tm->tm_wday = 0; - else if (memcmp(buffer + j, "Mon", 3) == 0) - tm->tm_wday = 1; - else if (memcmp(buffer + j, "Tue", 3) == 0) - tm->tm_wday = 2; - else if (memcmp(buffer + j, "Wed", 3) == 0) - tm->tm_wday = 3; - else if (memcmp(buffer + j, "Thu", 3) == 0) - tm->tm_wday = 4; - else if (memcmp(buffer + j, "Fri", 3) == 0) - tm->tm_wday = 5; - else if (memcmp(buffer + j, "Sat", 3) == 0) - tm->tm_wday = 6; - else - return NULL; - - j += 3; - break; - case 'b': - if (bufferLen < j + 3) - return NULL; - - if (memcmp(buffer + j, "Jan", 3) == 0) - tm->tm_mon = 0; - else if (memcmp(buffer + j, "Feb", 3) == 0) - tm->tm_mon = 1; - else if (memcmp(buffer + j, "Mar", 3) == 0) - tm->tm_mon = 2; - else if (memcmp(buffer + j, "Apr", 3) == 0) - tm->tm_mon = 3; - else if (memcmp(buffer + j, "May", 3) == 0) - tm->tm_mon = 4; - else if (memcmp(buffer + j, "Jun", 3) == 0) - tm->tm_mon = 5; - else if (memcmp(buffer + j, "Jul", 3) == 0) - tm->tm_mon = 6; - else if (memcmp(buffer + j, "Aug", 3) == 0) - tm->tm_mon = 7; - else if (memcmp(buffer + j, "Sep", 3) == 0) - tm->tm_mon = 8; - else if (memcmp(buffer + j, "Oct", 3) == 0) - tm->tm_mon = 9; - else if (memcmp(buffer + j, "Nov", 3) == 0) - tm->tm_mon = 10; - else if (memcmp(buffer + j, "Dec", 3) == 0) - tm->tm_mon = 11; - else - return NULL; - - j += 3; - break; - case 'd': - case 'e': - tm->tm_mday = number; - break; - case 'H': - tm->tm_hour = number; - break; - case 'm': - tm->tm_mon = number - 1; - break; - case 'M': - tm->tm_min = number; - break; - case 'S': - tm->tm_sec = number; - break; - case 'y': - if (number <= 68) - number += 100; - - tm->tm_year = number; - break; - case 'Y': - if (number < 1900) - return NULL; - - tm->tm_year = number - 1900; - break; - case 'z': - if (buffer[j] == '-' || buffer[j] == '+') { - const char *b = buffer + j; - - if (bufferLen < j + 5) - return NULL; - - if (tz == NULL) - break; - - *tz = (((short)b[1] - '0') * 600 + - ((short)b[2] - '0') * 60 + - ((short)b[3] - '0') * 10 + - ((short)b[4] - '0')) * - (b[0] == '-' ? -1 : 1); - - j += 5; - } else if (buffer[j] == 'Z') { - if (tz != NULL) - *tz = 0; - - j++; - } else if (buffer[j] == 'G') { - if (bufferLen < j + 3) - return NULL; - - if (buffer[j + 1] != 'M' || - buffer[j + 2] != 'T') - return NULL; - - if (tz != NULL) - *tz = 0; - - j += 3; - } else - return NULL; - - break; - case '%': - if (buffer[j++] != '%') - return NULL; - break; - case 'n': - if (buffer[j++] != '\n') - return NULL; - break; - case 't': - if (buffer[j++] != '\t') - return NULL; - break; - } - - state = SEARCH_CONVERSION_SPECIFIER; - - break; - } - } - - return buffer + j; -} DELETED src/once.h Index: src/once.h ================================================================== --- src/once.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "objfw-defs.h" - -#include "platform.h" - -#if defined(OF_HAVE_PTHREADS) -# include -typedef pthread_once_t of_once_t; -# define OF_ONCE_INIT PTHREAD_ONCE_INIT -#elif defined(OF_HAVE_ATOMIC_OPS) -typedef volatile int of_once_t; -# define OF_ONCE_INIT 0 -#elif defined(OF_AMIGAOS) || !defined(OF_HAVE_THREADS) -typedef int of_once_t; -# define OF_ONCE_INIT 0 -#endif - -#ifdef __cplusplus -extern "C" { -#endif -extern void of_once(of_once_t *control, void (*func)(void)); -#ifdef __cplusplus -} -#endif DELETED src/once.m Index: src/once.m ================================================================== --- src/once.m +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "once.h" - -#ifdef OF_AMIGAOS -# include -#endif - -#if defined(OF_HAVE_THREADS) && defined(OF_HAVE_ATOMIC_OPS) -# import "atomic.h" -# import "mutex.h" -#endif - -void -of_once(of_once_t *control, void (*func)(void)) -{ -#if !defined(OF_HAVE_THREADS) - if (*control == 0) { - func(); - *control = 1; - } -#elif defined(OF_HAVE_PTHREADS) - pthread_once(control, func); -#elif defined(OF_HAVE_ATOMIC_OPS) - /* Avoid atomic operations in case it's already done. */ - if (*control == 2) - return; - - if (of_atomic_int_cmpswap(control, 0, 1)) { - func(); - - of_memory_barrier(); - - of_atomic_int_inc(control); - } else - while (*control == 1) - of_thread_yield(); -#elif defined(OF_AMIGAOS) - bool run = false; - - /* Avoid Forbid() in case it's already done. */ - if (*control == 2) - return; - - Forbid(); - - switch (*control) { - case 0: - *control = 1; - run = true; - break; - case 1: - while (*control == 1) { - Permit(); - Forbid(); - } - } - - Permit(); - - if (run) { - func(); - *control = 2; - } -#else -# error No of_once available -#endif -} DELETED src/pbkdf2.h Index: src/pbkdf2.h ================================================================== --- src/pbkdf2.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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. - */ - -#ifndef __STDC_LIMIT_MACROS -# define __STDC_LIMIT_MACROS -#endif -#ifndef __STDC_CONSTANT_MACROS -# define __STDC_CONSTANT_MACROS -#endif - -#import "macros.h" - -OF_ASSUME_NONNULL_BEGIN - -/** @file */ - -@class OFHMAC; - -/** - * @brief The parameters for @ref of_pbkdf2. - */ -typedef struct of_pbkdf2_parameters_t { - /** @brief The HMAC to use to derive a key. */ - __unsafe_unretained OFHMAC *HMAC; - /** @brief The number of iterations to perform. */ - size_t iterations; - /** @brief The salt to derive a key with. */ - const unsigned char *salt; - /** @brief The length of the salt. */ - size_t saltLength; - /** @brief The password to derive a key from. */ - const char *password; - /** @brief The length of the password. */ - size_t passwordLength; - /** @brief The buffer to write the key to. */ - unsigned char *key; - /** - * @brief The desired length for the derived key. - * - * @ref key needs to have enough storage. - */ - size_t keyLength; - /** @brief Whether data may be stored in swappable memory. */ - bool allowsSwappableMemory; -} of_pbkdf2_parameters_t; - -#ifdef __cplusplus -extern "C" { -#endif -/** - * @brief Derives a key from a password and a salt using PBKDF2. - * - * @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 - */ -extern void of_pbkdf2(of_pbkdf2_parameters_t param); -#ifdef __cplusplus -} -#endif - -OF_ASSUME_NONNULL_END DELETED src/pbkdf2.m Index: src/pbkdf2.m ================================================================== --- src/pbkdf2.m +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "OFHMAC.h" -#import "OFSecureData.h" - -#import "OFInvalidArgumentException.h" -#import "OFOutOfMemoryException.h" -#import "OFOutOfRangeException.h" - -#import "pbkdf2.h" - -void -of_pbkdf2(of_pbkdf2_parameters_t param) -{ - void *pool = objc_autoreleasePoolPush(); - size_t blocks, digestSize = param.HMAC.digestSize; - OFSecureData *buffer = [OFSecureData - dataWithCount: digestSize - allowsSwappableMemory: param.allowsSwappableMemory]; - OFSecureData *digest = [OFSecureData - dataWithCount: digestSize - allowsSwappableMemory: param.allowsSwappableMemory]; - unsigned char *bufferItems = buffer.mutableItems; - unsigned char *digestItems = digest.mutableItems; - OFSecureData *extendedSalt; - unsigned char *extendedSaltItems; - - if (param.HMAC == nil || param.iterations == 0 || param.salt == NULL || - param.password == NULL || param.key == NULL || param.keyLength == 0) - @throw [OFInvalidArgumentException exception]; - - blocks = param.keyLength / digestSize; - if (param.keyLength % digestSize != 0) - blocks++; - - if (param.saltLength > SIZE_MAX - 4 || blocks > UINT32_MAX) - @throw [OFOutOfRangeException exception]; - - extendedSalt = [OFSecureData - dataWithCount: param.saltLength + 4 - allowsSwappableMemory: param.allowsSwappableMemory]; - extendedSaltItems = extendedSalt.mutableItems; - - @try { - uint32_t i = OF_BSWAP32_IF_LE(1); - - [param.HMAC setKey: param.password - length: param.passwordLength]; - - memcpy(extendedSaltItems, param.salt, param.saltLength); - - while (param.keyLength > 0) { - size_t length; - - memcpy(extendedSaltItems + param.saltLength, &i, 4); - - [param.HMAC reset]; - [param.HMAC updateWithBuffer: extendedSaltItems - length: param.saltLength + 4]; - memcpy(bufferItems, param.HMAC.digest, digestSize); - memcpy(digestItems, param.HMAC.digest, digestSize); - - for (size_t j = 1; j < param.iterations; j++) { - [param.HMAC reset]; - [param.HMAC updateWithBuffer: digestItems - length: digestSize]; - memcpy(digestItems, param.HMAC.digest, - digestSize); - - for (size_t k = 0; k < digestSize; k++) - bufferItems[k] ^= digestItems[k]; - } - - length = digestSize; - if (length > param.keyLength) - length = param.keyLength; - - memcpy(param.key, bufferItems, length); - param.key += length; - param.keyLength -= length; - - i = OF_BSWAP32_IF_LE(OF_BSWAP32_IF_LE(i) + 1); - } - } @catch (id e) { - [extendedSalt zero]; - [buffer zero]; - [digest zero]; - - @throw e; - } @finally { - [param.HMAC zero]; - } - - objc_autoreleasePoolPop(pool); -} Index: src/platform.h ================================================================== --- src/platform.h +++ src/platform.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -66,12 +64,13 @@ # define OF_MIPS_EABI #elif defined(__sparc64__) || (defined(__sparc__) && defined(__arch64__)) # define OF_SPARC64 #elif defined(__sparc__) && !defined(__arch64__) # define OF_SPARC -#elif defined(__hppa__) || defined(__HPPA__) || \ - defined(_PA_RISC1_0) || defined(_PA_RISC1_1) +#elif defined(__hppa64__) || defined(_PA_RISC2_0) +# define OF_PA_RISC_2_0 +#elif defined(__hppa__) || defined(_PA_RISC1_0) || defined(_PA_RISC1_1) # define OF_PA_RISC #elif defined(__ia64__) || defined(__IA64__) # define OF_ITANIUM #elif defined(__m68k__) # define OF_M68K @@ -96,10 +95,12 @@ # define OF_RISC_V #elif defined(__s390x__) # define OF_S390X #elif defined(__s390__) # define OF_S390 +#elif defined(__e2k__) +# define OF_ELBRUS_2000 #endif #if defined(__APPLE__) # include # if (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) || \ @@ -125,16 +126,12 @@ #elif defined(__HAIKU__) # define OF_HAIKU #elif defined(_AIX) # define OF_AIX #elif defined(__MORPHOS__) -# ifndef __ixemul__ -# define OF_MORPHOS -# define OF_AMIGAOS -# else -# define OF_MORPHOS_IXEMUL -# endif +# define OF_MORPHOS +# define OF_AMIGAOS #elif defined(__amigaos4__) # define OF_AMIGAOS4 # define OF_AMIGAOS #elif defined(__amigaos__) # define OF_AMIGAOS_M68K @@ -141,17 +138,21 @@ # define OF_AMIGAOS #elif defined(__sun__) # define OF_SOLARIS #elif defined(__QNX__) # define OF_QNX +#elif defined(__hpux__) +# define OF_HPUX #elif defined(_PSP) # define OF_PSP #elif defined(__DJGPP__) # define OF_DJGPP # define OF_MSDOS #elif defined(__riscos__) # define OF_ACORN_RISC_OS +#elif defined(__MINT__) +# define OF_MINT #endif #if defined(__ELF__) # define OF_ELF #elif defined(__MACH__) ADDED src/platform/AmigaOS/OFPlainCondition.m Index: src/platform/AmigaOS/OFPlainCondition.m ================================================================== --- /dev/null +++ src/platform/AmigaOS/OFPlainCondition.m @@ -0,0 +1,251 @@ +/* + * 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 "OFPlainCondition.h" + +#include +#include +#ifndef OF_AMIGAOS4 +# include +#endif + +int +OFPlainConditionNew(OFPlainCondition *condition) +{ + condition->waitingTasks = NULL; + + return 0; +} + +int +OFPlainConditionSignal(OFPlainCondition *condition) +{ + Forbid(); + @try { + if (condition->waitingTasks == NULL) + return 0; + + Signal(condition->waitingTasks->task, + (1ul << condition->waitingTasks->sigBit)); + + condition->waitingTasks = condition->waitingTasks->next; + } @finally { + Permit(); + } + + return 0; +} + +int +OFPlainConditionBroadcast(OFPlainCondition *condition) +{ + Forbid(); + @try { + if (condition->waitingTasks == NULL) + return 0; + + while (condition->waitingTasks != NULL) { + Signal(condition->waitingTasks->task, + (1ul << condition->waitingTasks->sigBit)); + + condition->waitingTasks = condition->waitingTasks->next; + } + } @finally { + Permit(); + } + + return 0; +} + +int +OFPlainConditionWait(OFPlainCondition *condition, OFPlainMutex *mutex) +{ + ULONG signalMask = 0; + + return OFPlainConditionWaitOrExecSignal(condition, mutex, &signalMask); +} + +int +OFPlainConditionWaitOrExecSignal(OFPlainCondition *condition, + OFPlainMutex *mutex, ULONG *signalMask) +{ + struct OFPlainConditionWaitingTask waitingTask = { + .task = FindTask(NULL), + .sigBit = AllocSignal(-1) + }; + int error = 0; + ULONG mask; + + if (waitingTask.sigBit == -1) + return EAGAIN; + + Forbid(); + + if ((error = OFPlainMutexUnlock(mutex)) != 0) { + FreeSignal(waitingTask.sigBit); + return error; + } + + waitingTask.next = condition->waitingTasks; + condition->waitingTasks = &waitingTask; + + mask = Wait((1ul << waitingTask.sigBit) | *signalMask); + if (mask & (1ul << waitingTask.sigBit) || (*signalMask &= mask)) + error = OFPlainMutexLock(mutex); + else + /* + * This should not happen - it means something interrupted the + * Wait(), so the best we can do is return EINTR. + */ + error = EINTR; + + FreeSignal(waitingTask.sigBit); + + Permit(); + + return error; +} + +int +OFPlainConditionTimedWait(OFPlainCondition *condition, OFPlainMutex *mutex, + OFTimeInterval timeout) +{ + ULONG signalMask = 0; + + return OFPlainConditionTimedWaitOrExecSignal(condition, mutex, timeout, + &signalMask); +} + +int +OFPlainConditionTimedWaitOrExecSignal(OFPlainCondition *condition, + OFPlainMutex *mutex, OFTimeInterval timeout, ULONG *signalMask) +{ + struct OFPlainConditionWaitingTask waitingTask = { + .task = FindTask(NULL), + .sigBit = AllocSignal(-1) + }; + struct MsgPort port = { + .mp_Node = { + .ln_Type = NT_MSGPORT + }, + .mp_Flags = PA_SIGNAL, + .mp_SigTask = waitingTask.task, + .mp_SigBit = AllocSignal(-1) + }; +#ifdef OF_AMIGAOS4 + struct TimeRequest request = { + .Request = { +#else + struct timerequest request = { + .tr_node = { +#endif + .io_Message = { + .mn_Node = { + .ln_Type = NT_MESSAGE + }, + .mn_ReplyPort = &port, + .mn_Length = sizeof(request) + }, + .io_Command = TR_ADDREQUEST + }, +#ifdef OF_AMIGAOS4 + .Time = { + .Seconds = (ULONG)timeout, + .Microseconds = + (timeout - request.Time.Seconds) * 1000000 +#else + .tr_time = { + .tv_sec = (ULONG)timeout, + .tv_micro = (timeout - request.tr_time.tv_sec) * 1000000 +#endif + } + }; + int error = 0; + ULONG mask; + + NewList(&port.mp_MsgList); + + if (waitingTask.sigBit == -1 || port.mp_SigBit == -1) { + error = EAGAIN; + goto fail; + } + + if (OpenDevice("timer.device", UNIT_MICROHZ, + (struct IORequest *)&request, 0) != 0) { + error = EAGAIN; + goto fail; + } + + Forbid(); + + if ((error = OFPlainMutexUnlock(mutex)) != 0) { + Permit(); + goto fail; + } + + waitingTask.next = condition->waitingTasks; + condition->waitingTasks = &waitingTask; + + SendIO((struct IORequest *)&request); + + mask = Wait((1ul << waitingTask.sigBit) | (1ul << port.mp_SigBit) | + *signalMask); + if (mask & (1ul << waitingTask.sigBit) || (*signalMask &= mask)) + error = OFPlainMutexLock(mutex); + else if (mask & (1ul << port.mp_SigBit)) + error = ETIMEDOUT; + else + /* + * This should not happen - it means something interrupted the + * Wait(), so the best we can do is return EINTR. + */ + error = EINTR; + + condition->waitingTasks = waitingTask.next; + + if (!CheckIO((struct IORequest *)&request)) { + AbortIO((struct IORequest *)&request); + WaitIO((struct IORequest *)&request); + } + CloseDevice((struct IORequest *)&request); + + Permit(); + +fail: + if (waitingTask.sigBit != -1) + FreeSignal(waitingTask.sigBit); + if (port.mp_SigBit != -1) + FreeSignal(port.mp_SigBit); + + return error; +} + +int +OFPlainConditionFree(OFPlainCondition *condition) +{ + Forbid(); + @try { + if (condition->waitingTasks != NULL) + return EBUSY; + } @finally { + Permit(); + } + + return 0; +} ADDED src/platform/AmigaOS/OFPlainMutex.m Index: src/platform/AmigaOS/OFPlainMutex.m ================================================================== --- /dev/null +++ src/platform/AmigaOS/OFPlainMutex.m @@ -0,0 +1,91 @@ +/* + * 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 "OFPlainMutex.h" + +#include + +int +OFPlainMutexNew(OFPlainMutex *mutex) +{ + InitSemaphore(mutex); + + return 0; +} + +int +OFPlainMutexLock(OFPlainMutex *mutex) +{ + ObtainSemaphore(mutex); + + return 0; +} + +int +OFPlainMutexTryLock(OFPlainMutex *mutex) +{ + if (!AttemptSemaphore(mutex)) + return EBUSY; + + return 0; +} + +int +OFPlainMutexUnlock(OFPlainMutex *mutex) +{ + ReleaseSemaphore(mutex); + + return 0; +} + +int +OFPlainMutexFree(OFPlainMutex *mutex) +{ + return 0; +} + +int +OFPlainRecursiveMutexNew(OFPlainRecursiveMutex *rmutex) +{ + return OFPlainMutexNew(rmutex); +} + +int +OFPlainRecursiveMutexLock(OFPlainRecursiveMutex *rmutex) +{ + return OFPlainMutexLock(rmutex); +} + +int +OFPlainRecursiveMutexTryLock(OFPlainRecursiveMutex *rmutex) +{ + return OFPlainMutexTryLock(rmutex); +} + +int +OFPlainRecursiveMutexUnlock(OFPlainRecursiveMutex *rmutex) +{ + return OFPlainMutexUnlock(rmutex); +} + +int +OFPlainRecursiveMutexFree(OFPlainRecursiveMutex *rmutex) +{ + return OFPlainMutexFree(rmutex); +} ADDED src/platform/AmigaOS/OFPlainThread.m Index: src/platform/AmigaOS/OFPlainThread.m ================================================================== --- /dev/null +++ src/platform/AmigaOS/OFPlainThread.m @@ -0,0 +1,220 @@ +/* + * 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 "OFPlainThread.h" +#import "OFData.h" +#import "OFTLSKey.h" + +#include +#include +#include + +#ifndef OF_MORPHOS +extern void OFTLSKeyThreadExited(void); +#endif +static OFTLSKey threadKey; + +OF_CONSTRUCTOR() +{ + OFEnsure(OFTLSKeyNew(&threadKey) == 0); +} + +static void +functionWrapper(void) +{ + bool detached = false; + OFPlainThread thread = + (OFPlainThread)((struct Process *)FindTask(NULL))->pr_ExitData; + OFEnsure(OFTLSKeySet(threadKey, thread) == 0); + + thread->function(thread->object); + + ObtainSemaphore(&thread->semaphore); + @try { + thread->done = true; + +#ifndef OF_MORPHOS + OFTLSKeyThreadExited(); +#endif + + if (thread->detached) + detached = true; + else if (thread->joinTask != NULL) + Signal(thread->joinTask, (1ul << thread->joinSigBit)); + } @finally { + ReleaseSemaphore(&thread->semaphore); + } + + if (detached) + free(thread); +} + +int +OFPlainThreadAttributesInit(OFPlainThreadAttributes *attr) +{ + attr->priority = 0; + attr->stackSize = 0; + + return 0; +} + +int +OFPlainThreadNew(OFPlainThread *thread, const char *name, void (*function)(id), + id object, const OFPlainThreadAttributes *attr) +{ + OFMutableData *tags = nil; + + if ((*thread = calloc(1, sizeof(**thread))) == NULL) + return ENOMEM; + + @try { + (*thread)->function = function; + (*thread)->object = object; + InitSemaphore(&(*thread)->semaphore); + + tags = [[OFMutableData alloc] + initWithItemSize: sizeof(struct TagItem) + capacity: 12]; +#define ADD_TAG(tag, data) \ + { \ + struct TagItem t = { \ + .ti_Tag = tag, \ + .ti_Data = data \ + }; \ + [tags addItem: &t]; \ + } + ADD_TAG(NP_Entry, (ULONG)functionWrapper) + ADD_TAG(NP_ExitData, (ULONG)*thread) +#ifdef OF_AMIGAOS4 + ADD_TAG(NP_Child, TRUE) +#endif +#ifdef OF_MORPHOS + ADD_TAG(NP_CodeType, CODETYPE_PPC); +#endif + if (name != NULL) + ADD_TAG(NP_Name, (ULONG)name); + + ADD_TAG(NP_Input, ((struct Process *)FindTask(NULL))->pr_CIS) + ADD_TAG(NP_Output, ((struct Process *)FindTask(NULL))->pr_COS) + ADD_TAG(NP_Error, ((struct Process *)FindTask(NULL))->pr_CES) + ADD_TAG(NP_CloseInput, FALSE) + ADD_TAG(NP_CloseOutput, FALSE) + ADD_TAG(NP_CloseError, FALSE) + + if (attr != NULL && attr->priority != 0) { + if (attr->priority < 1 || attr->priority > 1) + return EINVAL; + + /* + * -1 should be -128 (lowest possible priority) while + * +1 should be +127 (highest possible priority). + */ + ADD_TAG(NP_Priority, (attr->priority > 0 + ? attr->priority * 127 : attr->priority * 128)) + } + + if (attr != NULL && attr->stackSize != 0) + ADD_TAG(NP_StackSize, attr->stackSize) + else + ADD_TAG(NP_StackSize, + ((struct Process *)FindTask(NULL))->pr_StackSize) + + ADD_TAG(TAG_DONE, 0) +#undef ADD_TAG + + (*thread)->task = (struct Task *)CreateNewProc(tags.items); + if ((*thread)->task == NULL) { + free(*thread); + return EAGAIN; + } + } @catch (id e) { + free(*thread); + @throw e; + } @finally { + [tags release]; + } + + return 0; +} + +OFPlainThread +OFCurrentPlainThread(void) +{ + return OFTLSKeyGet(threadKey); +} + +bool +OFPlainThreadIsCurrent(OFPlainThread thread) +{ + return (thread->task == FindTask(NULL)); +} + +int +OFPlainThreadJoin(OFPlainThread thread) +{ + ObtainSemaphore(&thread->semaphore); + + if (thread->done) { + ReleaseSemaphore(&thread->semaphore); + + free(thread); + return 0; + } + + @try { + if (thread->detached || thread->joinTask != NULL) + return EINVAL; + + if ((thread->joinSigBit = AllocSignal(-1)) == -1) + return EAGAIN; + + thread->joinTask = FindTask(NULL); + } @finally { + ReleaseSemaphore(&thread->semaphore); + } + + Wait(1ul << thread->joinSigBit); + FreeSignal(thread->joinSigBit); + + assert(thread->done); + free(thread); + + return 0; +} + +int +OFPlainThreadDetach(OFPlainThread thread) +{ + ObtainSemaphore(&thread->semaphore); + + if (thread->done) + free(thread); + else + thread->detached = true; + + ReleaseSemaphore(&thread->semaphore); + + return 0; +} + +void +OFSetThreadName(const char *name) +{ +} ADDED src/platform/AmigaOS/OFString+PathAdditions.m Index: src/platform/AmigaOS/OFString+PathAdditions.m ================================================================== --- /dev/null +++ src/platform/AmigaOS/OFString+PathAdditions.m @@ -0,0 +1,337 @@ +/* + * 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+PathAdditions.h" +#import "OFArray.h" +#import "OFFileURLHandler.h" + +#import "OFOutOfRangeException.h" + +int _OFString_PathAdditions_reference; + +@implementation OFString (PathAdditions) ++ (OFString *)pathWithComponents: (OFArray *)components +{ + OFMutableString *ret = [OFMutableString string]; + void *pool = objc_autoreleasePoolPush(); + bool firstAfterDevice = true; + + for (OFString *component in components) { + if (component.length == 0) + continue; + + if (!firstAfterDevice) + [ret appendString: @"/"]; + + [ret appendString: component]; + + if (![component hasSuffix: @":"]) + firstAfterDevice = false; + } + + [ret makeImmutable]; + + objc_autoreleasePoolPop(pool); + + return ret; +} + +- (bool)isAbsolutePath +{ + return [self containsString: @":"]; +} + +- (OFArray *)pathComponents +{ + OFMutableArray OF_GENERIC(OFString *) *ret = [OFMutableArray array]; + void *pool = objc_autoreleasePoolPush(); + const char *cString = self.UTF8String; + size_t i, last = 0, cStringLength = self.UTF8StringLength; + + if (cStringLength == 0) { + objc_autoreleasePoolPop(pool); + return ret; + } + + for (i = 0; i < cStringLength; i++) { + if (cString[i] == '/') { + if (i - last != 0) + [ret addObject: [OFString + stringWithUTF8String: cString + last + length: i - last]]; + else + [ret addObject: @"/"]; + + last = i + 1; + } else if (cString[i] == ':') { + [ret addObject: [OFString + stringWithUTF8String: cString + last + length: i - last + 1]]; + + last = i + 1; + } + } + if (i - last != 0) + [ret addObject: [OFString stringWithUTF8String: cString + last + length: i - last]]; + + [ret makeImmutable]; + + objc_autoreleasePoolPop(pool); + + return ret; +} + +- (OFString *)lastPathComponent +{ + /* + * AmigaOS needs the full parsing to determine the last path component. + * This could be optimized by not creating the temporary objects, + * though. + */ + void *pool = objc_autoreleasePoolPush(); + OFString *ret = self.pathComponents.lastObject; + + [ret retain]; + objc_autoreleasePoolPop(pool); + return [ret autorelease]; +} + +- (OFString *)pathExtension +{ + void *pool = objc_autoreleasePoolPush(); + OFString *ret, *fileName; + size_t pos; + + fileName = self.lastPathComponent; + pos = [fileName rangeOfString: @"." + options: OFStringSearchBackwards].location; + if (pos == OFNotFound || pos == 0) { + objc_autoreleasePoolPop(pool); + return @""; + } + + ret = [fileName substringFromIndex: pos + 1]; + + [ret retain]; + objc_autoreleasePoolPop(pool); + return [ret autorelease]; +} + +- (OFString *)stringByDeletingLastPathComponent +{ + /* + * AmigaOS needs the full parsing to delete the last path component. + * This could be optimized, though. + */ + void *pool = objc_autoreleasePoolPush(); + OFArray OF_GENERIC(OFString *) *components = self.pathComponents; + size_t count = components.count; + OFString *ret; + + if (count < 2) { + if ([components.firstObject hasSuffix: @":"]) { + ret = [components.firstObject retain]; + objc_autoreleasePoolPop(pool); + return [ret autorelease]; + } + + objc_autoreleasePoolPop(pool); + return @""; + } + + components = [components objectsInRange: + OFRangeMake(0, components.count - 1)]; + ret = [OFString pathWithComponents: components]; + + [ret retain]; + objc_autoreleasePoolPop(pool); + return [ret autorelease]; +} + +- (OFString *)stringByDeletingPathExtension +{ + void *pool; + OFMutableArray OF_GENERIC(OFString *) *components; + OFString *ret, *fileName; + size_t pos; + + if (self.length == 0) + return [[self copy] autorelease]; + + pool = objc_autoreleasePoolPush(); + components = [[self.pathComponents mutableCopy] autorelease]; + fileName = components.lastObject; + + pos = [fileName rangeOfString: @"." + options: OFStringSearchBackwards].location; + if (pos == OFNotFound || pos == 0) { + objc_autoreleasePoolPop(pool); + return [[self copy] autorelease]; + } + + fileName = [fileName substringToIndex: pos]; + [components replaceObjectAtIndex: components.count - 1 + withObject: fileName]; + + ret = [OFString pathWithComponents: components]; + + [ret retain]; + objc_autoreleasePoolPop(pool); + return [ret autorelease]; +} + +- (OFString *)stringByStandardizingPath +{ + void *pool = objc_autoreleasePoolPush(); + OFArray OF_GENERIC(OFString *) *components; + OFMutableArray OF_GENERIC(OFString *) *array; + OFString *ret; + bool done = false; + + if (self.length == 0) + return @""; + + components = self.pathComponents; + + if (components.count == 1) { + objc_autoreleasePoolPop(pool); + return [[self copy] autorelease]; + } + + array = [[components mutableCopy] autorelease]; + + while (!done) { + size_t length = array.count; + + done = true; + + for (size_t i = 0; i < length; i++) { + OFString *component = [array objectAtIndex: i]; + OFString *parent = + (i > 0 ? [array objectAtIndex: i - 1] : 0); + + if (component.length == 0) { + [array removeObjectAtIndex: i]; + + done = false; + break; + } + + if ([component isEqual: @"/"] && + parent != nil && ![parent isEqual: @"/"]) { + [array removeObjectsInRange: + OFRangeMake(i - 1, 2)]; + + done = false; + break; + } + } + } + + ret = [OFString pathWithComponents: array]; + + if ([self hasSuffix: @"/"]) + ret = [ret stringByAppendingString: @"/"]; + + [ret retain]; + objc_autoreleasePoolPop(pool); + return [ret autorelease]; +} + +- (OFString *)stringByAppendingPathComponent: (OFString *)component +{ + if ([self hasSuffix: @"/"] || [self hasSuffix: @":"]) + return [self stringByAppendingString: component]; + else { + OFMutableString *ret = [[self mutableCopy] autorelease]; + + [ret appendString: @"/"]; + [ret appendString: component]; + + [ret makeImmutable]; + + return ret; + } +} + +- (bool)of_isDirectoryPath +{ + return ([self hasSuffix: @"/"] || [self hasSuffix: @":"] || + [OFFileURLHandler of_directoryExistsAtPath: self]); +} + +- (OFString *)of_pathToURLPathWithURLEncodedHost: (OFString **)URLEncodedHost +{ + OFArray OF_GENERIC(OFString *) *components = self.pathComponents; + OFMutableString *ret = [OFMutableString string]; + + for (OFString *component in components) { + if (component.length == 0) + continue; + + if ([component isEqual: @"/"]) + [ret appendString: @"/.."]; + else { + [ret appendString: @"/"]; + [ret appendString: component]; + } + } + + [ret makeImmutable]; + + return ret; +} + +- (OFString *)of_URLPathToPathWithURLEncodedHost: (OFString *)URLEncodedHost +{ + OFString *path = self; + + if (path.length > 1 && [path hasSuffix: @"/"]) + path = [path substringToIndex: path.length - 1]; + + OFMutableArray OF_GENERIC(OFString *) *components; + size_t count; + + path = [path substringFromIndex: 1]; + components = [[[path + componentsSeparatedByString: @"/"] mutableCopy] autorelease]; + count = components.count; + + for (size_t i = 0; i < count; i++) { + OFString *component = [components objectAtIndex: i]; + + if ([component isEqual: @"."]) { + [components removeObjectAtIndex: i]; + count--; + + i--; + continue; + } + + if ([component isEqual: @".."]) + [components replaceObjectAtIndex: i withObject: @"/"]; + } + + return [OFString pathWithComponents: components]; +} + +- (OFString *)of_pathComponentToURLPathComponent +{ + return self; +} +@end ADDED src/platform/AmigaOS/OFTLSKey.m Index: src/platform/AmigaOS/OFTLSKey.m ================================================================== --- /dev/null +++ src/platform/AmigaOS/OFTLSKey.m @@ -0,0 +1,167 @@ +/* + * 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 "OFTLSKey.h" + +#include +#include + +/* + * As we use this file in both the runtime and ObjFW, and since AmigaOS always + * has the runtime, use the hashtable from the runtime. + */ +#import "runtime/private.h" + +static OFTLSKey firstKey = NULL, lastKey = NULL; +static struct SignalSemaphore semaphore; +static bool semaphoreInitialized = false; + +static uint32_t +hashFunc(const void *ptr) +{ + return (uint32_t)(uintptr_t)ptr; +} + +static bool +equalFunc(const void *ptr1, const void *ptr2) +{ + return (ptr1 == ptr2); +} + +OF_CONSTRUCTOR() +{ + if (!semaphoreInitialized) { + InitSemaphore(&semaphore); + semaphoreInitialized = true; + } +} + +int +OFTLSKeyNew(OFTLSKey *key) +{ + if (!semaphoreInitialized) { + /* + * We might be called from another constructor, while ours has + * not run yet. This is safe, as the constructor is definitely + * run before a thread is spawned. + */ + InitSemaphore(&semaphore); + semaphoreInitialized = true; + } + + if ((*key = malloc(sizeof(**key))) == NULL) + return ENOMEM; + + (*key)->table = NULL; + + ObtainSemaphore(&semaphore); + @try { + (*key)->next = NULL; + (*key)->previous = lastKey; + + if (lastKey != NULL) + lastKey->next = *key; + + lastKey = *key; + + if (firstKey == NULL) + firstKey = *key; + } @finally { + ReleaseSemaphore(&semaphore); + } + + /* We create the hash table lazily. */ + return 0; +} + +int +OFTLSKeyFree(OFTLSKey key) +{ + ObtainSemaphore(&semaphore); + @try { + if (key->previous != NULL) + key->previous->next = key->next; + if (key->next != NULL) + key->next->previous = key->previous; + + if (firstKey == key) + firstKey = key->next; + if (lastKey == key) + lastKey = key->previous; + + objc_hashtable_free(key->table); + free(key); + } @finally { + ReleaseSemaphore(&semaphore); + } + + return 0; +} + +void * +OFTLSKeyGet(OFTLSKey key) +{ + void *ret; + + ObtainSemaphore(&semaphore); + @try { + if (key->table == NULL) + return NULL; + + ret = objc_hashtable_get(key->table, FindTask(NULL)); + } @finally { + ReleaseSemaphore(&semaphore); + } + + return ret; +} + +int +OFTLSKeySet(OFTLSKey key, void *ptr) +{ + ObtainSemaphore(&semaphore); + @try { + struct Task *task = FindTask(NULL); + + if (key->table == NULL) + key->table = objc_hashtable_new(hashFunc, equalFunc, 2); + + if (ptr == NULL) + objc_hashtable_delete(key->table, task); + else + objc_hashtable_set(key->table, task, ptr); + } @finally { + ReleaseSemaphore(&semaphore); + } + + return 0; +} + +void +OFTLSKeyThreadExited(void) +{ + ObtainSemaphore(&semaphore); + @try { + struct Task *task = FindTask(NULL); + + for (OFTLSKey iter = firstKey; iter != NULL; iter = iter->next) + if (iter->table != NULL) + objc_hashtable_delete(iter->table, task); + } @finally { + ReleaseSemaphore(&semaphore); + } +} ADDED src/platform/GCC4.7/OFAtomic.h Index: src/platform/GCC4.7/OFAtomic.h ================================================================== --- /dev/null +++ src/platform/GCC4.7/OFAtomic.h @@ -0,0 +1,150 @@ +/* + * 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. + */ + +static OF_INLINE int +OFAtomicIntAdd(volatile int *_Nonnull p, int i) +{ + return __atomic_add_fetch(p, i, __ATOMIC_RELAXED); +} + +static OF_INLINE int32_t +OFAtomicInt32Add(volatile int32_t *_Nonnull p, int32_t i) +{ + return __atomic_add_fetch(p, i, __ATOMIC_RELAXED); +} + +static OF_INLINE void *_Nullable +OFAtomicPointerAdd(void *volatile _Nullable *_Nonnull p, intptr_t i) +{ + return __atomic_add_fetch(p, i, __ATOMIC_RELAXED); +} + +static OF_INLINE int +OFAtomicIntSubtract(volatile int *_Nonnull p, int i) +{ + return __atomic_sub_fetch(p, i, __ATOMIC_RELAXED); +} + +static OF_INLINE int32_t +OFAtomicInt32Subtract(volatile int32_t *_Nonnull p, int32_t i) +{ + return __atomic_sub_fetch(p, i, __ATOMIC_RELAXED); +} + +static OF_INLINE void *_Nullable +OFAtomicPointerSubtract(void *volatile _Nullable *_Nonnull p, intptr_t i) +{ + return __atomic_sub_fetch(p, i, __ATOMIC_RELAXED); +} + +static OF_INLINE int +OFAtomicIntIncrease(volatile int *_Nonnull p) +{ + return __atomic_add_fetch(p, 1, __ATOMIC_RELAXED); +} + +static OF_INLINE int32_t +OFAtomicInt32Increase(volatile int32_t *_Nonnull p) +{ + return __atomic_add_fetch(p, 1, __ATOMIC_RELAXED); +} + +static OF_INLINE int +OFAtomicIntDecrease(volatile int *_Nonnull p) +{ + return __atomic_sub_fetch(p, 1, __ATOMIC_RELAXED); +} + +static OF_INLINE int32_t +OFAtomicInt32Decrease(volatile int32_t *_Nonnull p) +{ + return __atomic_sub_fetch(p, 1, __ATOMIC_RELAXED); +} + +static OF_INLINE unsigned int +OFAtomicIntOr(volatile unsigned int *_Nonnull p, unsigned int i) +{ + return __atomic_or_fetch(p, i, __ATOMIC_RELAXED); +} + +static OF_INLINE uint32_t +OFAtomicInt32Or(volatile uint32_t *_Nonnull p, uint32_t i) +{ + return __atomic_or_fetch(p, i, __ATOMIC_RELAXED); +} + +static OF_INLINE unsigned int +OFAtomicIntAnd(volatile unsigned int *_Nonnull p, unsigned int i) +{ + return __atomic_and_fetch(p, i, __ATOMIC_RELAXED); +} + +static OF_INLINE uint32_t +OFAtomicInt32And(volatile uint32_t *_Nonnull p, uint32_t i) +{ + return __atomic_and_fetch(p, i, __ATOMIC_RELAXED); +} + +static OF_INLINE unsigned int +OFAtomicIntXor(volatile unsigned int *_Nonnull p, unsigned int i) +{ + return __atomic_xor_fetch(p, i, __ATOMIC_RELAXED); +} + +static OF_INLINE uint32_t +OFAtomicInt32Xor(volatile uint32_t *_Nonnull p, uint32_t i) +{ + return __atomic_xor_fetch(p, i, __ATOMIC_RELAXED); +} + +static OF_INLINE bool +OFAtomicIntCompareAndSwap(volatile int *_Nonnull p, int o, int n) +{ + return __atomic_compare_exchange(p, &o, &n, false, + __ATOMIC_RELAXED, __ATOMIC_RELAXED); +} + +static OF_INLINE bool +OFAtomicInt32CompareAndSwap(volatile int32_t *_Nonnull p, int32_t o, int32_t n) +{ + return __atomic_compare_exchange(p, &o, &n, false, + __ATOMIC_RELAXED, __ATOMIC_RELAXED); +} + +static OF_INLINE bool +OFAtomicPointerCompareAndSwap(void *volatile _Nullable *_Nonnull p, + void *_Nullable o, void *_Nullable n) +{ + return __atomic_compare_exchange(p, &o, &n, false, + __ATOMIC_RELAXED, __ATOMIC_RELAXED); +} + +static OF_INLINE void +OFMemoryBarrier(void) +{ + __atomic_thread_fence(__ATOMIC_SEQ_CST); +} + +static OF_INLINE void +OFAcquireMemoryBarrier(void) +{ + __atomic_thread_fence(__ATOMIC_ACQUIRE); +} + +static OF_INLINE void +OFReleaseMemoryBarrier(void) +{ + __atomic_thread_fence(__ATOMIC_RELEASE); +} ADDED src/platform/GCC4/OFAtomic.h Index: src/platform/GCC4/OFAtomic.h ================================================================== --- /dev/null +++ src/platform/GCC4/OFAtomic.h @@ -0,0 +1,147 @@ +/* + * 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. + */ + +static OF_INLINE int +OFAtomicIntAdd(volatile int *_Nonnull p, int i) +{ + return __sync_add_and_fetch(p, i); +} + +static OF_INLINE int32_t +OFAtomicInt32Add(volatile int32_t *_Nonnull p, int32_t i) +{ + return __sync_add_and_fetch(p, i); +} + +static OF_INLINE void *_Nullable +OFAtomicPointerAdd(void *volatile _Nullable *_Nonnull p, intptr_t i) +{ + return __sync_add_and_fetch(p, (void *)i); +} + +static OF_INLINE int +OFAtomicIntSubtract(volatile int *_Nonnull p, int i) +{ + return __sync_sub_and_fetch(p, i); +} + +static OF_INLINE int32_t +OFAtomicInt32Subtract(volatile int32_t *_Nonnull p, int32_t i) +{ + return __sync_sub_and_fetch(p, i); +} + +static OF_INLINE void *_Nullable +OFAtomicPointerSubtract(void *volatile _Nullable *_Nonnull p, intptr_t i) +{ + return __sync_sub_and_fetch(p, (void *)i); +} + +static OF_INLINE int +OFAtomicIntIncrease(volatile int *_Nonnull p) +{ + return __sync_add_and_fetch(p, 1); +} + +static OF_INLINE int32_t +OFAtomicInt32Increase(volatile int32_t *_Nonnull p) +{ + return __sync_add_and_fetch(p, 1); +} + +static OF_INLINE int +OFAtomicIntDecrease(volatile int *_Nonnull p) +{ + return __sync_sub_and_fetch(p, 1); +} + +static OF_INLINE int32_t +OFAtomicInt32Decrease(volatile int32_t *_Nonnull p) +{ + return __sync_sub_and_fetch(p, 1); +} + +static OF_INLINE unsigned int +OFAtomicIntOr(volatile unsigned int *_Nonnull p, unsigned int i) +{ + return __sync_or_and_fetch(p, i); +} + +static OF_INLINE uint32_t +OFAtomicInt32Or(volatile uint32_t *_Nonnull p, uint32_t i) +{ + return __sync_or_and_fetch(p, i); +} + +static OF_INLINE unsigned int +OFAtomicIntAnd(volatile unsigned int *_Nonnull p, unsigned int i) +{ + return __sync_and_and_fetch(p, i); +} + +static OF_INLINE uint32_t +OFAtomicInt32And(volatile uint32_t *_Nonnull p, uint32_t i) +{ + return __sync_and_and_fetch(p, i); +} + +static OF_INLINE unsigned int +OFAtomicIntXor(volatile unsigned int *_Nonnull p, unsigned int i) +{ + return __sync_xor_and_fetch(p, i); +} + +static OF_INLINE uint32_t +OFAtomicInt32Xor(volatile uint32_t *_Nonnull p, uint32_t i) +{ + return __sync_xor_and_fetch(p, i); +} + +static OF_INLINE bool +OFAtomicIntCompareAndSwap(volatile int *_Nonnull p, int o, int n) +{ + return __sync_bool_compare_and_swap(p, o, n); +} + +static OF_INLINE bool +OFAtomicInt32CompareAndSwap(volatile int32_t *_Nonnull p, int32_t o, int32_t n) +{ + return __sync_bool_compare_and_swap(p, o, n); +} + +static OF_INLINE bool +OFAtomicPointerCompareAndSwap(void *volatile _Nullable *_Nonnull p, + void *_Nullable o, void *_Nullable n) +{ + return __sync_bool_compare_and_swap(p, o, n); +} + +static OF_INLINE void +OFMemoryBarrier(void) +{ + __sync_synchronize(); +} + +static OF_INLINE void +OFAcquireMemoryBarrier(void) +{ + __sync_synchronize(); +} + +static OF_INLINE void +OFReleaseMemoryBarrier(void) +{ + __sync_synchronize(); +} ADDED src/platform/MorphOS/OFTLSKey.m Index: src/platform/MorphOS/OFTLSKey.m ================================================================== --- /dev/null +++ src/platform/MorphOS/OFTLSKey.m @@ -0,0 +1,35 @@ +/* + * 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 "OFTLSKey.h" + +int +OFTLSKeyNew(OFTLSKey *key) +{ + *key = TLSAllocA(NULL); + + if (*key == TLS_INVALID_INDEX) + return EAGAIN; + + return 0; +} + +int +OFTLSKeyFree(OFTLSKey key) +{ + return (TLSFree(key) ? 0 : EINVAL); +} ADDED src/platform/POSIX/OFPlainCondition.m Index: src/platform/POSIX/OFPlainCondition.m ================================================================== --- /dev/null +++ src/platform/POSIX/OFPlainCondition.m @@ -0,0 +1,60 @@ +/* + * 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 "OFPlainCondition.h" + +int +OFPlainConditionNew(OFPlainCondition *condition) +{ + return pthread_cond_init(condition, NULL); +} + +int +OFPlainConditionSignal(OFPlainCondition *condition) +{ + return pthread_cond_signal(condition); +} + +int +OFPlainConditionBroadcast(OFPlainCondition *condition) +{ + return pthread_cond_broadcast(condition); +} + +int +OFPlainConditionWait(OFPlainCondition *condition, OFPlainMutex *mutex) +{ + return pthread_cond_wait(condition, mutex); +} + +int +OFPlainConditionTimedWait(OFPlainCondition *condition, OFPlainMutex *mutex, + OFTimeInterval timeout) +{ + struct timespec ts; + + ts.tv_sec = (time_t)timeout; + ts.tv_nsec = (long)((timeout - ts.tv_sec) * 1000000000); + + return pthread_cond_timedwait(condition, mutex, &ts); +} + +int +OFPlainConditionFree(OFPlainCondition *condition) +{ + return pthread_cond_destroy(condition); +} ADDED src/platform/POSIX/OFPlainMutex.m Index: src/platform/POSIX/OFPlainMutex.m ================================================================== --- /dev/null +++ src/platform/POSIX/OFPlainMutex.m @@ -0,0 +1,197 @@ +/* + * 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 "OFPlainMutex.h" + +int +OFPlainMutexNew(OFPlainMutex *mutex) +{ + return pthread_mutex_init(mutex, NULL); +} + +int +OFPlainMutexLock(OFPlainMutex *mutex) +{ + return pthread_mutex_lock(mutex); +} + +int +OFPlainMutexTryLock(OFPlainMutex *mutex) +{ + return pthread_mutex_trylock(mutex); +} + +int +OFPlainMutexUnlock(OFPlainMutex *mutex) +{ + return pthread_mutex_unlock(mutex); +} + +int +OFPlainMutexFree(OFPlainMutex *mutex) +{ + return pthread_mutex_destroy(mutex); +} + +#ifdef OF_HAVE_RECURSIVE_PTHREAD_MUTEXES +int +OFPlainRecursiveMutexNew(OFPlainRecursiveMutex *rmutex) +{ + int error; + pthread_mutexattr_t attr; + + if ((error = pthread_mutexattr_init(&attr)) != 0) + return error; + + if ((error = pthread_mutexattr_settype(&attr, + PTHREAD_MUTEX_RECURSIVE)) != 0) + return error; + + if ((error = pthread_mutex_init(rmutex, &attr)) != 0) + return error; + + if ((error = pthread_mutexattr_destroy(&attr)) != 0) + return error; + + return 0; +} + +int +OFPlainRecursiveMutexLock(OFPlainRecursiveMutex *rmutex) +{ + return OFPlainMutexLock(rmutex); +} + +int +OFPlainRecursiveMutexTryLock(OFPlainRecursiveMutex *rmutex) +{ + return OFPlainMutexTryLock(rmutex); +} + +int +OFPlainRecursiveMutexUnlock(OFPlainRecursiveMutex *rmutex) +{ + return OFPlainMutexUnlock(rmutex); +} + +int +OFPlainRecursiveMutexFree(OFPlainRecursiveMutex *rmutex) +{ + return OFPlainMutexFree(rmutex); +} +#else +int +OFPlainRecursiveMutexNew(OFPlainRecursiveMutex *rmutex) +{ + int error; + + if ((error = OFPlainMutexNew(&rmutex->mutex)) != 0) + return error; + + if ((error = OFTLSKeyNew(&rmutex->count)) != 0) + return error; + + return 0; +} + +int +OFPlainRecursiveMutexLock(OFPlainRecursiveMutex *rmutex) +{ + uintptr_t count = (uintptr_t)OFTLSKeyGet(rmutex->count); + int error; + + if (count > 0) { + if ((error = OFTLSKeySet(rmutex->count, + (void *)(count + 1))) != 0) + return error; + + return 0; + } + + if ((error = OFPlainMutexLock(&rmutex->mutex)) != 0) + return error; + + if ((error = OFTLSKeySet(rmutex->count, (void *)1)) != 0) { + OFPlainMutexUnlock(&rmutex->mutex); + return error; + } + + return 0; +} + +int +OFPlainRecursiveMutexTryLock(OFPlainRecursiveMutex *rmutex) +{ + uintptr_t count = (uintptr_t)OFTLSKeyGet(rmutex->count); + int error; + + if (count > 0) { + if ((error = OFTLSKeySet(rmutex->count, + (void *)(count + 1))) != 0) + return error; + + return 0; + } + + if ((error = OFPlainMutexTryLock(&rmutex->mutex)) != 0) + return error; + + if ((error = OFTLSKeySet(rmutex->count, (void *)1)) != 0) { + OFPlainMutexUnlock(&rmutex->mutex); + return error; + } + + return 0; +} + +int +OFPlainRecursiveMutexUnlock(OFPlainRecursiveMutex *rmutex) +{ + uintptr_t count = (uintptr_t)OFTLSKeyGet(rmutex->count); + int error; + + if (count > 1) { + if ((error = OFTLSKeySet(rmutex->count, + (void *)(count - 1))) != 0) + return error; + + return 0; + } + + if ((error = OFTLSKeySet(rmutex->count, (void *)0)) != 0) + return error; + + if ((error = OFPlainMutexUnlock(&rmutex->mutex)) != 0) + return error; + + return 0; +} + +int +OFPlainRecursiveMutexFree(OFPlainRecursiveMutex *rmutex) +{ + int error; + + if ((error = OFPlainMutexFree(&rmutex->mutex)) != 0) + return error; + + if ((error = OFTLSKeyFree(rmutex->count)) != 0) + return error; + + return 0; +} +#endif ADDED src/platform/POSIX/OFPlainThread.m Index: src/platform/POSIX/OFPlainThread.m ================================================================== --- /dev/null +++ src/platform/POSIX/OFPlainThread.m @@ -0,0 +1,220 @@ +/* + * 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 + +#ifdef HAVE_PTHREAD_NP_H +# include +#endif + +#ifdef OF_HAIKU +# include +#endif + +#import "OFPlainThread.h" + +#import "macros.h" + +static int minPrio = 0, maxPrio = 0, normalPrio = 0; + +struct ThreadContext { + void (*function)(id object); + id object; + const char *name; +}; + +/* + * This is done here to make sure this is done as early as possible in the main + * thread. + */ +OF_CONSTRUCTOR() +{ + pthread_attr_t attr; + + if (pthread_attr_init(&attr) == 0) { +#ifdef HAVE_PTHREAD_ATTR_GETSCHEDPOLICY + int policy; +#endif + struct sched_param param; + +#ifdef HAVE_PTHREAD_ATTR_GETSCHEDPOLICY + if (pthread_attr_getschedpolicy(&attr, &policy) == 0) { + minPrio = sched_get_priority_min(policy); + maxPrio = sched_get_priority_max(policy); + + if (minPrio == -1 || maxPrio == -1) + minPrio = maxPrio = 0; + } +#endif + + if (pthread_attr_getschedparam(&attr, ¶m) != 0) + normalPrio = param.sched_priority; + else + minPrio = maxPrio = 0; + + pthread_attr_destroy(&attr); + } +} + +static void * +functionWrapper(void *data) +{ + struct ThreadContext *ctx = data; + + if (ctx->name != NULL) + OFSetThreadName(ctx->name); + + pthread_cleanup_push(free, data); + + ctx->function(ctx->object); + + pthread_cleanup_pop(1); + return NULL; +} + +int +OFPlainThreadAttributesInit(OFPlainThreadAttributes *attr) +{ + int error; + pthread_attr_t POSIXAttr; + + attr->priority = 0; + attr->stackSize = 0; + + if ((error = pthread_attr_init(&POSIXAttr)) != 0) { + if (error == ENOSYS) + return 0; + + return error; + } + + error = pthread_attr_getstacksize(&POSIXAttr, &attr->stackSize); + + pthread_attr_destroy(&POSIXAttr); + + return error; +} + +int +OFPlainThreadNew(OFPlainThread *thread, const char *name, void (*function)(id), + id object, const OFPlainThreadAttributes *attr) +{ + int error = 0; + pthread_attr_t POSIXAttr; + bool POSIXAttrAvailable = true; + + if ((error = pthread_attr_init(&POSIXAttr)) != 0) { + if (error == ENOSYS) + POSIXAttrAvailable = false; + else + return error; + } + + @try { + struct ThreadContext *ctx; + + if (attr != NULL && POSIXAttrAvailable) { +#ifndef OF_HPUX + struct sched_param param; +#endif + + if (attr->priority < -1 || attr->priority > 1) + return EINVAL; + +#ifndef OF_HPUX +# ifdef HAVE_PTHREAD_ATTR_SETINHERITSCHED + if ((error = pthread_attr_setinheritsched(&POSIXAttr, + PTHREAD_EXPLICIT_SCHED)) != 0) + return error; +# endif + + if ((error = pthread_attr_getschedparam(&POSIXAttr, + ¶m)) != 0) + return error; + + if (attr->priority < 0) { + param.sched_priority = minPrio + + (1.0f + attr->priority) * + (normalPrio - minPrio); + } else + param.sched_priority = normalPrio + + attr->priority * (maxPrio - normalPrio); + + if ((error = pthread_attr_setschedparam(&POSIXAttr, + ¶m)) != 0) + return error; +#endif + + if (attr->stackSize > 0) { + if ((error = pthread_attr_setstacksize( + &POSIXAttr, attr->stackSize)) != 0) + return error; + } + } + + if ((ctx = malloc(sizeof(*ctx))) == NULL) + return ENOMEM; + + ctx->function = function; + ctx->object = object; + ctx->name = name; + + error = pthread_create(thread, + (POSIXAttrAvailable ? &POSIXAttr : NULL), functionWrapper, + ctx); + } @finally { + if (POSIXAttrAvailable) + pthread_attr_destroy(&POSIXAttr); + } + + return error; +} + +int +OFPlainThreadJoin(OFPlainThread thread) +{ + void *ret; + + return pthread_join(thread, &ret); +} + +int +OFPlainThreadDetach(OFPlainThread thread) +{ + return pthread_detach(thread); +} + +void +OFSetThreadName(const char *name) +{ +#if defined(OF_HAIKU) + rename_thread(find_thread(NULL), name); +#elif defined(HAVE_PTHREAD_SET_NAME_NP) + pthread_set_name_np(pthread_self(), name); +#elif defined(HAVE_PTHREAD_SETNAME_NP) +# if defined(OF_MACOS) || defined(OF_IOS) + pthread_setname_np(name); +# elif defined(__GLIBC__) + char buffer[16]; + + strncpy(buffer, name, 15); + buffer[15] = 0; + + pthread_setname_np(pthread_self(), buffer); +# endif +#endif +} ADDED src/platform/POSIX/OFSubprocess.m Index: src/platform/POSIX/OFSubprocess.m ================================================================== --- /dev/null +++ src/platform/POSIX/OFSubprocess.m @@ -0,0 +1,403 @@ +/* + * 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 + +#ifdef HAVE_SYS_WAIT_H +# include +#endif + +#include "unistd_wrapper.h" +#ifdef HAVE_SPAWN_H +# include +#endif + +#import "OFSubprocess.h" +#import "OFString.h" +#import "OFArray.h" +#import "OFDictionary.h" +#import "OFLocale.h" + +#import "OFInitializationFailedException.h" +#import "OFNotOpenException.h" +#import "OFOutOfRangeException.h" +#import "OFReadFailedException.h" +#import "OFWriteFailedException.h" + +#ifndef HAVE_POSIX_SPAWNP +extern char **environ; +#endif + +@interface OFSubprocess () +- (void)of_getArgv: (char ***)argv + forProgramName: (OFString *)programName + andArguments: (OFArray *)arguments; +- (char **)of_environmentForDictionary: (OFDictionary *)dictionary; +@end + +@implementation OFSubprocess ++ (instancetype)subprocessWithProgram: (OFString *)program +{ + return [[[self alloc] initWithProgram: program] autorelease]; +} + ++ (instancetype)subprocessWithProgram: (OFString *)program + arguments: (OFArray *)arguments +{ + return [[[self alloc] initWithProgram: program + arguments: arguments] autorelease]; +} + ++ (instancetype)subprocessWithProgram: (OFString *)program + programName: (OFString *)programName + arguments: (OFArray *)arguments +{ + return [[[self alloc] initWithProgram: program + programName: programName + arguments: arguments] autorelease]; +} + ++ (instancetype)subprocessWithProgram: (OFString *)program + programName: (OFString *)programName + arguments: (OFArray *)arguments + environment: (OFDictionary *)environment +{ + return [[[self alloc] initWithProgram: program + programName: programName + arguments: arguments + environment: environment] autorelease]; +} + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)initWithProgram: (OFString *)program +{ + return [self initWithProgram: program + programName: program + arguments: nil + environment: nil]; +} + +- (instancetype)initWithProgram: (OFString *)program + arguments: (OFArray *)arguments +{ + return [self initWithProgram: program + programName: program + arguments: arguments + environment: nil]; +} + +- (instancetype)initWithProgram: (OFString *)program + programName: (OFString *)programName + arguments: (OFArray *)arguments +{ + return [self initWithProgram: program + programName: program + arguments: arguments + environment: nil]; +} + +- (instancetype)initWithProgram: (OFString *)program + programName: (OFString *)programName + arguments: (OFArray *)arguments + environment: (OFDictionary *)environment +{ + self = [super init]; + + @try { + void *pool = objc_autoreleasePoolPush(); + const char *path; + char **argv, **env = NULL; + + _pid = -1; + _readPipe[0] = _writePipe[1] = -1; + + if (pipe(_readPipe) != 0 || pipe(_writePipe) != 0) + @throw [OFInitializationFailedException + exceptionWithClass: self.class]; + + path = [program cStringWithEncoding: [OFLocale encoding]]; + [self of_getArgv: &argv + forProgramName: programName + andArguments: arguments]; + + @try { + env = [self of_environmentForDictionary: environment]; +#ifdef HAVE_POSIX_SPAWNP + posix_spawn_file_actions_t actions; + posix_spawnattr_t attr; + + if (posix_spawn_file_actions_init(&actions) != 0) + @throw [OFInitializationFailedException + exceptionWithClass: self.class]; + + if (posix_spawnattr_init(&attr) != 0) { + posix_spawn_file_actions_destroy(&actions); + + @throw [OFInitializationFailedException + exceptionWithClass: self.class]; + } + + @try { + if (posix_spawn_file_actions_addclose(&actions, + _readPipe[0]) != 0 || + posix_spawn_file_actions_addclose(&actions, + _writePipe[1]) != 0 || + posix_spawn_file_actions_adddup2(&actions, + _writePipe[0], 0) != 0 || + posix_spawn_file_actions_adddup2(&actions, + _readPipe[1], 1) != 0) + @throw [OFInitializationFailedException + exceptionWithClass: self.class]; + +# ifdef POSIX_SPAWN_CLOEXEC_DEFAULT + if (posix_spawnattr_setflags(&attr, + POSIX_SPAWN_CLOEXEC_DEFAULT) != 0) + @throw [OFInitializationFailedException + exceptionWithClass: self.class]; +# endif + + if (posix_spawnp(&_pid, path, &actions, &attr, + argv, env) != 0) + @throw [OFInitializationFailedException + exceptionWithClass: self.class]; + } @finally { + posix_spawn_file_actions_destroy(&actions); + posix_spawnattr_destroy(&attr); + } +#else + if ((_pid = vfork()) == 0) { + environ = env; + + close(_readPipe[0]); + close(_writePipe[1]); + dup2(_writePipe[0], 0); + dup2(_readPipe[1], 1); + execvp(path, argv); + + _exit(EXIT_FAILURE); + } + + if (_pid == -1) + @throw [OFInitializationFailedException + exceptionWithClass: self.class]; +#endif + } @finally { + char **iter; + + close(_readPipe[1]); + close(_writePipe[0]); + OFFreeMemory(argv); + + if (env != NULL) + for (iter = env; *iter != NULL; iter++) + OFFreeMemory(*iter); + + OFFreeMemory(env); + } + + objc_autoreleasePoolPop(pool); + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + if (_readPipe[0] != -1) + [self close]; + + [super dealloc]; +} + +- (void)of_getArgv: (char ***)argv + forProgramName: (OFString *)programName + andArguments: (OFArray *)arguments +{ + OFString *const *objects = arguments.objects; + size_t i, count = arguments.count; + OFStringEncoding encoding; + + *argv = OFAllocMemory(count + 2, sizeof(char *)); + + encoding = [OFLocale encoding]; + + (*argv)[0] = (char *)[programName cStringWithEncoding: encoding]; + + for (i = 0; i < count; i++) + (*argv)[i + 1] = + (char *)[objects[i] cStringWithEncoding: encoding]; + + (*argv)[i + 1] = NULL; +} + +- (char **)of_environmentForDictionary: (OFDictionary *)environment +{ + char **envp; + size_t count; + OFStringEncoding encoding; + + if (environment == nil) + return NULL; + + encoding = [OFLocale encoding]; + + count = environment.count; + envp = OFAllocZeroedMemory(count + 1, sizeof(char *)); + + @try { + OFEnumerator *keyEnumerator = [environment keyEnumerator]; + OFEnumerator *objectEnumerator = [environment objectEnumerator]; + + for (size_t i = 0; i < count; i++) { + OFString *key; + OFString *object; + size_t keyLen, objectLen; + + key = [keyEnumerator nextObject]; + object = [objectEnumerator nextObject]; + + keyLen = [key cStringLengthWithEncoding: encoding]; + objectLen = [object + cStringLengthWithEncoding: encoding]; + + envp[i] = OFAllocMemory(keyLen + objectLen + 2, 1); + + memcpy(envp[i], + [key cStringWithEncoding: encoding], keyLen); + envp[i][keyLen] = '='; + memcpy(envp[i] + keyLen + 1, + [object cStringWithEncoding: encoding], objectLen); + envp[i][keyLen + objectLen + 1] = '\0'; + } + } @catch (id e) { + for (size_t i = 0; i < count; i++) + OFFreeMemory(envp[i]); + + OFFreeMemory(envp); + + @throw e; + } + + return envp; +} + +- (bool)lowlevelIsAtEndOfStream +{ + if (_readPipe[0] == -1) + @throw [OFNotOpenException exceptionWithObject: self]; + + return _atEndOfStream; +} + +- (size_t)lowlevelReadIntoBuffer: (void *)buffer + length: (size_t)length +{ + ssize_t ret; + + if (_readPipe[0] == -1) + @throw [OFNotOpenException exceptionWithObject: self]; + + if ((ret = read(_readPipe[0], buffer, length)) < 0) + @throw [OFReadFailedException exceptionWithObject: self + requestedLength: length + errNo: errno]; + + if (ret == 0) + _atEndOfStream = true; + + return ret; +} + +- (size_t)lowlevelWriteBuffer: (const void *)buffer length: (size_t)length +{ + ssize_t bytesWritten; + + if (_writePipe[1] == -1) + @throw [OFNotOpenException exceptionWithObject: self]; + + if (length > SSIZE_MAX) + @throw [OFOutOfRangeException exception]; + + if ((bytesWritten = write(_writePipe[1], buffer, length)) < 0) + @throw [OFWriteFailedException exceptionWithObject: self + requestedLength: length + bytesWritten: 0 + errNo: errno]; + + return (size_t)bytesWritten; +} + +- (int)fileDescriptorForReading +{ + return _readPipe[0]; +} + +- (int)fileDescriptorForWriting +{ + return _writePipe[1]; +} + +- (void)closeForWriting +{ + if (_writePipe[1] != -1) + close(_writePipe[1]); + + _writePipe[1] = -1; +} + +- (void)close +{ + if (_readPipe[0] == -1) + @throw [OFNotOpenException exceptionWithObject: self]; + + [self closeForWriting]; + close(_readPipe[0]); + + if (_pid != -1) { + kill(_pid, SIGTERM); + waitpid(_pid, &_status, WNOHANG); + } + + _pid = -1; + _readPipe[0] = -1; + + [super close]; +} + +- (int)waitForTermination +{ + if (_readPipe[0] == -1) + @throw [OFNotOpenException exceptionWithObject: self]; + + if (_pid != -1) { + waitpid(_pid, &_status, 0); + _pid = -1; + } + + return WEXITSTATUS(_status); +} +@end ADDED src/platform/POSIX/OFTLSKey.m Index: src/platform/POSIX/OFTLSKey.m ================================================================== --- /dev/null +++ src/platform/POSIX/OFTLSKey.m @@ -0,0 +1,30 @@ +/* + * 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 "OFTLSKey.h" + +int +OFTLSKeyNew(OFTLSKey *key) +{ + return pthread_key_create(key, NULL); +} + +int +OFTLSKeyFree(OFTLSKey key) +{ + return pthread_key_delete(key); +} ADDED src/platform/PowerPC/OFAtomic.h Index: src/platform/PowerPC/OFAtomic.h ================================================================== --- /dev/null +++ src/platform/PowerPC/OFAtomic.h @@ -0,0 +1,397 @@ +/* + * 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. + */ + +static OF_INLINE int +OFAtomicIntAdd(volatile int *_Nonnull p, int i) +{ + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %2\n\t" + "add %0, %0, %1\n\t" + "stwcx. %0, 0, %2\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(i), "r"(p) + : "cc", "memory" + ); + + return i; +} + +static OF_INLINE int32_t +OFAtomicInt32Add(volatile int32_t *_Nonnull p, int32_t i) +{ + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %2\n\t" + "add %0, %0, %1\n\t" + "stwcx. %0, 0, %2\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(i), "r"(p) + : "cc", "memory" + ); + + return i; +} + +static OF_INLINE void *_Nullable +OFAtomicPointerAdd(void *volatile _Nullable *_Nonnull p, intptr_t i) +{ + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %2\n\t" + "add %0, %0, %1\n\t" + "stwcx. %0, 0, %2\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(i), "r"(p) + : "cc", "memory" + ); + + return (void *)i; +} + +static OF_INLINE int +OFAtomicIntSubtract(volatile int *_Nonnull p, int i) +{ + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %2\n\t" + "sub %0, %0, %1\n\t" + "stwcx. %0, 0, %2\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(i), "r"(p) + : "cc", "memory" + ); + + return i; +} + +static OF_INLINE int32_t +OFAtomicInt32Subtract(volatile int32_t *_Nonnull p, int32_t i) +{ + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %2\n\t" + "sub %0, %0, %1\n\t" + "stwcx. %0, 0, %2\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(i), "r"(p) + : "cc", "memory" + ); + + return i; +} + +static OF_INLINE void *_Nullable +OFAtomicPointerSubtract(void *volatile _Nullable *_Nonnull p, intptr_t i) +{ + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %2\n\t" + "sub %0, %0, %1\n\t" + "stwcx. %0, 0, %2\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(i), "r"(p) + : "cc", "memory" + ); + + return (void *)i; +} + +static OF_INLINE int +OFAtomicIntIncrease(volatile int *_Nonnull p) +{ + int i; + + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %1\n\t" + "addi %0, %0, 1\n\t" + "stwcx. %0, 0, %1\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(p) + : "cc", "memory" + ); + + return i; +} + +static OF_INLINE int32_t +OFAtomicInt32Increase(volatile int32_t *_Nonnull p) +{ + int32_t i; + + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %1\n\t" + "addi %0, %0, 1\n\t" + "stwcx. %0, 0, %1\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(p) + : "cc", "memory" + ); + + return i; +} + +static OF_INLINE int +OFAtomicIntDecrease(volatile int *_Nonnull p) +{ + int i; + + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %1\n\t" + "subi %0, %0, 1\n\t" + "stwcx. %0, 0, %1\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(p) + : "cc", "memory" + ); + + return i; +} + +static OF_INLINE int32_t +OFAtomicInt32Decrease(volatile int32_t *_Nonnull p) +{ + int32_t i; + + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %1\n\t" + "subi %0, %0, 1\n\t" + "stwcx. %0, 0, %1\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(p) + : "cc", "memory" + ); + + return i; +} + +static OF_INLINE unsigned int +OFAtomicIntOr(volatile unsigned int *_Nonnull p, unsigned int i) +{ + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %2\n\t" + "or %0, %0, %1\n\t" + "stwcx. %0, 0, %2\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(i), "r"(p) + : "cc", "memory" + ); + + return i; +} + +static OF_INLINE uint32_t +OFAtomicInt32Or(volatile uint32_t *_Nonnull p, uint32_t i) +{ + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %2\n\t" + "or %0, %0, %1\n\t" + "stwcx. %0, 0, %2\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(i), "r"(p) + : "cc", "memory" + ); + + return i; +} + +static OF_INLINE unsigned int +OFAtomicIntAnd(volatile unsigned int *_Nonnull p, unsigned int i) +{ + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %2\n\t" + "and %0, %0, %1\n\t" + "stwcx. %0, 0, %2\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(i), "r"(p) + : "cc", "memory" + ); + + return i; +} + +static OF_INLINE uint32_t +OFAtomicInt32And(volatile uint32_t *_Nonnull p, uint32_t i) +{ + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %2\n\t" + "and %0, %0, %1\n\t" + "stwcx. %0, 0, %2\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(i), "r"(p) + : "cc", "memory" + ); + + return i; +} + +static OF_INLINE unsigned int +OFAtomicIntXor(volatile unsigned int *_Nonnull p, unsigned int i) +{ + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %2\n\t" + "xor %0, %0, %1\n\t" + "stwcx. %0, 0, %2\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(i), "r"(p) + : "cc", "memory" + ); + + return i; +} + +static OF_INLINE uint32_t +OFAtomicInt32Xor(volatile uint32_t *_Nonnull p, uint32_t i) +{ + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %2\n\t" + "xor %0, %0, %1\n\t" + "stwcx. %0, 0, %2\n\t" + "bne- 0b" + : "=&r"(i) + : "r"(i), "r"(p) + : "cc", "memory" + ); + + return i; +} + +static OF_INLINE bool +OFAtomicIntCompareAndSwap(volatile int *_Nonnull p, int o, int n) +{ + int r; + + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %3\n\t" + "cmpw %0, %1\n\t" + "bne 1f\n\t" + "stwcx. %2, 0, %3\n\t" + "bne- 0b\n\t" + "li %0, 1\n\t" + "b 2f\n\t" + "1:\n\t" + "stwcx. %0, 0, %3\n\t" + "li %0, 0\n\t" + "2:" + : "=&r"(r) + : "r"(o), "r"(n), "r"(p) + : "cc", "memory" + ); + + return r; +} + +static OF_INLINE bool +OFAtomicInt32CompareAndSwap(volatile int32_t *_Nonnull p, int32_t o, int32_t n) +{ + int r; + + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %3\n\t" + "cmpw %0, %1\n\t" + "bne 1f\n\t" + "stwcx. %2, 0, %3\n\t" + "bne- 0b\n\t" + "li %0, 1\n\t" + "b 2f\n\t" + "1:\n\t" + "stwcx. %0, 0, %3\n\t" + "li %0, 0\n\t" + "2:" + : "=&r"(r) + : "r"(o), "r"(n), "r"(p) + : "cc", "memory" + ); + + return r; +} + +static OF_INLINE bool +OFAtomicPointerCompareAndSwap(void *volatile _Nullable *_Nonnull p, + void *_Nullable o, void *_Nullable n) +{ + int r; + + __asm__ __volatile__ ( + "0:\n\t" + "lwarx %0, 0, %3\n\t" + "cmpw %0, %1\n\t" + "bne 1f\n\t" + "stwcx. %2, 0, %3\n\t" + "bne- 0b\n\t" + "li %0, 1\n\t" + "b 2f\n\t" + "1:\n\t" + "stwcx. %0, 0, %3\n\t" + "li %0, 0\n\t" + "2:" + : "=&r"(r) + : "r"(o), "r"(n), "r"(p) + : "cc", "memory" + ); + + return r; +} + +static OF_INLINE void +OFMemoryBarrier(void) +{ + __asm__ __volatile__ ( + ".long 0x7C2004AC /* lwsync */" ::: "memory" + ); +} + +static OF_INLINE void +OFAcquireMemoryBarrier(void) +{ + __asm__ __volatile__ ( + ".long 0x7C2004AC /* lwsync */" ::: "memory" + ); +} + +static OF_INLINE void +OFReleaseMemoryBarrier(void) +{ + __asm__ __volatile__ ( + ".long 0x7C2004AC /* lwsync */" ::: "memory" + ); +} ADDED src/platform/Windows/OFPlainCondition.m Index: src/platform/Windows/OFPlainCondition.m ================================================================== --- /dev/null +++ src/platform/Windows/OFPlainCondition.m @@ -0,0 +1,135 @@ +/* + * 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 "OFPlainCondition.h" + +#include + +int +OFPlainConditionNew(OFPlainCondition *condition) +{ + condition->count = 0; + + if ((condition->event = CreateEvent(NULL, FALSE, 0, NULL)) == NULL) + return EAGAIN; + + return 0; +} + +int +OFPlainConditionSignal(OFPlainCondition *condition) +{ + if (!SetEvent(condition->event)) { + switch (GetLastError()) { + case ERROR_INVALID_HANDLE: + return EINVAL; + default: + OFEnsure(0); + } + } + + return 0; +} + +int +OFPlainConditionBroadcast(OFPlainCondition *condition) +{ + int count = condition->count; + + for (int i = 0; i < count; i++) { + if (!SetEvent(condition->event)) { + switch (GetLastError()) { + case ERROR_INVALID_HANDLE: + return EINVAL; + default: + OFEnsure(0); + } + } + } + + return 0; +} + +int +OFPlainConditionWait(OFPlainCondition *condition, OFPlainMutex *mutex) +{ + int error; + DWORD status; + + if ((error = OFPlainMutexUnlock(mutex)) != 0) + return error; + + OFAtomicIntIncrease(&condition->count); + status = WaitForSingleObject(condition->event, INFINITE); + OFAtomicIntDecrease(&condition->count); + + switch (status) { + case WAIT_OBJECT_0: + return OFPlainMutexLock(mutex); + case WAIT_FAILED: + switch (GetLastError()) { + case ERROR_INVALID_HANDLE: + return EINVAL; + default: + OFEnsure(0); + } + default: + OFEnsure(0); + } +} + +int +OFPlainConditionTimedWait(OFPlainCondition *condition, OFPlainMutex *mutex, + OFTimeInterval timeout) +{ + int error; + DWORD status; + + if ((error = OFPlainMutexUnlock(mutex)) != 0) + return error; + + OFAtomicIntIncrease(&condition->count); + status = WaitForSingleObject(condition->event, timeout * 1000); + OFAtomicIntDecrease(&condition->count); + + switch (status) { + case WAIT_OBJECT_0: + return OFPlainMutexLock(mutex); + case WAIT_TIMEOUT: + return ETIMEDOUT; + case WAIT_FAILED: + switch (GetLastError()) { + case ERROR_INVALID_HANDLE: + return EINVAL; + default: + OFEnsure(0); + } + default: + OFEnsure(0); + } +} + +int +OFPlainConditionFree(OFPlainCondition *condition) +{ + if (condition->count != 0) + return EBUSY; + + return (CloseHandle(condition->event) ? 0 : EINVAL); +} ADDED src/platform/Windows/OFPlainMutex.m Index: src/platform/Windows/OFPlainMutex.m ================================================================== --- /dev/null +++ src/platform/Windows/OFPlainMutex.m @@ -0,0 +1,93 @@ +/* + * 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 "OFPlainMutex.h" + +#include + +int +OFPlainMutexNew(OFPlainMutex *mutex) +{ + InitializeCriticalSection(mutex); + + return 0; +} + +int +OFPlainMutexLock(OFPlainMutex *mutex) +{ + EnterCriticalSection(mutex); + + return 0; +} + +int +OFPlainMutexTryLock(OFPlainMutex *mutex) +{ + if (!TryEnterCriticalSection(mutex)) + return EBUSY; + + return 0; +} + +int +OFPlainMutexUnlock(OFPlainMutex *mutex) +{ + LeaveCriticalSection(mutex); + + return 0; +} + +int +OFPlainMutexFree(OFPlainMutex *mutex) +{ + DeleteCriticalSection(mutex); + + return 0; +} + +int +OFPlainRecursiveMutexNew(OFPlainRecursiveMutex *rmutex) +{ + return OFPlainMutexNew(rmutex); +} + +int +OFPlainRecursiveMutexLock(OFPlainRecursiveMutex *rmutex) +{ + return OFPlainMutexLock(rmutex); +} + +int +OFPlainRecursiveMutexTryLock(OFPlainRecursiveMutex *rmutex) +{ + return OFPlainMutexTryLock(rmutex); +} + +int +OFPlainRecursiveMutexUnlock(OFPlainRecursiveMutex *rmutex) +{ + return OFPlainMutexUnlock(rmutex); +} + +int +OFPlainRecursiveMutexFree(OFPlainRecursiveMutex *rmutex) +{ + return OFPlainMutexFree(rmutex); +} ADDED src/platform/Windows/OFPlainThread.m Index: src/platform/Windows/OFPlainThread.m ================================================================== --- /dev/null +++ src/platform/Windows/OFPlainThread.m @@ -0,0 +1,133 @@ +/* + * 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 "OFPlainThread.h" + +#import "macros.h" + +#include + +struct ThreadContext { + void (*function)(id); + id object; +}; + +static WINAPI void +functionWrapper(struct ThreadContext *context) +{ + context->function(context->object); + + free(context); +} + +int +OFPlainThreadAttributesInit(OFPlainThreadAttributes *attr) +{ + attr->priority = 0; + attr->stackSize = 0; + + return 0; +} + +int +OFPlainThreadNew(OFPlainThread *thread, const char *name, void (*function)(id), + id object, const OFPlainThreadAttributes *attr) +{ + DWORD priority = THREAD_PRIORITY_NORMAL; + struct ThreadContext *context; + DWORD threadID; + + if (attr != NULL && attr->priority != 0) { + if (attr->priority < -1 || attr->priority > 1) + return EINVAL; + + if (attr->priority < 0) + priority = THREAD_PRIORITY_LOWEST + + (1.0 + attr->priority) * + (THREAD_PRIORITY_NORMAL - THREAD_PRIORITY_LOWEST); + else + priority = THREAD_PRIORITY_NORMAL + + attr->priority * + (THREAD_PRIORITY_HIGHEST - THREAD_PRIORITY_NORMAL); + } + + if ((context = malloc(sizeof(*context))) == NULL) + return ENOMEM; + + context->function = function; + context->object = object; + + *thread = CreateThread(NULL, (attr != NULL ? attr->stackSize : 0), + (LPTHREAD_START_ROUTINE)functionWrapper, context, 0, &threadID); + + if (thread == NULL) { + int error; + + switch (GetLastError()) { + case ERROR_NOT_ENOUGH_MEMORY: + error = ENOMEM; + break; + case ERROR_ACCESS_DENIED: + error = EACCES; + break; + default: + OFEnsure(0); + } + + free(context); + return error; + } + + if (attr != NULL && attr->priority != 0) + OFEnsure(!SetThreadPriority(*thread, priority)); + + return 0; +} + +int +OFPlainThreadJoin(OFPlainThread thread) +{ + switch (WaitForSingleObject(thread, INFINITE)) { + case WAIT_OBJECT_0: + CloseHandle(thread); + return 0; + case WAIT_FAILED: + switch (GetLastError()) { + case ERROR_INVALID_HANDLE: + return EINVAL; + default: + OFEnsure(0); + } + default: + OFEnsure(0); + } +} + +int +OFPlainThreadDetach(OFPlainThread thread) +{ + CloseHandle(thread); + + return 0; +} + +void +OFSetThreadName(const char *name) +{ +} ADDED src/platform/Windows/OFSubprocess.m Index: src/platform/Windows/OFSubprocess.m ================================================================== --- /dev/null +++ src/platform/Windows/OFSubprocess.m @@ -0,0 +1,419 @@ +/* + * 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 "OFSubprocess.h" +#import "OFArray.h" +#import "OFData.h" +#import "OFDictionary.h" +#import "OFLocale.h" +#import "OFString.h" +#import "OFSystemInfo.h" + +#import "OFInitializationFailedException.h" +#import "OFNotOpenException.h" +#import "OFOutOfRangeException.h" +#import "OFReadFailedException.h" +#import "OFWriteFailedException.h" + +#include + +@interface OFSubprocess () +- (OFChar16 *)of_wideEnvironmentForDictionary: (OFDictionary *)dictionary; +- (char *)of_environmentForDictionary: (OFDictionary *)environment; +@end + +@implementation OFSubprocess ++ (instancetype)subprocessWithProgram: (OFString *)program +{ + return [[[self alloc] initWithProgram: program] autorelease]; +} + ++ (instancetype)subprocessWithProgram: (OFString *)program + arguments: (OFArray *)arguments +{ + return [[[self alloc] initWithProgram: program + arguments: arguments] autorelease]; +} + ++ (instancetype)subprocessWithProgram: (OFString *)program + programName: (OFString *)programName + arguments: (OFArray *)arguments +{ + return [[[self alloc] initWithProgram: program + programName: programName + arguments: arguments] autorelease]; +} + ++ (instancetype)subprocessWithProgram: (OFString *)program + programName: (OFString *)programName + arguments: (OFArray *)arguments + environment: (OFDictionary *)environment +{ + return [[[self alloc] initWithProgram: program + programName: programName + arguments: arguments + environment: environment] autorelease]; +} + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)initWithProgram: (OFString *)program +{ + return [self initWithProgram: program + programName: program + arguments: nil + environment: nil]; +} + +- (instancetype)initWithProgram: (OFString *)program + arguments: (OFArray *)arguments +{ + return [self initWithProgram: program + programName: program + arguments: arguments + environment: nil]; +} + +- (instancetype)initWithProgram: (OFString *)program + programName: (OFString *)programName + arguments: (OFArray *)arguments +{ + return [self initWithProgram: program + programName: program + arguments: arguments + environment: nil]; +} + +- (instancetype)initWithProgram: (OFString *)program + programName: (OFString *)programName + arguments: (OFArray *)arguments + environment: (OFDictionary *)environment +{ + self = [super init]; + + @try { + SECURITY_ATTRIBUTES sa; + PROCESS_INFORMATION pi; + void *pool; + OFMutableString *argumentsString; + + _handle = INVALID_HANDLE_VALUE; + _readPipe[0] = _writePipe[1] = NULL; + + sa.nLength = sizeof(sa); + sa.bInheritHandle = TRUE; + sa.lpSecurityDescriptor = NULL; + + if (!CreatePipe(&_readPipe[0], &_readPipe[1], &sa, 0)) + @throw [OFInitializationFailedException + exceptionWithClass: self.class]; + + if (!SetHandleInformation(_readPipe[0], HANDLE_FLAG_INHERIT, 0)) + if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) + @throw [OFInitializationFailedException + exceptionWithClass: self.class]; + + if (!CreatePipe(&_writePipe[0], &_writePipe[1], &sa, 0)) + @throw [OFInitializationFailedException + exceptionWithClass: self.class]; + + if (!SetHandleInformation(_writePipe[1], + HANDLE_FLAG_INHERIT, 0)) + if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) + @throw [OFInitializationFailedException + exceptionWithClass: self.class]; + + memset(&pi, 0, sizeof(pi)); + + pool = objc_autoreleasePoolPush(); + + argumentsString = + [OFMutableString stringWithString: programName]; + [argumentsString replaceOccurrencesOfString: @"\\\"" + withString: @"\\\\\""]; + [argumentsString replaceOccurrencesOfString: @"\"" + withString: @"\\\""]; + + if ([argumentsString containsString: @" "]) { + [argumentsString prependString: @"\""]; + [argumentsString appendString: @"\""]; + } + + for (OFString *argument in arguments) { + OFMutableString *tmp = + [[argument mutableCopy] autorelease]; + bool containsSpaces = [tmp containsString: @" "]; + + [argumentsString appendString: @" "]; + + if (containsSpaces) + [argumentsString appendString: @"\""]; + + [tmp replaceOccurrencesOfString: @"\\\"" + withString: @"\\\\\""]; + [tmp replaceOccurrencesOfString: @"\"" + withString: @"\\\""]; + + [argumentsString appendString: tmp]; + + if (containsSpaces) + [argumentsString appendString: @"\""]; + } + + if ([OFSystemInfo isWindowsNT]) { + size_t length; + OFChar16 *argumentsCopy; + STARTUPINFOW si; + + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + si.hStdInput = _writePipe[0]; + si.hStdOutput = _readPipe[1]; + si.hStdError = GetStdHandle(STD_ERROR_HANDLE); + si.dwFlags |= STARTF_USESTDHANDLES; + + length = argumentsString.UTF16StringLength; + argumentsCopy = OFAllocMemory(length + 1, + sizeof(OFChar16)); + memcpy(argumentsCopy, argumentsString.UTF16String, + (length + 1) * 2); + @try { + if (!CreateProcessW(program.UTF16String, + argumentsCopy, NULL, NULL, TRUE, + CREATE_UNICODE_ENVIRONMENT, + [self of_wideEnvironmentForDictionary: + environment], NULL, &si, &pi)) + @throw [OFInitializationFailedException + exceptionWithClass: self.class]; + } @finally { + OFFreeMemory(argumentsCopy); + } + } else { + OFStringEncoding encoding = [OFLocale encoding]; + STARTUPINFO si; + + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + si.hStdInput = _writePipe[0]; + si.hStdOutput = _readPipe[1]; + si.hStdError = GetStdHandle(STD_ERROR_HANDLE); + si.dwFlags |= STARTF_USESTDHANDLES; + + if (!CreateProcessA([program cStringWithEncoding: + encoding], (char *)[argumentsString + cStringWithEncoding: encoding], NULL, NULL, TRUE, 0, + [self of_environmentForDictionary: environment], + NULL, &si, &pi)) + @throw [OFInitializationFailedException + exceptionWithClass: self.class]; + } + + objc_autoreleasePoolPop(pool); + + _handle = pi.hProcess; + CloseHandle(pi.hThread); + + CloseHandle(_readPipe[1]); + CloseHandle(_writePipe[0]); + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + if (_readPipe[0] != NULL) + [self close]; + + [super dealloc]; +} + +- (OFChar16 *)of_wideEnvironmentForDictionary: (OFDictionary *)environment +{ + OFMutableData *env; + OFEnumerator *keyEnumerator, *objectEnumerator; + OFString *key, *object; + const OFChar16 equal = '='; + const OFChar16 zero[2] = { 0, 0 }; + + if (environment == nil) + return NULL; + + env = [OFMutableData dataWithItemSize: sizeof(OFChar16)]; + + keyEnumerator = [environment keyEnumerator]; + objectEnumerator = [environment objectEnumerator]; + while ((key = [keyEnumerator nextObject]) != nil && + (object = [objectEnumerator nextObject]) != nil) { + [env addItems: key.UTF16String count: key.UTF16StringLength]; + [env addItems: &equal count: 1]; + [env addItems: object.UTF16String + count: object.UTF16StringLength]; + [env addItems: &zero count: 1]; + } + [env addItems: zero count: 2]; + + return env.mutableItems; +} + +- (char *)of_environmentForDictionary: (OFDictionary *)environment +{ + OFStringEncoding encoding = [OFLocale encoding]; + OFMutableData *env; + OFEnumerator *keyEnumerator, *objectEnumerator; + OFString *key, *object; + + if (environment == nil) + return NULL; + + env = [OFMutableData data]; + + keyEnumerator = [environment keyEnumerator]; + objectEnumerator = [environment objectEnumerator]; + while ((key = [keyEnumerator nextObject]) != nil && + (object = [objectEnumerator nextObject]) != nil) { + [env addItems: [key cStringWithEncoding: encoding] + count: [key cStringLengthWithEncoding: encoding]]; + [env addItems: "=" count: 1]; + [env addItems: [object cStringWithEncoding: encoding] + count: [object cStringLengthWithEncoding: encoding]]; + [env addItems: "" count: 1]; + } + [env addItems: "\0" count: 2]; + + return env.mutableItems; +} + +- (bool)lowlevelIsAtEndOfStream +{ + if (_readPipe[0] == NULL) + @throw [OFNotOpenException exceptionWithObject: self]; + + return _atEndOfStream; +} + +- (size_t)lowlevelReadIntoBuffer: (void *)buffer length: (size_t)length +{ + DWORD ret; + + if (length > UINT32_MAX) + @throw [OFOutOfRangeException exception]; + + if (_readPipe[0] == NULL) + @throw [OFNotOpenException exceptionWithObject: self]; + + if (!ReadFile(_readPipe[0], buffer, (DWORD)length, &ret, NULL)) { + if (GetLastError() == ERROR_BROKEN_PIPE) { + _atEndOfStream = true; + return 0; + } + + @throw [OFReadFailedException exceptionWithObject: self + requestedLength: length + errNo: EIO]; + } + + if (ret == 0) + _atEndOfStream = true; + + return ret; +} + +- (size_t)lowlevelWriteBuffer: (const void *)buffer length: (size_t)length +{ + DWORD bytesWritten; + + if (length > UINT32_MAX) + @throw [OFOutOfRangeException exception]; + + if (_writePipe[1] == NULL) + @throw [OFNotOpenException exceptionWithObject: self]; + + if (!WriteFile(_writePipe[1], buffer, (DWORD)length, &bytesWritten, + NULL)) { + int errNo = EIO; + + if (GetLastError() == ERROR_BROKEN_PIPE) + errNo = EPIPE; + + @throw [OFWriteFailedException exceptionWithObject: self + requestedLength: length + bytesWritten: bytesWritten + errNo: errNo]; + } + + return (size_t)bytesWritten; +} + +- (void)closeForWriting +{ + if (_writePipe[1] != NULL) + CloseHandle(_writePipe[1]); + + _writePipe[1] = NULL; +} + +- (void)close +{ + if (_readPipe[0] == NULL) + @throw [OFNotOpenException exceptionWithObject: self]; + + [self closeForWriting]; + CloseHandle(_readPipe[0]); + + if (_handle != INVALID_HANDLE_VALUE) { + TerminateProcess(_handle, 0); + CloseHandle(_handle); + } + + _handle = INVALID_HANDLE_VALUE; + _readPipe[0] = NULL; + + [super close]; +} + +- (int)waitForTermination +{ + if (_readPipe[0] == NULL) + @throw [OFNotOpenException exceptionWithObject: self]; + + if (_handle != INVALID_HANDLE_VALUE) { + DWORD exitCode; + + WaitForSingleObject(_handle, INFINITE); + + if (GetExitCodeProcess(_handle, &exitCode)) + _status = exitCode; + else + _status = GetLastError(); + + CloseHandle(_handle); + _handle = INVALID_HANDLE_VALUE; + } + + return _status; +} +@end ADDED src/platform/Windows/OFTLSKey.m Index: src/platform/Windows/OFTLSKey.m ================================================================== --- /dev/null +++ src/platform/Windows/OFTLSKey.m @@ -0,0 +1,35 @@ +/* + * 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 "OFTLSKey.h" + +int +OFTLSKeyNew(OFTLSKey *key) +{ + *key = TlsAlloc(); + + if (*key == TLS_OUT_OF_INDEXES) + return EAGAIN; + + return 0; +} + +int +OFTLSKeyFree(OFTLSKey key) +{ + return (TlsFree(key) ? 0 : EINVAL); +} DELETED src/platform/amiga/OFString+PathAdditions.m Index: src/platform/amiga/OFString+PathAdditions.m ================================================================== --- src/platform/amiga/OFString+PathAdditions.m +++ /dev/null @@ -1,340 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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+PathAdditions.h" -#import "OFArray.h" -#import "OFFileURLHandler.h" - -#import "OFOutOfRangeException.h" - -int _OFString_PathAdditions_reference; - -@implementation OFString (PathAdditions) -+ (OFString *)pathWithComponents: (OFArray *)components -{ - OFMutableString *ret = [OFMutableString string]; - void *pool = objc_autoreleasePoolPush(); - bool firstAfterDevice = true; - - for (OFString *component in components) { - if (component.length == 0) - continue; - - if (!firstAfterDevice) - [ret appendString: @"/"]; - - [ret appendString: component]; - - if (![component hasSuffix: @":"]) - firstAfterDevice = false; - } - - [ret makeImmutable]; - - objc_autoreleasePoolPop(pool); - - return ret; -} - -- (bool)isAbsolutePath -{ - return [self containsString: @":"]; -} - -- (OFArray *)pathComponents -{ - OFMutableArray OF_GENERIC(OFString *) *ret = [OFMutableArray array]; - void *pool = objc_autoreleasePoolPush(); - const char *cString = self.UTF8String; - size_t i, last = 0, cStringLength = self.UTF8StringLength; - - if (cStringLength == 0) { - objc_autoreleasePoolPop(pool); - return ret; - } - - for (i = 0; i < cStringLength; i++) { - if (cString[i] == '/') { - if (i - last != 0) - [ret addObject: [OFString - stringWithUTF8String: cString + last - length: i - last]]; - else - [ret addObject: @"/"]; - - last = i + 1; - } else if (cString[i] == ':') { - [ret addObject: [OFString - stringWithUTF8String: cString + last - length: i - last + 1]]; - - last = i + 1; - } - } - if (i - last != 0) - [ret addObject: [OFString stringWithUTF8String: cString + last - length: i - last]]; - - [ret makeImmutable]; - - objc_autoreleasePoolPop(pool); - - return ret; -} - -- (OFString *)lastPathComponent -{ - /* - * AmigaOS needs the full parsing to determine the last path component. - * This could be optimized by not creating the temporary objects, - * though. - */ - void *pool = objc_autoreleasePoolPush(); - OFString *ret = self.pathComponents.lastObject; - - [ret retain]; - objc_autoreleasePoolPop(pool); - return [ret autorelease]; -} - -- (OFString *)pathExtension -{ - void *pool = objc_autoreleasePoolPush(); - OFString *ret, *fileName; - size_t pos; - - fileName = self.lastPathComponent; - pos = [fileName rangeOfString: @"." - options: OF_STRING_SEARCH_BACKWARDS].location; - if (pos == OF_NOT_FOUND || pos == 0) { - objc_autoreleasePoolPop(pool); - return @""; - } - - ret = [fileName substringFromIndex: pos + 1]; - - [ret retain]; - objc_autoreleasePoolPop(pool); - return [ret autorelease]; -} - -- (OFString *)stringByDeletingLastPathComponent -{ - /* - * AmigaOS needs the full parsing to delete the last path component. - * This could be optimized, though. - */ - void *pool = objc_autoreleasePoolPush(); - OFArray OF_GENERIC(OFString *) *components = self.pathComponents; - size_t count = components.count; - OFString *ret; - - if (count < 2) { - if ([components.firstObject hasSuffix: @":"]) { - ret = [components.firstObject retain]; - objc_autoreleasePoolPop(pool); - return [ret autorelease]; - } - - objc_autoreleasePoolPop(pool); - return @""; - } - - components = [components objectsInRange: - of_range(0, components.count - 1)]; - ret = [OFString pathWithComponents: components]; - - [ret retain]; - objc_autoreleasePoolPop(pool); - return [ret autorelease]; -} - -- (OFString *)stringByDeletingPathExtension -{ - void *pool; - OFMutableArray OF_GENERIC(OFString *) *components; - OFString *ret, *fileName; - size_t pos; - - if (self.length == 0) - return [[self copy] autorelease]; - - pool = objc_autoreleasePoolPush(); - components = [[self.pathComponents mutableCopy] autorelease]; - fileName = components.lastObject; - - pos = [fileName rangeOfString: @"." - options: OF_STRING_SEARCH_BACKWARDS].location; - if (pos == OF_NOT_FOUND || pos == 0) { - objc_autoreleasePoolPop(pool); - return [[self copy] autorelease]; - } - - fileName = [fileName substringToIndex: pos]; - [components replaceObjectAtIndex: components.count - 1 - withObject: fileName]; - - ret = [OFString pathWithComponents: components]; - - [ret retain]; - objc_autoreleasePoolPop(pool); - return [ret autorelease]; -} - -- (OFString *)stringByStandardizingPath -{ - void *pool = objc_autoreleasePoolPush(); - OFArray OF_GENERIC(OFString *) *components; - OFMutableArray OF_GENERIC(OFString *) *array; - OFString *ret; - bool done = false; - - if (self.length == 0) - return @""; - - components = self.pathComponents; - - if (components.count == 1) { - objc_autoreleasePoolPop(pool); - return [[self copy] autorelease]; - } - - array = [[components mutableCopy] autorelease]; - - while (!done) { - size_t length = array.count; - - done = true; - - for (size_t i = 0; i < length; i++) { - OFString *component = [array objectAtIndex: i]; - OFString *parent = - (i > 0 ? [array objectAtIndex: i - 1] : 0); - - if (component.length == 0) { - [array removeObjectAtIndex: i]; - - done = false; - break; - } - - if ([component isEqual: @"/"] && - parent != nil && ![parent isEqual: @"/"]) { - [array removeObjectsInRange: - of_range(i - 1, 2)]; - - done = false; - break; - } - } - } - - ret = [OFString pathWithComponents: array]; - - if ([self hasSuffix: @"/"]) - ret = [ret stringByAppendingString: @"/"]; - - [ret retain]; - objc_autoreleasePoolPop(pool); - return [ret autorelease]; -} - -- (OFString *)stringByAppendingPathComponent: (OFString *)component -{ - if ([self hasSuffix: @"/"] || [self hasSuffix: @":"]) - return [self stringByAppendingString: component]; - else { - OFMutableString *ret = [[self mutableCopy] autorelease]; - - [ret appendString: @"/"]; - [ret appendString: component]; - - [ret makeImmutable]; - - return ret; - } -} - -- (bool)of_isDirectoryPath -{ - return ([self hasSuffix: @"/"] || [self hasSuffix: @":"] || - [OFFileURLHandler of_directoryExistsAtPath: self]); -} - -- (OFString *)of_pathToURLPathWithURLEncodedHost: (OFString **)URLEncodedHost -{ - OFArray OF_GENERIC(OFString *) *components = self.pathComponents; - OFMutableString *ret = [OFMutableString string]; - - for (OFString *component in components) { - if (component.length == 0) - continue; - - if ([component isEqual: @"/"]) - [ret appendString: @"/.."]; - else { - [ret appendString: @"/"]; - [ret appendString: component]; - } - } - - [ret makeImmutable]; - - return ret; -} - -- (OFString *)of_URLPathToPathWithURLEncodedHost: (OFString *)URLEncodedHost -{ - OFString *path = self; - - if (path.length > 1 && [path hasSuffix: @"/"]) - path = [path substringToIndex: path.length - 1]; - - OFMutableArray OF_GENERIC(OFString *) *components; - size_t count; - - path = [path substringFromIndex: 1]; - components = [[[path - componentsSeparatedByString: @"/"] mutableCopy] autorelease]; - count = components.count; - - for (size_t i = 0; i < count; i++) { - OFString *component = [components objectAtIndex: i]; - - if ([component isEqual: @"."]) { - [components removeObjectAtIndex: i]; - count--; - - i--; - continue; - } - - if ([component isEqual: @".."]) - [components replaceObjectAtIndex: i - withObject: @"/"]; - } - - return [OFString pathWithComponents: components]; -} - -- (OFString *)of_pathComponentToURLPathComponent -{ - return self; -} -@end DELETED src/platform/amiga/condition.m Index: src/platform/amiga/condition.m ================================================================== --- src/platform/amiga/condition.m +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "condition.h" - -#include -#include -#ifndef OF_AMIGAOS4 -# include -#endif - -bool -of_condition_new(of_condition_t *condition) -{ - condition->waitingTasks = NULL; - - return true; -} - -bool -of_condition_signal(of_condition_t *condition) -{ - Forbid(); - @try { - if (condition->waitingTasks == NULL) - return true; - - Signal(condition->waitingTasks->task, - (1ul << condition->waitingTasks->sigBit)); - - condition->waitingTasks = condition->waitingTasks->next; - } @finally { - Permit(); - } - - return true; -} - -bool -of_condition_broadcast(of_condition_t *condition) -{ - Forbid(); - @try { - if (condition->waitingTasks == NULL) - return true; - - while (condition->waitingTasks != NULL) { - Signal(condition->waitingTasks->task, - (1ul << condition->waitingTasks->sigBit)); - - condition->waitingTasks = condition->waitingTasks->next; - } - } @finally { - Permit(); - } - - return true; -} - -bool -of_condition_wait(of_condition_t *condition, of_mutex_t *mutex) -{ - ULONG signalMask = 0; - - return of_condition_wait_or_signal(condition, mutex, &signalMask); -} - -bool -of_condition_wait_or_signal(of_condition_t *condition, of_mutex_t *mutex, - ULONG *signalMask) -{ - struct of_condition_waiting_task waitingTask = { - .task = FindTask(NULL), - .sigBit = AllocSignal(-1) - }; - bool ret; - ULONG mask; - - if (waitingTask.sigBit == -1) { - errno = EAGAIN; - return false; - } - - Forbid(); - - if (!of_mutex_unlock(mutex)) { - FreeSignal(waitingTask.sigBit); - return false; - } - - waitingTask.next = condition->waitingTasks; - condition->waitingTasks = &waitingTask; - - mask = Wait((1ul << waitingTask.sigBit) | *signalMask); - if (mask & (1ul << waitingTask.sigBit) || (*signalMask &= mask)) - ret = of_mutex_lock(mutex); - else { - /* - * This should not happen - it means something interrupted the - * Wait(), so the best we can do is return EINTR. - */ - ret = false; - errno = EINTR; - } - - FreeSignal(waitingTask.sigBit); - - Permit(); - - return ret; -} - -bool -of_condition_timed_wait(of_condition_t *condition, of_mutex_t *mutex, - of_time_interval_t timeout) -{ - ULONG signalMask = 0; - - return of_condition_timed_wait_or_signal(condition, mutex, timeout, - &signalMask); -} - -bool -of_condition_timed_wait_or_signal(of_condition_t *condition, of_mutex_t *mutex, - of_time_interval_t timeout, ULONG *signalMask) -{ - struct of_condition_waiting_task waitingTask = { - .task = FindTask(NULL), - .sigBit = AllocSignal(-1) - }; - struct MsgPort port = { - .mp_Node = { - .ln_Type = NT_MSGPORT - }, - .mp_Flags = PA_SIGNAL, - .mp_SigTask = waitingTask.task, - .mp_SigBit = AllocSignal(-1) - }; -#ifdef OF_AMIGAOS4 - struct TimeRequest request = { - .Request = { -#else - struct timerequest request = { - .tr_node = { -#endif - .io_Message = { - .mn_Node = { - .ln_Type = NT_MESSAGE - }, - .mn_ReplyPort = &port, - .mn_Length = sizeof(request) - }, - .io_Command = TR_ADDREQUEST - }, -#ifdef OF_AMIGAOS4 - .Time = { - .Seconds = (ULONG)timeout, - .Microseconds = - (timeout - request.Time.Seconds) * 1000000 -#else - .tr_time = { - .tv_sec = (ULONG)timeout, - .tv_micro = (timeout - request.tr_time.tv_sec) * 1000000 -#endif - } - }; - ULONG mask; - bool ret; - - NewList(&port.mp_MsgList); - - if (waitingTask.sigBit == -1 || port.mp_SigBit == -1) { - errno = EAGAIN; - goto fail; - } - - if (OpenDevice("timer.device", UNIT_MICROHZ, - (struct IORequest *)&request, 0) != 0) { - errno = EAGAIN; - goto fail; - } - - Forbid(); - - if (!of_mutex_unlock(mutex)) { - Permit(); - goto fail; - } - - waitingTask.next = condition->waitingTasks; - condition->waitingTasks = &waitingTask; - - SendIO((struct IORequest *)&request); - - mask = Wait((1ul << waitingTask.sigBit) | (1ul << port.mp_SigBit) | - *signalMask); - if (mask & (1ul << waitingTask.sigBit) || (*signalMask &= mask)) - ret = of_mutex_lock(mutex); - else if (mask & (1ul << port.mp_SigBit)) { - ret = false; - errno = ETIMEDOUT; - } else { - /* - * This should not happen - it means something interrupted the - * Wait(), so the best we can do is return EINTR. - */ - ret = false; - errno = EINTR; - } - - condition->waitingTasks = waitingTask.next; - - if (!CheckIO((struct IORequest *)&request)) { - AbortIO((struct IORequest *)&request); - WaitIO((struct IORequest *)&request); - } - CloseDevice((struct IORequest *)&request); - - Permit(); - - FreeSignal(waitingTask.sigBit); - FreeSignal(port.mp_SigBit); - - return ret; - -fail: - if (waitingTask.sigBit != -1) - FreeSignal(waitingTask.sigBit); - if (port.mp_SigBit != -1) - FreeSignal(port.mp_SigBit); - - return false; -} - -bool -of_condition_free(of_condition_t *condition) -{ - Forbid(); - @try { - if (condition->waitingTasks != NULL) { - errno = EBUSY; - return false; - } - } @finally { - Permit(); - } - - return true; -} DELETED src/platform/amiga/mutex.m Index: src/platform/amiga/mutex.m ================================================================== --- src/platform/amiga/mutex.m +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "mutex.h" - -#include - -bool -of_mutex_new(of_mutex_t *mutex) -{ - InitSemaphore(mutex); - - return true; -} - -bool -of_mutex_lock(of_mutex_t *mutex) -{ - ObtainSemaphore(mutex); - - return true; -} - -bool -of_mutex_trylock(of_mutex_t *mutex) -{ - if (!AttemptSemaphore(mutex)) { - errno = EBUSY; - return false; - } - - return true; -} - -bool -of_mutex_unlock(of_mutex_t *mutex) -{ - ReleaseSemaphore(mutex); - - return true; -} - -bool -of_mutex_free(of_mutex_t *mutex) -{ - return true; -} - -bool -of_rmutex_new(of_rmutex_t *rmutex) -{ - return of_mutex_new(rmutex); -} - -bool -of_rmutex_lock(of_rmutex_t *rmutex) -{ - return of_mutex_lock(rmutex); -} - -bool -of_rmutex_trylock(of_rmutex_t *rmutex) -{ - return of_mutex_trylock(rmutex); -} - -bool -of_rmutex_unlock(of_rmutex_t *rmutex) -{ - return of_mutex_unlock(rmutex); -} - -bool -of_rmutex_free(of_rmutex_t *rmutex) -{ - return of_mutex_free(rmutex); -} DELETED src/platform/amiga/thread.m Index: src/platform/amiga/thread.m ================================================================== --- src/platform/amiga/thread.m +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "OFData.h" - -#import "thread.h" -#import "tlskey.h" - -#include -#include -#include - -extern void of_tlskey_thread_exited(void); -static of_tlskey_t threadKey; - -OF_CONSTRUCTOR() -{ - OF_ENSURE(of_tlskey_new(&threadKey)); -} - -static void -functionWrapper(void) -{ - bool detached = false; - of_thread_t thread = - (of_thread_t)((struct Process *)FindTask(NULL))->pr_ExitData; - OF_ENSURE(of_tlskey_set(threadKey, thread)); - - thread->function(thread->object); - - ObtainSemaphore(&thread->semaphore); - @try { - thread->done = true; - - of_tlskey_thread_exited(); - - if (thread->detached) - detached = true; - else if (thread->joinTask != NULL) - Signal(thread->joinTask, (1ul << thread->joinSigBit)); - } @finally { - ReleaseSemaphore(&thread->semaphore); - } - - if (detached) - free(thread); -} - -bool -of_thread_attr_init(of_thread_attr_t *attr) -{ - attr->priority = 0; - attr->stackSize = 0; - - return true; -} - -bool -of_thread_new(of_thread_t *thread, const char *name, void (*function)(id), - id object, const of_thread_attr_t *attr) -{ - OFMutableData *tags = nil; - - if ((*thread = calloc(1, sizeof(**thread))) == NULL) { - errno = ENOMEM; - return false; - } - - @try { - (*thread)->function = function; - (*thread)->object = object; - InitSemaphore(&(*thread)->semaphore); - - tags = [[OFMutableData alloc] - initWithItemSize: sizeof(struct TagItem) - capacity: 12]; -#define ADD_TAG(tag, data) \ - { \ - struct TagItem t = { \ - .ti_Tag = tag, \ - .ti_Data = data \ - }; \ - [tags addItem: &t]; \ - } - ADD_TAG(NP_Entry, (ULONG)functionWrapper) - ADD_TAG(NP_ExitData, (ULONG)*thread) -#ifdef OF_AMIGAOS4 - ADD_TAG(NP_Child, TRUE) -#endif -#ifdef OF_MORPHOS - ADD_TAG(NP_CodeType, CODETYPE_PPC); -#endif - if (name != NULL) - ADD_TAG(NP_Name, (ULONG)name); - - ADD_TAG(NP_Input, ((struct Process *)FindTask(NULL))->pr_CIS) - ADD_TAG(NP_Output, ((struct Process *)FindTask(NULL))->pr_COS) - ADD_TAG(NP_Error, ((struct Process *)FindTask(NULL))->pr_CES) - ADD_TAG(NP_CloseInput, FALSE) - ADD_TAG(NP_CloseOutput, FALSE) - ADD_TAG(NP_CloseError, FALSE) - - if (attr != NULL && attr->priority != 0) { - if (attr->priority < 1 || attr->priority > 1) { - errno = EINVAL; - return false; - } - - /* - * -1 should be -128 (lowest possible priority) while - * +1 should be +127 (highest possible priority). - */ - ADD_TAG(NP_Priority, (attr->priority > 0 - ? attr->priority * 127 : attr->priority * 128)) - } - - if (attr != NULL && attr->stackSize != 0) - ADD_TAG(NP_StackSize, attr->stackSize) - else - ADD_TAG(NP_StackSize, - ((struct Process *)FindTask(NULL))->pr_StackSize) - - ADD_TAG(TAG_DONE, 0) -#undef ADD_TAG - - (*thread)->task = (struct Task *)CreateNewProc(tags.items); - if ((*thread)->task == NULL) { - free(*thread); - errno = EAGAIN; - return false; - } - } @catch (id e) { - free(*thread); - @throw e; - } @finally { - [tags release]; - } - - return true; -} - -of_thread_t -of_thread_current(void) -{ - return of_tlskey_get(threadKey); -} - -bool -of_thread_join(of_thread_t thread) -{ - ObtainSemaphore(&thread->semaphore); - - if (thread->done) { - ReleaseSemaphore(&thread->semaphore); - - free(thread); - return true; - } - - @try { - if (thread->detached || thread->joinTask != NULL) { - errno = EINVAL; - return false; - } - - if ((thread->joinSigBit = AllocSignal(-1)) == -1) { - errno = EAGAIN; - return false; - } - - thread->joinTask = FindTask(NULL); - } @finally { - ReleaseSemaphore(&thread->semaphore); - } - - Wait(1ul << thread->joinSigBit); - FreeSignal(thread->joinSigBit); - - assert(thread->done); - free(thread); - - return true; -} - -bool -of_thread_detach(of_thread_t thread) -{ - ObtainSemaphore(&thread->semaphore); - - if (thread->done) - free(thread); - else - thread->detached = true; - - ReleaseSemaphore(&thread->semaphore); - - return true; -} - -void -of_thread_set_name(const char *name) -{ -} DELETED src/platform/amiga/tlskey.m Index: src/platform/amiga/tlskey.m ================================================================== --- src/platform/amiga/tlskey.m +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "tlskey.h" - -#include -#include - -/* - * As we use this file in both the runtime and ObjFW, and since AmigaOS always - * has the runtime, use the hashtable from the runtime. - */ -#import "runtime/private.h" - -static of_tlskey_t firstKey = NULL, lastKey = NULL; -static struct SignalSemaphore semaphore; -static bool semaphoreInitialized = false; - -static uint32_t -hashFunc(const void *ptr) -{ - return (uint32_t)(uintptr_t)ptr; -} - -static bool -equalFunc(const void *ptr1, const void *ptr2) -{ - return (ptr1 == ptr2); -} - -OF_CONSTRUCTOR() -{ - if (!semaphoreInitialized) { - InitSemaphore(&semaphore); - semaphoreInitialized = true; - } -} - -bool -of_tlskey_new(of_tlskey_t *key) -{ - if (!semaphoreInitialized) { - /* - * We might be called from another constructor, while ours has - * not run yet. This is safe, as the constructor is definitely - * run before a thread is spawned. - */ - InitSemaphore(&semaphore); - semaphoreInitialized = true; - } - - if ((*key = malloc(sizeof(**key))) == NULL) - return false; - - (*key)->table = NULL; - - ObtainSemaphore(&semaphore); - @try { - (*key)->next = NULL; - (*key)->previous = lastKey; - - if (lastKey != NULL) - lastKey->next = *key; - - lastKey = *key; - - if (firstKey == NULL) - firstKey = *key; - } @finally { - ReleaseSemaphore(&semaphore); - } - - /* We create the hash table lazily. */ - return true; -} - -bool -of_tlskey_free(of_tlskey_t key) -{ - ObtainSemaphore(&semaphore); - @try { - if (key->previous != NULL) - key->previous->next = key->next; - if (key->next != NULL) - key->next->previous = key->previous; - - if (firstKey == key) - firstKey = key->next; - if (lastKey == key) - lastKey = key->previous; - - objc_hashtable_free(key->table); - free(key); - } @finally { - ReleaseSemaphore(&semaphore); - } - - return true; -} - -void * -of_tlskey_get(of_tlskey_t key) -{ - void *ret; - - ObtainSemaphore(&semaphore); - @try { - if (key->table == NULL) - return NULL; - - ret = objc_hashtable_get(key->table, FindTask(NULL)); - } @finally { - ReleaseSemaphore(&semaphore); - } - - return ret; -} - -bool -of_tlskey_set(of_tlskey_t key, void *ptr) -{ - ObtainSemaphore(&semaphore); - @try { - struct Task *task = FindTask(NULL); - - if (key->table == NULL) - key->table = objc_hashtable_new(hashFunc, equalFunc, 2); - - if (ptr == NULL) - objc_hashtable_delete(key->table, task); - else - objc_hashtable_set(key->table, task, ptr); - } @catch (id e) { - return false; - } @finally { - ReleaseSemaphore(&semaphore); - } - - return true; -} - -void -of_tlskey_thread_exited(void) -{ - ObtainSemaphore(&semaphore); - @try { - struct Task *task = FindTask(NULL); - - for (of_tlskey_t iter = firstKey; iter != NULL; - iter = iter->next) - if (iter->table != NULL) - objc_hashtable_delete(iter->table, task); - } @finally { - ReleaseSemaphore(&semaphore); - } -} Index: src/platform/libfat/OFString+PathAdditions.m ================================================================== --- src/platform/libfat/OFString+PathAdditions.m +++ src/platform/libfat/OFString+PathAdditions.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -153,12 +151,12 @@ OFString *ret, *fileName; size_t pos; fileName = self.lastPathComponent; pos = [fileName rangeOfString: @"." - options: OF_STRING_SEARCH_BACKWARDS].location; - if (pos == OF_NOT_FOUND || pos == 0) { + options: OFStringSearchBackwards].location; + if (pos == OFNotFound || pos == 0) { objc_autoreleasePoolPop(pool); return @""; } ret = [fileName substringFromIndex: pos + 1]; @@ -223,12 +221,12 @@ pool = objc_autoreleasePoolPush(); components = [[self.pathComponents mutableCopy] autorelease]; fileName = components.lastObject; pos = [fileName rangeOfString: @"." - options: OF_STRING_SEARCH_BACKWARDS].location; - if (pos == OF_NOT_FOUND || pos == 0) { + options: OFStringSearchBackwards].location; + if (pos == OFNotFound || pos == 0) { objc_autoreleasePoolPop(pool); return [[self copy] autorelease]; } fileName = [fileName substringToIndex: pos]; @@ -281,11 +279,11 @@ } if ([component isEqual: @".."] && parent != nil && ![parent isEqual: @".."]) { [array removeObjectsInRange: - of_range(i - 1, 2)]; + OFRangeMake(i - 1, 2)]; done = false; break; } } ADDED src/platform/macOS/OFAtomic.h Index: src/platform/macOS/OFAtomic.h ================================================================== --- /dev/null +++ src/platform/macOS/OFAtomic.h @@ -0,0 +1,157 @@ +/* + * 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 + +static OF_INLINE int +OFAtomicIntAdd(volatile int *_Nonnull p, int i) +{ + return OSAtomicAdd32(i, p); +} + +static OF_INLINE int32_t +OFAtomicInt32Add(volatile int32_t *_Nonnull p, int32_t i) +{ + return OSAtomicAdd32(i, p); +} + +static OF_INLINE void *_Nullable +OFAtomicPointerAdd(void *volatile _Nullable *_Nonnull p, intptr_t i) +{ +#ifdef __LP64__ + return (void *)OSAtomicAdd64(i, (int64_t *)p); +#else + return (void *)OSAtomicAdd32(i, (int32_t *)p); +#endif +} + +static OF_INLINE int +OFAtomicIntSubtract(volatile int *_Nonnull p, int i) +{ + return OSAtomicAdd32(-i, p); +} + +static OF_INLINE int32_t +OFAtomicInt32Subtract(volatile int32_t *_Nonnull p, int32_t i) +{ + return OSAtomicAdd32(-i, p); +} + +static OF_INLINE void *_Nullable +OFAtomicPointerSubtract(void *volatile _Nullable *_Nonnull p, intptr_t i) +{ +#ifdef __LP64__ + return (void *)OSAtomicAdd64(-i, (int64_t *)p); +#else + return (void *)OSAtomicAdd32(-i, (int32_t *)p); +#endif +} + +static OF_INLINE int +OFAtomicIntIncrease(volatile int *_Nonnull p) +{ + return OSAtomicIncrement32(p); +} + +static OF_INLINE int32_t +OFAtomicInt32Increase(volatile int32_t *_Nonnull p) +{ + return OSAtomicIncrement32(p); +} + +static OF_INLINE int +OFAtomicIntDecrease(volatile int *_Nonnull p) +{ + return OSAtomicDecrement32(p); +} + +static OF_INLINE int32_t +OFAtomicInt32Decrease(volatile int32_t *_Nonnull p) +{ + return OSAtomicDecrement32(p); +} + +static OF_INLINE unsigned int +OFAtomicIntOr(volatile unsigned int *_Nonnull p, unsigned int i) +{ + return OSAtomicOr32(i, p); +} + +static OF_INLINE uint32_t +OFAtomicInt32Or(volatile uint32_t *_Nonnull p, uint32_t i) +{ + return OSAtomicOr32(i, p); +} + +static OF_INLINE unsigned int +OFAtomicIntAnd(volatile unsigned int *_Nonnull p, unsigned int i) +{ + return OSAtomicAnd32(i, p); +} + +static OF_INLINE uint32_t +OFAtomicInt32And(volatile uint32_t *_Nonnull p, uint32_t i) +{ + return OSAtomicAnd32(i, p); +} + +static OF_INLINE unsigned int +OFAtomicIntXor(volatile unsigned int *_Nonnull p, unsigned int i) +{ + return OSAtomicXor32(i, p); +} + +static OF_INLINE uint32_t +OFAtomicInt32Xor(volatile uint32_t *_Nonnull p, uint32_t i) +{ + return OSAtomicXor32(i, p); +} + +static OF_INLINE bool +OFAtomicIntCompareAndSwap(volatile int *_Nonnull p, int o, int n) +{ + return OSAtomicCompareAndSwapInt(o, n, p); +} + +static OF_INLINE bool +OFAtomicInt32CompareAndSwap(volatile int32_t *_Nonnull p, int32_t o, int32_t n) +{ + return OSAtomicCompareAndSwap32(o, n, p); +} + +static OF_INLINE bool +OFAtomicPointerCompareAndSwap(void *volatile _Nullable *_Nonnull p, + void *_Nullable o, void *_Nullable n) +{ + return OSAtomicCompareAndSwapPtr(o, n, p); +} + +static OF_INLINE void +OFMemoryBarrier(void) +{ + OSMemoryBarrier(); +} + +static OF_INLINE void +OFAcquireMemoryBarrier(void) +{ + OSMemoryBarrier(); +} + +static OF_INLINE void +OFReleaseMemoryBarrier(void) +{ + OSMemoryBarrier(); +} DELETED src/platform/posix/OFProcess.m Index: src/platform/posix/OFProcess.m ================================================================== --- src/platform/posix/OFProcess.m +++ /dev/null @@ -1,393 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 - -#ifdef HAVE_SYS_WAIT_H -# include -#endif - -#include "unistd_wrapper.h" -#ifdef HAVE_SPAWN_H -# include -#endif - -#import "OFProcess.h" -#import "OFString.h" -#import "OFArray.h" -#import "OFDictionary.h" -#import "OFLocale.h" - -#import "OFInitializationFailedException.h" -#import "OFNotOpenException.h" -#import "OFOutOfRangeException.h" -#import "OFReadFailedException.h" -#import "OFWriteFailedException.h" - -#ifndef HAVE_POSIX_SPAWNP -extern char **environ; -#endif - -@interface OFProcess () -- (void)of_getArgv: (char ***)argv - forProgramName: (OFString *)programName - andArguments: (OFArray *)arguments; -- (char **)of_environmentForDictionary: (OFDictionary *)dictionary; -@end - -@implementation OFProcess -+ (instancetype)processWithProgram: (OFString *)program -{ - return [[[self alloc] initWithProgram: program] autorelease]; -} - -+ (instancetype)processWithProgram: (OFString *)program - arguments: (OFArray *)arguments -{ - return [[[self alloc] initWithProgram: program - arguments: arguments] autorelease]; -} - -+ (instancetype)processWithProgram: (OFString *)program - programName: (OFString *)programName - arguments: (OFArray *)arguments -{ - return [[[self alloc] initWithProgram: program - programName: programName - arguments: arguments] autorelease]; -} - -+ (instancetype)processWithProgram: (OFString *)program - programName: (OFString *)programName - arguments: (OFArray *)arguments - environment: (OFDictionary *)environment -{ - return [[[self alloc] initWithProgram: program - programName: programName - arguments: arguments - environment: environment] autorelease]; -} - -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - -- (instancetype)initWithProgram: (OFString *)program -{ - return [self initWithProgram: program - programName: program - arguments: nil - environment: nil]; -} - -- (instancetype)initWithProgram: (OFString *)program - arguments: (OFArray *)arguments -{ - return [self initWithProgram: program - programName: program - arguments: arguments - environment: nil]; -} - -- (instancetype)initWithProgram: (OFString *)program - programName: (OFString *)programName - arguments: (OFArray *)arguments -{ - return [self initWithProgram: program - programName: program - arguments: arguments - environment: nil]; -} - -- (instancetype)initWithProgram: (OFString *)program - programName: (OFString *)programName - arguments: (OFArray *)arguments - environment: (OFDictionary *)environment -{ - self = [super init]; - - @try { - void *pool = objc_autoreleasePoolPush(); - const char *path; - char **argv; - - _pid = -1; - _readPipe[0] = _writePipe[1] = -1; - - if (pipe(_readPipe) != 0 || pipe(_writePipe) != 0) - @throw [OFInitializationFailedException - exceptionWithClass: self.class]; - - path = [program cStringWithEncoding: [OFLocale encoding]]; - [self of_getArgv: &argv - forProgramName: programName - andArguments: arguments]; - - @try { - char **env = [self - of_environmentForDictionary: environment]; -#ifdef HAVE_POSIX_SPAWNP - posix_spawn_file_actions_t actions; - posix_spawnattr_t attr; - - if (posix_spawn_file_actions_init(&actions) != 0) - @throw [OFInitializationFailedException - exceptionWithClass: self.class]; - - if (posix_spawnattr_init(&attr) != 0) { - posix_spawn_file_actions_destroy(&actions); - - @throw [OFInitializationFailedException - exceptionWithClass: self.class]; - } - - @try { - if (posix_spawn_file_actions_addclose(&actions, - _readPipe[0]) != 0 || - posix_spawn_file_actions_addclose(&actions, - _writePipe[1]) != 0 || - posix_spawn_file_actions_adddup2(&actions, - _writePipe[0], 0) != 0 || - posix_spawn_file_actions_adddup2(&actions, - _readPipe[1], 1) != 0) - @throw [OFInitializationFailedException - exceptionWithClass: self.class]; - -# ifdef POSIX_SPAWN_CLOEXEC_DEFAULT - if (posix_spawnattr_setflags(&attr, - POSIX_SPAWN_CLOEXEC_DEFAULT) != 0) - @throw [OFInitializationFailedException - exceptionWithClass: self.class]; -# endif - - if (posix_spawnp(&_pid, path, &actions, &attr, - argv, env) != 0) - @throw [OFInitializationFailedException - exceptionWithClass: self.class]; - } @finally { - posix_spawn_file_actions_destroy(&actions); - posix_spawnattr_destroy(&attr); - } -#else - if ((_pid = vfork()) == 0) { - environ = env; - - close(_readPipe[0]); - close(_writePipe[1]); - dup2(_writePipe[0], 0); - dup2(_readPipe[1], 1); - execvp(path, argv); - - _exit(EXIT_FAILURE); - } - - if (_pid == -1) - @throw [OFInitializationFailedException - exceptionWithClass: self.class]; -#endif - } @finally { - close(_readPipe[1]); - close(_writePipe[0]); - [self freeMemory: argv]; - } - - objc_autoreleasePoolPop(pool); - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - if (_readPipe[0] != -1) - [self close]; - - [super dealloc]; -} - -- (void)of_getArgv: (char ***)argv - forProgramName: (OFString *)programName - andArguments: (OFArray *)arguments -{ - OFString *const *objects = arguments.objects; - size_t i, count = arguments.count; - of_string_encoding_t encoding; - - *argv = [self allocMemoryWithSize: sizeof(char *) - count: count + 2]; - - encoding = [OFLocale encoding]; - - (*argv)[0] = (char *)[programName cStringWithEncoding: encoding]; - - for (i = 0; i < count; i++) - (*argv)[i + 1] = - (char *)[objects[i] cStringWithEncoding: encoding]; - - (*argv)[i + 1] = NULL; -} - -- (char **)of_environmentForDictionary: (OFDictionary *)environment -{ - OFEnumerator *keyEnumerator, *objectEnumerator; - char **envp; - size_t i, count; - of_string_encoding_t encoding; - - if (environment == nil) - return NULL; - - encoding = [OFLocale encoding]; - - count = environment.count; - envp = [self allocMemoryWithSize: sizeof(char *) - count: count + 1]; - - keyEnumerator = [environment keyEnumerator]; - objectEnumerator = [environment objectEnumerator]; - - for (i = 0; i < count; i++) { - OFString *key; - OFString *object; - size_t keyLen, objectLen; - - key = [keyEnumerator nextObject]; - object = [objectEnumerator nextObject]; - - keyLen = [key cStringLengthWithEncoding: encoding]; - objectLen = [object cStringLengthWithEncoding: encoding]; - - envp[i] = [self allocMemoryWithSize: keyLen + objectLen + 2]; - - memcpy(envp[i], [key cStringWithEncoding: encoding], keyLen); - envp[i][keyLen] = '='; - memcpy(envp[i] + keyLen + 1, - [object cStringWithEncoding: encoding], objectLen); - envp[i][keyLen + objectLen + 1] = '\0'; - } - - envp[i] = NULL; - - return envp; -} - -- (bool)lowlevelIsAtEndOfStream -{ - if (_readPipe[0] == -1) - @throw [OFNotOpenException exceptionWithObject: self]; - - return _atEndOfStream; -} - -- (size_t)lowlevelReadIntoBuffer: (void *)buffer - length: (size_t)length -{ - ssize_t ret; - - if (_readPipe[0] == -1) - @throw [OFNotOpenException exceptionWithObject: self]; - - if ((ret = read(_readPipe[0], buffer, length)) < 0) - @throw [OFReadFailedException exceptionWithObject: self - requestedLength: length - errNo: errno]; - - if (ret == 0) - _atEndOfStream = true; - - return ret; -} - -- (size_t)lowlevelWriteBuffer: (const void *)buffer - length: (size_t)length -{ - ssize_t bytesWritten; - - if (_writePipe[1] == -1) - @throw [OFNotOpenException exceptionWithObject: self]; - - if (length > SSIZE_MAX) - @throw [OFOutOfRangeException exception]; - - if ((bytesWritten = write(_writePipe[1], buffer, length)) < 0) - @throw [OFWriteFailedException exceptionWithObject: self - requestedLength: length - bytesWritten: 0 - errNo: errno]; - - return (size_t)bytesWritten; -} - -- (int)fileDescriptorForReading -{ - return _readPipe[0]; -} - -- (int)fileDescriptorForWriting -{ - return _writePipe[1]; -} - -- (void)closeForWriting -{ - if (_writePipe[1] != -1) - close(_writePipe[1]); - - _writePipe[1] = -1; -} - -- (void)close -{ - if (_readPipe[0] == -1) - @throw [OFNotOpenException exceptionWithObject: self]; - - [self closeForWriting]; - close(_readPipe[0]); - - if (_pid != -1) { - kill(_pid, SIGTERM); - waitpid(_pid, &_status, WNOHANG); - } - - _pid = -1; - _readPipe[0] = -1; - - [super close]; -} - -- (int)waitForTermination -{ - if (_readPipe[0] == -1) - @throw [OFNotOpenException exceptionWithObject: self]; - - if (_pid != -1) { - waitpid(_pid, &_status, 0); - _pid = -1; - } - - return WEXITSTATUS(_status); -} -@end Index: src/platform/posix/OFString+PathAdditions.m ================================================================== --- src/platform/posix/OFString+PathAdditions.m +++ src/platform/posix/OFString+PathAdditions.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -146,12 +144,12 @@ OFString *ret, *fileName; size_t pos; fileName = self.lastPathComponent; pos = [fileName rangeOfString: @"." - options: OF_STRING_SEARCH_BACKWARDS].location; - if (pos == OF_NOT_FOUND || pos == 0) { + options: OFStringSearchBackwards].location; + if (pos == OFNotFound || pos == 0) { objc_autoreleasePoolPop(pool); return @""; } ret = [fileName substringFromIndex: pos + 1]; @@ -215,12 +213,12 @@ pool = objc_autoreleasePoolPush(); components = [[self.pathComponents mutableCopy] autorelease]; fileName = components.lastObject; pos = [fileName rangeOfString: @"." - options: OF_STRING_SEARCH_BACKWARDS].location; - if (pos == OF_NOT_FOUND || pos == 0) { + options: OFStringSearchBackwards].location; + if (pos == OFNotFound || pos == 0) { objc_autoreleasePoolPop(pool); return [[self copy] autorelease]; } fileName = [fileName substringToIndex: pos]; @@ -277,21 +275,20 @@ } if ([component isEqual: @".."] && parent != nil && ![parent isEqual: @".."]) { [array removeObjectsInRange: - of_range(i - 1, 2)]; + OFRangeMake(i - 1, 2)]; done = false; break; } } } if (startsWithSlash) - [array insertObject: @"" - atIndex: 0]; + [array insertObject: @"" atIndex: 0]; if ([self hasSuffix: @"/"]) [array addObject: @""]; ret = [[array componentsJoinedByString: @"/"] retain]; DELETED src/platform/posix/condition.m Index: src/platform/posix/condition.m ================================================================== --- src/platform/posix/condition.m +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "condition.h" - -bool -of_condition_new(of_condition_t *condition) -{ - return (pthread_cond_init(condition, NULL) == 0); -} - -bool -of_condition_signal(of_condition_t *condition) -{ - return (pthread_cond_signal(condition) == 0); -} - -bool -of_condition_broadcast(of_condition_t *condition) -{ - return (pthread_cond_broadcast(condition) == 0); -} - -bool -of_condition_wait(of_condition_t *condition, of_mutex_t *mutex) -{ - return (pthread_cond_wait(condition, mutex) == 0); -} - -bool -of_condition_timed_wait(of_condition_t *condition, of_mutex_t *mutex, - of_time_interval_t timeout) -{ - struct timespec ts; - - ts.tv_sec = (time_t)timeout; - ts.tv_nsec = (long)((timeout - ts.tv_sec) * 1000000000); - - return (pthread_cond_timedwait(condition, mutex, &ts) == 0); -} - -bool -of_condition_free(of_condition_t *condition) -{ - return (pthread_cond_destroy(condition) == 0); -} DELETED src/platform/posix/mutex.m Index: src/platform/posix/mutex.m ================================================================== --- src/platform/posix/mutex.m +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "mutex.h" - -bool -of_mutex_new(of_mutex_t *mutex) -{ - return (pthread_mutex_init(mutex, NULL) == 0); -} - -bool -of_mutex_lock(of_mutex_t *mutex) -{ - return (pthread_mutex_lock(mutex) == 0); -} - -bool -of_mutex_trylock(of_mutex_t *mutex) -{ - return (pthread_mutex_trylock(mutex) == 0); -} - -bool -of_mutex_unlock(of_mutex_t *mutex) -{ - return (pthread_mutex_unlock(mutex) == 0); -} - -bool -of_mutex_free(of_mutex_t *mutex) -{ - return (pthread_mutex_destroy(mutex) == 0); -} - -#ifdef OF_HAVE_RECURSIVE_PTHREAD_MUTEXES -bool -of_rmutex_new(of_rmutex_t *rmutex) -{ - pthread_mutexattr_t attr; - - if (pthread_mutexattr_init(&attr) != 0) - return false; - - if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0) - return false; - - if (pthread_mutex_init(rmutex, &attr) != 0) - return false; - - if (pthread_mutexattr_destroy(&attr) != 0) - return false; - - return true; -} - -bool -of_rmutex_lock(of_rmutex_t *rmutex) -{ - return of_mutex_lock(rmutex); -} - -bool -of_rmutex_trylock(of_rmutex_t *rmutex) -{ - return of_mutex_trylock(rmutex); -} - -bool -of_rmutex_unlock(of_rmutex_t *rmutex) -{ - return of_mutex_unlock(rmutex); -} - -bool -of_rmutex_free(of_rmutex_t *rmutex) -{ - return of_mutex_free(rmutex); -} -#else -bool -of_rmutex_new(of_rmutex_t *rmutex) -{ - if (!of_mutex_new(&rmutex->mutex)) - return false; - - if (!of_tlskey_new(&rmutex->count)) - return false; - - return true; -} - -bool -of_rmutex_lock(of_rmutex_t *rmutex) -{ - uintptr_t count = (uintptr_t)of_tlskey_get(rmutex->count); - - if (count > 0) { - if (!of_tlskey_set(rmutex->count, (void *)(count + 1))) - return false; - - return true; - } - - if (!of_mutex_lock(&rmutex->mutex)) - return false; - - if (!of_tlskey_set(rmutex->count, (void *)1)) { - of_mutex_unlock(&rmutex->mutex); - return false; - } - - return true; -} - -bool -of_rmutex_trylock(of_rmutex_t *rmutex) -{ - uintptr_t count = (uintptr_t)of_tlskey_get(rmutex->count); - - if (count > 0) { - if (!of_tlskey_set(rmutex->count, (void *)(count + 1))) - return false; - - return true; - } - - if (!of_mutex_trylock(&rmutex->mutex)) - return false; - - if (!of_tlskey_set(rmutex->count, (void *)1)) { - of_mutex_unlock(&rmutex->mutex); - return false; - } - - return true; -} - -bool -of_rmutex_unlock(of_rmutex_t *rmutex) -{ - uintptr_t count = (uintptr_t)of_tlskey_get(rmutex->count); - - if (count > 1) { - if (!of_tlskey_set(rmutex->count, (void *)(count - 1))) - return false; - - return true; - } - - if (!of_tlskey_set(rmutex->count, (void *)0)) - return false; - - if (!of_mutex_unlock(&rmutex->mutex)) - return false; - - return true; -} - -bool -of_rmutex_free(of_rmutex_t *rmutex) -{ - if (!of_mutex_free(&rmutex->mutex)) - return false; - - if (!of_tlskey_free(rmutex->count)) - return false; - - return true; -} -#endif DELETED src/platform/posix/thread.m Index: src/platform/posix/thread.m ================================================================== --- src/platform/posix/thread.m +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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_PTHREAD_NP_H -# include -#endif - -#ifdef OF_HAIKU -# include -#endif - -#import "thread.h" -#import "macros.h" - -static int minPrio = 0, maxPrio = 0, normalPrio = 0; - -struct thread_ctx { - void (*function)(id object); - id object; - const char *name; -}; - -/* - * This is done here to make sure this is done as early as possible in the main - * thread. - */ -OF_CONSTRUCTOR() -{ - pthread_attr_t pattr; - - if (pthread_attr_init(&pattr) == 0) { -#ifdef HAVE_PTHREAD_ATTR_GETSCHEDPOLICY - int policy; -#endif - struct sched_param param; - -#ifdef HAVE_PTHREAD_ATTR_GETSCHEDPOLICY - if (pthread_attr_getschedpolicy(&pattr, &policy) == 0) { - minPrio = sched_get_priority_min(policy); - maxPrio = sched_get_priority_max(policy); - - if (minPrio == -1 || maxPrio == -1) - minPrio = maxPrio = 0; - } -#endif - - if (pthread_attr_getschedparam(&pattr, ¶m) != 0) - normalPrio = param.sched_priority; - else - minPrio = maxPrio = 0; - - pthread_attr_destroy(&pattr); - } -} - -static void * -functionWrapper(void *data) -{ - struct thread_ctx *ctx = data; - - if (ctx->name != NULL) - of_thread_set_name(ctx->name); - - pthread_cleanup_push(free, data); - - ctx->function(ctx->object); - - pthread_cleanup_pop(1); - return NULL; -} - -bool -of_thread_attr_init(of_thread_attr_t *attr) -{ - pthread_attr_t pattr; - - if (pthread_attr_init(&pattr) != 0) - return false; - - @try { - attr->priority = 0; - - if (pthread_attr_getstacksize(&pattr, &attr->stackSize) != 0) - return false; - } @finally { - pthread_attr_destroy(&pattr); - } - - return true; -} - -bool -of_thread_new(of_thread_t *thread, const char *name, void (*function)(id), - id object, const of_thread_attr_t *attr) -{ - bool ret; - pthread_attr_t pattr; - - if (pthread_attr_init(&pattr) != 0) - return false; - - @try { - struct thread_ctx *ctx; - - if (attr != NULL) { - struct sched_param param; - - if (attr->priority < -1 || attr->priority > 1) { - errno = EINVAL; - return false; - } - -#ifdef HAVE_PTHREAD_ATTR_SETINHERITSCHED - if (pthread_attr_setinheritsched(&pattr, - PTHREAD_EXPLICIT_SCHED) != 0) - return false; -#endif - - if (attr->priority < 0) { - param.sched_priority = minPrio + - (1.0f + attr->priority) * - (normalPrio - minPrio); - } else - param.sched_priority = normalPrio + - attr->priority * (maxPrio - normalPrio); - - if (pthread_attr_setschedparam(&pattr, ¶m) != 0) - return false; - - if (attr->stackSize > 0) { - if (pthread_attr_setstacksize(&pattr, - attr->stackSize) != 0) - return false; - } - } - - if ((ctx = malloc(sizeof(*ctx))) == NULL) { - errno = ENOMEM; - return false; - } - - ctx->function = function; - ctx->object = object; - ctx->name = name; - - ret = (pthread_create(thread, &pattr, - functionWrapper, ctx) == 0); - } @finally { - pthread_attr_destroy(&pattr); - } - - return ret; -} - -bool -of_thread_join(of_thread_t thread) -{ - void *ret; - - return (pthread_join(thread, &ret) == 0); -} - -bool -of_thread_detach(of_thread_t thread) -{ - return (pthread_detach(thread) == 0); -} - -void -of_thread_set_name(const char *name) -{ -#if defined(OF_HAIKU) - rename_thread(find_thread(NULL), name); -#elif defined(HAVE_PTHREAD_SET_NAME_NP) - pthread_set_name_np(pthread_self(), name); -#elif defined(HAVE_PTHREAD_SETNAME_NP) -# if defined(OF_MACOS) || defined(OF_IOS) - pthread_setname_np(name); -# elif defined(__GLIBC__) - char buffer[16]; - - strncpy(buffer, name, 15); - buffer[15] = 0; - - pthread_setname_np(pthread_self(), buffer); -# endif -#endif -} DELETED src/platform/posix/tlskey.m Index: src/platform/posix/tlskey.m ================================================================== --- src/platform/posix/tlskey.m +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "tlskey.h" - -bool -of_tlskey_new(of_tlskey_t *key) -{ - return (pthread_key_create(key, NULL) == 0); -} - -bool -of_tlskey_free(of_tlskey_t key) -{ - return (pthread_key_delete(key) == 0); -} DELETED src/platform/windows/OFProcess.m Index: src/platform/windows/OFProcess.m ================================================================== --- src/platform/windows/OFProcess.m +++ /dev/null @@ -1,431 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "OFProcess.h" -#import "OFArray.h" -#import "OFData.h" -#import "OFDictionary.h" -#import "OFLocale.h" -#import "OFString.h" -#import "OFSystemInfo.h" - -#import "OFInitializationFailedException.h" -#import "OFNotOpenException.h" -#import "OFOutOfRangeException.h" -#import "OFReadFailedException.h" -#import "OFWriteFailedException.h" - -#include - -@interface OFProcess () -- (of_char16_t *)of_wideEnvironmentForDictionary: (OFDictionary *)dictionary; -- (char *)of_environmentForDictionary: (OFDictionary *)environment; -@end - -@implementation OFProcess -+ (instancetype)processWithProgram: (OFString *)program -{ - return [[[self alloc] initWithProgram: program] autorelease]; -} - -+ (instancetype)processWithProgram: (OFString *)program - arguments: (OFArray *)arguments -{ - return [[[self alloc] initWithProgram: program - arguments: arguments] autorelease]; -} - -+ (instancetype)processWithProgram: (OFString *)program - programName: (OFString *)programName - arguments: (OFArray *)arguments -{ - return [[[self alloc] initWithProgram: program - programName: programName - arguments: arguments] autorelease]; -} - -+ (instancetype)processWithProgram: (OFString *)program - programName: (OFString *)programName - arguments: (OFArray *)arguments - environment: (OFDictionary *)environment -{ - return [[[self alloc] initWithProgram: program - programName: programName - arguments: arguments - environment: environment] autorelease]; -} - -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - -- (instancetype)initWithProgram: (OFString *)program -{ - return [self initWithProgram: program - programName: program - arguments: nil - environment: nil]; -} - -- (instancetype)initWithProgram: (OFString *)program - arguments: (OFArray *)arguments -{ - return [self initWithProgram: program - programName: program - arguments: arguments - environment: nil]; -} - -- (instancetype)initWithProgram: (OFString *)program - programName: (OFString *)programName - arguments: (OFArray *)arguments -{ - return [self initWithProgram: program - programName: program - arguments: arguments - environment: nil]; -} - -- (instancetype)initWithProgram: (OFString *)program - programName: (OFString *)programName - arguments: (OFArray *)arguments - environment: (OFDictionary *)environment -{ - self = [super init]; - - @try { - SECURITY_ATTRIBUTES sa; - PROCESS_INFORMATION pi; - void *pool; - OFMutableString *argumentsString; - - _process = INVALID_HANDLE_VALUE; - _readPipe[0] = _writePipe[1] = NULL; - - sa.nLength = sizeof(sa); - sa.bInheritHandle = TRUE; - sa.lpSecurityDescriptor = NULL; - - if (!CreatePipe(&_readPipe[0], &_readPipe[1], &sa, 0)) - @throw [OFInitializationFailedException - exceptionWithClass: self.class]; - - if (!SetHandleInformation(_readPipe[0], HANDLE_FLAG_INHERIT, 0)) - if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) - @throw [OFInitializationFailedException - exceptionWithClass: self.class]; - - if (!CreatePipe(&_writePipe[0], &_writePipe[1], &sa, 0)) - @throw [OFInitializationFailedException - exceptionWithClass: self.class]; - - if (!SetHandleInformation(_writePipe[1], - HANDLE_FLAG_INHERIT, 0)) - if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) - @throw [OFInitializationFailedException - exceptionWithClass: self.class]; - - memset(&pi, 0, sizeof(pi)); - - pool = objc_autoreleasePoolPush(); - - argumentsString = - [OFMutableString stringWithString: programName]; - [argumentsString replaceOccurrencesOfString: @"\\\"" - withString: @"\\\\\""]; - [argumentsString replaceOccurrencesOfString: @"\"" - withString: @"\\\""]; - - if ([argumentsString containsString: @" "]) { - [argumentsString prependString: @"\""]; - [argumentsString appendString: @"\""]; - } - - for (OFString *argument in arguments) { - OFMutableString *tmp = - [[argument mutableCopy] autorelease]; - bool containsSpaces = [tmp containsString: @" "]; - - [argumentsString appendString: @" "]; - - if (containsSpaces) - [argumentsString appendString: @"\""]; - - [tmp replaceOccurrencesOfString: @"\\\"" - withString: @"\\\\\""]; - [tmp replaceOccurrencesOfString: @"\"" - withString: @"\\\""]; - - [argumentsString appendString: tmp]; - - if (containsSpaces) - [argumentsString appendString: @"\""]; - } - - if ([OFSystemInfo isWindowsNT]) { - size_t length; - of_char16_t *argumentsCopy; - STARTUPINFOW si; - - memset(&si, 0, sizeof(si)); - si.cb = sizeof(si); - si.hStdInput = _writePipe[0]; - si.hStdOutput = _readPipe[1]; - si.hStdError = GetStdHandle(STD_ERROR_HANDLE); - si.dwFlags |= STARTF_USESTDHANDLES; - - length = argumentsString.UTF16StringLength; - argumentsCopy = [self - allocMemoryWithSize: sizeof(of_char16_t) - count: length + 1]; - memcpy(argumentsCopy, argumentsString.UTF16String, - (length + 1) * 2); - @try { - if (!CreateProcessW(program.UTF16String, - argumentsCopy, NULL, NULL, TRUE, - CREATE_UNICODE_ENVIRONMENT, - [self of_wideEnvironmentForDictionary: - environment], NULL, &si, &pi)) - @throw [OFInitializationFailedException - exceptionWithClass: self.class]; - } @finally { - [self freeMemory: argumentsCopy]; - } - } else { - of_string_encoding_t encoding = [OFLocale encoding]; - STARTUPINFO si; - - memset(&si, 0, sizeof(si)); - si.cb = sizeof(si); - si.hStdInput = _writePipe[0]; - si.hStdOutput = _readPipe[1]; - si.hStdError = GetStdHandle(STD_ERROR_HANDLE); - si.dwFlags |= STARTF_USESTDHANDLES; - - if (!CreateProcessA([program cStringWithEncoding: - encoding], (char *)[argumentsString - cStringWithEncoding: encoding], NULL, NULL, TRUE, 0, - [self of_environmentForDictionary: environment], - NULL, &si, &pi)) - @throw [OFInitializationFailedException - exceptionWithClass: self.class]; - } - - objc_autoreleasePoolPop(pool); - - _process = pi.hProcess; - CloseHandle(pi.hThread); - - CloseHandle(_readPipe[1]); - CloseHandle(_writePipe[0]); - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - if (_readPipe[0] != NULL) - [self close]; - - [super dealloc]; -} - -- (of_char16_t *)of_wideEnvironmentForDictionary: (OFDictionary *)environment -{ - OFMutableData *env; - OFEnumerator *keyEnumerator, *objectEnumerator; - OFString *key, *object; - const of_char16_t equal = '='; - const of_char16_t zero[2] = { 0, 0 }; - - if (environment == nil) - return NULL; - - env = [OFMutableData dataWithItemSize: sizeof(of_char16_t)]; - - keyEnumerator = [environment keyEnumerator]; - objectEnumerator = [environment objectEnumerator]; - while ((key = [keyEnumerator nextObject]) != nil && - (object = [objectEnumerator nextObject]) != nil) { - [env addItems: key.UTF16String - count: key.UTF16StringLength]; - [env addItems: &equal - count: 1]; - [env addItems: object.UTF16String - count: object.UTF16StringLength]; - [env addItems: &zero - count: 1]; - } - [env addItems: zero - count: 2]; - - return env.mutableItems; -} - -- (char *)of_environmentForDictionary: (OFDictionary *)environment -{ - of_string_encoding_t encoding = [OFLocale encoding]; - OFMutableData *env; - OFEnumerator *keyEnumerator, *objectEnumerator; - OFString *key, *object; - - if (environment == nil) - return NULL; - - env = [OFMutableData data]; - - keyEnumerator = [environment keyEnumerator]; - objectEnumerator = [environment objectEnumerator]; - while ((key = [keyEnumerator nextObject]) != nil && - (object = [objectEnumerator nextObject]) != nil) { - [env addItems: [key cStringWithEncoding: encoding] - count: [key cStringLengthWithEncoding: encoding]]; - [env addItems: "=" - count: 1]; - [env addItems: [object cStringWithEncoding: encoding] - count: [object cStringLengthWithEncoding: encoding]]; - [env addItems: "" - count: 1]; - } - [env addItems: "\0" - count: 2]; - - return env.mutableItems; -} - -- (bool)lowlevelIsAtEndOfStream -{ - if (_readPipe[0] == NULL) - @throw [OFNotOpenException exceptionWithObject: self]; - - return _atEndOfStream; -} - -- (size_t)lowlevelReadIntoBuffer: (void *)buffer - length: (size_t)length -{ - DWORD ret; - - if (length > UINT32_MAX) - @throw [OFOutOfRangeException exception]; - - if (_readPipe[0] == NULL) - @throw [OFNotOpenException exceptionWithObject: self]; - - if (!ReadFile(_readPipe[0], buffer, (DWORD)length, &ret, NULL)) { - if (GetLastError() == ERROR_BROKEN_PIPE) { - _atEndOfStream = true; - return 0; - } - - @throw [OFReadFailedException exceptionWithObject: self - requestedLength: length - errNo: EIO]; - } - - if (ret == 0) - _atEndOfStream = true; - - return ret; -} - -- (size_t)lowlevelWriteBuffer: (const void *)buffer - length: (size_t)length -{ - DWORD bytesWritten; - - if (length > UINT32_MAX) - @throw [OFOutOfRangeException exception]; - - if (_writePipe[1] == NULL) - @throw [OFNotOpenException exceptionWithObject: self]; - - if (!WriteFile(_writePipe[1], buffer, (DWORD)length, &bytesWritten, - NULL)) { - int errNo = EIO; - - if (GetLastError() == ERROR_BROKEN_PIPE) - errNo = EPIPE; - - @throw [OFWriteFailedException exceptionWithObject: self - requestedLength: length - bytesWritten: 0 - errNo: errNo]; - } - - return (size_t)bytesWritten; -} - -- (void)closeForWriting -{ - if (_writePipe[1] != NULL) - CloseHandle(_writePipe[1]); - - _writePipe[1] = NULL; -} - -- (void)close -{ - if (_readPipe[0] == NULL) - @throw [OFNotOpenException exceptionWithObject: self]; - - [self closeForWriting]; - CloseHandle(_readPipe[0]); - - if (_process != INVALID_HANDLE_VALUE) { - TerminateProcess(_process, 0); - CloseHandle(_process); - } - - _process = INVALID_HANDLE_VALUE; - _readPipe[0] = NULL; - - [super close]; -} - -- (int)waitForTermination -{ - if (_readPipe[0] == NULL) - @throw [OFNotOpenException exceptionWithObject: self]; - - if (_process != INVALID_HANDLE_VALUE) { - DWORD exitCode; - - WaitForSingleObject(_process, INFINITE); - - if (GetExitCodeProcess(_process, &exitCode)) - _status = exitCode; - else - _status = GetLastError(); - - CloseHandle(_process); - _process = INVALID_HANDLE_VALUE; - } - - return _status; -} -@end Index: src/platform/windows/OFString+PathAdditions.m ================================================================== --- src/platform/windows/OFString+PathAdditions.m +++ src/platform/windows/OFString+PathAdditions.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -14,12 +12,12 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ /* - * This file is also used for MS-DOS! Don't forget to #ifdef Windows-specific - * parts! + * This file is also used for MS-DOS and MiNT! Don't forget to #ifdef + * Windows-specific parts! */ #include "config.h" #import "OFString+PathAdditions.h" @@ -157,12 +155,12 @@ OFString *ret, *fileName; size_t pos; fileName = self.lastPathComponent; pos = [fileName rangeOfString: @"." - options: OF_STRING_SEARCH_BACKWARDS].location; - if (pos == OF_NOT_FOUND || pos == 0) { + options: OFStringSearchBackwards].location; + if (pos == OFNotFound || pos == 0) { objc_autoreleasePoolPop(pool); return @""; } ret = [fileName substringFromIndex: pos + 1]; @@ -203,11 +201,11 @@ objc_autoreleasePoolPop(pool); return @"."; } components = [components objectsInRange: - of_range(0, components.count - 1)]; + OFRangeMake(0, components.count - 1)]; ret = [OFString pathWithComponents: components]; [ret retain]; objc_autoreleasePoolPop(pool); return [ret autorelease]; @@ -226,12 +224,12 @@ pool = objc_autoreleasePoolPush(); components = [[self.pathComponents mutableCopy] autorelease]; fileName = components.lastObject; pos = [fileName rangeOfString: @"." - options: OF_STRING_SEARCH_BACKWARDS].location; - if (pos == OF_NOT_FOUND || pos == 0) { + options: OFStringSearchBackwards].location; + if (pos == OFNotFound || pos == 0) { objc_autoreleasePoolPop(pool); return [[self copy] autorelease]; } fileName = [fileName substringToIndex: pos]; @@ -288,11 +286,11 @@ ![parent hasSuffix: @":"] && ![parent hasSuffix: @":\\"] && ![parent hasSuffix: @"://"] && (![parent hasPrefix: @"\\"] || i != 1)) { [array removeObjectsInRange: - of_range(i - 1, 2)]; + OFRangeMake(i - 1, 2)]; done = false; break; } } @@ -339,11 +337,11 @@ *URLEncodedHost = [[components objectAtIndex: 1] stringByURLEncodingWithAllowedCharacters: [OFCharacterSet URLHostAllowedCharacterSet]]; path = [OFString pathWithComponents: [components - objectsInRange: of_range(2, components.count - 2)]]; + objectsInRange: OFRangeMake(2, components.count - 2)]]; } path = [path stringByReplacingOccurrencesOfString: @"\\" withString: @"/"]; path = [path stringByPrependingString: @"/"]; DELETED src/platform/windows/condition.m Index: src/platform/windows/condition.m ================================================================== --- src/platform/windows/condition.m +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "condition.h" - -#include - -bool -of_condition_new(of_condition_t *condition) -{ - condition->count = 0; - - if ((condition->event = CreateEvent(NULL, FALSE, 0, NULL)) == NULL) { - errno = EAGAIN; - return false; - } - - return true; -} - -bool -of_condition_signal(of_condition_t *condition) -{ - if (!SetEvent(condition->event)) { - switch (GetLastError()) { - case ERROR_INVALID_HANDLE: - errno = EINVAL; - return false; - default: - OF_ENSURE(0); - } - } - - return true; -} - -bool -of_condition_broadcast(of_condition_t *condition) -{ - int count = condition->count; - - for (int i = 0; i < count; i++) { - if (!SetEvent(condition->event)) { - switch (GetLastError()) { - case ERROR_INVALID_HANDLE: - errno = EINVAL; - return false; - default: - OF_ENSURE(0); - } - } - } - - return true; -} - -bool -of_condition_wait(of_condition_t *condition, of_mutex_t *mutex) -{ - DWORD status; - - if (!of_mutex_unlock(mutex)) - return false; - - of_atomic_int_inc(&condition->count); - status = WaitForSingleObject(condition->event, INFINITE); - of_atomic_int_dec(&condition->count); - - switch (status) { - case WAIT_OBJECT_0: - return of_mutex_lock(mutex); - case WAIT_FAILED: - switch (GetLastError()) { - case ERROR_INVALID_HANDLE: - errno = EINVAL; - return false; - default: - OF_ENSURE(0); - } - default: - OF_ENSURE(0); - } -} - -bool -of_condition_timed_wait(of_condition_t *condition, of_mutex_t *mutex, - of_time_interval_t timeout) -{ - DWORD status; - - if (!of_mutex_unlock(mutex)) - return false; - - of_atomic_int_inc(&condition->count); - status = WaitForSingleObject(condition->event, timeout * 1000); - of_atomic_int_dec(&condition->count); - - switch (status) { - case WAIT_OBJECT_0: - return of_mutex_lock(mutex); - case WAIT_TIMEOUT: - errno = ETIMEDOUT; - return false; - case WAIT_FAILED: - switch (GetLastError()) { - case ERROR_INVALID_HANDLE: - errno = EINVAL; - return false; - default: - OF_ENSURE(0); - } - default: - OF_ENSURE(0); - } -} - -bool -of_condition_free(of_condition_t *condition) -{ - if (condition->count != 0) { - errno = EBUSY; - return false; - } - - return CloseHandle(condition->event); -} DELETED src/platform/windows/mutex.m Index: src/platform/windows/mutex.m ================================================================== --- src/platform/windows/mutex.m +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "mutex.h" - -#include - -bool -of_mutex_new(of_mutex_t *mutex) -{ - InitializeCriticalSection(mutex); - - return true; -} - -bool -of_mutex_lock(of_mutex_t *mutex) -{ - EnterCriticalSection(mutex); - - return true; -} - -bool -of_mutex_trylock(of_mutex_t *mutex) -{ - if (!TryEnterCriticalSection(mutex)) { - errno = EBUSY; - return false; - } - - return true; -} - -bool -of_mutex_unlock(of_mutex_t *mutex) -{ - LeaveCriticalSection(mutex); - - return true; -} - -bool -of_mutex_free(of_mutex_t *mutex) -{ - DeleteCriticalSection(mutex); - - return true; -} - -bool -of_rmutex_new(of_rmutex_t *rmutex) -{ - return of_mutex_new(rmutex); -} - -bool -of_rmutex_lock(of_rmutex_t *rmutex) -{ - return of_mutex_lock(rmutex); -} - -bool -of_rmutex_trylock(of_rmutex_t *rmutex) -{ - return of_mutex_trylock(rmutex); -} - -bool -of_rmutex_unlock(of_rmutex_t *rmutex) -{ - return of_mutex_unlock(rmutex); -} - -bool -of_rmutex_free(of_rmutex_t *rmutex) -{ - return of_mutex_free(rmutex); -} DELETED src/platform/windows/thread.m Index: src/platform/windows/thread.m ================================================================== --- src/platform/windows/thread.m +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "thread.h" -#import "macros.h" - -#include - -struct thread_context { - void (*function)(id); - id object; -}; - -static WINAPI void -functionWrapper(struct thread_context *context) -{ - context->function(context->object); - - free(context); -} - -bool -of_thread_attr_init(of_thread_attr_t *attr) -{ - attr->priority = 0; - attr->stackSize = 0; - - return true; -} - -bool -of_thread_new(of_thread_t *thread, const char *name, void (*function)(id), - id object, const of_thread_attr_t *attr) -{ - DWORD priority = THREAD_PRIORITY_NORMAL; - struct thread_context *context; - DWORD threadID; - - if (attr != NULL && attr->priority != 0) { - if (attr->priority < -1 || attr->priority > 1) { - errno = EINVAL; - return false; - } - - if (attr->priority < 0) - priority = THREAD_PRIORITY_LOWEST + - (1.0 + attr->priority) * - (THREAD_PRIORITY_NORMAL - THREAD_PRIORITY_LOWEST); - else - priority = THREAD_PRIORITY_NORMAL + - attr->priority * - (THREAD_PRIORITY_HIGHEST - THREAD_PRIORITY_NORMAL); - } - - if ((context = malloc(sizeof(*context))) == NULL) { - errno = ENOMEM; - return false; - } - - context->function = function; - context->object = object; - - *thread = CreateThread(NULL, (attr != NULL ? attr->stackSize : 0), - (LPTHREAD_START_ROUTINE)functionWrapper, context, 0, &threadID); - - if (thread == NULL) { - int errNo; - - switch (GetLastError()) { - case ERROR_NOT_ENOUGH_MEMORY: - errNo = ENOMEM; - break; - case ERROR_ACCESS_DENIED: - errNo = EACCES; - break; - default: - OF_ENSURE(0); - } - - free(context); - errno = errNo; - return false; - } - - if (attr != NULL && attr->priority != 0) - OF_ENSURE(!SetThreadPriority(*thread, priority)); - - return true; -} - -bool -of_thread_join(of_thread_t thread) -{ - switch (WaitForSingleObject(thread, INFINITE)) { - case WAIT_OBJECT_0: - CloseHandle(thread); - return true; - case WAIT_FAILED: - switch (GetLastError()) { - case ERROR_INVALID_HANDLE: - errno = EINVAL; - return false; - default: - OF_ENSURE(0); - } - default: - OF_ENSURE(0); - } -} - -bool -of_thread_detach(of_thread_t thread) -{ - CloseHandle(thread); - - return true; -} - -void -of_thread_set_name(const char *name) -{ -} DELETED src/platform/windows/tlskey.m Index: src/platform/windows/tlskey.m ================================================================== --- src/platform/windows/tlskey.m +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "tlskey.h" - -bool -of_tlskey_new(of_tlskey_t *key) -{ - return ((*key = TlsAlloc()) != TLS_OUT_OF_INDEXES); -} - -bool -of_tlskey_free(of_tlskey_t key) -{ - return TlsFree(key); -} ADDED src/platform/x86/OFAtomic.h Index: src/platform/x86/OFAtomic.h ================================================================== --- /dev/null +++ src/platform/x86/OFAtomic.h @@ -0,0 +1,502 @@ +/* + * 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. + */ + +OF_ASSUME_NONNULL_BEGIN + +static OF_INLINE int +OFAtomicIntAdd(volatile int *_Nonnull p, int i) +{ + if (sizeof(int) == 4) + __asm__ __volatile__ ( + "lock\n\t" + "xaddl %0, %2\n\t" + "addl %1, %0" + : "+&r"(i) + : "r"(i), "m"(*p) + ); +#ifdef OF_X86_64 + else if (sizeof(int) == 8) + __asm__ __volatile__ ( + "lock\n\t" + "xaddq %0, %2\n\t" + "addq %1, %0" + : "+&r"(i) + : "r"(i), "m"(*p) + ); +#endif + else + abort(); + + return i; +} + +static OF_INLINE int32_t +OFAtomicInt32Add(volatile int32_t *_Nonnull p, int32_t i) +{ + __asm__ __volatile__ ( + "lock\n\t" + "xaddl %0, %2\n\t" + "addl %1, %0" + : "+&r"(i) + : "r"(i), "m"(*p) + ); + + return i; +} + +static OF_INLINE void *_Nullable +OFAtomicPointerAdd(void *volatile _Nullable *_Nonnull p, intptr_t i) +{ +#if defined(OF_X86_64) + __asm__ __volatile__ ( + "lock\n\t" + "xaddq %0, %2\n\t" + "addq %1, %0" + : "+&r"(i) + : "r"(i), "m"(*p) + ); + + return (void *)i; +#elif defined(OF_X86) + __asm__ __volatile__ ( + "lock\n\t" + "xaddl %0, %2\n\t" + "addl %1, %0" + : "+&r"(i) + : "r"(i), "m"(*p) + ); + + return (void *)i; +#endif +} + +static OF_INLINE int +OFAtomicIntSubtract(volatile int *_Nonnull p, int i) +{ + if (sizeof(int) == 4) + __asm__ __volatile__ ( + "negl %0\n\t" + "lock\n\t" + "xaddl %0, %2\n\t" + "subl %1, %0" + : "+&r"(i) + : "r"(i), "m"(*p) + ); +#ifdef OF_X86_64 + else if (sizeof(int) == 8) + __asm__ __volatile__ ( + "negq %0\n\t" + "lock\n\t" + "xaddq %0, %2\n\t" + "subq %1, %0" + : "+&r"(i) + : "r"(i), "m"(*p) + ); +#endif + else + abort(); + + return i; +} + +static OF_INLINE int32_t +OFAtomicInt32Subtract(volatile int32_t *_Nonnull p, int32_t i) +{ + __asm__ __volatile__ ( + "negl %0\n\t" + "lock\n\t" + "xaddl %0, %2\n\t" + "subl %1, %0" + : "+&r"(i) + : "r"(i), "m"(*p) + ); + + return i; +} + +static OF_INLINE void *_Nullable +OFAtomicPointerSubtract(void *volatile _Nullable *_Nonnull p, intptr_t i) +{ +#if defined(OF_X86_64) + __asm__ __volatile__ ( + "negq %0\n\t" + "lock\n\t" + "xaddq %0, %2\n\t" + "subq %1, %0" + : "+&r"(i) + : "r"(i), "m"(*p) + ); + + return (void *)i; +#elif defined(OF_X86) + __asm__ __volatile__ ( + "negl %0\n\t" + "lock\n\t" + "xaddl %0, %2\n\t" + "subl %1, %0" + : "+&r"(i) + : "r"(i), "m"(*p) + ); + + return (void *)i; +#endif +} + +static OF_INLINE int +OFAtomicIntIncrease(volatile int *_Nonnull p) +{ + int i; + + if (sizeof(int) == 4) + __asm__ __volatile__ ( + "xorl %0, %0\n\t" + "incl %0\n\t" + "lock\n\t" + "xaddl %0, %1\n\t" + "incl %0" + : "=&r"(i) + : "m"(*p) + ); +#ifdef OF_X86_64 + else if (sizeof(int) == 8) + __asm__ __volatile__ ( + "xorq %0, %0\n\t" + "incq %0\n\t" + "lock\n\t" + "xaddq %0, %1\n\t" + "incq %0" + : "=&r"(i) + : "m"(*p) + ); +#endif + else + abort(); + + return i; +} + +static OF_INLINE int32_t +OFAtomicInt32Increase(volatile int32_t *_Nonnull p) +{ + int32_t i; + + __asm__ __volatile__ ( + "xorl %0, %0\n\t" + "incl %0\n\t" + "lock\n\t" + "xaddl %0, %1\n\t" + "incl %0" + : "=&r"(i) + : "m"(*p) + ); + + return i; +} + +static OF_INLINE int +OFAtomicIntDecrease(volatile int *_Nonnull p) +{ + int i; + + if (sizeof(int) == 4) + __asm__ __volatile__ ( + "xorl %0, %0\n\t" + "decl %0\n\t" + "lock\n\t" + "xaddl %0, %1\n\t" + "decl %0" + : "=&r"(i) + : "m"(*p) + ); +#ifdef OF_X86_64 + else if (sizeof(int) == 8) + __asm__ __volatile__ ( + "xorq %0, %0\n\t" + "decq %0\n\t" + "lock\n\t" + "xaddq %0, %1\n\t" + "decq %0" + : "=&r"(i) + : "m"(*p) + ); +#endif + else + abort(); + + return i; +} + +static OF_INLINE int32_t +OFAtomicInt32Decrease(volatile int32_t *_Nonnull p) +{ + int32_t i; + + __asm__ __volatile__ ( + "xorl %0, %0\n\t" + "decl %0\n\t" + "lock\n\t" + "xaddl %0, %1\n\t" + "decl %0" + : "=&r"(i) + : "m"(*p) + ); + + return i; +} + +static OF_INLINE unsigned int +OFAtomicIntOr(volatile unsigned int *_Nonnull p, unsigned int i) +{ + if (sizeof(int) == 4) + __asm__ __volatile__ ( + "0:\n\t" + "movl %2, %0\n\t" + "movl %0, %%eax\n\t" + "orl %1, %0\n\t" + "lock\n\t" + "cmpxchg %0, %2\n\t" + "jne 0b" + : "=&r"(i) + : "r"(i), "m"(*p) + : "eax", "cc" + ); +#ifdef OF_X86_64 + else if (sizeof(int) == 8) + __asm__ __volatile__ ( + "0:\n\t" + "movq %2, %0\n\t" + "movq %0, %%rax\n\t" + "orq %1, %0\n\t" + "lock\n\t" + "cmpxchg %0, %2\n\t" + "jne 0b" + : "=&r"(i) + : "r"(i), "m"(*p) + : "rax", "cc" + ); +#endif + else + abort(); + + return i; +} + +static OF_INLINE uint32_t +OFAtomicInt32Or(volatile uint32_t *_Nonnull p, uint32_t i) +{ + __asm__ __volatile__ ( + "0:\n\t" + "movl %2, %0\n\t" + "movl %0, %%eax\n\t" + "orl %1, %0\n\t" + "lock\n\t" + "cmpxchg %0, %2\n\t" + "jne 0b" + : "=&r"(i) + : "r"(i), "m"(*p) + : "eax", "cc" + ); + + return i; +} + +static OF_INLINE unsigned int +OFAtomicIntAnd(volatile unsigned int *_Nonnull p, unsigned int i) +{ + if (sizeof(int) == 4) + __asm__ __volatile__ ( + "0:\n\t" + "movl %2, %0\n\t" + "movl %0, %%eax\n\t" + "andl %1, %0\n\t" + "lock\n\t" + "cmpxchg %0, %2\n\t" + "jne 0b" + : "=&r"(i) + : "r"(i), "m"(*p) + : "eax", "cc" + ); +#ifdef OF_X86_64 + else if (sizeof(int) == 8) + __asm__ __volatile__ ( + "0:\n\t" + "movq %2, %0\n\t" + "movq %0, %%rax\n\t" + "andq %1, %0\n\t" + "lock\n\t" + "cmpxchg %0, %2\n\t" + "jne 0b" + : "=&r"(i) + : "r"(i), "m"(*p) + : "rax", "cc" + ); +#endif + else + abort(); + + return i; +} + +static OF_INLINE uint32_t +OFAtomicInt32And(volatile uint32_t *_Nonnull p, uint32_t i) +{ + __asm__ __volatile__ ( + "0:\n\t" + "movl %2, %0\n\t" + "movl %0, %%eax\n\t" + "andl %1, %0\n\t" + "lock\n\t" + "cmpxchg %0, %2\n\t" + "jne 0b" + : "=&r"(i) + : "r"(i), "m"(*p) + : "eax", "cc" + ); + + return i; +} + +static OF_INLINE unsigned int +OFAtomicIntXor(volatile unsigned int *_Nonnull p, unsigned int i) +{ + if (sizeof(int) == 4) + __asm__ __volatile__ ( + "0:\n\t" + "movl %2, %0\n\t" + "movl %0, %%eax\n\t" + "xorl %1, %0\n\t" + "lock\n\t" + "cmpxchg %0, %2\n\t" + "jne 0b" + : "=&r"(i) + : "r"(i), "m"(*p) + : "eax", "cc" + ); +#ifdef OF_X86_64 + else if (sizeof(int) == 8) + __asm__ __volatile__ ( + "0:\n\t" + "movq %2, %0\n\t" + "movq %0, %%rax\n\t" + "xorq %1, %0\n\t" + "lock\n\t" + "cmpxchg %0, %2\n\t" + "jne 0b" + : "=&r"(i) + : "r"(i), "m"(*p) + : "rax", "cc" + ); +#endif + else + abort(); + + return i; +} + +static OF_INLINE uint32_t +OFAtomicInt32Xor(volatile uint32_t *_Nonnull p, uint32_t i) +{ + __asm__ __volatile__ ( + "0:\n\t" + "movl %2, %0\n\t" + "movl %0, %%eax\n\t" + "xorl %1, %0\n\t" + "lock\n\t" + "cmpxchgl %0, %2\n\t" + "jne 0b" + : "=&r"(i) + : "r"(i), "m"(*p) + : "eax", "cc" + ); + + return i; +} + +static OF_INLINE bool +OFAtomicIntCompareAndSwap(volatile int *_Nonnull p, int o, int n) +{ + int r; + + __asm__ __volatile__ ( + "lock\n\t" + "cmpxchg %2, %3\n\t" + "sete %b0\n\t" + "movzbl %b0, %0" + : "=&d"(r), "+a"(o) /* use d instead of r to avoid a gcc bug */ + : "r"(n), "m"(*p) + : "cc" + ); + + return r; +} + +static OF_INLINE bool +OFAtomicInt32CompareAndSwap(volatile int32_t *_Nonnull p, int32_t o, int32_t n) +{ + int r; + + __asm__ __volatile__ ( + "lock\n\t" + "cmpxchg %2, %3\n\t" + "sete %b0\n\t" + "movzbl %b0, %0" + : "=&d"(r), "+a"(o) /* use d instead of r to avoid a gcc bug */ + : "r"(n), "m"(*p) + : "cc" + ); + + return r; +} + +static OF_INLINE bool +OFAtomicPointerCompareAndSwap(void *volatile _Nullable *_Nonnull p, + void *_Nullable o, void *_Nullable n) +{ + int r; + + __asm__ __volatile__ ( + "lock\n\t" + "cmpxchg %2, %3\n\t" + "sete %b0\n\t" + "movzbl %b0, %0" + : "=&d"(r), "+a"(o) /* use d instead of r to avoid a gcc bug */ + : "r"(n), "m"(*p) + : "cc" + ); + + return r; +} + +static OF_INLINE void +OFMemoryBarrier(void) +{ + __asm__ __volatile__ ( + "mfence" ::: "memory" + ); +} + +static OF_INLINE void +OFAcquireMemoryBarrier(void) +{ + __asm__ __volatile__ ("" ::: "memory"); +} + +static OF_INLINE void +OFReleaseMemoryBarrier(void) +{ + __asm__ __volatile__ ("" ::: "memory"); +} + +OF_ASSUME_NONNULL_END Index: src/runtime/Makefile ================================================================== --- src/runtime/Makefile +++ src/runtime/Makefile @@ -1,10 +1,9 @@ include ../../extra.mk SUBDIRS = lookup-asm SUBDIRS_AFTER = ${LINKLIB} -CLEAN = amiga-library-functable.inc inline.h DISTCLEAN = Info.plist SHARED_LIB = ${OBJFWRT_SHARED_LIB} STATIC_LIB = ${OBJFWRT_STATIC_LIB} FRAMEWORK = ${OBJFWRT_FRAMEWORK} @@ -31,36 +30,29 @@ sparsearray.m \ static-instances.m \ synchronized.m \ tagged-pointer.m \ ${USE_SRCS_THREADS} -SRCS_THREADS = threading.m \ - ../mutex.m \ - ../once.m \ - ../tlskey.m +SRCS_THREADS = OFOnce.m \ + OFPlainMutex.m \ + OFTLSKey.m \ + threading.m INCLUDES = ObjFWRT.h includesubdir = ObjFWRT -OBJS_EXTRA = ${LOOKUP_ASM_LOOKUP_ASM_A} -LIB_OBJS_EXTRA = ${LOOKUP_ASM_LOOKUP_ASM_LIB_A} +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_A} \ + lookup-asm/lookup-asm.amigalib.a \ amiga-end.amigalib.o include ../../buildsys.mk -${OBJFWRT_AMIGA_LIB}: inline.h - -${SFDC_INLINE_H}: ${SFD_FILE} - sfdc -q --target=${SFDC_TARGET} --mode=macros -o $@ $<; \ - -${CVINCLUDE_INLINE_H}: morphos.fd morphos-clib.h - cvinclude.pl --quiet --fd=morphos.fd --clib=morphos-clib.h --inlines=$@ - 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} ADDED src/runtime/OFOnce.m Index: src/runtime/OFOnce.m ================================================================== --- /dev/null +++ src/runtime/OFOnce.m @@ -0,0 +1,21 @@ +/* + * 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" + +#include "../OFOnce.m" ADDED src/runtime/OFPlainMutex.m Index: src/runtime/OFPlainMutex.m ================================================================== --- /dev/null +++ src/runtime/OFPlainMutex.m @@ -0,0 +1,21 @@ +/* + * 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" + +#include "../OFPlainMutex.m" ADDED src/runtime/OFTLSKey.m Index: src/runtime/OFTLSKey.m ================================================================== --- /dev/null +++ src/runtime/OFTLSKey.m @@ -0,0 +1,21 @@ +/* + * 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" + +#include "../OFTLSKey.m" Index: src/runtime/ObjFWRT.h ================================================================== --- src/runtime/ObjFWRT.h +++ src/runtime/ObjFWRT.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -146,18 +144,18 @@ /** * @brief A handler for uncaught exceptions. * * @param exception The exception which was not caught. */ -typedef void (*objc_uncaught_exception_handler_t)(id _Nullable exception); +typedef void (*objc_uncaught_exception_handler)(id _Nullable exception); /** * @brief A handler for mutation during enumeration. * * @param object The object that was mutated during enumeration */ -typedef void (*objc_enumeration_mutation_handler_t)(id _Nonnull object); +typedef void (*objc_enumeration_mutation_handler)(id _Nonnull object); /** * @brief A struct representing a call to super. */ struct objc_super { @@ -520,27 +518,27 @@ */ extern char *_Nullable property_copyAttributeValue( objc_property_t _Nonnull property, const char *_Nonnull name); /** - * @brief Exits the Objective-C runtime. + * @brief Deinitializes the Objective-C runtime. * * This frees all data structures used by the runtime, after which Objective-C * can no longer be used inside the current process. This is only useful for - * debugging. + * debugging and tests. */ -extern void objc_exit(void); +extern void objc_deinit(void); /** * @brief Sets the handler for uncaught exceptions. * * @param handler The new handler for uncaught exceptions * @return The old handler for uncaught exceptions */ -extern _Nullable objc_uncaught_exception_handler_t +extern _Nullable objc_uncaught_exception_handler objc_setUncaughtExceptionHandler( - objc_uncaught_exception_handler_t _Nullable handler); + objc_uncaught_exception_handler _Nullable handler); /** * @brief Sets the forwarding handler for unimplemented methods. * * @param forward The forwarding handler for regular methods @@ -554,11 +552,11 @@ * @brief Sets the handler for mutations during enumeration. * * @param handler The handler for mutations during enumeration */ extern void objc_setEnumerationMutationHandler( - objc_enumeration_mutation_handler_t _Nullable handler); + objc_enumeration_mutation_handler _Nullable handler); /** * @brief Constructs an instance of the specified class in the specified array * of bytes. * Index: src/runtime/amiga-end.m ================================================================== --- src/runtime/amiga-end.m +++ src/runtime/amiga-end.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -19,13 +17,15 @@ #import "platform.h" #ifdef OF_MORPHOS __asm__ ( - ".section .ctors, \"aw\", @progbits\n" + ".section .eh_frame, \"aw\"\n" " .long 0\n" + ".section .ctors, \"aw\"\n" + " .long 0" ); #else __asm__ ( "" ); #endif ADDED src/runtime/amiga-funcarray.inc Index: src/runtime/amiga-funcarray.inc ================================================================== --- /dev/null +++ src/runtime/amiga-funcarray.inc @@ -0,0 +1,106 @@ +/* + * 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, ADDED src/runtime/amiga-glue.h Index: src/runtime/amiga-glue.h ================================================================== --- /dev/null +++ src/runtime/amiga-glue.h @@ -0,0 +1,119 @@ +/* + * 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); Index: src/runtime/amiga-glue.m ================================================================== --- src/runtime/amiga-glue.m +++ src/runtime/amiga-glue.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -13,25 +11,15 @@ * 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" -#import "macros.h" - -#ifdef OF_AMIGAOS_M68K -# define PPC_PARAMS(...) (void) -# define M68K_ARG OBJC_M68K_ARG -#else -# define PPC_PARAMS(...) (__VA_ARGS__) -# define M68K_ARG(...) -#endif - -extern bool objc_init(unsigned int, struct objc_libc *, FILE *, FILE *); +#import "amiga-glue.h" #ifdef OF_MORPHOS /* All __saveds functions in this file need to use the SysV ABI */ __asm__ ( ".section .text\n" @@ -41,763 +29,733 @@ " blr\n" ); #endif bool __saveds -glue_objc_init PPC_PARAMS(unsigned int version, struct objc_libc *libc, - FILE *stdout_, FILE *stderr_) +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) - M68K_ARG(FILE *, stdout_, a1) - M68K_ARG(FILE *, stderr_, a2) - return objc_init(version, libc, stdout_, stderr_); + return objc_init(version, libc); } void __saveds -glue___objc_exec_class PPC_PARAMS(struct objc_module *module) +glue___objc_exec_class PPC_PARAMS(struct objc_module *_Nonnull module) { - M68K_ARG(struct objc_module *, module, a0) + M68K_ARG(struct objc_module *_Nonnull, module, a0) __objc_exec_class(module); } -IMP __saveds -glue_objc_msg_lookup PPC_PARAMS(id object, SEL selector) +IMP _Nonnull __saveds +glue_objc_msg_lookup PPC_PARAMS(id _Nullable object, SEL _Nonnull selector) { - M68K_ARG(id, object, a0) - M68K_ARG(SEL, selector, a1) + M68K_ARG(id _Nullable, object, a0) + M68K_ARG(SEL _Nonnull, selector, a1) return objc_msg_lookup(object, selector); } -IMP __saveds -glue_objc_msg_lookup_stret PPC_PARAMS(id object, SEL selector) +IMP _Nonnull __saveds +glue_objc_msg_lookup_stret PPC_PARAMS(id _Nullable object, SEL _Nonnull selector) { - M68K_ARG(id, object, a0) - M68K_ARG(SEL, selector, a1) + M68K_ARG(id _Nullable, object, a0) + M68K_ARG(SEL _Nonnull, selector, a1) return objc_msg_lookup_stret(object, selector); } -IMP __saveds -glue_objc_msg_lookup_super PPC_PARAMS(struct objc_super *super, SEL selector) +IMP _Nonnull __saveds +glue_objc_msg_lookup_super PPC_PARAMS(struct objc_super *_Nonnull super, SEL _Nonnull selector) { - M68K_ARG(struct objc_super *, super, a0) - M68K_ARG(SEL, selector, a1) + M68K_ARG(struct objc_super *_Nonnull, super, a0) + M68K_ARG(SEL _Nonnull, selector, a1) return objc_msg_lookup_super(super, selector); } -IMP __saveds -glue_objc_msg_lookup_super_stret PPC_PARAMS(struct objc_super *super, - SEL 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 *, super, a0) - M68K_ARG(SEL, selector, a1) + M68K_ARG(struct objc_super *_Nonnull, super, a0) + M68K_ARG(SEL _Nonnull, selector, a1) return objc_msg_lookup_super_stret(super, selector); } -Class __saveds -glue_objc_lookUpClass PPC_PARAMS(const char *name) +Class _Nullable __saveds +glue_objc_lookUpClass PPC_PARAMS(const char *_Nonnull name) { - M68K_ARG(const char *, name, a0) + M68K_ARG(const char *_Nonnull, name, a0) return objc_lookUpClass(name); } -Class __saveds -glue_objc_getClass PPC_PARAMS(const char *name) +Class _Nullable __saveds +glue_objc_getClass PPC_PARAMS(const char *_Nonnull name) { - M68K_ARG(const char *, name, a0) + M68K_ARG(const char *_Nonnull, name, a0) return objc_getClass(name); } -Class __saveds -glue_objc_getRequiredClass PPC_PARAMS(const char *name) +Class _Nonnull __saveds +glue_objc_getRequiredClass PPC_PARAMS(const char *_Nonnull name) { - M68K_ARG(const char *, name, a0) + M68K_ARG(const char *_Nonnull, name, a0) return objc_getRequiredClass(name); } -Class __saveds -glue_objc_lookup_class PPC_PARAMS(const char *name) +Class _Nullable __saveds +glue_objc_lookup_class PPC_PARAMS(const char *_Nonnull name) { - M68K_ARG(const char *, name, a0) + M68K_ARG(const char *_Nonnull, name, a0) return objc_lookup_class(name); } -Class __saveds -glue_objc_get_class PPC_PARAMS(const char *name) +Class _Nonnull __saveds +glue_objc_get_class PPC_PARAMS(const char *_Nonnull name) { - M68K_ARG(const char *, name, a0) + M68K_ARG(const char *_Nonnull, name, a0) return objc_get_class(name); } void __saveds -glue_objc_exception_throw PPC_PARAMS(id object) +glue_objc_exception_throw PPC_PARAMS(id _Nonnull object) { - M68K_ARG(id, object, a0) + M68K_ARG(id _Nonnull, object, a0) objc_exception_throw(object); - - OF_UNREACHABLE } int __saveds -glue_objc_sync_enter PPC_PARAMS(id object) +glue_objc_sync_enter PPC_PARAMS(id _Nullable object) { - M68K_ARG(id, object, a0) + M68K_ARG(id _Nullable, object, a0) return objc_sync_enter(object); } int __saveds -glue_objc_sync_exit PPC_PARAMS(id object) +glue_objc_sync_exit PPC_PARAMS(id _Nullable object) { - M68K_ARG(id, object, a0) + M68K_ARG(id _Nullable, object, a0) return objc_sync_exit(object); } -id __saveds -glue_objc_getProperty PPC_PARAMS(id self, SEL _cmd, ptrdiff_t offset, - bool atomic) +id _Nullable __saveds +glue_objc_getProperty PPC_PARAMS(id _Nonnull self, SEL _Nonnull _cmd, ptrdiff_t offset, bool atomic) { - M68K_ARG(id, self, a0) - M68K_ARG(SEL, _cmd, a1) + 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 self, SEL _cmd, ptrdiff_t offset, id value, - bool atomic, signed char copy) +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, self, a0) - M68K_ARG(SEL, _cmd, a1) + M68K_ARG(id _Nonnull, self, a0) + M68K_ARG(SEL _Nonnull, _cmd, a1) M68K_ARG(ptrdiff_t, offset, d0) - M68K_ARG(id, value, a2) + 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 *dest, const void *src, - ptrdiff_t size, bool atomic, bool strong) +glue_objc_getPropertyStruct PPC_PARAMS(void *_Nonnull dest, const void *_Nonnull src, ptrdiff_t size, bool atomic, bool strong) { - M68K_ARG(void *, dest, a0) - M68K_ARG(const void *, src, a1) + 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 *dest, const void *src, - ptrdiff_t size, bool atomic, bool strong) +glue_objc_setPropertyStruct PPC_PARAMS(void *_Nonnull dest, const void *_Nonnull src, ptrdiff_t size, bool atomic, bool strong) { - M68K_ARG(void *, dest, a0) - M68K_ARG(const void *, src, a1) + 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 object) +glue_objc_enumerationMutation PPC_PARAMS(id _Nonnull object) { - M68K_ARG(id, object, a0) + M68K_ARG(id _Nonnull, object, a0) objc_enumerationMutation(object); } int __saveds -glue___gnu_objc_personality PPC_PARAMS(int version, int actions, - uint64_t exClass, void *ex, void *ctx) +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 *, exClassPtr, d2) - M68K_ARG(void *, ex, a0) - M68K_ARG(void *, ctx, a1) -#ifdef OF_AMIGAOS_M68K - uint64_t exClass = *exClassPtr; -#endif - -#ifdef HAVE_SJLJ_EXCEPTIONS - return __gnu_objc_personality_sj0(version, actions, exClass, ex, ctx); -#else - return __gnu_objc_personality_v0(version, actions, exClass, ex, ctx); -#endif -} - -id __saveds -glue_objc_retain PPC_PARAMS(id object) -{ - M68K_ARG(id, object, a0) + 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 __saveds -glue_objc_retainBlock PPC_PARAMS(id block) +id _Nullable __saveds +glue_objc_retainBlock PPC_PARAMS(id _Nullable block) { - M68K_ARG(id, block, a0) + M68K_ARG(id _Nullable, block, a0) return objc_retainBlock(block); } -id __saveds -glue_objc_retainAutorelease PPC_PARAMS(id object) +id _Nullable __saveds +glue_objc_retainAutorelease PPC_PARAMS(id _Nullable object) { - M68K_ARG(id, object, a0) + M68K_ARG(id _Nullable, object, a0) return objc_retainAutorelease(object); } void __saveds -glue_objc_release PPC_PARAMS(id object) +glue_objc_release PPC_PARAMS(id _Nullable object) { - M68K_ARG(id, object, a0) + M68K_ARG(id _Nullable, object, a0) objc_release(object); } -id __saveds -glue_objc_autorelease PPC_PARAMS(id object) +id _Nullable __saveds +glue_objc_autorelease PPC_PARAMS(id _Nullable object) { - M68K_ARG(id, object, a0) + M68K_ARG(id _Nullable, object, a0) return objc_autorelease(object); } -id __saveds -glue_objc_autoreleaseReturnValue PPC_PARAMS(id object) +id _Nullable __saveds +glue_objc_autoreleaseReturnValue PPC_PARAMS(id _Nullable object) { - M68K_ARG(id, object, a0) + M68K_ARG(id _Nullable, object, a0) return objc_autoreleaseReturnValue(object); } -id __saveds -glue_objc_retainAutoreleaseReturnValue PPC_PARAMS(id object) +id _Nullable __saveds +glue_objc_retainAutoreleaseReturnValue PPC_PARAMS(id _Nullable object) { - M68K_ARG(id, object, a0) + M68K_ARG(id _Nullable, object, a0) return objc_retainAutoreleaseReturnValue(object); } -id __saveds -glue_objc_retainAutoreleasedReturnValue PPC_PARAMS(id object) +id _Nullable __saveds +glue_objc_retainAutoreleasedReturnValue PPC_PARAMS(id _Nullable object) { - M68K_ARG(id, object, a0) + M68K_ARG(id _Nullable, object, a0) return objc_retainAutoreleasedReturnValue(object); } -id __saveds -glue_objc_storeStrong PPC_PARAMS(id *object, id value) +id _Nullable __saveds +glue_objc_storeStrong PPC_PARAMS(id _Nullable *_Nonnull object, id _Nullable value) { - M68K_ARG(id *, object, a0) - M68K_ARG(id, value, a1) + M68K_ARG(id _Nullable *_Nonnull, object, a0) + M68K_ARG(id _Nullable, value, a1) return objc_storeStrong(object, value); } -id __saveds -glue_objc_storeWeak PPC_PARAMS(id *object, id value) +id _Nullable __saveds +glue_objc_storeWeak PPC_PARAMS(id _Nullable *_Nonnull object, id _Nullable value) { - M68K_ARG(id *, object, a0) - M68K_ARG(id, value, a1) + M68K_ARG(id _Nullable *_Nonnull, object, a0) + M68K_ARG(id _Nullable, value, a1) return objc_storeWeak(object, value); } -id __saveds -glue_objc_loadWeakRetained PPC_PARAMS(id *object) +id _Nullable __saveds +glue_objc_loadWeakRetained PPC_PARAMS(id _Nullable *_Nonnull object) { - M68K_ARG(id *, object, a0) + M68K_ARG(id _Nullable *_Nonnull, object, a0) return objc_loadWeakRetained(object); } -id __saveds -glue_objc_initWeak PPC_PARAMS(id *object, id value) +id _Nullable __saveds +glue_objc_initWeak PPC_PARAMS(id _Nullable *_Nonnull object, id _Nullable value) { - M68K_ARG(id *, object, a0) - M68K_ARG(id, value, a1) + 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 *object) +glue_objc_destroyWeak PPC_PARAMS(id _Nullable *_Nonnull object) { - M68K_ARG(id *, object, a0) + M68K_ARG(id _Nullable *_Nonnull, object, a0) objc_destroyWeak(object); } -id __saveds -glue_objc_loadWeak PPC_PARAMS(id *object) +id _Nullable __saveds +glue_objc_loadWeak PPC_PARAMS(id _Nullable *_Nonnull object) { - M68K_ARG(id *, object, a0) + M68K_ARG(id _Nullable *_Nonnull, object, a0) return objc_loadWeak(object); } void __saveds -glue_objc_copyWeak PPC_PARAMS(id *dest, id *src) +glue_objc_copyWeak PPC_PARAMS(id _Nullable *_Nonnull dest, id _Nullable *_Nonnull src) { - M68K_ARG(id *, dest, a0) - M68K_ARG(id *, src, a1) + 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 *dest, id *src) +glue_objc_moveWeak PPC_PARAMS(id _Nullable *_Nonnull dest, id _Nullable *_Nonnull src) { - M68K_ARG(id *, dest, a0) - M68K_ARG(id *, src, a1) + M68K_ARG(id _Nullable *_Nonnull, dest, a0) + M68K_ARG(id _Nullable *_Nonnull, src, a1) objc_moveWeak(dest, src); } -SEL __saveds -glue_sel_registerName PPC_PARAMS(const char *name) +SEL _Nonnull __saveds +glue_sel_registerName PPC_PARAMS(const char *_Nonnull name) { - M68K_ARG(const char *, name, a0) + M68K_ARG(const char *_Nonnull, name, a0) return sel_registerName(name); } -const char *__saveds -glue_sel_getName PPC_PARAMS(SEL selector) +const char *_Nonnull __saveds +glue_sel_getName PPC_PARAMS(SEL _Nonnull selector) { - M68K_ARG(SEL, selector, a0) + M68K_ARG(SEL _Nonnull, selector, a0) return sel_getName(selector); } bool __saveds -glue_sel_isEqual PPC_PARAMS(SEL selector1, SEL selector2) +glue_sel_isEqual PPC_PARAMS(SEL _Nonnull selector1, SEL _Nonnull selector2) { - M68K_ARG(SEL, selector1, a0) - M68K_ARG(SEL, selector2, a1) + M68K_ARG(SEL _Nonnull, selector1, a0) + M68K_ARG(SEL _Nonnull, selector2, a1) return sel_isEqual(selector1, selector2); } -Class __saveds -glue_objc_allocateClassPair PPC_PARAMS(Class superclass, const char *name, - size_t extraBytes) +Class _Nonnull __saveds +glue_objc_allocateClassPair PPC_PARAMS(Class _Nullable superclass, const char *_Nonnull name, size_t extraBytes) { - M68K_ARG(Class, superclass, a0) - M68K_ARG(const char *, name, a1) + 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 class) +glue_objc_registerClassPair PPC_PARAMS(Class _Nonnull class) { - M68K_ARG(Class, class, a0) + M68K_ARG(Class _Nonnull, class, a0) objc_registerClassPair(class); } unsigned int __saveds -glue_objc_getClassList PPC_PARAMS(Class *buffer, unsigned int count) +glue_objc_getClassList PPC_PARAMS(Class _Nonnull *_Nullable buffer, unsigned int count) { - M68K_ARG(Class *, buffer, a0) + M68K_ARG(Class _Nonnull *_Nullable, buffer, a0) M68K_ARG(unsigned int, count, d0) return objc_getClassList(buffer, count); } -Class *__saveds -glue_objc_copyClassList PPC_PARAMS(unsigned int *length) +Class _Nonnull *_Nonnull __saveds +glue_objc_copyClassList PPC_PARAMS(unsigned int *_Nullable length) { - M68K_ARG(unsigned int *, length, a0) + M68K_ARG(unsigned int *_Nullable, length, a0) return objc_copyClassList(length); } bool __saveds -glue_class_isMetaClass PPC_PARAMS(Class class) +glue_class_isMetaClass PPC_PARAMS(Class _Nullable class) { - M68K_ARG(Class, class, a0) + M68K_ARG(Class _Nullable, class, a0) return class_isMetaClass(class); } -const char *__saveds -glue_class_getName PPC_PARAMS(Class class) +const char *_Nullable __saveds +glue_class_getName PPC_PARAMS(Class _Nullable class) { - M68K_ARG(Class, class, a0) + M68K_ARG(Class _Nullable, class, a0) return class_getName(class); } -Class __saveds -glue_class_getSuperclass PPC_PARAMS(Class class) +Class _Nullable __saveds +glue_class_getSuperclass PPC_PARAMS(Class _Nullable class) { - M68K_ARG(Class, class, a0) + M68K_ARG(Class _Nullable, class, a0) return class_getSuperclass(class); } unsigned long __saveds -glue_class_getInstanceSize PPC_PARAMS(Class class) +glue_class_getInstanceSize PPC_PARAMS(Class _Nullable class) { - M68K_ARG(Class, class, a0) + M68K_ARG(Class _Nullable, class, a0) return class_getInstanceSize(class); } bool __saveds -glue_class_respondsToSelector PPC_PARAMS(Class class, SEL selector) +glue_class_respondsToSelector PPC_PARAMS(Class _Nullable class, SEL _Nonnull selector) { - M68K_ARG(Class, class, a0) - M68K_ARG(SEL, selector, a1) + 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 class, Protocol *protocol) +glue_class_conformsToProtocol PPC_PARAMS(Class _Nullable class, Protocol *_Nonnull p) { - M68K_ARG(Class, class, a0) - M68K_ARG(Protocol *, protocol, a1) + M68K_ARG(Class _Nullable, class, a0) + M68K_ARG(Protocol *_Nonnull, p, a1) - return class_conformsToProtocol(class, protocol); + return class_conformsToProtocol(class, p); } -IMP __saveds -glue_class_getMethodImplementation PPC_PARAMS(Class class, SEL selector) +IMP _Nullable __saveds +glue_class_getMethodImplementation PPC_PARAMS(Class _Nullable class, SEL _Nonnull selector) { - M68K_ARG(Class, class, a0) - M68K_ARG(SEL, selector, a1) + M68K_ARG(Class _Nullable, class, a0) + M68K_ARG(SEL _Nonnull, selector, a1) return class_getMethodImplementation(class, selector); } -IMP __saveds -glue_class_getMethodImplementation_stret PPC_PARAMS(Class class, SEL selector) +IMP _Nullable __saveds +glue_class_getMethodImplementation_stret PPC_PARAMS(Class _Nullable class, SEL _Nonnull selector) { - M68K_ARG(Class, class, a0) - M68K_ARG(SEL, selector, a1) + M68K_ARG(Class _Nullable, class, a0) + M68K_ARG(SEL _Nonnull, selector, a1) return class_getMethodImplementation_stret(class, selector); } -Method __saveds -glue_class_getInstanceMethod PPC_PARAMS(Class class, SEL selector) +Method _Nullable __saveds +glue_class_getInstanceMethod PPC_PARAMS(Class _Nullable class, SEL _Nonnull selector) { - M68K_ARG(Class, class, a0) - M68K_ARG(SEL, selector, a1) + 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 class, SEL selector, IMP implementation, - const char *typeEncoding) +glue_class_addMethod PPC_PARAMS(Class _Nonnull class, SEL _Nonnull selector, IMP _Nonnull implementation, const char *_Nullable typeEncoding) { - M68K_ARG(Class, class, a0) - M68K_ARG(SEL, selector, a1) - M68K_ARG(IMP, implementation, a2) - M68K_ARG(const char *, typeEncoding, a3) + 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 __saveds -glue_class_replaceMethod PPC_PARAMS(Class class, SEL selector, - IMP implementation, const char *typeEncoding) -{ - M68K_ARG(Class, class, a0) - M68K_ARG(SEL, selector, a1) - M68K_ARG(IMP, implementation, a2) - M68K_ARG(const char *, typeEncoding, a3) - - return class_replaceMethod(class, selector, implementation, - typeEncoding); -} - -Class __saveds -glue_object_getClass PPC_PARAMS(id object) -{ - M68K_ARG(id, object, a0) +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 __saveds -glue_object_setClass PPC_PARAMS(id object, Class class) +Class _Nullable __saveds +glue_object_setClass PPC_PARAMS(id _Nullable object, Class _Nonnull class) { - M68K_ARG(id, object, a0) - M68K_ARG(Class, class, a1) + M68K_ARG(id _Nullable, object, a0) + M68K_ARG(Class _Nonnull, class, a1) return object_setClass(object, class); } -const char *__saveds -glue_object_getClassName PPC_PARAMS(id object) +const char *_Nullable __saveds +glue_object_getClassName PPC_PARAMS(id _Nullable object) { - M68K_ARG(id, object, a0) + M68K_ARG(id _Nullable, object, a0) return object_getClassName(object); } -const char *__saveds -glue_protocol_getName PPC_PARAMS(Protocol *protocol) +const char *_Nonnull __saveds +glue_protocol_getName PPC_PARAMS(Protocol *_Nonnull protocol) { - M68K_ARG(Protocol *, protocol, a0) + M68K_ARG(Protocol *_Nonnull, protocol, a0) return protocol_getName(protocol); } bool __saveds -glue_protocol_isEqual PPC_PARAMS(Protocol *protocol1, Protocol *protocol2) +glue_protocol_isEqual PPC_PARAMS(Protocol *_Nonnull protocol1, Protocol *_Nonnull protocol2) { - M68K_ARG(Protocol *, protocol1, a0) - M68K_ARG(Protocol *, protocol2, a1) + 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 *protocol1, - Protocol *protocol2) +glue_protocol_conformsToProtocol PPC_PARAMS(Protocol *_Nonnull protocol1, Protocol *_Nonnull protocol2) { - M68K_ARG(Protocol *, protocol1, a0) - M68K_ARG(Protocol *, protocol2, a1) + M68K_ARG(Protocol *_Nonnull, protocol1, a0) + M68K_ARG(Protocol *_Nonnull, protocol2, a1) return protocol_conformsToProtocol(protocol1, protocol2); } -objc_uncaught_exception_handler_t __saveds -glue_objc_setUncaughtExceptionHandler PPC_PARAMS( - objc_uncaught_exception_handler_t handler) +_Nullable objc_uncaught_exception_handler __saveds +glue_objc_setUncaughtExceptionHandler PPC_PARAMS(objc_uncaught_exception_handler _Nullable handler) { - M68K_ARG(objc_uncaught_exception_handler_t, handler, a0) + M68K_ARG(objc_uncaught_exception_handler _Nullable, handler, a0) return objc_setUncaughtExceptionHandler(handler); } void __saveds -glue_objc_setForwardHandler PPC_PARAMS(IMP forward, IMP stretForward) +glue_objc_setForwardHandler PPC_PARAMS(IMP _Nullable forward, IMP _Nullable stretForward) { - M68K_ARG(IMP, forward, a0) - M68K_ARG(IMP, stretForward, a1) + 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_t handler) +glue_objc_setEnumerationMutationHandler PPC_PARAMS(objc_enumeration_mutation_handler _Nullable hadler) { - M68K_ARG(objc_enumeration_mutation_handler_t, handler, a0) + M68K_ARG(objc_enumeration_mutation_handler _Nullable, hadler, a0) - objc_setEnumerationMutationHandler(handler); + objc_setEnumerationMutationHandler(hadler); } -id __saveds -glue_objc_constructInstance PPC_PARAMS(Class class, void *bytes) +id _Nullable __saveds +glue_objc_constructInstance PPC_PARAMS(Class _Nullable class, void *_Nullable bytes) { - M68K_ARG(Class, class, a0) - M68K_ARG(void *, bytes, a1) + M68K_ARG(Class _Nullable, class, a0) + M68K_ARG(void *_Nullable, bytes, a1) return objc_constructInstance(class, bytes); } void __saveds -glue_objc_exit(void) +glue_objc_deinit(void) { - objc_exit(); + objc_deinit(); } -Ivar *__saveds -glue_class_copyIvarList PPC_PARAMS(Class class, unsigned int *outCount) +Ivar _Nullable *_Nullable __saveds +glue_class_copyIvarList PPC_PARAMS(Class _Nullable class, unsigned int *_Nullable outCount) { - M68K_ARG(Class, class, a0) - M68K_ARG(unsigned int *, outCount, a1) + M68K_ARG(Class _Nullable, class, a0) + M68K_ARG(unsigned int *_Nullable, outCount, a1) return class_copyIvarList(class, outCount); } -const char *__saveds -glue_ivar_getName PPC_PARAMS(Ivar ivar) +const char *_Nonnull __saveds +glue_ivar_getName PPC_PARAMS(Ivar _Nonnull ivar) { - M68K_ARG(Ivar, ivar, a0) + M68K_ARG(Ivar _Nonnull, ivar, a0) return ivar_getName(ivar); } -const char *__saveds -glue_ivar_getTypeEncoding PPC_PARAMS(Ivar ivar) +const char *_Nonnull __saveds +glue_ivar_getTypeEncoding PPC_PARAMS(Ivar _Nonnull ivar) { - M68K_ARG(Ivar, ivar, a0) + M68K_ARG(Ivar _Nonnull, ivar, a0) return ivar_getTypeEncoding(ivar); } ptrdiff_t __saveds -glue_ivar_getOffset PPC_PARAMS(Ivar ivar) +glue_ivar_getOffset PPC_PARAMS(Ivar _Nonnull ivar) { - M68K_ARG(Ivar, ivar, a0) + M68K_ARG(Ivar _Nonnull, ivar, a0) return ivar_getOffset(ivar); } -Method *__saveds -glue_class_copyMethodList PPC_PARAMS(Class class, unsigned int *outCount) +Method _Nullable *_Nullable __saveds +glue_class_copyMethodList PPC_PARAMS(Class _Nullable class, unsigned int *_Nullable outCount) { - M68K_ARG(Class, class, a0) - M68K_ARG(unsigned int *, outCount, a1) + M68K_ARG(Class _Nullable, class, a0) + M68K_ARG(unsigned int *_Nullable, outCount, a1) return class_copyMethodList(class, outCount); } -SEL __saveds -glue_method_getName PPC_PARAMS(Method method) +SEL _Nonnull __saveds +glue_method_getName PPC_PARAMS(Method _Nonnull method) { - M68K_ARG(Method, method, a0) + M68K_ARG(Method _Nonnull, method, a0) return method_getName(method); } -const char *__saveds -glue_method_getTypeEncoding PPC_PARAMS(Method method) +const char *_Nullable __saveds +glue_method_getTypeEncoding PPC_PARAMS(Method _Nonnull method) { - M68K_ARG(Method, method, a0) + M68K_ARG(Method _Nonnull, method, a0) return method_getTypeEncoding(method); } -objc_property_t *__saveds -glue_class_copyPropertyList PPC_PARAMS(Class class, unsigned int *outCount) +objc_property_t _Nullable *_Nullable __saveds +glue_class_copyPropertyList PPC_PARAMS(Class _Nullable class, unsigned int *_Nullable outCount) { - M68K_ARG(Class, class, a0) - M68K_ARG(unsigned int *, outCount, a1) + M68K_ARG(Class _Nullable, class, a0) + M68K_ARG(unsigned int *_Nullable, outCount, a1) return class_copyPropertyList(class, outCount); } -const char *__saveds -glue_property_getName PPC_PARAMS(objc_property_t property) +const char *_Nonnull __saveds +glue_property_getName PPC_PARAMS(objc_property_t _Nonnull property) { - M68K_ARG(objc_property_t, property, a0) + M68K_ARG(objc_property_t _Nonnull, property, a0) return property_getName(property); } -char *__saveds -glue_property_copyAttributeValue PPC_PARAMS(objc_property_t property, - const char *name) +char *_Nullable __saveds +glue_property_copyAttributeValue PPC_PARAMS(objc_property_t _Nonnull property, const char *_Nonnull name) { - M68K_ARG(objc_property_t, property, a0) - M68K_ARG(const char *, name, a1) + M68K_ARG(objc_property_t _Nonnull, property, a0) + M68K_ARG(const char *_Nonnull, name, a1) return property_copyAttributeValue(property, name); } -void *__saveds -glue_objc_destructInstance PPC_PARAMS(id object) +void *_Nullable __saveds +glue_objc_destructInstance PPC_PARAMS(id _Nullable object) { - M68K_ARG(id, object, a0) + M68K_ARG(id _Nullable, object, a0) return objc_destructInstance(object); } -void *__saveds +void *_Null_unspecified __saveds glue_objc_autoreleasePoolPush(void) { return objc_autoreleasePoolPush(); } void __saveds -glue_objc_autoreleasePoolPop PPC_PARAMS(void *pool) +glue_objc_autoreleasePoolPop PPC_PARAMS(void *_Null_unspecified pool) { - M68K_ARG(void *, pool, a0) + M68K_ARG(void *_Null_unspecified, pool, a0) objc_autoreleasePoolPop(pool); } -id __saveds -glue__objc_rootAutorelease PPC_PARAMS(id object) +id _Nullable __saveds +glue__objc_rootAutorelease PPC_PARAMS(id _Nullable object) { - M68K_ARG(id, object, a0) + M68K_ARG(id _Nullable, object, a0) return _objc_rootAutorelease(object); } -struct objc_hashtable *__saveds -glue_objc_hashtable_new PPC_PARAMS(objc_hashtable_hash_func hash, - objc_hashtable_equal_func equal, uint32_t size) +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 *table, - const void *key, const void *object) +glue_objc_hashtable_set PPC_PARAMS(struct objc_hashtable *_Nonnull table, const void *_Nonnull key, const void *_Nonnull object) { - M68K_ARG(struct objc_hashtable *, table, a0) - M68K_ARG(const void *, key, a1) - M68K_ARG(const void *, object, a2) + 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 *__saveds -glue_objc_hashtable_get PPC_PARAMS(struct objc_hashtable *table, - const void *key) +void *_Nullable __saveds +glue_objc_hashtable_get PPC_PARAMS(struct objc_hashtable *_Nonnull table, const void *_Nonnull key) { - M68K_ARG(struct objc_hashtable *, table, a0) - M68K_ARG(const void *, key, a1) + 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 *table, - const void *key) +glue_objc_hashtable_delete PPC_PARAMS(struct objc_hashtable *_Nonnull table, const void *_Nonnull key) { - M68K_ARG(struct objc_hashtable *, table, a0) - M68K_ARG(const void *, key, a1) + 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 *table) +glue_objc_hashtable_free PPC_PARAMS(struct objc_hashtable *_Nonnull table) { - M68K_ARG(struct objc_hashtable *, table, a0) + M68K_ARG(struct objc_hashtable *_Nonnull, table, a0) objc_hashtable_free(table); } void __saveds @@ -807,44 +765,36 @@ objc_setTaggedPointerSecret(secret); } int __saveds -glue_objc_registerTaggedPointerClass PPC_PARAMS(Class class) +glue_objc_registerTaggedPointerClass PPC_PARAMS(Class _Nonnull class) { - M68K_ARG(Class, class, a0) + M68K_ARG(Class _Nonnull, class, a0) return objc_registerTaggedPointerClass(class); } bool __saveds -glue_object_isTaggedPointer PPC_PARAMS(id object) +glue_object_isTaggedPointer PPC_PARAMS(id _Nullable object) { - M68K_ARG(id, object, a0) + M68K_ARG(id _Nullable, object, a0) return object_isTaggedPointer(object); } -Class __saveds -glue_object_getTaggedPointerClass PPC_PARAMS(id object) -{ - M68K_ARG(id, object, a0) - - return object_getTaggedPointerClass(object); -} - -uintptr_t __saveds -glue_object_getTaggedPointerValue PPC_PARAMS(id object) -{ - M68K_ARG(id, object, a0) +uintptr_t __saveds +glue_object_getTaggedPointerValue PPC_PARAMS(id _Nonnull object) +{ + M68K_ARG(id _Nonnull, object, a0) return object_getTaggedPointerValue(object); } -id __saveds +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); } Index: src/runtime/amiga-library.m ================================================================== --- src/runtime/amiga-library.m +++ src/runtime/amiga-library.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -17,10 +15,12 @@ #include "config.h" #import "ObjFWRT.h" #import "private.h" + +#import "amiga-glue.h" #include #include #include #include @@ -45,10 +45,17 @@ int _start() { return -1; } + +#ifdef OF_AMIGAOS_M68K +void +__init_eh(void) +{ +} +#endif struct ObjFWRTBase { struct Library library; void *segList; struct ObjFWRTBase *parent; @@ -60,109 +67,15 @@ extern uintptr_t __CTOR_LIST__[]; extern const void *_EH_FRAME_BEGINS__; extern void *_EH_FRAME_OBJECTS__; #endif -extern bool glue_objc_init(void); -extern void glue___objc_exec_class(void); -extern IMP glue_objc_msg_lookup(void); -extern IMP glue_objc_msg_lookup_stret(void); -extern IMP glue_objc_msg_lookup_super(void); -extern IMP glue_objc_msg_lookup_super_stret(void); -extern Class glue_objc_lookUpClass(void); -extern Class glue_objc_getClass(void); -extern Class glue_objc_getRequiredClass(void); -extern Class glue_objc_lookup_class(void); -extern Class glue_objc_get_class(void); -extern void glue_objc_exception_throw(void); -extern int glue_objc_sync_enter(void); -extern int glue_objc_sync_exit(void); -extern id glue_objc_getProperty(void); -extern void glue_objc_setProperty(void); -extern void glue_objc_getPropertyStruct(void); -extern void glue_objc_setPropertyStruct(void); -extern void glue_objc_enumerationMutation(void); -extern int glue___gnu_objc_personality(void); -extern id glue_objc_retain(void); -extern id glue_objc_retainBlock(void); -extern id glue_objc_retainAutorelease(void); -extern void glue_objc_release(void); -extern id glue_objc_autorelease(void); -extern id glue_objc_autoreleaseReturnValue(void); -extern id glue_objc_retainAutoreleaseReturnValue(void); -extern id glue_objc_retainAutoreleasedReturnValue(void); -extern id glue_objc_storeStrong(void); -extern id glue_objc_storeWeak(void); -extern id glue_objc_loadWeakRetained(void); -extern id glue_objc_initWeak(void); -extern void glue_objc_destroyWeak(void); -extern id glue_objc_loadWeak(void); -extern void glue_objc_copyWeak(void); -extern void glue_objc_moveWeak(void); -extern SEL glue_sel_registerName(void); -extern const char *glue_sel_getName(void); -extern bool glue_sel_isEqual(void); -extern Class glue_objc_allocateClassPair(void); -extern void glue_objc_registerClassPair(void); -extern unsigned int glue_objc_getClassList(void); -extern Class *glue_objc_copyClassList(void); -extern bool glue_class_isMetaClass(void); -extern const char *glue_class_getName(void); -extern Class glue_class_getSuperclass(void); -extern unsigned long glue_class_getInstanceSize(void); -extern bool glue_class_respondsToSelector(void); -extern bool glue_class_conformsToProtocol(void); -extern IMP glue_class_getMethodImplementation(void); -extern IMP glue_class_getMethodImplementation_stret(void); -extern Method glue_class_getInstanceMethod(void); -extern bool glue_class_addMethod(void); -extern IMP glue_class_replaceMethod(void); -extern Class glue_object_getClass(void); -extern Class glue_object_setClass(void); -extern const char *glue_object_getClassName(void); -extern const char *glue_protocol_getName(void); -extern bool glue_protocol_isEqual(void); -extern bool glue_protocol_conformsToProtocol(void); -extern objc_uncaught_exception_handler_t - glue_objc_setUncaughtExceptionHandler(void); -extern void glue_objc_setForwardHandler(void); -extern void glue_objc_setEnumerationMutationHandler(void); -extern id glue_objc_constructInstance(void); -extern void glue_objc_exit(void); -extern Ivar *glue_class_copyIvarList(void); -extern const char *glue_ivar_getName(void); -extern const char *glue_ivar_getTypeEncoding(void); -extern ptrdiff_t glue_ivar_getOffset(void); -extern Method *glue_class_copyMethodList(void); -extern SEL glue_method_getName(void); -extern const char *glue_method_getTypeEncoding(void); -extern objc_property_t *glue_class_copyPropertyList(void); -extern const char *glue_property_getName(void); -extern char *glue_property_copyAttributeValue(void); -extern void *glue_objc_destructInstance(void); -extern void *glue_objc_autoreleasePoolPush(void); -extern void glue_objc_autoreleasePoolPop(void); -extern id glue__objc_rootAutorelease(void); -extern struct objc_hashtable *glue_objc_hashtable_new(void); -extern void glue_objc_hashtable_set(void); -extern void *glue_objc_hashtable_get(void); -extern void glue_objc_hashtable_delete(void); -extern void glue_objc_hashtable_free(void); -extern void glue_objc_setTaggedPointerSecret(void); -extern int glue_objc_registerTaggedPointerClass(void); -extern bool glue_object_isTaggedPointer(void); -extern Class glue_object_getTaggedPointerClass(void); -extern uintptr_t glue_object_getTaggedPointerValue(void); -extern id glue_objc_createTaggedPointer(void); - #ifdef OF_MORPHOS const ULONG __abox__ = 1; #endif struct ExecBase *SysBase; struct objc_libc libc; -FILE *stdout; -FILE *stderr; #if defined(OF_AMIGAOS_M68K) __asm__ ( ".text\n" ".globl ___restore_a4\n" @@ -329,12 +242,13 @@ return &child->library; } static void * -expunge(struct ObjFWRTBase *base) +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; @@ -350,23 +264,31 @@ 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); + 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; @@ -386,39 +308,40 @@ base = parent; } if (--base->library.lib_OpenCnt == 0 && (base->library.lib_Flags & LIBF_DELEXP)) - return expunge(base); + 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_, FILE *stdout_, - FILE *stderr_) +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)); - stdout = stdout_; - stderr = stderr_; #ifdef OF_AMIGAOS_M68K if ((size_t)_EH_FRAME_BEGINS__ != (size_t)_EH_FRAME_OBJECTS__) return false; @@ -427,14 +350,18 @@ (&_EH_FRAME_OBJECTS__)[i]); iter0 = &__CTOR_LIST__[1]; #elif defined(OF_MORPHOS) __asm__ ( - "lis %0, ctors+4@ha\n\t" - "la %0, ctors+4@l(%0)\n\t" - : "=r"(iter0) + "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) { @@ -469,37 +396,10 @@ free(void *ptr) { libc.free(ptr); } -int -fprintf(FILE *restrict stream, const char *restrict fmt, ...) -{ - int ret; - va_list args; - - va_start(args, fmt); - ret = libc.vfprintf(stream, fmt, args); - va_end(args); - - return ret; -} - -int -fflush(FILE *restrict stream) -{ - return libc.fflush(stream); -} - -void -abort(void) -{ - libc.abort(); - - OF_UNREACHABLE -} - #ifdef HAVE_SJLJ_EXCEPTIONS int _Unwind_SjLj_RaiseException(void *ex) { return libc._Unwind_SjLj_RaiseException(ex); @@ -577,10 +477,46 @@ _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 @@ -593,100 +529,11 @@ (CONST_APTR)lib_null, #ifdef OF_MORPHOS (CONST_APTR)-1, (CONST_APTR)FUNCARRAY_32BIT_SYSTEMV, #endif - (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_exit, - (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_getTaggedPointerClass, - (CONST_APTR)glue_object_getTaggedPointerValue, - (CONST_APTR)glue_objc_createTaggedPointer, +#include "amiga-funcarray.inc" (CONST_APTR)-1, #ifdef OF_MORPHOS (CONST_APTR)FUNCARRAY_END #endif }; @@ -719,21 +566,26 @@ .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-2019 Jonathan Schleifer", + " \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 .ctors, \"aw\", @progbits\n" - "ctors:\n" - " .long -1\n" + ".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 ADDED src/runtime/amiga-library.xml Index: src/runtime/amiga-library.xml ================================================================== --- /dev/null +++ src/runtime/amiga-library.xml @@ -0,0 +1,345 @@ + + ObjFWRT.h + private.h + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DELETED src/runtime/amigaos3.sfd Index: src/runtime/amigaos3.sfd ================================================================== --- src/runtime/amigaos3.sfd +++ /dev/null @@ -1,99 +0,0 @@ -==base _ObjFWRTBase -==basetype struct Library * -==libname objfwrt68k.library -==bias 30 -==public -* The following function is only for the linklib. -bool glue_objc_init(unsigned int version, struct objc_libc *libc, FILE *stdout, FILE *stderr)(d0,a0,a1,a2) -void glue___objc_exec_class(struct objc_module *_Nonnull module)(a0) -IMP _Nonnull glue_objc_msg_lookup(id _Nullable object, SEL _Nonnull selector)(a0,a1) -IMP _Nonnull glue_objc_msg_lookup_stret(id _Nullable object, SEL _Nonnull selector)(a0,a1) -IMP _Nonnull glue_objc_msg_lookup_super(struct objc_super *_Nonnull super, SEL _Nonnull selector)(a0,a1) -IMP _Nonnull glue_objc_msg_lookup_super_stret(struct objc_super *_Nonnull super, SEL _Nonnull selector)(a0,a1) -Class _Nullable glue_objc_lookUpClass(const char *_Nonnull name)(a0) -Class _Nullable glue_objc_getClass(const char *_Nonnull name)(a0) -Class _Nonnull glue_objc_getRequiredClass(const char *_Nonnull name)(a0) -Class _Nullable glue_objc_lookup_class(const char *_Nonnull name)(a0) -Class _Nonnull glue_objc_get_class(const char *_Nonnull name)(a0) -void glue_objc_exception_throw(id _Nonnull object)(a0) -int glue_objc_sync_enter(id _Nullable object)(a0) -int glue_objc_sync_exit(id _Nullable object)(a0) -id glue_objc_getProperty(id _Nonnull self, SEL _Nonnull _cmd, ptrdiff_t offset, bool atomic)(a0,a1,d0,d1) -void glue_objc_setProperty(id _Nonnull self, SEL _Nonnull _cmd, ptrdiff_t offset, id value, bool atomic, signed char copy)(a0,a1,d0,a2,d1,d2) -void glue_objc_getPropertyStruct(void *_Nonnull dest, const void *_Nonnull src, ptrdiff_t size, bool atomic, bool strong)(a0,a1,d0,d1,d2) -void glue_objc_setPropertyStruct(void *_Nonnull dest, const void *_Nonnull src, ptrdiff_t size, bool atomic, bool strong)(a0,a1,d0,d1,d2) -void glue_objc_enumerationMutation(id _Nonnull object)(a0) -int glue___gnu_objc_personality(int version, int actions, uint64_t *_Nonnull exClass, void *_Nonnull ex, void *_Nonnull ctx)(d0,d1,d2,a0,a1) -id _Nullable glue_objc_retain(id _Nullable object)(a0) -id _Nullable glue_objc_retainBlock(id _Nullable block)(a0) -id _Nullable glue_objc_retainAutorelease(id _Nullable object)(a0) -void glue_objc_release(id _Nullable object)(a0) -id _Nullable glue_objc_autorelease(id _Nullable object)(a0) -id _Nullable glue_objc_autoreleaseReturnValue(id _Nullable object)(a0) -id _Nullable glue_objc_retainAutoreleaseReturnValue(id _Nullable object)(a0) -id _Nullable glue_objc_retainAutoreleasedReturnValue(id _Nullable object)(a0) -id _Nullable glue_objc_storeStrong(id _Nullable *_Nonnull object, id _Nullable value)(a0,a1) -id _Nullable glue_objc_storeWeak(id _Nullable *_Nonnull object, id _Nullable value)(a0,a1) -id _Nullable glue_objc_loadWeakRetained(id _Nullable *_Nonnull object)(a0) -id _Nullable glue_objc_initWeak(id _Nullable *_Nonnull object, id _Nullable value)(a0,a1) -void glue_objc_destroyWeak(id _Nullable *_Nonnull object)(a0) -id _Nullable glue_objc_loadWeak(id _Nullable *_Nonnull object)(a0) -void glue_objc_copyWeak(id _Nullable *_Nonnull dest, id _Nullable *_Nonnull src)(a0,a1) -void glue_objc_moveWeak(id _Nullable *_Nonnull dest, id _Nullable *_Nonnull src)(a0,a1) -SEL _Nonnull glue_sel_registerName(const char *_Nonnull name)(a0) -const char *_Nonnull glue_sel_getName(SEL _Nonnull selector)(a0) -bool glue_sel_isEqual(SEL _Nonnull selector1, SEL _Nonnull selector2)(a0,a1) -Class _Nonnull glue_objc_allocateClassPair(Class _Nullable superclass, const char *_Nonnull name, size_t extraBytes)(a0,a1,d0) -void glue_objc_registerClassPair(Class _Nonnull class_)(a0) -unsigned int glue_objc_getClassList(Class _Nonnull *_Nullable buffer, unsigned int count)(a0,d0) -Class _Nonnull *_Nonnull glue_objc_copyClassList(unsigned int *_Nullable length)(a0) -bool glue_class_isMetaClass(Class _Nullable class_)(a0) -const char *_Nullable glue_class_getName(Class _Nullable class_)(a0) -Class _Nullable glue_class_getSuperclass(Class _Nullable class_)(a0) -unsigned long glue_class_getInstanceSize(Class _Nullable class_)(a0) -bool glue_class_respondsToSelector(Class _Nullable class_, SEL _Nonnull selector)(a0,a1) -bool glue_class_conformsToProtocol(Class _Nullable class_, Protocol *_Nonnull p)(a0,a1) -IMP _Nullable glue_class_getMethodImplementation(Class _Nullable class_, SEL _Nonnull selector)(a0,a1) -IMP _Nullable glue_class_getMethodImplementation_stret(Class _Nullable class_, SEL _Nonnull selector)(a0,a1) -Method _Nullable glue_class_getInstanceMethod(Class _Nullable class_, SEL _Nonnull selector)(a0,a1) -bool glue_class_addMethod(Class _Nonnull class_, SEL _Nonnull selector, IMP _Nonnull implementation, const char *_Nullable typeEncoding)(a0,a1,a2,a3) -IMP _Nullable glue_class_replaceMethod(Class _Nonnull class_, SEL _Nonnull selector, IMP _Nonnull implementation, const char *_Nullable typeEncoding)(a0,a1,a2,a3) -Class _Nullable glue_object_getClass(id _Nullable object)(a0) -Class _Nullable glue_object_setClass(id _Nullable object, Class _Nonnull class_)(a0,a1) -const char *_Nullable glue_object_getClassName(id _Nullable object)(a0) -const char *_Nonnull glue_protocol_getName(Protocol *_Nonnull protocol)(a0) -bool glue_protocol_isEqual(Protocol *_Nonnull protocol1, Protocol *_Nonnull protocol2)(a0,a1) -bool glue_protocol_conformsToProtocol(Protocol *_Nonnull protocol1, Protocol *_Nonnull protocol2)(a0,a1) -_Nullable objc_uncaught_exception_handler_t glue_objc_setUncaughtExceptionHandler(objc_uncaught_exception_handler_t _Nullable handler)(a0) -void glue_objc_setForwardHandler(IMP _Nullable forward, IMP _Nullable stretForward)(a0,a1) -void glue_objc_setEnumerationMutationHandler(objc_enumeration_mutation_handler_t _Nullable handler)(a0) -id _Nullable glue_objc_constructInstance(Class _Nullable class_, void *_Nullable bytes)(a0,a1) -void glue_objc_exit(void)() -Ivar _Nullable *_Nullable glue_class_copyIvarList(Class _Nullable class_, unsigned int *_Nullable outCount)(a0,a1) -const char *_Nonnull glue_ivar_getName(Ivar _Nonnull ivar)(a0) -const char *_Nonnull glue_ivar_getTypeEncoding(Ivar _Nonnull ivar)(a0) -ptrdiff_t glue_ivar_getOffset(Ivar _Nonnull ivar)(a0) -Method _Nullable *_Nullable glue_class_copyMethodList(Class _Nullable class_, unsigned int *_Nullable outCount)(a0,a1) -SEL _Nonnull glue_method_getName(Method _Nonnull method)(a0) -const char *_Nullable glue_method_getTypeEncoding(Method _Nonnull method)(a0) -objc_property_t _Nullable *_Nullable glue_class_copyPropertyList(Class _Nullable class_, unsigned int *_Nullable outCount)(a0,a1) -const char *_Nonnull glue_property_getName(objc_property_t _Nonnull property)(a0) -char *_Nullable glue_property_copyAttributeValue(objc_property_t _Nonnull property, const char *_Nonnull name)(a0,a1) -void *_Nullable glue_objc_destructInstance(id _Nullable object)(a0) -void *_Null_unspecified glue_objc_autoreleasePoolPush(void)() -void glue_objc_autoreleasePoolPop(void *_Null_unspecified pool)(a0) -id _Nullable glue__objc_rootAutorelease(id _Nullable object)(a0) -* The following functions are private! Don't use! -struct objc_hashtable *_Nonnull glue_objc_hashtable_new(objc_hashtable_hash_func hash, objc_hashtable_equal_func equal, uint32_t size)(a0,a1,d0) -void glue_objc_hashtable_set(struct objc_hashtable *_Nonnull table, const void *_Nonnull key, const void *_Nonnull object)(a0,a1,a2) -void *_Nullable glue_objc_hashtable_get(struct objc_hashtable *_Nonnull table, const void *_Nonnull key)(a0,a1) -void glue_objc_hashtable_delete(struct objc_hashtable *_Nonnull table, const void *_Nonnull key)(a0,a1) -void glue_objc_hashtable_free(struct objc_hashtable *_Nonnull table)(a0) -* Public functions again -void glue_objc_setTaggedPointerSecret(uintptr_t secret)(d0) -int glue_objc_registerTaggedPointerClass(Class _Nonnull class_)(a0) -bool glue_object_isTaggedPointer(id _Nullable object)(a0) -Class _Nullable glue_object_getTaggedPointerClass(id _Nonnull object)(a0) -uintptr_t glue_object_getTaggedPointerValue(id _Nonnull object)(a0) -id _Nullable glue_objc_createTaggedPointer(int class_, uintptr_t value)(d0,d1) -==end Index: src/runtime/arc.m ================================================================== --- src/runtime/arc.m +++ src/runtime/arc.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -19,21 +17,21 @@ #import "ObjFWRT.h" #import "private.h" #ifdef OF_HAVE_THREADS -# import "mutex.h" +# import "OFPlainMutex.h" #endif -struct weak_ref { +struct WeakRef { id **locations; size_t count; }; static struct objc_hashtable *hashtable; #ifdef OF_HAVE_THREADS -static of_spinlock_t spinlock; +static OFSpinlock spinlock; #endif static uint32_t hash(const void *object) { @@ -49,12 +47,12 @@ OF_CONSTRUCTOR() { hashtable = objc_hashtable_new(hash, equal, 2); #ifdef OF_HAVE_THREADS - if (!of_spinlock_new(&spinlock)) - OBJC_ERROR("Failed to create spinlock!") + if (OFSpinlockNew(&spinlock) != 0) + OBJC_ERROR("Failed to create spinlock!"); #endif } id objc_retain(id object) @@ -117,15 +115,15 @@ } id objc_storeWeak(id *object, id value) { - struct weak_ref *old; + struct WeakRef *old; #ifdef OF_HAVE_THREADS - if (!of_spinlock_lock(&spinlock)) - OBJC_ERROR("Failed to lock spinlock!") + if (OFSpinlockLock(&spinlock) != 0) + OBJC_ERROR("Failed to lock spinlock!"); #endif if (*object != nil && (old = objc_hashtable_get(hashtable, *object)) != NULL) { for (size_t i = 0; i < old->count; i++) { @@ -155,11 +153,11 @@ } } if (value != nil && class_respondsToSelector(object_getClass(value), @selector(allowsWeakReference)) && [value allowsWeakReference]) { - struct weak_ref *ref = objc_hashtable_get(hashtable, value); + struct WeakRef *ref = objc_hashtable_get(hashtable, value); if (ref == NULL) { if ((ref = calloc(1, sizeof(*ref))) == NULL) OBJC_ERROR("Not enough memory to allocate weak " "reference!"); @@ -168,44 +166,44 @@ } if ((ref->locations = realloc(ref->locations, (ref->count + 1) * sizeof(id *))) == NULL) OBJC_ERROR("Not enough memory to allocate weak " - "reference!") + "reference!"); ref->locations[ref->count++] = object; } else value = nil; *object = value; #ifdef OF_HAVE_THREADS - if (!of_spinlock_unlock(&spinlock)) - OBJC_ERROR("Failed to unlock spinlock!") + if (OFSpinlockUnlock(&spinlock) != 0) + OBJC_ERROR("Failed to unlock spinlock!"); #endif return value; } id objc_loadWeakRetained(id *object) { id value = nil; - struct weak_ref *ref; + struct WeakRef *ref; #ifdef OF_HAVE_THREADS - if (!of_spinlock_lock(&spinlock)) - OBJC_ERROR("Failed to lock spinlock!") + if (OFSpinlockLock(&spinlock) != 0) + OBJC_ERROR("Failed to lock spinlock!"); #endif if (*object != nil && (ref = objc_hashtable_get(hashtable, *object)) != NULL) value = *object; #ifdef OF_HAVE_THREADS - if (!of_spinlock_unlock(&spinlock)) - OBJC_ERROR("Failed to unlock spinlock!") + if (OFSpinlockUnlock(&spinlock) != 0) + OBJC_ERROR("Failed to unlock spinlock!"); #endif if (class_respondsToSelector(object_getClass(value), @selector(retainWeakReference)) && [value retainWeakReference]) return value; @@ -239,15 +237,15 @@ } void objc_moveWeak(id *dest, id *src) { - struct weak_ref *ref; + struct WeakRef *ref; #ifdef OF_HAVE_THREADS - if (!of_spinlock_lock(&spinlock)) - OBJC_ERROR("Failed to lock spinlock!") + if (OFSpinlockLock(&spinlock) != 0) + OBJC_ERROR("Failed to lock spinlock!"); #endif if (*src != nil && (ref = objc_hashtable_get(hashtable, *src)) != NULL) { for (size_t i = 0; i < ref->count; i++) { @@ -260,23 +258,23 @@ *dest = *src; *src = nil; #ifdef OF_HAVE_THREADS - if (!of_spinlock_unlock(&spinlock)) - OBJC_ERROR("Failed to unlock spinlock!") + if (OFSpinlockUnlock(&spinlock) != 0) + OBJC_ERROR("Failed to unlock spinlock!"); #endif } void -objc_zero_weak_references(id value) +objc_zeroWeakReferences(id value) { - struct weak_ref *ref; + struct WeakRef *ref; #ifdef OF_HAVE_THREADS - if (!of_spinlock_lock(&spinlock)) - OBJC_ERROR("Failed to lock spinlock!") + if (OFSpinlockLock(&spinlock) != 0) + OBJC_ERROR("Failed to lock spinlock!"); #endif if ((ref = objc_hashtable_get(hashtable, value)) != NULL) { for (size_t i = 0; i < ref->count; i++) *ref->locations[i] = nil; @@ -285,9 +283,9 @@ free(ref->locations); free(ref); } #ifdef OF_HAVE_THREADS - if (!of_spinlock_unlock(&spinlock)) - OBJC_ERROR("Failed to unlock spinlock!") + if (OFSpinlockUnlock(&spinlock) != 0) + OBJC_ERROR("Failed to unlock spinlock!"); #endif } Index: src/runtime/autorelease.m ================================================================== --- src/runtime/autorelease.m +++ src/runtime/autorelease.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -27,55 +25,60 @@ # import #endif #import "macros.h" #if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) -# import "tlskey.h" +# import "OFTLSKey.h" #endif #ifndef OF_OBJFW_RUNTIME @interface DummyObject - (void)release; @end #endif + +#ifndef OBJC_ERROR +/* This is also used with old Apple runtimes that lack autorelease pools. */ +# define OBJC_ERROR(...) abort() +#endif #if defined(OF_HAVE_COMPILER_TLS) static thread_local id *objects = NULL; static thread_local uintptr_t count = 0; static thread_local uintptr_t size = 0; #elif defined(OF_HAVE_THREADS) -static of_tlskey_t objectsKey, countKey, sizeKey; +static OFTLSKey objectsKey, countKey, sizeKey; #else static id *objects = NULL; static uintptr_t count = 0; static uintptr_t size = 0; #endif #if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) OF_CONSTRUCTOR() { - OF_ENSURE(of_tlskey_new(&objectsKey)); - OF_ENSURE(of_tlskey_new(&countKey)); - OF_ENSURE(of_tlskey_new(&sizeKey)); + if (OFTLSKeyNew(&objectsKey) != 0 || OFTLSKeyNew(&countKey) != 0 || + OFTLSKeyNew(&sizeKey) != 0) + OBJC_ERROR("Failed to create TLS keys!"); } #endif void * objc_autoreleasePoolPush() { #if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) - uintptr_t count = (uintptr_t)of_tlskey_get(countKey); + uintptr_t count = (uintptr_t)OFTLSKeyGet(countKey); #endif return (void *)count; } void objc_autoreleasePoolPop(void *pool) { #if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) - id *objects = of_tlskey_get(objectsKey); - uintptr_t count = (uintptr_t)of_tlskey_get(countKey); + id *objects = OFTLSKeyGet(objectsKey); + uintptr_t count = (uintptr_t)OFTLSKeyGet(countKey); #endif uintptr_t idx = (uintptr_t)pool; bool freeMem = false; if (idx == (uintptr_t)-1) { @@ -85,12 +88,12 @@ for (uintptr_t i = idx; i < count; i++) { [objects[i] release]; #if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) - objects = of_tlskey_get(objectsKey); - count = (uintptr_t)of_tlskey_get(countKey); + objects = OFTLSKeyGet(objectsKey); + count = (uintptr_t)OFTLSKeyGet(countKey); #endif } count = idx; @@ -98,47 +101,51 @@ free(objects); objects = NULL; #if defined(OF_HAVE_COMPILER_TLS) || !defined(OF_HAVE_THREADS) size = 0; #else - OF_ENSURE(of_tlskey_set(objectsKey, objects)); - OF_ENSURE(of_tlskey_set(sizeKey, (void *)0)); + if (OFTLSKeySet(objectsKey, objects) != 0 || + OFTLSKeySet(sizeKey, (void *)0) != 0) + OBJC_ERROR("Failed to set TLS key!"); #endif } #if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) - OF_ENSURE(of_tlskey_set(countKey, (void *)count)); + if (OFTLSKeySet(countKey, (void *)count) != 0) + OBJC_ERROR("Failed to set TLS key!"); #endif } id _objc_rootAutorelease(id object) { #if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) - id *objects = of_tlskey_get(objectsKey); - uintptr_t count = (uintptr_t)of_tlskey_get(countKey); - uintptr_t size = (uintptr_t)of_tlskey_get(sizeKey); + id *objects = OFTLSKeyGet(objectsKey); + uintptr_t count = (uintptr_t)OFTLSKeyGet(countKey); + uintptr_t size = (uintptr_t)OFTLSKeyGet(sizeKey); #endif if (count >= size) { if (size == 0) size = 16; else size *= 2; - OF_ENSURE((objects = - realloc(objects, size * sizeof(id))) != NULL); + if ((objects = realloc(objects, size * sizeof(id))) == NULL) + OBJC_ERROR("Failed to resize autorelease pool!"); #if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) - OF_ENSURE(of_tlskey_set(objectsKey, objects)); - OF_ENSURE(of_tlskey_set(sizeKey, (void *)size)); + if (OFTLSKeySet(objectsKey, objects) != 0 || + OFTLSKeySet(sizeKey, (void *)size) != 0) + OBJC_ERROR("Failed to set TLS key!"); #endif } objects[count++] = object; #if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) - OF_ENSURE(of_tlskey_set(countKey, (void *)count)); + if (OFTLSKeySet(countKey, (void *)count) != 0) + OBJC_ERROR("Failed to set TLS key!"); #endif return object; } Index: src/runtime/category.m ================================================================== --- src/runtime/category.m +++ src/runtime/category.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -32,26 +30,26 @@ struct objc_method_list *iter; unsigned int i; for (iter = category->instanceMethods; iter != NULL; iter = iter->next) for (i = 0; i < iter->count; i++) - objc_register_selector(&iter->methods[i].selector); + objc_registerSelector(&iter->methods[i].selector); for (iter = category->classMethods; iter != NULL; iter = iter->next) for (i = 0; i < iter->count; i++) - objc_register_selector(&iter->methods[i].selector); + objc_registerSelector(&iter->methods[i].selector); } static void registerCategory(struct objc_category *category) { struct objc_category **categories; - Class class = objc_classname_to_class(category->className, false); + Class class = objc_classnameToClass(category->className, false); if (categoriesMap == NULL) categoriesMap = objc_hashtable_new( - objc_hash_string, objc_equal_string, 2); + objc_string_hash, objc_string_equal, 2); categories = (struct objc_category **)objc_hashtable_get( categoriesMap, category->className); if (categories != NULL) { @@ -70,12 +68,12 @@ newCategories[i + 1] = NULL; objc_hashtable_set(categoriesMap, category->className, newCategories); if (class != Nil && class->info & OBJC_CLASS_INFO_SETUP) { - objc_update_dtable(class); - objc_update_dtable(class->isa); + objc_updateDTable(class); + objc_updateDTable(class->isa); } return; } @@ -86,17 +84,17 @@ categories[0] = category; categories[1] = NULL; objc_hashtable_set(categoriesMap, category->className, categories); if (class != Nil && class->info & OBJC_CLASS_INFO_SETUP) { - objc_update_dtable(class); - objc_update_dtable(class->isa); + objc_updateDTable(class); + objc_updateDTable(class->isa); } } void -objc_register_all_categories(struct objc_symtab *symtab) +objc_registerAllCategories(struct objc_symtab *symtab) { struct objc_category **categories = (struct objc_category **)symtab->defs + symtab->classDefsCount; for (size_t i = 0; i < symtab->categoryDefsCount; i++) { @@ -104,21 +102,21 @@ registerCategory(categories[i]); } } struct objc_category ** -objc_categories_for_class(Class class) +objc_categoriesForClass(Class class) { if (categoriesMap == NULL) return NULL; return (struct objc_category **)objc_hashtable_get(categoriesMap, class->name); } void -objc_unregister_all_categories(void) +objc_unregisterAllCategories(void) { if (categoriesMap == NULL) return; for (uint32_t i = 0; i < categoriesMap->size; i++) Index: src/runtime/class.m ================================================================== --- src/runtime/class.m +++ src/runtime/class.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -36,38 +34,38 @@ static void registerClass(Class class) { if (classes == NULL) classes = objc_hashtable_new( - objc_hash_string, objc_equal_string, 2); + objc_string_hash, objc_string_equal, 2); objc_hashtable_set(classes, class->name, class); if (emptyDTable == NULL) emptyDTable = objc_dtable_new(); - class->DTable = emptyDTable; - class->isa->DTable = emptyDTable; + class->dTable = emptyDTable; + class->isa->dTable = emptyDTable; if (strcmp(class->name, "Protocol") != 0) classesCount++; } bool class_registerAlias_np(Class class, const char *name) { - objc_global_mutex_lock(); + objc_globalMutex_lock(); if (classes == NULL) { - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return NO; } objc_hashtable_set(classes, name, (Class)((uintptr_t)class | 1)); - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return YES; } static void @@ -76,15 +74,15 @@ struct objc_method_list *iter; unsigned int i; for (iter = class->methodList; iter != NULL; iter = iter->next) for (i = 0; i < iter->count; i++) - objc_register_selector(&iter->methods[i].selector); + objc_registerSelector(&iter->methods[i].selector); } Class -objc_classname_to_class(const char *name, bool cache) +objc_classnameToClass(const char *name, bool cache) { Class class; if (classes == NULL) return Nil; @@ -115,21 +113,21 @@ if (class != Nil) return class; } - objc_global_mutex_lock(); + objc_globalMutex_lock(); class = (Class)((uintptr_t)objc_hashtable_get(classes, name) & ~1); if (cache && fastPath == NULL && --lookupsUntilFastPath == 0) fastPath = objc_sparsearray_new(sizeof(uintptr_t)); if (cache && fastPath != NULL) objc_sparsearray_set(fastPath, (uintptr_t)name, class); - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return class; } static void @@ -180,31 +178,31 @@ class->info |= OBJC_CLASS_INFO_LOADED; } void -objc_update_dtable(Class class) +objc_updateDTable(Class class) { struct objc_category **categories; if (!(class->info & OBJC_CLASS_INFO_DTABLE)) return; - if (class->DTable == emptyDTable) - class->DTable = objc_dtable_new(); + if (class->dTable == emptyDTable) + class->dTable = objc_dtable_new(); if (class->superclass != Nil) - objc_dtable_copy(class->DTable, class->superclass->DTable); + objc_dtable_copy(class->dTable, class->superclass->dTable); for (struct objc_method_list *methodList = class->methodList; methodList != NULL; methodList = methodList->next) for (unsigned int i = 0; i < methodList->count; i++) - objc_dtable_set(class->DTable, + objc_dtable_set(class->dTable, (uint32_t)methodList->methods[i].selector.UID, methodList->methods[i].implementation); - if ((categories = objc_categories_for_class(class)) != NULL) { + if ((categories = objc_categoriesForClass(class)) != NULL) { for (unsigned int i = 0; categories[i] != NULL; i++) { struct objc_method_list *methodList = (class->info & OBJC_CLASS_INFO_CLASS ? categories[i]->instanceMethods : categories[i]->classMethods); @@ -211,21 +209,21 @@ for (; methodList != NULL; methodList = methodList->next) for (unsigned int j = 0; j < methodList->count; j++) - objc_dtable_set(class->DTable, + objc_dtable_set(class->dTable, (uint32_t)methodList->methods[j] .selector.UID, methodList->methods[j] .implementation); } } if (class->subclassList != NULL) for (Class *iter = class->subclassList; *iter != NULL; iter++) - objc_update_dtable(*iter); + objc_updateDTable(*iter); } static void addSubclass(Class class) { @@ -282,26 +280,26 @@ for (unsigned int i = 0; i < class->ivars->count; i++) *class->ivarOffsets[i] = class->ivars->ivars[i].offset; } static void -setupClass(Class class) +setUpClass(Class class) { const char *superclassName; if (class->info & OBJC_CLASS_INFO_SETUP) return; superclassName = (const char *)class->superclass; if (superclassName != NULL) { - Class super = objc_classname_to_class(superclassName, false); + Class super = objc_classnameToClass(superclassName, false); Class rootClass; if (super == Nil) return; - setupClass(super); + setUpClass(super); if (!(super->info & OBJC_CLASS_INFO_SETUP)) return; /* @@ -341,15 +339,22 @@ return; if (class->superclass) initializeClass(class->superclass); + /* + * Avoid double-initialization: One of the superclasses' +[initialize] + * might have called this class and hence it already got initialized. + */ + if (class->info & OBJC_CLASS_INFO_INITIALIZED) + return; + class->info |= OBJC_CLASS_INFO_DTABLE; class->isa->info |= OBJC_CLASS_INFO_DTABLE; - objc_update_dtable(class); - objc_update_dtable(class->isa); + objc_updateDTable(class); + objc_updateDTable(class->isa); /* * Set it first to prevent calling it recursively due to message sends * in the initialize method */ @@ -368,44 +373,44 @@ initialize(class, initializeSel); } } void -objc_initialize_class(Class class) +objc_initializeClass(Class class) { if (class->info & OBJC_CLASS_INFO_INITIALIZED) return; - objc_global_mutex_lock(); + objc_globalMutex_lock(); /* * It's possible that two threads try to initialize a class at the same * time. Make sure that the thread which held the lock did not already * initialize it. */ if (class->info & OBJC_CLASS_INFO_INITIALIZED) { - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return; } - setupClass(class); + setUpClass(class); if (!(class->info & OBJC_CLASS_INFO_SETUP)) { - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return; } initializeClass(class); - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); } static void processLoadQueue() { for (size_t i = 0; i < loadQueueCount; i++) { - setupClass(loadQueue[i]); + setUpClass(loadQueue[i]); if (loadQueue[i]->info & OBJC_CLASS_INFO_SETUP) { callLoad(loadQueue[i]); loadQueueCount--; @@ -426,11 +431,11 @@ } } } void -objc_register_all_classes(struct objc_symtab *symtab) +objc_registerAllClasses(struct objc_symtab *symtab) { for (uint16_t i = 0; i < symtab->classDefsCount; i++) { Class class = (Class)symtab->defs[i]; registerClass(class); @@ -440,11 +445,11 @@ for (uint16_t i = 0; i < symtab->classDefsCount; i++) { Class class = (Class)symtab->defs[i]; if (hasLoad(class)) { - setupClass(class); + setUpClass(class); if (class->info & OBJC_CLASS_INFO_SETUP) callLoad(class); else { loadQueue = realloc(loadQueue, @@ -467,24 +472,27 @@ objc_allocateClassPair(Class superclass, const char *name, size_t extraBytes) { struct objc_class *class, *metaclass; Class iter, rootclass = Nil; - if (extraBytes > LONG_MAX) - OBJC_ERROR("extraBytes out of range!") - if ((class = calloc(1, sizeof(*class))) == NULL || (metaclass = calloc(1, sizeof(*class))) == NULL) OBJC_ERROR("Not enough memory to allocate class pair for class " - "%s!", name) + "%s!", name); class->isa = metaclass; class->superclass = superclass; class->name = name; class->info = OBJC_CLASS_INFO_CLASS; class->instanceSize = (superclass != Nil ? - superclass->instanceSize : 0) + (long)extraBytes; + superclass->instanceSize : 0); + + if (extraBytes > LONG_MAX || + LONG_MAX - class->instanceSize < (long)extraBytes) + OBJC_ERROR("extraBytes too large!"); + + class->instanceSize += (long)extraBytes; for (iter = superclass; iter != Nil; iter = iter->superclass) rootclass = iter; metaclass->isa = (rootclass != Nil ? rootclass->isa : class); @@ -498,11 +506,11 @@ } void objc_registerClassPair(Class class) { - objc_global_mutex_lock(); + objc_globalMutex_lock(); registerClass(class); if (class->superclass != Nil) { addSubclass(class); @@ -517,29 +525,29 @@ else class->info |= OBJC_CLASS_INFO_LOADED; processLoadQueue(); - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); } Class objc_lookUpClass(const char *name) { Class class; - if ((class = objc_classname_to_class(name, true)) == NULL) + if ((class = objc_classnameToClass(name, true)) == NULL) return Nil; if (class->info & OBJC_CLASS_INFO_SETUP) return class; - objc_global_mutex_lock(); + objc_globalMutex_lock(); - setupClass(class); + setUpClass(class); - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); if (!(class->info & OBJC_CLASS_INFO_SETUP)) return Nil; return class; @@ -576,11 +584,11 @@ unsigned int objc_getClassList(Class *buffer, unsigned int count) { unsigned int j; - objc_global_mutex_lock(); + objc_globalMutex_lock(); if (buffer == NULL) return classesCount; if (classesCount < count) @@ -589,11 +597,11 @@ j = 0; for (uint32_t i = 0; i < classes->size; i++) { void *class; if (j >= count) { - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return j; } if (classes->data[i] == NULL) continue; @@ -607,11 +615,11 @@ continue; buffer[j++] = class; } - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return j; } Class * @@ -618,24 +626,25 @@ objc_copyClassList(unsigned int *length) { Class *ret; unsigned int count; - objc_global_mutex_lock(); + objc_globalMutex_lock(); if ((ret = malloc((classesCount + 1) * sizeof(Class))) == NULL) OBJC_ERROR("Failed to allocate memory for class list!"); count = objc_getClassList(ret, classesCount); - OF_ENSURE(count == classesCount); + if (count != classesCount) + OBJC_ERROR("Fatal internal inconsistency!"); ret[count] = Nil; if (length != NULL) *length = count; - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return ret; } bool @@ -719,11 +728,11 @@ static struct objc_method * getMethod(Class class, SEL selector) { struct objc_category **categories; - if ((categories = objc_categories_for_class(class)) != NULL) { + if ((categories = objc_categoriesForClass(class)) != NULL) { for (; *categories != NULL; categories++) { struct objc_method_list *methodList = (class->info & OBJC_CLASS_INFO_METACLASS ? (*categories)->classMethods : (*categories)->instanceMethods); @@ -753,11 +762,11 @@ addMethod(Class class, SEL selector, IMP implementation, const char *typeEncoding) { struct objc_method_list *methodList; - /* FIXME: We need a way to free this at objc_exit() */ + /* FIXME: We need a way to free this at objc_deinit() */ if ((methodList = malloc(sizeof(*methodList))) == NULL) OBJC_ERROR("Not enough memory to replace method!"); methodList->next = class->methodList; methodList->count = 1; @@ -765,11 +774,11 @@ methodList->methods[0].selector.typeEncoding = typeEncoding; methodList->methods[0].implementation = implementation; class->methodList = methodList; - objc_update_dtable(class); + objc_updateDTable(class); } Method class_getInstanceMethod(Class class, SEL selector) { @@ -777,20 +786,20 @@ Class superclass; if (class == Nil) return NULL; - objc_global_mutex_lock(); + objc_globalMutex_lock(); if ((method = getMethod(class, selector)) != NULL) { - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return method; } superclass = class->superclass; - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); if (superclass != Nil) return class_getInstanceMethod(superclass, selector); return NULL; @@ -800,19 +809,19 @@ class_addMethod(Class class, SEL selector, IMP implementation, const char *typeEncoding) { bool ret; - objc_global_mutex_lock(); + objc_globalMutex_lock(); if (getMethod(class, selector) == NULL) { addMethod(class, selector, implementation, typeEncoding); ret = true; } else ret = false; - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return ret; } IMP @@ -820,22 +829,22 @@ const char *typeEncoding) { struct objc_method *method; IMP oldImplementation; - objc_global_mutex_lock(); + objc_globalMutex_lock(); if ((method = getMethod(class, selector)) != NULL) { oldImplementation = method->implementation; method->implementation = implementation; - objc_update_dtable(class); + objc_updateDTable(class); } else { oldImplementation = NULL; addMethod(class, selector, implementation, typeEncoding); } - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return oldImplementation; } Class @@ -907,31 +916,33 @@ if (class->subclassList != NULL) { free(class->subclassList); class->subclassList = NULL; } - if (class->DTable != NULL && class->DTable != emptyDTable) - objc_dtable_free(class->DTable); + if (class->dTable != NULL && class->dTable != emptyDTable) + objc_dtable_free(class->dTable); - class->DTable = NULL; + class->dTable = NULL; if ((class->info & OBJC_CLASS_INFO_SETUP) && class->superclass != Nil) class->superclass = (Class)class->superclass->name; class->info &= ~OBJC_CLASS_INFO_SETUP; } void -objc_unregister_class(Class class) +objc_unregisterClass(Class class) { static SEL unloadSel = NULL; + + objc_globalMutex_lock(); if (unloadSel == NULL) unloadSel = sel_registerName("unload"); while (class->subclassList != NULL && class->subclassList[0] != Nil) - objc_unregister_class(class->subclassList[0]); + objc_unregisterClass(class->subclassList[0]); if (class->info & OBJC_CLASS_INFO_LOADED) callSelector(class, unloadSel); objc_hashtable_delete(classes, class->name); @@ -939,27 +950,29 @@ if (strcmp(class_getName(class), "Protocol") != 0) classesCount--; unregisterClass(class); unregisterClass(class->isa); + + objc_globalMutex_unlock(); } void -objc_unregister_all_classes(void) +objc_unregisterAllClasses(void) { if (classes == NULL) return; for (uint32_t i = 0; i < classes->size; i++) { if (classes->data[i] != NULL && - classes->data[i] != &objc_deleted_bucket) { + classes->data[i] != &objc_deletedBucket) { void *class = (Class)classes->data[i]->object; if (class == Nil || (uintptr_t)class & 1) continue; - objc_unregister_class(class); + objc_unregisterClass(class); /* * The table might have been resized, so go back to the * start again. * @@ -969,11 +982,12 @@ */ i = UINT32_MAX; } } - OF_ENSURE(classesCount == 0); + if (classesCount != 0) + OBJC_ERROR("Fatal internal inconsistency!"); if (emptyDTable != NULL) { objc_dtable_free(emptyDTable); emptyDTable = NULL; } Index: src/runtime/dtable.m ================================================================== --- src/runtime/dtable.m +++ src/runtime/dtable.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -30,15 +28,15 @@ static void init(void) { if ((emptyLevel2 = malloc(sizeof(*emptyLevel2))) == NULL) - OBJC_ERROR("Not enough memory to allocate dtable!"); + OBJC_ERROR("Not enough memory to allocate dispatch table!"); #ifdef OF_SELUID24 if ((emptyLevel3 = malloc(sizeof(*emptyLevel3))) == NULL) - OBJC_ERROR("Not enough memory to allocate dtable!"); + OBJC_ERROR("Not enough memory to allocate dispatch table!"); #endif #ifdef OF_SELUID24 for (uint_fast16_t i = 0; i < 256; i++) { emptyLevel2->buckets[i] = emptyLevel3; @@ -51,27 +49,27 @@ } struct objc_dtable * objc_dtable_new(void) { - struct objc_dtable *DTable; + struct objc_dtable *dTable; #ifdef OF_SELUID24 if (emptyLevel2 == NULL || emptyLevel3 == NULL) init(); #else if (emptyLevel2 == NULL) init(); #endif - if ((DTable = malloc(sizeof(*DTable))) == NULL) - OBJC_ERROR("Not enough memory to allocate dtable!"); + if ((dTable = malloc(sizeof(*dTable))) == NULL) + OBJC_ERROR("Not enough memory to allocate dispatch table!"); for (uint_fast16_t i = 0; i < 256; i++) - DTable->buckets[i] = emptyLevel2; + dTable->buckets[i] = emptyLevel2; - return DTable; + return dTable; } void objc_dtable_copy(struct objc_dtable *dest, struct objc_dtable *src) { @@ -113,11 +111,11 @@ #endif } } void -objc_dtable_set(struct objc_dtable *DTable, uint32_t idx, IMP implementation) +objc_dtable_set(struct objc_dtable *dTable, uint32_t idx, IMP implementation) { #ifdef OF_SELUID24 uint8_t i = idx >> 16; uint8_t j = idx >> 8; uint8_t k = idx; @@ -124,62 +122,64 @@ #else uint8_t i = idx >> 8; uint8_t j = idx; #endif - if (DTable->buckets[i] == emptyLevel2) { + if (dTable->buckets[i] == emptyLevel2) { struct objc_dtable_level2 *level2 = malloc(sizeof(*level2)); if (level2 == NULL) - OBJC_ERROR("Not enough memory to insert into dtable!"); + OBJC_ERROR("Not enough memory to insert into " + "dispatch table!"); for (uint_fast16_t l = 0; l < 256; l++) #ifdef OF_SELUID24 level2->buckets[l] = emptyLevel3; #else level2->buckets[l] = (IMP)0; #endif - DTable->buckets[i] = level2; + dTable->buckets[i] = level2; } #ifdef OF_SELUID24 - if (DTable->buckets[i]->buckets[j] == emptyLevel3) { + if (dTable->buckets[i]->buckets[j] == emptyLevel3) { struct objc_dtable_level3 *level3 = malloc(sizeof(*level3)); if (level3 == NULL) - OBJC_ERROR("Not enough memory to insert into dtable!"); + OBJC_ERROR("Not enough memory to insert into " + "dispatch table!"); for (uint_fast16_t l = 0; l < 256; l++) level3->buckets[l] = (IMP)0; - DTable->buckets[i]->buckets[j] = level3; + dTable->buckets[i]->buckets[j] = level3; } - DTable->buckets[i]->buckets[j]->buckets[k] = implementation; + dTable->buckets[i]->buckets[j]->buckets[k] = implementation; #else - DTable->buckets[i]->buckets[j] = implementation; + dTable->buckets[i]->buckets[j] = implementation; #endif } void -objc_dtable_free(struct objc_dtable *DTable) +objc_dtable_free(struct objc_dtable *dTable) { for (uint_fast16_t i = 0; i < 256; i++) { - if (DTable->buckets[i] == emptyLevel2) + if (dTable->buckets[i] == emptyLevel2) continue; #ifdef OF_SELUID24 for (uint_fast16_t j = 0; j < 256; j++) - if (DTable->buckets[i]->buckets[j] != emptyLevel3) - free(DTable->buckets[i]->buckets[j]); + if (dTable->buckets[i]->buckets[j] != emptyLevel3) + free(dTable->buckets[i]->buckets[j]); #endif - free(DTable->buckets[i]); + free(dTable->buckets[i]); } - free(DTable); + free(dTable); } void objc_dtable_cleanup(void) { Index: src/runtime/exception.m ================================================================== --- src/runtime/exception.m +++ src/runtime/exception.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -26,11 +24,11 @@ #import "ObjFWRT.h" #import "private.h" #import "macros.h" #ifdef OF_HAVE_THREADS -# include "mutex.h" +# include "OFPlainMutex.h" #endif #ifdef HAVE_SEH_EXCEPTIONS # include #endif @@ -69,42 +67,48 @@ #define GNUCOBJC_EXCEPTION_CLASS UINT64_C(0x474E55434F424A43) /* GNUCOBJC */ #define GNUCCXX0_EXCEPTION_CLASS UINT64_C(0x474E5543432B2B00) /* GNUCC++\0 */ #define CLNGCXX0_EXCEPTION_CLASS UINT64_C(0x434C4E47432B2B00) /* CLNGC++\0 */ -#define NUM_EMERGENCY_EXCEPTIONS 4 - -#define _UA_SEARCH_PHASE 0x01 -#define _UA_CLEANUP_PHASE 0x02 -#define _UA_HANDLER_FRAME 0x04 -#define _UA_FORCE_UNWIND 0x08 - -#define DW_EH_PE_absptr 0x00 - -#define DW_EH_PE_uleb128 0x01 -#define DW_EH_PE_udata2 0x02 -#define DW_EH_PE_udata4 0x03 -#define DW_EH_PE_udata8 0x04 - -#define DW_EH_PE_signed 0x08 -#define DW_EH_PE_sleb128 (DW_EH_PE_signed | DW_EH_PE_uleb128) -#define DW_EH_PE_sdata2 (DW_EH_PE_signed | DW_EH_PE_udata2) -#define DW_EH_PE_sdata4 (DW_EH_PE_signed | DW_EH_PE_udata4) -#define DW_EH_PE_sdata8 (DW_EH_PE_signed | DW_EH_PE_udata8) - -#define DW_EH_PE_pcrel 0x10 -#define DW_EH_PE_textrel 0x20 -#define DW_EH_PE_datarel 0x30 -#define DW_EH_PE_funcrel 0x40 -#define DW_EH_PE_aligned 0x50 - -#define DW_EH_PE_indirect 0x80 - -#define DW_EH_PE_omit 0xFF - -#define CLEANUP_FOUND 0x01 -#define HANDLER_FOUND 0x02 +#define numEmergencyExceptions 4 + +enum { + _UA_SEARCH_PHASE = 0x01, + _UA_CLEANUP_PHASE = 0x02, + _UA_HANDLER_FRAME = 0x04, + _UA_FORCE_UNWIND = 0x08 +}; + +enum { + DW_EH_PE_absptr = 0x00, + + DW_EH_PE_uleb128 = 0x01, + DW_EH_PE_udata2 = 0x02, + DW_EH_PE_udata4 = 0x03, + DW_EH_PE_udata8 = 0x04, + + DW_EH_PE_signed = 0x08, + DW_EH_PE_sleb128 = (DW_EH_PE_signed | DW_EH_PE_uleb128), + DW_EH_PE_sdata2 = (DW_EH_PE_signed | DW_EH_PE_udata2), + DW_EH_PE_sdata4 = (DW_EH_PE_signed | DW_EH_PE_udata4), + DW_EH_PE_sdata8 = (DW_EH_PE_signed | DW_EH_PE_udata8), + + DW_EH_PE_pcrel = 0x10, + DW_EH_PE_textrel = 0x20, + DW_EH_PE_datarel = 0x30, + DW_EH_PE_funcrel = 0x40, + DW_EH_PE_aligned = 0x50, + + DW_EH_PE_indirect = 0x80, + + DW_EH_PE_omit = 0xFF +}; + +enum { + CLEANUP_FOUND = 0x01, + HANDLER_FOUND = 0x02 +}; struct _Unwind_Context; typedef enum { _URC_OK = 0, @@ -158,11 +162,11 @@ uintptr_t landingpad; intptr_t filter; #endif }; -struct lsda { +struct LSDA { uintptr_t regionStart, landingpadsStart; uint8_t typesTableEnc; const uint8_t *typesTable; uintptr_t typesTableBase; uint8_t callsitesEnc; @@ -239,19 +243,19 @@ extern EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD, void *, PCONTEXT, PDISPATCHER_CONTEXT, _Unwind_Reason_Code (*)(int, int, uint64_t, struct _Unwind_Exception *, struct _Unwind_Context *)); #endif -static objc_uncaught_exception_handler_t uncaughtExceptionHandler; -static struct objc_exception emergencyExceptions[NUM_EMERGENCY_EXCEPTIONS]; +static objc_uncaught_exception_handler uncaughtExceptionHandler; +static struct objc_exception emergencyExceptions[numEmergencyExceptions]; #ifdef OF_HAVE_THREADS -static of_spinlock_t emergencyExceptionsSpinlock; +static OFSpinlock emergencyExceptionsSpinlock; OF_CONSTRUCTOR() { - if (!of_spinlock_new(&emergencyExceptionsSpinlock)) - OBJC_ERROR("Cannot create spinlock!") + if (OFSpinlockNew(&emergencyExceptionsSpinlock) != 0) + OBJC_ERROR("Failed to create spinlock!"); } #endif static uint64_t readULEB128(const uint8_t **ptr) @@ -308,11 +312,11 @@ case DW_EH_PE_textrel: return _Unwind_GetTextRelBase(ctx); #endif } - OBJC_ERROR("Unknown encoding!") + OBJC_ERROR("Unknown encoding!"); } static size_t sizeForEncoding(uint8_t enc) { @@ -328,20 +332,26 @@ return 4; case DW_EH_PE_udata8: return 8; } - OBJC_ERROR("Unknown encoding!") + OBJC_ERROR("Unknown encoding!"); } static uint64_t readValue(uint8_t enc, const uint8_t **ptr) { uint64_t value; - if (enc == DW_EH_PE_aligned) - OBJC_ERROR("DW_EH_PE_aligned is not implemented!") + if (enc == DW_EH_PE_aligned) { + const uintptr_t *aligned = (const uintptr_t *) + OFRoundUpToPowerOf2(sizeof(void *), (uintptr_t)*ptr); + + *ptr = (const uint8_t *)(aligned + 1); + + return *aligned; + } #define READ(type) \ { \ type tmp; \ memcpy(&tmp, *ptr, sizeof(type)); \ @@ -369,11 +379,11 @@ case DW_EH_PE_sdata4: READ(int32_t) case DW_EH_PE_sdata8: READ(int64_t) default: - OBJC_ERROR("Unknown encoding!") + OBJC_ERROR("Unknown encoding!"); } #undef READ return value; } @@ -380,12 +390,12 @@ #ifndef HAVE_ARM_EHABI_EXCEPTIONS static uint64_t resolveValue(uint64_t value, uint8_t enc, const uint8_t *start, uint64_t base) { - if (value == 0) - return 0; + if (value == 0 || enc == DW_EH_PE_aligned) + return value; value += ((enc & 0x70) == DW_EH_PE_pcrel ? (uintptr_t)start : base); if (enc & DW_EH_PE_indirect) value = *(uintptr_t *)(uintptr_t)value; @@ -393,11 +403,11 @@ return value; } #endif static void -readLSDA(struct _Unwind_Context *ctx, const uint8_t *ptr, struct lsda *LSDA) +readLSDA(struct _Unwind_Context *ctx, const uint8_t *ptr, struct LSDA *LSDA) { uint8_t landingpadsStartEnc; uintptr_t callsitesSize; LSDA->regionStart = _Unwind_GetRegionStart(ctx); @@ -421,11 +431,11 @@ LSDA->actionTable = LSDA->callsites + callsitesSize; } static bool -findCallsite(struct _Unwind_Context *ctx, struct lsda *LSDA, +findCallsite(struct _Unwind_Context *ctx, struct LSDA *LSDA, uintptr_t *landingpad, const uint8_t **actionRecords) { uintptr_t IP = _Unwind_GetIP(ctx); const uint8_t *ptr = LSDA->callsites; @@ -498,11 +508,11 @@ return false; } static uint8_t -findActionRecord(const uint8_t *actionRecords, struct lsda *LSDA, int actions, +findActionRecord(const uint8_t *actionRecords, struct LSDA *LSDA, int actions, bool foreign, struct objc_exception *e, intptr_t *filterPtr) { const uint8_t *ptr; intptr_t filter, displacement; @@ -558,11 +568,11 @@ return HANDLER_FOUND; } } else if (filter == 0) return CLEANUP_FOUND; else if (filter < 0) - OBJC_ERROR("Invalid filter!") + OBJC_ERROR("Invalid filter!"); } while (displacement != 0); return 0; } @@ -594,11 +604,11 @@ _Unwind_SetGR(ctx, 12, (uintptr_t)ex); #endif struct objc_exception *e = (struct objc_exception *)ex; bool foreign = (exClass != GNUCOBJC_EXCEPTION_CLASS); const uint8_t *LSDAAddr, *actionRecords; - struct lsda LSDA; + struct LSDA LSDA; uintptr_t landingpad = 0; uint8_t found = 0; intptr_t filter = 0; if (foreign) { @@ -690,11 +700,12 @@ _Unwind_SetIP(ctx, landingpad); return _URC_INSTALL_CONTEXT; } - OBJC_ERROR("Neither _UA_SEARCH_PHASE nor _UA_CLEANUP_PHASE in actions!") + OBJC_ERROR( + "Neither _UA_SEARCH_PHASE nor _UA_CLEANUP_PHASE in actions!"); } static void cleanup(_Unwind_Reason_Code reason, struct _Unwind_Exception *ex) { @@ -704,19 +715,19 @@ static void emergencyExceptionCleanup(_Unwind_Reason_Code reason, struct _Unwind_Exception *ex) { #ifdef OF_HAVE_THREADS - if (!of_spinlock_lock(&emergencyExceptionsSpinlock)) - OBJC_ERROR("Cannot lock spinlock!"); + if (OFSpinlockLock(&emergencyExceptionsSpinlock) != 0) + OBJC_ERROR("Failed to lock spinlock!"); #endif ex->class = 0; #ifdef OF_HAVE_THREADS - if (!of_spinlock_unlock(&emergencyExceptionsSpinlock)) - OBJC_ERROR("Cannot unlock spinlock!"); + if (OFSpinlockUnlock(&emergencyExceptionsSpinlock) != 0) + OBJC_ERROR("Failed to unlock spinlock!"); #endif } void objc_exception_throw(id object) @@ -724,15 +735,15 @@ struct objc_exception *e = calloc(1, sizeof(*e)); bool emergency = false; if (e == NULL) { #ifdef OF_HAVE_THREADS - if (!of_spinlock_lock(&emergencyExceptionsSpinlock)) - OBJC_ERROR("Cannot lock spinlock!"); + if (OFSpinlockLock(&emergencyExceptionsSpinlock) != 0) + OBJC_ERROR("Failed to lock spinlock!"); #endif - for (uint_fast8_t i = 0; i < NUM_EMERGENCY_EXCEPTIONS; i++) { + for (uint_fast8_t i = 0; i < numEmergencyExceptions; i++) { if (emergencyExceptions[i].exception.class == 0) { e = &emergencyExceptions[i]; e->exception.class = GNUCOBJC_EXCEPTION_CLASS; emergency = true; @@ -739,17 +750,17 @@ break; } } #ifdef OF_HAVE_THREADS - if (!of_spinlock_unlock(&emergencyExceptionsSpinlock)) - OBJC_ERROR("Cannot lock spinlock!"); + if (OFSpinlockUnlock(&emergencyExceptionsSpinlock) != 0) + OBJC_ERROR("Failed to lock spinlock!"); #endif } if (e == NULL) - OBJC_ERROR("Not enough memory to allocate exception!") + OBJC_ERROR("Not enough memory to allocate exception!"); e->exception.class = GNUCOBJC_EXCEPTION_CLASS; e->exception.cleanup = (emergency ? emergencyExceptionCleanup : cleanup); e->object = object; @@ -757,17 +768,17 @@ _Unwind_RaiseException(&e->exception); if (uncaughtExceptionHandler != NULL) uncaughtExceptionHandler(object); - OBJC_ERROR("_Unwind_RaiseException() returned!") + OBJC_ERROR("_Unwind_RaiseException() returned!"); } -objc_uncaught_exception_handler_t -objc_setUncaughtExceptionHandler(objc_uncaught_exception_handler_t handler) +objc_uncaught_exception_handler +objc_setUncaughtExceptionHandler(objc_uncaught_exception_handler handler) { - objc_uncaught_exception_handler_t old = uncaughtExceptionHandler; + objc_uncaught_exception_handler old = uncaughtExceptionHandler; uncaughtExceptionHandler = handler; return old; } Index: src/runtime/hashtable.m ================================================================== --- src/runtime/hashtable.m +++ src/runtime/hashtable.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -24,14 +22,14 @@ #include #import "ObjFWRT.h" #import "private.h" -struct objc_hashtable_bucket objc_deleted_bucket; +struct objc_hashtable_bucket objc_deletedBucket; uint32_t -objc_hash_string(const void *str_) +objc_string_hash(const void *str_) { const char *str = str_; uint32_t hash = 0; while (*str != 0) { @@ -47,11 +45,11 @@ return hash; } bool -objc_equal_string(const void *ptr1, const void *ptr2) +objc_string_equal(const void *ptr1, const void *ptr2) { return (strcmp(ptr1, ptr2) == 0); } struct objc_hashtable * @@ -103,11 +101,11 @@ if ((newData = calloc(newSize, sizeof(*newData))) == NULL) OBJC_ERROR("Not enough memory to resize hash table!"); for (uint32_t i = 0; i < table->size; i++) { if (table->data[i] != NULL && - table->data[i] != &objc_deleted_bucket) { + table->data[i] != &objc_deletedBucket) { uint32_t j, last; last = newSize; for (j = table->data[i]->hash & (newSize - 1); @@ -119,11 +117,11 @@ for (j = 0; j < last && newData[j] != NULL; j++); } if (j >= last) - OBJC_ERROR("No free bucket!"); + OBJC_ERROR("No free bucket in hash table!"); newData[j] = table->data[i]; } } @@ -138,11 +136,11 @@ uint32_t i, hash; hash = table->hash(key) & (table->size - 1); for (i = hash; i < table->size && table->data[i] != NULL; i++) { - if (table->data[i] == &objc_deleted_bucket) + if (table->data[i] == &objc_deletedBucket) continue; if (table->equal(table->data[i]->key, key)) { *idx = i; return true; @@ -151,11 +149,11 @@ if (i < table->size) return false; for (i = 0; i < hash && table->data[i] != NULL; i++) { - if (table->data[i] == &objc_deleted_bucket) + if (table->data[i] == &objc_deletedBucket) continue; if (table->equal(table->data[i]->key, key)) { *idx = i; return true; @@ -181,21 +179,21 @@ hash = table->hash(key); last = table->size; for (i = hash & (table->size - 1); i < last && table->data[i] != NULL && - table->data[i] != &objc_deleted_bucket; i++); + table->data[i] != &objc_deletedBucket; i++); if (i >= last) { last = hash & (table->size - 1); for (i = 0; i < last && table->data[i] != NULL && - table->data[i] != &objc_deleted_bucket; i++); + table->data[i] != &objc_deletedBucket; i++); } if (i >= last) - OBJC_ERROR("No free bucket!"); + OBJC_ERROR("No free bucket in hash table!"); if ((bucket = malloc(sizeof(*bucket))) == NULL) OBJC_ERROR("Not enough memory to allocate hash table bucket!"); bucket->key = key; @@ -224,11 +222,11 @@ if (!indexForKey(table, key, &idx)) return; free(table->data[idx]); - table->data[idx] = &objc_deleted_bucket; + table->data[idx] = &objc_deletedBucket; table->count--; resize(table, table->count); } @@ -235,11 +233,11 @@ void objc_hashtable_free(struct objc_hashtable *table) { for (uint32_t i = 0; i < table->size; i++) if (table->data[i] != NULL && - table->data[i] != &objc_deleted_bucket) + table->data[i] != &objc_deletedBucket) free(table->data[i]); free(table->data); free(table); } Index: src/runtime/init.m ================================================================== --- src/runtime/init.m +++ src/runtime/init.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -21,28 +19,28 @@ #import "private.h" void __objc_exec_class(struct objc_module *module) { - objc_global_mutex_lock(); - - objc_register_all_selectors(module->symtab); - objc_register_all_classes(module->symtab); - objc_register_all_categories(module->symtab); - objc_init_static_instances(module->symtab); - - objc_global_mutex_unlock(); + objc_globalMutex_lock(); + + objc_registerAllSelectors(module->symtab); + objc_registerAllClasses(module->symtab); + objc_registerAllCategories(module->symtab); + objc_initStaticInstances(module->symtab); + + objc_globalMutex_unlock(); } void -objc_exit(void) -{ - objc_global_mutex_lock(); - - objc_unregister_all_categories(); - objc_unregister_all_classes(); - objc_unregister_all_selectors(); - objc_forget_pending_static_instances(); +objc_deinit(void) +{ + objc_globalMutex_lock(); + + objc_unregisterAllCategories(); + objc_unregisterAllClasses(); + objc_unregisterAllSelectors(); + objc_forgetPendingStaticInstances(); objc_dtable_cleanup(); - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); } Index: src/runtime/instance.m ================================================================== --- src/runtime/instance.m +++ src/runtime/instance.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -81,11 +79,11 @@ if (object == nil) return NULL; #ifdef OF_OBJFW_RUNTIME - objc_zero_weak_references(object); + objc_zeroWeakReferences(object); #endif if (destructSelector == NULL) destructSelector = sel_registerName(".cxx_destruct"); Index: src/runtime/ivar.m ================================================================== --- src/runtime/ivar.m +++ src/runtime/ivar.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -31,33 +29,33 @@ *outCount = 0; return NULL; } - objc_global_mutex_lock(); + objc_globalMutex_lock(); count = (class->ivars != NULL ? class->ivars->count : 0); if (count == 0) { if (outCount != NULL) *outCount = 0; - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return NULL; } if ((ivars = malloc((count + 1) * sizeof(Ivar))) == NULL) - OBJC_ERROR("Not enough memory to copy ivars"); + OBJC_ERROR("Not enough memory to copy ivars!"); for (unsigned int i = 0; i < count; i++) ivars[i] = &class->ivars->ivars[i]; ivars[count] = NULL; if (outCount != NULL) *outCount = count; - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return ivars; } const char * Index: src/runtime/linklib/Makefile ================================================================== --- src/runtime/linklib/Makefile +++ src/runtime/linklib/Makefile @@ -1,9 +1,10 @@ include ../../../extra.mk STATIC_LIB = libobjfwrt.library.a -SRCS = linklib.m +SRCS = init.m \ + linklib.m include ../../../buildsys.mk CPPFLAGS += -I.. -I../.. -I../../.. \ -DOBJC_COMPILING_AMIGA_LINKLIB \ ADDED src/runtime/linklib/init.m Index: src/runtime/linklib/init.m ================================================================== --- /dev/null +++ src/runtime/linklib/init.m @@ -0,0 +1,188 @@ +/* + * 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 +} Index: src/runtime/linklib/linklib.m ================================================================== --- src/runtime/linklib/linklib.m +++ src/runtime/linklib/linklib.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -13,733 +11,1528 @@ * 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" -#import "macros.h" - -#include - -struct ObjFWRTBase; - -#import "inline.h" - -#include -#include - -#if defined(OF_AMIGAOS_M68K) -# include -# define SYM(name) __asm__("_" name) -#elif defined(OF_MORPHOS) -# include -# define SYM(name) __asm__(name) -#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 -extern void __register_frame_info(const void *, void *); -extern void *__deregister_frame_info(const void *); - -struct Library *ObjFWRTBase; -void *__objc_class_name_Protocol; - -static void __attribute__((__used__)) -ctor(void) -{ - static bool initialized = false; - struct objc_libc libc = { - .malloc = malloc, - .calloc = calloc, - .realloc = realloc, - .free = free, - .vfprintf = vfprintf, - .fflush = fflush, - .abort = abort, -#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 - .__register_frame_info = __register_frame_info, - .__deregister_frame_info = __deregister_frame_info, - }; - - if (initialized) - return; - - if ((ObjFWRTBase = OpenLibrary(OBJFWRT_AMIGA_LIB, - OBJFWRT_LIB_MINOR)) == NULL) { - fputs("Failed to open " OBJFWRT_AMIGA_LIB "!\n", stderr); - abort(); - } - - if (!glue_objc_init(1, &libc, stdout, stderr)) { - fputs("Failed to initialize " OBJFWRT_AMIGA_LIB "!\n", stderr); - abort(); - } - - initialized = true; -} - -static void __attribute__((__used__)) -dtor(void) -{ - CloseLibrary(ObjFWRTBase); -} - -#if defined(OF_AMIGAOS_M68K) -ADD2INIT(ctor, -2); -ADD2EXIT(dtor, -2); -#elif defined(OF_MORPHOS) -CONSTRUCTOR_P(ObjFWRT, 4000) -{ - ctor(); - - return 0; -} - -DESTRUCTOR_P(ObjFWRT, 4000) -{ - dtor(); -} -#endif - -void -__objc_exec_class(struct objc_module *module) -{ - /* - * The compiler generates constructors that call into this, so it is - * possible that we are not set up yet when we get called. - */ - ctor(); - - glue___objc_exec_class(module); -} - -IMP -objc_msg_lookup(id object, SEL selector) -{ - return glue_objc_msg_lookup(object, selector); -} - -IMP -objc_msg_lookup_stret(id object, SEL selector) -{ - return glue_objc_msg_lookup_stret(object, selector); -} - -IMP -objc_msg_lookup_super(struct objc_super *super, SEL selector) -{ - return glue_objc_msg_lookup_super(super, selector); -} - -IMP -objc_msg_lookup_super_stret(struct objc_super *super, SEL selector) -{ - return glue_objc_msg_lookup_super_stret(super, selector); -} - -Class -objc_lookUpClass(const char *name) -{ - return glue_objc_lookUpClass(name); -} - -Class -objc_getClass(const char *name) -{ - return glue_objc_getClass(name); -} - -Class -objc_getRequiredClass(const char *name) -{ - return glue_objc_getRequiredClass(name); -} - -Class -objc_lookup_class(const char *name) -{ - return glue_objc_lookup_class(name); -} - -Class -objc_get_class(const char *name) -{ - return glue_objc_get_class(name); -} - -void -objc_exception_throw(id object) -{ -#ifdef OF_AMIGAOS_M68K - /* - * This does not use the glue code to hack around a compiler bug. - * - * When using the generated inline stubs, the compiler does not emit - * any frame information, making the unwind fail. As unwind always - * starts from objc_exception_throw(), this means exceptions would - * never work. If, however, we're using a function pointer instead of - * the inline stub, the compiler does generate a frame and everything - * works fine. - */ - register void *a6 __asm__("a6") = ObjFWRTBase; - uintptr_t throw = (((uintptr_t)ObjFWRTBase) - 0x60); - ((void (*)(id __asm__("a0")))throw)(object); - (void)a6; -#else - glue_objc_exception_throw(object); + +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 object) -{ - return glue_objc_sync_enter(object); -} - -int -objc_sync_exit(id object) -{ - return glue_objc_sync_exit(object); -} - -id -objc_getProperty(id self, SEL _cmd, ptrdiff_t offset, bool atomic) -{ - return glue_objc_getProperty(self, _cmd, offset, atomic); -} - -void -objc_setProperty(id self, SEL _cmd, ptrdiff_t offset, id value, bool atomic, - signed char copy) -{ - glue_objc_setProperty(self, _cmd, offset, value, atomic, copy); -} - -void -objc_getPropertyStruct(void *dest, const void *src, ptrdiff_t size, bool atomic, - bool strong) -{ - glue_objc_getPropertyStruct(dest, src, size, atomic, strong); -} - -void -objc_setPropertyStruct(void *dest, const void *src, ptrdiff_t size, bool atomic, - bool strong) -{ - glue_objc_setPropertyStruct(dest, src, size, atomic, strong); -} - -void -objc_enumerationMutation(id object) -{ -#ifdef OF_AMIGAOS_M68K - /* - * This does not use the glue code to hack around a compiler bug. - * - * When using the generated inline stubs, the compiler does not emit - * any frame information, making the unwind fail. As a result - * objc_enumerationMutation() might throw an exception that could never - * be caught. If, however, we're using a function pointer instead of - * the inline stub, the compiler does generate a frame and everything - * works fine. - */ - register void *a6 __asm__("a6") = ObjFWRTBase; - uintptr_t enumerationMutation = (((uintptr_t)ObjFWRTBase) - 0x8A); - ((void (*)(id __asm__("a0")))enumerationMutation)(object); - (void)a6; -#else - glue_objc_enumerationMutation(object); -#endif - - OF_UNREACHABLE -} - -#ifdef HAVE_SJLJ_EXCEPTIONS -int -__gnu_objc_personality_sj0(int version, int actions, uint64_t exClass, - void *ex, void *ctx) -{ -# ifdef OF_AMIGAOS_M68K - return glue___gnu_objc_personality(version, actions, &exClass, ex, ctx); -# else - return glue___gnu_objc_personality(version, actions, exClass, ex, ctx); -# endif -} -#else -int -__gnu_objc_personality_v0(int version, int actions, uint64_t exClass, - void *ex, void *ctx) -{ -# ifdef OF_AMIGAOS_M68K - return glue___gnu_objc_personality(version, actions, &exClass, ex, ctx); -# else - return glue___gnu_objc_personality(version, actions, exClass, ex, ctx); -# endif -} -#endif - -id -objc_retain(id object) -{ - return glue_objc_retain(object); -} - -id -objc_retainBlock(id block) -{ - return glue_objc_retainBlock(block); -} - -id -objc_retainAutorelease(id object) -{ - return glue_objc_retainAutorelease(object); -} - -void -objc_release(id object) -{ - glue_objc_release(object); -} - -id -objc_autorelease(id object) -{ - return glue_objc_autorelease(object); -} - -id -objc_autoreleaseReturnValue(id object) -{ - return glue_objc_autoreleaseReturnValue(object); -} - -id -objc_retainAutoreleaseReturnValue(id object) -{ - return glue_objc_retainAutoreleaseReturnValue(object); -} - -id -objc_retainAutoreleasedReturnValue(id object) -{ - return glue_objc_retainAutoreleasedReturnValue(object); -} - -id -objc_storeStrong(id *object, id value) -{ - return glue_objc_storeStrong(object, value); -} - -id -objc_storeWeak(id *object, id value) -{ - return glue_objc_storeWeak(object, value); -} - -id -objc_loadWeakRetained(id *object) -{ - return glue_objc_loadWeakRetained(object); -} - -id -objc_initWeak(id *object, id value) -{ - return glue_objc_initWeak(object, value); -} - -void -objc_destroyWeak(id *object) -{ - glue_objc_destroyWeak(object); -} - -id -objc_loadWeak(id *object) -{ - return glue_objc_loadWeak(object); -} - -void -objc_copyWeak(id *dest, id *src) -{ - glue_objc_copyWeak(dest, src); -} - -void -objc_moveWeak(id *dest, id *src) -{ - glue_objc_moveWeak(dest, src); -} - -SEL -sel_registerName(const char *name) -{ - return glue_sel_registerName(name); -} - -const char * -sel_getName(SEL selector) -{ - return glue_sel_getName(selector); -} - -bool -sel_isEqual(SEL selector1, SEL selector2) -{ - return glue_sel_isEqual(selector1, selector2); -} - -Class -objc_allocateClassPair(Class superclass, const char *name, size_t extraBytes) -{ - return glue_objc_allocateClassPair(superclass, name, extraBytes); -} - -void -objc_registerClassPair(Class class) -{ - glue_objc_registerClassPair(class); +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 *buffer, unsigned int count) +objc_getClassList(Class _Nonnull *_Nullable buffer, unsigned int count) { - return glue_objc_getClassList(buffer, 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 * -objc_copyClassList(unsigned int *length) +Class _Nonnull *_Nonnull +objc_copyClassList(unsigned int *_Nullable length) { - return glue_objc_copyClassList(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 class) -{ - return glue_class_isMetaClass(class); -} - -const char * -class_getName(Class class) -{ - return glue_class_getName(class); -} - -Class -class_getSuperclass(Class class) -{ - return glue_class_getSuperclass(class); +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 class) -{ - return glue_class_getInstanceSize(class); -} - -bool -class_respondsToSelector(Class class, SEL selector) -{ - return glue_class_respondsToSelector(class, selector); -} - -bool -class_conformsToProtocol(Class class, Protocol *protocol) -{ - return glue_class_conformsToProtocol(class, protocol); -} - -IMP -class_getMethodImplementation(Class class, SEL selector) -{ - return glue_class_getMethodImplementation(class, selector); -} - -IMP -class_getMethodImplementation_stret(Class class, SEL selector) -{ - return glue_class_getMethodImplementation_stret(class, selector); -} - -Method -class_getInstanceMethod(Class class, SEL selector) -{ - return glue_class_getInstanceMethod(class, selector); -} - -bool -class_addMethod(Class class, SEL selector, IMP implementation, - const char *typeEncoding) -{ - return glue_class_addMethod(class, selector, implementation, - typeEncoding); -} - -IMP -class_replaceMethod(Class class, SEL selector, IMP implementation, - const char *typeEncoding) -{ - return glue_class_replaceMethod(class, selector, implementation, - typeEncoding); -} - -Class -object_getClass(id object) -{ - return glue_object_getClass(object); -} - -Class -object_setClass(id object, Class class) -{ - return glue_object_setClass(object, class); -} - -const char * -object_getClassName(id object) -{ - return glue_object_getClassName(object); -} - -const char * -protocol_getName(Protocol *protocol) -{ - return glue_protocol_getName(protocol); -} - -bool -protocol_isEqual(Protocol *protocol1, Protocol *protocol2) -{ - return glue_protocol_isEqual(protocol1, protocol2); -} - -bool -protocol_conformsToProtocol(Protocol *protocol1, Protocol *protocol2) -{ - return glue_protocol_conformsToProtocol(protocol1, protocol2); -} - -objc_uncaught_exception_handler_t -objc_setUncaughtExceptionHandler(objc_uncaught_exception_handler_t handler) -{ - return glue_objc_setUncaughtExceptionHandler(handler); -} - -void -objc_setForwardHandler(IMP forward, IMP stretForward) -{ - glue_objc_setForwardHandler(forward, stretForward); -} - -void -objc_setEnumerationMutationHandler(objc_enumeration_mutation_handler_t handler) -{ - glue_objc_setEnumerationMutationHandler(handler); -} - -id -objc_constructInstance(Class class, void *_Nullable bytes) -{ - return glue_objc_constructInstance(class, bytes); -} - -void -objc_exit(void) -{ - glue_objc_exit(); -} - -Ivar * -class_copyIvarList(Class class, unsigned int *outCount) -{ - return glue_class_copyIvarList(class, outCount); -} - -const char * -ivar_getName(Ivar ivar) -{ - return glue_ivar_getName(ivar); -} - -const char * -ivar_getTypeEncoding(Ivar ivar) -{ - return glue_ivar_getTypeEncoding(ivar); -} - -ptrdiff_t -ivar_getOffset(Ivar ivar) -{ - return glue_ivar_getOffset(ivar); -} - -Method * -class_copyMethodList(Class class, unsigned int *outCount) -{ - return glue_class_copyMethodList(class, outCount); -} - -SEL -method_getName(Method method) -{ - return glue_method_getName(method); -} - -const char * -method_getTypeEncoding(Method method) -{ - return glue_method_getTypeEncoding(method); -} - -objc_property_t * -class_copyPropertyList(Class class, unsigned int *outCount) -{ - return glue_class_copyPropertyList(class, outCount); -} - -const char * -property_getName(objc_property_t property) -{ - return glue_property_getName(property); -} - -char * -property_copyAttributeValue(objc_property_t property, const char *name) -{ - return glue_property_copyAttributeValue(property, name); -} - -void * -objc_destructInstance(id object) -{ - return glue_objc_destructInstance(object); -} - -void * -objc_autoreleasePoolPush(void) -{ - return glue_objc_autoreleasePoolPush(); -} - -void -objc_autoreleasePoolPop(void *pool) -{ - glue_objc_autoreleasePoolPop(pool); -} - -id -_objc_rootAutorelease(id object) -{ - return glue__objc_rootAutorelease(object); -} - -struct objc_hashtable * -objc_hashtable_new(objc_hashtable_hash_func hash, - objc_hashtable_equal_func equal, uint32_t size) -{ - return glue_objc_hashtable_new(hash, equal, size); -} - -void -objc_hashtable_set(struct objc_hashtable *table, const void *key, - const void *object) -{ - glue_objc_hashtable_set(table, key, object); -} - -void * -objc_hashtable_get(struct objc_hashtable *table, const void *key) -{ - return glue_objc_hashtable_get(table, key); -} - -void -objc_hashtable_delete(struct objc_hashtable *table, const void *key) -{ - glue_objc_hashtable_delete(table, key); -} - -void -objc_hashtable_free(struct objc_hashtable *table) -{ - glue_objc_hashtable_free(table); +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) { - glue_objc_setTaggedPointerSecret(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 class) +objc_registerTaggedPointerClass(Class _Nonnull class) { - return glue_objc_registerTaggedPointerClass(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 object) -{ - return glue_object_isTaggedPointer(object); -} - -Class -object_getTaggedPointerClass(id object) -{ - return glue_object_getTaggedPointerClass(object); +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 object) +object_getTaggedPointerValue(id _Nonnull object) { - return glue_object_getTaggedPointerValue(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 +id _Nullable objc_createTaggedPointer(int class, uintptr_t value) { - return objc_createTaggedPointer(class, 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,10 +1,12 @@ 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 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,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -23,17 +21,17 @@ .globl objc_msg_lookup_stret .globl objc_msg_lookup_super .globl objc_msg_lookup_super_stret .section .text -.macro generate_lookup name not_found +.macro GENERATE_LOOKUP name notFound \name: cmp r0, #0 - beq ret_nil + beq returnNilMethod tst r0, #1 - bne .Ltagged_pointer_\name + bne .LtaggedPointer_\name ldr r2, [r0, #0] ldr r2, [r2, #32] .Lmain_\name: @@ -56,67 +54,67 @@ ldrb r3, [r1, #3] ldr r2, [r2, r3, lsl #2] #endif cmp r2, #0 - beq \not_found(PLT) + beq \notFound(PLT) mov r0, r2 bx lr -.Ltagged_pointer_\name: - ldr r2, .Lgot$indirect_.Ltagged_pointer_\name +.LtaggedPointer_\name: + ldr r2, .Lgot$indirect_.LtaggedPointer_\name add r2, pc, r2 - ldr r3, .Lgot$indirect_.Ltagged_pointer_\name+4 + ldr r3, .Lgot$indirect_.LtaggedPointer_\name+4 ldr r3, [r2, r3] ldr r3, [r3] eor r0, r0, r3 and r0, r0, #0xE lsl r0, r0, #1 - ldr r3, .Lgot$indirect_.Ltagged_pointer_\name+8 + ldr r3, .Lgot$indirect_.LtaggedPointer_\name+8 ldr r3, [r2, r3] ldr r2, [r3, r0] ldr r2, [r2, #32] b .Lmain_\name .type \name, %function .size \name, .-\name -.Lgot$indirect_.Ltagged_pointer_\name: - .long _GLOBAL_OFFSET_TABLE_-(.Ltagged_pointer_\name+12) - .long objc_tagged_pointer_secret(GOT) - .long objc_tagged_pointer_classes(GOT) +.Lgot$indirect_.LtaggedPointer_\name: + .long _GLOBAL_OFFSET_TABLE_-(.LtaggedPointer_\name+12) + .long objc_taggedPointerSecret(GOT) + .long objc_taggedPointerClasses(GOT) .endm -.macro generate_lookup_super name lookup +.macro GENERATE_LOOKUP_SUPER name lookup \name: mov r2, r0 ldr r0, [r0, #0] cmp r0, #0 - beq ret_nil + beq returnNilMethod ldr r2, [r2, #4] ldr r2, [r2, #32] b .Lmain_\lookup .type \name, %function .size \name, .-\name .endm -generate_lookup objc_msg_lookup objc_method_not_found -generate_lookup objc_msg_lookup_stret objc_method_not_found_stret -generate_lookup_super objc_msg_lookup_super objc_msg_lookup -generate_lookup_super objc_msg_lookup_super_stret objc_msg_lookup_stret +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 -ret_nil: - adr r0, nil_method +returnNilMethod: + adr r0, nilMethod bx lr -nil_method: +nilMethod: mov r0, #0 bx lr #ifdef OF_LINUX .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,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -23,16 +21,16 @@ .globl objc_msg_lookup_stret .globl objc_msg_lookup_super .globl objc_msg_lookup_super_stret .section .text -.macro generate_lookup name not_found +.macro GENERATE_LOOKUP name notFound \name: - cbz x0, ret_nil + cbz x0, returnNilMethod tst x0, #1 - b.ne .Ltagged_pointer_\name + b.ne .LtaggedPointer_\name ldr x2, [x0] ldr x2, [x2, #64] .Lmain_\name: @@ -43,58 +41,58 @@ ldrb w3, [x1, #1] ldr x2, [x2, x3, lsl #3] ldrb w3, [x1] ldr x2, [x2, x3, lsl #3] - cbz x2, \not_found + cbz x2, \notFound mov x0, x2 ret -.Ltagged_pointer_\name: - adrp x2, :got:objc_tagged_pointer_secret - ldr x2, [x2, #:got_lo12:objc_tagged_pointer_secret] +.LtaggedPointer_\name: + adrp x2, :got:objc_taggedPointerSecret + ldr x2, [x2, #:got_lo12:objc_taggedPointerSecret] ldr x2, [x2] eor x0, x0, x2 and x0, x0, #0xE lsl x0, x0, #2 - adrp x2, :got:objc_tagged_pointer_classes - ldr x2, [x2, #:got_lo12:objc_tagged_pointer_classes] + adrp x2, :got:objc_taggedPointerClasses + ldr x2, [x2, #:got_lo12:objc_taggedPointerClasses] ldr x2, [x2, x0] ldr x2, [x2, #64] b .Lmain_\name .type \name, %function .size \name, .-\name .endm -.macro generate_lookup_super name lookup +.macro GENERATE_LOOKUP_SUPER name lookup \name: mov x2, x0 ldr x0, [x0] - cbz x0, ret_nil + cbz x0, returnNilMethod ldr x2, [x2, #8] ldr x2, [x2, #64] b .Lmain_\lookup .type \name, %function .size \name, .-\name .endm -generate_lookup objc_msg_lookup objc_method_not_found -generate_lookup objc_msg_lookup_stret objc_method_not_found_stret -generate_lookup_super objc_msg_lookup_super objc_msg_lookup -generate_lookup_super objc_msg_lookup_super_stret objc_msg_lookup_stret +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 -ret_nil: - adr x0, nil_method +returnNilMethod: + adr x0, nilMethod ret -nil_method: +nilMethod: mov x0, #0 ret #ifdef OF_LINUX .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,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -23,16 +21,16 @@ .globl objc_msg_lookup_stret .globl objc_msg_lookup_super .globl objc_msg_lookup_super_stret .section .text -.macro generate_lookup name not_found +.macro GENERATE_LOOKUP name notFound \name: beqz $a0, 0f andi $t0, $a0, 1 - bnez $t0, .Ltagged_pointer_\name + bnez $t0, .LtaggedPointer_\name lw $t0, 0($a0) lw $t0, 32($t0) .Lmain_\name: @@ -66,21 +64,21 @@ lw $t0, 0($t0) #ifdef OF_PIC beqz $t0, 1f #else - beqz $t0, \not_found + beqz $t0, \notFound #endif move $v0, $t0 jr $ra 0: #ifdef OF_PIC - addiu $v0, $t9, nil_method-\name + addiu $v0, $t9, nilMethod-\name #else - la $v0, nil_method + la $v0, nilMethod #endif jr $ra #ifdef OF_PIC 1: @@ -87,35 +85,35 @@ lui $gp, %hi(_gp_disp) addiu $gp, $gp, %lo(_gp_disp) addu $gp, $gp, $t9 addiu $gp, $gp, 1b-\name - lw $t9, %call16(\not_found)($gp) + lw $t9, %call16(\notFound)($gp) jr $t9 #endif -.Ltagged_pointer_\name: +.LtaggedPointer_\name: #ifdef OF_PIC 0: lui $gp, %hi(_gp_disp) addiu $gp, $gp, %lo(_gp_disp) addu $gp, $gp, $t9 addiu $gp, $gp, 0b-\name - lw $t0, %got(objc_tagged_pointer_secret)($gp) + lw $t0, %got(objc_taggedPointerSecret)($gp) #else - la $t0, objc_tagged_pointer_secret + la $t0, objc_taggedPointerSecret #endif lw $t0, 0($t0) xor $t0, $a0, $t0 and $t0, $t0, 0xE sll $t0, $t0, 1 #ifdef OF_PIC - lw $t1, %got(objc_tagged_pointer_classes)($gp) + lw $t1, %got(objc_taggedPointerClasses)($gp) #else - la $t1, objc_tagged_pointer_classes + la $t1, objc_taggedPointerClasses #endif addu $t0, $t1, $t0 ld $t0, ($t0) ld $t0, 32($t0) @@ -122,11 +120,11 @@ b .Lmain_\name .type \name, %function .size \name, .-\name .endm -.macro generate_lookup_super name lookup +.macro GENERATE_LOOKUP_SUPER name lookup \name: move $t0, $a0 lw $a0, 0($a0) beqz $a0, 0f @@ -136,26 +134,26 @@ addiu $t9, $t9, \lookup-\name b .Lmain_\lookup 0: #ifdef OF_PIC - addiu $v0, $t9, nil_method-\name + addiu $v0, $t9, nilMethod-\name #else - la $v0, nil_method + la $v0, nilMethod #endif jr $ra .type \name, %function .size \name, .-\name .endm -generate_lookup objc_msg_lookup objc_method_not_found -generate_lookup objc_msg_lookup_stret objc_method_not_found_stret -generate_lookup_super objc_msg_lookup_super objc_msg_lookup -generate_lookup_super objc_msg_lookup_super_stret objc_msg_lookup_stret +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 -nil_method: +nilMethod: move $v0, $zero jr $ra #ifdef OF_LINUX .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,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -23,16 +21,16 @@ .globl objc_msg_lookup_stret .globl objc_msg_lookup_super .globl objc_msg_lookup_super_stret .section .text -.macro generate_lookup name not_found +.macro GENERATE_LOOKUP name notFound \name: beqz $a0, 0f andi $t0, $a0, 1 - bnez $t0, .Ltagged_pointer_\name + bnez $t0, .LtaggedPointer_\name ld $t0, ($a0) ld $t0, 64($t0) .Lmain_\name: @@ -72,42 +70,42 @@ 0: lui $v0, %hi(%neg(%gp_rel(\name))) daddiu $v0, $v0, %lo(%neg(%gp_rel(\name))) daddu $v0, $v0, $t9 - ld $v0, %got_disp(nil_method)($v0) + ld $v0, %got_disp(nilMethod)($v0) jr $ra 1: lui $t0, %hi(%neg(%gp_rel(\name))) daddiu $t0, $t0, %lo(%neg(%gp_rel(\name))) daddu $t0, $t0, $t9 - ld $t9, %got_disp(\not_found)($t0) + ld $t9, %got_disp(\notFound)($t0) jr $t9 -.Ltagged_pointer_\name: +.LtaggedPointer_\name: lui $t0, %hi(%neg(%gp_rel(\name))) daddiu $t0, $t0, %lo(%neg(%gp_rel(\name))) daddu $t0, $t0, $t9 - ld $t1, %got_disp(objc_tagged_pointer_secret)($t0) + ld $t1, %got_disp(objc_taggedPointerSecret)($t0) ld $t1, 0($t1) xor $t1, $a0, $t1 and $t1, $t1, 0xE dsll $t1, $t1, 2 - ld $t0, %got_disp(objc_tagged_pointer_classes)($t0) + ld $t0, %got_disp(objc_taggedPointerClasses)($t0) daddu $t0, $t0, $t1 ld $t0, ($t0) ld $t0, 64($t0) b .Lmain_\name .type \name, %function .size \name, .-\name .endm -.macro generate_lookup_super name lookup +.macro GENERATE_LOOKUP_SUPER name lookup \name: move $t0, $a0 ld $a0, ($a0) beqz $a0, 0f @@ -119,23 +117,23 @@ 0: lui $v0, %hi(%neg(%gp_rel(\name))) daddiu $v0, $v0, %lo(%neg(%gp_rel(\name))) daddu $v0, $v0, $t9 - ld $v0, %got_disp(nil_method)($v0) + ld $v0, %got_disp(nilMethod)($v0) jr $ra .type \name, %function .size \name, .-\name .endm -generate_lookup objc_msg_lookup objc_method_not_found -generate_lookup objc_msg_lookup_stret objc_method_not_found_stret -generate_lookup_super objc_msg_lookup_super objc_msg_lookup -generate_lookup_super objc_msg_lookup_super_stret objc_msg_lookup_stret +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 -nil_method: +nilMethod: move $v0, $zero jr $ra #ifdef OF_LINUX .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,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -23,17 +21,17 @@ .globl objc_msg_lookup_stret .globl objc_msg_lookup_super .globl objc_msg_lookup_super_stret .section .text -.macro generate_lookup name not_found +.macro GENERATE_LOOKUP name notFound \name: cmpwi %r3, 0 - beq- ret_nil + beq- returnNilMethod andi. %r0, %r3, 1 - bne- .Ltagged_pointer_\name + bne- .LtaggedPointer_\name lwz %r5, 0(%r3) lwz %r5, 32(%r5) .Lmain_\name: @@ -55,10 +53,11 @@ mr %r3, %r5 blr 0: +#ifdef OF_PIC stwu %r1, -16(%r1) mflr %r0 stw %r0, 20(%r1) stw %r30, 8(%r1) @@ -66,88 +65,109 @@ 0: mflr %r30 addis %r30, %r30, .Lbiased_got2-0b@ha addi %r30, %r30, .Lbiased_got2-0b@l - lwz %r0, .Lgot_\not_found-.Lbiased_got2(%r30) + lwz %r0, .Lgot_\notFound-.Lbiased_got2(%r30) mtctr %r0 lwz %r30, 8(%r1) lwz %r0, 20(%r1) addi %r1, %r1, 16 mtlr %r0 bctr +#else + b \notFound +#endif -.Ltagged_pointer_\name: +.LtaggedPointer_\name: +#if defined(OF_PIC) mflr %r7 bl 0f 0: mflr %r6 mtlr %r7 addis %r6, %r6, .Lbiased_got2-0b@ha addi %r6, %r6, .Lbiased_got2-0b@l - lwz %r5, .Lgot_objc_tagged_pointer_secret-.Lbiased_got2(%r6) + lwz %r5, .Lgot_objc_taggedPointerSecret-.Lbiased_got2(%r6) lwz %r5, 0(%r5) +#elif defined(OF_BASEREL) + addis %r5, %r13, objc_taggedPointerSecret@drel@ha + lwz %r5, objc_taggedPointerSecret@drel@l(%r5) +#else + lis %r5, objc_taggedPointerSecret@ha + lwz %r5, objc_taggedPointerSecret@l(%r5) +#endif xor %r5, %r3, %r5 rlwinm %r5, %r5, 1, 0x1C - lwz %r6, .Lgot_objc_tagged_pointer_classes-.Lbiased_got2(%r6) +#if defined(OF_PIC) + lwz %r6, .Lgot_objc_taggedPointerClasses-.Lbiased_got2(%r6) +#elif defined(OF_BASEREL) + addis %r6, %r13, objc_taggedPointerClasses@drel@ha + addi %r6, %r6, objc_taggedPointerClasses@drel@l +#else + lis %r6, objc_taggedPointerClasses@ha + addi %r6, %r6, objc_taggedPointerClasses@l +#endif lwzx %r5, %r6, %r5 lwz %r5, 32(%r5) b .Lmain_\name .type \name, @function .size \name, .-\name .endm -.macro generate_lookup_super name lookup +.macro GENERATE_LOOKUP_SUPER name lookup \name: mr %r5, %r3 lwz %r3, 0(%r3) cmpwi %r3, 0 - beq- ret_nil + beq- returnNilMethod lwz %r5, 4(%r5) lwz %r5, 32(%r5) b .Lmain_\lookup .type \name, @function .size \name, .-\name .endm -generate_lookup objc_msg_lookup objc_method_not_found -generate_lookup objc_msg_lookup_stret objc_method_not_found_stret -generate_lookup_super objc_msg_lookup_super objc_msg_lookup -generate_lookup_super objc_msg_lookup_super_stret objc_msg_lookup_stret - -ret_nil: - mflr %r0 - bl get_pc +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: + mflr %r0 + bl getPC mtlr %r0 0: - addi %r3, %r3, nil_method-0b + addi %r3, %r3, nilMethod-0b blr -nil_method: +nilMethod: li %r3, 0 blr -get_pc: +getPC: mflr %r3 blr +#ifdef OF_PIC .section .got2, "aw" .Lbiased_got2 = .+0x8000 -.Lgot_objc_method_not_found: - .long objc_method_not_found -.Lgot_objc_method_not_found_stret: - .long objc_method_not_found_stret -.Lgot_objc_tagged_pointer_secret: - .long objc_tagged_pointer_secret -.Lgot_objc_tagged_pointer_classes: - .long objc_tagged_pointer_classes +.Lgot_objc_methodNotFound: + .long objc_methodNotFound +.Lgot_objc_methodNotFound_stret: + .long objc_methodNotFound_stret +.Lgot_objc_taggedPointerSecret: + .long objc_taggedPointerSecret +.Lgot_objc_taggedPointerClasses: + .long objc_taggedPointerClasses +#endif #ifdef OF_LINUX .section .note.GNU-stack, "", @progbits #endif ADDED src/runtime/lookup-asm/lookup-asm-powerpc64-elf.S Index: src/runtime/lookup-asm/lookup-asm-powerpc64-elf.S ================================================================== --- /dev/null +++ src/runtime/lookup-asm/lookup-asm-powerpc64-elf.S @@ -0,0 +1,163 @@ +/* + * 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" + +#if defined(_CALL_ELF) && _CALL_ELF == 2 +.abiversion 2 +#endif + +.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 +#if defined(_CALL_ELF) && _CALL_ELF == 2 +\name: + addis %r2, %r12, .TOC.-\name@ha + addi %r2, %r2, .TOC.-\name@l +.localentry \name, .-\name +#else +.section .opd, "aw", @progbits +\name: + .p2align 3 + .quad .Lbegin_\name + .quad .TOC.@tocbase + .quad 0 +.section .text +#endif +.Lbegin_\name: + cmpdi %r3, 0 + beq- .LreturnNilMethod + + andi. %r0, %r3, 1 + bne- .LtaggedPointer_\name + + ld %r5, 0(%r3) + ld %r5, 64(%r5) + +.Lmain_\name: + ld %r8, 0(%r4) +#ifdef OF_SELUID24 + rlwinm %r6, %r8, 19, 0x7F8 +#endif + rlwinm %r7, %r8, 27, 0x7F8 + rlwinm %r8, %r8, 3, 0x7F8 + +#ifdef OF_SELUID24 + ldx %r5, %r5, %r6 +#endif + ldx %r5, %r5, %r7 + ldx %r5, %r5, %r8 + + cmpdi %r5, 0 + beq- 0f + + mr %r3, %r5 + blr + +0: + mflr %r0 + std %r0, 16(%r1) + stdu %r1, -112(%r1) + bl \notFound + nop + addi %r1, %r1, 112 + ld %r0, 16(%r1) + mtlr %r0 + blr + +.LtaggedPointer_\name: + addis %r5, %r2, objc_taggedPointerSecret@toc@ha + ld %r5, objc_taggedPointerSecret@toc@l(%r5) + xor %r5, %r3, %r5 + rlwinm %r5, %r5, 2, 0x38 + + addis %r6, %r2, objc_taggedPointerClasses@toc@ha + addi %r6, %r6, objc_taggedPointerClasses@toc@l + ldx %r5, %r6, %r5 + ld %r5, 64(%r5) + + b .Lmain_\name +.type \name, @function +.size \name, .-.Lbegin_\name +.endm + +.macro GENERATE_LOOKUP_SUPER name lookup +#if defined(_CALL_ELF) && _CALL_ELF == 2 +\name: + addis %r2, %r12, .TOC.-\name@ha + addi %r2, %r2, .TOC.-\name@l +.localentry \name, .-\name +#else +.section .opd, "aw", @progbits +\name: + .p2align 3 + .quad .Lbegin_\name + .quad .TOC.@tocbase + .quad 0 +.section .text +#endif +.Lbegin_\name: + mr %r5, %r3 + ld %r3, 0(%r3) + cmpdi %r3, 0 + beq- .LreturnNilMethod + + ld %r5, 8(%r5) + ld %r5, 64(%r5) + + b .Lmain_\lookup +.type \name, @function +.size \name, .-.Lbegin_\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 + +.LreturnNilMethod: + addis %r3, %r2, nilMethod@toc@ha + addi %r3, %r3, nilMethod@toc@l + blr + +#if defined(_CALL_ELF) && _CALL_ELF == 2 +nilMethod: + addis %r2, %r12, .TOC.-nilMethod@ha + addi %r2, %r2, .TOC.-nilMethod@l +.localentry nilMethod, .-nilMethod +#else +.section .opd, "aw", @progbits +nilMethod: + .p2align 3 + .quad .Lbegin_nilMethod + .quad .TOC.@tocbase + .quad 0 +.section .text +#endif +.Lbegin_nilMethod: + li %r3, 0 + blr +.type nilMethod, @function +.size nilMethod, .-.Lbegin_nilMethod + +#ifdef OF_LINUX +.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,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -23,16 +21,16 @@ .globl objc_msg_lookup_stret .globl objc_msg_lookup_super .globl objc_msg_lookup_super_stret .section .text -.macro generate_lookup name not_found +.macro GENERATE_LOOKUP name notFound \name: tst %o0 - bz ret_nil + bz returnNilMethod btst 1, %o0 - bnz .Ltagged_pointer_\name + bnz .LtaggedPointer_\name nop ld [%o0], %o2 ld [%o2 + 32], %o2 @@ -62,14 +60,14 @@ retl mov %o2, %o0 0: mov %o7, %g1 - call \not_found + call \notFound mov %g1, %o7 -.Ltagged_pointer_\name: +.LtaggedPointer_\name: #ifdef OF_PIC mov %o7, %g1 sethi %hi(_GLOBAL_OFFSET_TABLE_ - 4), %o3 call 0f or %o3, %lo(_GLOBAL_OFFSET_TABLE_ + 4), %o3 @@ -76,22 +74,22 @@ 0: add %o7, %o3, %o3 mov %g1, %o7 #endif - sethi %hi(objc_tagged_pointer_secret), %o2 - or %o2, %lo(objc_tagged_pointer_secret), %o2 + sethi %hi(objc_taggedPointerSecret), %o2 + or %o2, %lo(objc_taggedPointerSecret), %o2 #ifdef OF_PIC ld [%o3 + %o2], %o2 #endif ld [%o2], %o2 xor %o0, %o2, %o0 and %o0, 0xE, %o0 sll %o0, 1, %o0 - sethi %hi(objc_tagged_pointer_classes), %o2 - or %o2, %lo(objc_tagged_pointer_classes), %o2 + sethi %hi(objc_taggedPointerClasses), %o2 + or %o2, %lo(objc_taggedPointerClasses), %o2 #ifdef OF_PIC ld [%o3 + %o2], %o2 #endif ld [%o2 + %o0], %o2 @@ -99,53 +97,53 @@ ld [%o2 + 32], %o2 .type \name, %function .size \name, .-\name .endm -.macro generate_lookup_super name lookup +.macro GENERATE_LOOKUP_SUPER name lookup \name: mov %o0, %o2 ld [%o0], %o0 cmp %o0, 0 - be ret_nil + be returnNilMethod nop ld [%o2 + 4], %o2 ba .Lmain_\lookup ld [%o2 + 32], %o2 .type \name, %function .size \name, .-\name .endm -generate_lookup objc_msg_lookup objc_method_not_found -generate_lookup objc_msg_lookup_stret objc_method_not_found_stret -generate_lookup_super objc_msg_lookup_super objc_msg_lookup -generate_lookup_super objc_msg_lookup_super_stret objc_msg_lookup_stret +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 -ret_nil: +returnNilMethod: #ifdef OF_PIC mov %o7, %g1 sethi %hi(_GLOBAL_OFFSET_TABLE_ - 4), %o1 call 0f add %o1, %lo(_GLOBAL_OFFSET_TABLE_ + 4), %o1 0: add %o7, %o1, %o1 - sethi %hi(nil_method), %o0 - or %o0, %lo(nil_method), %o0 + sethi %hi(nilMethod), %o0 + or %o0, %lo(nilMethod), %o0 jmpl %g1 + 8, %g0 ld [%o1 + %o0], %o0 #else - sethi %hi(nil_method), %o0 + sethi %hi(nilMethod), %o0 retl - or %o0, %lo(nil_method), %o0 + or %o0, %lo(nilMethod), %o0 #endif -nil_method: +nilMethod: retl clr %o0 #ifdef OF_LINUX .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,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -23,15 +21,15 @@ .globl objc_msg_lookup_stret .globl objc_msg_lookup_super .globl objc_msg_lookup_super_stret .section .text -.macro generate_lookup name not_found +.macro GENERATE_LOOKUP name notFound \name: - brz,pn %o0, ret_nil + brz,pn %o0, returnNilMethod and %o0, 1, %o2 - brnz,pn %o2, .Ltagged_pointer_\name + brnz,pn %o2, .LtaggedPointer_\name nop ldx [%o0], %o2 ldx [%o2 + 64], %o2 @@ -60,14 +58,14 @@ retl mov %o2, %o0 0: mov %o7, %g1 - call \not_found + call \notFound mov %g1, %o7 -.Ltagged_pointer_\name: +.LtaggedPointer_\name: #ifdef OF_PIC mov %o7, %g1 sethi %hi(_GLOBAL_OFFSET_TABLE_ - 4), %o3 call 0f or %o3, %lo(_GLOBAL_OFFSET_TABLE_ + 4), %o3 @@ -74,22 +72,22 @@ 0: add %o7, %o3, %o3 mov %g1, %o7 #endif - sethi %hi(objc_tagged_pointer_secret), %o2 - or %o2, %lo(objc_tagged_pointer_secret), %o2 + sethi %hi(objc_taggedPointerSecret), %o2 + or %o2, %lo(objc_taggedPointerSecret), %o2 #ifdef OF_PIC ldx [%o3 + %o2], %o2 #endif ldx [%o2], %o2 xor %o0, %o2, %o0 and %o0, 0xE, %o0 sll %o0, 2, %o0 - sethi %hi(objc_tagged_pointer_classes), %o2 - or %o2, %lo(objc_tagged_pointer_classes), %o2 + sethi %hi(objc_taggedPointerClasses), %o2 + or %o2, %lo(objc_taggedPointerClasses), %o2 #ifdef OF_PIC ldx [%o3 + %o2], %o2 #endif ldx [%o2 + %o0], %o2 @@ -97,52 +95,52 @@ ldx [%o2 + 64], %o2 .type \name, %function .size \name, .-\name .endm -.macro generate_lookup_super name lookup +.macro GENERATE_LOOKUP_SUPER name lookup \name: mov %o0, %o2 ldx [%o0], %o0 - brz,pn %o0, ret_nil + brz,pn %o0, returnNilMethod nop ldx [%o2 + 8], %o2 ba .Lmain_\lookup ldx [%o2 + 64], %o2 .type \name, %function .size \name, .-\name .endm -generate_lookup objc_msg_lookup objc_method_not_found -generate_lookup objc_msg_lookup_stret objc_method_not_found_stret -generate_lookup_super objc_msg_lookup_super objc_msg_lookup -generate_lookup_super objc_msg_lookup_super_stret objc_msg_lookup_stret +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 -ret_nil: +returnNilMethod: #ifdef OF_PIC mov %o7, %g1 sethi %hi(_GLOBAL_OFFSET_TABLE_ - 4), %o1 call 0f or %o1, %lo(_GLOBAL_OFFSET_TABLE_ + 4), %o1 0: add %o7, %o1, %o1 - sethi %hi(nil_method), %o0 - or %o0, %lo(nil_method), %o0 + sethi %hi(nilMethod), %o0 + or %o0, %lo(nilMethod), %o0 jmpl %g1 + 8, %g0 ldx [%o1 + %o0], %o0 #else - sethi %hi(nil_method), %o0 + sethi %hi(nilMethod), %o0 retl - or %o0, %lo(nil_method), %o0 + or %o0, %lo(nilMethod), %o0 #endif -nil_method: +nilMethod: retl clr %o0 #ifdef OF_LINUX .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,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -17,103 +15,101 @@ #include "config.h" #include "platform.h" -.intel_syntax noprefix - .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 not_found +.macro GENERATE_LOOKUP name notFound \name: - mov edx, [esp+4] - test edx, edx - jz short ret_nil - - bt edx, 0 - jc short .Ltagged_pointer_\name - - mov edx, [edx] - mov edx, [edx+32] + movl 4(%esp), %edx + testl %edx, %edx + jz returnNilMethod + + testb $1, %dl + jnz .LtaggedPointer_\name + + movl (%edx), %edx + movl 32(%edx), %edx .Lmain_\name: - mov eax, [esp+8] + movl 8(%esp), %eax #ifdef OF_SELUID24 - movzx ecx, byte ptr [eax+2] - mov edx, [edx+ecx*4] + movzbl 2(%eax), %ecx + movl (%edx,%ecx,4), %edx #endif - movzx ecx, byte ptr [eax+1] - mov edx, [edx+ecx*4] - movzx ecx, byte ptr [eax] - mov eax, [edx+ecx*4] + movzbl 1(%eax), %ecx + movl (%edx,%ecx,4), %edx + movzbl (%eax), %ecx + movl (%edx,%ecx,4), %eax - test eax, eax - jz short 0f + testl %eax, %eax + jz 0f ret 0: - call get_eip - add eax, offset _GLOBAL_OFFSET_TABLE_ - lea eax, [eax+\not_found@GOTOFF] - jmp eax - -.Ltagged_pointer_\name: - call get_eip - add eax, offset _GLOBAL_OFFSET_TABLE_ - - lea ecx, [eax+objc_tagged_pointer_secret@GOTOFF] - xor edx, [ecx] - and dl, 0xE - movzx edx, dl - - lea eax, [eax+objc_tagged_pointer_classes@GOTOFF] - mov edx, [eax+edx*2] - mov edx, [edx+32] - - jmp short .Lmain_\name -.type \name, %function -.size \name, .-\name -.endm - -.macro generate_lookup_super name lookup -\name: - mov edx, [esp+4] - mov eax, [edx] - test eax, eax - jz short ret_nil - - mov [esp+4], eax - mov edx, [edx+4] - mov edx, [edx+32] - jmp short .Lmain_\lookup -.type \name, %function -.size \name, .-\name -.endm - -generate_lookup objc_msg_lookup objc_method_not_found -generate_lookup objc_msg_lookup_stret objc_method_not_found_stret -generate_lookup_super objc_msg_lookup_super objc_msg_lookup -generate_lookup_super objc_msg_lookup_super_stret objc_msg_lookup_stret - -ret_nil: - call get_eip - add eax, offset _GLOBAL_OFFSET_TABLE_ - lea eax, [eax+nil_method@GOTOFF] - ret - -nil_method: - xor eax, eax - ret - -get_eip: - mov eax, [esp] + call getEIP + addl $_GLOBAL_OFFSET_TABLE_, %eax + lea \notFound@GOTOFF(%eax), %eax + jmp *%eax + +.LtaggedPointer_\name: + call getEIP + addl $_GLOBAL_OFFSET_TABLE_, %eax + + leal objc_taggedPointerSecret@GOTOFF(%eax), %ecx + xorl (%ecx), %edx + andb $0xE, %dl + movzbl %dl, %edx + + leal objc_taggedPointerClasses@GOTOFF(%eax), %eax + movl (%eax,%edx,2), %edx + movl 32(%edx), %edx + + jmp .Lmain_\name +.type \name, %function +.size \name, .-\name +.endm + +.macro GENERATE_LOOKUP_SUPER name lookup +\name: + movl 4(%esp), %edx + movl (%edx), %eax + testl %eax, %eax + jz returnNilMethod + + movl %eax, 4(%esp) + mov 4(%edx), %edx + mov 32(%edx), %edx + 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: + call getEIP + addl $_GLOBAL_OFFSET_TABLE_, %eax + leal nilMethod@GOTOFF(%eax), %eax + ret + +nilMethod: + xorl %eax, %eax + ret + +getEIP: + movl (%esp), %eax ret #ifdef OF_LINUX .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,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -15,78 +13,84 @@ * file. */ #include "config.h" -.intel_syntax noprefix - .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 not_found +.macro GENERATE_LOOKUP name notFound \name: - mov edx, [esp+4] - test edx, edx - jz short ret_nil - - bt edx, 0 - jc short .Ltagged_pointer_\name - - mov edx, [edx] - mov edx, [edx+32] + movl 4(%esp), %edx + testl %edx, %edx + jz returnNilMethod + + testb $1, %dl + jnz .LtaggedPointer_\name + + movl (%edx), %edx + movl 32(%edx), %edx .Lmain_\name: - mov eax, [esp+8] + movl 8(%esp), %eax #ifdef OF_SELUID24 - movzx ecx, byte ptr [eax+2] - mov edx, [edx+ecx*4] -#endif - movzx ecx, byte ptr [eax+1] - mov edx, [edx+ecx*4] - movzx ecx, byte ptr [eax] - mov eax, [edx+ecx*4] - - test eax, eax - jz \not_found - - ret - -.Ltagged_pointer_\name: - xor edx, _objc_tagged_pointer_secret - and dl, 0xE - movzx edx, dl - - mov edx, [_objc_tagged_pointer_classes+edx*2] - mov edx, [edx+32] - - jmp short .Lmain_\name -.endm - -.macro generate_lookup_super name lookup -\name: - mov edx, [esp+4] - mov eax, [edx] - test eax, eax - jz short ret_nil - - mov [esp+4], eax - mov edx, [edx+4] - mov edx, [edx+32] - jmp short .Lmain_\lookup -.endm - -generate_lookup _objc_msg_lookup _objc_method_not_found -generate_lookup _objc_msg_lookup_stret _objc_method_not_found_stret -generate_lookup_super _objc_msg_lookup_super _objc_msg_lookup -generate_lookup_super _objc_msg_lookup_super_stret _objc_msg_lookup_stret - -ret_nil: - mov eax, offset nil_method - ret - -nil_method: - xor eax, eax + movzbl 2(%eax), %ecx + movl (%edx,%ecx,4), %edx +#endif + movzbl 1(%eax), %ecx + movl (%edx,%ecx,4), %edx + movzbl (%eax), %ecx + movl (%edx,%ecx,4), %eax + + testl %eax, %eax + jz \notFound + + ret + +.LtaggedPointer_\name: + xorl _objc_taggedPointerSecret, %edx + andb $0xE, %dl + movzbl %dl, %edx + + movl _objc_taggedPointerClasses(,%edx,2), %edx + movl 32(%edx), %edx + + jmp .Lmain_\name +.def \name +.scl 2 +.type 32 +.endef +.endm + +.macro GENERATE_LOOKUP_SUPER name lookup +\name: + movl 4(%esp), %edx + movl (%edx), %eax + test %eax, %eax + jz returnNilMethod + + movl %eax, 4(%esp) + movl 4(%edx), %edx + movl 32(%edx), %edx + 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: + movl $nilMethod, %eax + ret + +nilMethod: + xorl %eax, %eax ret 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,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -17,86 +15,84 @@ #include "config.h" #include "platform.h" -.intel_syntax noprefix - .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 not_found -\name: - test rdi, rdi - jz short ret_nil - - bt edi, 0 - jc short .Ltagged_pointer_\name - - mov r8, [rdi] - mov r8, [r8+64] - -.Lmain_\name: - mov rax, [rsi] - movzx ecx, ah - movzx edx, al -#ifdef OF_SELUID24 - shr eax, 16 - - mov r8, [r8+rax*8] -#endif - mov r8, [r8+rcx*8] - mov rax, [r8+rdx*8] - - test rax, rax - jz short \not_found@PLT - - ret - -.Ltagged_pointer_\name: - mov rax, [rip+objc_tagged_pointer_secret@GOTPCREL] - xor rdi, [rax] - and dil, 0xE - movzx r8, dil - - mov rax, [rip+objc_tagged_pointer_classes@GOTPCREL] - mov r8, [rax+r8*4] - mov r8, [r8+64] - - jmp short .Lmain_\name -.type \name, %function -.size \name, .-\name -.endm - -.macro generate_lookup_super name lookup -\name: - mov r8, rdi - mov rdi, [rdi] - test rdi, rdi - jz short ret_nil - - mov r8, [r8+8] - mov r8, [r8+64] - jmp short .Lmain_\lookup -.type \name, %function -.size \name, .-\name -.endm - -generate_lookup objc_msg_lookup objc_method_not_found -generate_lookup objc_msg_lookup_stret objc_method_not_found_stret -generate_lookup_super objc_msg_lookup_super objc_msg_lookup -generate_lookup_super objc_msg_lookup_super_stret objc_msg_lookup_stret - -ret_nil: - lea rax, [rip+nil_method] - ret - -nil_method: - xor rax, rax +.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 Index: src/runtime/lookup-asm/lookup-asm-x86_64-macho.S ================================================================== --- src/runtime/lookup-asm/lookup-asm-x86_64-macho.S +++ src/runtime/lookup-asm/lookup-asm-x86_64-macho.S @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -15,78 +13,76 @@ * file. */ #include "config.h" -.intel_syntax noprefix - .globl _objc_msg_lookup .globl _objc_msg_lookup_stret .globl _objc_msg_lookup_super .globl _objc_msg_lookup_super_stret .section __TEXT, __text, regular, pure_instructions -.macro generate_lookup +.macro GENERATE_LOOKUP $0: - test rdi, rdi - jz ret_nil - - bt edi, 0 - jc Ltagged_pointer_$0 - - mov r8, [rdi] - mov r8, [r8+64] + testq %rdi, %rdi + jz returnNilMethod + + testb $$1, %dil + jnz LtaggedPointer_$0 + + movq (%rdi), %r8 + movq 64(%r8), %r8 Lmain_$0: - mov rax, [rsi] - movzx ecx, ah - movzx edx, al + movq (%rsi), %rax + movzbl %ah, %ecx + movzbl %al, %edx #ifdef OF_SELUID24 - shr eax, 16 + shrl $$16, %eax - mov r8, [r8+rax*8] + movq (%r8,%rax,8), %r8 #endif - mov r8, [r8+rcx*8] - mov rax, [r8+rdx*8] + movq (%r8,%rcx,8), %r8 + movq (%r8,%rdx,8), %rax - test rax, rax + testq %rax, %rax jz $1 ret -Ltagged_pointer_$0: - mov rax, [rip+_objc_tagged_pointer_secret@GOTPCREL] - xor rdi, [rax] - and dil, 0xE - movzx r8, dil - - mov rax, [rip+_objc_tagged_pointer_classes@GOTPCREL] - mov r8, [rax+r8*4] - mov r8, [r8+64] +LtaggedPointer_$0: + movq _objc_taggedPointerSecret@GOTPCREL(%rip), %rax + xorq (%rax), %rdi + andb $$0xE, %dil + movzbl %dil, %r8d + + movq _objc_taggedPointerClasses@GOTPCREL(%rip), %rax + movq (%rax,%r8,4), %r8 + movq 64(%r8), %r8 jmp Lmain_$0 .endmacro -.macro generate_lookup_super -$0: - mov r8, rdi - mov rdi, [rdi] - test rdi, rdi - jz ret_nil - - mov r8, [r8+8] - mov r8, [r8+64] +.macro GENERATE_LOOKUP_SUPER +$0: + movq %rdi, %r8 + movq (%rdi), %rdi + testq %rdi, %rdi + jz returnNilMethod + + movq 8(%r8), %r8 + movq 64(%r8), %r8 jmp Lmain_$1 .endmacro -generate_lookup _objc_msg_lookup, _objc_method_not_found -generate_lookup _objc_msg_lookup_stret, _objc_method_not_found_stret -generate_lookup_super _objc_msg_lookup_super, _objc_msg_lookup -generate_lookup_super _objc_msg_lookup_super_stret, _objc_msg_lookup_stret +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 -ret_nil: - lea rax, [rip+nil_method] +returnNilMethod: + leaq nilMethod(%rip), %rax ret -nil_method: - mov rax, rdi +nilMethod: + xorq %rax, %rax ret 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,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -15,84 +13,91 @@ * file. */ #include "config.h" -.intel_syntax noprefix - .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 not_found +.macro GENERATE_LOOKUP name notFound \name: - test rcx, rcx - jz short ret_nil - - bt ecx, 0 - jc short .Ltagged_pointer_\name - - mov r8, [rcx] - mov r8, [r8+56] + testq %rcx, %rcx + jz returnNilMethod + + testb $1, %cl + jnz .LtaggedPointer_\name + + movq (%rcx), %r8 + movq 56(%r8), %r8 .Lmain_\name: - mov r10, rcx - mov r11, rdx + movq %rcx, %r10 + movq %rdx, %r11 - mov rax, [rdx] - movzx ecx, ah - movzx edx, al + movq (%rdx), %rax + movzbl %ah, %ecx + movzbl %al, %edx #ifdef OF_SELUID24 - shr eax, 16 + shrl $16, %eax - mov r8, [r8+rax*8] + movq (%r8,%rax,8), %r8 #endif - mov r8, [r8+rcx*8] - mov rax, [r8+rdx*8] + movq (%r8,%rcx,8), %r8 + movq (%r8,%rdx,8), %rax - test rax, rax - jz short 0f + testq %rax, %rax + jz 0f ret 0: - mov rcx, r10 - mov rdx, r11 - jmp \not_found - -.Ltagged_pointer_\name: - xor rcx, objc_tagged_pointer_secret - and cl, 0xE - movzx r8, cl - - mov r8, [objc_tagged_pointer_classes+r8*4] - mov r8, [r8+56] - - jmp short .Lmain_\name -.endm - -.macro generate_lookup_super name lookup -\name: - mov r8, rcx - mov rcx, [rcx] - test rcx, rcx - jz short ret_nil - - mov r8, [r8+8] - mov r8, [r8+56] - jmp short .Lmain_\lookup -.endm - -generate_lookup objc_msg_lookup objc_method_not_found -generate_lookup objc_msg_lookup_stret objc_method_not_found_stret -generate_lookup_super objc_msg_lookup_super objc_msg_lookup -generate_lookup_super objc_msg_lookup_super_stret objc_msg_lookup_stret - -ret_nil: - mov rax, offset nil_method - ret - -nil_method: - xor rax, rax + 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,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -26,10 +24,12 @@ # include "lookup-asm-x86-elf.S" # elif defined(OF_ARM64) # include "lookup-asm-arm64-elf.S" # elif defined(OF_ARM) # include "lookup-asm-arm-elf.S" +# elif defined(OF_POWERPC64) +# include "lookup-asm-powerpc64-elf.S" # elif defined(OF_POWERPC) # include "lookup-asm-powerpc-elf.S" # elif defined(OF_MIPS64_N64) # include "lookup-asm-mips64-n64-elf.S" # elif defined(OF_MIPS) Index: src/runtime/lookup.m ================================================================== --- src/runtime/lookup.m +++ src/runtime/lookup.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -41,15 +39,16 @@ if (!(object_getClass(object)->info & OBJC_CLASS_INFO_INITIALIZED)) { Class class = (isClass ? (Class)object : object_getClass(object)); - objc_initialize_class(class); + objc_initializeClass(class); if (!(class->info & OBJC_CLASS_INFO_SETUP)) - OBJC_ERROR("Could not dispatch message for incomplete " - "class %s!", class_getName(class)); + OBJC_ERROR("Could not dispatch message %s for " + "incomplete class %s!", + sel_getName(selector), class_getName(class)); /* * We don't need to handle the case that super was called. * The reason for this is that a call to super is not possible * before a message to the class has been sent and it thus has @@ -97,18 +96,18 @@ (isClass ? '+' : '-'), sel_getName(selector), object_getClassName(object)); } IMP -objc_method_not_found(id object, SEL selector) +objc_methodNotFound(id object, SEL selector) { return commonMethodNotFound(object, selector, objc_msg_lookup, forwardHandler); } IMP -objc_method_not_found_stret(id object, SEL selector) +objc_methodNotFound_stret(id object, SEL selector) { return commonMethodNotFound(object, selector, objc_msg_lookup_stret, stretForwardHandler); } @@ -123,11 +122,11 @@ class_respondsToSelector(Class class, SEL selector) { if (class == Nil) return false; - return (objc_dtable_get(class->DTable, + return (objc_dtable_get(class->dTable, (uint32_t)selector->UID) != (IMP)0); } #ifndef OF_ASM_LOOKUP static id @@ -142,11 +141,11 @@ IMP imp; if (object == nil) return (IMP)nilMethod; - imp = objc_dtable_get(object_getClass(object)->DTable, + imp = objc_dtable_get(object_getClass(object)->dTable, (uint32_t)selector->UID); if (imp == (IMP)0) return notFound(object, selector); @@ -154,17 +153,17 @@ } IMP objc_msg_lookup(id object, SEL selector) { - return commonLookup(object, selector, objc_method_not_found); + return commonLookup(object, selector, objc_methodNotFound); } IMP objc_msg_lookup_stret(id object, SEL selector) { - return commonLookup(object, selector, objc_method_not_found_stret); + return commonLookup(object, selector, objc_methodNotFound_stret); } static OF_INLINE IMP commonSuperLookup(struct objc_super *super, SEL selector, IMP (*notFound)(id, SEL)) @@ -172,11 +171,11 @@ IMP imp; if (super->self == nil) return (IMP)nilMethod; - imp = objc_dtable_get(super->class->DTable, (uint32_t)selector->UID); + imp = objc_dtable_get(super->class->dTable, (uint32_t)selector->UID); if (imp == (IMP)0) return notFound(super->self, selector); return imp; @@ -183,14 +182,14 @@ } IMP objc_msg_lookup_super(struct objc_super *super, SEL selector) { - return commonSuperLookup(super, selector, objc_method_not_found); + return commonSuperLookup(super, selector, objc_methodNotFound); } IMP objc_msg_lookup_super_stret(struct objc_super *super, SEL selector) { - return commonSuperLookup(super, selector, objc_method_not_found_stret); + return commonSuperLookup(super, selector, objc_methodNotFound_stret); } #endif Index: src/runtime/method.m ================================================================== --- src/runtime/method.m +++ src/runtime/method.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -32,21 +30,21 @@ *outCount = 0; return NULL; } - objc_global_mutex_lock(); + objc_globalMutex_lock(); count = 0; for (iter = class->methodList; iter != NULL; iter = iter->next) count += iter->count; if (count == 0) { if (outCount != NULL) *outCount = 0; - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return NULL; } if ((methods = malloc((count + 1) * sizeof(Method))) == NULL) OBJC_ERROR("Not enough memory to copy methods"); @@ -53,17 +51,20 @@ i = 0; for (iter = class->methodList; iter != NULL; iter = iter->next) for (unsigned int j = 0; j < iter->count; j++) methods[i++] = &iter->methods[j]; - OF_ENSURE(i == count); + + if (i != count) + OBJC_ERROR("Fatal internal inconsistency!"); + methods[count] = NULL; if (outCount != NULL) *outCount = count; - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return methods; } SEL Index: src/runtime/misc.m ================================================================== --- src/runtime/misc.m +++ src/runtime/misc.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -15,17 +13,33 @@ * file. */ #include "config.h" +#include #include #include #include "ObjFWRT.h" #include "private.h" -static objc_enumeration_mutation_handler_t enumerationMutationHandler = NULL; +#ifdef OF_WINDOWS +# include +#endif + +#ifdef OF_AMIGAOS +# define USE_INLINE_STDARG +# include +# include +# define __NOLIBBASE__ +# define Class IntuitionClass +# include +# undef Class +# undef __NOLIBBASE__ +#endif + +static objc_enumeration_mutation_handler enumerationMutationHandler = NULL; void objc_enumerationMutation(id object) { if (enumerationMutationHandler != NULL) @@ -33,9 +47,101 @@ else OBJC_ERROR("Object was mutated during enumeration!"); } void -objc_setEnumerationMutationHandler(objc_enumeration_mutation_handler_t handler) +objc_setEnumerationMutationHandler(objc_enumeration_mutation_handler handler) { enumerationMutationHandler = handler; } + +void +objc_error(const char *title, const char *format, ...) +{ +#if defined(OF_WINDOWS) || defined(OF_AMIGAOS) +# define messageLen 512 + char message[messageLen]; + int status; + va_list args; + + va_start(args, format); + status = vsnprintf(message, messageLen, format, args); + if (status <= 0 || status >= messageLen) + message[0] = '\0'; + va_end(args); +# undef BUF_LEN +#endif + +#if defined(OF_WINDOWS) + fprintf(stderr, "[%s] %s\n", title, message); + fflush(stderr); + + MessageBoxA(NULL, message, title, + MB_OK | MB_SYSTEMMODAL | MB_ICONERROR); + + exit(EXIT_FAILURE); +#elif defined(OF_AMIGAOS) + struct Library *IntuitionBase; +# ifdef OF_AMIGAOS4 + struct IntuitionIFace *IIntuition; +# endif + struct EasyStruct easy; + +# ifndef OF_AMIGAOS4 + kprintf("[%s] %s\n", title, message); +# endif + + if ((IntuitionBase = OpenLibrary("intuition.library", 0)) == NULL) + exit(EXIT_FAILURE); + +# ifdef OF_AMIGAOS4 + if ((IIntuition = (struct IntuitionIFace *)GetInterface(IntuitionBase, + "main", 1, NULL)) == NULL) + exit(EXIT_FAILURE); +# endif + + easy.es_StructSize = sizeof(easy); + easy.es_Flags = 0; + easy.es_Title = (void *)title; + easy.es_TextFormat = (void *)"%s"; + easy.es_GadgetFormat = (void *)"OK"; + + EasyRequest(NULL, &easy, NULL, (ULONG)message); + +# ifdef OF_AMIGAOS4 + DropInterface((struct Interface *)IIntuition); +# endif + + CloseLibrary(IntuitionBase); + + exit(EXIT_FAILURE); +#else + va_list args; + + va_start(args, format); + + fprintf(stderr, "[%s] ", title); + vfprintf(stderr, format, args); + fprintf(stderr, "\n"); + fflush(stderr); + + va_end(args); + + abort(); +#endif + + OF_UNREACHABLE +} + +char * +objc_strdup(const char *string) +{ + char *copy; + size_t length = strlen(string); + + if ((copy = (char *)malloc(length + 1)) == NULL) + return NULL; + + memcpy(copy, string, length + 1); + + return copy; +} DELETED src/runtime/morphos-clib.h Index: src/runtime/morphos-clib.h ================================================================== --- src/runtime/morphos-clib.h +++ /dev/null @@ -1,93 +0,0 @@ -/* The following function is only for the linklib. */ -bool glue_objc_init(unsigned int, struct objc_libc *, FILE *, FILE *); -void glue___objc_exec_class(struct objc_module *); -IMP glue_objc_msg_lookup(id, SEL); -IMP glue_objc_msg_lookup_stret(id, SEL); -IMP glue_objc_msg_lookup_super(struct objc_super *, SEL); -IMP glue_objc_msg_lookup_super_stret(struct objc_super *, SEL); -Class glue_objc_lookUpClass(const char *); -Class glue_objc_getClass(const char *); -Class glue_objc_getRequiredClass(const char *); -Class glue_objc_lookup_class(const char *); -Class glue_objc_get_class(const char *); -void glue_objc_exception_throw(id); -int glue_objc_sync_enter(id); -int glue_objc_sync_exit(id); -id glue_objc_getProperty(id, SEL, ptrdiff_t, bool); -void glue_objc_setProperty(id, SEL, ptrdiff_t, id, bool, signed char); -void glue_objc_getPropertyStruct(void *, const void *, ptrdiff_t, bool, bool); -void glue_objc_setPropertyStruct(void *, const void *, ptrdiff_t, bool, bool); -void glue_objc_enumerationMutation(id); -int glue___gnu_objc_personality(int, int, uint64_t, void *, void *); -id glue_objc_retain(id); -id glue_objc_retainBlock(id); -id glue_objc_retainAutorelease(id); -void glue_objc_release(id); -id glue_objc_autorelease(id); -id glue_objc_autoreleaseReturnValue(id); -id glue_objc_retainAutoreleaseReturnValue(id); -id glue_objc_retainAutoreleasedReturnValue(id); -id glue_objc_storeStrong(id *, id); -id glue_objc_storeWeak(id *, id); -id glue_objc_loadWeakRetained(id *); -id glue_objc_initWeak(id *, id); -void glue_objc_destroyWeak(id *); -id glue_objc_loadWeak(id *); -void glue_objc_copyWeak(id *, id *); -void glue_objc_moveWeak(id *, id *); -SEL glue_sel_registerName(const char *); -const char *glue_sel_getName(SEL); -bool glue_sel_isEqual(SEL, SEL); -Class glue_objc_allocateClassPair(Class, const char *, size_t); -void glue_objc_registerClassPair(Class); -unsigned int glue_objc_getClassList(Class *, unsigned int); -Class *glue_objc_copyClassList(unsigned int *); -bool glue_class_isMetaClass(Class); -const char *glue_class_getName(Class); -Class glue_class_getSuperclass(Class); -unsigned long glue_class_getInstanceSize(Class); -bool glue_class_respondsToSelector(Class, SEL); -bool glue_class_conformsToProtocol(Class, Protocol *); -IMP glue_class_getMethodImplementation(Class, SEL); -IMP glue_class_getMethodImplementation_stret(Class, SEL); -Method glue_class_getInstanceMethod(Class, SEL); -bool glue_class_addMethod(Class, SEL, IMP, const char *); -IMP glue_class_replaceMethod(Class, SEL, IMP, const char *); -Class glue_object_getClass(id); -Class glue_object_setClass(id, Class); -const char *glue_object_getClassName(id); -const char *glue_protocol_getName(Protocol *); -bool glue_protocol_isEqual(Protocol *, Protocol *); -bool glue_protocol_conformsToProtocol(Protocol *, Protocol *); -objc_uncaught_exception_handler_t glue_objc_setUncaughtExceptionHandler(objc_uncaught_exception_handler_t); -void glue_objc_setForwardHandler(IMP, IMP); -void glue_objc_setEnumerationMutationHandler(objc_enumeration_mutation_handler_t); -id glue_objc_constructInstance(Class, void *); -void glue_objc_exit(void); -Ivar *glue_class_copyIvarList(Class, unsigned int *); -const char *glue_ivar_getName(Ivar); -const char *glue_ivar_getTypeEncoding(Ivar); -ptrdiff_t glue_ivar_getOffset(Ivar); -Method *glue_class_copyMethodList(Class, unsigned int *); -SEL glue_method_getName(Method); -const char *glue_method_getTypeEncoding(Method); -objc_property_t *glue_class_copyPropertyList(Class, unsigned int *); -const char *glue_property_getName(objc_property_t); -char *glue_property_copyAttributeValue(objc_property_t, const char *); -void *glue_objc_destructInstance(id); -void *glue_objc_autoreleasePoolPush(void); -void glue_objc_autoreleasePoolPop(void *); -id glue__objc_rootAutorelease(id); -/* The following functions are private! Don't use! */ -struct objc_hashtable *glue_objc_hashtable_new(objc_hashtable_hash_func, objc_hashtable_equal_func, uint32_t); -void glue_objc_hashtable_set(struct objc_hashtable *, const void *, const void *); -void *glue_objc_hashtable_get(struct objc_hashtable *, const void *); -void glue_objc_hashtable_delete(struct objc_hashtable *, const void *); -void glue_objc_hashtable_free(struct objc_hashtable *); -/* Public functions again */ -void glue_objc_setTaggedPointerSecret(uintptr_t); -int glue_objc_registerTaggedPointerClass(Class); -bool glue_object_isTaggedPointer(id); -Class _Nullable glue_object_getTaggedPointerClass(id); -uintptr_t glue_object_getTaggedPointerValue(id); -id glue_objc_createTaggedPointer(int, uintptr_t); DELETED src/runtime/morphos.fd Index: src/runtime/morphos.fd ================================================================== --- src/runtime/morphos.fd +++ /dev/null @@ -1,97 +0,0 @@ -##base _ObjFWRTBase -##bias 30 -##public -* The following function is only for the linklib. -glue_objc_init(version,libc,stdout,stderr)(sysv,r12base) -glue___objc_exec_class(module)(sysv,r12base) -glue_objc_msg_lookup(object,selector)(sysv,r12base) -glue_objc_msg_lookup_stret(object,selector)(sysv,r12base) -glue_objc_msg_lookup_super(super,selector)(sysv,r12base) -glue_objc_msg_lookup_super_stret(super,selector)(sysv,r12base) -glue_objc_lookUpClass(name)(sysv,r12base) -glue_objc_getClass(name)(sysv,r12base) -glue_objc_getRequiredClass(name)(sysv,r12base) -glue_objc_lookup_class(name)(sysv,r12base) -glue_objc_get_class(name)(sysv,r12base) -glue_objc_exception_throw(object)(sysv,r12base) -glue_objc_sync_enter(object)(sysv,r12base) -glue_objc_sync_exit(object)(sysv,r12base) -glue_objc_getProperty(self,_cmd,offset,atomic)(sysv,r12base) -glue_objc_setProperty(self,_cmd,offset,value,atomic,copy)(sysv,r12base) -glue_objc_getPropertyStruct(dest,src,size,atomic,strong)(sysv,r12base) -glue_objc_setPropertyStruct(dest,src,size,atomic,strong)(sysv,r12base) -glue_objc_enumerationMutation(object)(sysv,r12base) -glue___gnu_objc_personality(version,actions,exClass,ex,ctx)(sysv,r12base) -glue_objc_retain(object)(sysv,r12base) -glue_objc_retainBlock(block)(sysv,r12base) -glue_objc_retainAutorelease(object)(sysv,r12base) -glue_objc_release(object)(sysv,r12base) -glue_objc_autorelease(object)(sysv,r12base) -glue_objc_autoreleaseReturnValue(object)(sysv,r12base) -glue_objc_retainAutoreleaseReturnValue(object)(sysv,r12base) -glue_objc_retainAutoreleasedReturnValue(object)(sysv,r12base) -glue_objc_storeStrong(object,value)(sysv,r12base) -glue_objc_storeWeak(object,value)(sysv,r12base) -glue_objc_loadWeakRetained(object)(sysv,r12base) -glue_objc_initWeak(object,value)(sysv,r12base) -glue_objc_destroyWeak(object)(sysv,r12base) -glue_objc_loadWeak(object)(sysv,r12base) -glue_objc_copyWeak(dest,src)(sysv,r12base) -glue_objc_moveWeak(dest,src)(sysv,r12base) -glue_sel_registerName(name)(sysv,r12base) -glue_sel_getName(selector)(sysv,r12base) -glue_sel_isEqual(selector1,selector2)(sysv,r12base) -glue_objc_allocateClassPair(superclass,name,extraBytes)(sysv,r12base) -glue_objc_registerClassPair(class_)(sysv,r12base) -glue_objc_getClassList(buffer,count)(sysv,r12base) -glue_objc_copyClassList(length)(sysv,r12base) -glue_class_isMetaClass(class_)(sysv,r12base) -glue_class_getName(class_)(sysv,r12base) -glue_class_getSuperclass(class_)(sysv,r12base) -glue_class_getInstanceSize(class_)(sysv,r12base) -glue_class_respondsToSelector(class_,selector)(sysv,r12base) -glue_class_conformsToProtocol(class_,p)(sysv,r12base) -glue_class_getMethodImplementation(class_,selector)(sysv,r12base) -glue_class_getMethodImplementation_stret(class_,selector)(sysv,r12base) -glue_class_getInstanceMethod(class_,selector)(sysv,r12base) -glue_class_addMethod(class_,selector,implementation,typeEncoding)(sysv,r12base) -glue_class_replaceMethod(class_,selector,implementation,typeEncoding)(sysv,r12base) -glue_object_getClass(object)(sysv,r12base) -glue_object_setClass(object,class_)(sysv,r12base) -glue_object_getClassName(object)(sysv,r12base) -glue_protocol_getName(protocol)(sysv,r12base) -glue_protocol_isEqual(protocol1,protocol2)(sysv,r12base) -glue_protocol_conformsToProtocol(protocol1,protocol2)(sysv,r12base) -glue_objc_setUncaughtExceptionHandler(handler)(sysv,r12base) -glue_objc_setForwardHandler(forward,stretForward)(sysv,r12base) -glue_objc_setEnumerationMutationHandler(handler)(sysv,r12base) -glue_objc_constructInstance(class_,bytes)(sysv,r12base) -glue_objc_exit()(sysv,r12base) -glue_class_copyIvarList(class_,outCount)(sysv,r12base) -glue_ivar_getName(ivar)(sysv,r12base) -glue_ivar_getTypeEncoding(ivar)(sysv,r12base) -glue_ivar_getOffset(ivar)(sysv,r12base) -glue_class_copyMethodList(class_,outCount)(sysv,r12base) -glue_method_getName(method)(sysv,r12base) -glue_method_getTypeEncoding(method)(sysv,r12base) -glue_class_copyPropertyList(class_,outCount)(sysv,r12base) -glue_property_getName(property)(sysv,r12base) -glue_property_copyAttributeValue(property,name)(sysv,r12base) -glue_objc_destructInstance(object)(sysv,r12base) -glue_objc_autoreleasePoolPush()(sysv,r12base) -glue_objc_autoreleasePoolPop(pool)(sysv,r12base) -glue__objc_rootAutorelease(object)(sysv,r12base) -* The following functions are private! Don't use! -glue_objc_hashtable_new(hash,equal,size)(sysv,r12base) -glue_objc_hashtable_set(table,key,object)(sysv,r12base) -glue_objc_hashtable_get(table,key)(sysv,r12base) -glue_objc_hashtable_delete(table,key)(sysv,r12base) -glue_objc_hashtable_free(table)(sysv,r12base) -* Public functions again -glue_objc_setTaggedPointerSecret(secret)(sysv,r12base) -glue_objc_registerTaggedPointerClass(class_)(sysv,r12base) -glue_object_isTaggedPointer(object)(sysv,r12base) -glue_object_getTaggedPointerClass(object)(sysv,r12base) -glue_object_getTaggedPointerValue(object)(sysv,r12base) -glue_objc_createTaggedPointer(class_,value)(sysv,r12base) -##end Index: src/runtime/private.h ================================================================== --- src/runtime/private.h +++ src/runtime/private.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -40,11 +38,11 @@ unsigned long version; unsigned long info; long instanceSize; struct objc_ivar_list *_Nullable ivars; struct objc_method_list *_Nullable methodList; - struct objc_dtable *_Nonnull DTable; + struct objc_dtable *_Nonnull dTable; Class _Nullable *_Nullable subclassList; void *_Nullable siblingClass; struct objc_protocol_list *_Nullable protocols; void *_Nullable GCObjectType; unsigned long ABIVersion; @@ -201,11 +199,11 @@ struct objc_sparsearray { struct objc_sparsearray_data { void *_Nullable next[256]; } *_Nonnull data; - uint8_t indexSize; + uint8_t levels; }; struct objc_dtable { struct objc_dtable_level2 { #ifdef OF_SELUID24 @@ -223,13 +221,10 @@ 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); - int (*_Nonnull vfprintf)(FILE *_Nonnull, const char *_Nonnull, va_list); - int (*_Nonnull fflush)(FILE *_Nonnull); - void (*_Nonnull abort)(void); # ifdef HAVE_SJLJ_EXCEPTIONS int (*_Nonnull _Unwind_SjLj_RaiseException)(void *_Nonnull); # else int (*_Nonnull _Unwind_RaiseException)(void *_Nonnull); # endif @@ -246,13 +241,25 @@ # 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__) @@ -261,40 +268,46 @@ # else # define OBJC_M68K_ARG(type, name, reg) \ register type reg_##name __asm__(#reg); \ type name = reg_##name; # endif -# undef stdout -# undef stderr -extern FILE *stdout, *stderr; + +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_register_all_categories(struct objc_symtab *_Nonnull); +extern void objc_registerAllCategories(struct objc_symtab *_Nonnull); extern struct objc_category *_Nullable *_Nullable - objc_categories_for_class(Class _Nonnull); -extern void objc_unregister_all_categories(void); -extern void objc_initialize_class(Class _Nonnull); -extern void objc_update_dtable(Class _Nonnull); -extern void objc_register_all_classes(struct objc_symtab *_Nonnull); -extern Class _Nullable objc_classname_to_class(const char *_Nonnull, bool); -extern void objc_unregister_class(Class _Nonnull); -extern void objc_unregister_all_classes(void); -extern uint32_t objc_hash_string(const void *_Nonnull); -extern bool objc_equal_string(const void *_Nonnull, const void *_Nonnull); + objc_categoriesForClass(Class _Nonnull); +extern void objc_unregisterAllCategories(void); +extern void objc_initializeClass(Class _Nonnull); +extern void objc_updateDTable(Class _Nonnull); +extern void objc_registerAllClasses(struct objc_symtab *_Nonnull); +extern Class _Nullable objc_classnameToClass(const char *_Nonnull, bool); +extern void objc_unregisterClass(Class _Nonnull); +extern void objc_unregisterAllClasses(void); +extern uint32_t objc_string_hash(const void *_Nonnull); +extern bool objc_string_equal(const void *_Nonnull, const void *_Nonnull); extern struct objc_hashtable *_Nonnull objc_hashtable_new( objc_hashtable_hash_func, objc_hashtable_equal_func, uint32_t); -extern struct objc_hashtable_bucket objc_deleted_bucket; +extern struct objc_hashtable_bucket objc_deletedBucket; extern void objc_hashtable_set(struct objc_hashtable *_Nonnull, const void *_Nonnull, const void *_Nonnull); extern void *_Nullable objc_hashtable_get(struct objc_hashtable *_Nonnull, const void *_Nonnull); extern void objc_hashtable_delete(struct objc_hashtable *_Nonnull, const void *_Nonnull); extern void objc_hashtable_free(struct objc_hashtable *_Nonnull); -extern void objc_register_selector(struct objc_selector *_Nonnull); -extern void objc_register_all_selectors(struct objc_symtab *_Nonnull); -extern void objc_unregister_all_selectors(void); +extern void objc_registerSelector(struct objc_selector *_Nonnull); +extern void objc_registerAllSelectors(struct objc_symtab *_Nonnull); +extern void objc_unregisterAllSelectors(void); extern struct objc_sparsearray *_Nonnull objc_sparsearray_new(uint8_t); extern void *_Nullable objc_sparsearray_get(struct objc_sparsearray *_Nonnull, uintptr_t); extern void objc_sparsearray_set(struct objc_sparsearray *_Nonnull, uintptr_t, void *_Nullable); @@ -304,23 +317,24 @@ struct objc_dtable *_Nonnull); extern void objc_dtable_set(struct objc_dtable *_Nonnull, uint32_t, IMP _Nullable); extern void objc_dtable_free(struct objc_dtable *_Nonnull); extern void objc_dtable_cleanup(void); -extern void objc_init_static_instances(struct objc_symtab *_Nonnull); -extern void objc_forget_pending_static_instances(void); -extern void objc_zero_weak_references(id _Nonnull); +extern void objc_initStaticInstances(struct objc_symtab *_Nonnull); +extern void objc_forgetPendingStaticInstances(void); +extern void objc_zeroWeakReferences(id _Nonnull); extern Class _Nullable object_getTaggedPointerClass(id _Nonnull); #ifdef OF_HAVE_THREADS -extern void objc_global_mutex_lock(void); -extern void objc_global_mutex_unlock(void); -extern void objc_global_mutex_free(void); +extern void objc_globalMutex_lock(void); +extern void objc_globalMutex_unlock(void); +extern void objc_globalMutex_free(void); #else -# define objc_global_mutex_lock() -# define objc_global_mutex_unlock() -# define objc_global_mutex_free() +# define objc_globalMutex_lock() +# define objc_globalMutex_unlock() +# define objc_globalMutex_free() #endif +extern char *_Nullable objc_strdup(const char *_Nonnull string); static inline IMP _Nullable objc_dtable_get(const struct objc_dtable *_Nonnull dtable, uint32_t idx) { #ifdef OF_SELUID24 @@ -334,13 +348,20 @@ uint8_t j = idx; return dtable->buckets[i]->buckets[j]; #endif } + +extern void OF_NO_RETURN_FUNC objc_error(const char *_Nonnull title, + const char *_Nonnull format, ...); +#define OBJC_ERROR(...) \ + objc_error("ObjFWRT @ " __FILE__ ":" OF_STRINGIFY(__LINE__), \ + __VA_ARGS__) #if defined(OF_ELF) -# if defined(OF_X86_64) || defined(OF_X86) || defined(OF_POWERPC) || \ +# if defined(OF_X86_64) || 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 @@ -352,20 +373,10 @@ # if defined(OF_X86_64) || defined(OF_X86) # define OF_ASM_LOOKUP # endif #endif -#define OBJC_ERROR(...) \ - { \ - fprintf(stderr, "[objc @ " __FILE__ ":%d] ", __LINE__); \ - fprintf(stderr, __VA_ARGS__); \ - fprintf(stderr, "\n"); \ - fflush(stderr); \ - abort(); \ - OF_UNREACHABLE \ - } - @interface DummyObject { Class _Nonnull isa; } Index: src/runtime/property.m ================================================================== --- src/runtime/property.m +++ src/runtime/property.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -21,38 +19,45 @@ #import "ObjFWRT.h" #import "private.h" #ifdef OF_HAVE_THREADS -# import "mutex.h" -# define NUM_SPINLOCKS 8 /* needs to be a power of 2 */ -# define SPINLOCK_HASH(p) ((unsigned)((uintptr_t)p >> 4) & (NUM_SPINLOCKS - 1)) -static of_spinlock_t spinlocks[NUM_SPINLOCKS]; +# import "OFPlainMutex.h" +# define numSpinlocks 8 /* needs to be a power of 2 */ +static OFSpinlock spinlocks[numSpinlocks]; + +static OF_INLINE size_t +spinlockSlot(const void *ptr) +{ + return ((size_t)((uintptr_t)ptr >> 4) & (numSpinlocks - 1)); +} #endif #ifdef OF_HAVE_THREADS OF_CONSTRUCTOR() { - for (size_t i = 0; i < NUM_SPINLOCKS; i++) - if (!of_spinlock_new(&spinlocks[i])) - OBJC_ERROR("Failed to initialize spinlocks!") + for (size_t i = 0; i < numSpinlocks; i++) + if (OFSpinlockNew(&spinlocks[i]) != 0) + OBJC_ERROR("Failed to create spinlocks!"); } #endif id objc_getProperty(id self, SEL _cmd, ptrdiff_t offset, bool atomic) { if (atomic) { id *ptr = (id *)(void *)((char *)self + offset); #ifdef OF_HAVE_THREADS - unsigned hash = SPINLOCK_HASH(ptr); + size_t slot = spinlockSlot(ptr); - OF_ENSURE(of_spinlock_lock(&spinlocks[hash])); + if (OFSpinlockLock(&spinlocks[slot]) != 0) + OBJC_ERROR("Failed to lock spinlock!"); @try { return [[*ptr retain] autorelease]; } @finally { - OF_ENSURE(of_spinlock_unlock(&spinlocks[hash])); + if (OFSpinlockUnlock(&spinlocks[slot]) != 0) + OBJC_ERROR("Failed to unlock spinlock!"); } #else return [[*ptr retain] autorelease]; #endif } @@ -65,13 +70,14 @@ signed char copy) { if (atomic) { id *ptr = (id *)(void *)((char *)self + offset); #ifdef OF_HAVE_THREADS - unsigned hash = SPINLOCK_HASH(ptr); + size_t slot = spinlockSlot(ptr); - OF_ENSURE(of_spinlock_lock(&spinlocks[hash])); + if (OFSpinlockLock(&spinlocks[slot]) != 0) + OBJC_ERROR("Failed to lock spinlock!"); @try { #endif id old = *ptr; switch (copy) { @@ -86,11 +92,12 @@ } [old release]; #ifdef OF_HAVE_THREADS } @finally { - OF_ENSURE(of_spinlock_unlock(&spinlocks[hash])); + if (OFSpinlockUnlock(&spinlocks[slot]) != 0) + OBJC_ERROR("Failed to unlock spinlock!"); } #endif return; } @@ -117,17 +124,19 @@ objc_getPropertyStruct(void *dest, const void *src, ptrdiff_t size, bool atomic, bool strong) { if (atomic) { #ifdef OF_HAVE_THREADS - unsigned hash = SPINLOCK_HASH(src); + size_t slot = spinlockSlot(src); - OF_ENSURE(of_spinlock_lock(&spinlocks[hash])); + if (OFSpinlockLock(&spinlocks[slot]) != 0) + OBJC_ERROR("Failed to lock spinlock!"); #endif memcpy(dest, src, size); #ifdef OF_HAVE_THREADS - OF_ENSURE(of_spinlock_unlock(&spinlocks[hash])); + if (OFSpinlockUnlock(&spinlocks[slot]) != 0) + OBJC_ERROR("Failed to unlock spinlock!"); #endif return; } @@ -138,17 +147,19 @@ objc_setPropertyStruct(void *dest, const void *src, ptrdiff_t size, bool atomic, bool strong) { if (atomic) { #ifdef OF_HAVE_THREADS - unsigned hash = SPINLOCK_HASH(src); + size_t slot = spinlockSlot(src); - OF_ENSURE(of_spinlock_lock(&spinlocks[hash])); + if (OFSpinlockLock(&spinlocks[slot]) != 0) + OBJC_ERROR("Failed to lock spinlock!"); #endif memcpy(dest, src, size); #ifdef OF_HAVE_THREADS - OF_ENSURE(of_spinlock_unlock(&spinlocks[hash])); + if (OFSpinlockUnlock(&spinlocks[slot]) != 0) + OBJC_ERROR("Failed to unlock spinlock!"); #endif return; } @@ -167,11 +178,11 @@ *outCount = 0; return NULL; } - objc_global_mutex_lock(); + objc_globalMutex_lock(); count = 0; if (class->info & OBJC_CLASS_INFO_NEW_ABI) for (iter = class->propertyList; iter != NULL; iter = iter->next) @@ -179,11 +190,11 @@ if (count == 0) { if (outCount != NULL) *outCount = 0; - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return NULL; } properties = malloc((count + 1) * sizeof(objc_property_t)); if (properties == NULL) @@ -191,17 +202,20 @@ i = 0; for (iter = class->propertyList; iter != NULL; iter = iter->next) for (unsigned int j = 0; j < iter->count; j++) properties[i++] = &iter->properties[j]; - OF_ENSURE(i == count); + + if (i != count) + OBJC_ERROR("Fatal internal inconsistency!"); + properties[count] = NULL; if (outCount != NULL) *outCount = count; - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return properties; } const char * @@ -219,22 +233,22 @@ if (strlen(name) != 1) return NULL; switch (*name) { case 'T': - ret = of_strdup(property->getter.typeEncoding); + ret = objc_strdup(property->getter.typeEncoding); nullIsError = true; break; case 'G': if (property->attributes & OBJC_PROPERTY_GETTER) { - ret = of_strdup(property->getter.name); + ret = objc_strdup(property->getter.name); nullIsError = true; } break; case 'S': if (property->attributes & OBJC_PROPERTY_SETTER) { - ret = of_strdup(property->setter.name); + ret = objc_strdup(property->setter.name); nullIsError = true; } break; #define BOOL_CASE(name, field, flag) \ case name: \ @@ -253,9 +267,9 @@ #undef BOOL_CASE } if (nullIsError && ret == NULL) OBJC_ERROR("Not enough memory to copy property attribute " - "value"); + "value!"); return ret; } Index: src/runtime/protocol.m ================================================================== --- src/runtime/protocol.m +++ src/runtime/protocol.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -67,14 +65,14 @@ for (long i = 0; i < protocolList->count; i++) if (protocol_conformsToProtocol(protocolList->list[i], protocol)) return true; - objc_global_mutex_lock(); + objc_globalMutex_lock(); - if ((categories = objc_categories_for_class(class)) == NULL) { - objc_global_mutex_unlock(); + if ((categories = objc_categoriesForClass(class)) == NULL) { + objc_globalMutex_unlock(); return false; } for (long i = 0; categories[i] != NULL; i++) { for (struct objc_protocol_list *protocolList = @@ -81,16 +79,16 @@ categories[i]->protocols; protocolList != NULL; protocolList = protocolList->next) { for (long j = 0; j < protocolList->count; j++) { if (protocol_conformsToProtocol( protocolList->list[j], protocol)) { - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return true; } } } } - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return false; } Index: src/runtime/selector.m ================================================================== --- src/runtime/selector.m +++ src/runtime/selector.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -25,43 +23,43 @@ #import "private.h" #import "macros.h" #ifdef OF_SELUID24 -# define SEL_MAX 0xFFFFFF -# define SEL_SIZE 3 +static const uint32_t maxSel = 0xFFFFFF; +static const uint8_t selLevels = 3; #else -# define SEL_MAX 0xFFFF -# define SEL_SIZE 2 +static const uint32_t maxSel = 0xFFFF; +static const uint8_t selLevels = 2; #endif static struct objc_hashtable *selectors = NULL; static uint32_t selectorsCount = 0; static struct objc_sparsearray *selectorNames = NULL; static void **freeList = NULL; static size_t freeListCount = 0; void -objc_register_selector(struct objc_selector *selector) +objc_registerSelector(struct objc_selector *selector) { SEL existingSelector; const char *name; - if (selectorsCount > SEL_MAX) + if (selectorsCount > maxSel) OBJC_ERROR("Out of selector slots!"); if (selectors == NULL) selectors = objc_hashtable_new( - objc_hash_string, objc_equal_string, 2); + objc_string_hash, objc_string_equal, 2); else if ((existingSelector = objc_hashtable_get(selectors, (const char *)selector->UID)) != NULL) { selector->UID = existingSelector->UID; return; } if (selectorNames == NULL) - selectorNames = objc_sparsearray_new(SEL_SIZE); + selectorNames = objc_sparsearray_new(selLevels); name = (const char *)selector->UID; selector->UID = selectorsCount++; objc_hashtable_set(selectors, name, selector); @@ -72,22 +70,20 @@ SEL sel_registerName(const char *name) { struct objc_selector *selector; - objc_global_mutex_lock(); + objc_globalMutex_lock(); if (selectors != NULL && (selector = objc_hashtable_get(selectors, name)) != NULL) { - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return (SEL)selector; } - if ((selector = malloc(sizeof(*selector))) == NULL) - OBJC_ERROR("Not enough memory to allocate selector!"); - - if ((selector->UID = (uintptr_t)of_strdup(name)) == 0) + if ((selector = malloc(sizeof(*selector))) == NULL || + (selector->UID = (uintptr_t)objc_strdup(name)) == 0) OBJC_ERROR("Not enough memory to allocate selector!"); selector->typeEncoding = NULL; if ((freeList = realloc(freeList, @@ -95,36 +91,36 @@ OBJC_ERROR("Not enough memory to allocate selector!"); freeList[freeListCount++] = selector; freeList[freeListCount++] = (char *)selector->UID; - objc_register_selector(selector); + objc_registerSelector(selector); - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return (SEL)selector; } void -objc_register_all_selectors(struct objc_symtab *symtab) +objc_registerAllSelectors(struct objc_symtab *symtab) { struct objc_selector *selector; if (symtab->selectorRefs == NULL) return; for (selector = symtab->selectorRefs; selector->UID != 0; selector++) - objc_register_selector(selector); + objc_registerSelector(selector); } const char * sel_getName(SEL selector) { const char *ret; - objc_global_mutex_lock(); + objc_globalMutex_lock(); ret = objc_sparsearray_get(selectorNames, (uint32_t)selector->UID); - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return ret; } bool @@ -132,11 +128,11 @@ { return (selector1->UID == selector2->UID); } void -objc_unregister_all_selectors(void) +objc_unregisterAllSelectors(void) { objc_hashtable_free(selectors); objc_sparsearray_free(selectorNames); if (freeList != NULL) { Index: src/runtime/sparsearray.m ================================================================== --- src/runtime/sparsearray.m +++ src/runtime/sparsearray.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -22,33 +20,31 @@ #import "ObjFWRT.h" #import "private.h" struct objc_sparsearray * -objc_sparsearray_new(uint8_t indexSize) +objc_sparsearray_new(uint8_t levels) { struct objc_sparsearray *sparsearray; - if ((sparsearray = calloc(1, sizeof(*sparsearray))) == NULL) + if ((sparsearray = calloc(1, sizeof(*sparsearray))) == NULL || + (sparsearray->data = calloc(1, sizeof(*sparsearray->data))) == NULL) OBJC_ERROR("Failed to allocate memory for sparse array!"); - if ((sparsearray->data = calloc(1, sizeof(*sparsearray->data))) == NULL) - OBJC_ERROR("Failed to allocate memory for sparse array!"); - - sparsearray->indexSize = indexSize; + sparsearray->levels = levels; return sparsearray; } void * objc_sparsearray_get(struct objc_sparsearray *sparsearray, uintptr_t idx) { struct objc_sparsearray_data *iter = sparsearray->data; - for (uint8_t i = 0; i < sparsearray->indexSize - 1; i++) { + for (uint8_t i = 0; i < sparsearray->levels - 1; i++) { uintptr_t j = - (idx >> ((sparsearray->indexSize - i - 1) * 8)) & 0xFF; + (idx >> ((sparsearray->levels - i - 1) * 8)) & 0xFF; if ((iter = iter->next[j]) == NULL) return NULL; } @@ -59,13 +55,13 @@ objc_sparsearray_set(struct objc_sparsearray *sparsearray, uintptr_t idx, void *value) { struct objc_sparsearray_data *iter = sparsearray->data; - for (uint8_t i = 0; i < sparsearray->indexSize - 1; i++) { + for (uint8_t i = 0; i < sparsearray->levels - 1; i++) { uintptr_t j = - (idx >> ((sparsearray->indexSize - i - 1) * 8)) & 0xFF; + (idx >> ((sparsearray->levels - i - 1) * 8)) & 0xFF; if (iter->next[j] == NULL) if ((iter->next[j] = calloc(1, sizeof(struct objc_sparsearray_data))) == NULL) OBJC_ERROR("Failed to allocate memory for " @@ -90,8 +86,8 @@ } void objc_sparsearray_free(struct objc_sparsearray *sparsearray) { - freeSparsearrayData(sparsearray->data, sparsearray->indexSize); + freeSparsearrayData(sparsearray->data, sparsearray->levels); free(sparsearray); } Index: src/runtime/static-instances.m ================================================================== --- src/runtime/static-instances.m +++ src/runtime/static-instances.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -25,11 +23,11 @@ static struct objc_static_instances **staticInstancesList = NULL; static size_t staticInstancesCount = 0; void -objc_init_static_instances(struct objc_symtab *symtab) +objc_initStaticInstances(struct objc_symtab *symtab) { struct objc_static_instances **staticInstances; /* Check if the class for a static instance became available */ for (size_t i = 0; i < staticInstancesCount; i++) { @@ -95,11 +93,11 @@ } } } void -objc_forget_pending_static_instances() +objc_forgetPendingStaticInstances() { free(staticInstancesList); staticInstancesList = NULL; staticInstancesCount = 0; } Index: src/runtime/synchronized.m ================================================================== --- src/runtime/synchronized.m +++ src/runtime/synchronized.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -22,25 +20,25 @@ #import "ObjFWRT.h" #import "private.h" #ifdef OF_HAVE_THREADS -# import "mutex.h" +# import "OFPlainMutex.h" -static struct lock_s { - id object; - int count; - of_rmutex_t rmutex; - struct lock_s *next; +static struct Lock { + id object; + int count; + OFPlainRecursiveMutex rmutex; + struct Lock *next; } *locks = NULL; -static of_mutex_t mutex; +static OFPlainMutex mutex; OF_CONSTRUCTOR() { - if (!of_mutex_new(&mutex)) - OBJC_ERROR("Failed to create mutex!") + if (OFPlainMutexNew(&mutex) != 0) + OBJC_ERROR("Failed to create mutex!"); } #endif int objc_sync_enter(id object) @@ -47,48 +45,48 @@ { if (object == nil) return 0; #ifdef OF_HAVE_THREADS - struct lock_s *lock; + struct Lock *lock; - if (!of_mutex_lock(&mutex)) + if (OFPlainMutexLock(&mutex) != 0) OBJC_ERROR("Failed to lock mutex!"); /* Look if we already have a lock */ for (lock = locks; lock != NULL; lock = lock->next) { if (lock->object != object) continue; lock->count++; - if (!of_mutex_unlock(&mutex)) + if (OFPlainMutexUnlock(&mutex) != 0) OBJC_ERROR("Failed to unlock mutex!"); - if (!of_rmutex_lock(&lock->rmutex)) + if (OFPlainRecursiveMutexLock(&lock->rmutex) != 0) OBJC_ERROR("Failed to lock mutex!"); return 0; } /* Create a new lock */ if ((lock = malloc(sizeof(*lock))) == NULL) OBJC_ERROR("Failed to allocate memory for mutex!"); - if (!of_rmutex_new(&lock->rmutex)) + if (OFPlainRecursiveMutexNew(&lock->rmutex) != 0) OBJC_ERROR("Failed to create mutex!"); lock->object = object; lock->count = 1; lock->next = locks; locks = lock; - if (!of_mutex_unlock(&mutex)) + if (OFPlainMutexUnlock(&mutex) != 0) OBJC_ERROR("Failed to unlock mutex!"); - if (!of_rmutex_lock(&lock->rmutex)) + if (OFPlainRecursiveMutexLock(&lock->rmutex) != 0) OBJC_ERROR("Failed to lock mutex!"); #endif return 0; } @@ -98,26 +96,26 @@ { if (object == nil) return 0; #ifdef OF_HAVE_THREADS - struct lock_s *lock, *last = NULL; + struct Lock *lock, *last = NULL; - if (!of_mutex_lock(&mutex)) + if (OFPlainMutexLock(&mutex) != 0) OBJC_ERROR("Failed to lock mutex!"); for (lock = locks; lock != NULL; lock = lock->next) { if (lock->object != object) { last = lock; continue; } - if (!of_rmutex_unlock(&lock->rmutex)) + if (OFPlainRecursiveMutexUnlock(&lock->rmutex) != 0) OBJC_ERROR("Failed to unlock mutex!"); if (--lock->count == 0) { - if (!of_rmutex_free(&lock->rmutex)) + if (OFPlainRecursiveMutexFree(&lock->rmutex) != 0) OBJC_ERROR("Failed to destroy mutex!"); if (last != NULL) last->next = lock->next; if (locks == lock) @@ -124,16 +122,16 @@ locks = lock->next; free(lock); } - if (!of_mutex_unlock(&mutex)) + if (OFPlainMutexUnlock(&mutex) != 0) OBJC_ERROR("Failed to unlock mutex!"); return 0; } - OBJC_ERROR("objc_sync_exit() was called for an object not locked!"); + OBJC_ERROR("objc_sync_exit() was called for an unlocked object!"); #else return 0; #endif } Index: src/runtime/tagged-pointer.m ================================================================== --- src/runtime/tagged-pointer.m +++ src/runtime/tagged-pointer.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -17,39 +15,39 @@ #import "ObjFWRT.h" #import "private.h" -#define TAGGED_POINTER_BITS 4 -#define NUM_TAGGED_POINTER_CLASSES (1 << (TAGGED_POINTER_BITS - 1)) +#define numTaggedPointerBits 4 +#define maxNumTaggedPointerClasses (1 << (numTaggedPointerBits - 1)) -Class objc_tagged_pointer_classes[NUM_TAGGED_POINTER_CLASSES]; +Class objc_taggedPointerClasses[maxNumTaggedPointerClasses]; static int taggedPointerClassesCount; -uintptr_t objc_tagged_pointer_secret; +uintptr_t objc_taggedPointerSecret; void objc_setTaggedPointerSecret(uintptr_t secret) { - objc_tagged_pointer_secret = secret & ~(uintptr_t)1; + objc_taggedPointerSecret = secret & ~(uintptr_t)1; } int objc_registerTaggedPointerClass(Class class) { int i; - objc_global_mutex_lock(); + objc_globalMutex_lock(); - if (taggedPointerClassesCount == NUM_TAGGED_POINTER_CLASSES) { - objc_global_mutex_unlock(); + if (taggedPointerClassesCount == maxNumTaggedPointerClasses) { + objc_globalMutex_unlock(); return -1; } i = taggedPointerClassesCount++; - objc_tagged_pointer_classes[i] = class; + objc_taggedPointerClasses[i] = class; - objc_global_mutex_unlock(); + objc_globalMutex_unlock(); return i; } bool @@ -61,42 +59,42 @@ } Class object_getTaggedPointerClass(id object) { - uintptr_t pointer = (uintptr_t)object ^ objc_tagged_pointer_secret; + uintptr_t pointer = (uintptr_t)object ^ objc_taggedPointerSecret; - pointer &= (1 << TAGGED_POINTER_BITS) - 1; + pointer &= (1 << numTaggedPointerBits) - 1; pointer >>= 1; - if (pointer >= NUM_TAGGED_POINTER_CLASSES) + if (pointer >= maxNumTaggedPointerClasses) return Nil; - return objc_tagged_pointer_classes[pointer]; + return objc_taggedPointerClasses[pointer]; } uintptr_t object_getTaggedPointerValue(id object) { - uintptr_t pointer = (uintptr_t)object ^ objc_tagged_pointer_secret; + uintptr_t pointer = (uintptr_t)object ^ objc_taggedPointerSecret; - pointer >>= TAGGED_POINTER_BITS; + pointer >>= numTaggedPointerBits; return pointer; } id objc_createTaggedPointer(int class, uintptr_t value) { uintptr_t pointer; - if (class < 0 || class >= NUM_TAGGED_POINTER_CLASSES) + if (class < 0 || class >= maxNumTaggedPointerClasses) return nil; - if (value > (UINTPTR_MAX >> TAGGED_POINTER_BITS)) + if (value > (UINTPTR_MAX >> numTaggedPointerBits)) return nil; pointer = (class << 1) | 1; - pointer |= (value << TAGGED_POINTER_BITS); + pointer |= (value << numTaggedPointerBits); - return (id)(pointer ^ objc_tagged_pointer_secret); + return (id)(pointer ^ objc_taggedPointerSecret); } Index: src/runtime/threading.m ================================================================== --- src/runtime/threading.m +++ src/runtime/threading.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -20,33 +18,34 @@ #include #include #import "ObjFWRT.h" #import "private.h" -#import "mutex.h" -#import "once.h" + +#import "OFOnce.h" +#import "OFPlainMutex.h" -static of_rmutex_t globalMutex; +static OFPlainRecursiveMutex globalMutex; static void init(void) { - if (!of_rmutex_new(&globalMutex)) + if (OFPlainRecursiveMutexNew(&globalMutex) != 0) OBJC_ERROR("Failed to create global mutex!"); } void -objc_global_mutex_lock(void) +objc_globalMutex_lock(void) { - static of_once_t once_control = OF_ONCE_INIT; - of_once(&once_control, init); + static OFOnceControl onceControl = OFOnceControlInitValue; + OFOnce(&onceControl, init); - if (!of_rmutex_lock(&globalMutex)) + if (OFPlainRecursiveMutexLock(&globalMutex) != 0) OBJC_ERROR("Failed to lock global mutex!"); } void -objc_global_mutex_unlock(void) +objc_globalMutex_unlock(void) { - if (!of_rmutex_unlock(&globalMutex)) + if (OFPlainRecursiveMutexUnlock(&globalMutex) != 0) OBJC_ERROR("Failed to unlock global mutex!"); } DELETED src/scrypt.h Index: src/scrypt.h ================================================================== --- src/scrypt.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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. - */ - -#ifndef __STDC_LIMIT_MACROS -# define __STDC_LIMIT_MACROS -#endif -#ifndef __STDC_CONSTANT_MACROS -# define __STDC_CONSTANT_MACROS -#endif - -#import "macros.h" - -OF_ASSUME_NONNULL_BEGIN - -/** @file */ - -@class OFHMAC; - -/** - * @brief The parameters for @ref of_scrypt. - */ -typedef struct of_scrypt_parameters_t { - /** @brief The block size to use. */ - size_t blockSize; - /** @brief The CPU/memory cost factor to use. */ - size_t costFactor; - /** @brief The parallelization to use. */ - size_t parallelization; - /** @brief The salt to derive a key with. */ - const unsigned char *salt; - /** @brief The length of the salt. */ - size_t saltLength; - /** @brief The password to derive a key from. */ - const char *password; - /** @brief The length of the password. */ - size_t passwordLength; - /** @brief The buffer to write the key to. */ - unsigned char *key; - /** - * @brief The desired length for the derived key. - * - * @ref key needs to have enough storage. - */ - size_t keyLength; - /** @brief Whether data may be stored in swappable memory. */ - bool allowsSwappableMemory; -} of_scrypt_parameters_t; - -#ifdef __cplusplus -extern "C" { -#endif -extern void of_salsa20_8_core(uint32_t buffer[_Nonnull 16]); -extern void of_scrypt_block_mix(uint32_t *output, const uint32_t *input, - size_t blockSize); -extern void of_scrypt_romix(uint32_t *buffer, size_t blockSize, - size_t costFactor, uint32_t *tmp); - -/** - * @brief Derives a key from a password and a salt using scrypt. - * - * @param param The parameters to use - */ -extern void of_scrypt(of_scrypt_parameters_t param); -#ifdef __cplusplus -} -#endif - -OF_ASSUME_NONNULL_END DELETED src/scrypt.m Index: src/scrypt.m ================================================================== --- src/scrypt.m +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "OFHMAC.h" -#import "OFSHA256Hash.h" -#import "OFSecureData.h" - -#import "OFInvalidArgumentException.h" -#import "OFOutOfMemoryException.h" -#import "OFOutOfRangeException.h" - -#import "scrypt.h" -#import "pbkdf2.h" - -void -of_salsa20_8_core(uint32_t buffer[16]) -{ - uint32_t tmp[16]; - - for (uint_fast8_t i = 0; i < 16; i++) - tmp[i] = OF_BSWAP32_IF_BE(buffer[i]); - - for (uint_fast8_t i = 0; i < 8; i += 2) { - tmp[ 4] ^= OF_ROL(tmp[ 0] + tmp[12], 7); - tmp[ 8] ^= OF_ROL(tmp[ 4] + tmp[ 0], 9); - tmp[12] ^= OF_ROL(tmp[ 8] + tmp[ 4], 13); - tmp[ 0] ^= OF_ROL(tmp[12] + tmp[ 8], 18); - tmp[ 9] ^= OF_ROL(tmp[ 5] + tmp[ 1], 7); - tmp[13] ^= OF_ROL(tmp[ 9] + tmp[ 5], 9); - tmp[ 1] ^= OF_ROL(tmp[13] + tmp[ 9], 13); - tmp[ 5] ^= OF_ROL(tmp[ 1] + tmp[13], 18); - tmp[14] ^= OF_ROL(tmp[10] + tmp[ 6], 7); - tmp[ 2] ^= OF_ROL(tmp[14] + tmp[10], 9); - tmp[ 6] ^= OF_ROL(tmp[ 2] + tmp[14], 13); - tmp[10] ^= OF_ROL(tmp[ 6] + tmp[ 2], 18); - tmp[ 3] ^= OF_ROL(tmp[15] + tmp[11], 7); - tmp[ 7] ^= OF_ROL(tmp[ 3] + tmp[15], 9); - tmp[11] ^= OF_ROL(tmp[ 7] + tmp[ 3], 13); - tmp[15] ^= OF_ROL(tmp[11] + tmp[ 7], 18); - tmp[ 1] ^= OF_ROL(tmp[ 0] + tmp[ 3], 7); - tmp[ 2] ^= OF_ROL(tmp[ 1] + tmp[ 0], 9); - tmp[ 3] ^= OF_ROL(tmp[ 2] + tmp[ 1], 13); - tmp[ 0] ^= OF_ROL(tmp[ 3] + tmp[ 2], 18); - tmp[ 6] ^= OF_ROL(tmp[ 5] + tmp[ 4], 7); - tmp[ 7] ^= OF_ROL(tmp[ 6] + tmp[ 5], 9); - tmp[ 4] ^= OF_ROL(tmp[ 7] + tmp[ 6], 13); - tmp[ 5] ^= OF_ROL(tmp[ 4] + tmp[ 7], 18); - tmp[11] ^= OF_ROL(tmp[10] + tmp[ 9], 7); - tmp[ 8] ^= OF_ROL(tmp[11] + tmp[10], 9); - tmp[ 9] ^= OF_ROL(tmp[ 8] + tmp[11], 13); - tmp[10] ^= OF_ROL(tmp[ 9] + tmp[ 8], 18); - tmp[12] ^= OF_ROL(tmp[15] + tmp[14], 7); - tmp[13] ^= OF_ROL(tmp[12] + tmp[15], 9); - tmp[14] ^= OF_ROL(tmp[13] + tmp[12], 13); - tmp[15] ^= OF_ROL(tmp[14] + tmp[13], 18); - } - - for (uint_fast8_t i = 0; i < 16; i++) - buffer[i] = OF_BSWAP32_IF_BE(OF_BSWAP32_IF_BE(buffer[i]) + - tmp[i]); - - of_explicit_memset(tmp, 0, sizeof(tmp)); -} - -void -of_scrypt_block_mix(uint32_t *output, const uint32_t *input, size_t blockSize) -{ - uint32_t tmp[16]; - - /* Check defined here and executed in of_scrypt() */ -#define OVERFLOW_CHECK_1 \ - if (param.blockSize > SIZE_MAX / 2 || \ - 2 * param.blockSize - 1 > SIZE_MAX / 16) \ - @throw [OFOutOfRangeException exception]; - - memcpy(tmp, input + (2 * blockSize - 1) * 16, 64); - - for (size_t i = 0; i < 2 * blockSize; i++) { - for (size_t j = 0; j < 16; j++) - tmp[j] ^= input[i * 16 + j]; - - of_salsa20_8_core(tmp); - - /* - * Even indices are stored in the first half and odd ones in - * the second. - */ - memcpy(output + ((i / 2) + (i & 1) * blockSize) * 16, tmp, 64); - } - - of_explicit_memset(tmp, 0, sizeof(tmp)); -} - -void -of_scrypt_romix(uint32_t *buffer, size_t blockSize, size_t costFactor, - uint32_t *tmp) -{ - /* Check defined here and executed in of_scrypt() */ -#define OVERFLOW_CHECK_2 \ - if (param.blockSize > SIZE_MAX / 128 / param.costFactor) \ - @throw [OFOutOfRangeException exception]; - - uint32_t *tmp2 = tmp + 32 * blockSize; - - memcpy(tmp, buffer, 128 * blockSize); - - for (size_t i = 0; i < costFactor; i++) { - memcpy(tmp2 + i * 32 * blockSize, tmp, 128 * blockSize); - of_scrypt_block_mix(tmp, tmp2 + i * 32 * blockSize, blockSize); - } - - for (size_t i = 0; i < costFactor; i++) { - uint32_t j = OF_BSWAP32_IF_BE(tmp[(2 * blockSize - 1) * 16]) & - (costFactor - 1); - - for (size_t k = 0; k < 32 * blockSize; k++) - tmp[k] ^= tmp2[j * 32 * blockSize + k]; - - of_scrypt_block_mix(buffer, tmp, blockSize); - - if (i < costFactor - 1) - memcpy(tmp, buffer, 128 * blockSize); - } -} - -void -of_scrypt(of_scrypt_parameters_t param) -{ - OFSecureData *tmp = nil, *buffer = nil; - OFHMAC *HMAC = nil; - - if (param.blockSize == 0 || param.costFactor <= 1 || - (param.costFactor & (param.costFactor - 1)) != 0 || - param.parallelization == 0) - @throw [OFInvalidArgumentException exception]; - - /* - * These are defined by the functions above. They are defined there so - * that the check is next to the code and easy to verify, but actually - * checked here for performance. - */ - OVERFLOW_CHECK_1 - OVERFLOW_CHECK_2 - - @try { - uint32_t *tmpItems, *bufferItems; - - if (param.costFactor > SIZE_MAX - 1 || - (param.costFactor + 1) > SIZE_MAX / 128) - @throw [OFOutOfRangeException exception]; - - tmp = [[OFSecureData alloc] - initWithItemSize: param.blockSize - count: (param.costFactor + 1) * 128 - allowsSwappableMemory: param.allowsSwappableMemory]; - tmpItems = tmp.mutableItems; - - if (param.parallelization > SIZE_MAX / 128) - @throw [OFOutOfRangeException exception]; - - buffer = [[OFSecureData alloc] - initWithItemSize: param.blockSize - count: param.parallelization * 128 - allowsSwappableMemory: param.allowsSwappableMemory]; - bufferItems = buffer.mutableItems; - - HMAC = [[OFHMAC alloc] - initWithHashClass: [OFSHA256Hash class] - allowsSwappableMemory: param.allowsSwappableMemory]; - - of_pbkdf2((of_pbkdf2_parameters_t){ - .HMAC = HMAC, - .iterations = 1, - .salt = param.salt, - .saltLength = param.saltLength, - .password = param.password, - .passwordLength = param.passwordLength, - .key = (unsigned char *)bufferItems, - .keyLength = param.parallelization * 128 * - param.blockSize, - .allowsSwappableMemory = param.allowsSwappableMemory - }); - - for (size_t i = 0; i < param.parallelization; i++) - of_scrypt_romix(bufferItems + i * 32 * param.blockSize, - param.blockSize, param.costFactor, tmpItems); - - of_pbkdf2((of_pbkdf2_parameters_t){ - .HMAC = HMAC, - .iterations = 1, - .salt = (unsigned char *)bufferItems, - .saltLength = param.parallelization * 128 * - param.blockSize, - .password = param.password, - .passwordLength = param.passwordLength, - .key = param.key, - .keyLength = param.keyLength, - .allowsSwappableMemory = param.allowsSwappableMemory - }); - } @finally { - [tmp release]; - [buffer release]; - [HMAC release]; - } -} DELETED src/socket.h Index: src/socket.h ================================================================== --- src/socket.h +++ /dev/null @@ -1,314 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "objfw-defs.h" - -#ifndef OF_HAVE_SOCKETS -# error No sockets available! -#endif - -#include - -#import "OFString.h" - -#ifdef OF_HAVE_SYS_SOCKET_H -# include -#endif -#ifdef OF_HAVE_NETINET_IN_H -# include -#endif -#ifdef OF_HAVE_NETINET_TCP_H -# include -#endif -#ifdef OF_HAVE_NETINET_SCTP_H -# include -#endif -#ifdef OF_HAVE_NETIPX_IPX_H -# include -#endif - -#include "platform.h" - -#ifdef OF_WINDOWS -# include -# include -# ifdef OF_HAVE_IPX -# include -# endif -#endif - -/** @file */ - -#ifdef OF_WII -# include -#endif - -#ifdef OF_PSP -# include -#endif - -#import "macros.h" -#if defined(OF_HAVE_THREADS) && defined(OF_AMIGAOS) -# import "tlskey.h" -#endif - -OF_ASSUME_NONNULL_BEGIN - -#ifndef OF_WINDOWS -typedef int of_socket_t; -#else -typedef SOCKET of_socket_t; -#endif - -#ifdef OF_WII -typedef u8 sa_family_t; -#endif - -#ifdef OF_MORPHOS -typedef long socklen_t; -typedef u_char sa_family_t; -typedef u_short in_port_t; -#endif - -#ifdef OF_MORPHOS_IXEMUL -typedef int socklen_t; -#endif - -/** - * @brief A socket address family. - */ -typedef enum { - /** An unknown address family. */ - OF_SOCKET_ADDRESS_FAMILY_UNKNOWN, - /** IPv4 */ - OF_SOCKET_ADDRESS_FAMILY_IPV4, - /** IPv6 */ - OF_SOCKET_ADDRESS_FAMILY_IPV6, - /** IPX */ - OF_SOCKET_ADDRESS_FAMILY_IPX, - /** Any address family */ - OF_SOCKET_ADDRESS_FAMILY_ANY = 255 -} of_socket_address_family_t; - -#ifndef OF_HAVE_IPV6 -struct sockaddr_in6 { - sa_family_t sin6_family; - in_port_t sin6_port; - uint32_t sin6_flowinfo; - struct in6_addr { - uint8_t s6_addr[16]; - } sin6_addr; - uint32_t sin6_scope_id; -}; -#endif - -#ifndef OF_HAVE_IPX -# define IPX_NODE_LEN 6 -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 -# 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 -#endif - -/** - * @struct of_socket_address_t socket.h ObjFW/socket.h - * - * @brief A struct which represents a host / port pair for a socket. - */ -struct OF_BOXABLE of_socket_address_t { - /* - * Even though struct sockaddr contains the family, we need to use our - * own family, as we need to support storing an IPv6 address on systems - * that don't support IPv6. These may not have AF_INET6 defined and we - * can't just define it, as the value is system-dependent and might - * clash with an existing value. - */ - of_socket_address_family_t family; - union { - struct sockaddr sockaddr; - struct sockaddr_in in; - struct sockaddr_in6 in6; - struct sockaddr_ipx ipx; - } sockaddr; - socklen_t length; -}; -typedef struct of_socket_address_t of_socket_address_t; - -#ifdef __cplusplus -extern "C" { -#endif -/** - * @brief Parses the specified IP and port into an of_socket_address_t. - * - * @param IP The IP to parse - * @param port The port to use - * @return The parsed IP and port as an of_socket_address_t - */ -extern of_socket_address_t of_socket_address_parse_ip( - OFString *IP, uint16_t port); - -/** - * @brief Parses the specified IPv4 and port into an of_socket_address_t. - * - * @param IP The IPv4 to parse - * @param port The port to use - * @return The parsed IPv4 and port as an of_socket_address_t - */ -extern of_socket_address_t of_socket_address_parse_ipv4( - OFString *IP, uint16_t port); - -/** - * @brief Parses the specified IPv6 and port into an of_socket_address_t. - * - * @param IP The IPv6 to parse - * @param port The port to use - * @return The parsed IPv6 and port as an of_socket_address_t - */ -extern of_socket_address_t of_socket_address_parse_ipv6( - OFString *IP, uint16_t port); - -/** - * @brief Creates an IPX address for the specified network, node and port. - * - * @param node The node in the IPX network - * @param network The IPX network - * @param port The IPX port (sometimes called socket number) on the node - */ -extern of_socket_address_t of_socket_address_ipx( - const unsigned char node[_Nonnull IPX_NODE_LEN], uint32_t network, - uint16_t port); - -/** - * @brief Compares two of_socket_address_t for equality. - * - * @param address1 The address to compare with the second address - * @param address2 The second address - * @return Whether the two addresses are equal - */ -extern bool of_socket_address_equal( - const of_socket_address_t *_Nonnull address1, - const of_socket_address_t *_Nonnull address2); - -/** - * @brief Returns the hash for the specified of_socket_address_t. - * - * @param address The address to hash - * @return The hash for the specified of_socket_address_t - */ -extern unsigned long of_socket_address_hash( - const of_socket_address_t *_Nonnull address); - -/** - * @brief Converts the specified of_socket_address_t to an IP string and port. - * - * @param address The address to convert to a string - * @param port A pointer to an uint16_t which should be set to the port of the - * address or NULL if the port is not needed - * @return The address as an IP string - */ -extern OFString *_Nonnull of_socket_address_ip_string( - const of_socket_address_t *_Nonnull address, uint16_t *_Nullable port); - -/** - * @brief Sets the port of the specified of_socket_address_t, independent of - * the address family used. - * - * @param address The address on which to set the port - * @param port The port to set on the address - */ -extern void of_socket_address_set_port(of_socket_address_t *_Nonnull address, - uint16_t port); - -/** - * @brief Returns the port of the specified of_socket_address_t, independent of - * the address family used. - * - * @param address The address on which to get the port - * @return The port of the address - */ -extern uint16_t of_socket_address_get_port( - const of_socket_address_t *_Nonnull address); - -/** - * @brief Sets the IPX network of the specified of_socket_address_t. - * - * @param address The address on which to set the IPX network - * @param network The IPX network to set on the address - */ -extern void of_socket_address_set_ipx_network( - of_socket_address_t *_Nonnull address, uint32_t network); - -/** - * @brief Returns the IPX network of the specified of_socket_address_t. - * - * @param address The address on which to get the IPX network - * @return The IPX network of the address - */ -extern uint32_t of_socket_address_get_ipx_network( - const of_socket_address_t *_Nonnull address); - -/** - * @brief Sets the IPX node of the specified of_socket_address_t. - * - * @param address The address on which to set the IPX node - * @param node The IPX node to set on the address - */ -extern void of_socket_address_set_ipx_node( - of_socket_address_t *_Nonnull address, - const unsigned char node[_Nonnull IPX_NODE_LEN]); - -/** - * @brief Gets the IPX node of the specified of_socket_address_t. - * - * @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 of_socket_address_get_ipx_node( - const of_socket_address_t *_Nonnull address, - unsigned char node[_Nonnull IPX_NODE_LEN]); - -extern bool of_socket_init(void); -#if defined(OF_HAVE_THREADS) && defined(OF_AMIGAOS) -extern void of_socket_deinit(void); -#endif -extern int of_socket_errno(void); -#if !defined(OF_WII) && !defined(OF_NINTENDO_3DS) -extern int of_getsockname(of_socket_t sock, struct sockaddr *restrict addr, - socklen_t *restrict addrLen); -#endif - -#if defined(OF_HAVE_THREADS) && defined(OF_AMIGAOS) -extern of_tlskey_t of_socket_base_key; -# ifdef OF_AMIGAOS4 -extern of_tlskey_t of_socket_interface_key; -# endif -#endif -#ifdef __cplusplus -} -#endif - -OF_ASSUME_NONNULL_END DELETED src/socket.m Index: src/socket.m ================================================================== --- src/socket.m +++ /dev/null @@ -1,853 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 OF_NINTENDO_3DS -# include /* For memalign() */ -#endif - -#include - -#import "OFArray.h" -#import "OFCharacterSet.h" -#import "OFLocale.h" -#import "OFString.h" - -#import "OFException.h" /* For some E* -> WSAE* defines */ -#import "OFInitializationFailedException.h" -#import "OFInvalidArgumentException.h" -#import "OFInvalidFormatException.h" -#import "OFLockFailedException.h" -#import "OFUnlockFailedException.h" - -#import "socket.h" -#import "socket_helpers.h" -#ifdef OF_HAVE_THREADS -# ifndef OF_AMIGAOS -# import "mutex.h" -# else -# import "tlskey.h" -# endif -#endif -#import "once.h" - -#ifdef OF_AMIGAOS -# include -#endif - -#ifdef OF_NINTENDO_3DS -# include <3ds/types.h> -# include <3ds/services/soc.h> -#endif - -#if defined(OF_HAVE_THREADS) && !defined(OF_AMIGAOS) -static of_mutex_t mutex; -#endif -#if !defined(OF_AMIGAOS) || !defined(OF_HAVE_THREADS) -static bool initSuccessful = false; -#else -# ifdef OF_HAVE_THREADS -of_tlskey_t of_socket_base_key; -# ifdef OF_AMIGAOS4 -of_tlskey_t of_socket_interface_key; -# endif -# else -struct Library *SocketBase; -# ifdef OF_AMIGAOS4 -struct SocketIFace *ISocket = NULL; -# endif -# endif -#endif - -#if defined(OF_HAVE_THREADS) && defined(OF_AMIGAOS) -OF_CONSTRUCTOR() -{ - if (!of_tlskey_new(&of_socket_base_key)) - @throw [OFInitializationFailedException exception]; - -# ifdef OF_AMIGAOS4 - if (!of_tlskey_new(&of_socket_interface_key)) - @throw [OFInitializationFailedException exception]; -# endif -} -#endif - -#if !defined(OF_AMIGAOS) || !defined(OF_HAVE_THREADS) -static void -init(void) -{ -# if defined(OF_WINDOWS) - WSADATA wsa; - - if (WSAStartup(MAKEWORD(2, 0), &wsa)) - return; -# elif defined(OF_AMIGAOS) - if ((SocketBase = OpenLibrary("bsdsocket.library", 4)) == NULL) - return; - -# ifdef OF_AMIGAOS4 - if ((ISocket = (struct SocketIFace *) - GetInterface(SocketBase, "main", 1, NULL)) == NULL) { - CloseLibrary(SocketBase); - return; - } -# endif -# elif defined(OF_WII) - if (net_init() < 0) - return; -# elif defined(OF_NINTENDO_3DS) - void *ctx; - - if ((ctx = memalign(0x1000, 0x100000)) == NULL) - return; - - if (socInit(ctx, 0x100000) != 0) - return; - - atexit((void (*)(void))socExit); -# endif - -# if defined(OF_HAVE_THREADS) && !defined(OF_AMIGAOS) - if (!of_mutex_new(&mutex)) - return; - -# ifdef OF_WII - if (!of_spinlock_new(&spinlock)) - return; -# endif -# endif - - initSuccessful = true; -} - -# ifdef OF_AMIGAOS -OF_DESTRUCTOR() -{ -# ifdef OF_AMIGAOS4 - if (ISocket != NULL) - DropInterface((struct Interface *)ISocket); -# endif - - if (SocketBase != NULL) - CloseLibrary(SocketBase); -} -# endif -#endif - -bool -of_socket_init(void) -{ -#if !defined(OF_AMIGAOS) || !defined(OF_HAVE_THREADS) - static of_once_t onceControl = OF_ONCE_INIT; - of_once(&onceControl, init); - - return initSuccessful; -#else - struct Library *socketBase; -# ifdef OF_AMIGAOS4 - struct SocketIFace *socketInterface; -# endif - -# ifdef OF_AMIGAOS4 - if ((socketInterface = of_tlskey_get(of_socket_interface_key)) != NULL) -# else - if ((socketBase = of_tlskey_get(of_socket_base_key)) != NULL) -# endif - return true; - - if ((socketBase = OpenLibrary("bsdsocket.library", 4)) == NULL) - return false; - -# ifdef OF_AMIGAOS4 - if ((socketInterface = (struct SocketIFace *) - GetInterface(socketBase, "main", 1, NULL)) == NULL) { - CloseLibrary(socketBase); - return false; - } -# endif - - if (!of_tlskey_set(of_socket_base_key, socketBase)) { - CloseLibrary(socketBase); -# ifdef OF_AMIGAOS4 - DropInterface((struct Interface *)socketInterface); -# endif - return false; - } - -# ifdef OF_AMIGAOS4 - if (!of_tlskey_set(of_socket_interface_key, socketInterface)) { - CloseLibrary(socketBase); - DropInterface((struct Interface *)socketInterface); - return false; - } -# endif - - return true; -#endif -} - -#if defined(OF_HAVE_THREADS) && defined(OF_AMIGAOS) -void -of_socket_deinit(void) -{ - struct Library *socketBase = of_tlskey_get(of_socket_base_key); -# ifdef OF_AMIGAOS4 - struct SocketIFace *socketInterface = - of_tlskey_get(of_socket_interface_key); - - if (socketInterface != NULL) - DropInterface((struct Interface *)socketInterface); -# endif - if (socketBase != NULL) - CloseLibrary(socketBase); -} -#endif - -int -of_socket_errno() -{ -#if defined(OF_WINDOWS) - switch (WSAGetLastError()) { - case WSAEACCES: - return EACCES; - case WSAEADDRINUSE: - return EADDRINUSE; - case WSAEADDRNOTAVAIL: - return EADDRNOTAVAIL; - case WSAEAFNOSUPPORT: - return EAFNOSUPPORT; - case WSAEALREADY: - return EALREADY; - case WSAEBADF: - return EBADF; - case WSAECONNABORTED: - return ECONNABORTED; - case WSAECONNREFUSED: - return ECONNREFUSED; - case WSAECONNRESET: - return ECONNRESET; - case WSAEDESTADDRREQ: - return EDESTADDRREQ; - case WSAEDISCON: - return EPIPE; - case WSAEDQUOT: - return EDQUOT; - case WSAEFAULT: - return EFAULT; - case WSAEHOSTDOWN: - return EHOSTDOWN; - case WSAEHOSTUNREACH: - return EHOSTUNREACH; - case WSAEINPROGRESS: - return EINPROGRESS; - case WSAEINTR: - return EINTR; - case WSAEINVAL: - return EINVAL; - case WSAEISCONN: - return EISCONN; - case WSAELOOP: - return ELOOP; - case WSAEMSGSIZE: - return EMSGSIZE; - case WSAENAMETOOLONG: - return ENAMETOOLONG; - case WSAENETDOWN: - return ENETDOWN; - case WSAENETRESET: - return ENETRESET; - case WSAENETUNREACH: - return ENETUNREACH; - case WSAENOBUFS: - return ENOBUFS; - case WSAENOPROTOOPT: - return ENOPROTOOPT; - case WSAENOTCONN: - return ENOTCONN; - case WSAENOTEMPTY: - return ENOTEMPTY; - case WSAENOTSOCK: - return ENOTSOCK; - case WSAEOPNOTSUPP: - return EOPNOTSUPP; - case WSAEPFNOSUPPORT: - return EPFNOSUPPORT; - case WSAEPROCLIM: - return EPROCLIM; - case WSAEPROTONOSUPPORT: - return EPROTONOSUPPORT; - case WSAEPROTOTYPE: - return EPROTOTYPE; - case WSAEREMOTE: - return EREMOTE; - case WSAESHUTDOWN: - return ESHUTDOWN; - case WSAESOCKTNOSUPPORT: - return ESOCKTNOSUPPORT; - case WSAESTALE: - return ESTALE; - case WSAETIMEDOUT: - return ETIMEDOUT; - case WSAETOOMANYREFS: - return ETOOMANYREFS; - case WSAEUSERS: - return EUSERS; - case WSAEWOULDBLOCK: - return EWOULDBLOCK; - } - - return 0; -#elif defined(OF_AMIGAOS) - return Errno(); -#else - return errno; -#endif -} - -#ifndef OF_WII -int -of_getsockname(of_socket_t sock, struct sockaddr *restrict addr, - socklen_t *restrict addrLen) -{ - int ret; - -# if defined(OF_HAVE_THREADS) && !defined(OF_AMIGAOS) - if (!of_mutex_lock(&mutex)) - @throw [OFLockFailedException exception]; - -# endif - - ret = getsockname(sock, addr, addrLen); - -# if defined(OF_HAVE_THREADS) && !defined(OF_AMIGAOS) - if (!of_mutex_unlock(&mutex)) - @throw [OFUnlockFailedException exception]; -# endif - - return ret; -} -#endif - -of_socket_address_t -of_socket_address_parse_ipv4(OFString *IPv4, uint16_t port) -{ - void *pool = objc_autoreleasePoolPush(); - OFCharacterSet *whitespaceCharacterSet = - [OFCharacterSet whitespaceCharacterSet]; - of_socket_address_t ret; - struct sockaddr_in *addrIn = &ret.sockaddr.in; - OFArray OF_GENERIC(OFString *) *components; - uint32_t addr; - - memset(&ret, '\0', sizeof(ret)); - ret.family = OF_SOCKET_ADDRESS_FAMILY_IPV4; -#if defined(OF_WII) || defined(OF_NINTENDO_3DS) - ret.length = 8; -#else - ret.length = sizeof(ret.sockaddr.in); -#endif - - addrIn->sin_family = AF_INET; - addrIn->sin_port = OF_BSWAP16_IF_LE(port); -#ifdef OF_WII - addrIn->sin_len = ret.length; -#endif - - components = [IPv4 componentsSeparatedByString: @"."]; - - if (components.count != 4) - @throw [OFInvalidFormatException exception]; - - addr = 0; - - for (OFString *component in components) { - unsigned long long number; - - if (component.length == 0) - @throw [OFInvalidFormatException exception]; - - if ([component indexOfCharacterFromSet: - whitespaceCharacterSet] != OF_NOT_FOUND) - @throw [OFInvalidFormatException exception]; - - number = component.unsignedLongLongValue; - - if (number > UINT8_MAX) - @throw [OFInvalidFormatException exception]; - - addr = (addr << 8) | ((uint32_t)number & 0xFF); - } - - addrIn->sin_addr.s_addr = OF_BSWAP32_IF_LE(addr); - - objc_autoreleasePoolPop(pool); - - return ret; -} - -static uint16_t -parseIPv6Component(OFString *component) -{ - unsigned long long number; - - if ([component indexOfCharacterFromSet: - [OFCharacterSet whitespaceCharacterSet]] != OF_NOT_FOUND) - @throw [OFInvalidFormatException exception]; - - number = [component unsignedLongLongValueWithBase: 16]; - - if (number > UINT16_MAX) - @throw [OFInvalidFormatException exception]; - - return (uint16_t)number; -} - -of_socket_address_t -of_socket_address_parse_ipv6(OFString *IPv6, uint16_t port) -{ - void *pool = objc_autoreleasePoolPush(); - of_socket_address_t ret; - struct sockaddr_in6 *addrIn6 = &ret.sockaddr.in6; - size_t doubleColon; - - memset(&ret, '\0', sizeof(ret)); - ret.family = OF_SOCKET_ADDRESS_FAMILY_IPV6; - ret.length = sizeof(ret.sockaddr.in6); - -#ifdef AF_INET6 - addrIn6->sin6_family = AF_INET6; -#else - addrIn6->sin6_family = AF_UNSPEC; -#endif - addrIn6->sin6_port = OF_BSWAP16_IF_LE(port); - - doubleColon = [IPv6 rangeOfString: @"::"].location; - - if (doubleColon != OF_NOT_FOUND) { - OFString *left = [IPv6 substringToIndex: doubleColon]; - OFString *right = [IPv6 substringFromIndex: doubleColon + 2]; - OFArray OF_GENERIC(OFString *) *leftComponents; - OFArray OF_GENERIC(OFString *) *rightComponents; - size_t i; - - if ([right hasPrefix: @":"] || [right containsString: @"::"]) - @throw [OFInvalidFormatException exception]; - - leftComponents = [left componentsSeparatedByString: @":"]; - rightComponents = [right componentsSeparatedByString: @":"]; - - if (leftComponents.count + rightComponents.count > 7) - @throw [OFInvalidFormatException exception]; - - i = 0; - for (OFString *component in leftComponents) { - uint16_t number = parseIPv6Component(component); - - addrIn6->sin6_addr.s6_addr[i++] = number >> 8; - addrIn6->sin6_addr.s6_addr[i++] = number; - } - - i = 16; - for (OFString *component in rightComponents.reversedArray) { - uint16_t number = parseIPv6Component(component); - - addrIn6->sin6_addr.s6_addr[--i] = number; - addrIn6->sin6_addr.s6_addr[--i] = number >> 8; - } - } else { - OFArray OF_GENERIC(OFString *) *components = - [IPv6 componentsSeparatedByString: @":"]; - size_t i; - - if (components.count != 8) - @throw [OFInvalidFormatException exception]; - - i = 0; - for (OFString *component in components) { - uint16_t number; - - if (component.length == 0) - @throw [OFInvalidFormatException exception]; - - number = parseIPv6Component(component); - - addrIn6->sin6_addr.s6_addr[i++] = number >> 8; - addrIn6->sin6_addr.s6_addr[i++] = number; - } - } - - objc_autoreleasePoolPop(pool); - - return ret; -} - -of_socket_address_t -of_socket_address_parse_ip(OFString *IP, uint16_t port) -{ - of_socket_address_t ret; - - @try { - ret = of_socket_address_parse_ipv6(IP, port); - } @catch (OFInvalidFormatException *e) { - ret = of_socket_address_parse_ipv4(IP, port); - } - - return ret; -} - -of_socket_address_t -of_socket_address_ipx(const unsigned char node[IPX_NODE_LEN], uint32_t network, - uint16_t port) -{ - of_socket_address_t ret; - - memset(&ret, '\0', sizeof(ret)); - ret.family = OF_SOCKET_ADDRESS_FAMILY_IPX; - ret.length = sizeof(ret.sockaddr.ipx); - -#ifdef AF_IPX - ret.sockaddr.ipx.sipx_family = AF_IPX; -#else - ret.sockaddr.ipx.sipx_family = AF_UNSPEC; -#endif - memcpy(ret.sockaddr.ipx.sipx_node, node, IPX_NODE_LEN); - network = OF_BSWAP32_IF_LE(network); - memcpy(&ret.sockaddr.ipx.sipx_network, &network, - sizeof(ret.sockaddr.ipx.sipx_network)); - ret.sockaddr.ipx.sipx_port = OF_BSWAP16_IF_LE(port); - - return ret; -} - -bool -of_socket_address_equal(const of_socket_address_t *address1, - const of_socket_address_t *address2) -{ - const struct sockaddr_in *addrIn1, *addrIn2; - const struct sockaddr_in6 *addrIn6_1, *addrIn6_2; - const struct sockaddr_ipx *addrIPX1, *addrIPX2; - - if (address1->family != address2->family) - return false; - - switch (address1->family) { - case OF_SOCKET_ADDRESS_FAMILY_IPV4: -#if defined(OF_WII) || defined(OF_NINTENDO_3DS) - if (address1->length < 8 || address2->length < 8) - @throw [OFInvalidArgumentException exception]; -#else - if (address1->length < (socklen_t)sizeof(struct sockaddr_in) || - address2->length < (socklen_t)sizeof(struct sockaddr_in)) - @throw [OFInvalidArgumentException exception]; -#endif - - addrIn1 = &address1->sockaddr.in; - addrIn2 = &address2->sockaddr.in; - - if (addrIn1->sin_port != addrIn2->sin_port) - return false; - if (addrIn1->sin_addr.s_addr != addrIn2->sin_addr.s_addr) - return false; - - break; - case OF_SOCKET_ADDRESS_FAMILY_IPV6: - if (address1->length < (socklen_t)sizeof(struct sockaddr_in6) || - address2->length < (socklen_t)sizeof(struct sockaddr_in6)) - @throw [OFInvalidArgumentException exception]; - - addrIn6_1 = &address1->sockaddr.in6; - addrIn6_2 = &address2->sockaddr.in6; - - if (addrIn6_1->sin6_port != addrIn6_2->sin6_port) - return false; - if (memcmp(addrIn6_1->sin6_addr.s6_addr, - addrIn6_2->sin6_addr.s6_addr, - sizeof(addrIn6_1->sin6_addr.s6_addr)) != 0) - return false; - - break; - case OF_SOCKET_ADDRESS_FAMILY_IPX: - if (address1->length < (socklen_t)sizeof(struct sockaddr_ipx) || - address2->length < (socklen_t)sizeof(struct sockaddr_ipx)) - @throw [OFInvalidArgumentException exception]; - - addrIPX1 = &address1->sockaddr.ipx; - addrIPX2 = &address2->sockaddr.ipx; - - if (addrIPX1->sipx_port != addrIPX2->sipx_port) - return false; - if (memcmp(&addrIPX1->sipx_network, &addrIPX2->sipx_network, - 4) != 0) - return false; - if (memcmp(addrIPX1->sipx_node, addrIPX2->sipx_node, - IPX_NODE_LEN) != 0) - return false; - - break; - default: - @throw [OFInvalidArgumentException exception]; - } - - return true; -} - -unsigned long -of_socket_address_hash(const of_socket_address_t *address) -{ - uint32_t hash; - - OF_HASH_INIT(hash); - OF_HASH_ADD(hash, address->family); - - switch (address->family) { - case OF_SOCKET_ADDRESS_FAMILY_IPV4: -#if defined(OF_WII) || defined(OF_NINTENDO_3DS) - if (address->length < 8) - @throw [OFInvalidArgumentException exception]; -#else - if (address->length < (socklen_t)sizeof(struct sockaddr_in)) - @throw [OFInvalidArgumentException exception]; -#endif - - OF_HASH_ADD(hash, address->sockaddr.in.sin_port >> 8); - OF_HASH_ADD(hash, address->sockaddr.in.sin_port); - OF_HASH_ADD(hash, address->sockaddr.in.sin_addr.s_addr >> 24); - OF_HASH_ADD(hash, address->sockaddr.in.sin_addr.s_addr >> 16); - OF_HASH_ADD(hash, address->sockaddr.in.sin_addr.s_addr >> 8); - OF_HASH_ADD(hash, address->sockaddr.in.sin_addr.s_addr); - - break; - case OF_SOCKET_ADDRESS_FAMILY_IPV6: - if (address->length < (socklen_t)sizeof(struct sockaddr_in6)) - @throw [OFInvalidArgumentException exception]; - - OF_HASH_ADD(hash, address->sockaddr.in6.sin6_port >> 8); - OF_HASH_ADD(hash, address->sockaddr.in6.sin6_port); - - for (size_t i = 0; - i < sizeof(address->sockaddr.in6.sin6_addr.s6_addr); i++) - OF_HASH_ADD(hash, - address->sockaddr.in6.sin6_addr.s6_addr[i]); - - break; - case OF_SOCKET_ADDRESS_FAMILY_IPX:; - unsigned char network[ - sizeof(address->sockaddr.ipx.sipx_network)]; - - if (address->length < (socklen_t)sizeof(struct sockaddr_ipx)) - @throw [OFInvalidArgumentException exception]; - - OF_HASH_ADD(hash, address->sockaddr.ipx.sipx_port >> 8); - OF_HASH_ADD(hash, address->sockaddr.ipx.sipx_port); - - memcpy(network, &address->sockaddr.ipx.sipx_network, - sizeof(network)); - - for (size_t i = 0; i < sizeof(network); i++) - OF_HASH_ADD(hash, network[i]); - - for (size_t i = 0; i < IPX_NODE_LEN; i++) - OF_HASH_ADD(hash, address->sockaddr.ipx.sipx_node[i]); - - break; - default: - @throw [OFInvalidArgumentException exception]; - } - - OF_HASH_FINALIZE(hash); - - return hash; -} - -static OFString * -IPv4String(const of_socket_address_t *address, uint16_t *port) -{ - const struct sockaddr_in *addrIn = &address->sockaddr.in; - uint32_t addr = OF_BSWAP32_IF_LE(addrIn->sin_addr.s_addr); - OFString *string; - - string = [OFString stringWithFormat: @"%u.%u.%u.%u", - (addr & 0xFF000000) >> 24, (addr & 0x00FF0000) >> 16, - (addr & 0x0000FF00) >> 8, addr & 0x000000FF]; - - if (port != NULL) - *port = OF_BSWAP16_IF_LE(addrIn->sin_port); - - return string; -} - -static OFString * -IPv6String(const of_socket_address_t *address, uint16_t *port) -{ - OFMutableString *string = [OFMutableString string]; - const struct sockaddr_in6 *addrIn6 = &address->sockaddr.in6; - int_fast8_t zerosStart = -1, maxZerosStart = -1; - uint_fast8_t zerosCount = 0, maxZerosCount = 0; - bool first = true; - - for (uint_fast8_t i = 0; i < 16; i += 2) { - if (addrIn6->sin6_addr.s6_addr[i] == 0 && - addrIn6->sin6_addr.s6_addr[i + 1] == 0) { - if (zerosStart >= 0) - zerosCount++; - else { - zerosStart = i; - zerosCount = 1; - } - } else { - if (zerosCount > maxZerosCount) { - maxZerosStart = zerosStart; - maxZerosCount = zerosCount; - } - - zerosStart = -1; - } - } - if (zerosCount > maxZerosCount) { - maxZerosStart = zerosStart; - maxZerosCount = zerosCount; - } - - if (maxZerosCount >= 2) { - for (int_fast8_t i = 0; i < maxZerosStart; i += 2) { - [string appendFormat: - (first ? @"%x" : @":%x"), - (addrIn6->sin6_addr.s6_addr[(uint_fast8_t)i] << 8) | - addrIn6->sin6_addr.s6_addr[(uint_fast8_t)i + 1]]; - first = false; - } - - [string appendString: @"::"]; - first = true; - - for (int_fast8_t i = maxZerosStart + (maxZerosCount * 2); - i < 16; i += 2) { - [string appendFormat: - (first ? @"%x" : @":%x"), - (addrIn6->sin6_addr.s6_addr[(uint_fast8_t)i] << 8) | - addrIn6->sin6_addr.s6_addr[(uint_fast8_t)i + 1]]; - first = false; - } - } else { - for (uint_fast8_t i = 0; i < 16; i += 2) { - [string appendFormat: - (first ? @"%x" : @":%x"), - (addrIn6->sin6_addr.s6_addr[i] << 8) | - addrIn6->sin6_addr.s6_addr[i + 1]]; - first = false; - } - } - - [string makeImmutable]; - - if (port != NULL) - *port = OF_BSWAP16_IF_LE(addrIn6->sin6_port); - - return string; -} - -OFString * -of_socket_address_ip_string(const of_socket_address_t *address, uint16_t *port) -{ - switch (address->family) { - case OF_SOCKET_ADDRESS_FAMILY_IPV4: - return IPv4String(address, port); - case OF_SOCKET_ADDRESS_FAMILY_IPV6: - return IPv6String(address, port); - default: - @throw [OFInvalidArgumentException exception]; - } -} - -void -of_socket_address_set_port(of_socket_address_t *address, uint16_t port) -{ - switch (address->family) { - case OF_SOCKET_ADDRESS_FAMILY_IPV4: - address->sockaddr.in.sin_port = OF_BSWAP16_IF_LE(port); - break; - case OF_SOCKET_ADDRESS_FAMILY_IPV6: - address->sockaddr.in6.sin6_port = OF_BSWAP16_IF_LE(port); - break; - case OF_SOCKET_ADDRESS_FAMILY_IPX: - address->sockaddr.ipx.sipx_port = OF_BSWAP16_IF_LE(port); - break; - default: - @throw [OFInvalidArgumentException exception]; - } -} - -uint16_t -of_socket_address_get_port(const of_socket_address_t *address) -{ - switch (address->family) { - case OF_SOCKET_ADDRESS_FAMILY_IPV4: - return OF_BSWAP16_IF_LE(address->sockaddr.in.sin_port); - case OF_SOCKET_ADDRESS_FAMILY_IPV6: - return OF_BSWAP16_IF_LE(address->sockaddr.in6.sin6_port); - case OF_SOCKET_ADDRESS_FAMILY_IPX: - return OF_BSWAP16_IF_LE(address->sockaddr.ipx.sipx_port); - default: - @throw [OFInvalidArgumentException exception]; - } -} - -void -of_socket_address_set_ipx_network(of_socket_address_t *address, - uint32_t network) -{ - if (address->family != OF_SOCKET_ADDRESS_FAMILY_IPX) - @throw [OFInvalidArgumentException exception]; - - network = OF_BSWAP32_IF_LE(network); - memcpy(&address->sockaddr.ipx.sipx_network, &network, - sizeof(address->sockaddr.ipx.sipx_network)); -} - -uint32_t -of_socket_address_get_ipx_network(const of_socket_address_t *address) -{ - uint32_t network; - - if (address->family != OF_SOCKET_ADDRESS_FAMILY_IPX) - @throw [OFInvalidArgumentException exception]; - - memcpy(&network, &address->sockaddr.ipx.sipx_network, sizeof(network)); - - return OF_BSWAP32_IF_LE(network); -} - -void -of_socket_address_set_ipx_node(of_socket_address_t *address, - const unsigned char node[IPX_NODE_LEN]) -{ - if (address->family != OF_SOCKET_ADDRESS_FAMILY_IPX) - @throw [OFInvalidArgumentException exception]; - - memcpy(address->sockaddr.ipx.sipx_node, node, IPX_NODE_LEN); -} - -void -of_socket_address_get_ipx_node(const of_socket_address_t *address, - unsigned char node[IPX_NODE_LEN]) -{ - if (address->family != OF_SOCKET_ADDRESS_FAMILY_IPX) - @throw [OFInvalidArgumentException exception]; - - memcpy(node, address->sockaddr.ipx.sipx_node, IPX_NODE_LEN); -} DELETED src/socket_helpers.h Index: src/socket_helpers.h ================================================================== --- src/socket_helpers.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "unistd_wrapper.h" - -#ifdef HAVE_ARPA_INET_H -# include -#endif -#ifdef HAVE_NETDB_H -# include -#endif - -#include "socket.h" - -#ifndef INVALID_SOCKET -# define INVALID_SOCKET -1 -#endif - -#ifndef INADDR_NONE -# define INADDR_NONE ((in_addr_t)-1) -#endif - -#ifndef SOMAXCONN -/* - * Use 16 as everything > 17 fails on Nintendo 3DS and 16 is a less arbitrary - * number than 17. - */ -# define SOMAXCONN 16 -#endif - -#ifndef SOCK_CLOEXEC -# define SOCK_CLOEXEC 0 -#endif - -#if defined(OF_AMIGAOS) -# ifdef OF_MORPHOS -# include -# else -# include -# endif -# include -# define closesocket(sock) CloseSocket(sock) -# define ioctlsocket(fd, req, arg) IoctlSocket(fd, req, arg) -# define hstrerror(err) "unknown (no hstrerror)" -# define SOCKET_ERROR -1 -# ifdef OF_HAVE_THREADS -# define SocketBase ((struct Library *)of_tlskey_get(of_socket_base_key)) -# ifdef OF_AMIGAOS4 -# define ISocket \ - ((struct SocketIFace *)of_tlskey_get(of_socket_interface_key)) -# endif -# endif -# ifdef OF_MORPHOS -typedef uint32_t in_addr_t; -# endif -#elif !defined(OF_WINDOWS) && !defined(OF_WII) -# define closesocket(sock) close(sock) -#endif - -#ifdef OF_MORPHOS_IXEMUL -typedef uint32_t in_addr_t; -#endif - -#ifdef OF_WII -# define accept(sock, addr, addrlen) net_accept(sock, addr, addrlen) -# define bind(sock, addr, addrlen) net_bind(sock, addr, addrlen) -# define closesocket(sock) net_close(sock) -# define connect(sock, addr, addrlen) \ - net_connect(sock, (struct sockaddr *)addr, addrlen) -# define fcntl(fd, cmd, flags) net_fcntl(fd, cmd, flags) -# define h_errno 0 -# define hstrerror(err) "unknown (no hstrerror)" -# define listen(sock, backlog) net_listen(sock, backlog) -# define poll(fds, nfds, timeout) net_poll(fds, nfds, timeout) -# define recv(sock, buf, len, flags) net_recv(sock, buf, len, flags) -# define recvfrom(sock, buf, len, flags, addr, addrlen) \ - net_recvfrom(sock, buf, len, flags, addr, addrlen) -# define select(nfds, readfds, writefds, errorfds, timeout) \ - net_select(nfds, readfds, writefds, errorfds, timeout) -# define send(sock, buf, len, flags) net_send(sock, buf, len, flags) -# define sendto(sock, buf, len, flags, addr, addrlen) \ - net_sendto(sock, buf, len, flags, (struct sockaddr *)(addr), addrlen) -# define setsockopt(sock, level, name, value, len) \ - net_setsockopt(sock, level, name, value, len) -# define socket(domain, type, proto) net_socket(domain, type, proto) -typedef u32 in_addr_t; -typedef u32 nfds_t; -#endif DELETED src/thread.h Index: src/thread.h ================================================================== --- src/thread.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "objfw-defs.h" - -#include "platform.h" - -#if !defined(OF_HAVE_THREADS) || \ - (!defined(OF_HAVE_PTHREADS) && !defined(OF_WINDOWS) && !defined(OF_AMIGAOS)) -# error No threads available! -#endif - -#import "macros.h" - -#if defined(OF_HAVE_PTHREADS) -# include -typedef pthread_t of_thread_t; -#elif defined(OF_WINDOWS) -# include -typedef HANDLE of_thread_t; -#elif defined(OF_AMIGAOS) -# include -# include -typedef struct { - struct Task *task; - void (*function)(id); - id object; - struct SignalSemaphore semaphore; - struct Task *joinTask; - unsigned char joinSigBit; - bool detached, done; -} *of_thread_t; -#endif - -typedef struct of_thread_attr_t { - float priority; - size_t stackSize; -} of_thread_attr_t; - -#if defined(OF_HAVE_PTHREADS) -# define of_thread_is_current(t) pthread_equal(t, pthread_self()) -# define of_thread_current() pthread_self() -#elif defined(OF_WINDOWS) -# define of_thread_is_current(t) (t == GetCurrentThread()) -# define of_thread_current() GetCurrentThread() -#elif defined(OF_AMIGAOS) -# define of_thread_is_current(t) (t->thread == FindTask(NULL)) -extern of_thread_t of_thread_current(void); -#endif - -#ifdef __cplusplus -extern "C" { -#endif -extern bool of_thread_attr_init(of_thread_attr_t *attr); -extern bool of_thread_new(of_thread_t *thread, const char *name, - void (*function)(id), id object, const of_thread_attr_t *attr); -extern void of_thread_set_name(const char *name); -extern bool of_thread_join(of_thread_t thread); -extern bool of_thread_detach(of_thread_t thread); -#ifdef __cplusplus -} -#endif DELETED src/thread.m Index: src/thread.m ================================================================== --- src/thread.m +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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" - -#if defined(OF_HAVE_PTHREADS) -# include "platform/posix/thread.m" -#elif defined(OF_WINDOWS) -# include "platform/windows/thread.m" -#elif defined(OF_AMIGAOS) -# include "platform/amiga/thread.m" -#endif ADDED src/tls/Info.plist.in Index: src/tls/Info.plist.in ================================================================== --- /dev/null +++ src/tls/Info.plist.in @@ -0,0 +1,22 @@ + + + + + CFBundleExecutable + ObjFWTLS + CFBundleName + ObjFWTLS + CFBundleIdentifier + im.nil.objfw.tls + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + FMWK + CFBundleVersion + @BUNDLE_VERSION@ + CFBundleShortVersionString + @BUNDLE_SHORT_VERSION@ + MinimumOSVersion + 9.0 + + ADDED src/tls/Makefile Index: src/tls/Makefile ================================================================== --- /dev/null +++ src/tls/Makefile @@ -0,0 +1,23 @@ +include ../../extra.mk + +DISTCLEAN = Info.plist + +SHARED_LIB = ${OBJFWTLS_SHARED_LIB} +STATIC_LIB = ${OBJFWTLS_STATIC_LIB} +FRAMEWORK = ${OBJFWTLS_FRAMEWORK} +LIB_MAJOR = ${OBJFW_LIB_MAJOR} +LIB_MINOR = ${OBJFW_LIB_MINOR} + +INCLUDES := ObjFWTLS.h +SRCS = ${OF_GNUTLS_TLS_STREAM_M} \ + ${OF_OPENSSL_TLS_STREAM_M} \ + ${OF_SECURE_TRANSPORT_TLS_STREAM_M} + +includesubdir = ObjFWTLS + +include ../../buildsys.mk + +CPPFLAGS += -I. -I.. -I../.. -I../exceptions -I../runtime ${TLS_CPPFLAGS} +LD = ${OBJC} +FRAMEWORK_LIBS := ${TLS_LIBS} -F.. -framework ObjFW ${LIBS} +LIBS := ${TLS_LIBS} -L.. -lobjfw -L../runtime ${RUNTIME_LIBS} ${LIBS} ADDED src/tls/OFGnuTLSTLSStream.h Index: src/tls/OFGnuTLSTLSStream.h ================================================================== --- /dev/null +++ src/tls/OFGnuTLSTLSStream.h @@ -0,0 +1,30 @@ +/* + * 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 "OFTLSStream.h" + +#include + +OF_ASSUME_NONNULL_BEGIN + +@interface OFGnuTLSTLSStream: OFTLSStream +{ + bool _initialized, _handshakeDone; + gnutls_session_t _session; + OFString *_host; +} +@end + +OF_ASSUME_NONNULL_END ADDED src/tls/OFGnuTLSTLSStream.m Index: src/tls/OFGnuTLSTLSStream.m ================================================================== --- /dev/null +++ src/tls/OFGnuTLSTLSStream.m @@ -0,0 +1,356 @@ +/* + * 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 "OFGnuTLSTLSStream.h" +#import "OFData.h" + +#import "OFAlreadyConnectedException.h" +#import "OFInitializationFailedException.h" +#import "OFNotOpenException.h" +#import "OFReadFailedException.h" +#import "OFTLSHandshakeFailedException.h" +#import "OFWriteFailedException.h" + +int _ObjFWTLS_reference; +static gnutls_certificate_credentials_t systemTrustCreds; + +#ifndef GNUTLS_SAFE_PADDING_CHECK +/* Some older versions don't have it. */ +# define GNUTLS_SAFE_PADDING_CHECK 0 +#endif + +@implementation OFGnuTLSTLSStream +static ssize_t +readFunc(gnutls_transport_ptr_t transport, void *buffer, size_t length) +{ + OFGnuTLSTLSStream *stream = (OFGnuTLSTLSStream *)transport; + + @try { + length = [stream.underlyingStream readIntoBuffer: buffer + length: length]; + } @catch (OFReadFailedException *e) { + gnutls_transport_set_errno(stream->_session, e.errNo); + return -1; + } + + if (length == 0 && !stream.underlyingStream.atEndOfStream) { + gnutls_transport_set_errno(stream->_session, EAGAIN); + return -1; + } + + return length; +} + +static ssize_t +writeFunc(gnutls_transport_ptr_t transport, const void *buffer, size_t length) +{ + OFGnuTLSTLSStream *stream = (OFGnuTLSTLSStream *)transport; + + @try { + [stream.underlyingStream writeBuffer: buffer length: length]; + } @catch (OFWriteFailedException *e) { + gnutls_transport_set_errno(stream->_session, e.errNo); + + if (e.errNo == EWOULDBLOCK || e.errNo == EAGAIN) + return e.bytesWritten; + + return -1; + } + + return length; +} + ++ (void)load +{ + if (OFTLSStreamImplementation == Nil) + OFTLSStreamImplementation = self; +} + ++ (void)initialize +{ + if (self != [OFGnuTLSTLSStream class]) + return; + + if (gnutls_certificate_allocate_credentials(&systemTrustCreds) != + GNUTLS_E_SUCCESS || + gnutls_certificate_set_x509_system_trust(systemTrustCreds) < 0) + @throw [OFInitializationFailedException exception]; +} + +- (instancetype)initWithStream: (OFStream *)stream +{ + self = [super initWithStream: stream]; + + @try { + _underlyingStream.delegate = self; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + if (_initialized) + [self close]; + + [_host release]; + + [super dealloc]; +} + +- (void)close +{ + if (!_initialized) + @throw [OFNotOpenException exceptionWithObject: self]; + + if (_handshakeDone) + gnutls_bye(_session, GNUTLS_SHUT_WR); + + gnutls_deinit(_session); + _initialized = false; + + [_host release]; + _host = nil; + + [super close]; +} + +- (size_t)lowlevelReadIntoBuffer: (void *)buffer length: (size_t)length +{ + ssize_t ret; + + if (!_handshakeDone) + @throw [OFNotOpenException exceptionWithObject: self]; + + if ((ret = gnutls_record_recv(_session, buffer, length)) < 0) { + /* + * The underlying stream might have had data ready, but not + * enough for GnuTLS to return decrypted data. This means the + * caller might have observed the TLS stream for reading, got a + * ready signal and read - and expects the read to succeed, not + * to fail with EWOULDBLOCK/EAGAIN, as it was signaled ready. + * Therefore, return 0, as we could read 0 decrypted bytes, but + * cleared the ready signal of the underlying stream. + */ + if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) + return 0; + + /* FIXME: Translate error to errNo */ + @throw [OFReadFailedException exceptionWithObject: self + requestedLength: length + errNo: 0]; + } + + return ret; +} + +- (size_t)lowlevelWriteBuffer: (const void *)buffer length: (size_t)length +{ + ssize_t ret; + + if (!_handshakeDone) + @throw [OFNotOpenException exceptionWithObject: self]; + + if ((ret = gnutls_record_send(_session, buffer, length)) < 0) { + if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) + return 0; + + /* FIXME: Translate error to errNo */ + @throw [OFWriteFailedException exceptionWithObject: self + requestedLength: length + bytesWritten: ret + errNo: 0]; + } + + return ret; +} + +- (bool)hasDataInReadBuffer +{ + if (gnutls_record_check_pending(_session) > 0) + return true; + + return super.hasDataInReadBuffer; +} + +- (void)asyncPerformClientHandshakeWithHost: (OFString *)host + runLoopMode: (OFRunLoopMode)runLoopMode +{ + static const OFTLSStreamErrorCode initFailedErrorCode = + OFTLSStreamErrorCodeInitializationFailed; + id exception = nil; + int status; + + if (_initialized) + @throw [OFAlreadyConnectedException exceptionWithSocket: self]; + + if (gnutls_init(&_session, GNUTLS_CLIENT | GNUTLS_NONBLOCK | + GNUTLS_SAFE_PADDING_CHECK) != GNUTLS_E_SUCCESS) + @throw [OFTLSHandshakeFailedException + exceptionWithStream: self + host: host + errorCode: initFailedErrorCode]; + + _initialized = true; + + gnutls_transport_set_ptr(_session, self); + gnutls_transport_set_pull_function(_session, readFunc); + gnutls_transport_set_push_function(_session, writeFunc); + + if (gnutls_set_default_priority(_session) != GNUTLS_E_SUCCESS || + gnutls_credentials_set(_session, GNUTLS_CRD_CERTIFICATE, + systemTrustCreds) != GNUTLS_E_SUCCESS) + @throw [OFTLSHandshakeFailedException + exceptionWithStream: self + host: host + errorCode: initFailedErrorCode]; + + _host = [host copy]; + + if (gnutls_server_name_set(_session, GNUTLS_NAME_DNS, + _host.UTF8String, _host.UTF8StringLength) != GNUTLS_E_SUCCESS) + @throw [OFTLSHandshakeFailedException + exceptionWithStream: self + host: host + errorCode: initFailedErrorCode]; + + if (_verifiesCertificates) + gnutls_session_set_verify_cert(_session, _host.UTF8String, 0); + + status = gnutls_handshake(_session); + + if (status == GNUTLS_E_INTERRUPTED || status == GNUTLS_E_AGAIN) { + if (gnutls_record_get_direction(_session) == 1) + [_underlyingStream + asyncWriteData: [OFData dataWithItems: "" count: 0] + runLoopMode: runLoopMode]; + else + [_underlyingStream asyncReadIntoBuffer: (void *)"" + length: 0 + runLoopMode: runLoopMode]; + + [_delegate retain]; + return; + } + + if (status == GNUTLS_E_SUCCESS) + _handshakeDone = true; + else + /* FIXME: Map to better errors */ + exception = [OFTLSHandshakeFailedException + exceptionWithStream: self + host: host + errorCode: OFTLSStreamErrorCodeUnknown]; + + if ([_delegate respondsToSelector: + @selector(stream:didPerformClientHandshakeWithHost:exception:)]) + [_delegate stream: self + didPerformClientHandshakeWithHost: host + exception: exception]; +} + +- (bool)stream: (OFStream *)stream + didReadIntoBuffer: (void *)buffer + length: (size_t)length + exception: (nullable id)exception +{ + if (exception == nil) { + int status = gnutls_handshake(_session); + + if (status == GNUTLS_E_INTERRUPTED || + status == GNUTLS_E_AGAIN) { + if (gnutls_record_get_direction(_session) == 1) { + OFData *data = [OFData dataWithItems: "" + count: 0]; + OFRunLoopMode runLoopMode = + [OFRunLoop currentRunLoop].currentMode; + [_underlyingStream asyncWriteData: data + runLoopMode: runLoopMode]; + return false; + } else + return true; + } + + if (status == GNUTLS_E_SUCCESS) + _handshakeDone = true; + else + exception = [OFTLSHandshakeFailedException + exceptionWithStream: self + host: _host + errorCode: OFTLSStreamErrorCodeUnknown]; + } + + if ([_delegate respondsToSelector: + @selector(stream:didPerformClientHandshakeWithHost:exception:)]) + [_delegate stream: self + didPerformClientHandshakeWithHost: _host + exception: exception]; + + [_delegate release]; + + return false; +} + +- (OFData *)stream: (OFStream *)stream + didWriteData: (OFData *)data + bytesWritten: (size_t)bytesWritten + exception: (id)exception +{ + if (exception == nil) { + int status = gnutls_handshake(_session); + + if (status == GNUTLS_E_INTERRUPTED || + status == GNUTLS_E_AGAIN) { + if (gnutls_record_get_direction(_session) == 1) + return data; + else { + OFRunLoopMode runLoopMode = + [OFRunLoop currentRunLoop].currentMode; + [_underlyingStream + asyncReadIntoBuffer: (void *)"" + length: 0 + runLoopMode: runLoopMode]; + return nil; + } + } + + if (status == GNUTLS_E_SUCCESS) + _handshakeDone = true; + else + exception = [OFTLSHandshakeFailedException + exceptionWithStream: self + host: _host + errorCode: OFTLSStreamErrorCodeUnknown]; + } + + if ([_delegate respondsToSelector: + @selector(stream:didPerformClientHandshakeWithHost:exception:)]) + [_delegate stream: self + didPerformClientHandshakeWithHost: _host + exception: exception]; + + [_delegate release]; + + return nil; +} +@end ADDED src/tls/OFOpenSSLTLSStream.h Index: src/tls/OFOpenSSLTLSStream.h ================================================================== --- /dev/null +++ src/tls/OFOpenSSLTLSStream.h @@ -0,0 +1,35 @@ +/* + * 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 "OFTLSStream.h" + +#include +#include + +OF_ASSUME_NONNULL_BEGIN + +#define OFOpenSSLTLSStreamBufferSize 512 + +@interface OFOpenSSLTLSStream: OFTLSStream +{ + bool _handshakeDone; + SSL *_SSL; + BIO *_readBIO, *_writeBIO; + OFString *_host; + char _buffer[OFOpenSSLTLSStreamBufferSize]; +} +@end + +OF_ASSUME_NONNULL_END ADDED src/tls/OFOpenSSLTLSStream.m Index: src/tls/OFOpenSSLTLSStream.m ================================================================== --- /dev/null +++ src/tls/OFOpenSSLTLSStream.m @@ -0,0 +1,428 @@ +/* + * 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 "OFOpenSSLTLSStream.h" +#import "OFData.h" + +#import "OFAlreadyConnectedException.h" +#import "OFInitializationFailedException.h" +#import "OFNotOpenException.h" +#import "OFReadFailedException.h" +#import "OFTLSHandshakeFailedException.h" +#import "OFWriteFailedException.h" + +#define bufferSize OFOpenSSLTLSStreamBufferSize + +int _ObjFWTLS_reference; +static SSL_CTX *clientContext; + +@implementation OFOpenSSLTLSStream ++ (void)load +{ + if (OFTLSStreamImplementation == Nil) + OFTLSStreamImplementation = self; +} + ++ (void)initialize +{ + if (self != [OFOpenSSLTLSStream class]) + return; + + SSL_load_error_strings(); + SSL_library_init(); + + if ((clientContext = SSL_CTX_new(TLS_client_method())) == NULL || + SSL_CTX_set_default_verify_paths(clientContext) != 1) + @throw [OFInitializationFailedException + exceptionWithClass: self]; +} + +- (instancetype)initWithStream: (OFStream *)stream +{ + self = [super initWithStream: stream]; + + @try { + _underlyingStream.delegate = self; + /* + * Buffer writes so that nothing gets lost if we write more + * than the underlying stream can write. + */ + _underlyingStream.buffersWrites = true; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + if (_SSL != NULL) + [self close]; + + [_host release]; + + [super dealloc]; +} + +- (void)close +{ + if (_SSL == NULL) + @throw [OFNotOpenException exceptionWithObject: self]; + + if (_handshakeDone) + SSL_shutdown(_SSL); + + SSL_free(_SSL); + _SSL = NULL; + + [_host release]; + _host = nil; + + [super close]; +} + +- (size_t)lowlevelReadIntoBuffer: (void *)buffer length: (size_t)length +{ + int ret; + size_t bytesRead; + + if (!_handshakeDone) + @throw [OFNotOpenException exceptionWithObject: self]; + + if (BIO_ctrl_pending(_readBIO) < 1) { + @try { + size_t tmp = [_underlyingStream + readIntoBuffer: _buffer + length: bufferSize]; + + OFEnsure(tmp <= INT_MAX); + /* Writing to a memory BIO must never fail. */ + OFEnsure(BIO_write(_readBIO, _buffer, (int)tmp) == + (int)tmp); + } @catch (OFReadFailedException *e) { + if (e.errNo != EWOULDBLOCK && e.errNo != EAGAIN) + @throw e; + } + } + + ret = SSL_read_ex(_SSL, buffer, length, &bytesRead); + + while (BIO_ctrl_pending(_writeBIO) > 0) { + int tmp = BIO_read(_writeBIO, _buffer, bufferSize); + + OFEnsure(tmp >= 0); + + [_underlyingStream writeBuffer: _buffer length: tmp]; + [_underlyingStream flushWriteBuffer]; + } + + if (ret != 1) { + /* + * The underlying stream might have had data ready, but not + * enough for OpenSSL to return decrypted data. This means the + * caller might have observed the TLS stream for reading, got a + * ready signal and read - and expects the read to succeed, not + * to fail with EWOULDBLOCK, as it was signaled ready. + * Therefore, return 0, as we could read 0 decrypted bytes, but + * cleared the ready signal of the underlying stream. + */ + if (SSL_get_error(_SSL, ret) == SSL_ERROR_WANT_READ) + return 0; + + /* FIXME: Translate error to errNo */ + @throw [OFReadFailedException exceptionWithObject: self + requestedLength: length + errNo: 0]; + } + + return bytesRead; +} + +- (size_t)lowlevelWriteBuffer: (const void *)buffer length: (size_t)length +{ + int ret; + size_t bytesWritten; + + if (!_handshakeDone) + @throw [OFNotOpenException exceptionWithObject: self]; + + if ((ret = SSL_write_ex(_SSL, buffer, length, &bytesWritten)) != 1) { + /* FIXME: Translate error to errNo */ + int errNo = 0; + + if (SSL_get_error(_SSL, ret) == SSL_ERROR_WANT_WRITE) + return bytesWritten; + + @throw [OFWriteFailedException exceptionWithObject: self + requestedLength: length + bytesWritten: bytesWritten + errNo: errNo]; + } + + while (BIO_ctrl_pending(_writeBIO) > 0) { + int tmp = BIO_read(_writeBIO, _buffer, bufferSize); + + OFEnsure(tmp >= 0); + + [_underlyingStream writeBuffer: _buffer length: tmp]; + [_underlyingStream flushWriteBuffer]; + } + + return bytesWritten; +} + +- (bool)hasDataInReadBuffer +{ + if (SSL_has_pending(_SSL) || BIO_ctrl_pending(_readBIO) > 0) + return true; + + return super.hasDataInReadBuffer; +} + +- (void)asyncPerformClientHandshakeWithHost: (OFString *)host + runLoopMode: (OFRunLoopMode)runLoopMode +{ + static const OFTLSStreamErrorCode initFailedErrorCode = + OFTLSStreamErrorCodeInitializationFailed; + id exception = nil; + int status; + + if (_SSL != NULL) + @throw [OFAlreadyConnectedException exceptionWithSocket: self]; + + if ((_readBIO = BIO_new(BIO_s_mem())) == NULL) + @throw [OFTLSHandshakeFailedException + exceptionWithStream: self + host: host + errorCode: initFailedErrorCode]; + + if ((_writeBIO = BIO_new(BIO_s_mem())) == NULL) { + BIO_free(_readBIO); + @throw [OFTLSHandshakeFailedException + exceptionWithStream: self + host: host + errorCode: initFailedErrorCode]; + } + + BIO_set_mem_eof_return(_readBIO, -1); + BIO_set_mem_eof_return(_writeBIO, -1); + + if ((_SSL = SSL_new(clientContext)) == NULL) { + BIO_free(_readBIO); + BIO_free(_writeBIO); + @throw [OFTLSHandshakeFailedException + exceptionWithStream: self + host: host + errorCode: initFailedErrorCode]; + } + + SSL_set_bio(_SSL, _readBIO, _writeBIO); + SSL_set_connect_state(_SSL); + + _host = [host copy]; + + if (SSL_set_tlsext_host_name(_SSL, _host.UTF8String) != 1) + @throw [OFTLSHandshakeFailedException + exceptionWithStream: self + host: host + errorCode: initFailedErrorCode]; + + if (_verifiesCertificates) { + SSL_set_verify(_SSL, SSL_VERIFY_PEER, NULL); + + if (SSL_set1_host(_SSL, _host.UTF8String) != 1) + @throw [OFTLSHandshakeFailedException + exceptionWithStream: self + host: host + errorCode: initFailedErrorCode]; + } + + status = SSL_do_handshake(_SSL); + + while (BIO_ctrl_pending(_writeBIO) > 0) { + int tmp = BIO_read(_writeBIO, _buffer, bufferSize); + + OFEnsure(tmp >= 0); + + [_underlyingStream writeBuffer: _buffer length: tmp]; + [_underlyingStream flushWriteBuffer]; + } + + if (status == 1) + _handshakeDone = true; + else { + switch (SSL_get_error(_SSL, status)) { + case SSL_ERROR_WANT_READ: + [_underlyingStream asyncReadIntoBuffer: _buffer + length: bufferSize + runLoopMode: runLoopMode]; + [_delegate retain]; + return; + case SSL_ERROR_WANT_WRITE: + [_underlyingStream + asyncWriteData: [OFData dataWithItems: "" count: 0] + runLoopMode: runLoopMode]; + [_delegate retain]; + return; + default: + /* FIXME: Map to better errors */ + exception = [OFTLSHandshakeFailedException + exceptionWithStream: self + host: host + errorCode: OFTLSStreamErrorCodeUnknown]; + break; + } + } + + if ([_delegate respondsToSelector: + @selector(stream:didPerformClientHandshakeWithHost:exception:)]) + [_delegate stream: self + didPerformClientHandshakeWithHost: host + exception: exception]; +} + +- (bool)stream: (OFStream *)stream + didReadIntoBuffer: (void *)buffer + length: (size_t)length + exception: (nullable id)exception +{ + if (exception == nil) { + static const OFTLSStreamErrorCode unknownErrorCode = + OFTLSStreamErrorCodeUnknown; + int status; + OFData *data; + + OFEnsure(length <= INT_MAX); + OFEnsure(BIO_write(_readBIO, buffer, (int)length) == + (int)length); + + status = SSL_do_handshake(_SSL); + + while (BIO_ctrl_pending(_writeBIO) > 0) { + int tmp = BIO_read(_writeBIO, buffer, bufferSize); + + OFEnsure(tmp >= 0); + + [_underlyingStream writeBuffer: _buffer length: tmp]; + [_underlyingStream flushWriteBuffer]; + } + + if (status == 1) + _handshakeDone = true; + else { + switch (SSL_get_error(_SSL, status)) { + case SSL_ERROR_WANT_READ: + return true; + case SSL_ERROR_WANT_WRITE: + data = [OFData dataWithItems: "" count: 0]; + OFRunLoopMode runLoopMode = + [OFRunLoop currentRunLoop].currentMode; + [_underlyingStream asyncWriteData: data + runLoopMode: runLoopMode]; + return false; + default: + exception = [OFTLSHandshakeFailedException + exceptionWithStream: self + host: _host + errorCode: unknownErrorCode]; + break; + } + } + } + + if ([_delegate respondsToSelector: + @selector(stream:didPerformClientHandshakeWithHost:exception:)]) + [_delegate stream: self + didPerformClientHandshakeWithHost: _host + exception: exception]; + + [_delegate release]; + + return false; +} + +- (OFData *)stream: (OFStream *)stream + didWriteData: (OFData *)data + bytesWritten: (size_t)bytesWritten + exception: (id)exception +{ + if (exception == nil) { + static const OFTLSStreamErrorCode unknownErrorCode = + OFTLSStreamErrorCodeUnknown; + int status; + OFRunLoopMode runLoopMode; + + while (BIO_ctrl_pending(_writeBIO) > 0) { + int tmp = BIO_read(_writeBIO, _buffer, bufferSize); + + OFEnsure(tmp >= 0); + + [_underlyingStream writeBuffer: _buffer length: tmp]; + [_underlyingStream flushWriteBuffer]; + } + + status = SSL_do_handshake(_SSL); + + while (BIO_ctrl_pending(_writeBIO) > 0) { + int tmp = BIO_read(_writeBIO, _buffer, bufferSize); + + OFEnsure(tmp >= 0); + + [_underlyingStream writeBuffer: _buffer length: tmp]; + [_underlyingStream flushWriteBuffer]; + } + + if (status == 1) + _handshakeDone = true; + else { + switch (SSL_get_error(_SSL, status)) { + case SSL_ERROR_WANT_READ: + runLoopMode = + [OFRunLoop currentRunLoop].currentMode; + [_underlyingStream + asyncReadIntoBuffer: _buffer + length: bufferSize + runLoopMode: runLoopMode]; + return nil; + case SSL_ERROR_WANT_WRITE: + return data; + default: + exception = [OFTLSHandshakeFailedException + exceptionWithStream: self + host: _host + errorCode: unknownErrorCode]; + break; + } + } + } + + if ([_delegate respondsToSelector: + @selector(stream:didPerformClientHandshakeWithHost:exception:)]) + [_delegate stream: self + didPerformClientHandshakeWithHost: _host + exception: exception]; + + [_delegate release]; + + return nil; +} +@end ADDED src/tls/OFSecureTransportTLSStream.h Index: src/tls/OFSecureTransportTLSStream.h ================================================================== --- /dev/null +++ src/tls/OFSecureTransportTLSStream.h @@ -0,0 +1,29 @@ +/* + * 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 "OFTLSStream.h" + +#include + +OF_ASSUME_NONNULL_BEGIN + +@interface OFSecureTransportTLSStream: OFTLSStream +{ + SSLContextRef _context; + OFString *_host; +} +@end + +OF_ASSUME_NONNULL_END ADDED src/tls/OFSecureTransportTLSStream.m Index: src/tls/OFSecureTransportTLSStream.m ================================================================== --- /dev/null +++ src/tls/OFSecureTransportTLSStream.m @@ -0,0 +1,281 @@ +/* + * 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 "OFSecureTransportTLSStream.h" + +#import "OFAlreadyConnectedException.h" +#import "OFNotOpenException.h" +#import "OFReadFailedException.h" +#import "OFTLSHandshakeFailedException.h" +#import "OFWriteFailedException.h" + +int _ObjFWTLS_reference; + +static OSStatus +readFunc(SSLConnectionRef connection, void *data, size_t *dataLength) +{ + bool incomplete; + size_t length; + + @try { + length = [((OFTLSStream *)connection).underlyingStream + readIntoBuffer: data + length: *dataLength]; + } @catch (OFReadFailedException *e) { + if (e.errNo == EWOULDBLOCK || e.errNo == EAGAIN) { + *dataLength = 0; + return errSSLWouldBlock; + } + + @throw e; + } + + incomplete = (length < *dataLength); + *dataLength = length; + + return (incomplete ? errSSLWouldBlock : noErr); +} + +static OSStatus +writeFunc(SSLConnectionRef connection, const void *data, size_t *dataLength) +{ + @try { + [((OFTLSStream *)connection).underlyingStream + writeBuffer: data + length: *dataLength]; + } @catch (OFWriteFailedException *e) { + *dataLength = e.bytesWritten; + + if (e.errNo == EWOULDBLOCK || e.errNo == EAGAIN) + return errSSLWouldBlock; + + @throw e; + } + + return noErr; +} + +/* + * Apple deprecated Secure Transport without providing a replacement that can + * work with any socket. On top of that, their replacement, Network.framework, + * doesn't support STARTTLS at all. + */ +#if OF_GCC_VERSION >= 402 +# pragma GCC diagnostic ignored "-Wdeprecated" +#endif + +@implementation OFSecureTransportTLSStream ++ (void)load +{ + if (OFTLSStreamImplementation == Nil) + OFTLSStreamImplementation = self; +} + +- (instancetype)initWithStream: (OFStream *)stream +{ + self = [super initWithStream: stream]; + + @try { + _underlyingStream.delegate = self; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + if (_context != NULL) + [self close]; + + [_host release]; + + [super dealloc]; +} + +- (void)close +{ + if (_context == NULL) + @throw [OFNotOpenException exceptionWithObject: self]; + + [_host release]; + _host = nil; + + SSLClose(_context); +#ifdef HAVE_SSLCREATECONTEXT + CFRelease(_context); +#else + SSLDisposeContext(_context); +#endif + _context = NULL; + + [super close]; +} + +- (size_t)lowlevelReadIntoBuffer: (void *)buffer length: (size_t)length +{ + OSStatus status; + size_t ret; + + if (_context == NULL) + @throw [OFNotOpenException exceptionWithObject: self]; + + status = SSLRead(_context, buffer, length, &ret); + if (status != noErr && status != errSSLWouldBlock) + /* FIXME: Translate status to errNo */ + @throw [OFReadFailedException exceptionWithObject: self + requestedLength: length + errNo: 0]; + + return ret; +} + +- (size_t)lowlevelWriteBuffer: (const void *)buffer length: (size_t)length +{ + OSStatus status; + size_t bytesWritten = 0; + + if (_context == NULL) + @throw [OFNotOpenException exceptionWithObject: self]; + + status = SSLWrite(_context, buffer, length, &bytesWritten); + if (status != noErr && status != errSSLWouldBlock) + /* FIXME: Translate status to errNo */ + @throw [OFWriteFailedException exceptionWithObject: self + requestedLength: length + bytesWritten: bytesWritten + errNo: 0]; + + return bytesWritten; +} + +- (bool)hasDataInReadBuffer +{ + size_t bufferSize; + + if (SSLGetBufferedReadSize(_context, &bufferSize) == noErr && + bufferSize > 0) + return true; + + return super.hasDataInReadBuffer; +} + +- (void)asyncPerformClientHandshakeWithHost: (OFString *)host + runLoopMode: (OFRunLoopMode)runLoopMode +{ + static const OFTLSStreamErrorCode initFailedErrorCode = + OFTLSStreamErrorCodeInitializationFailed; + id exception = nil; + OSStatus status; + + if (_context != NULL) + @throw [OFAlreadyConnectedException exceptionWithSocket: self]; + +#ifdef HAVE_SSLCREATECONTEXT + if ((_context = SSLCreateContext(kCFAllocatorDefault, kSSLClientSide, + kSSLStreamType)) == NULL) +#else + if (SSLNewContext(false, &_context) != noErr) +#endif + @throw [OFTLSHandshakeFailedException + exceptionWithStream: self + host: host + errorCode: initFailedErrorCode]; + + if (SSLSetIOFuncs(_context, readFunc, writeFunc) != noErr || + SSLSetConnection(_context, self) != noErr) + @throw [OFTLSHandshakeFailedException + exceptionWithStream: self + host: host + errorCode: initFailedErrorCode]; + + _host = [host copy]; + + if (_verifiesCertificates) + if (SSLSetPeerDomainName(_context, + _host.UTF8String, _host.UTF8StringLength) != noErr) + @throw [OFTLSHandshakeFailedException + exceptionWithStream: self + host: _host + errorCode: initFailedErrorCode]; + + status = SSLHandshake(_context); + + if (status == errSSLWouldBlock) { + /* + * Theoretically it is possible we block because Secure + * Transport cannot write without blocking. But unfortunately, + * Secure Transport does not tell us whether it's blocked on + * reading or writing. Waiting for the stream to be either + * readable or writable doesn't work either, as the stream is + * almost always at least ready for one of the two. + */ + [_underlyingStream asyncReadIntoBuffer: (void *)"" + length: 0 + runLoopMode: runLoopMode]; + [_delegate retain]; + return; + } + + if (status != noErr) + /* FIXME: Map to better errors */ + exception = [OFTLSHandshakeFailedException + exceptionWithStream: self + host: _host + errorCode: OFTLSStreamErrorCodeUnknown]; + + if ([_delegate respondsToSelector: + @selector(stream:didPerformClientHandshakeWithHost:exception:)]) + [_delegate stream: self + didPerformClientHandshakeWithHost: _host + exception: exception]; +} + +- (bool)stream: (OFStream *)stream + didReadIntoBuffer: (void *)buffer + length: (size_t)length + exception: (nullable id)exception +{ + if (exception == nil) { + OSStatus status = SSLHandshake(_context); + + if (status == errSSLWouldBlock) + return true; + + if (status != noErr) + exception = [OFTLSHandshakeFailedException + exceptionWithStream: self + host: _host + errorCode: OFTLSStreamErrorCodeUnknown]; + } + + if ([_delegate respondsToSelector: + @selector(stream:didPerformClientHandshakeWithHost:exception:)]) + [_delegate stream: self + didPerformClientHandshakeWithHost: _host + exception: exception]; + + [_delegate release]; + + return false; +} +@end ADDED src/tls/ObjFWTLS.h Index: src/tls/ObjFWTLS.h ================================================================== --- /dev/null +++ src/tls/ObjFWTLS.h @@ -0,0 +1,24 @@ +/* + * 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 "macros.h" + +#ifdef __cplusplus +extern "C" { +#endif +extern int _ObjFWTLS_reference; +#ifdef __cplusplus +} +#endif DELETED src/tlskey.h Index: src/tlskey.h ================================================================== --- src/tlskey.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "objfw-defs.h" - -#include "platform.h" - -#if !defined(OF_HAVE_THREADS) || \ - (!defined(OF_HAVE_PTHREADS) && !defined(OF_WINDOWS) && !defined(OF_AMIGAOS)) -# error No thread-local storage available! -#endif - -#import "macros.h" - -#if defined(OF_HAVE_PTHREADS) -# include -typedef pthread_key_t of_tlskey_t; -#elif defined(OF_WINDOWS) -# include -typedef DWORD of_tlskey_t; -#elif defined(OF_AMIGAOS) -typedef struct of_tlskey { - struct objc_hashtable *table; - struct of_tlskey *next, *previous; -} *of_tlskey_t; -#endif - -#ifdef __cplusplus -extern "C" { -#endif -extern bool of_tlskey_new(of_tlskey_t *key); -extern bool of_tlskey_free(of_tlskey_t key); -#ifdef __cplusplus -} -#endif - -/* TLS keys are inlined for performance. */ - -#if defined(OF_HAVE_PTHREADS) -static OF_INLINE void * -of_tlskey_get(of_tlskey_t key) -{ - return pthread_getspecific(key); -} - -static OF_INLINE bool -of_tlskey_set(of_tlskey_t key, void *ptr) -{ - return (pthread_setspecific(key, ptr) == 0); -} -#elif defined(OF_WINDOWS) -static OF_INLINE void * -of_tlskey_get(of_tlskey_t key) -{ - return TlsGetValue(key); -} - -static OF_INLINE bool -of_tlskey_set(of_tlskey_t key, void *ptr) -{ - return TlsSetValue(key, ptr); -} -#elif defined(OF_AMIGAOS) -/* Those are too big too inline. */ -# ifdef __cplusplus -extern "C" { -# endif -extern void *of_tlskey_get(of_tlskey_t key); -extern bool of_tlskey_set(of_tlskey_t key, void *ptr); -# ifdef __cplusplus -} -# endif -#endif DELETED src/tlskey.m Index: src/tlskey.m ================================================================== --- src/tlskey.m +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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" - -#if defined(OF_HAVE_PTHREADS) -# include "platform/posix/tlskey.m" -#elif defined(OF_WINDOWS) -# include "platform/windows/tlskey.m" -#elif defined(OF_AMIGAOS) -# include "platform/amiga/tlskey.m" -#endif Index: src/unicode.h ================================================================== --- src/unicode.h +++ src/unicode.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -15,30 +13,30 @@ * file. */ #import "OFString.h" -#define OF_UNICODE_UPPERCASE_TABLE_SIZE 0x1EA -#define OF_UNICODE_LOWERCASE_TABLE_SIZE 0x1EA -#define OF_UNICODE_TITLECASE_TABLE_SIZE 0x1EA -#define OF_UNICODE_CASEFOLDING_TABLE_SIZE 0x1EA -#define OF_UNICODE_DECOMPOSITION_TABLE_SIZE 0x2FB -#define OF_UNICODE_DECOMPOSITION_COMPAT_TABLE_SIZE 0x2FB +#define OFUnicodeUppercaseTableSize 0x1EA +#define OFUnicodeLowercaseTableSize 0x1EA +#define OFUnicodeTitlecaseTableSize 0x1EA +#define OFUnicodeCaseFoldingTableSize 0x1EA +#define OFUnicodeDecompositionTableSize 0x2FB +#define OFUnicodeDecompositionCompatTableSize 0x2FB #ifdef __cplusplus extern "C" { #endif -extern const of_unichar_t *const _Nonnull - of_unicode_uppercase_table[OF_UNICODE_UPPERCASE_TABLE_SIZE]; -extern const of_unichar_t *const _Nonnull - of_unicode_lowercase_table[OF_UNICODE_LOWERCASE_TABLE_SIZE]; -extern const of_unichar_t *const _Nonnull - of_unicode_titlecase_table[OF_UNICODE_TITLECASE_TABLE_SIZE]; -extern const of_unichar_t *const _Nonnull - of_unicode_casefolding_table[OF_UNICODE_CASEFOLDING_TABLE_SIZE]; -extern const char *const _Nullable *const _Nonnull - of_unicode_decomposition_table[OF_UNICODE_DECOMPOSITION_TABLE_SIZE]; -extern const char *const _Nullable *const _Nonnull - of_unicode_decomposition_compat_table[OF_UNICODE_DECOMPOSITION_COMPAT_TABLE_SIZE]; +extern const OFUnichar *const _Nonnull + OFUnicodeUppercaseTable[OFUnicodeUppercaseTableSize]; +extern const OFUnichar *const _Nonnull + OFUnicodeLowercaseTable[OFUnicodeLowercaseTableSize]; +extern const OFUnichar *const _Nonnull + OFUnicodeTitlecaseTable[OFUnicodeTitlecaseTableSize]; +extern const OFUnichar *const _Nonnull + OFUnicodeCaseFoldingTable[OFUnicodeCaseFoldingTableSize]; +extern const char *const _Nullable *const _Nonnull + OFUnicodeDecompositionTable[OFUnicodeDecompositionTableSize]; +extern const char *const _Nullable *const _Nonnull + OFUnicodeDecompositionCompatTable[OFUnicodeDecompositionCompatTableSize]; #ifdef __cplusplus } #endif Index: src/unicode.m ================================================================== --- src/unicode.m +++ src/unicode.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -17,14 +15,14 @@ #include "config.h" #import "OFString.h" -static const of_unichar_t emptyPage[0x100] = { 0 }; +static const OFUnichar emptyPage[0x100] = { 0 }; static const char *emptyDecompositionPage[0x100] = { NULL }; -static const of_unichar_t uppercasePage0[0x100] = { +static const OFUnichar uppercasePage0[0x100] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -55,11 +53,11 @@ 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 0, 216, 217, 218, 219, 220, 221, 222, 376, }; -static const of_unichar_t uppercasePage1[0x100] = { +static const OFUnichar uppercasePage1[0x100] = { 0, 256, 0, 258, 0, 260, 0, 262, 0, 264, 0, 266, 0, 268, 0, 270, 0, 272, 0, 274, 0, 276, 0, 278, 0, 280, 0, 282, 0, 284, 0, 286, 0, 288, 0, 290, 0, 292, 0, 294, @@ -90,11 +88,11 @@ 0, 488, 0, 490, 0, 492, 0, 494, 0, 0, 497, 497, 0, 500, 0, 0, 0, 504, 0, 506, 0, 508, 0, 510, }; -static const of_unichar_t uppercasePage2[0x100] = { +static const OFUnichar uppercasePage2[0x100] = { 0, 512, 0, 514, 0, 516, 0, 518, 0, 520, 0, 522, 0, 524, 0, 526, 0, 528, 0, 530, 0, 532, 0, 534, 0, 536, 0, 538, 0, 540, 0, 542, 0, 0, 0, 546, 0, 548, 0, 550, @@ -125,11 +123,11 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -static const of_unichar_t uppercasePage3[0x100] = { +static const OFUnichar uppercasePage3[0x100] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -160,11 +158,11 @@ 0, 1000, 0, 1002, 0, 1004, 0, 1006, 922, 929, 1017, 895, 0, 917, 0, 0, 1015, 0, 0, 1018, 0, 0, 0, 0, }; -static const of_unichar_t uppercasePage4[0x100] = { +static const OFUnichar uppercasePage4[0x100] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -195,11 +193,11 @@ 0, 1256, 0, 1258, 0, 1260, 0, 1262, 0, 1264, 0, 1266, 0, 1268, 0, 1270, 0, 1272, 0, 1274, 0, 1276, 0, 1278, }; -static const of_unichar_t uppercasePage5[0x100] = { +static const OFUnichar uppercasePage5[0x100] = { 0, 1280, 0, 1282, 0, 1284, 0, 1286, 0, 1288, 0, 1290, 0, 1292, 0, 1294, 0, 1296, 0, 1298, 0, 1300, 0, 1302, 0, 1304, 0, 1306, 0, 1308, 0, 1310, 0, 1312, 0, 1314, 0, 1316, 0, 1318, @@ -230,11 +228,11 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -static const of_unichar_t uppercasePage16[0x100] = { +static const OFUnichar uppercasePage16[0x100] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -265,11 +263,11 @@ 7336, 7337, 7338, 7339, 7340, 7341, 7342, 7343, 7344, 7345, 7346, 7347, 7348, 7349, 7350, 7351, 7352, 7353, 7354, 0, 0, 7357, 7358, 7359, }; -static const of_unichar_t uppercasePage19[0x100] = { +static const OFUnichar uppercasePage19[0x100] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -300,11 +298,11 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5104, 5105, 5106, 5107, 5108, 5109, 0, 0, }; -static const of_unichar_t uppercasePage28[0x100] = { +static const OFUnichar uppercasePage28[0x100] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -335,11 +333,11 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -static const of_unichar_t uppercasePage29[0x100] = { +static const OFUnichar uppercasePage29[0x100] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -370,11 +368,11 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -static const of_unichar_t uppercasePage30[0x100] = { +static const OFUnichar uppercasePage30[0x100] = { 0, 7680, 0, 7682, 0, 7684, 0, 7686, 0, 7688, 0, 7690, 0, 7692, 0, 7694, 0, 7696, 0, 7698, 0, 7700, 0, 7702, 0, 7704, 0, 7706, 0, 7708, 0, 7710, 0, 7712, 0, 7714, 0, 7716, 0, 7718, @@ -405,11 +403,11 @@ 0, 7912, 0, 7914, 0, 7916, 0, 7918, 0, 7920, 0, 7922, 0, 7924, 0, 7926, 0, 7928, 0, 7930, 0, 7932, 0, 7934, }; -static const of_unichar_t uppercasePage31[0x100] = { +static const OFUnichar uppercasePage31[0x100] = { 7944, 7945, 7946, 7947, 7948, 7949, 7950, 7951, 0, 0, 0, 0, 0, 0, 0, 0, 7960, 7961, 7962, 7963, 7964, 7965, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7976, 7977, 7978, 7979, 7980, 7981, 7982, 7983, @@ -440,11 +438,11 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8188, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -static const of_unichar_t uppercasePage33[0x100] = { +static const OFUnichar uppercasePage33[0x100] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -475,11 +473,11 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -static const of_unichar_t uppercasePage36[0x100] = { +static const OFUnichar uppercasePage36[0x100] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -510,11 +508,11 @@ 9422, 9423, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -static const of_unichar_t uppercasePage44[0x100] = { +static const OFUnichar uppercasePage44[0x100] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -545,11 +543,11 @@ 0, 0, 0, 0, 11499, 0, 11501, 0, 0, 0, 0, 11506, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -static const of_unichar_t uppercasePage45[0x100] = { +static const OFUnichar uppercasePage45[0x100] = { 4256, 4257, 4258, 4259, 4260, 4261, 4262, 4263, 4264, 4265, 4266, 4267, 4268, 4269, 4270, 4271, 4272, 4273, 4274, 4275, 4276, 4277, 4278, 4279, 4280, 4281, 4282, 4283, 4284, 4285, 4286, 4287, 4288, 4289, 4290, 4291, 4292, 4293, 0, 4295, @@ -580,11 +578,11 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -static const of_unichar_t uppercasePage166[0x100] = { +static const OFUnichar uppercasePage166[0x100] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -615,11 +613,11 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -static const of_unichar_t uppercasePage167[0x100] = { +static const OFUnichar uppercasePage167[0x100] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42786, 0, 42788, 0, 42790, @@ -650,11 +648,11 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42997, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -static const of_unichar_t uppercasePage171[0x100] = { +static const OFUnichar uppercasePage171[0x100] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -685,11 +683,11 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -static const of_unichar_t uppercasePage255[0x100] = { +static const OFUnichar uppercasePage255[0x100] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -720,11 +718,11 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -static const of_unichar_t uppercasePage260[0x100] = { +static const OFUnichar uppercasePage260[0x100] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -755,11 +753,11 @@ 66752, 66753, 66754, 66755, 66756, 66757, 66758, 66759, 66760, 66761, 66762, 66763, 66764, 66765, 66766, 66767, 66768, 66769, 66770, 66771, 0, 0, 0, 0, }; -static const of_unichar_t uppercasePage268[0x100] = { +static const OFUnichar uppercasePage268[0x100] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -790,11 +788,11 @@ 68776, 68777, 68778, 68779, 68780, 68781, 68782, 68783, 68784, 68785, 68786, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -static const of_unichar_t uppercasePage280[0x100] = { +static const OFUnichar uppercasePage280[0x100] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -825,11 +823,11 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -static const of_unichar_t uppercasePage366[0x100] = { +static const OFUnichar uppercasePage366[0x100] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -860,11 +858,11 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -static const of_unichar_t uppercasePage489[0x100] = { +static const OFUnichar uppercasePage489[0x100] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 125184, 125185, 125186, 125187, 125188, 125189, @@ -895,11 +893,11 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -static const of_unichar_t lowercasePage0[0x100] = { +static const OFUnichar lowercasePage0[0x100] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -930,11 +928,11 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -static const of_unichar_t lowercasePage1[0x100] = { +static const OFUnichar lowercasePage1[0x100] = { 257, 0, 259, 0, 261, 0, 263, 0, 265, 0, 267, 0, 269, 0, 271, 0, 273, 0, 275, 0, 277, 0, 279, 0, 281, 0, 283, 0, 285, 0, 287, 0, 289, 0, 291, 0, 293, 0, 295, 0, @@ -965,11 +963,11 @@ 489, 0, 491, 0, 493, 0, 495, 0, 0, 499, 499, 0, 501, 0, 405, 447, 505, 0, 507, 0, 509, 0, 511, 0, }; -static const of_unichar_t lowercasePage2[0x100] = { +static const OFUnichar lowercasePage2[0x100] = { 513, 0, 515, 0, 517, 0, 519, 0, 521, 0, 523, 0, 525, 0, 527, 0, 529, 0, 531, 0, 533, 0, 535, 0, 537, 0, 539, 0, 541, 0, 543, 0, 414, 0, 547, 0, 549, 0, 551, 0, @@ -1000,11 +998,11 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -static const of_unichar_t lowercasePage3[0x100] = { +static const OFUnichar lowercasePage3[0x100] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1035,11 +1033,11 @@ 1001, 0, 1003, 0, 1005, 0, 1007, 0, 0, 0, 0, 0, 952, 0, 0, 1016, 0, 1010, 1019, 0, 0, 891, 892, 893, }; -static const of_unichar_t lowercasePage4[0x100] = { +static const OFUnichar lowercasePage4[0x100] = { 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111, 1112, 1113, 1114, 1115, 1116, 1117, 1118, 1119, 1072, 1073, 1074, 1075, 1076, 1077, 1078, 1079, 1080, 1081, 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1090, 1091, 1092, 1093, 1094, 1095, @@ -1070,11 +1068,11 @@ 1257, 0, 1259, 0, 1261, 0, 1263, 0, 1265, 0, 1267, 0, 1269, 0, 1271, 0, 1273, 0, 1275, 0, 1277, 0, 1279, 0, }; -static const of_unichar_t lowercasePage5[0x100] = { +static const OFUnichar lowercasePage5[0x100] = { 1281, 0, 1283, 0, 1285, 0, 1287, 0, 1289, 0, 1291, 0, 1293, 0, 1295, 0, 1297, 0, 1299, 0, 1301, 0, 1303, 0, 1305, 0, 1307, 0, 1309, 0, 1311, 0, 1313, 0, 1315, 0, 1317, 0, 1319, 0, @@ -1105,11 +1103,11 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -static const of_unichar_t lowercasePage16[0x100] = { +static const OFUnichar lowercasePage16[0x100] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1140,11 +1138,11 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -static const of_unichar_t lowercasePage19[0x100] = { +static const OFUnichar lowercasePage19[0x100] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1175,11 +1173,11 @@ 43960, 43961, 43962, 43963, 43964, 43965, 43966, 43967, 5112, 5113, 5114, 5115, 5116, 5117, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -static const of_unichar_t lowercasePage28[0x100] = { +static const OFUnichar lowercasePage28[0x100] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1210,11 +1208,11 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -static const of_unichar_t lowercasePage30[0x100] = { +static const OFUnichar lowercasePage30[0x100] = { 7681, 0, 7683, 0, 7685, 0, 7687, 0, 7689, 0, 7691, 0, 7693, 0, 7695, 0, 7697, 0, 7699, 0, 7701, 0, 7703, 0, 7705, 0, 7707, 0, 7709, 0, 7711, 0, 7713, 0, 7715, 0, 7717, 0, 7719, 0, @@ -1245,11 +1243,11 @@ 7913, 0, 7915, 0, 7917, 0, 7919, 0, 7921, 0, 7923, 0, 7925, 0, 7927, 0, 7929, 0, 7931, 0, 7933, 0, 7935, 0, }; -static const of_unichar_t lowercasePage31[0x100] = { +static const OFUnichar lowercasePage31[0x100] = { 0, 0, 0, 0, 0, 0, 0, 0, 7936, 7937, 7938, 7939, 7940, 7941, 7942, 7943, 0, 0, 0, 0, 0, 0, 0, 0, 7952, 7953, 7954, 7955, 7956, 7957, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1280,11 +1278,11 @@ 8160, 8161, 8058, 8059, 8165, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8056, 8057, 8060, 8061, 8179, 0, 0, 0, }; -static const of_unichar_t lowercasePage33[0x100] = { +static const OFUnichar lowercasePage33[0x100] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 969, 0, @@ -1315,11 +1313,11 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -static const of_unichar_t lowercasePage36[0x100] = { +static const OFUnichar lowercasePage36[0x100] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1350,11 +1348,11 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -static const of_unichar_t lowercasePage44[0x100] = { +static const OFUnichar lowercasePage44[0x100] = { 11312, 11313, 11314, 11315, 11316, 11317, 11318, 11319, 11320, 11321, 11322, 11323, 11324, 11325, 11326, 11327, 11328, 11329, 11330, 11331, 11332, 11333, 11334, 11335, 11336, 11337, 11338, 11339, 11340, 11341, 11342, 11343, 11344, 11345, 11346, 11347, 11348, 11349, 11350, 11351, @@ -1385,11 +1383,11 @@ 0, 0, 0, 11500, 0, 11502, 0, 0, 0, 0, 11507, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -static const of_unichar_t lowercasePage166[0x100] = { +static const OFUnichar lowercasePage166[0x100] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1420,11 +1418,11 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -static const of_unichar_t lowercasePage167[0x100] = { +static const OFUnichar lowercasePage167[0x100] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42787, 0, 42789, 0, 42791, 0, @@ -1455,11 +1453,11 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42998, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -static const of_unichar_t lowercasePage255[0x100] = { +static const OFUnichar lowercasePage255[0x100] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65345, 65346, 65347, 65348, 65349, 65350, 65351, @@ -1490,11 +1488,11 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -static const of_unichar_t lowercasePage260[0x100] = { +static const OFUnichar lowercasePage260[0x100] = { 66600, 66601, 66602, 66603, 66604, 66605, 66606, 66607, 66608, 66609, 66610, 66611, 66612, 66613, 66614, 66615, 66616, 66617, 66618, 66619, 66620, 66621, 66622, 66623, 66624, 66625, 66626, 66627, 66628, 66629, 66630, 66631, 66632, 66633, 66634, 66635, 66636, 66637, 66638, 66639, @@ -1525,11 +1523,11 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -static const of_unichar_t lowercasePage268[0x100] = { +static const OFUnichar lowercasePage268[0x100] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1560,11 +1558,11 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -static const of_unichar_t lowercasePage280[0x100] = { +static const OFUnichar lowercasePage280[0x100] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1595,11 +1593,11 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -static const of_unichar_t lowercasePage366[0x100] = { +static const OFUnichar lowercasePage366[0x100] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1630,11 +1628,11 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -static const of_unichar_t lowercasePage489[0x100] = { +static const OFUnichar lowercasePage489[0x100] = { 125218, 125219, 125220, 125221, 125222, 125223, 125224, 125225, 125226, 125227, 125228, 125229, 125230, 125231, 125232, 125233, 125234, 125235, 125236, 125237, 125238, 125239, 125240, 125241, 125242, 125243, 125244, 125245, 125246, 125247, 125248, 125249, 125250, 125251, 0, 0, 0, 0, 0, 0, @@ -1665,11 +1663,11 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -static const of_unichar_t titlecasePage1[0x100] = { +static const OFUnichar titlecasePage1[0x100] = { 0, 256, 0, 258, 0, 260, 0, 262, 0, 264, 0, 266, 0, 268, 0, 270, 0, 272, 0, 274, 0, 276, 0, 278, 0, 280, 0, 282, 0, 284, 0, 286, 0, 288, 0, 290, 0, 292, 0, 294, @@ -1700,11 +1698,11 @@ 0, 488, 0, 490, 0, 492, 0, 494, 0, 498, 498, 498, 0, 500, 0, 0, 0, 504, 0, 506, 0, 508, 0, 510, }; -static const of_unichar_t titlecasePage16[0x100] = { +static const OFUnichar titlecasePage16[0x100] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1735,11 +1733,11 @@ 4328, 4329, 4330, 4331, 4332, 4333, 4334, 4335, 4336, 4337, 4338, 4339, 4340, 4341, 4342, 4343, 4344, 4345, 4346, 0, 0, 4349, 4350, 4351, }; -static const of_unichar_t casefoldingPage0[0x100] = { +static const OFUnichar caseFoldingPage0[0x100] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1770,11 +1768,11 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -static const of_unichar_t casefoldingPage1[0x100] = { +static const OFUnichar caseFoldingPage1[0x100] = { 257, 0, 259, 0, 261, 0, 263, 0, 265, 0, 267, 0, 269, 0, 271, 0, 273, 0, 275, 0, 277, 0, 279, 0, 281, 0, 283, 0, 285, 0, 287, 0, 289, 0, 291, 0, 293, 0, 295, 0, @@ -1805,11 +1803,11 @@ 489, 0, 491, 0, 493, 0, 495, 0, 0, 499, 499, 0, 501, 0, 405, 447, 505, 0, 507, 0, 509, 0, 511, 0, }; -static const of_unichar_t casefoldingPage3[0x100] = { +static const OFUnichar caseFoldingPage3[0x100] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1840,11 +1838,11 @@ 1001, 0, 1003, 0, 1005, 0, 1007, 0, 954, 961, 0, 0, 952, 949, 0, 1016, 0, 1010, 1019, 0, 0, 891, 892, 893, }; -static const of_unichar_t casefoldingPage19[0x100] = { +static const OFUnichar caseFoldingPage19[0x100] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1875,11 +1873,11 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5104, 5105, 5106, 5107, 5108, 5109, 0, 0, }; -static const of_unichar_t casefoldingPage28[0x100] = { +static const OFUnichar caseFoldingPage28[0x100] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1910,11 +1908,11 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -static const of_unichar_t casefoldingPage30[0x100] = { +static const OFUnichar caseFoldingPage30[0x100] = { 7681, 0, 7683, 0, 7685, 0, 7687, 0, 7689, 0, 7691, 0, 7693, 0, 7695, 0, 7697, 0, 7699, 0, 7701, 0, 7703, 0, 7705, 0, 7707, 0, 7709, 0, 7711, 0, 7713, 0, 7715, 0, 7717, 0, 7719, 0, @@ -1945,11 +1943,11 @@ 7913, 0, 7915, 0, 7917, 0, 7919, 0, 7921, 0, 7923, 0, 7925, 0, 7927, 0, 7929, 0, 7931, 0, 7933, 0, 7935, 0, }; -static const of_unichar_t casefoldingPage31[0x100] = { +static const OFUnichar caseFoldingPage31[0x100] = { 0, 0, 0, 0, 0, 0, 0, 0, 7936, 7937, 7938, 7939, 7940, 7941, 7942, 7943, 0, 0, 0, 0, 0, 0, 0, 0, 7952, 7953, 7954, 7955, 7956, 7957, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1980,11 +1978,11 @@ 8160, 8161, 8058, 8059, 8165, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8056, 8057, 8060, 8061, 8179, 0, 0, 0, }; -static const of_unichar_t casefoldingPage171[0x100] = { +static const OFUnichar caseFoldingPage171[0x100] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -12364,11 +12362,11 @@ NULL, NULL, NULL, NULL, NULL, NULL, }; -const of_unichar_t *const of_unicode_uppercase_table[0x1EA] = { +const OFUnichar *const OFUnicodeUppercaseTable[0x1EA] = { uppercasePage0, uppercasePage1, uppercasePage2, uppercasePage3, uppercasePage4, uppercasePage5, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, uppercasePage16, emptyPage, emptyPage, uppercasePage19, @@ -12490,11 +12488,11 @@ emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, uppercasePage489 }; -const of_unichar_t *const of_unicode_lowercase_table[0x1EA] = { +const OFUnichar *const OFUnicodeLowercaseTable[0x1EA] = { lowercasePage0, lowercasePage1, lowercasePage2, lowercasePage3, lowercasePage4, lowercasePage5, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, lowercasePage16, emptyPage, emptyPage, lowercasePage19, @@ -12616,11 +12614,11 @@ emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, lowercasePage489 }; -const of_unichar_t *const of_unicode_titlecase_table[0x1EA] = { +const OFUnichar *const OFUnicodeTitlecaseTable[0x1EA] = { uppercasePage0, titlecasePage1, uppercasePage2, uppercasePage3, uppercasePage4, uppercasePage5, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, titlecasePage16, emptyPage, emptyPage, uppercasePage19, @@ -12742,22 +12740,22 @@ emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, uppercasePage489 }; -const of_unichar_t *const of_unicode_casefolding_table[0x1EA] = { - casefoldingPage0, casefoldingPage1, lowercasePage2, - casefoldingPage3, lowercasePage4, lowercasePage5, +const OFUnichar *const OFUnicodeCaseFoldingTable[0x1EA] = { + caseFoldingPage0, caseFoldingPage1, lowercasePage2, + caseFoldingPage3, lowercasePage4, lowercasePage5, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, lowercasePage16, emptyPage, - emptyPage, casefoldingPage19, emptyPage, + emptyPage, caseFoldingPage19, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, - emptyPage, casefoldingPage28, emptyPage, - casefoldingPage30, casefoldingPage31, emptyPage, + emptyPage, caseFoldingPage28, emptyPage, + caseFoldingPage30, caseFoldingPage31, emptyPage, lowercasePage33, emptyPage, emptyPage, lowercasePage36, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, lowercasePage44, emptyPage, emptyPage, emptyPage, @@ -12800,11 +12798,11 @@ emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, lowercasePage166, lowercasePage167, emptyPage, emptyPage, emptyPage, - casefoldingPage171, emptyPage, emptyPage, + caseFoldingPage171, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, @@ -12909,11 +12907,11 @@ emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, emptyPage, lowercasePage489 }; -const char *const *of_unicode_decomposition_table[0x2FB] = { +const char *const *OFUnicodeDecompositionTable[0x2FB] = { decompositionPage0, decompositionPage1, decompositionPage2, decompositionPage3, decompositionPage4, emptyDecompositionPage, decompositionPage6, emptyDecompositionPage, emptyDecompositionPage, decompositionPage9, decompositionPage10, decompositionPage11, decompositionPage12, decompositionPage13, emptyDecompositionPage, @@ -13167,11 +13165,11 @@ emptyDecompositionPage, emptyDecompositionPage, emptyDecompositionPage, emptyDecompositionPage, decompositionPage760, decompositionPage761, decompositionPage762 }; -const char *const *of_unicode_decomposition_compat_table[0x2FB] = { +const char *const *OFUnicodeDecompositionCompatTable[0x2FB] = { decompCompatPage0, decompCompatPage1, decompCompatPage2, decompCompatPage3, decompositionPage4, decompCompatPage5, decompCompatPage6, emptyDecompositionPage, emptyDecompositionPage, decompositionPage9, decompositionPage10, decompositionPage11, decompCompatPage12, decompCompatPage13, decompCompatPage14, Index: src/unistd_wrapper.h ================================================================== --- src/unistd_wrapper.h +++ src/unistd_wrapper.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: tests/ForwardingTests.m ================================================================== --- tests/ForwardingTests.m +++ tests/ForwardingTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -19,22 +17,22 @@ #include #import "TestsAppDelegate.h" -#define FMT @"%@ %@ %@ %@ %@ %@ %@ %@ %@ %g %g %g %g %g %g %g %g %g" +#define FORMAT @"%@ %@ %@ %@ %@ %@ %@ %@ %@ %g %g %g %g %g %g %g %g %g" #define ARGS @"a", @"b", @"c", @"d", @"e", @"f", @"g", @"h", @"i", \ 1.5, 2.25, 3.125, 4.0625, 5.03125, 6.5, 7.25, 8.0, 9.0 #define RESULT @"a b c d e f g h i 1.5 2.25 3.125 4.0625 5.03125 6.5 7.25 8 9" -static OFString *module = @"Forwarding"; -static size_t forwardings = 0; +static OFString *const module = @"Forwarding"; +static size_t forwardingsCount = 0; static bool success = false; static id target = nil; -struct stret_test { - char s[1024]; +struct StretTest { + char buffer[1024]; }; @interface ForwardingTest: OFObject @end @@ -43,17 +41,17 @@ - (void)test; - (uint32_t)forwardingTargetTest: (intptr_t)a0 : (intptr_t)a1 : (double)a2 : (double)a3; -- (OFString *)forwardingTargetVarArgTest: (OFConstantString *)fmt, ...; +- (OFString *)forwardingTargetVarArgTest: (OFConstantString *)format, ...; - (long double)forwardingTargetFPRetTest; -- (struct stret_test)forwardingTargetStRetTest; +- (struct StretTest)forwardingTargetStRetTest; - (void)forwardingTargetNilTest; - (void)forwardingTargetSelfTest; -- (struct stret_test)forwardingTargetNilStRetTest; -- (struct stret_test)forwardingTargetSelfStRetTest; +- (struct StretTest)forwardingTargetNilStRetTest; +- (struct StretTest)forwardingTargetSelfStRetTest; @end @interface ForwardingTarget: OFObject @end @@ -64,11 +62,11 @@ } @implementation ForwardingTest + (bool)resolveClassMethod: (SEL)selector { - forwardings++; + forwardingsCount++; if (sel_isEqual(selector, @selector(test))) { class_replaceMethod(object_getClass(self), @selector(test), (IMP)test, "v#:"); return YES; @@ -77,11 +75,11 @@ return NO; } + (bool)resolveInstanceMethod: (SEL)selector { - forwardings++; + forwardingsCount++; if (sel_isEqual(selector, @selector(test))) { class_replaceMethod(self, @selector(test), (IMP)test, "v@:"); return YES; } @@ -127,11 +125,11 @@ - (uint32_t)forwardingTargetTest: (intptr_t)a0 : (intptr_t)a1 : (double)a2 : (double)a3 { - OF_ENSURE(self == target); + OFEnsure(self == target); if (a0 != (intptr_t)0xDEADBEEF) return 0; if (a1 != -1) return 0; @@ -141,39 +139,39 @@ return 0; return 0x12345678; } -- (OFString *)forwardingTargetVarArgTest: (OFConstantString *)fmt, ... +- (OFString *)forwardingTargetVarArgTest: (OFConstantString *)format, ... { va_list args; OFString *ret; - OF_ENSURE(self == target); + OFEnsure(self == target); - va_start(args, fmt); - ret = [[[OFString alloc] initWithFormat: fmt + va_start(args, format); + ret = [[[OFString alloc] initWithFormat: format arguments: args] autorelease]; va_end(args); return ret; } - (long double)forwardingTargetFPRetTest { - OF_ENSURE(self == target); + OFEnsure(self == target); return 12345678.00006103515625; } -- (struct stret_test)forwardingTargetStRetTest +- (struct StretTest)forwardingTargetStRetTest { - struct stret_test ret = { { 0 } }; + struct StretTest ret = { { 0 } }; - OF_ENSURE(self == target); + OFEnsure(self == target); - memcpy(ret.s, "abcdefghijklmnopqrstuvwxyz", 27); + memcpy(ret.buffer, "abcdefghijklmnopqrstuvwxyz", 27); return ret; } @end @@ -182,55 +180,58 @@ { void *pool = objc_autoreleasePoolPush(); TEST(@"Forwarding a message and adding a class method", R([ForwardingTest test]) && success && - R([ForwardingTest test]) && forwardings == 1); + R([ForwardingTest test]) && forwardingsCount == 1); - ForwardingTest *t = [[[ForwardingTest alloc] init] autorelease]; + ForwardingTest *testObject = + [[[ForwardingTest alloc] init] autorelease]; success = false; - forwardings = 0; + forwardingsCount = 0; TEST(@"Forwarding a message and adding an instance method", - R([t test]) && success && R([t test]) && forwardings == 1); + R([testObject test]) && success && R([testObject test]) && + forwardingsCount == 1); #ifdef OF_HAVE_FORWARDING_TARGET_FOR_SELECTOR target = [[[ForwardingTarget alloc] init] autorelease]; TEST(@"-[forwardingTargetForSelector:]", - [t forwardingTargetTest: 0xDEADBEEF - : -1 - : 1.25 - : 2.75] == 0x12345678) + [testObject forwardingTargetTest: 0xDEADBEEF + : -1 + : 1.25 + : 2.75] == 0x12345678) TEST(@"-[forwardingTargetForSelector:] variable arguments", - [[t forwardingTargetVarArgTest: FMT, ARGS] isEqual: RESULT]) + [[testObject forwardingTargetVarArgTest: FORMAT, ARGS] + 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) TEST(@"-[forwardingTargetForSelector:] fp return", - [t forwardingTargetFPRetTest] == 12345678.00006103515625) + [testObject forwardingTargetFPRetTest] == 12345678.00006103515625) # endif # ifdef OF_HAVE_FORWARDING_TARGET_FOR_SELECTOR_STRET TEST(@"-[forwardingTargetForSelector:] struct return", - !memcmp([t forwardingTargetStRetTest].s, + !memcmp([testObject forwardingTargetStRetTest].buffer, "abcdefghijklmnopqrstuvwxyz", 27)) # endif EXPECT_EXCEPTION(@"-[forwardingTargetForSelector:] nil target", - OFNotImplementedException, [t forwardingTargetNilTest]) + OFNotImplementedException, [testObject forwardingTargetNilTest]) EXPECT_EXCEPTION(@"-[forwardingTargetForSelector:] self target", - OFNotImplementedException, [t forwardingTargetSelfTest]) + OFNotImplementedException, [testObject forwardingTargetSelfTest]) # ifdef OF_HAVE_FORWARDING_TARGET_FOR_SELECTOR_STRET EXPECT_EXCEPTION(@"-[forwardingTargetForSelector:] nil target + " @"stret", OFNotImplementedException, - [t forwardingTargetNilStRetTest]) + [testObject forwardingTargetNilStRetTest]) EXPECT_EXCEPTION(@"-[forwardingTargetForSelector:] self target + " @"stret", OFNotImplementedException, - [t forwardingTargetSelfStRetTest]) + [testObject forwardingTargetSelfStRetTest]) # endif #endif objc_autoreleasePoolPop(pool); } @end Index: tests/ImportTest.m ================================================================== --- tests/ImportTest.m +++ tests/ImportTest.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: tests/Makefile ================================================================== --- tests/Makefile +++ tests/Makefile @@ -1,8 +1,10 @@ include ../extra.mk -SUBDIRS = ${TESTPLUGIN} +SUBDIRS = ${TESTPLUGIN} \ + ${OBJC_SYNC} \ + terminal CLEAN = EBOOT.PBP \ boot.dol \ ${PROG_NOINST}.arm9 \ ${PROG_NOINST}.nds @@ -9,12 +11,10 @@ DISTCLEAN = Info.plist PROG_NOINST = tests${PROG_SUFFIX} STATIC_LIB_NOINST = ${TESTS_STATIC_LIB} SRCS = ForwardingTests.m \ - OFASN1DERParsingTests.m \ - OFASN1DERRepresentationTests.m \ OFArrayTests.m \ ${OF_BLOCK_TESTS_M} \ OFCharacterSetTests.m \ OFDataTests.m \ OFDateTests.m \ @@ -22,26 +22,27 @@ OFInvocationTests.m \ OFJSONTests.m \ OFListTests.m \ OFLocaleTests.m \ OFMethodSignatureTests.m \ + OFNotificationCenterTests.m \ OFNumberTests.m \ OFObjectTests.m \ + OFPBKDF2Tests.m \ OFPropertyListTests.m \ + OFScryptTests.m \ OFSetTests.m \ OFStreamTests.m \ OFStringTests.m \ OFSystemInfoTests.m \ OFURLTests.m \ OFValueTests.m \ OFXMLElementBuilderTests.m \ OFXMLNodeTests.m \ OFXMLParserTests.m \ - PBKDF2Tests.m \ RuntimeTests.m \ ${RUNTIME_ARC_TESTS_M} \ - ScryptTests.m \ TestsAppDelegate.m \ ${USE_SRCS_FILES} \ ${USE_SRCS_PLUGINS} \ ${USE_SRCS_SOCKETS} \ ${USE_SRCS_THREADS} \ @@ -54,54 +55,55 @@ OFSHA1HashTests.m \ OFSHA224HashTests.m \ OFSHA256HashTests.m \ OFSHA384HashTests.m \ OFSHA512HashTests.m -SRCS_IPX = OFIPXSocketTests.m \ - OFSPXSocketTests.m \ - OFSPXStreamSocketTests.m SRCS_PLUGINS = OFPluginTests.m -SRCS_SCTP = OFSCTPSocketTests.m SRCS_SOCKETS = OFDNSResolverTests.m \ ${OF_HTTP_CLIENT_TESTS_M} \ OFHTTPCookieTests.m \ OFHTTPCookieManagerTests.m \ OFKernelEventObserverTests.m \ + OFSocketTests.m \ OFTCPSocketTests.m \ OFUDPSocketTests.m \ - SocketTests.m \ ${USE_SRCS_IPX} \ - ${USE_SRCS_SCTP} + ${USE_SRCS_UNIX_SOCKETS} +SRCS_IPX = OFIPXSocketTests.m \ + OFSPXSocketTests.m \ + OFSPXStreamSocketTests.m +SRCS_UNIX_SOCKETS = OFUNIXDatagramSocketTests.m \ + OFUNIXStreamSocketTests.m SRCS_THREADS = OFThreadTests.m SRCS_WINDOWS = OFWindowsRegistryKeyTests.m IOS_USER ?= mobile IOS_TMP ?= /tmp/objfw-test include ../buildsys.mk -post-all: ${RUN_TESTS} - .PHONY: run run-on-ios run-on-android run: rm -f libobjfw.so.${OBJFW_LIB_MAJOR} rm -f libobjfw.so.${OBJFW_LIB_MAJOR_MINOR} - rm -f objfw.dll libobjfw.${OBJFW_LIB_MAJOR}.dylib + 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.dll libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib + 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.dll; then \ - ${LN_S} ../src/objfw.dll objfw.dll; \ + 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 @@ -111,12 +113,13 @@ ${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.dll; then \ - ${LN_S} ../src/runtime/objfwrt.dll objfwrt.dll; \ + 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 @@ -129,14 +132,16 @@ 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} objfw.dll; \ + 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} objfwrt.dll; \ + rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR}; \ + rm -f objfwrt${OBJFWRT_LIB_MAJOR}.dll; \ rm -f libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib; \ exit $$EXIT run-on-ios: all if [ -z "${IOS_HOST}" ]; then \ DELETED tests/OFASN1DERParsingTests.m Index: tests/OFASN1DERParsingTests.m ================================================================== --- tests/OFASN1DERParsingTests.m +++ /dev/null @@ -1,483 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 *module = @"OFData+ASN1DERParsing"; - -@implementation TestsAppDelegate (OFASN1DERParsingTests) -- (void)ASN1DERParsingTests -{ - void *pool = objc_autoreleasePoolPush(); - OFASN1BitString *bitString; - OFArray *array; - OFSet *set; - OFEnumerator *enumerator; - - /* Boolean */ - TEST(@"Parsing of boolean", - ![[[OFData dataWithItems: "\x01\x01\x00" - count: 3] objectByParsingASN1DER] - booleanValue] && - [[[OFData dataWithItems: "\x01\x01\xFF" - count: 3] objectByParsingASN1DER] booleanValue]) - - EXPECT_EXCEPTION(@"Detection of invalid boolean #1", - OFInvalidFormatException, - [[OFData dataWithItems: "\x01\x01\x01" - count: 3] objectByParsingASN1DER]) - - EXPECT_EXCEPTION(@"Detection of invalid boolean #2", - OFInvalidFormatException, - [[OFData dataWithItems: "\x01\x02\x00\x00" - count: 4] objectByParsingASN1DER]) - - EXPECT_EXCEPTION(@"Detection of invalid boolean #3", - OFInvalidFormatException, - [[OFData dataWithItems: "\x01\x00" - count: 2] objectByParsingASN1DER]) - - EXPECT_EXCEPTION(@"Detection of truncated boolean", - OFTruncatedDataException, - [[OFData dataWithItems: "\x01\x01" - count: 2] objectByParsingASN1DER]) - - /* Integer */ - TEST(@"Parsing of integer", - [[[OFData dataWithItems: "\x02\x00" - count: 2] objectByParsingASN1DER] - longLongValue] == 0 && - [[[OFData dataWithItems: "\x02\x01\x01" - count: 3] objectByParsingASN1DER] - longLongValue] == 1 && - [[[OFData dataWithItems: "\x02\x02\x01\x04" - count: 4] objectByParsingASN1DER] - longLongValue] == 260 && - [[[OFData dataWithItems: "\x02\x01\xFF" - count: 3] objectByParsingASN1DER] - longLongValue] == -1 && - [[[OFData dataWithItems: "\x02\x03\xFF\x00\x00" - count: 5] objectByParsingASN1DER] - longLongValue] == -65536 && - (unsigned long long)[[[OFData dataWithItems: "\x02\x09\x00\xFF\xFF" - "\xFF\xFF\xFF\xFF\xFF" - "\xFF" - count: 11] - objectByParsingASN1DER] longLongValue] == ULLONG_MAX) - - EXPECT_EXCEPTION(@"Detection of invalid integer #1", - OFInvalidFormatException, - [[OFData dataWithItems: "\x02\x02\x00\x00" - count: 4] objectByParsingASN1DER]) - - EXPECT_EXCEPTION(@"Detection of invalid integer #2", - OFInvalidFormatException, - [[OFData dataWithItems: "\x02\x02\x00\x7F" - count: 4] objectByParsingASN1DER]) - - EXPECT_EXCEPTION(@"Detection of invalid integer #3", - OFInvalidFormatException, - [[OFData dataWithItems: "\x02\x02\xFF\x80" - count: 4] objectByParsingASN1DER]) - - EXPECT_EXCEPTION(@"Detection of out of range integer", - OFOutOfRangeException, - [[OFData dataWithItems: "\x02\x09\x01" - "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" - count: 11] objectByParsingASN1DER]) - - EXPECT_EXCEPTION(@"Detection of truncated integer", - OFTruncatedDataException, - [[OFData dataWithItems: "\x02\x02\x00" - count: 3] objectByParsingASN1DER]) - - /* Bit string */ - TEST(@"Parsing of bit string", - (bitString = [[OFData dataWithItems: "\x03\x01\x00" - count: 3] objectByParsingASN1DER]) && - [bitString.bitStringValue isEqual: [OFData dataWithItems: "" - count: 0]] && - bitString.bitStringLength == 0 && - (bitString = [[OFData dataWithItems: "\x03\x0D\x01Hello World\x80" - count: 15] objectByParsingASN1DER]) && - [bitString.bitStringValue - isEqual: [OFData dataWithItems: "Hello World\x80" - count: 12]] && - bitString.bitStringLength == 95 && - (bitString = [[OFData dataWithItems: "\x03\x81\x80\x00xxxxxxxxxxxxx" - "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - "xxxxxxxxxxxxxxxxxxxxxxxxxxx" - count: 131] objectByParsingASN1DER]) && - [bitString.bitStringValue - isEqual: [OFData dataWithItems: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - "xxxxxxxxxxxxxxxxxxxxxxxxx" - count: 127]] && - bitString.bitStringLength == 127 * 8) - - EXPECT_EXCEPTION(@"Detection of invalid bit string #1", - OFInvalidFormatException, - [[OFData dataWithItems: "\x03\x00" - count: 2] objectByParsingASN1DER]) - - EXPECT_EXCEPTION(@"Detection of invalid bit string #2", - OFInvalidFormatException, - [[OFData dataWithItems: "\x03\x01\x01" - count: 3] objectByParsingASN1DER]) - - EXPECT_EXCEPTION(@"Detection of out of range bit string", - OFOutOfRangeException, - [[OFData dataWithItems: "\x03\x89" - "\x01\x01\x01\x01\x01\x01\x01\x01\x01" - count: 11] objectByParsingASN1DER]) - - EXPECT_EXCEPTION(@"Detection of truncated bit string", - OFTruncatedDataException, - [[OFData dataWithItems: "\x03\x01" - count: 2] objectByParsingASN1DER]) - - /* Octet string */ - TEST(@"Parsing of octet string", - [[[[OFData dataWithItems: "\x04\x0CHello World!" - count: 14] objectByParsingASN1DER] - octetStringValue] isEqual: [OFData dataWithItems: "Hello World!" - count: 12]] && - [[[[OFData dataWithItems: "\x04\x81\x80xxxxxxxxxxxxxxxxxxxxxxxxxxxx" - "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - "xxxxxxxxxxxxxxxxxxxx" - count: 131] objectByParsingASN1DER] - octetStringValue] isEqual: - [OFData dataWithItems: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - count: 128]]) - - EXPECT_EXCEPTION(@"Detection of out of range octet string", - OFOutOfRangeException, - [[OFData dataWithItems: "\x04\x89" - "\x01\x01\x01\x01\x01\x01\x01\x01\x01" - count: 11] objectByParsingASN1DER]) - - EXPECT_EXCEPTION(@"Detection of truncated octet string", - OFTruncatedDataException, - [[OFData dataWithItems: "\x04\x01" - count: 2] objectByParsingASN1DER]) - - /* Null */ - TEST(@"Parsing of null", - [[[OFData dataWithItems: "\x05\x00" - count: 2] objectByParsingASN1DER] - isEqual: [OFNull null]]) - - EXPECT_EXCEPTION(@"Detection of invalid null", - OFInvalidFormatException, - [[OFData dataWithItems: "\x05\x01\x00" - count: 3] objectByParsingASN1DER]) - - /* Object Identifier */ - TEST(@"Parsing of Object Identifier", - (array = [[[OFData dataWithItems: "\x06\x01\x27" - count: 3] objectByParsingASN1DER] - subidentifiers]) && array.count == 2 && - [[array objectAtIndex: 0] unsignedLongLongValue] == 0 && - [[array objectAtIndex: 1] unsignedLongLongValue] == 39 && - (array = [[[OFData dataWithItems: "\x06\x01\x4F" - count: 3] objectByParsingASN1DER] - subidentifiers]) && array.count == 2 && - [[array objectAtIndex: 0] unsignedLongLongValue] == 1 && - [[array objectAtIndex: 1] unsignedLongLongValue] == 39 && - (array = [[[OFData dataWithItems: "\x06\x02\x88\x37" - count: 4] objectByParsingASN1DER] - subidentifiers]) && array.count == 2 && - [[array objectAtIndex: 0] unsignedLongLongValue] == 2 && - [[array objectAtIndex: 1] unsignedLongLongValue] == 999 && - (array = [[[OFData dataWithItems: "\x06\x09\x2A\x86\x48\x86\xF7\x0D" - "\x01\x01\x0B" - count: 11] objectByParsingASN1DER] - subidentifiers]) && array.count == 7 && - [[array objectAtIndex: 0] unsignedLongLongValue] == 1 && - [[array objectAtIndex: 1] unsignedLongLongValue] == 2 && - [[array objectAtIndex: 2] unsignedLongLongValue] == 840 && - [[array objectAtIndex: 3] unsignedLongLongValue] == 113549 && - [[array objectAtIndex: 4] unsignedLongLongValue] == 1 && - [[array objectAtIndex: 5] unsignedLongLongValue] == 1 && - [[array objectAtIndex: 6] unsignedLongLongValue] == 11) - - EXPECT_EXCEPTION(@"Detection of invalid Object Identifier #1", - OFInvalidFormatException, - [[OFData dataWithItems: "\x06\x01\x81" - count: 3] objectByParsingASN1DER]) - - EXPECT_EXCEPTION(@"Detection of invalid Object Identifier #2", - OFInvalidFormatException, - [[OFData dataWithItems: "\x06\x02\x80\x01" - count: 4] objectByParsingASN1DER]) - - EXPECT_EXCEPTION(@"Detection of out of range Object Identifier", - OFOutOfRangeException, - [[OFData dataWithItems: "\x06\x0A\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" - "\xFF\x7F" - count: 12] objectByParsingASN1DER]) - - EXPECT_EXCEPTION(@"Detection of truncated Object Identifier", - OFTruncatedDataException, - [[OFData dataWithItems: "\x06\x02\x00" - count: 3] objectByParsingASN1DER]) - - /* Enumerated */ - TEST(@"Parsing of enumerated", - [[[OFData dataWithItems: "\x0A\x00" - count: 2] objectByParsingASN1DER] longLongValue] == - 0 && - [[[OFData dataWithItems: "\x0A\x01\x01" - count: 3] objectByParsingASN1DER] longLongValue] == - 1 && - [[[OFData dataWithItems: "\x0A\x02\x01\x04" - count: 4] objectByParsingASN1DER] longLongValue] == - 260 && - [[[OFData dataWithItems: "\x0A\x01\xFF" - count: 3] objectByParsingASN1DER] longLongValue] == - -1 && - [[[OFData dataWithItems: "\x0A\x03\xFF\x00\x00" - count: 5] objectByParsingASN1DER] longLongValue] == - -65536 && - (unsigned long long)[[[OFData dataWithItems: "\x0A\x09\x00\xFF\xFF" - "\xFF\xFF\xFF\xFF\xFF" - "\xFF" - count: 11] - objectByParsingASN1DER] longLongValue] == ULLONG_MAX) - - EXPECT_EXCEPTION(@"Detection of invalid enumerated #1", - OFInvalidFormatException, - [[OFData dataWithItems: "\x0A\x02\x00\x00" - count: 4] objectByParsingASN1DER]) - - EXPECT_EXCEPTION(@"Detection of invalid enumerated #2", - OFInvalidFormatException, - [[OFData dataWithItems: "\x0A\x02\x00\x7F" - count: 4] objectByParsingASN1DER]) - - EXPECT_EXCEPTION(@"Detection of invalid enumerated #3", - OFInvalidFormatException, - [[OFData dataWithItems: "\x0A\x02\xFF\x80" - count: 4] objectByParsingASN1DER]) - - EXPECT_EXCEPTION(@"Detection of out of range enumerated", - OFOutOfRangeException, - [[OFData dataWithItems: "\x0A\x09\x01" - "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" - count: 11] objectByParsingASN1DER]) - - EXPECT_EXCEPTION(@"Detection of truncated enumerated", - OFTruncatedDataException, - [[OFData dataWithItems: "\x0A\x02\x00" - count: 3] objectByParsingASN1DER]) - - /* UTF-8 string */ - TEST(@"Parsing of UTF-8 string", - [[[[OFData dataWithItems: "\x0C\x0EHällo Wörld!" - count: 16] objectByParsingASN1DER] - UTF8StringValue] isEqual: @"Hällo Wörld!"] && - [[[[OFData dataWithItems: "\x0C\x81\x80xxxxxxxxxxxxxxxxxxxxxxxxxxxx" - "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - "xxxxxxxxxxxxxxxxxxxx" - count: 131] objectByParsingASN1DER] - UTF8StringValue] isEqual: @"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - @"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - @"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - @"xxxxxxxxxxx"]) - - EXPECT_EXCEPTION(@"Detection of out of range UTF-8 string", - OFOutOfRangeException, - [[OFData dataWithItems: "\x0C\x89" - "\x01\x01\x01\x01\x01\x01\x01\x01\x01" - count: 11] objectByParsingASN1DER]) - - EXPECT_EXCEPTION(@"Detection of truncated UTF-8 string", - OFTruncatedDataException, - [[OFData dataWithItems: "\x0C\x01" - count: 2] objectByParsingASN1DER]) - - EXPECT_EXCEPTION(@"Detection of truncated length", - OFTruncatedDataException, - [[OFData dataWithItems: "\x0C\x83\x01\x01" - count: 4] objectByParsingASN1DER]) - - EXPECT_EXCEPTION(@"Detection of invalid / inefficient length #1", - OFInvalidFormatException, - [[OFData dataWithItems: "\x0C\x81\x7F" - count: 3] objectByParsingASN1DER]) - - EXPECT_EXCEPTION(@"Detection of invalid / inefficient length #2", - OFInvalidFormatException, - [[OFData dataWithItems: "\x0C\x82\x00\x80xxxxxxxxxxxxxxxxxxxxxxxxxx" - "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - "xxxxxxxxxxxxxxxxxx" - count: 132] objectByParsingASN1DER]) - - /* Sequence */ - TEST(@"Parsing of sequence", - (array = [[OFData dataWithItems: "\x30\x00" - count: 2] objectByParsingASN1DER]) && - [array isKindOfClass: [OFArray class]] && array.count == 0 && - (array = [[OFData dataWithItems: "\x30\x09\x02\x01\x7B\x0C\x04Test" - count: 11] objectByParsingASN1DER]) && - [array isKindOfClass: [OFArray class]] && array.count == 2 && - [[array objectAtIndex: 0] longLongValue] == 123 && - [[[array objectAtIndex: 1] stringValue] isEqual: @"Test"]) - - EXPECT_EXCEPTION(@"Detection of truncated sequence #1", - OFTruncatedDataException, - [[OFData dataWithItems: "\x30\x01" - count: 2] objectByParsingASN1DER]) - - EXPECT_EXCEPTION(@"Detection of truncated sequence #2", - OFTruncatedDataException, - [[OFData dataWithItems: "\x30\x04\x02\x01\x01\x00\x00" - count: 7] objectByParsingASN1DER]) - - /* Set */ - TEST(@"Parsing of set", - (set = [[OFData dataWithItems: "\x31\x00" - count: 2] objectByParsingASN1DER]) && - [set isKindOfClass: [OFSet class]] && set.count == 0 && - (set = [[OFData dataWithItems: "\x31\x09\x02\x01\x7B\x0C\x04Test" - count: 11] objectByParsingASN1DER]) && - [set isKindOfClass: [OFSet class]] && set.count == 2 && - (enumerator = [set objectEnumerator]) && - [[enumerator nextObject] longLongValue] == 123 && - [[[enumerator nextObject] stringValue] isEqual: @"Test"]) - - EXPECT_EXCEPTION(@"Detection of invalid set", - OFInvalidFormatException, - [[OFData dataWithItems: "\x31\x06\x02\x01\x02\x02\x01\x01" - count: 8] objectByParsingASN1DER]) - - EXPECT_EXCEPTION(@"Detection of truncated set #1", - OFTruncatedDataException, - [[OFData dataWithItems: "\x31\x01" - count: 2] objectByParsingASN1DER]) - - EXPECT_EXCEPTION(@"Detection of truncated set #2", - OFTruncatedDataException, - [[OFData dataWithItems: "\x31\x04\x02\x01\x01\x00\x00" - count: 7] objectByParsingASN1DER]) - - /* NumericString */ - TEST(@"Parsing of NumericString", - [[[[OFData dataWithItems: "\x12\x0B" "12345 67890" - count: 13] objectByParsingASN1DER] - numericStringValue] isEqual: @"12345 67890"] && - [[[[OFData dataWithItems: "\x12\x81\x80" "0000000000000000000000000" - "0000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000" - "00000000000000000000000" - count: 131] objectByParsingASN1DER] - numericStringValue] isEqual: @"000000000000000000000000000000000000" - @"000000000000000000000000000000000000" - @"000000000000000000000000000000000000" - @"00000000000000000000"]) - - EXPECT_EXCEPTION(@"Detection of invalid NumericString", - OFInvalidEncodingException, - [[OFData dataWithItems: "\x12\x02." - count: 4] objectByParsingASN1DER]) - - EXPECT_EXCEPTION(@"Detection of out of range NumericString", - OFOutOfRangeException, - [[OFData dataWithItems: "\x12\x89" - "\x01\x01\x01\x01\x01\x01\x01\x01\x01" - count: 11] objectByParsingASN1DER]) - - EXPECT_EXCEPTION(@"Detection of truncated NumericString", - OFTruncatedDataException, - [[OFData dataWithItems: "\x12\x01" - count: 2] objectByParsingASN1DER]) - - /* PrintableString */ - TEST(@"Parsing of PrintableString", - [[[[OFData dataWithItems: "\x13\x0CHello World." - count: 14] objectByParsingASN1DER] - printableStringValue] isEqual: @"Hello World."] && - [[[[OFData dataWithItems: "\x13\x81\x80 '()+,-./:=?abcdefghijklmnop" - "qrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ '()" - "+,-./:=?abcdefghijklmnopqrstuvwxyzABCDEF" - "GHIJKLMNOPQRSTUVWXYZ" - count: 131] objectByParsingASN1DER] - printableStringValue] isEqual: @" '()+,-./:=?abcdefghijklmnopqrstuv" - @"wxyzABCDEFGHIJKLMNOPQRSTUVWXYZ '()" - @"+,-./:=?abcdefghijklmnopqrstuvwxyz" - @"ABCDEFGHIJKLMNOPQRSTUVWXYZ"]) - - EXPECT_EXCEPTION(@"Detection of invalid PrintableString", - OFInvalidEncodingException, - [[OFData dataWithItems: "\x13\x02;" - count: 4] objectByParsingASN1DER]) - - EXPECT_EXCEPTION(@"Detection of out of range PrintableString", - OFOutOfRangeException, - [[OFData dataWithItems: "\x13\x89" - "\x01\x01\x01\x01\x01\x01\x01\x01\x01" - count: 11] objectByParsingASN1DER]) - - EXPECT_EXCEPTION(@"Detection of truncated PrintableString", - OFTruncatedDataException, - [[OFData dataWithItems: "\x13\x01" - count: 2] objectByParsingASN1DER]) - - /* IA5String */ - TEST(@"Parsing of IA5String", - [[[[OFData dataWithItems: "\x16\x0CHello World!" - count: 14] objectByParsingASN1DER] - IA5StringValue] isEqual: @"Hello World!"] && - [[[[OFData dataWithItems: "\x16\x81\x80xxxxxxxxxxxxxxxxxxxxxxxxxxxx" - "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - "xxxxxxxxxxxxxxxxxxxx" - count: 131] objectByParsingASN1DER] - IA5StringValue] isEqual: @"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - @"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - @"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - @"xxxxxxxx"]) - - EXPECT_EXCEPTION(@"Detection of invalid IA5String", - OFInvalidEncodingException, - [[OFData dataWithItems: "\x16\x02ä" - count: 4] objectByParsingASN1DER]) - - EXPECT_EXCEPTION(@"Detection of out of range IA5String", - OFOutOfRangeException, - [[OFData dataWithItems: "\x16\x89" - "\x01\x01\x01\x01\x01\x01\x01\x01\x01" - count: 11] objectByParsingASN1DER]) - - EXPECT_EXCEPTION(@"Detection of truncated IA5String", - OFTruncatedDataException, - [[OFData dataWithItems: "\x16\x01" - count: 2] objectByParsingASN1DER]) - - objc_autoreleasePoolPop(pool); -} -@end DELETED tests/OFASN1DERRepresentationTests.m Index: tests/OFASN1DERRepresentationTests.m ================================================================== --- tests/OFASN1DERRepresentationTests.m +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 *module; - -@implementation TestsAppDelegate (OFASN1DERRepresentationTests) -- (void)ASN1DERRepresentationTests -{ - void *pool = objc_autoreleasePoolPush(); - OFData *data; - - module = @"OFASN1BitString"; - TEST(@"-[ASN1DERRepresentation]", - (data = [OFData dataWithItems: "\xFF\x00\xF8" - count: 3]) && - [[[OFASN1BitString bitStringWithBitStringValue: data - bitStringLength: 21] - ASN1DERRepresentation] isEqual: - [OFData dataWithItems: "\x03\x04\x03\xFF\x00\xF8" - count: 6]] && - (data = [OFData dataWithItems: "abcdefäöü" - count: 12]) && - [[[OFASN1BitString bitStringWithBitStringValue: data - bitStringLength: 12 * 8] - ASN1DERRepresentation] isEqual: - [OFData dataWithItems: "\x03\x0D\x00" "abcdefäöü" - count: 15]] && - (data = [OFData dataWithItems: "" - count: 0]) && - [[[OFASN1BitString bitStringWithBitStringValue: data - bitStringLength: 0] - ASN1DERRepresentation] isEqual: - [OFData dataWithItems: "\x03\x01\x00" - count: 3]]) - - module = @"OFASN1Boolean"; - TEST(@"-[ASN1DERRepresentation]", - [[[OFASN1Boolean booleanWithBooleanValue: false] - ASN1DERRepresentation] isEqual: - [OFData dataWithItems: "\x01\x01\x00" - count: 3]] && - [[[OFASN1Boolean booleanWithBooleanValue: true] - ASN1DERRepresentation] isEqual: - [OFData dataWithItems: "\x01\x01\xFF" - count: 3]]) - - module = @"OFNull"; - TEST(@"-[OFASN1DERRepresentation]", - [[[OFNull null] ASN1DERRepresentation] isEqual: - [OFData dataWithItems: "\x05\x00" - count: 2]]) - - objc_autoreleasePoolPop(pool); -} -@end Index: tests/OFArrayTests.m ================================================================== --- tests/OFArrayTests.m +++ tests/OFArrayTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -17,12 +15,12 @@ #include "config.h" #import "TestsAppDelegate.h" -static OFString *module = nil; -static OFString *c_ary[] = { +static OFString *module; +static OFString *const cArray[] = { @"Foo", @"Bar", @"Baz" }; @@ -51,12 +49,11 @@ } return self; } -- (instancetype)initWithObject: (id)object - arguments: (va_list)arguments +- (instancetype)initWithObject: (id)object arguments: (va_list)arguments { self = [super init]; @try { _array = [[OFMutableArray alloc] initWithObject: object @@ -67,12 +64,11 @@ } return self; } -- (instancetype)initWithObjects: (id const *)objects - count: (size_t)count +- (instancetype)initWithObjects: (id const *)objects count: (size_t)count { self = [super init]; @try { _array = [[OFMutableArray alloc] initWithObjects: objects @@ -108,22 +104,18 @@ { if (self == [SimpleMutableArray class]) [self inheritMethodsFromClass: [SimpleArray class]]; } -- (void)insertObject: (id)object - atIndex: (size_t)idx +- (void)insertObject: (id)object atIndex: (size_t)idx { - [_array insertObject: object - atIndex: idx]; + [_array insertObject: object atIndex: idx]; } -- (void)replaceObjectAtIndex: (size_t)idx - withObject: (id)object +- (void)replaceObjectAtIndex: (size_t)idx withObject: (id)object { - [_array replaceObjectAtIndex: idx - withObject: object]; + [_array replaceObjectAtIndex: idx withObject: object]; } - (void)removeObjectAtIndex: (size_t)idx { [_array removeObjectAtIndex: idx]; @@ -133,291 +125,302 @@ @implementation TestsAppDelegate (OFArrayTests) - (void)arrayTestsWithClass: (Class)arrayClass mutableClass: (Class)mutableArrayClass { void *pool = objc_autoreleasePoolPush(); - OFArray *a[3]; - OFMutableArray *m[2]; + OFArray *array1, *array2; + OFMutableArray *mutableArray1, *mutableArray2; OFEnumerator *enumerator; - id obj; + id object; bool ok; size_t i; - TEST(@"+[array]", (m[0] = [mutableArrayClass array])) + TEST(@"+[array]", (mutableArray1 = [mutableArrayClass array])) TEST(@"+[arrayWithObjects:]", - (a[0] = [arrayClass arrayWithObjects: @"Foo", @"Bar", @"Baz", nil])) + (array1 = + [arrayClass arrayWithObjects: @"Foo", @"Bar", @"Baz", nil])) TEST(@"+[arrayWithObjects:count:]", - (a[1] = [arrayClass arrayWithObjects: c_ary - count: 3]) && - [a[1] isEqual: a[0]]) + (array2 = [arrayClass arrayWithObjects: cArray count: 3]) && + [array2 isEqual: array1]) TEST(@"-[description]", - [a[0].description isEqual: @"(\n\tFoo,\n\tBar,\n\tBaz\n)"]) - - TEST(@"-[addObject:]", R([m[0] addObject: c_ary[0]]) && - R([m[0] addObject: c_ary[2]])) - - TEST(@"-[insertObject:atIndex:]", R([m[0] insertObject: c_ary[1] - atIndex: 1])) - - TEST(@"-[count]", m[0].count == 3 && a[0].count == 3 && a[1].count == 3) - - TEST(@"-[isEqual:]", [m[0] isEqual: a[0]] && [a[0] isEqual: a[1]]) + [array1.description isEqual: @"(\n\tFoo,\n\tBar,\n\tBaz\n)"]) + + TEST(@"-[addObject:]", + R([mutableArray1 addObject: cArray[0]]) && + R([mutableArray1 addObject: cArray[2]])) + + TEST(@"-[insertObject:atIndex:]", + R([mutableArray1 insertObject: cArray[1] atIndex: 1])) + + TEST(@"-[count]", + mutableArray1.count == 3 && array1.count == 3 && array2.count == 3) + + TEST(@"-[isEqual:]", + [mutableArray1 isEqual: array1] && [array1 isEqual: array2]) TEST(@"-[objectAtIndex:]", - [[m[0] objectAtIndex: 0] isEqual: c_ary[0]] && - [[m[0] objectAtIndex: 1] isEqual: c_ary[1]] && - [[m[0] objectAtIndex: 2] isEqual: c_ary[2]] && - [[a[0] objectAtIndex: 0] isEqual: c_ary[0]] && - [[a[0] objectAtIndex: 1] isEqual: c_ary[1]] && - [[a[0] objectAtIndex: 2] isEqual: c_ary[2]] && - [[a[1] objectAtIndex: 0] isEqual: c_ary[0]] && - [[a[1] objectAtIndex: 1] isEqual: c_ary[1]] && - [[a[1] objectAtIndex: 2] isEqual: c_ary[2]]) + [[mutableArray1 objectAtIndex: 0] isEqual: cArray[0]] && + [[mutableArray1 objectAtIndex: 1] isEqual: cArray[1]] && + [[mutableArray1 objectAtIndex: 2] isEqual: cArray[2]] && + [[array1 objectAtIndex: 0] isEqual: cArray[0]] && + [[array1 objectAtIndex: 1] isEqual: cArray[1]] && + [[array1 objectAtIndex: 2] isEqual: cArray[2]] && + [[array2 objectAtIndex: 0] isEqual: cArray[0]] && + [[array2 objectAtIndex: 1] isEqual: cArray[1]] && + [[array2 objectAtIndex: 2] isEqual: cArray[2]]) TEST(@"-[containsObject:]", - [a[0] containsObject: c_ary[1]] && - ![a[0] containsObject: @"nonexistent"]) + [array1 containsObject: cArray[1]] && + ![array1 containsObject: @"nonexistent"]) TEST(@"-[containsObjectIdenticalTo:]", - [a[0] containsObjectIdenticalTo: c_ary[1]] && - ![a[0] containsObjectIdenticalTo: - [OFString stringWithString: c_ary[1]]]) + [array1 containsObjectIdenticalTo: cArray[1]] && + ![array1 containsObjectIdenticalTo: + [OFString stringWithString: cArray[1]]]) - TEST(@"-[indexOfObject:]", [a[0] indexOfObject: c_ary[1]] == 1) + TEST(@"-[indexOfObject:]", [array1 indexOfObject: cArray[1]] == 1) TEST(@"-[indexOfObjectIdenticalTo:]", - [a[1] indexOfObjectIdenticalTo: c_ary[1]] == 1) + [array2 indexOfObjectIdenticalTo: cArray[1]] == 1) TEST(@"-[objectsInRange:]", - [[a[0] objectsInRange: of_range(1, 2)] isEqual: - [arrayClass arrayWithObjects: c_ary[1], c_ary[2], nil]]) + [[array1 objectsInRange: OFRangeMake(1, 2)] isEqual: + [arrayClass arrayWithObjects: cArray[1], cArray[2], nil]]) TEST(@"-[replaceObject:withObject:]", - R([m[0] replaceObject: c_ary[1] - withObject: c_ary[0]]) && - [[m[0] objectAtIndex: 0] isEqual: c_ary[0]] && - [[m[0] objectAtIndex: 1] isEqual: c_ary[0]] && - [[m[0] objectAtIndex: 2] isEqual: c_ary[2]]) + R([mutableArray1 replaceObject: cArray[1] withObject: cArray[0]]) && + [[mutableArray1 objectAtIndex: 0] isEqual: cArray[0]] && + [[mutableArray1 objectAtIndex: 1] isEqual: cArray[0]] && + [[mutableArray1 objectAtIndex: 2] isEqual: cArray[2]]) TEST(@"-[replaceObject:identicalTo:]", - R([m[0] replaceObjectIdenticalTo: c_ary[0] - withObject: c_ary[1]]) && - [[m[0] objectAtIndex: 0] isEqual: c_ary[1]] && - [[m[0] objectAtIndex: 1] isEqual: c_ary[0]] && - [[m[0] objectAtIndex: 2] isEqual: c_ary[2]]) + R([mutableArray1 replaceObjectIdenticalTo: cArray[0] + withObject: cArray[1]]) && + [[mutableArray1 objectAtIndex: 0] isEqual: cArray[1]] && + [[mutableArray1 objectAtIndex: 1] isEqual: cArray[0]] && + [[mutableArray1 objectAtIndex: 2] isEqual: cArray[2]]) TEST(@"-[replaceObjectAtIndex:withObject:]", - R([m[0] replaceObjectAtIndex: 0 - withObject: c_ary[0]]) && - [[m[0] objectAtIndex: 0] isEqual: c_ary[0]] && - [[m[0] objectAtIndex: 1] isEqual: c_ary[0]] && - [[m[0] objectAtIndex: 2] isEqual: c_ary[2]]) + R([mutableArray1 replaceObjectAtIndex: 0 withObject: cArray[0]]) && + [[mutableArray1 objectAtIndex: 0] isEqual: cArray[0]] && + [[mutableArray1 objectAtIndex: 1] isEqual: cArray[0]] && + [[mutableArray1 objectAtIndex: 2] isEqual: cArray[2]]) TEST(@"-[removeObject:]", - R([m[0] removeObject: c_ary[0]]) && m[0].count == 2) + R([mutableArray1 removeObject: cArray[0]]) && + mutableArray1.count == 1) + + [mutableArray1 addObject: cArray[0]]; TEST(@"-[removeObjectIdenticalTo:]", - R([m[0] removeObjectIdenticalTo: c_ary[2]]) && m[0].count == 1) - - m[1] = [[a[0] mutableCopy] autorelease]; - TEST(@"-[removeObjectAtIndex:]", R([m[1] removeObjectAtIndex: 1]) && - m[1].count == 2 && [[m[1] objectAtIndex: 1] isEqual: c_ary[2]]) - - m[1] = [[a[0] mutableCopy] autorelease]; - TEST(@"-[removeObjectsInRange:]", - R([m[1] removeObjectsInRange: of_range(0, 2)]) && - m[1].count == 1 && [[m[1] objectAtIndex: 0] isEqual: c_ary[2]]) - - m[1] = [[a[0] mutableCopy] autorelease]; - [m[1] addObject: @"qux"]; - [m[1] addObject: @"last"]; - TEST(@"-[reverse]", - R([m[1] reverse]) && [m[1] isEqual: [arrayClass arrayWithObjects: - @"last", @"qux", @"Baz", @"Bar", @"Foo", nil]]) - - m[1] = [[a[0] mutableCopy] autorelease]; - [m[1] addObject: @"qux"]; - [m[1] addObject: @"last"]; - TEST(@"-[reversedArray]", - [[m[1] reversedArray] isEqual: [arrayClass arrayWithObjects: - @"last", @"qux", @"Baz", @"Bar", @"Foo", nil]]) - - m[1] = [[a[0] mutableCopy] autorelease]; - [m[1] addObject: @"0"]; - [m[1] addObject: @"z"]; - TEST(@"-[sortedArray]", - [[m[1] sortedArray] isEqual: [arrayClass arrayWithObjects: - @"0", @"Bar", @"Baz", @"Foo", @"z", nil]] && - [[m[1] sortedArrayUsingSelector: @selector(compare:) - options: OF_ARRAY_SORT_DESCENDING] + R([mutableArray1 removeObjectIdenticalTo: cArray[2]]) && + mutableArray1.count == 1) + + mutableArray2 = [[array1 mutableCopy] autorelease]; + TEST(@"-[removeObjectAtIndex:]", + R([mutableArray2 removeObjectAtIndex: 1]) && + mutableArray2.count == 2 && + [[mutableArray2 objectAtIndex: 1] isEqual: cArray[2]]) + + mutableArray2 = [[array1 mutableCopy] autorelease]; + TEST(@"-[removeObjectsInRange:]", + R([mutableArray2 removeObjectsInRange: OFRangeMake(0, 2)]) && + mutableArray2.count == 1 && + [[mutableArray2 objectAtIndex: 0] isEqual: cArray[2]]) + + mutableArray2 = [[array1 mutableCopy] autorelease]; + [mutableArray2 addObject: @"qux"]; + [mutableArray2 addObject: @"last"]; + TEST(@"-[reverse]", + R([mutableArray2 reverse]) && + [mutableArray2 isEqual: [arrayClass arrayWithObjects: + @"last", @"qux", @"Baz", @"Bar", @"Foo", nil]]) + + mutableArray2 = [[array1 mutableCopy] autorelease]; + [mutableArray2 addObject: @"qux"]; + [mutableArray2 addObject: @"last"]; + TEST(@"-[reversedArray]", + [[mutableArray2 reversedArray] isEqual: + [arrayClass arrayWithObjects: + @"last", @"qux", @"Baz", @"Bar", @"Foo", nil]]) + + mutableArray2 = [[array1 mutableCopy] autorelease]; + [mutableArray2 addObject: @"0"]; + [mutableArray2 addObject: @"z"]; + TEST(@"-[sortedArray]", + [[mutableArray2 sortedArray] isEqual: [arrayClass arrayWithObjects: + @"0", @"Bar", @"Baz", @"Foo", @"z", nil]] && + [[mutableArray2 sortedArrayUsingSelector: @selector(compare:) + options: OFArraySortDescending] isEqual: [arrayClass arrayWithObjects: @"z", @"Foo", @"Baz", @"Bar", @"0", nil]]) EXPECT_EXCEPTION(@"Detect out of range in -[objectAtIndex:]", - OFOutOfRangeException, [a[0] objectAtIndex: a[0].count]) + OFOutOfRangeException, [array1 objectAtIndex: array1.count]) EXPECT_EXCEPTION(@"Detect out of range in -[removeObjectsInRange:]", - OFOutOfRangeException, [m[0] removeObjectsInRange: - of_range(0, m[0].count + 1)]) + OFOutOfRangeException, [mutableArray1 removeObjectsInRange: + OFRangeMake(0, mutableArray1.count + 1)]) TEST(@"-[componentsJoinedByString:]", - (a[1] = [arrayClass arrayWithObjects: @"", @"a", @"b", @"c", + (array2 = [arrayClass arrayWithObjects: @"", @"a", @"b", @"c", nil]) && - [[a[1] componentsJoinedByString: @" "] isEqual: @" a b c"] && - (a[1] = [arrayClass arrayWithObject: @"foo"]) && - [[a[1] componentsJoinedByString: @" "] isEqual: @"foo"]) + [[array2 componentsJoinedByString: @" "] isEqual: @" a b c"] && + (array2 = [arrayClass arrayWithObject: @"foo"]) && + [[array2 componentsJoinedByString: @" "] isEqual: @"foo"]) TEST(@"-[componentsJoinedByString:options]", - (a[1] = [arrayClass arrayWithObjects: @"", @"foo", @"", @"", @"bar", - @"", nil]) && [[a[1] componentsJoinedByString: @" " - options: OF_ARRAY_SKIP_EMPTY] + (array2 = [arrayClass arrayWithObjects: @"", @"foo", @"", @"", + @"bar", @"", nil]) && + [[array2 componentsJoinedByString: @" " + options: OFArraySkipEmptyComponents] isEqual: @"foo bar"]) - m[0] = [[a[0] mutableCopy] autorelease]; + mutableArray1 = [[array1 mutableCopy] autorelease]; ok = true; i = 0; - TEST(@"-[objectEnumerator]", (enumerator = [m[0] objectEnumerator])) + TEST(@"-[objectEnumerator]", + (enumerator = [mutableArray1 objectEnumerator])) - while ((obj = [enumerator nextObject]) != nil) { - if (![obj isEqual: c_ary[i]]) + while ((object = [enumerator nextObject]) != nil) { + if (![object isEqual: cArray[i]]) ok = false; - [m[0] replaceObjectAtIndex: i - withObject: @""]; + [mutableArray1 replaceObjectAtIndex: i withObject: @""]; i++; } - if (m[0].count != i) + if (mutableArray1.count != i) ok = false; TEST(@"OFEnumerator's -[nextObject]", ok) - [m[0] removeObjectAtIndex: 0]; + [mutableArray1 removeObjectAtIndex: 0]; EXPECT_EXCEPTION(@"Detection of mutation during enumeration", OFEnumerationMutationException, [enumerator nextObject]) - m[0] = [[a[0] mutableCopy] autorelease]; + mutableArray1 = [[array1 mutableCopy] autorelease]; ok = true; i = 0; - for (OFString *s in m[0]) { - if (![s isEqual: c_ary[i]]) + for (OFString *string in mutableArray1) { + if (![string isEqual: cArray[i]]) ok = false; - [m[0] replaceObjectAtIndex: i - withObject: @""]; + [mutableArray1 replaceObjectAtIndex: i withObject: @""]; i++; } - if (m[0].count != i) + if (mutableArray1.count != i) ok = false; TEST(@"Fast Enumeration", ok) - [m[0] replaceObjectAtIndex: 0 - withObject: c_ary[0]]; - [m[0] replaceObjectAtIndex: 1 - withObject: c_ary[1]]; - [m[0] replaceObjectAtIndex: 2 - withObject: c_ary[2]]; + [mutableArray1 replaceObjectAtIndex: 0 withObject: cArray[0]]; + [mutableArray1 replaceObjectAtIndex: 1 withObject: cArray[1]]; + [mutableArray1 replaceObjectAtIndex: 2 withObject: cArray[2]]; ok = false; i = 0; @try { - for (OFString *s in m[0]) { - (void)s; + for (OFString *string in mutableArray1) { + (void)string; if (i == 0) - [m[0] addObject: @""]; + [mutableArray1 addObject: @""]; i++; } } @catch (OFEnumerationMutationException *e) { ok = true; } TEST(@"Detection of mutation during Fast Enumeration", ok) - [m[0] removeLastObject]; + [mutableArray1 removeLastObject]; #ifdef OF_HAVE_BLOCKS { - __block bool blockOk = true; - __block size_t count = 0; - OFArray *cmp = a[0]; - OFMutableArray *a2; - - m[0] = [[a[0] mutableCopy] autorelease]; - [m[0] enumerateObjectsUsingBlock: - ^ (id object, size_t idx, bool *stop) { - count++; - if (![object isEqual: [cmp objectAtIndex: idx]]) - blockOk = false; - }]; - - if (count != cmp.count) - blockOk = false; - - TEST(@"Enumeration using blocks", blockOk) - - blockOk = false; - a2 = m[0]; - @try { - [a2 enumerateObjectsUsingBlock: - ^ (id object, size_t idx, bool *stop) { - [a2 removeObjectAtIndex: idx]; - }]; - } @catch (OFEnumerationMutationException *e) { - blockOk = true; + __block bool blockOK = true; + __block size_t count = 0; + OFArray *compareArray = array1; + OFMutableArray *mutableArray3; + + mutableArray1 = [[array1 mutableCopy] autorelease]; + [mutableArray1 enumerateObjectsUsingBlock: + ^ (id object_, size_t idx, bool *stop) { + count++; + if (![object_ isEqual: + [compareArray objectAtIndex: idx]]) + blockOK = false; + }]; + + if (count != compareArray.count) + blockOK = false; + + TEST(@"Enumeration using blocks", blockOK) + + blockOK = false; + mutableArray3 = mutableArray1; + @try { + [mutableArray3 enumerateObjectsUsingBlock: + ^ (id object_, size_t idx, bool *stop) { + [mutableArray3 removeObjectAtIndex: idx]; + }]; + } @catch (OFEnumerationMutationException *e) { + blockOK = true; } @catch (OFOutOfRangeException *e) { /* * Out of bounds access due to enumeration not being * detected. */ } TEST(@"Detection of mutation during enumeration using blocks", - blockOk) + blockOK) } TEST(@"-[replaceObjectsUsingBlock:]", - R([m[0] replaceObjectsUsingBlock: ^ id (id object, size_t idx) { - switch (idx) { - case 0: - return @"foo"; - case 1: - return @"bar"; - } - - return nil; - }]) && [m[0].description isEqual: @"(\n\tfoo,\n\tbar\n)"]) + R([mutableArray1 replaceObjectsUsingBlock: + ^ id (id object_, size_t idx) { + switch (idx) { + case 0: + return @"foo"; + case 1: + return @"bar"; + } + + return nil; + }]) && [mutableArray1.description isEqual: @"(\n\tfoo,\n\tbar\n)"]) TEST(@"-[mappedArrayUsingBlock:]", - [[m[0] mappedArrayUsingBlock: ^ id (id object, size_t idx) { - switch (idx) { - case 0: - return @"foobar"; - case 1: - return @"qux"; - } - - return nil; + [[mutableArray1 mappedArrayUsingBlock: + ^ id (id object_, size_t idx) { + switch (idx) { + case 0: + return @"foobar"; + case 1: + return @"qux"; + } + + return nil; }].description isEqual: @"(\n\tfoobar,\n\tqux\n)"]) TEST(@"-[filteredArrayUsingBlock:]", - [[m[0] filteredArrayUsingBlock: ^ bool (id object, size_t idx) { - return [object isEqual: @"foo"]; + [[mutableArray1 filteredArrayUsingBlock: + ^ bool (id object_, size_t idx) { + return [object_ isEqual: @"foo"]; }].description isEqual: @"(\n\tfoo\n)"]) TEST(@"-[foldUsingBlock:]", [[arrayClass arrayWithObjects: [OFMutableString string], @"foo", @"bar", @"baz", nil] foldUsingBlock: ^ id (id left, id right) { - [left appendString: right]; - return left; + [left appendString: right]; + return left; }]) #endif TEST(@"-[valueForKey:]", [[[arrayClass arrayWithObjects: @"foo", @"bar", @"quxqux", nil] @@ -425,18 +428,18 @@ [arrayClass arrayWithObjects: [OFNumber numberWithInt: 3], [OFNumber numberWithInt: 3], [OFNumber numberWithInt: 6], nil]] && [[[arrayClass arrayWithObjects: @"1", @"2", nil] valueForKey: @"@count"] isEqual: [OFNumber numberWithInt: 2]]) - m[0] = [mutableArrayClass arrayWithObjects: + mutableArray1 = [mutableArrayClass arrayWithObjects: [OFMutableURL URLWithString: @"http://foo.bar/"], [OFMutableURL URLWithString: @"http://bar.qux/"], [OFMutableURL URLWithString: @"http://qux.quxqux/"], nil]; TEST(@"-[setValue:forKey:]", - R([m[0] setValue: [OFNumber numberWithShort: 1234] - forKey: @"port"]) && - [m[0] isEqual: [arrayClass arrayWithObjects: + R([mutableArray1 setValue: [OFNumber numberWithShort: 1234] + forKey: @"port"]) && + [mutableArray1 isEqual: [arrayClass arrayWithObjects: [OFURL URLWithString: @"http://foo.bar:1234/"], [OFURL URLWithString: @"http://bar.qux:1234/"], [OFURL URLWithString: @"http://qux.quxqux:1234/"], nil]]) objc_autoreleasePoolPop(pool); Index: tests/OFBlockTests.m ================================================================== --- tests/OFBlockTests.m +++ tests/OFBlockTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -17,11 +15,11 @@ #include "config.h" #import "TestsAppDelegate.h" -static OFString *module = @"OFBlock"; +static OFString *const module = @"OFBlock"; #if defined(OF_OBJFW_RUNTIME) extern struct objc_class _NSConcreteStackBlock; extern struct objc_class _NSConcreteGlobalBlock; extern struct objc_class _NSConcreteMallocBlock; @@ -29,11 +27,11 @@ extern void *_NSConcreteStackBlock; extern void *_NSConcreteGlobalBlock; extern void *_NSConcreteMallocBlock; #endif -static void (^g)(void) = ^ {}; +static void (^globalBlock)(void) = ^ {}; static int (^returnStackBlock(void))(void) { __block int i = 42; @@ -43,70 +41,76 @@ static double forwardTest(void) { __block double d; - void (^b)(void) = Block_copy(^ { + void (^block)(void) = Block_copy(^ { d = 5; }); - b(); - Block_release(b); + block(); + Block_release(block); return d; } @implementation TestsAppDelegate (OFBlockTests) - (void)blockTests { void *pool = objc_autoreleasePoolPush(); __block int x; - void (^s)(void) = ^ { x = 0; }; - void (^m)(void); - int (^v)(void); + void (^stackBlock)(void) = ^ { + x = 0; + (void)x; + }; + void (^mallocBlock)(void); + int (^voidBlock)(void); TEST(@"Class of stack block", (Class)&_NSConcreteStackBlock == objc_getClass("OFStackBlock") && - [s isKindOfClass: [OFBlock class]]) + [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. */ TEST(@"Class of global block", (Class)&_NSConcreteGlobalBlock == objc_getClass("OFGlobalBlock") && - [g isKindOfClass: [OFBlock class]]) + [globalBlock isKindOfClass: [OFBlock class]]) #endif TEST(@"Class of a malloc block", (Class)&_NSConcreteMallocBlock == objc_getClass("OFMallocBlock")) TEST(@"Copying a stack block", - (m = [[s copy] autorelease]) && - [m class] == objc_getClass("OFMallocBlock") && - [m isKindOfClass: [OFBlock class]]) + (mallocBlock = [[stackBlock copy] autorelease]) && + [mallocBlock class] == objc_getClass("OFMallocBlock") && + [mallocBlock isKindOfClass: [OFBlock class]]) TEST(@"Copying a stack block and referencing its variable", forwardTest() == 5) TEST(@"Copying a stack block and using its copied variable", - (v = returnStackBlock()) && v() == 43 && v() == 44 && v() == 45) + (voidBlock = returnStackBlock()) && voidBlock() == 43 && + voidBlock() == 44 && voidBlock() == 45) - TEST(@"Copying a global block", (id)g == [[g copy] autorelease]) + TEST(@"Copying a global block", + (id)globalBlock == [[globalBlock copy] autorelease]) #ifndef __clang_analyzer__ TEST(@"Copying a malloc block", - (id)m == [m copy] && [m retainCount] == 2) + (id)mallocBlock == [mallocBlock copy] && + [mallocBlock retainCount] == 2) #endif - TEST(@"Autorelease a stack block", R([s autorelease])) + TEST(@"Autorelease a stack block", R([stackBlock autorelease])) - TEST(@"Autorelease a global block", R([g autorelease])) + TEST(@"Autorelease a global block", R([globalBlock autorelease])) #ifndef __clang_analyzer__ - TEST(@"Autorelease a malloc block", R([m autorelease])) + TEST(@"Autorelease a malloc block", R([mallocBlock autorelease])) #endif objc_autoreleasePoolPop(pool); } @end Index: tests/OFCharacterSetTests.m ================================================================== --- tests/OFCharacterSetTests.m +++ tests/OFCharacterSetTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -21,88 +19,89 @@ #import "OFCharacterSet.h" #import "OFBitSetCharacterSet.h" #import "OFRangeCharacterSet.h" -static OFString *module = nil; +static OFString *module; @interface SimpleCharacterSet: OFCharacterSet @end @implementation SimpleCharacterSet -- (bool)characterIsMember: (of_unichar_t)character +- (bool)characterIsMember: (OFUnichar)character { return (character % 2 == 0); } @end @implementation TestsAppDelegate (OFCharacterSetTests) - (void)characterSetTests { void *pool = objc_autoreleasePoolPush(); - OFCharacterSet *cs, *ics; + OFCharacterSet *characterSet, *invertedCharacterSet; bool ok; module = @"OFCharacterSet"; - cs = [[[SimpleCharacterSet alloc] init] autorelease]; + characterSet = [[[SimpleCharacterSet alloc] init] autorelease]; ok = true; - for (of_unichar_t c = 0; c < 65536; c++) { + for (OFUnichar c = 0; c < 65536; c++) { if (c % 2 == 0) { - if (![cs characterIsMember: c]) + if (![characterSet characterIsMember: c]) ok = false; - } else if ([cs characterIsMember: c]) + } else if ([characterSet characterIsMember: c]) ok = false; } TEST(@"-[characterIsMember:]", ok); module = @"OFBitSetCharacterSet"; TEST(@"+[characterSetWithCharactersInString:]", - (cs = [OFCharacterSet characterSetWithCharactersInString: + (characterSet = [OFCharacterSet characterSetWithCharactersInString: @"0123456789"]) && - [cs isKindOfClass: [OFBitSetCharacterSet class]]) + [characterSet isKindOfClass: [OFBitSetCharacterSet class]]) ok = true; - for (of_unichar_t c = 0; c < 65536; c++) { + for (OFUnichar c = 0; c < 65536; c++) { if (c >= '0' && c <= '9') { - if (![cs characterIsMember: c]) + if (![characterSet characterIsMember: c]) ok = false; - } else if ([cs characterIsMember: c]) + } else if ([characterSet characterIsMember: c]) ok = false; } TEST(@"-[characterIsMember:]", ok); module = @"OFRangeCharacterSet"; TEST(@"+[characterSetWithRange:]", - (cs = [OFCharacterSet characterSetWithRange: of_range('0', 10)]) && - [cs isKindOfClass: [OFRangeCharacterSet class]]) + (characterSet = [OFCharacterSet + characterSetWithRange: OFRangeMake('0', 10)]) && + [characterSet isKindOfClass: [OFRangeCharacterSet class]]) ok = true; - for (of_unichar_t c = 0; c < 65536; c++) { + for (OFUnichar c = 0; c < 65536; c++) { if (c >= '0' && c <= '9') { - if (![cs characterIsMember: c]) + if (![characterSet characterIsMember: c]) ok = false; - } else if ([cs characterIsMember: c]) + } else if ([characterSet characterIsMember: c]) ok = false; } TEST(@"-[characterIsMember:]", ok); ok = true; - ics = cs.invertedSet; - for (of_unichar_t c = 0; c < 65536; c++) { + invertedCharacterSet = characterSet.invertedSet; + for (OFUnichar c = 0; c < 65536; c++) { if (c >= '0' && c <= '9') { - if ([ics characterIsMember: c]) + if ([invertedCharacterSet characterIsMember: c]) ok = false; - } else if (![ics characterIsMember: c]) + } else if (![invertedCharacterSet characterIsMember: c]) ok = false; } TEST(@"-[invertedSet]", ok); TEST(@"Inverting -[invertedSet] returns original set", - ics.invertedSet == cs) + invertedCharacterSet.invertedSet == characterSet) objc_autoreleasePoolPop(pool); } @end Index: tests/OFDNSResolverTests.m ================================================================== --- tests/OFDNSResolverTests.m +++ tests/OFDNSResolverTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -24,11 +22,11 @@ { void *pool = objc_autoreleasePoolPush(); OFDNSResolver *resolver = [OFDNSResolver resolver]; OFMutableString *staticHosts = [OFMutableString string]; - [of_stdout setForegroundColor: [OFColor lime]]; + [OFStdOut setForegroundColor: [OFColor lime]]; for (OFString *host in resolver.staticHosts) { OFString *IPs; if (staticHosts.length > 0) @@ -37,37 +35,37 @@ IPs = [[resolver.staticHosts objectForKey: host] componentsJoinedByString: @", "]; [staticHosts appendFormat: @"%@=(%@)", host, IPs]; } - [of_stdout writeFormat: @"[OFDNSResolver] Static hosts: %@\n", + [OFStdOut writeFormat: @"[OFDNSResolver] Static hosts: %@\n", staticHosts]; - [of_stdout writeFormat: @"[OFDNSResolver] Name servers: %@\n", + [OFStdOut writeFormat: @"[OFDNSResolver] Name servers: %@\n", [resolver.nameServers componentsJoinedByString: @", "]]; - [of_stdout writeFormat: @"[OFDNSResolver] Local domain: %@\n", + [OFStdOut writeFormat: @"[OFDNSResolver] Local domain: %@\n", resolver.localDomain]; - [of_stdout writeFormat: @"[OFDNSResolver] Search domains: %@\n", + [OFStdOut writeFormat: @"[OFDNSResolver] Search domains: %@\n", [resolver.searchDomains componentsJoinedByString: @", "]]; - [of_stdout writeFormat: @"[OFDNSResolver] Timeout: %lf\n", + [OFStdOut writeFormat: @"[OFDNSResolver] Timeout: %lf\n", resolver.timeout]; - [of_stdout writeFormat: @"[OFDNSResolver] Max attempts: %u\n", + [OFStdOut writeFormat: @"[OFDNSResolver] Max attempts: %u\n", resolver.maxAttempts]; - [of_stdout writeFormat: + [OFStdOut writeFormat: @"[OFDNSResolver] Min number of dots in absolute name: %u\n", resolver.minNumberOfDotsInAbsoluteName]; - [of_stdout writeFormat: @"[OFDNSResolver] Uses TCP: %u\n", + [OFStdOut writeFormat: @"[OFDNSResolver] Uses TCP: %u\n", resolver.usesTCP]; - [of_stdout writeFormat: + [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,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -19,195 +17,212 @@ #include #import "TestsAppDelegate.h" -static OFString *module = @"OFData"; -const char *str = "Hello!"; +static OFString *const module = @"OFData"; @implementation TestsAppDelegate (OFDataTests) - (void)dataTests { void *pool = objc_autoreleasePoolPush(); - OFMutableData *mutable; - OFData *immutable; + OFMutableData *mutableData; + OFData *data; void *raw[2]; - of_range_t range; + OFRange range; TEST(@"+[dataWithItemSize:]", - (mutable = [OFMutableData dataWithItemSize: 4096])) + (mutableData = [OFMutableData dataWithItemSize: 4096])) - OFObject *tmp = [[[OFObject alloc] init] autorelease]; - raw[0] = [tmp allocMemoryWithSize: 4096]; - raw[1] = [tmp allocMemoryWithSize: 4096]; + raw[0] = OFAllocMemory(1, 4096); + raw[1] = OFAllocMemory(1, 4096); memset(raw[0], 0xFF, 4096); memset(raw[1], 0x42, 4096); - TEST(@"-[addItem:]", R([mutable addItem: raw[0]]) && - R([mutable addItem: raw[1]])) + TEST(@"-[addItem:]", R([mutableData addItem: raw[0]]) && + R([mutableData addItem: raw[1]])) TEST(@"-[itemAtIndex:]", - memcmp([mutable itemAtIndex: 0], raw[0], 4096) == 0 && - memcmp([mutable itemAtIndex: 1], raw[1], 4096) == 0) + memcmp([mutableData itemAtIndex: 0], raw[0], 4096) == 0 && + memcmp([mutableData itemAtIndex: 1], raw[1], 4096) == 0) - TEST(@"-[lastItem]", memcmp(mutable.lastItem, raw[1], 4096) == 0) + TEST(@"-[lastItem]", memcmp(mutableData.lastItem, raw[1], 4096) == 0) - TEST(@"-[count]", mutable.count == 2) + TEST(@"-[count]", mutableData.count == 2) TEST(@"-[isEqual:]", - (immutable = [OFData dataWithItems: mutable.items - itemSize: mutable.itemSize - count: mutable.count]) && - [immutable isEqual: mutable] && - R([mutable removeLastItem]) && ![mutable isEqual: immutable]) + (data = [OFData dataWithItems: mutableData.items + count: mutableData.count + itemSize: mutableData.itemSize]) && + [data isEqual: mutableData] && + R([mutableData removeLastItem]) && ![mutableData isEqual: data]) TEST(@"-[mutableCopy]", - (mutable = [[immutable mutableCopy] autorelease]) && - [mutable isEqual: immutable]) - - TEST(@"-[compare]", [mutable compare: immutable] == 0 && - R([mutable removeLastItem]) && - [immutable compare: mutable] == OF_ORDERED_DESCENDING && - [mutable compare: immutable] == OF_ORDERED_ASCENDING && - [[OFData dataWithItems: "aa" - count: 2] compare: - [OFData dataWithItems: "z" - count: 1]] == OF_ORDERED_ASCENDING) - - TEST(@"-[hash]", immutable.hash == 0x634A529F) - - mutable = [OFMutableData dataWithItems: "abcdef" - count: 6]; - - TEST(@"-[removeLastItem]", R([mutable removeLastItem]) && - mutable.count == 5 && memcmp(mutable.items, "abcde", 5) == 0) + (mutableData = [[data mutableCopy] autorelease]) && + [mutableData isEqual: data]) + + TEST(@"-[compare]", [mutableData compare: data] == 0 && + R([mutableData removeLastItem]) && + [data compare: mutableData] == OFOrderedDescending && + [mutableData compare: data] == OFOrderedAscending && + [[OFData dataWithItems: "aa" count: 2] compare: + [OFData dataWithItems: "z" count: 1]] == OFOrderedAscending) + + TEST(@"-[hash]", data.hash == 0x634A529F) + + mutableData = [OFMutableData dataWithItems: "abcdef" count: 6]; + + TEST(@"-[removeLastItem]", + R([mutableData removeLastItem]) && mutableData.count == 5 && + memcmp(mutableData.items, "abcde", 5) == 0) TEST(@"-[removeItemsInRange:]", - R([mutable removeItemsInRange: of_range(1, 2)]) && - mutable.count == 3 && memcmp(mutable.items, "ade", 3) == 0) + R([mutableData removeItemsInRange: OFRangeMake(1, 2)]) && + mutableData.count == 3 && memcmp(mutableData.items, "ade", 3) == 0) TEST(@"-[insertItems:atIndex:count:]", - R([mutable insertItems: "bc" - atIndex: 1 - count: 2]) && mutable.count == 5 && - memcmp(mutable.items, "abcde", 5) == 0) - - immutable = [OFData dataWithItems: "aaabaccdacaabb" - itemSize: 2 - count: 7]; - TEST(@"-[rangeOfString:options:range:]", - R(range = [immutable rangeOfData: [OFData dataWithItems: "aa" - itemSize: 2 - count: 1] - options: 0 - range: of_range(0, 7)]) && - range.location == 0 && range.length == 1 && - R(range = [immutable rangeOfData: [OFData dataWithItems: "aa" - itemSize: 2 - count: 1] - options: OF_DATA_SEARCH_BACKWARDS - range: of_range(0, 7)]) && - range.location == 5 && range.length == 1 && - R(range = [immutable rangeOfData: [OFData dataWithItems: "ac" - itemSize: 2 - count: 1] - options: 0 - range: of_range(0, 7)]) && - range.location == 2 && range.length == 1 && - R(range = [immutable rangeOfData: [OFData dataWithItems: "aabb" - itemSize: 2 - count: 2] - options: 0 - range: of_range(0, 7)]) && - range.location == 5 && range.length == 2 && - R(range = [immutable rangeOfData: [OFData dataWithItems: "aa" - itemSize: 2 - count: 1] - options: 0 - range: of_range(1, 6)]) && - range.location == 5 && range.length == 1 && - R(range = [immutable rangeOfData: [OFData dataWithItems: "aa" - itemSize: 2 - count: 1] - options: OF_DATA_SEARCH_BACKWARDS - range: of_range(0, 5)]) && + R([mutableData insertItems: "bc" atIndex: 1 count: 2]) && + mutableData.count == 5 && + memcmp(mutableData.items, "abcde", 5) == 0) + + data = [OFData dataWithItems: "aaabaccdacaabb" count: 7 itemSize: 2]; + + range = [data rangeOfData: [OFData dataWithItems: "aa" + count: 1 + itemSize: 2] + options: 0 + range: OFRangeMake(0, 7)]; + TEST(@"-[rangeOfData:options:range:] #1", + range.location == 0 && range.length == 1) + + range = [data rangeOfData: [OFData dataWithItems: "aa" + count: 1 + itemSize: 2] + options: OFDataSearchBackwards + range: OFRangeMake(0, 7)]; + TEST(@"-[rangeOfData:options:range:] #2", + range.location == 5 && range.length == 1) + + range = [data rangeOfData: [OFData dataWithItems: "ac" + count: 1 + itemSize: 2] + options: 0 + range: OFRangeMake(0, 7)]; + TEST(@"-[rangeOfData:options:range:] #3", + range.location == 2 && range.length == 1) + + range = [data rangeOfData: [OFData dataWithItems: "aabb" + count: 2 + itemSize: 2] + options: 0 + range: OFRangeMake(0, 7)]; + TEST(@"-[rangeOfData:options:range:] #4", + range.location == 5 && range.length == 2) + + TEST(@"-[rangeOfData:options:range:] #5", + R(range = [data rangeOfData: [OFData dataWithItems: "aa" + count: 1 + itemSize: 2] + options: 0 + range: OFRangeMake(1, 6)]) && + range.location == 5 && range.length == 1) + + range = [data rangeOfData: [OFData dataWithItems: "aa" + count: 1 + itemSize: 2] + options: OFDataSearchBackwards + range: OFRangeMake(0, 5)]; + TEST(@"-[rangeOfData:options:range:] #6", range.location == 0 && range.length == 1) EXPECT_EXCEPTION( - @"-[rangeOfString:options:range:] failing on different itemSize", + @"-[rangeOfData:options:range:] failing on different itemSize", OFInvalidArgumentException, - [immutable rangeOfData: [OFData dataWithItems: "aaa" - itemSize: 3 - count: 1] - options: 0 - range: of_range(0, 1)]) + [data rangeOfData: [OFData dataWithItems: "aaa" + count: 1 + itemSize: 3] + options: 0 + range: OFRangeMake(0, 1)]) EXPECT_EXCEPTION( @"-[rangeOfData:options:range:] failing on out of range", OFOutOfRangeException, - [immutable rangeOfData: [OFData dataWithItems: "" - itemSize: 2 - count: 0] - options: 0 - range: of_range(8, 1)]) + [data rangeOfData: [OFData dataWithItems: "" count: 0 itemSize: 2] + options: 0 + range: OFRangeMake(8, 1)]) TEST(@"-[subdataWithRange:]", - [[immutable subdataWithRange: of_range(2, 4)] - isEqual: [OFData dataWithItems: "accdacaa" - itemSize: 2 - count: 4]] && - [[mutable subdataWithRange: of_range(2, 3)] - isEqual: [OFData dataWithItems: "cde" - count: 3]]) + [[data subdataWithRange: OFRangeMake(2, 4)] + isEqual: [OFData dataWithItems: "accdacaa" count: 4 itemSize: 2]] && + [[mutableData subdataWithRange: OFRangeMake(2, 3)] + isEqual: [OFData dataWithItems: "cde" count: 3]]) EXPECT_EXCEPTION(@"-[subdataWithRange:] failing on out of range #1", - OFOutOfRangeException, [immutable subdataWithRange: of_range(7, 1)]) + OFOutOfRangeException, + [data subdataWithRange: OFRangeMake(7, 1)]) EXPECT_EXCEPTION(@"-[subdataWithRange:] failing on out of range #2", - OFOutOfRangeException, [mutable subdataWithRange: of_range(6, 1)]) - - TEST(@"-[MD5Hash]", [mutable.MD5Hash isEqual: @"abcde".MD5Hash]) - - TEST(@"-[RIPEMD160Hash]", [mutable.RIPEMD160Hash - isEqual: @"abcde".RIPEMD160Hash]) - - TEST(@"-[SHA1Hash]", [mutable.SHA1Hash isEqual: @"abcde".SHA1Hash]) - - TEST(@"-[SHA224Hash]", [mutable.SHA224Hash - isEqual: @"abcde".SHA224Hash]) - - TEST(@"-[SHA256Hash]", [mutable.SHA256Hash - isEqual: @"abcde".SHA256Hash]) - - TEST(@"-[SHA384Hash]", [mutable.SHA384Hash - isEqual: @"abcde".SHA384Hash]) - - TEST(@"-[SHA512Hash]", [mutable.SHA512Hash - isEqual: @"abcde".SHA512Hash]) + OFOutOfRangeException, + [mutableData subdataWithRange: OFRangeMake(6, 1)]) + + TEST(@"-[stringByMD5Hashing]", + [mutableData.stringByMD5Hashing + isEqual: @"ab56b4d92b40713acc5af89985d4b786"]) + + TEST(@"-[stringByRIPEMD160Hashing]", + [mutableData.stringByRIPEMD160Hashing + isEqual: @"973398b6e6c6cfa6b5e6a5173f195ce3274bf828"]) + + TEST(@"-[stringBySHA1Hashing]", + [mutableData.stringBySHA1Hashing + isEqual: @"03de6c570bfe24bfc328ccd7ca46b76eadaf4334"]) + + TEST(@"-[stringBySHA224Hashing]", + [mutableData.stringBySHA224Hashing + isEqual: @"bdd03d560993e675516ba5a50638b6531ac2ac3d5847c61916cfced6" + ]) + + TEST(@"-[stringBySHA256Hashing]", + [mutableData.stringBySHA256Hashing + isEqual: @"36bbe50ed96841d10443bcb670d6554f0a34b761be67ec9c4a8ad2c0" + @"c44ca42c"]) + + TEST(@"-[stringBySHA384Hashing]", + [mutableData.stringBySHA384Hashing + isEqual: @"4c525cbeac729eaf4b4665815bc5db0c84fe6300068a727cf74e2813" + @"521565abc0ec57a37ee4d8be89d097c0d2ad52f0"]) + + TEST(@"-[stringBySHA512Hashing]", + [mutableData.stringBySHA512Hashing + isEqual: @"878ae65a92e86cac011a570d4c30a7eaec442b85ce8eca0c2952b5e3" + @"cc0628c2e79d889ad4d5c7c626986d452dd86374b6ffaa7cd8b67665" + @"bef2289a5c70b0a1"]) TEST(@"-[stringByBase64Encoding]", - [mutable.stringByBase64Encoding isEqual: @"YWJjZGU="]) + [mutableData.stringByBase64Encoding isEqual: @"YWJjZGU="]) TEST(@"+[dataWithBase64EncodedString:]", - memcmp([[OFData dataWithBase64EncodedString: @"YWJjZGU="] - items], "abcde", 5) == 0) + memcmp([[OFData dataWithBase64EncodedString: @"YWJjZGU="] items], + "abcde", 5) == 0) TEST(@"Building strings", - (mutable = [OFMutableData dataWithItems: str - count: 6]) && - R([mutable addItem: ""]) && - strcmp(mutable.items, str) == 0) + (mutableData = [OFMutableData dataWithItems: "Hello!" count: 6]) && + R([mutableData addItem: ""]) && + strcmp(mutableData.items, "Hello!") == 0) EXPECT_EXCEPTION(@"Detect out of range in -[itemAtIndex:]", - OFOutOfRangeException, [mutable itemAtIndex: mutable.count]) + OFOutOfRangeException, [mutableData itemAtIndex: mutableData.count]) EXPECT_EXCEPTION(@"Detect out of range in -[addItems:count:]", - OFOutOfRangeException, [mutable addItems: raw[0] - count: SIZE_MAX]) + OFOutOfRangeException, + [mutableData addItems: raw[0] count: SIZE_MAX]) EXPECT_EXCEPTION(@"Detect out of range in -[removeItemsInRange:]", OFOutOfRangeException, - [mutable removeItemsInRange: of_range(mutable.count, 1)]) + [mutableData removeItemsInRange: OFRangeMake(mutableData.count, 1)]) + + OFFreeMemory(raw[0]); + OFFreeMemory(raw[1]); objc_autoreleasePoolPop(pool); } @end Index: tests/OFDateTests.m ================================================================== --- tests/OFDateTests.m +++ tests/OFDateTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -18,36 +16,37 @@ #include "config.h" #include #import "TestsAppDelegate.h" +#import "OFStrPTime.h" -static OFString *module = @"OFDate"; +static OFString *const module = @"OFDate"; @implementation TestsAppDelegate (OFDateTests) - (void)dateTests { void *pool = objc_autoreleasePoolPush(); - OFDate *d1, *d2; + OFDate *date1, *date2; struct tm tm; int16_t tz; const char *dstr = "Wed, 09 Jun 2021 +0200x"; - TEST(@"of_strptime()", - of_strptime(dstr, "%a, %d %b %Y %z", &tm, &tz) == dstr + 22 && + TEST(@"OFStrPTime()", + OFStrPTime(dstr, "%a, %d %b %Y %z", &tm, &tz) == dstr + 22 && tm.tm_wday == 3 && tm.tm_mday == 9 && tm.tm_mon == 5 && tm.tm_year == 2021 - 1900 && tz == 2 * 60) TEST(@"+[dateWithTimeIntervalSince1970:]", - (d1 = [OFDate dateWithTimeIntervalSince1970: 0])) + (date1 = [OFDate dateWithTimeIntervalSince1970: 0])) TEST(@"-[dateByAddingTimeInterval:]", - (d2 = [d1 dateByAddingTimeInterval: 3600 * 25 + 5.000002])) + (date2 = [date1 dateByAddingTimeInterval: 3600 * 25 + 5.000002])) TEST(@"-[description]", - [d1.description isEqual: @"1970-01-01T00:00:00Z"] && - [d2.description isEqual: @"1970-01-02T01:00:05Z"]) + [date1.description isEqual: @"1970-01-01T00:00:00Z"] && + [date2.description isEqual: @"1970-01-02T01:00:05Z"]) TEST(@"+[dateWithDateString:format:]", [[[OFDate dateWithDateString: @"2000-06-20T12:34:56+0200" format: @"%Y-%m-%dT%H:%M:%S%z"] description] isEqual: @"2000-06-20T10:34:56Z"]); @@ -77,35 +76,37 @@ @"+[dateWithLocalDateString:format:] #2", OFInvalidFormatException, [OFDate dateWithLocalDateString: @"2000-06-20T12:34:56+0200x" format: @"%Y-%m-%dT%H:%M:%S%z"]) TEST(@"-[isEqual:]", - [d1 isEqual: [OFDate dateWithTimeIntervalSince1970: 0]] && - ![d1 isEqual: [OFDate dateWithTimeIntervalSince1970: 0.0000001]]) - - TEST(@"-[compare:]", [d1 compare: d2] == OF_ORDERED_ASCENDING) - - TEST(@"-[second]", d1.second == 0 && d2.second == 5) - - TEST(@"-[microsecond]", d1.microsecond == 0 && d2.microsecond == 2) - - TEST(@"-[minute]", d1.minute == 0 && d2.minute == 0) - - TEST(@"-[hour]", d1.hour == 0 && d2.hour == 1) - - TEST(@"-[dayOfMonth]", d1.dayOfMonth == 1 && d2.dayOfMonth == 2) - - TEST(@"-[monthOfYear]", d1.monthOfYear == 1 && d2.monthOfYear == 1) - - TEST(@"-[year]", d1.year == 1970 && d2.year == 1970) - - TEST(@"-[dayOfWeek]", d1.dayOfWeek == 4 && d2.dayOfWeek == 5) - - TEST(@"-[dayOfYear]", d1.dayOfYear == 1 && d2.dayOfYear == 2) - - TEST(@"-[earlierDate:]", [[d1 earlierDate: d2] isEqual: d1]) - - TEST(@"-[laterDate:]", [[d1 laterDate: d2] isEqual: d2]) + [date1 isEqual: [OFDate dateWithTimeIntervalSince1970: 0]] && + ![date1 isEqual: [OFDate dateWithTimeIntervalSince1970: 0.0000001]]) + + TEST(@"-[compare:]", [date1 compare: date2] == OFOrderedAscending) + + TEST(@"-[second]", date1.second == 0 && date2.second == 5) + + TEST(@"-[microsecond]", + date1.microsecond == 0 && date2.microsecond == 2) + + TEST(@"-[minute]", date1.minute == 0 && date2.minute == 0) + + TEST(@"-[hour]", date1.hour == 0 && date2.hour == 1) + + TEST(@"-[dayOfMonth]", date1.dayOfMonth == 1 && date2.dayOfMonth == 2) + + TEST(@"-[monthOfYear]", + date1.monthOfYear == 1 && date2.monthOfYear == 1) + + TEST(@"-[year]", date1.year == 1970 && date2.year == 1970) + + TEST(@"-[dayOfWeek]", date1.dayOfWeek == 4 && date2.dayOfWeek == 5) + + TEST(@"-[dayOfYear]", date1.dayOfYear == 1 && date2.dayOfYear == 2) + + TEST(@"-[earlierDate:]", [[date1 earlierDate: date2] isEqual: date1]) + + TEST(@"-[laterDate:]", [[date1 laterDate: date2] isEqual: date2]) objc_autoreleasePoolPop(pool); } @end Index: tests/OFDictionaryTests.m ================================================================== --- tests/OFDictionaryTests.m +++ tests/OFDictionaryTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -17,11 +15,11 @@ #include "config.h" #import "TestsAppDelegate.h" -static OFString *module = nil; +static OFString *module; static OFString *keys[] = { @"key1", @"key2" }; static OFString *values[] = { @@ -55,12 +53,11 @@ } return self; } -- (instancetype)initWithKey: (id)key - arguments: (va_list)arguments +- (instancetype)initWithKey: (id)key arguments: (va_list)arguments { self = [super init]; @try { _dictionary = [[OFMutableDictionary alloc] @@ -105,11 +102,11 @@ return [_dictionary objectForKey: key]; } - (size_t)count { - return [_dictionary count]; + return _dictionary.count; } - (OFEnumerator *)keyEnumerator { return [_dictionary keyEnumerator]; @@ -121,17 +118,15 @@ { if (self == [SimpleMutableDictionary class]) [self inheritMethodsFromClass: [SimpleDictionary class]]; } -- (void)setObject: (id)object - forKey: (id)key +- (void)setObject: (id)object forKey: (id)key { bool existed = ([_dictionary objectForKey: key] == nil); - [_dictionary setObject: object - forKey: key]; + [_dictionary setObject: object forKey: key]; if (existed) _mutations++; } @@ -143,11 +138,11 @@ if (existed) _mutations++; } -- (int)countByEnumeratingWithState: (of_fast_enumeration_state_t *)state +- (int)countByEnumeratingWithState: (OFFastEnumerationState *)state objects: (id *)objects count: (int)count { int ret = [super countByEnumeratingWithState: state objects: objects @@ -162,107 +157,101 @@ @implementation TestsAppDelegate (OFDictionaryTests) - (void)dictionaryTestsWithClass: (Class)dictionaryClass mutableClass: (Class)mutableDictionaryClass { void *pool = objc_autoreleasePoolPush(); - OFMutableDictionary *mutDict = [mutableDictionaryClass dictionary]; + OFMutableDictionary *mutableDict = [mutableDictionaryClass dictionary]; OFDictionary *dict; OFEnumerator *keyEnumerator, *objectEnumerator; OFArray *keysArray, *valuesArray; - [mutDict setObject: values[0] - forKey: keys[0]]; - [mutDict setValue: values[1] - forKey: keys[1]]; + [mutableDict setObject: values[0] forKey: keys[0]]; + [mutableDict setValue: values[1] forKey: keys[1]]; TEST(@"-[objectForKey:]", - [[mutDict objectForKey: keys[0]] isEqual: values[0]] && - [[mutDict objectForKey: keys[1]] isEqual: values[1]] && - [mutDict objectForKey: @"key3"] == nil) + [[mutableDict objectForKey: keys[0]] isEqual: values[0]] && + [[mutableDict objectForKey: keys[1]] isEqual: values[1]] && + [mutableDict objectForKey: @"key3"] == nil) TEST(@"-[valueForKey:]", - [[mutDict valueForKey: keys[0]] isEqual: values[0]] && - [[mutDict valueForKey: @"@count"] isEqual: + [[mutableDict valueForKey: keys[0]] isEqual: values[0]] && + [[mutableDict valueForKey: @"@count"] isEqual: [OFNumber numberWithInt: 2]]) EXPECT_EXCEPTION(@"Catching -[setValue:forKey:] on immutable " @"dictionary", OFUndefinedKeyException, - [[dictionaryClass dictionary] setValue: @"x" - forKey: @"x"]) + [[dictionaryClass dictionary] setValue: @"x" forKey: @"x"]) TEST(@"-[containsObject:]", - [mutDict containsObject: values[0]] && - ![mutDict containsObject: @"nonexistent"]) + [mutableDict containsObject: values[0]] && + ![mutableDict containsObject: @"nonexistent"]) TEST(@"-[containsObjectIdenticalTo:]", - [mutDict containsObjectIdenticalTo: values[0]] && - ![mutDict containsObjectIdenticalTo: + [mutableDict containsObjectIdenticalTo: values[0]] && + ![mutableDict containsObjectIdenticalTo: [OFString stringWithString: values[0]]]) TEST(@"-[description]", - [[mutDict description] isEqual: + [[mutableDict description] isEqual: @"{\n\tkey1 = value1;\n\tkey2 = value2;\n}"]) TEST(@"-[allKeys]", - [[mutDict allKeys] isEqual: [OFArray arrayWithObjects: keys[0], - keys[1], nil]]) + [[mutableDict allKeys] isEqual: + [OFArray arrayWithObjects: keys[0], keys[1], nil]]) TEST(@"-[allObjects]", - [[mutDict allObjects] isEqual: [OFArray arrayWithObjects: values[0], - values[1], nil]]) + [[mutableDict allObjects] isEqual: + [OFArray arrayWithObjects: values[0], values[1], nil]]) - TEST(@"-[keyEnumerator]", (keyEnumerator = [mutDict keyEnumerator])) + TEST(@"-[keyEnumerator]", (keyEnumerator = [mutableDict keyEnumerator])) TEST(@"-[objectEnumerator]", - (objectEnumerator = [mutDict objectEnumerator])) + (objectEnumerator = [mutableDict objectEnumerator])) TEST(@"OFEnumerator's -[nextObject]", [[keyEnumerator nextObject] isEqual: keys[0]] && [[objectEnumerator nextObject] isEqual: values[0]] && [[keyEnumerator nextObject] isEqual: keys[1]] && [[objectEnumerator nextObject] isEqual: values[1]] && [keyEnumerator nextObject] == nil && [objectEnumerator nextObject] == nil) - [mutDict removeObjectForKey: keys[0]]; + [mutableDict removeObjectForKey: keys[0]]; EXPECT_EXCEPTION(@"Detection of mutation during enumeration", OFEnumerationMutationException, [keyEnumerator nextObject]); - [mutDict setObject: values[0] - forKey: keys[0]]; + [mutableDict setObject: values[0] forKey: keys[0]]; size_t i = 0; bool ok = true; - for (OFString *key in mutDict) { + for (OFString *key in mutableDict) { if (i > 1 || ![key isEqual: keys[i]]) { ok = false; break; } - [mutDict setObject: [mutDict objectForKey: key] - forKey: key]; + [mutableDict setObject: [mutableDict objectForKey: key] + forKey: key]; i++; } TEST(@"Fast Enumeration", ok) ok = false; @try { - for (OFString *key in mutDict) { + for (OFString *key in mutableDict) { (void)key; - - [mutDict setObject: @"" - forKey: @""]; + [mutableDict setObject: @"" forKey: @""]; } } @catch (OFEnumerationMutationException *e) { ok = true; } TEST(@"Detection of mutation during Fast Enumeration", ok) - [mutDict removeObjectForKey: @""]; + [mutableDict removeObjectForKey: @""]; TEST(@"-[stringByURLEncoding]", [[[OFDictionary dictionaryWithKeysAndObjects: @"foo", @"bar", @"q&x", @"q=x", nil] stringByURLEncoding] isEqual: @"q%26x=q%3Dx&foo=bar"]) @@ -270,71 +259,71 @@ #ifdef OF_HAVE_BLOCKS { __block size_t j = 0; __block bool blockOk = true; - [mutDict enumerateKeysAndObjectsUsingBlock: + [mutableDict enumerateKeysAndObjectsUsingBlock: ^ (id key, id object, bool *stop) { if (j > 1 || ![key isEqual: keys[j]]) { blockOk = false; *stop = true; return; } - [mutDict setObject: [mutDict objectForKey: key] - forKey: key]; + [mutableDict setObject: [mutableDict objectForKey: key] + forKey: key]; j++; }]; TEST(@"Enumeration using blocks", blockOk) blockOk = false; @try { - [mutDict enumerateKeysAndObjectsUsingBlock: + [mutableDict enumerateKeysAndObjectsUsingBlock: ^ (id key, id object, bool *stop) { - [mutDict setObject: @"" - forKey: @""]; + [mutableDict setObject: @"" forKey: @""]; }]; } @catch (OFEnumerationMutationException *e) { blockOk = true; } TEST(@"Detection of mutation during enumeration using blocks", blockOk) - [mutDict removeObjectForKey: @""]; + [mutableDict removeObjectForKey: @""]; } TEST(@"-[replaceObjectsUsingBlock:]", - R([mutDict replaceObjectsUsingBlock: ^ id (id key, id object) { - if ([key isEqual: keys[0]]) - return @"value_1"; - if ([key isEqual: keys[1]]) - return @"value_2"; - - return nil; - }]) && [[mutDict objectForKey: keys[0]] isEqual: @"value_1"] && - [[mutDict objectForKey: keys[1]] isEqual: @"value_2"]) + R([mutableDict replaceObjectsUsingBlock: ^ id (id key, id object) { + if ([key isEqual: keys[0]]) + return @"value_1"; + if ([key isEqual: keys[1]]) + return @"value_2"; + + return nil; + }]) && [[mutableDict objectForKey: keys[0]] isEqual: @"value_1"] && + [[mutableDict objectForKey: keys[1]] isEqual: @"value_2"]) TEST(@"-[mappedDictionaryUsingBlock:]", - [[[mutDict mappedDictionaryUsingBlock: ^ id (id key, id object) { - if ([key isEqual: keys[0]]) - return @"val1"; - if ([key isEqual: keys[1]]) - return @"val2"; + [[[mutableDict mappedDictionaryUsingBlock: + ^ id (id key, id object) { + if ([key isEqual: keys[0]]) + return @"val1"; + if ([key isEqual: keys[1]]) + return @"val2"; return nil; }] description] isEqual: @"{\n\tkey1 = val1;\n\tkey2 = val2;\n}"]) TEST(@"-[filteredDictionaryUsingBlock:]", - [[[mutDict filteredDictionaryUsingBlock: - ^ bool (id key, id object) { - return [key isEqual: keys[0]]; + [[[mutableDict filteredDictionaryUsingBlock: + ^ bool (id key, id object) { + return [key isEqual: keys[0]]; }] description] isEqual: @"{\n\tkey1 = value_1;\n}"]) #endif - TEST(@"-[count]", mutDict.count == 2) + TEST(@"-[count]", mutableDict.count == 2) TEST(@"+[dictionaryWithKeysAndObjects:]", (dict = [dictionaryClass dictionaryWithKeysAndObjects: @"foo", @"bar", @"baz", @"qux", nil]) && [[dict objectForKey: @"foo"] isEqual: @"bar"] && @@ -357,34 +346,30 @@ (dict = [[dict copy] autorelease]) && [[dict objectForKey: keys[0]] isEqual: values[0]] && [[dict objectForKey: keys[1]] isEqual: values[1]]) TEST(@"-[mutableCopy]", - (mutDict = [[dict mutableCopy] autorelease]) && - mutDict.count == dict.count && - [[mutDict objectForKey: keys[0]] isEqual: values[0]] && - [[mutDict objectForKey: keys[1]] isEqual: values[1]] && - R([mutDict setObject: @"value3" - forKey: @"key3"]) && - [[mutDict objectForKey: @"key3"] isEqual: @"value3"] && - [[mutDict objectForKey: keys[0]] isEqual: values[0]] && - R([mutDict setObject: @"foo" - forKey: keys[0]]) && - [[mutDict objectForKey: keys[0]] isEqual: @"foo"]) + (mutableDict = [[dict mutableCopy] autorelease]) && + mutableDict.count == dict.count && + [[mutableDict objectForKey: keys[0]] isEqual: values[0]] && + [[mutableDict objectForKey: keys[1]] isEqual: values[1]] && + R([mutableDict setObject: @"value3" forKey: @"key3"]) && + [[mutableDict objectForKey: @"key3"] isEqual: @"value3"] && + [[mutableDict objectForKey: keys[0]] isEqual: values[0]] && + R([mutableDict setObject: @"foo" forKey: keys[0]]) && + [[mutableDict objectForKey: keys[0]] isEqual: @"foo"]) TEST(@"-[removeObjectForKey:]", - R([mutDict removeObjectForKey: keys[0]]) && - [mutDict objectForKey: keys[0]] == nil) - - [mutDict setObject: @"foo" - forKey: keys[0]]; - TEST(@"-[isEqual:]", ![mutDict isEqual: dict] && - R([mutDict removeObjectForKey: @"key3"]) && - ![mutDict isEqual: dict] && - R([mutDict setObject: values[0] - forKey: keys[0]]) && - [mutDict isEqual: dict]) + R([mutableDict removeObjectForKey: keys[0]]) && + [mutableDict objectForKey: keys[0]] == nil) + + [mutableDict setObject: @"foo" forKey: keys[0]]; + TEST(@"-[isEqual:]", ![mutableDict isEqual: dict] && + R([mutableDict removeObjectForKey: @"key3"]) && + ![mutableDict isEqual: dict] && + R([mutableDict setObject: values[0] forKey: keys[0]]) && + [mutableDict isEqual: dict]) objc_autoreleasePoolPop(pool); } - (void)dictionaryTests Index: tests/OFHMACTests.m ================================================================== --- tests/OFHMACTests.m +++ tests/OFHMACTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -19,123 +17,113 @@ #include #import "TestsAppDelegate.h" -static OFString *module = @"OFHMAC"; +static OFString *const module = @"OFHMAC"; static const uint8_t key[] = "yM9h8K6IWnJRvxC/0F8XRWG7RnACDBz8wqK2tbXrYVLoKC3vPLeJikyJSM47tVHc" "DlXHww9zULAC2sJUlm2Kg1z4oz2aXY3Y1PQSB4VkC/m0DQ7hCI6cAg4TWnKdzWTy" "cvYGX+Y6HWeDY79/PGSd8fNItme6I8w4HDBqU7BP2sum3jbePJqoiSnhcyJZQTeZ" "jw0ZXoyrfHgOYD2M+NsTDaGpLblFtQ7n5CczjKtafG40PkEwx1dcrd46U9i3GyTK"; -static const size_t key_length = sizeof(key); -static const uint8_t digest_md5[] = +static const size_t keyLength = sizeof(key); +static const uint8_t MD5Digest[] = "\xCC\x1F\xEF\x09\x29\xA3\x25\x1A\x06\xA9\x83\x99\xF9\xBC\x8F\x42"; -static const uint8_t digest_sha1[] = +static const uint8_t SHA1Digest[] = "\x94\xB9\x0A\x6F\xFB\xA7\x13\x6A\x75\x55" "\xD5\x7F\x5D\xB7\xF4\xCA\xEB\x4A\xDE\xBF"; -static const uint8_t digest_rmd160[] = +static const uint8_t RIPEMD160Digest[] = "\x2C\xE1\xED\x41\xC6\xF3\x51\xA8\x04\xD2" "\xC3\x9B\x08\x33\x3B\xD5\xC9\x00\x39\x50"; -static const uint8_t digest_sha256[] = +static const uint8_t SHA256Digest[] = "\xFB\x8C\xDA\x88\xB3\x81\x32\x16\xD7\xD8\x62\xD4\xA6\x26\x9D\x77" "\x01\x99\x62\x65\x29\x02\x41\xE6\xEF\xA1\x02\x31\xA8\x9D\x77\x5D"; -static const uint8_t digest_sha384[] = +static const uint8_t SHA384Digest[] = "\x2F\x4A\x47\xAE\x13\x8E\x96\x52\xF1\x8F\x05\xFD\x65\xCD\x9A\x97" "\x93\x2F\xC9\x02\xD6\xC6\xAB\x2E\x15\x76\xC0\xA7\xA0\x05\xF4\xEF" "\x14\x52\x33\x4B\x9C\x5F\xD8\x07\x4E\x98\xAE\x97\x46\x29\x24\xB4"; -static const uint8_t digest_sha512[] = +static const uint8_t SHA512Digest[] = "\xF5\x8C\x3F\x9C\xA2\x2F\x0A\xF3\x26\xD8\xC0\x7E\x20\x63\x88\x61" "\xC9\xE1\x1F\xD7\xC7\xE5\x59\x33\xD5\x2F\xAF\x56\x1C\x94\xC8\xA4" "\x61\xB3\xF9\x1A\xE3\x09\x43\xA6\x5B\x85\xB1\x50\x5B\xCB\x1A\x2E" "\xB7\xE8\x87\xC1\x73\x19\x63\xF6\xA2\x91\x8D\x7E\x2E\xCC\xEC\x99"; @implementation TestsAppDelegate (OFHMACTests) - (void)HMACTests { void *pool = objc_autoreleasePoolPush(); - OFFile *f = [OFFile fileWithPath: @"testfile.bin" - mode: @"r"]; - OFHMAC *HMAC_MD5, *HMAC_SHA1, *HMAC_RMD160; - OFHMAC *HMAC_SHA256, *HMAC_SHA384, *HMAC_SHA512; + OFFile *file = [OFFile fileWithPath: @"testfile.bin" mode: @"r"]; + OFHMAC *HMACMD5, *HMACSHA1, *HMACRMD160; + OFHMAC *HMACSHA256, *HMACSHA384, *HMACSHA512; TEST(@"+[HMACWithHashClass:] with MD5", - (HMAC_MD5 = [OFHMAC HMACWithHashClass: [OFMD5Hash class] - allowsSwappableMemory: true])) + (HMACMD5 = [OFHMAC HMACWithHashClass: [OFMD5Hash class] + allowsSwappableMemory: true])) TEST(@"+[HMACWithHashClass:] with SHA-1", - (HMAC_SHA1 = [OFHMAC HMACWithHashClass: [OFSHA1Hash class] - allowsSwappableMemory: true])) + (HMACSHA1 = [OFHMAC HMACWithHashClass: [OFSHA1Hash class] + allowsSwappableMemory: true])) TEST(@"+[HMACWithHashClass:] with RIPEMD-160", - (HMAC_RMD160 = [OFHMAC HMACWithHashClass: [OFRIPEMD160Hash class] - allowsSwappableMemory: true])) + (HMACRMD160 = [OFHMAC HMACWithHashClass: [OFRIPEMD160Hash class] + allowsSwappableMemory: true])) TEST(@"+[HMACWithHashClass:] with SHA-256", - (HMAC_SHA256 = [OFHMAC HMACWithHashClass: [OFSHA256Hash class] - allowsSwappableMemory: true])) + (HMACSHA256 = [OFHMAC HMACWithHashClass: [OFSHA256Hash class] + allowsSwappableMemory: true])) TEST(@"+[HMACWithHashClass:] with SHA-384", - (HMAC_SHA384 = [OFHMAC HMACWithHashClass: [OFSHA384Hash class] - allowsSwappableMemory: true])) + (HMACSHA384 = [OFHMAC HMACWithHashClass: [OFSHA384Hash class] + allowsSwappableMemory: true])) TEST(@"+[HMACWithHashClass:] with SHA-512", - (HMAC_SHA512 = [OFHMAC HMACWithHashClass: [OFSHA512Hash class] - allowsSwappableMemory: true])) + (HMACSHA512 = [OFHMAC HMACWithHashClass: [OFSHA512Hash class] + allowsSwappableMemory: true])) EXPECT_EXCEPTION(@"Detection of missing key", - OFInvalidArgumentException, [HMAC_MD5 updateWithBuffer: "" - length: 0]) + OFInvalidArgumentException, + [HMACMD5 updateWithBuffer: "" length: 0]) TEST(@"-[setKey:length:] with MD5", - R([HMAC_MD5 setKey: key - length: key_length])) - TEST(@"-[setKey:length:] with SHA-1", - R([HMAC_SHA1 setKey: key - length: key_length])) - TEST(@"-[setKey:length:] with RIPEMD-160", - R([HMAC_RMD160 setKey: key - length: key_length])) - TEST(@"-[setKey:length:] with SHA-256", - R([HMAC_SHA256 setKey: key - length: key_length])) - TEST(@"-[setKey:length:] with SHA-384", - R([HMAC_SHA384 setKey: key - length: key_length])) - TEST(@"-[setKey:length:] with SHA-512", - R([HMAC_SHA512 setKey: key - length: key_length])) - - while (!f.atEndOfStream) { - char buf[64]; - size_t len = [f readIntoBuffer: buf - length: 64]; - [HMAC_MD5 updateWithBuffer: buf - length: len]; - [HMAC_SHA1 updateWithBuffer: buf - length: len]; - [HMAC_RMD160 updateWithBuffer: buf - length: len]; - [HMAC_SHA256 updateWithBuffer: buf - length: len]; - [HMAC_SHA384 updateWithBuffer: buf - length: len]; - [HMAC_SHA512 updateWithBuffer: buf - length: len]; - } - [f close]; + R([HMACMD5 setKey: key length: keyLength])) + TEST(@"-[setKey:length:] with SHA-1", + R([HMACSHA1 setKey: key length: keyLength])) + TEST(@"-[setKey:length:] with RIPEMD-160", + R([HMACRMD160 setKey: key length: keyLength])) + TEST(@"-[setKey:length:] with SHA-256", + R([HMACSHA256 setKey: key length: keyLength])) + TEST(@"-[setKey:length:] with SHA-384", + R([HMACSHA384 setKey: key length: keyLength])) + TEST(@"-[setKey:length:] with SHA-512", + R([HMACSHA512 setKey: key length: keyLength])) + + while (!file.atEndOfStream) { + char buffer[64]; + size_t length = [file readIntoBuffer: buffer length: 64]; + [HMACMD5 updateWithBuffer: buffer length: length]; + [HMACSHA1 updateWithBuffer: buffer length: length]; + [HMACRMD160 updateWithBuffer: buffer length: length]; + [HMACSHA256 updateWithBuffer: buffer length: length]; + [HMACSHA384 updateWithBuffer: buffer length: length]; + [HMACSHA512 updateWithBuffer: buffer length: length]; + } + [file close]; + + TEST(@"-[calculate] with MD5", R([HMACMD5 calculate])) + TEST(@"-[calculate] with SHA-1", R([HMACSHA1 calculate])) + TEST(@"-[calculate] with RIPEMD-160", R([HMACRMD160 calculate])) + TEST(@"-[calculate] with SHA-256", R([HMACSHA256 calculate])) + TEST(@"-[calculate] with SHA-384", R([HMACSHA384 calculate])) + TEST(@"-[calculate] with SHA-512", R([HMACSHA512 calculate])) TEST(@"-[digest] with MD5", - memcmp(HMAC_MD5.digest, digest_md5, HMAC_MD5.digestSize) == 0) + memcmp(HMACMD5.digest, MD5Digest, HMACMD5.digestSize) == 0) TEST(@"-[digest] with SHA-1", - memcmp(HMAC_SHA1.digest, digest_sha1, HMAC_SHA1.digestSize) == 0) + memcmp(HMACSHA1.digest, SHA1Digest, HMACSHA1.digestSize) == 0) TEST(@"-[digest] with RIPEMD-160", - memcmp(HMAC_RMD160.digest, digest_rmd160, - HMAC_RMD160.digestSize) == 0) + memcmp(HMACRMD160.digest, RIPEMD160Digest, + HMACRMD160.digestSize) == 0) TEST(@"-[digest] with SHA-256", - memcmp(HMAC_SHA256.digest, digest_sha256, - HMAC_SHA256.digestSize) == 0) + memcmp(HMACSHA256.digest, SHA256Digest, HMACSHA256.digestSize) == 0) TEST(@"-[digest] with SHA-384", - memcmp(HMAC_SHA384.digest, digest_sha384, - HMAC_SHA384.digestSize) == 0) + memcmp(HMACSHA384.digest, SHA384Digest, HMACSHA384.digestSize) == 0) TEST(@"-[digest] with SHA-512", - memcmp(HMAC_SHA512.digest, digest_sha512, - HMAC_SHA512.digestSize) == 0) + memcmp(HMACSHA512.digest, SHA512Digest, HMACSHA512.digestSize) == 0) objc_autoreleasePoolPop(pool); } @end Index: tests/OFHTTPClientTests.m ================================================================== --- tests/OFHTTPClientTests.m +++ tests/OFHTTPClientTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -20,12 +18,12 @@ #include #include #import "TestsAppDelegate.h" -static OFString *module = @"OFHTTPClient"; -static OFCondition *cond; +static OFString *const module = @"OFHTTPClient"; +static OFCondition *condition; static OFHTTPResponse *response = nil; @interface TestsAppDelegate (HTTPClientTests) @end @@ -40,46 +38,35 @@ - (id)main { OFTCPSocket *listener, *client; char buffer[5]; - [cond lock]; + [condition lock]; listener = [OFTCPSocket socket]; - _port = [listener bindToHost: @"127.0.0.1" - port: 0]; + _port = [listener bindToHost: @"127.0.0.1" port: 0]; [listener listen]; - [cond signal]; - [cond unlock]; + [condition signal]; + [condition unlock]; client = [listener accept]; - if (![[client readLine] isEqual: @"GET /foo HTTP/1.1"]) - OF_ENSURE(0); - - if (![[client readLine] hasPrefix: @"User-Agent:"]) - OF_ENSURE(0); - - if (![[client readLine] isEqual: @"Content-Length: 5"]) - OF_ENSURE(0); - - if (![[client readLine] isEqual: - @"Content-Type: application/x-www-form-urlencoded; charset=UTF-8"]) - OF_ENSURE(0); + OFEnsure([[client readLine] isEqual: @"GET /foo HTTP/1.1"]); + OFEnsure([[client readLine] hasPrefix: @"User-Agent:"]); + OFEnsure([[client readLine] isEqual: @"Content-Length: 5"]); + OFEnsure([[client readLine] isEqual: + @"Content-Type: application/x-www-form-urlencoded; charset=UTF-8"]); if (![[client readLine] isEqual: [OFString stringWithFormat: @"Host: 127.0.0.1:%" @PRIu16, _port]]) - OF_ENSURE(0); - - if (![[client readLine] isEqual: @""]) - OF_ENSURE(0); - - [client readIntoBuffer: buffer - exactLength: 5]; - if (memcmp(buffer, "Hello", 5) != 0) - OF_ENSURE(0); + OFEnsure(0); + + OFEnsure([[client readLine] isEqual: @""]); + + [client readIntoBuffer: buffer exactLength: 5]; + OFEnsure(memcmp(buffer, "Hello", 5) == 0); [client writeString: @"HTTP/1.0 200 OK\r\n" @"cONTeNT-lENgTH: 7\r\n" @"\r\n" @"foo\n" @@ -101,11 +88,11 @@ - (void)client: (OFHTTPClient *)client didPerformRequest: (OFHTTPRequest *)request response: (OFHTTPResponse *)response_ exception: (id)exception { - OF_ENSURE(exception == nil); + OFEnsure(exception == nil); response = [response_ retain]; [[OFRunLoop mainRunLoop] stop]; } @@ -117,19 +104,19 @@ OFURL *URL; OFHTTPClient *client; OFHTTPRequest *request; OFData *data; - cond = [OFCondition condition]; - [cond lock]; + condition = [OFCondition condition]; + [condition lock]; server = [[[HTTPClientTestsServer alloc] init] autorelease]; server.supportsSockets = true; [server start]; - [cond wait]; - [cond unlock]; + [condition wait]; + [condition unlock]; URL = [OFURL URLWithString: [OFString stringWithFormat: @"http://127.0.0.1:%" @PRIu16 "/foo", server->_port]]; Index: tests/OFHTTPCookieManagerTests.m ================================================================== --- tests/OFHTTPCookieManagerTests.m +++ tests/OFHTTPCookieManagerTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -17,89 +15,89 @@ #include "config.h" #import "TestsAppDelegate.h" -static OFString *module = @"OFHTTPCookieManager"; +static OFString *const module = @"OFHTTPCookieManager"; @implementation TestsAppDelegate (OFHTTPCookieManagerTests) - (void)HTTPCookieManagerTests { void *pool = objc_autoreleasePoolPush(); OFHTTPCookieManager *manager = [OFHTTPCookieManager manager]; - OFURL *URL[4]; - OFHTTPCookie *cookie[5]; - - URL[0] = [OFURL URLWithString: @"http://nil.im/foo"]; - URL[1] = [OFURL URLWithString: @"https://nil.im/foo/bar"]; - URL[2] = [OFURL URLWithString: @"https://test.nil.im/foo/bar"]; - URL[3] = [OFURL URLWithString: @"http://webkeks.org/foo/bar"]; - - cookie[0] = [OFHTTPCookie cookieWithName: @"test" - value: @"1" - domain: @"nil.im"]; - TEST(@"-[addCookie:forURL:] #1", R([manager addCookie: cookie[0] - forURL: URL[0]])) + OFURL *URL1, *URL2, *URL3, *URL4; + OFHTTPCookie *cookie1, *cookie2, *cookie3, *cookie4, *cookie5; + + URL1 = [OFURL URLWithString: @"http://nil.im/foo"]; + URL2 = [OFURL URLWithString: @"https://nil.im/foo/bar"]; + URL3 = [OFURL URLWithString: @"https://test.nil.im/foo/bar"]; + URL4 = [OFURL URLWithString: @"http://webkeks.org/foo/bar"]; + + cookie1 = [OFHTTPCookie cookieWithName: @"test" + value: @"1" + domain: @"nil.im"]; + TEST(@"-[addCookie:forURL:] #1", + R([manager addCookie: cookie1 forURL: URL1])) TEST(@"-[cookiesForURL:] #1", - [[manager cookiesForURL: URL[0]] isEqual: - [OFArray arrayWithObject: cookie[0]]]) - - cookie[1] = [OFHTTPCookie cookieWithName: @"test" - value: @"2" - domain: @"webkeks.org"]; - TEST(@"-[addCookie:forURL:] #2", R([manager addCookie: cookie[1] - forURL: URL[0]])) + [[manager cookiesForURL: URL1] isEqual: + [OFArray arrayWithObject: cookie1]]) + + cookie2 = [OFHTTPCookie cookieWithName: @"test" + value: @"2" + domain: @"webkeks.org"]; + TEST(@"-[addCookie:forURL:] #2", + R([manager addCookie: cookie2 forURL: URL1])) TEST(@"-[cookiesForURL:] #2", - [[manager cookiesForURL: URL[0]] isEqual: - [OFArray arrayWithObject: cookie[0]]] && - [[manager cookiesForURL: URL[3]] isEqual: [OFArray array]]) - - cookie[2] = [OFHTTPCookie cookieWithName: @"test" - value: @"3" - domain: @"nil.im"]; - cookie[2].secure = true; - TEST(@"-[addCookie:forURL:] #3", R([manager addCookie: cookie[2] - forURL: URL[1]])) + [[manager cookiesForURL: URL1] isEqual: + [OFArray arrayWithObject: cookie1]] && + [[manager cookiesForURL: URL4] isEqual: [OFArray array]]) + + cookie3 = [OFHTTPCookie cookieWithName: @"test" + value: @"3" + domain: @"nil.im"]; + cookie3.secure = true; + TEST(@"-[addCookie:forURL:] #3", + R([manager addCookie: cookie3 forURL: URL2])) TEST(@"-[cookiesForURL:] #3", - [[manager cookiesForURL: URL[1]] isEqual: - [OFArray arrayWithObject: cookie[2]]] && - [[manager cookiesForURL: URL[0]] isEqual: [OFArray array]]) - - cookie[2].expires = [OFDate dateWithTimeIntervalSinceNow: -1]; - cookie[3] = [OFHTTPCookie cookieWithName: @"test" - value: @"4" - domain: @"nil.im"]; - cookie[3].domain = @".nil.im"; - TEST(@"-[addCookie:forURL:] #4", R([manager addCookie: cookie[3] - forURL: URL[1]])) + [[manager cookiesForURL: URL2] isEqual: + [OFArray arrayWithObject: cookie3]] && + [[manager cookiesForURL: URL1] isEqual: [OFArray array]]) + + cookie3.expires = [OFDate dateWithTimeIntervalSinceNow: -1]; + cookie4 = [OFHTTPCookie cookieWithName: @"test" + value: @"4" + domain: @"nil.im"]; + cookie4.domain = @".nil.im"; + TEST(@"-[addCookie:forURL:] #4", + R([manager addCookie: cookie4 forURL: URL2])) TEST(@"-[cookiesForURL:] #4", - [[manager cookiesForURL: URL[1]] isEqual: - [OFArray arrayWithObject: cookie[3]]] && - [[manager cookiesForURL: URL[2]] isEqual: - [OFArray arrayWithObject: cookie[3]]]) - - cookie[4] = [OFHTTPCookie cookieWithName: @"bar" - value: @"5" - domain: @"test.nil.im"]; - TEST(@"-[addCookie:forURL:] #5", R([manager addCookie: cookie[4] - forURL: URL[0]])) + [[manager cookiesForURL: URL2] isEqual: + [OFArray arrayWithObject: cookie4]] && + [[manager cookiesForURL: URL3] isEqual: + [OFArray arrayWithObject: cookie4]]) + + cookie5 = [OFHTTPCookie cookieWithName: @"bar" + value: @"5" + domain: @"test.nil.im"]; + TEST(@"-[addCookie:forURL:] #5", + R([manager addCookie: cookie5 forURL: URL1])) TEST(@"-[cookiesForURL:] #5", - [[manager cookiesForURL: URL[0]] isEqual: - [OFArray arrayWithObject: cookie[3]]] && - [[manager cookiesForURL: URL[2]] isEqual: - [OFArray arrayWithObjects: cookie[3], cookie[4], nil]]) + [[manager cookiesForURL: URL1] isEqual: + [OFArray arrayWithObject: cookie4]] && + [[manager cookiesForURL: URL3] isEqual: + [OFArray arrayWithObjects: cookie4, cookie5, nil]]) TEST(@"-[purgeExpiredCookies]", [manager.cookies isEqual: - [OFArray arrayWithObjects: cookie[2], cookie[3], cookie[4], nil]] && + [OFArray arrayWithObjects: cookie3, cookie4, cookie5, nil]] && R([manager purgeExpiredCookies]) && [manager.cookies isEqual: - [OFArray arrayWithObjects: cookie[3], cookie[4], nil]]) + [OFArray arrayWithObjects: cookie4, cookie5, nil]]) objc_autoreleasePoolPop(pool); } @end Index: tests/OFHTTPCookieTests.m ================================================================== --- tests/OFHTTPCookieTests.m +++ tests/OFHTTPCookieTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -17,59 +15,59 @@ #include "config.h" #import "TestsAppDelegate.h" -static OFString *module = @"OFHTTPCookie"; +static OFString *const module = @"OFHTTPCookie"; @implementation TestsAppDelegate (OFHTTPCookieTests) - (void)HTTPCookieTests { void *pool = objc_autoreleasePoolPush(); OFURL *URL = [OFURL URLWithString: @"http://nil.im"]; - OFHTTPCookie *cookie[2]; + OFHTTPCookie *cookie1, *cookie2; OFArray OF_GENERIC(OFHTTPCookie *) *cookies; - cookie[0] = [OFHTTPCookie cookieWithName: @"foo" - value: @"bar" - domain: @"nil.im"]; + cookie1 = [OFHTTPCookie cookieWithName: @"foo" + value: @"bar" + domain: @"nil.im"]; TEST(@"+[cookiesWithResponseHeaderFields:forURL:] #1", [[OFHTTPCookie cookiesWithResponseHeaderFields: [OFDictionary dictionaryWithObject: @"foo=bar" forKey: @"Set-Cookie"] forURL: URL] - isEqual: [OFArray arrayWithObject: cookie[0]]]) + isEqual: [OFArray arrayWithObject: cookie1]]) - cookie[1] = [OFHTTPCookie cookieWithName: @"qux" - value: @"cookie" - domain: @"nil.im"]; + cookie2 = [OFHTTPCookie cookieWithName: @"qux" + value: @"cookie" + domain: @"nil.im"]; TEST(@"+[cookiesWithResponseHeaderFields:forURL:] #2", [[OFHTTPCookie cookiesWithResponseHeaderFields: [OFDictionary dictionaryWithObject: @"foo=bar,qux=cookie" forKey: @"Set-Cookie"] forURL: URL] - isEqual: [OFArray arrayWithObjects: cookie[0], cookie[1], nil]]) - - cookie[0].expires = [OFDate dateWithTimeIntervalSince1970: 1234567890]; - cookie[1].expires = [OFDate dateWithTimeIntervalSince1970: 1234567890]; - cookie[0].path = @"/x"; - cookie[1].domain = @"webkeks.org"; - cookie[1].path = @"/objfw"; - cookie[1].secure = true; - cookie[1].HTTPOnly = true; - [cookie[1].extensions addObject: @"foo"]; - [cookie[1].extensions addObject: @"bar"]; + isEqual: [OFArray arrayWithObjects: cookie1, cookie2, nil]]) + + cookie1.expires = [OFDate dateWithTimeIntervalSince1970: 1234567890]; + cookie2.expires = [OFDate dateWithTimeIntervalSince1970: 1234567890]; + cookie1.path = @"/x"; + cookie2.domain = @"webkeks.org"; + cookie2.path = @"/objfw"; + cookie2.secure = true; + cookie2.HTTPOnly = true; + [cookie2.extensions addObject: @"foo"]; + [cookie2.extensions addObject: @"bar"]; TEST(@"+[cookiesWithResponseHeaderFields:forURL:] #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"] forURL: URL]) isEqual: - [OFArray arrayWithObjects: cookie[0], cookie[1], nil]]) + [OFArray arrayWithObjects: cookie1, cookie2, nil]]) TEST(@"+[requestHeaderFieldsWithCookies:]", [[OFHTTPCookie requestHeaderFieldsWithCookies: cookies] isEqual: [OFDictionary dictionaryWithObject: @"foo=bar; qux=cookie" forKey: @"Cookie"]]) objc_autoreleasePoolPop(pool); } @end Index: tests/OFINIFileTests.m ================================================================== --- tests/OFINIFileTests.m +++ tests/OFINIFileTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -17,11 +15,11 @@ #include "config.h" #import "TestsAppDelegate.h" -static OFString *module = @"OFINIFile"; +static OFString *module; @implementation TestsAppDelegate (OFINIFileTests) - (void)INIFileTests { void *pool = objc_autoreleasePoolPush(); @@ -49,14 +47,16 @@ OFINICategory *tests, *foobar, *types; OFArray *array; #ifndef OF_NINTENDO_DS OFString *writePath; #endif + + module = @"OFINIFile"; TEST(@"+[fileWithPath:encoding:]", (file = [OFINIFile fileWithPath: @"testfile.ini" - encoding: OF_STRING_ENCODING_CODEPAGE_437])) + encoding: OFStringEncodingCodepage437])) tests = [file categoryForName: @"tests"]; foobar = [file categoryForName: @"foobar"]; types = [file categoryForName: @"types"]; TEST(@"-[categoryForName:]", @@ -67,80 +67,66 @@ TEST(@"-[stringForKey:]", [[tests stringForKey: @"foo"] isEqual: @"bar"] && [[foobar stringForKey: @"quxquxqux"] isEqual: @"hello\"wörld"]) TEST(@"-[setString:forKey:]", - R([tests setString: @"baz" - forKey: @"foo"]) && - R([tests setString: @"new" - forKey: @"new"]) && - R([foobar setString: @"a\fb" - forKey: @"qux3"])) - - TEST(@"-[integerForKey:defaultValue:]", - [types integerForKey: @"integer" - defaultValue: 2] == 0x20) - - TEST(@"-[setInteger:forKey:]", R([types setInteger: 0x10 - forKey: @"integer"])) + R([tests setString: @"baz" forKey: @"foo"]) && + R([tests setString: @"new" forKey: @"new"]) && + R([foobar setString: @"a\fb" forKey: @"qux3"])) + + TEST(@"-[longLongForKey:defaultValue:]", + [types longLongForKey: @"integer" defaultValue: 2] == 0x20) + + TEST(@"-[setLongLong:forKey:]", + R([types setLongLong: 0x10 forKey: @"integer"])) TEST(@"-[boolForKey:defaultValue:]", - [types boolForKey: @"bool" - defaultValue: false] == true) + [types boolForKey: @"bool" defaultValue: false] == true) - TEST(@"-[setBool:forKey:]", R([types setBool: false - forKey: @"bool"])) + TEST(@"-[setBool:forKey:]", R([types setBool: false forKey: @"bool"])) TEST(@"-[floatForKey:defaultValue:]", - [types floatForKey: @"float" - defaultValue: 1] == 0.5f) + [types floatForKey: @"float" defaultValue: 1] == 0.5f) - TEST(@"-[setFloat:forKey:]", R([types setFloat: 0.25f - forKey: @"float"])) + TEST(@"-[setFloat:forKey:]", + R([types setFloat: 0.25f forKey: @"float"])) TEST(@"-[doubleForKey:defaultValue:]", - [types doubleForKey: @"double" - defaultValue: 3] == 0.25) + [types doubleForKey: @"double" defaultValue: 3] == 0.25) - TEST(@"-[setDouble:forKey:]", R([types setDouble: 0.75 - forKey: @"double"])) + TEST(@"-[setDouble:forKey:]", + R([types setDouble: 0.75 forKey: @"double"])) array = [OFArray arrayWithObjects: @"1", @"2", nil]; - TEST(@"-[arrayForKey:]", - [[types arrayForKey: @"array1"] isEqual: array] && - [[types arrayForKey: @"array2"] isEqual: array] && - [[types arrayForKey: @"array3"] isEqual: [OFArray array]]) + TEST(@"-[stringArrayForKey:]", + [[types stringArrayForKey: @"array1"] isEqual: array] && + [[types stringArrayForKey: @"array2"] isEqual: array] && + [[types stringArrayForKey: @"array3"] isEqual: [OFArray array]]) array = [OFArray arrayWithObjects: @"foo", @"bar", nil]; - TEST(@"-[setArray:forKey:]", R([types setArray: array - forKey: @"array1"])) + TEST(@"-[setStringArray:forKey:]", + R([types setStringArray: array forKey: @"array1"])) TEST(@"-[removeValueForKey:]", R([foobar removeValueForKey: @"quxqux "]) && R([types removeValueForKey: @"array2"])) module = @"OFINIFile"; /* FIXME: Find a way to write files on Nintendo DS */ #ifndef OF_NINTENDO_DS -# ifndef OF_IOS - writePath = @"tmpfile.ini"; -# else - writePath = [OFString pathWithComponents: [OFArray arrayWithObjects: - [[OFApplication environment] objectForKey: @"HOME"], - @"tmp", @"tmpfile.ini", nil]]; -# endif + writePath = [[OFSystemInfo temporaryDirectoryPath] + stringByAppendingPathComponent: @"objfw-tests.ini"]; TEST(@"-[writeToFile:encoding:]", R([file writeToFile: writePath - encoding: OF_STRING_ENCODING_CODEPAGE_437]) && - [[OFString - stringWithContentsOfFile: writePath - encoding: OF_STRING_ENCODING_CODEPAGE_437] + encoding: OFStringEncodingCodepage437]) && + [[OFString stringWithContentsOfFile: writePath + encoding: OFStringEncodingCodepage437] isEqual: output]) [[OFFileManager defaultManager] removeItemAtPath: writePath]; #else (void)output; #endif objc_autoreleasePoolPop(pool); } @end Index: tests/OFIPXSocketTests.m ================================================================== --- tests/OFIPXSocketTests.m +++ tests/OFIPXSocketTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -19,38 +17,37 @@ #include #import "TestsAppDelegate.h" -static OFString *module = @"OFIPXSocket"; +static OFString *const module = @"OFIPXSocket"; @implementation TestsAppDelegate (OFIPXSocketTests) - (void)IPXSocketTests { void *pool = objc_autoreleasePoolPush(); OFIPXSocket *sock; - of_socket_address_t address1, address2; + OFSocketAddress address1, address2; char buffer[5]; TEST(@"+[socket]", (sock = [OFIPXSocket socket])) @try { TEST(@"-[bindToPort:packetType:]", - R(address1 = [sock bindToPort: 0 - packetType: 0])) + R(address1 = [sock bindToPort: 0 packetType: 0])) } @catch (OFBindFailedException *e) { switch (e.errNo) { case EAFNOSUPPORT: - [of_stdout setForegroundColor: [OFColor lime]]; - [of_stdout writeLine: - @"[OFIPXSocket] -[bindToPort:packetType:]: " + [OFStdOut setForegroundColor: [OFColor lime]]; + [OFStdOut writeLine: + @"\r[OFIPXSocket] -[bindToPort:packetType:]: " @"IPX unsupported, skipping tests"]; break; case EADDRNOTAVAIL: - [of_stdout setForegroundColor: [OFColor lime]]; - [of_stdout writeLine: - @"[OFIPXSocket] -[bindToPort:packetType:]: " + [OFStdOut setForegroundColor: [OFColor lime]]; + [OFStdOut writeLine: + @"\r[OFIPXSocket] -[bindToPort:packetType:]: " @"IPX not configured, skipping tests"]; break; default: @throw e; } @@ -58,21 +55,16 @@ objc_autoreleasePoolPop(pool); return; } TEST(@"-[sendBuffer:length:receiver:]", - R([sock sendBuffer: "Hello" - length: 5 - receiver: &address1])) + R([sock sendBuffer: "Hello" length: 5 receiver: &address1])) TEST(@"-[receiveIntoBuffer:length:sender:]", - [sock receiveIntoBuffer: buffer - length: 5 - sender: &address2] == 5 && + [sock receiveIntoBuffer: buffer length: 5 sender: &address2] == 5 && memcmp(buffer, "Hello", 5) == 0 && - of_socket_address_equal(&address1, &address2) && - of_socket_address_hash(&address1) == - of_socket_address_hash(&address2)) + OFSocketAddressEqual(&address1, &address2) && + OFSocketAddressHash(&address1) == OFSocketAddressHash(&address2)) objc_autoreleasePoolPop(pool); } @end Index: tests/OFInvocationTests.m ================================================================== --- tests/OFInvocationTests.m +++ tests/OFInvocationTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -24,246 +22,33 @@ # include #endif #import "TestsAppDelegate.h" -static OFString *module = @"OFInvocation"; +static OFString *const module = @"OFInvocation"; -struct test_struct { +struct TestStruct { unsigned char c; unsigned int i; }; @implementation TestsAppDelegate (OFInvocationTests) -- (struct test_struct)invocationTestMethod1: (unsigned char)c - : (unsigned int)i - : (struct test_struct *)ptr - : (struct test_struct)st +- (struct TestStruct)invocationTestMethod1: (unsigned char)c + : (unsigned int)i + : (struct TestStruct *)ptr + : (struct TestStruct)st { return st; } -#ifdef OF_INVOCATION_CAN_INVOKE -- (void)invocationTestMethod2: (id)obj -{ - assert(obj == self); -} - -- (int)invocationTestMethod3: (int)i1 - : (int)i2 - : (int)i3 - : (int)i4 - : (int)i5 - : (int)i6 - : (int)i7 - : (int)i8 - : (int)i9 - : (int)i10 - : (int)i11 - : (int)i12 - : (int)i13 - : (int)i14 - : (int)i15 - : (int)i16 -{ - return (i1 + i2 + i3 + i4 + i5 + i6 + i7 + i8 + i9 + i10 + i11 + - i12 + i13 + i14 + i15 + i16) / 16; -} - -- (double)invocationTestMethod4: (double)d1 - : (double)d2 - : (double)d3 - : (double)d4 - : (double)d5 - : (double)d6 - : (double)d7 - : (double)d8 - : (double)d9 - : (double)d10 - : (double)d11 - : (double)d12 - : (double)d13 - : (double)d14 - : (double)d15 - : (double)d16 -{ - return (d1 + d2 + d3 + d4 + d5 + d6 + d7 + d8 + d9 + d10 + d11 + - d12 + d13 + d14 + d15 + d16) / 16; -} - -- (float)invocationTestMethod5: (double)d1 - : (float)f2 - : (float)f3 - : (float)f4 - : (float)f5 - : (float)f6 - : (float)f7 - : (float)f8 - : (float)f9 - : (double)d10 - : (float)f11 - : (float)f12 - : (float)f13 - : (float)f14 - : (float)f15 - : (float)f16 -{ - return (float)((d1 + f2 + f3 + f4 + f5 + f6 + f7 + f8 + f9 + d10 + f11 + - f12 + f13 + f14 + f15 + f16) / 16); -} - -- (long double)invocationTestMethod6: (long double)d1 - : (long double)d2 - : (long double)d3 - : (long double)d4 - : (long double)d5 - : (long double)d6 - : (long double)d7 - : (long double)d8 - : (long double)d9 - : (long double)d10 - : (long double)d11 - : (long double)d12 - : (long double)d13 - : (long double)d14 - : (long double)d15 - : (long double)d16 -{ - return (d1 + d2 + d3 + d4 + d5 + d6 + d7 + d8 + d9 + d10 + d11 + - d12 + d13 + d14 + d15 + d16) / 16; -} - -# if defined(HAVE_COMPLEX_H) && !defined(__STDC_NO_COMPLEX__) -- (complex double)invocationTestMethod7: (complex float)c1 - : (complex double)c2 - : (complex float)c3 - : (complex double)c4 - : (complex float)c5 - : (complex double)c6 - : (complex float)c7 - : (complex double)c8 - : (complex float)c9 - : (complex double)c10 - : (complex float)c11 - : (complex double)c12 - : (complex float)c13 - : (complex double)c14 - : (complex float)c15 - : (complex double)c16 -{ - OF_ENSURE(creal(c1) == 1.0 && cimag(c1) == 0.5); - OF_ENSURE(creal(c2) == 2.0 && cimag(c2) == 1.0); - OF_ENSURE(creal(c3) == 3.0 && cimag(c3) == 1.5); - OF_ENSURE(creal(c4) == 4.0 && cimag(c4) == 2.0); - OF_ENSURE(creal(c5) == 5.0 && cimag(c5) == 2.5); - OF_ENSURE(creal(c6) == 6.0 && cimag(c6) == 3.0); - OF_ENSURE(creal(c7) == 7.0 && cimag(c7) == 3.5); - OF_ENSURE(creal(c8) == 8.0 && cimag(c8) == 4.0); - OF_ENSURE(creal(c9) == 9.0 && cimag(c9) == 4.5); - OF_ENSURE(creal(c10) == 10.0 && cimag(c10) == 5.0); - OF_ENSURE(creal(c11) == 11.0 && cimag(c11) == 5.5); - OF_ENSURE(creal(c12) == 12.0 && cimag(c12) == 6.0); - OF_ENSURE(creal(c13) == 13.0 && cimag(c13) == 6.5); - OF_ENSURE(creal(c14) == 14.0 && cimag(c14) == 7.0); - OF_ENSURE(creal(c15) == 15.0 && cimag(c15) == 7.5); - OF_ENSURE(creal(c16) == 16.0 && cimag(c16) == 8.0); - - return (c1 + c2 + c3 + c4 + c5 + c6 + c7 + c8 + c9 + c10 + c11 + - c12 + c13 + c14 + c15 + c16) / 16; -} - -- (complex long double)invocationTestMethod8: (complex double)c1 - : (complex float)c2 - : (complex long double)c3 - : (complex double)c4 - : (complex float)c5 - : (complex long double)c6 - : (complex double)c7 - : (complex float)c8 - : (complex long double)c9 - : (complex double)c10 - : (complex float)c11 - : (complex long double)c12 - : (complex double)c13 - : (complex float)c14 - : (complex long double)c15 - : (complex double)c16 -{ - OF_ENSURE(creal(c1) == 1.0 && cimag(c1) == 0.5); - OF_ENSURE(creal(c2) == 2.0 && cimag(c2) == 1.0); - OF_ENSURE(creal(c3) == 3.0 && cimag(c3) == 1.5); - OF_ENSURE(creal(c4) == 4.0 && cimag(c4) == 2.0); - OF_ENSURE(creal(c5) == 5.0 && cimag(c5) == 2.5); - OF_ENSURE(creal(c6) == 6.0 && cimag(c6) == 3.0); - OF_ENSURE(creal(c7) == 7.0 && cimag(c7) == 3.5); - OF_ENSURE(creal(c8) == 8.0 && cimag(c8) == 4.0); - OF_ENSURE(creal(c9) == 9.0 && cimag(c9) == 4.5); - OF_ENSURE(creal(c10) == 10.0 && cimag(c10) == 5.0); - OF_ENSURE(creal(c11) == 11.0 && cimag(c11) == 5.5); - OF_ENSURE(creal(c12) == 12.0 && cimag(c12) == 6.0); - OF_ENSURE(creal(c13) == 13.0 && cimag(c13) == 6.5); - OF_ENSURE(creal(c14) == 14.0 && cimag(c14) == 7.0); - OF_ENSURE(creal(c15) == 15.0 && cimag(c15) == 7.5); - OF_ENSURE(creal(c16) == 16.0 && cimag(c16) == 8.0); - - return (c1 + c2 + c3 + c4 + c5 + c6 + c7 + c8 + c9 + c10 + c11 + - c12 + c13 + c14 + c15 + c16) / 16; -} -# endif - -# ifdef __SIZEOF_INT128__ -__extension__ -- (__int128)invocationTestMethod9: (int)i1 - : (__int128)i2 - : (__int128)i3 - : (__int128)i4 - : (int)i5 - : (__int128)i6 - : (__int128)i7 - : (__int128)i8 - : (__int128)i9 - : (__int128)i10 - : (__int128)i11 - : (__int128)i12 - : (__int128)i13 - : (__int128)i14 - : (__int128)i15 - : (__int128)i16 -{ - __int128 mask = (__int128)0xFFFFFFFFFFFFFFFF << 64; - - OF_ENSURE(i1 == 1); - OF_ENSURE(i2 == mask + 2); - OF_ENSURE(i3 == mask + 3); - OF_ENSURE(i4 == mask + 4); - OF_ENSURE(i5 == 5); - OF_ENSURE(i6 == mask + 6); - OF_ENSURE(i7 == mask + 7); - OF_ENSURE(i8 == mask + 8); - OF_ENSURE(i9 == mask + 9); - OF_ENSURE(i10 == mask + 10); - OF_ENSURE(i11 == mask + 11); - OF_ENSURE(i12 == mask + 12); - OF_ENSURE(i13 == mask + 13); - OF_ENSURE(i14 == mask + 14); - OF_ENSURE(i15 == mask + 15); - OF_ENSURE(i16 == mask + 16); - - return ((i1 + (int)i2 + (int)i3 + (int)i4 + i5 + (int)i6 + (int)i7 + - (int)i8 + (int)i9 + (int)i10 + (int)i11 + (int)i12 + (int)i13 + - (int)i14 + (int)i15 + (int)i16) / 16) + mask; -} -# endif -#endif - - (void)invocationTests { void *pool = objc_autoreleasePoolPush(); SEL selector = @selector(invocationTestMethod1::::); OFMethodSignature *sig = [self methodSignatureForSelector: selector]; OFInvocation *invocation; - struct test_struct st, st2, *stp = &st, *stp2; + struct TestStruct st, st2, *stp = &st, *stp2; unsigned const char c = 0xAA; unsigned char c2; const unsigned int i = 0x55555555; unsigned int i2; @@ -283,241 +68,33 @@ TEST(@"-[getReturnValue]", R([invocation getReturnValue: &st2]) && memcmp(&st, &st2, sizeof(st)) == 0) memset(&st2, '\0', sizeof(st2)); - TEST(@"-[setArgument:atIndex:] #1", R([invocation setArgument: &c - atIndex: 2])) - - TEST(@"-[setArgument:atIndex:] #2", R([invocation setArgument: &i - atIndex: 3])) - - TEST(@"-[setArgument:atIndex:] #3", R([invocation setArgument: &stp - atIndex: 4])) - - TEST(@"-[setArgument:atIndex:] #4", R([invocation setArgument: &st - atIndex: 5])) - - TEST(@"-[getArgument:atIndex:] #1", R([invocation getArgument: &c2 - atIndex: 2]) && - c == c2) - - TEST(@"-[getArgument:atIndex:] #2", R([invocation getArgument: &i2 - atIndex: 3]) && - i == i2) - - TEST(@"-[getArgument:atIndex:] #3", R([invocation getArgument: &stp2 - atIndex: 4]) && - stp == stp2) - - TEST(@"-[getArgument:atIndex:] #4", R([invocation getArgument: &st2 - atIndex: 5]) && - memcmp(&st, &st2, sizeof(st)) == 0) - -#ifdef OF_INVOCATION_CAN_INVOKE - /* -[invoke] #1 */ - selector = @selector(invocationTestMethod2:); - invocation = [OFInvocation invocationWithMethodSignature: - [self methodSignatureForSelector: selector]]; - - [invocation setArgument: &self - atIndex: 0]; - [invocation setArgument: &selector - atIndex: 1]; - [invocation setArgument: &self - atIndex: 2]; - - TEST(@"-[invoke] #1", R([invocation invoke])) - - /* -[invoke] #2 */ - selector = @selector(invocationTestMethod3::::::::::::::::); - invocation = [OFInvocation invocationWithMethodSignature: - [self methodSignatureForSelector: selector]]; - - [invocation setArgument: &self - atIndex: 0]; - [invocation setArgument: &selector - atIndex: 1]; - - for (int j = 1; j <= 16; j++) - [invocation setArgument: &j - atIndex: j + 1]; - - int intResult; - TEST(@"-[invoke] #2", R([invocation invoke]) && - R([invocation getReturnValue: &intResult]) && intResult == 8) - - /* -[invoke] #3 */ - selector = @selector(invocationTestMethod4::::::::::::::::); - invocation = [OFInvocation invocationWithMethodSignature: - [self methodSignatureForSelector: selector]]; - - [invocation setArgument: &self - atIndex: 0]; - [invocation setArgument: &selector - atIndex: 1]; - - for (int j = 1; j <= 16; j++) { - double d = j; - [invocation setArgument: &d - atIndex: j + 1]; - } - - double doubleResult; - TEST(@"-[invoke] #3", R([invocation invoke]) && - R([invocation getReturnValue: &doubleResult]) && - doubleResult == 8.5) - - /* -[invoke] #4 */ - selector = @selector(invocationTestMethod5::::::::::::::::); - invocation = [OFInvocation invocationWithMethodSignature: - [self methodSignatureForSelector: selector]]; - - [invocation setArgument: &self - atIndex: 0]; - [invocation setArgument: &selector - atIndex: 1]; - - for (int j = 1; j <= 16; j++) { - float f = j; - double d = j; - - if (j == 1 || j == 10) - [invocation setArgument: &d - atIndex: j + 1]; - else - [invocation setArgument: &f - atIndex: j + 1]; - } - - float floatResult; - TEST(@"-[invoke] #4", R([invocation invoke]) && - R([invocation getReturnValue: &floatResult]) && floatResult == 8.5) - - /* Only when encoding long doubles is supported */ - if (strcmp(@encode(double), @encode(long double)) != 0) { - /* -[invoke] #5 */ - selector = @selector(invocationTestMethod6::::::::::::::::); - invocation = [OFInvocation invocationWithMethodSignature: - [self methodSignatureForSelector: selector]]; - - [invocation setArgument: &self - atIndex: 0]; - [invocation setArgument: &selector - atIndex: 1]; - - for (int j = 1; j <= 16; j++) { - long double d = j; - [invocation setArgument: &d - atIndex: j + 1]; - } - - long double longDoubleResult; - TEST(@"-[invoke] #5", R([invocation invoke]) && - R([invocation getReturnValue: &longDoubleResult]) && - longDoubleResult == 8.5) - } - -# if defined(HAVE_COMPLEX_H) && !defined(__STDC_NO_COMPLEX__) - /* -[invoke] #6 */ - selector = @selector(invocationTestMethod7::::::::::::::::); - invocation = [OFInvocation invocationWithMethodSignature: - [self methodSignatureForSelector: selector]]; - - [invocation setArgument: &self - atIndex: 0]; - [invocation setArgument: &selector - atIndex: 1]; - - for (int j = 1; j <= 16; j++) { - complex float cf = j + 0.5 * j * I; - complex double cd = j + 0.5 * j * I; - - if (j & 1) - [invocation setArgument: &cf - atIndex: j + 1]; - else - [invocation setArgument: &cd - atIndex: j + 1]; - } - - complex double complexDoubleResult; - TEST(@"-[invoke] #6", R([invocation invoke]) && - R([invocation getReturnValue: &complexDoubleResult]) && - complexDoubleResult == 8.5 + 4.25 * I) - - /* Only when encoding complex long doubles is supported */ - if (strcmp(@encode(complex double), - @encode(complex long double)) != 0) { - /* -[invoke] #7 */ - selector = @selector(invocationTestMethod8::::::::::::::::); - invocation = [OFInvocation invocationWithMethodSignature: - [self methodSignatureForSelector: selector]]; - - [invocation setArgument: &self - atIndex: 0]; - [invocation setArgument: &selector - atIndex: 1]; - - for (int j = 1; j <= 16; j++) { - complex double cd = j + 0.5 * j * I; - complex float cf = j + 0.5 * j * I; - complex long double cld = j + 0.5 * j * I; - - switch (j % 3) { - case 0: - [invocation setArgument: &cld - atIndex: j + 1]; - break; - case 1: - [invocation setArgument: &cd - atIndex: j + 1]; - break; - case 2: - [invocation setArgument: &cf - atIndex: j + 1]; - break; - } - } - - complex long double complexLongDoubleResult; - TEST(@"-[invoke] #7", R([invocation invoke]) && - R([invocation getReturnValue: &complexLongDoubleResult]) && - complexLongDoubleResult == 8.5 + 4.25 * I) - } -# endif - -# ifdef __SIZEOF_INT128__ - /* -[invoke] #8 */ - selector = @selector(invocationTestMethod9::::::::::::::::); - invocation = [OFInvocation invocationWithMethodSignature: - [self methodSignatureForSelector: selector]]; - - [invocation setArgument: &self - atIndex: 0]; - [invocation setArgument: &selector - atIndex: 1]; - - for (int j = 1; j <= 16; j++) { - __extension__ __int128 i128 = 0xFFFFFFFFFFFFFFFF; - i128 <<= 64; - i128 |= j; - - if (j == 1 || j == 5) - [invocation setArgument: &j - atIndex: j + 1]; - else - [invocation setArgument: &i128 - atIndex: j + 1]; - } - - __extension__ __int128 int128Result; - TEST(@"-[invoke] #8", R([invocation invoke]) && - R([invocation getReturnValue: &int128Result]) && - int128Result == __extension__ ((__int128)0xFFFFFFFFFFFFFFFF << 64) + - 8) -# endif -#endif + TEST(@"-[setArgument:atIndex:] #1", + R([invocation setArgument: &c atIndex: 2])) + + TEST(@"-[setArgument:atIndex:] #2", + R([invocation setArgument: &i atIndex: 3])) + + TEST(@"-[setArgument:atIndex:] #3", + R([invocation setArgument: &stp atIndex: 4])) + + TEST(@"-[setArgument:atIndex:] #4", + R([invocation setArgument: &st atIndex: 5])) + + TEST(@"-[getArgument:atIndex:] #1", + R([invocation getArgument: &c2 atIndex: 2]) && c == c2) + + TEST(@"-[getArgument:atIndex:] #2", + R([invocation getArgument: &i2 atIndex: 3]) && i == i2) + + TEST(@"-[getArgument:atIndex:] #3", + R([invocation getArgument: &stp2 atIndex: 4]) && stp == stp2) + + TEST(@"-[getArgument:atIndex:] #4", + R([invocation getArgument: &st2 atIndex: 5]) && + memcmp(&st, &st2, sizeof(st)) == 0) objc_autoreleasePoolPop(pool); } @end Index: tests/OFJSONTests.m ================================================================== --- tests/OFJSONTests.m +++ tests/OFJSONTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -17,42 +15,46 @@ #include "config.h" #import "TestsAppDelegate.h" -static OFString *module = @"OFJSON"; +static OFString *const module = @"OFJSON"; @implementation TestsAppDelegate (JSONTests) - (void)JSONTests { void *pool = objc_autoreleasePoolPush(); - OFString *s = @"{\"foo\"\t:'b\\na\\r', \"x\":/*foo*/ [.5\r,0xF,null" - @"//bar\n,\"foo\",false]}"; - OFDictionary *d = [OFDictionary dictionaryWithKeysAndObjects: + OFString *string = @"{\"foo\"\t:'b\\na\\r', \"x\":/*foo*/ [.5\r,0xF," + @"null//bar\n,\"foo\",false]}"; + OFDictionary *dict = [OFDictionary dictionaryWithKeysAndObjects: @"foo", @"b\na\r", @"x", [OFArray arrayWithObjects: - [OFNumber numberWithFloat: .5f], - [OFNumber numberWithInt: 0xF], - [OFNull null], - @"foo", - [OFNumber numberWithBool: false], - nil], + [OFNumber numberWithFloat: .5f], + [OFNumber numberWithInt: 0xF], + [OFNull null], + @"foo", + [OFNumber numberWithBool: false], + nil], nil]; - TEST(@"-[objectByParsingJSON] #1", [s.objectByParsingJSON isEqual: d]) + TEST(@"-[objectByParsingJSON] #1", + [string.objectByParsingJSON isEqual: dict]) - TEST(@"-[JSONRepresentation]", [[d JSONRepresentation] isEqual: + TEST(@"-[JSONRepresentation]", + [[dict JSONRepresentation] isEqual: @"{\"x\":[0.5,15,null,\"foo\",false],\"foo\":\"b\\na\\r\"}"]) - TEST(@"OF_JSON_REPRESENTATION_PRETTY", - [[d JSONRepresentationWithOptions: OF_JSON_REPRESENTATION_PRETTY] - isEqual: @"{\n\t\"x\": [\n\t\t0.5,\n\t\t15,\n\t\tnull,\n\t\t" - @"\"foo\",\n\t\tfalse\n\t],\n\t\"foo\": \"b\\na\\r\"\n}"]) - - TEST(@"OF_JSON_REPRESENTATION_JSON5", - [[d JSONRepresentationWithOptions: OF_JSON_REPRESENTATION_JSON5] - isEqual: @"{x:[0.5,15,null,\"foo\",false],foo:\"b\\\na\\r\"}"]) + TEST(@"OFJSONRepresentationOptionPretty", + [[dict JSONRepresentationWithOptions: + OFJSONRepresentationOptionPretty] isEqual: + @"{\n\t\"x\": [\n\t\t0.5,\n\t\t15,\n\t\tnull,\n\t\t" + @"\"foo\",\n\t\tfalse\n\t],\n\t\"foo\": \"b\\na\\r\"\n}"]) + + TEST(@"OFJSONRepresentationOptionJSON5", + [[dict JSONRepresentationWithOptions: + OFJSONRepresentationOptionJSON5] isEqual: + @"{x:[0.5,15,null,\"foo\",false],foo:\"b\\\na\\r\"}"]) EXPECT_EXCEPTION(@"-[objectByParsingJSON] #2", OFInvalidJSONException, [@"{" objectByParsingJSON]) EXPECT_EXCEPTION(@"-[objectByParsingJSON] #3", OFInvalidJSONException, [@"]" objectByParsingJSON]) Index: tests/OFKernelEventObserverTests.m ================================================================== --- tests/OFKernelEventObserverTests.m +++ tests/OFKernelEventObserverTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -30,11 +28,11 @@ # import "OFSelectKernelEventObserver.h" #endif #import "TestsAppDelegate.h" -#define EXPECTED_EVENTS 3 +static const size_t numExpectedEvents = 3; static OFString *module; @interface ObserverTest: OFObject { @@ -58,20 +56,16 @@ uint16_t port; _testsAppDelegate = testsAppDelegate; _server = [[OFTCPSocket alloc] init]; - port = [_server bindToHost: @"127.0.0.1" - port: 0]; + port = [_server bindToHost: @"127.0.0.1" port: 0]; [_server listen]; _client = [[OFTCPSocket alloc] init]; - [_client connectToHost: @"127.0.0.1" - port: port]; - - [_client writeBuffer: "0" - length: 1]; + [_client connectToHost: @"127.0.0.1" port: port]; + [_client writeBuffer: "0" length: 1]; } @catch (id e) { [self release]; @throw e; } @@ -94,11 +88,11 @@ [_testsAppDelegate outputTesting: @"-[observe] with listening socket" inModule: module]; deadline = [OFDate dateWithTimeIntervalSinceNow: 1]; - while (_events < EXPECTED_EVENTS) { + while (_events < numExpectedEvents) { if (deadline.timeIntervalSinceNow < 0) { deadlineExceeded = true; break; } @@ -114,11 +108,11 @@ outputFailure: @"-[observe] not exceeding deadline" inModule: module]; _fails++; } - if (_events == EXPECTED_EVENTS) + if (_events == numExpectedEvents) [_testsAppDelegate outputSuccess: @"-[observe] handling all events" inModule: module]; else { [_testsAppDelegate @@ -128,11 +122,11 @@ } } - (void)objectIsReadyForReading: (id)object { - char buf; + char buffer; switch (_events++) { case 0: if (object == _server) [_testsAppDelegate @@ -153,12 +147,12 @@ inModule: module]; break; case 1: if (object == _accepted && - [object readIntoBuffer: &buf - length: 1] == 1 && buf == '0') + [object readIntoBuffer: &buffer length: 1] == 1 && + buffer == '0') [_testsAppDelegate outputSuccess: @"-[observe] with data ready to read" inModule: module]; else { [_testsAppDelegate @@ -174,12 +168,11 @@ inModule: module]; break; case 2: if (object == _accepted && - [object readIntoBuffer: &buf - length: 1] == 0) + [object readIntoBuffer: &buffer length: 1] == 0) [_testsAppDelegate outputSuccess: @"-[observe] with closed connection" inModule: module]; else { [_testsAppDelegate @@ -188,11 +181,11 @@ _fails++; } break; default: - OF_ENSURE(0); + OFEnsure(0); } } @end @implementation TestsAppDelegate (OFKernelEventObserverTests) Index: tests/OFListTests.m ================================================================== --- tests/OFListTests.m +++ tests/OFListTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -17,11 +15,11 @@ #include "config.h" #import "TestsAppDelegate.h" -static OFString *module = @"OFList"; +static OFString *const module = @"OFList"; static OFString *strings[] = { @"Foo", @"Bar", @"Baz" }; @@ -30,47 +28,49 @@ - (void)listTests { void *pool = objc_autoreleasePoolPush(); OFList *list; OFEnumerator *enumerator; - of_list_object_t *loe; - OFString *obj; + OFListItem iter; + OFString *object; size_t i; bool ok; TEST(@"+[list]", (list = [OFList list])) TEST(@"-[appendObject:]", [list appendObject: strings[0]] && [list appendObject: strings[1]] && [list appendObject: strings[2]]) - TEST(@"-[firstListObject]", - [list.firstListObject->object isEqual: strings[0]]) - - TEST(@"-[firstListObject]->next", - [list.firstListObject->next->object isEqual: strings[1]]) - - TEST(@"-[lastListObject]", - [list.lastListObject->object isEqual: strings[2]]) - - TEST(@"-[lastListObject]->previous", - [list.lastListObject->previous->object isEqual: strings[1]]) - - TEST(@"-[removeListObject:]", - R([list removeListObject: list.lastListObject]) && - [list.lastListObject->object isEqual: strings[1]] && - R([list removeListObject: list.firstListObject]) && - [list.firstListObject->object isEqual: list.lastListObject->object]) - - TEST(@"-[insertObject:beforeListObject:]", - [list insertObject: strings[0] - beforeListObject: list.lastListObject] && - [list.lastListObject->previous->object isEqual: strings[0]]) - - TEST(@"-[insertObject:afterListObject:]", + TEST(@"-[firstListItem]", + [OFListItemObject(list.firstListItem) isEqual: strings[0]]) + + TEST(@"OFListItemNext()", + [OFListItemObject(OFListItemNext(list.firstListItem)) + isEqual: strings[1]]) + + TEST(@"-[lastListItem]", + [OFListItemObject(list.lastListItem) isEqual: strings[2]]) + + TEST(@"OFListItemPrevious()", + [OFListItemObject(OFListItemPrevious(list.lastListItem)) + isEqual: strings[1]]) + + TEST(@"-[removeListItem:]", + R([list removeListItem: list.lastListItem]) && + [list.lastObject isEqual: strings[1]] && + R([list removeListItem: list.firstListItem]) && + [list.firstObject isEqual: list.lastObject]) + + TEST(@"-[insertObject:beforeListItem:]", + [list insertObject: strings[0] beforeListItem: list.lastListItem] && + [OFListItemObject(OFListItemPrevious(list.lastListItem)) + isEqual: strings[0]]) + + TEST(@"-[insertObject:afterListItem:]", [list insertObject: strings[2] - afterListObject: list.firstListObject->next] && - [list.lastListObject->object isEqual: strings[2]]) + afterListItem: OFListItemNext(list.firstListItem)] && + [list.lastObject isEqual: strings[2]]) TEST(@"-[count]", list.count == 3) TEST(@"-[containsObject:]", [list containsObject: strings[1]] && @@ -80,53 +80,54 @@ [list containsObjectIdenticalTo: strings[1]] && ![list containsObjectIdenticalTo: [OFString stringWithString: strings[1]]]) TEST(@"-[copy]", (list = [[list copy] autorelease]) && - [list.firstListObject->object isEqual: strings[0]] && - [list.firstListObject->next->object isEqual: strings[1]] && - [list.lastListObject->object isEqual: strings[2]]) + [list.firstObject isEqual: strings[0]] && + [OFListItemObject(OFListItemNext(list.firstListItem)) + isEqual: strings[1]] && + [list.lastObject isEqual: strings[2]]) TEST(@"-[isEqual:]", [list isEqual: [[list copy] autorelease]]) TEST(@"-[description]", [list.description isEqual: @"[\n\tFoo,\n\tBar,\n\tBaz\n]"]) TEST(@"-[objectEnumerator]", (enumerator = [list objectEnumerator])) - loe = list.firstListObject; + iter = list.firstListItem; i = 0; ok = true; - while ((obj = [enumerator nextObject]) != nil) { - if (![obj isEqual: loe->object]) + while ((object = [enumerator nextObject]) != nil) { + if (![object isEqual: OFListItemObject(iter)]) ok = false; - loe = loe->next; + iter = OFListItemNext(iter); i++; } if (list.count != i) ok = false; TEST(@"OFEnumerator's -[nextObject]", ok); - [list removeListObject: list.firstListObject]; + [list removeListItem: list.firstListItem]; EXPECT_EXCEPTION(@"Detection of mutation during enumeration", OFEnumerationMutationException, [enumerator nextObject]) [list prependObject: strings[0]]; - loe = list.firstListObject; + iter = list.firstListItem; i = 0; ok = true; - for (OFString *object in list) { - if (![object isEqual: loe->object]) + for (OFString *object_ in list) { + if (![object_ isEqual: OFListItemObject(iter)]) ok = false; - loe = loe->next; + iter = OFListItemNext(iter); i++; } if (list.count != i) ok = false; @@ -133,14 +134,14 @@ TEST(@"Fast Enumeration", ok) ok = false; @try { - for (OFString *object in list) { - (void)object; + for (OFString *object_ in list) { + (void)object_; - [list removeListObject: list.lastListObject]; + [list removeListItem: list.lastListItem]; } } @catch (OFEnumerationMutationException *e) { ok = true; } Index: tests/OFLocaleTests.m ================================================================== --- tests/OFLocaleTests.m +++ tests/OFLocaleTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -22,22 +20,22 @@ @implementation TestsAppDelegate (OFLocaleTests) - (void)localeTests { void *pool = objc_autoreleasePoolPush(); - [of_stdout setForegroundColor: [OFColor lime]]; + [OFStdOut setForegroundColor: [OFColor lime]]; - [of_stdout writeFormat: @"[OFLocale] Language: %@\n", + [OFStdOut writeFormat: @"[OFLocale] Language: %@\n", [OFLocale language]]; - [of_stdout writeFormat: @"[OFLocale] Territory: %@\n", + [OFStdOut writeFormat: @"[OFLocale] Territory: %@\n", [OFLocale territory]]; - [of_stdout writeFormat: @"[OFLocale] Encoding: %@\n", - of_string_name_of_encoding([OFLocale encoding])]; + [OFStdOut writeFormat: @"[OFLocale] Encoding: %@\n", + OFStringEncodingName([OFLocale encoding])]; - [of_stdout writeFormat: @"[OFLocale] Decimal point: %@\n", + [OFStdOut writeFormat: @"[OFLocale] Decimal point: %@\n", [OFLocale decimalPoint]]; objc_autoreleasePoolPop(pool); } @end Index: tests/OFMD5HashTests.m ================================================================== --- tests/OFMD5HashTests.m +++ tests/OFMD5HashTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -19,44 +17,42 @@ #include #import "TestsAppDelegate.h" -static OFString *module = @"OFMD5Hash"; +static OFString *const module = @"OFMD5Hash"; -const uint8_t testfile_md5[16] = - "\x00\x8B\x9D\x1B\x58\xDF\xF8\xFE\xEE\xF3\xAE\x8D\xBB\x68\x2D\x38"; +const uint8_t testFileMD5[16] = + "\x00\x8B\x9D\x1B\x58\xDF\xF8\xFE\xEE\xF3\xAE\x8D\xBB\x68\x2D\x38"; @implementation TestsAppDelegate (OFMD5HashTests) - (void)MD5HashTests { void *pool = objc_autoreleasePoolPush(); - OFMD5Hash *md5, *copy; - OFFile *f = [OFFile fileWithPath: @"testfile.bin" - mode: @"r"]; - - TEST(@"+[cryptoHashWithAllowsSwappableMemory:]", - (md5 = [OFMD5Hash cryptoHashWithAllowsSwappableMemory: true])) - - while (!f.atEndOfStream) { - char buf[64]; - size_t len = [f readIntoBuffer: buf - length: 64]; - [md5 updateWithBuffer: buf - length: len]; - } - [f close]; - - TEST(@"-[copy]", (copy = [[md5 copy] autorelease])) + OFMD5Hash *MD5, *MD5Copy; + OFFile *file = [OFFile fileWithPath: @"testfile.bin" mode: @"r"]; + + TEST(@"+[hashWithAllowsSwappableMemory:]", + (MD5 = [OFMD5Hash hashWithAllowsSwappableMemory: true])) + + while (!file.atEndOfStream) { + char buffer[64]; + size_t length = [file readIntoBuffer: buffer length: 64]; + [MD5 updateWithBuffer: buffer length: length]; + } + [file close]; + + TEST(@"-[copy]", (MD5Copy = [[MD5 copy] autorelease])) + + TEST(@"-[calculate]", R([MD5 calculate]) && R([MD5Copy calculate])) TEST(@"-[digest]", - memcmp(md5.digest, testfile_md5, 16) == 0 && - memcmp(copy.digest, testfile_md5, 16) == 0) + memcmp(MD5.digest, testFileMD5, 16) == 0 && + memcmp(MD5Copy.digest, testFileMD5, 16) == 0) EXPECT_EXCEPTION(@"Detect invalid call of " @"-[updateWithBuffer:length]", OFHashAlreadyCalculatedException, - [md5 updateWithBuffer: "" - length: 1]) + [MD5 updateWithBuffer: "" length: 1]) objc_autoreleasePoolPop(pool); } @end Index: tests/OFMethodSignatureTests.m ================================================================== --- tests/OFMethodSignatureTests.m +++ tests/OFMethodSignatureTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -23,19 +21,19 @@ # include #endif #import "TestsAppDelegate.h" -static OFString *module = @"OFMethodSignature"; +static OFString *const module = @"OFMethodSignature"; -struct test1_struct { +struct Test1Struct { char c; int i; char d; }; -struct test2_struct { +struct Test2Struct { char c; struct { short s; int i; } st; @@ -45,23 +43,23 @@ } u; double d; }; #if !defined(__STDC_NO_COMPLEX__) && defined(HAVE_COMPLEX_H) -struct test3_struct { +struct Test3Struct { char c; complex double cd; }; #endif -union test3_union { +union Test3Union { char c; int i; double d; }; -union test4_union { +union Test4Union { char c; struct { short x, y; } st; int i; @@ -73,38 +71,42 @@ @implementation TestsAppDelegate (OFMethodSignatureTests) - (void)methodSignatureTests { void *pool = objc_autoreleasePoolPush(); - OFMethodSignature *ms; + OFMethodSignature *methodSignature; TEST(@"-[signatureWithObjCTypes:] #1", - (ms = [OFMethodSignature signatureWithObjCTypes: - "i28@0:8S16*20"]) && ms.numberOfArguments == 4 && - strcmp(ms.methodReturnType, "i") == 0 && - strcmp([ms argumentTypeAtIndex: 0], "@") == 0 && - strcmp([ms argumentTypeAtIndex: 1], ":") == 0 && - strcmp([ms argumentTypeAtIndex: 2], "S") == 0 && - strcmp([ms argumentTypeAtIndex: 3], "*") == 0 && - ms.frameLength == 28 && [ms argumentOffsetAtIndex: 0] == 0 && - [ms argumentOffsetAtIndex: 1] == 8 && - [ms argumentOffsetAtIndex: 2] == 16 && - [ms argumentOffsetAtIndex: 3] == 20) + (methodSignature = [OFMethodSignature signatureWithObjCTypes: + "i28@0:8S16*20"]) && + methodSignature.numberOfArguments == 4 && + strcmp(methodSignature.methodReturnType, "i") == 0 && + strcmp([methodSignature argumentTypeAtIndex: 0], "@") == 0 && + strcmp([methodSignature argumentTypeAtIndex: 1], ":") == 0 && + strcmp([methodSignature argumentTypeAtIndex: 2], "S") == 0 && + strcmp([methodSignature argumentTypeAtIndex: 3], "*") == 0 && + methodSignature.frameLength == 28 && + [methodSignature argumentOffsetAtIndex: 0] == 0 && + [methodSignature argumentOffsetAtIndex: 1] == 8 && + [methodSignature argumentOffsetAtIndex: 2] == 16 && + [methodSignature argumentOffsetAtIndex: 3] == 20) TEST(@"-[signatureWithObjCTypes:] #2", - (ms = [OFMethodSignature signatureWithObjCTypes: + (methodSignature = [OFMethodSignature signatureWithObjCTypes: "{s0=csi(u1={s2=iii{s3=(u4=ic^v*)}})}24@0:8" "^{s0=csi(u1={s2=iii{s3=(u4=ic^v*)}})}16"]) && - ms.numberOfArguments == 3 && strcmp(ms.methodReturnType, + methodSignature.numberOfArguments == 3 && + strcmp(methodSignature.methodReturnType, "{s0=csi(u1={s2=iii{s3=(u4=ic^v*)}})}") == 0 && - strcmp([ms argumentTypeAtIndex: 0], "@") == 0 && - strcmp([ms argumentTypeAtIndex: 1], ":") == 0 && - strcmp([ms argumentTypeAtIndex: 2], + strcmp([methodSignature argumentTypeAtIndex: 0], "@") == 0 && + strcmp([methodSignature argumentTypeAtIndex: 1], ":") == 0 && + strcmp([methodSignature argumentTypeAtIndex: 2], "^{s0=csi(u1={s2=iii{s3=(u4=ic^v*)}})}") == 0 && - ms.frameLength == 24 && [ms argumentOffsetAtIndex: 0] == 0 && - [ms argumentOffsetAtIndex: 1] == 8 && - [ms argumentOffsetAtIndex: 2] == 16) + methodSignature.frameLength == 24 && + [methodSignature argumentOffsetAtIndex: 0] == 0 && + [methodSignature argumentOffsetAtIndex: 1] == 8 && + [methodSignature argumentOffsetAtIndex: 2] == 16) EXPECT_EXCEPTION(@"-[signatureWithObjCTypes:] #3", OFInvalidFormatException, [OFMethodSignature signatureWithObjCTypes: "{ii"]) @@ -118,62 +120,62 @@ EXPECT_EXCEPTION(@"-[signatureWithObjCTypes:] #6", OFInvalidFormatException, [OFMethodSignature signatureWithObjCTypes: "{{}0"]) - TEST(@"of_sizeof_type_encoding() #1", - of_sizeof_type_encoding(@encode(struct test1_struct)) == - sizeof(struct test1_struct)) - - TEST(@"of_sizeof_type_encoding() #2", - of_sizeof_type_encoding(@encode(struct test2_struct)) == - sizeof(struct test2_struct)) - -#if !defined(__STDC_NO_COMPLEX__) && defined(HAVE_COMPLEX_H) && \ - OF_GCC_VERSION >= 402 - TEST(@"of_sizeof_type_encoding() #3", - of_sizeof_type_encoding(@encode(struct test3_struct)) == - sizeof(struct test3_struct)) -#endif - - TEST(@"of_sizeof_type_encoding() #4", - of_sizeof_type_encoding(@encode(union test3_union)) == - sizeof(union test3_union)) - - TEST(@"of_sizeof_type_encoding() #5", - of_sizeof_type_encoding(@encode(union test4_union)) == - sizeof(union test4_union)) - - TEST(@"of_sizeof_type_encoding() #6", - of_sizeof_type_encoding(@encode(struct test1_struct [5])) == - sizeof(struct test1_struct [5])) - - TEST(@"of_alignof_type_encoding() #1", - of_alignof_type_encoding(@encode(struct test1_struct)) == - OF_ALIGNOF(struct test1_struct)) - - TEST(@"of_alignof_type_encoding() #2", - of_alignof_type_encoding(@encode(struct test2_struct)) == - OF_ALIGNOF(struct test2_struct)) - -#if !defined(__STDC_NO_COMPLEX__) && defined(HAVE_COMPLEX_H) && \ - OF_GCC_VERSION >= 402 - TEST(@"of_alignof_type_encoding() #3", - of_alignof_type_encoding(@encode(struct test3_struct)) == - OF_ALIGNOF(struct test3_struct)) -#endif - - TEST(@"of_alignof_type_encoding() #4", - of_alignof_type_encoding(@encode(union test3_union)) == - OF_ALIGNOF(union test3_union)) - - TEST(@"of_alignof_type_encoding() #5", - of_alignof_type_encoding(@encode(union test4_union)) == - OF_ALIGNOF(union test4_union)) - - TEST(@"of_alignof_type_encoding() #6", - of_alignof_type_encoding(@encode(struct test1_struct [5])) == - OF_ALIGNOF(struct test1_struct [5])) + TEST(@"OFSizeOfTypeEncoding() #1", + OFSizeOfTypeEncoding(@encode(struct Test1Struct)) == + sizeof(struct Test1Struct)) + + TEST(@"OFSizeOfTypeEncoding() #2", + OFSizeOfTypeEncoding(@encode(struct Test2Struct)) == + sizeof(struct Test2Struct)) + +#if !defined(__STDC_NO_COMPLEX__) && defined(HAVE_COMPLEX_H) && \ + OF_GCC_VERSION >= 402 + TEST(@"OFSizeOfTypeEncoding() #3", + OFSizeOfTypeEncoding(@encode(struct Test3Struct)) == + sizeof(struct Test3Struct)) +#endif + + TEST(@"OFSizeOfTypeEncoding() #4", + OFSizeOfTypeEncoding(@encode(union Test3Union)) == + sizeof(union Test3Union)) + + TEST(@"OFSizeOfTypeEncoding() #5", + OFSizeOfTypeEncoding(@encode(union Test4Union)) == + sizeof(union Test4Union)) + + TEST(@"OFSizeOfTypeEncoding() #6", + OFSizeOfTypeEncoding(@encode(struct Test1Struct [5])) == + sizeof(struct Test1Struct [5])) + + TEST(@"OFAlignmentOfTypeEncoding() #1", + OFAlignmentOfTypeEncoding(@encode(struct Test1Struct)) == + OF_ALIGNOF(struct Test1Struct)) + + TEST(@"OFAlignmentOfTypeEncoding() #2", + OFAlignmentOfTypeEncoding(@encode(struct Test2Struct)) == + OF_ALIGNOF(struct Test2Struct)) + +#if !defined(__STDC_NO_COMPLEX__) && defined(HAVE_COMPLEX_H) && \ + OF_GCC_VERSION >= 402 + TEST(@"OFAlignmentOfTypeEncoding() #3", + OFAlignmentOfTypeEncoding(@encode(struct Test3Struct)) == + OF_ALIGNOF(struct Test3Struct)) +#endif + + TEST(@"OFAlignmentOfTypeEncoding() #4", + OFAlignmentOfTypeEncoding(@encode(union Test3Union)) == + OF_ALIGNOF(union Test3Union)) + + TEST(@"OFAlignmentOfTypeEncoding() #5", + OFAlignmentOfTypeEncoding(@encode(union Test4Union)) == + OF_ALIGNOF(union Test4Union)) + + TEST(@"OFAlignmentOfTypeEncoding() #6", + OFAlignmentOfTypeEncoding(@encode(struct Test1Struct [5])) == + OF_ALIGNOF(struct Test1Struct [5])) objc_autoreleasePoolPop(pool); } @end ADDED tests/OFNotificationCenterTests.m Index: tests/OFNotificationCenterTests.m ================================================================== --- /dev/null +++ tests/OFNotificationCenterTests.m @@ -0,0 +1,159 @@ +/* + * 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 = @"OFNotificationCenter"; +static const OFNotificationName notificationName = + @"OFNotificationCenterTestName"; +static const OFNotificationName otherNotificationName = + @"OFNotificationCenterTestOtherName"; + +@interface OFNotificationCenterTest: OFObject +{ +@public + id _expectedObject; + int _received; +} + +- (void)handleNotification: (OFNotification *)notification; +@end + +@implementation OFNotificationCenterTest +- (void)handleNotification: (OFNotification *)notification +{ + OFEnsure([notification.name isEqual: notificationName]); + OFEnsure(_expectedObject == nil || + notification.object == _expectedObject); + + _received++; +} +@end + +@implementation TestsAppDelegate (OFNotificationCenterTests) +- (void)notificationCenterTests +{ + void *pool = objc_autoreleasePoolPush(); + OFNotificationCenter *center = [OFNotificationCenter defaultCenter]; + OFNotificationCenterTest *test1, *test2, *test3, *test4; + OFNotification *notification; + + test1 = + [[[OFNotificationCenterTest alloc] init] autorelease]; + test1->_expectedObject = self; + test2 = + [[[OFNotificationCenterTest alloc] init] autorelease]; + test3 = + [[[OFNotificationCenterTest alloc] init] autorelease]; + test3->_expectedObject = self; + test4 = + [[[OFNotificationCenterTest alloc] init] autorelease]; + + /* First one intentionally added twice to test deduplication. */ + TEST(@"-[addObserver:selector:name:object:]", + R([center addObserver: test1 + selector: @selector(handleNotification:) + name: notificationName + object: self]) && + R([center addObserver: test1 + selector: @selector(handleNotification:) + name: notificationName + object: self]) && + R([center addObserver: test2 + selector: @selector(handleNotification:) + name: notificationName + object: nil]) && + R([center addObserver: test3 + selector: @selector(handleNotification:) + name: otherNotificationName + object: self]) && + R([center addObserver: test4 + selector: @selector(handleNotification:) + name: otherNotificationName + object: nil])) + + notification = [OFNotification notificationWithName: notificationName + object: nil]; + TEST(@"-[postNotification:] #1", + R([center postNotification: notification]) && + test1->_received == 0 && test2->_received == 1 && + test3->_received == 0 && test4->_received == 0) + + notification = [OFNotification notificationWithName: notificationName + object: self]; + TEST(@"-[postNotification:] #2", + R([center postNotification: notification]) && + test1->_received == 1 && test2->_received == 2 && + test3->_received == 0 && test4->_received == 0) + + notification = [OFNotification notificationWithName: notificationName + object: @"foo"]; + TEST(@"-[postNotification:] #3", + R([center postNotification: notification]) && + test1->_received == 1 && test2->_received == 3 && + test3->_received == 0 && test4->_received == 0) + +#ifdef OF_HAVE_BLOCKS + __block bool received = false; + OFNotificationCenterHandle *handle; + + notification = [OFNotification notificationWithName: notificationName + object: self]; + TEST(@"-[addObserverForName:object:usingBlock:]", + (handle = [center addObserverForName: notificationName + object: self + usingBlock: ^ (OFNotification *notif) { + OFEnsure(notif == notification && !received); + received = true; + }]) && R([center postNotification: notification]) && received && + test1->_received == 2 && test2->_received == 4 && + test3->_received == 0 && test4->_received == 0) + + /* Act like the block test didn't happen. */ + [center removeObserver: handle]; + test1->_received--; + test2->_received--; +#endif + + TEST(@"-[removeObserver:selector:name:object:]", + R([center removeObserver: test1 + selector: @selector(handleNotification:) + name: notificationName + object: self]) && + R([center removeObserver: test2 + selector: @selector(handleNotification:) + name: notificationName + object: nil]) && + R([center removeObserver: test3 + selector: @selector(handleNotification:) + name: otherNotificationName + object: self]) && + R([center removeObserver: test4 + selector: @selector(handleNotification:) + name: otherNotificationName + object: nil])) + + notification = [OFNotification notificationWithName: notificationName + object: self]; + TEST(@"-[postNotification:] with no observers", + R([center postNotification: notification]) && + test1->_received == 1 && test2->_received == 3 && + test3->_received == 0 && test4->_received == 0) + + objc_autoreleasePoolPop(pool); +} +@end Index: tests/OFNumberTests.m ================================================================== --- tests/OFNumberTests.m +++ tests/OFNumberTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -17,78 +15,78 @@ #include "config.h" #import "TestsAppDelegate.h" -static OFString *module = @"OFNumber"; +static OFString *const module = @"OFNumber"; @implementation TestsAppDelegate (OFNumberTests) - (void)numberTests { void *pool = objc_autoreleasePoolPush(); - OFNumber *num; + OFNumber *number; TEST(@"+[numberWithLongLong:]", - (num = [OFNumber numberWithLongLong: 123456789])) + (number = [OFNumber numberWithLongLong: 123456789])) TEST(@"-[isEqual:]", - [num isEqual: [OFNumber numberWithLong: 123456789]]) + [number isEqual: [OFNumber numberWithLong: 123456789]]) + + TEST(@"-[hash]", number.hash == 0x82D8BC42) - TEST(@"-[hash]", num.hash == 0x82D8BC42) + TEST(@"-[charValue]", number.charValue == 21) - TEST(@"-[charValue]", num.charValue == 21) - - TEST(@"-[doubleValue]", num.doubleValue == 123456789.L) + TEST(@"-[doubleValue]", number.doubleValue == 123456789.L) TEST(@"signed char minimum & maximum unmodified", - (num = [OFNumber numberWithChar: SCHAR_MIN]) && - num.charValue == SCHAR_MIN && - (num = [OFNumber numberWithChar: SCHAR_MAX]) && - num.charValue == SCHAR_MAX) + (number = [OFNumber numberWithChar: SCHAR_MIN]) && + number.charValue == SCHAR_MIN && + (number = [OFNumber numberWithChar: SCHAR_MAX]) && + number.charValue == SCHAR_MAX) TEST(@"short minimum & maximum unmodified", - (num = [OFNumber numberWithShort: SHRT_MIN]) && - num.shortValue == SHRT_MIN && - (num = [OFNumber numberWithShort: SHRT_MAX]) && - num.shortValue == SHRT_MAX) + (number = [OFNumber numberWithShort: SHRT_MIN]) && + number.shortValue == SHRT_MIN && + (number = [OFNumber numberWithShort: SHRT_MAX]) && + number.shortValue == SHRT_MAX) TEST(@"int minimum & maximum unmodified", - (num = [OFNumber numberWithInt: INT_MIN]) && - num.intValue == INT_MIN && - (num = [OFNumber numberWithInt: INT_MAX]) && - num.intValue == INT_MAX) + (number = [OFNumber numberWithInt: INT_MIN]) && + number.intValue == INT_MIN && + (number = [OFNumber numberWithInt: INT_MAX]) && + number.intValue == INT_MAX) TEST(@"long minimum & maximum unmodified", - (num = [OFNumber numberWithLong: LONG_MIN]) && - num.longValue == LONG_MIN && - (num = [OFNumber numberWithLong: LONG_MAX]) && - num.longValue == LONG_MAX) + (number = [OFNumber numberWithLong: LONG_MIN]) && + number.longValue == LONG_MIN && + (number = [OFNumber numberWithLong: LONG_MAX]) && + number.longValue == LONG_MAX) TEST(@"long long minimum & maximum unmodified", - (num = [OFNumber numberWithLongLong: LLONG_MIN]) && - num.longLongValue == LLONG_MIN && - (num = [OFNumber numberWithLongLong: LLONG_MAX]) && - num.longLongValue == LLONG_MAX) + (number = [OFNumber numberWithLongLong: LLONG_MIN]) && + number.longLongValue == LLONG_MIN && + (number = [OFNumber numberWithLongLong: LLONG_MAX]) && + number.longLongValue == LLONG_MAX) TEST(@"unsigned char maximum unmodified", - (num = [OFNumber numberWithUnsignedChar: UCHAR_MAX]) && - num.unsignedCharValue == UCHAR_MAX) + (number = [OFNumber numberWithUnsignedChar: UCHAR_MAX]) && + number.unsignedCharValue == UCHAR_MAX) TEST(@"unsigned short maximum unmodified", - (num = [OFNumber numberWithUnsignedShort: USHRT_MAX]) && - num.unsignedShortValue == USHRT_MAX) + (number = [OFNumber numberWithUnsignedShort: USHRT_MAX]) && + number.unsignedShortValue == USHRT_MAX) TEST(@"unsigned int maximum unmodified", - (num = [OFNumber numberWithUnsignedInt: UINT_MAX]) && - num.unsignedIntValue == UINT_MAX) + (number = [OFNumber numberWithUnsignedInt: UINT_MAX]) && + number.unsignedIntValue == UINT_MAX) TEST(@"unsigned long maximum unmodified", - (num = [OFNumber numberWithUnsignedLong: ULONG_MAX]) && - num.unsignedLongValue == ULONG_MAX) + (number = [OFNumber numberWithUnsignedLong: ULONG_MAX]) && + number.unsignedLongValue == ULONG_MAX) TEST(@"unsigned long long maximum unmodified", - (num = [OFNumber numberWithUnsignedLongLong: ULLONG_MAX]) && - num.unsignedLongLongValue == ULLONG_MAX) + (number = [OFNumber numberWithUnsignedLongLong: ULLONG_MAX]) && + number.unsignedLongLongValue == ULLONG_MAX) objc_autoreleasePoolPop(pool); } @end Index: tests/OFObjectTests.m ================================================================== --- tests/OFObjectTests.m +++ tests/OFObjectTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -23,13 +21,13 @@ # define TOO_BIG (SIZE_MAX / 3) #else # define TOO_BIG (SIZE_MAX - 128) #endif -static OFString *module = @"OFObject"; +static OFString *const module = @"OFObject"; -@interface MyObj: OFObject +@interface MyObject: OFObject { id _objectValue; Class _classValue; bool _boolValue; char _charValue; @@ -61,11 +59,11 @@ @property (nonatomic) unsigned long long unsignedLongLongValue; @property (nonatomic) float floatValue; @property (nonatomic) double doubleValue; @end -@implementation MyObj +@implementation MyObject @synthesize objectValue = _objectValue, classValue = _classValue; @synthesize boolValue = _boolValue, charValue = _charValue; @synthesize shortValue = _shortValue, intValue = _intValue; @synthesize longValue = _longValue, longLongValue = _longLongValue; @synthesize unsignedCharValue = _unsignedCharValue; @@ -85,178 +83,139 @@ @implementation TestsAppDelegate (OFObjectTests) - (void)objectTests { void *pool = objc_autoreleasePoolPush(); - OFObject *obj = [[[OFObject alloc] init] autorelease]; - void *p, *q, *r; - OFObject *o; - MyObj *m; - char *tmp; - - TEST(@"Allocating 4096 bytes", - (p = [obj allocMemoryWithSize: 4096]) != NULL) - - TEST(@"Freeing memory", R([obj freeMemory: p])) - - TEST(@"Allocating and freeing 4096 bytes 3 times", - (p = [obj allocMemoryWithSize: 4096]) != NULL && - (q = [obj allocMemoryWithSize: 4096]) != NULL && - (r = [obj allocMemoryWithSize: 4096]) != NULL && - R([obj freeMemory: p]) && R([obj freeMemory: q]) && - R([obj freeMemory: r])) - - tmp = [self allocMemoryWithSize: 1024]; - EXPECT_EXCEPTION(@"Detect freeing of memory not allocated by object", - OFMemoryNotPartOfObjectException, [obj freeMemory: tmp]) - - EXPECT_EXCEPTION(@"Detect out of memory on alloc", - OFOutOfMemoryException, tmp = [obj allocMemoryWithSize: TOO_BIG]) - - EXPECT_EXCEPTION(@"Detect out of memory on resize", - OFOutOfMemoryException, - { - p = [obj allocMemoryWithSize: 1]; - p = [obj resizeMemory: p - size: TOO_BIG]; - }) - [obj freeMemory: p]; - - TEST(@"Allocate when trying to resize NULL", - (p = [obj resizeMemory: NULL - size: 1024]) != NULL) - [obj freeMemory: p]; - - EXPECT_EXCEPTION(@"Detect resizing of memory not allocated by object", - OFMemoryNotPartOfObjectException, tmp = [obj resizeMemory: tmp - size: 2048]) - [self freeMemory: tmp]; + OFObject *object; + MyObject *myObject; TEST(@"+[description]", [[OFObject description] isEqual: @"OFObject"] && - [[MyObj description] isEqual: @"MyObj"]) + [[MyObject description] isEqual: @"MyObject"]) - o = [[[OFObject alloc] init] autorelease]; - m = [[[MyObj alloc] init] autorelease]; + object = [[[OFObject alloc] init] autorelease]; + myObject = [[[MyObject alloc] init] autorelease]; TEST(@"-[description]", - [o.description isEqual: @""] && - [m.description isEqual: @""]) + [object.description isEqual: @""] && + [myObject.description isEqual: @""]) - m.objectValue = @"Hello"; - m.classValue = [m class]; + myObject.objectValue = @"Hello"; + myObject.classValue = myObject.class; TEST(@"-[valueForKey:]", - [[m valueForKey: @"objectValue"] isEqual: @"Hello"] && - [[m valueForKey: @"classValue"] isEqual: m.class] && - [[m valueForKey: @"class"] isEqual: m.class]) + [[myObject valueForKey: @"objectValue"] isEqual: @"Hello"] && + [[myObject valueForKey: @"classValue"] isEqual: myObject.class] && + [[myObject valueForKey: @"class"] isEqual: myObject.class]) EXPECT_EXCEPTION(@"-[valueForKey:] with undefined key", - OFUndefinedKeyException, [m valueForKey: @"undefined"]) + OFUndefinedKeyException, [myObject valueForKey: @"undefined"]) TEST(@"-[setValue:forKey:]", - R([m setValue: @"World" - forKey: @"objectValue"]) && - R([m setValue: [OFObject class] - forKey: @"classValue"]) && - [m.objectValue isEqual: @"World"] && - [m.classValue isEqual: [OFObject class]]) + R([myObject setValue: @"World" forKey: @"objectValue"]) && + R([myObject setValue: [OFObject class] forKey: @"classValue"]) && + [myObject.objectValue isEqual: @"World"] && + [myObject.classValue isEqual: [OFObject class]]) EXPECT_EXCEPTION(@"-[setValue:forKey:] with undefined key", - OFUndefinedKeyException, [m setValue: @"x" - forKey: @"undefined"]) - - m.boolValue = 1; - m.charValue = 2; - m.shortValue = 3; - m.intValue = 4; - m.longValue = 5; - m.longLongValue = 6; - m.unsignedCharValue = 7; - m.unsignedShortValue = 8; - m.unsignedIntValue = 9; - m.unsignedLongValue = 10; - m.unsignedLongLongValue = 11; - m.floatValue = 12; - m.doubleValue = 13; + OFUndefinedKeyException, + [myObject setValue: @"x" forKey: @"undefined"]) + + myObject.boolValue = 1; + myObject.charValue = 2; + myObject.shortValue = 3; + myObject.intValue = 4; + myObject.longValue = 5; + myObject.longLongValue = 6; + myObject.unsignedCharValue = 7; + myObject.unsignedShortValue = 8; + myObject.unsignedIntValue = 9; + myObject.unsignedLongValue = 10; + myObject.unsignedLongLongValue = 11; + myObject.floatValue = 12; + myObject.doubleValue = 13; TEST(@"Auto-wrapping of -[valueForKey:]", - [[m valueForKey: @"boolValue"] isEqual: + [[myObject valueForKey: @"boolValue"] isEqual: [OFNumber numberWithBool: 1]] && - [[m valueForKey: @"charValue"] isEqual: + [[myObject valueForKey: @"charValue"] isEqual: [OFNumber numberWithChar: 2]] && - [[m valueForKey: @"shortValue"] isEqual: + [[myObject valueForKey: @"shortValue"] isEqual: [OFNumber numberWithShort: 3]] && - [[m valueForKey: @"intValue"] isEqual: + [[myObject valueForKey: @"intValue"] isEqual: [OFNumber numberWithInt: 4]] && - [[m valueForKey: @"longValue"] isEqual: + [[myObject valueForKey: @"longValue"] isEqual: [OFNumber numberWithLong: 5]] && - [[m valueForKey: @"longLongValue"] isEqual: + [[myObject valueForKey: @"longLongValue"] isEqual: [OFNumber numberWithLongLong: 6]] && - [[m valueForKey: @"unsignedCharValue"] isEqual: + [[myObject valueForKey: @"unsignedCharValue"] isEqual: [OFNumber numberWithUnsignedChar: 7]] && - [[m valueForKey: @"unsignedShortValue"] isEqual: + [[myObject valueForKey: @"unsignedShortValue"] isEqual: [OFNumber numberWithUnsignedShort: 8]] && - [[m valueForKey: @"unsignedIntValue"] isEqual: + [[myObject valueForKey: @"unsignedIntValue"] isEqual: [OFNumber numberWithUnsignedInt: 9]] && - [[m valueForKey: @"unsignedLongValue"] isEqual: + [[myObject valueForKey: @"unsignedLongValue"] isEqual: [OFNumber numberWithUnsignedLong: 10]] && - [[m valueForKey: @"unsignedLongLongValue"] isEqual: + [[myObject valueForKey: @"unsignedLongLongValue"] isEqual: [OFNumber numberWithUnsignedLongLong: 11]] && - [[m valueForKey: @"floatValue"] isEqual: + [[myObject valueForKey: @"floatValue"] isEqual: [OFNumber numberWithFloat: 12]] && - [[m valueForKey: @"doubleValue"] isEqual: + [[myObject valueForKey: @"doubleValue"] isEqual: [OFNumber numberWithDouble: 13]]) TEST(@"Auto-wrapping of -[setValue:forKey:]", - R([m setValue: [OFNumber numberWithBool: 0] - forKey: @"boolValue"]) && - R([m setValue: [OFNumber numberWithChar: 10] - forKey: @"charValue"]) && - R([m setValue: [OFNumber numberWithShort: 20] - forKey: @"shortValue"]) && - R([m setValue: [OFNumber numberWithInt: 30] - forKey: @"intValue"]) && - R([m setValue: [OFNumber numberWithLong: 40] - forKey: @"longValue"]) && - R([m setValue: [OFNumber numberWithLongLong: 50] - forKey: @"longLongValue"]) && - R([m setValue: [OFNumber numberWithUnsignedChar: 60] - forKey: @"unsignedCharValue"]) && - R([m setValue: [OFNumber numberWithUnsignedShort: 70] - forKey: @"unsignedShortValue"]) && - R([m setValue: [OFNumber numberWithUnsignedInt: 80] - forKey: @"unsignedIntValue"]) && - R([m setValue: [OFNumber numberWithUnsignedLong: 90] - forKey: @"unsignedLongValue"]) && - R([m setValue: [OFNumber numberWithUnsignedLongLong: 100] - forKey: @"unsignedLongLongValue"]) && - R([m setValue: [OFNumber numberWithFloat: 110] - forKey: @"floatValue"]) && - R([m setValue: [OFNumber numberWithDouble: 120] - forKey: @"doubleValue"]) && - m.isBoolValue == 0 && m.charValue == 10 && m.shortValue == 20 && - m.intValue == 30 && m.longValue == 40 && m.longLongValue == 50 && - m.unsignedCharValue == 60 && m.unsignedShortValue == 70 && - m.unsignedIntValue == 80 && m.unsignedLongValue == 90 && - m.unsignedLongLongValue == 100 && m.floatValue == 110 && - m.doubleValue == 120) + R([myObject setValue: [OFNumber numberWithBool: 0] + forKey: @"boolValue"]) && + R([myObject setValue: [OFNumber numberWithChar: 10] + forKey: @"charValue"]) && + R([myObject setValue: [OFNumber numberWithShort: 20] + forKey: @"shortValue"]) && + R([myObject setValue: [OFNumber numberWithInt: 30] + forKey: @"intValue"]) && + R([myObject setValue: [OFNumber numberWithLong: 40] + forKey: @"longValue"]) && + R([myObject setValue: [OFNumber numberWithLongLong: 50] + forKey: @"longLongValue"]) && + R([myObject setValue: [OFNumber numberWithUnsignedChar: 60] + forKey: @"unsignedCharValue"]) && + R([myObject setValue: [OFNumber numberWithUnsignedShort: 70] + forKey: @"unsignedShortValue"]) && + R([myObject setValue: [OFNumber numberWithUnsignedInt: 80] + forKey: @"unsignedIntValue"]) && + R([myObject setValue: [OFNumber numberWithUnsignedLong: 90] + forKey: @"unsignedLongValue"]) && + R([myObject setValue: [OFNumber numberWithUnsignedLongLong: 100] + forKey: @"unsignedLongLongValue"]) && + R([myObject setValue: [OFNumber numberWithFloat: 110] + forKey: @"floatValue"]) && + R([myObject setValue: [OFNumber numberWithDouble: 120] + forKey: @"doubleValue"]) && + myObject.isBoolValue == 0 && myObject.charValue == 10 && + myObject.shortValue == 20 && myObject.intValue == 30 && + myObject.longValue == 40 && myObject.longLongValue == 50 && + myObject.unsignedCharValue == 60 && + myObject.unsignedShortValue == 70 && + myObject.unsignedIntValue == 80 && + myObject.unsignedLongValue == 90 && + myObject.unsignedLongLongValue == 100 && + myObject.floatValue == 110 && + myObject.doubleValue == 120) EXPECT_EXCEPTION(@"Catch -[setValue:forKey:] with nil key for scalar", - OFInvalidArgumentException, [m setValue: (id _Nonnull)nil - forKey: @"intValue"]) + OFInvalidArgumentException, + [myObject setValue: (id _Nonnull)nil forKey: @"intValue"]) TEST(@"-[valueForKeyPath:]", - (m = [[[MyObj alloc] init] autorelease]) && - (m.objectValue = [[[MyObj alloc] init] autorelease]) && - R([m.objectValue - setObjectValue: [[[MyObj alloc] init] autorelease]]) && - R([[m.objectValue objectValue] setDoubleValue: 0.5]) && - [[m valueForKeyPath: @"objectValue.objectValue.doubleValue"] + (myObject = [[[MyObject alloc] init] autorelease]) && + (myObject.objectValue = [[[MyObject alloc] init] autorelease]) && + R([myObject.objectValue + setObjectValue: [[[MyObject alloc] init] autorelease]]) && + R([[myObject.objectValue objectValue] setDoubleValue: 0.5]) && + [[myObject valueForKeyPath: @"objectValue.objectValue.doubleValue"] doubleValue] == 0.5) TEST(@"[-setValue:forKeyPath:]", - R([m setValue: [OFNumber numberWithDouble: 0.75] - forKeyPath: @"objectValue.objectValue.doubleValue"]) && - [[m.objectValue objectValue] doubleValue] == 0.75) + R([myObject setValue: [OFNumber numberWithDouble: 0.75] + forKeyPath: @"objectValue.objectValue.doubleValue"]) && + [[myObject.objectValue objectValue] doubleValue] == 0.75) objc_autoreleasePoolPop(pool); } @end ADDED tests/OFPBKDF2Tests.m Index: tests/OFPBKDF2Tests.m ================================================================== --- /dev/null +++ tests/OFPBKDF2Tests.m @@ -0,0 +1,125 @@ +/* + * 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 "TestsAppDelegate.h" + +static OFString *const module = @"OFPBKDF2"; + +@implementation TestsAppDelegate (OFPBKDF2Tests) +- (void)PBKDF2Tests +{ + void *pool = objc_autoreleasePoolPush(); + OFHMAC *HMAC = [OFHMAC HMACWithHashClass: [OFSHA1Hash class] + allowsSwappableMemory: true]; + unsigned char key[25]; + + /* Test vectors from RFC 6070 */ + + TEST(@"PBKDF2-SHA1, 1 iteration", + R(OFPBKDF2((OFPBKDF2Parameters){ + .HMAC = HMAC, + .iterations = 1, + .salt = (unsigned char *)"salt", + .saltLength = 4, + .password = "password", + .passwordLength = 8, + .key = key, + .keyLength = 20, + .allowsSwappableMemory = true + })) && memcmp(key, "\x0C\x60\xC8\x0F\x96\x1F\x0E\x71\xF3\xA9\xB5" + "\x24\xAF\x60\x12\x06\x2F\xE0\x37\xA6", 20) == 0) + + TEST(@"PBKDF2-SHA1, 2 iterations", + R(OFPBKDF2((OFPBKDF2Parameters){ + .HMAC = HMAC, + .iterations = 2, + .salt = (unsigned char *)"salt", + .saltLength = 4, + .password = "password", + .passwordLength = 8, + .key = key, + .keyLength = 20, + .allowsSwappableMemory = true + })) && memcmp(key, "\xEA\x6C\x01\x4D\xC7\x2D\x6F\x8C\xCD\x1E\xD9" + "\x2A\xCE\x1D\x41\xF0\xD8\xDE\x89\x57", 20) == 0) + + TEST(@"PBKDF2-SHA1, 4096 iterations", + R(OFPBKDF2((OFPBKDF2Parameters){ + .HMAC = HMAC, + .iterations = 4096, + .salt = (unsigned char *)"salt", + .saltLength = 4, + .password = "password", + .passwordLength = 8, + .key = key, + .keyLength = 20, + .allowsSwappableMemory = true + })) && memcmp(key, "\x4B\x00\x79\x01\xB7\x65\x48\x9A\xBE\xAD\x49" + "\xD9\x26\xF7\x21\xD0\x65\xA4\x29\xC1", 20) == 0) + + /* This test takes too long, even on a fast machine. */ +#if 0 + TEST(@"PBKDF2-SHA1, 16777216 iterations", + R(OFPBKDF2((OFPBKDF2Parameters){ + .HMAC = HMAC, + .iterations = 16777216, + .salt = (unsigned char *)"salt", + .saltLength = 4, + .password = "password", + .passwordLength = 8, + .key = key, + .keyLength = 20, + .allowsSwappableMemory = true + })) && memcmp(key, "\xEE\xFE\x3D\x61\xCD\x4D\xA4\xE4\xE9\x94\x5B" + "\x3D\x6B\xA2\x15\x8C\x26\x34\xE9\x84", 20) == 0) +#endif + + TEST(@"PBKDF2-SHA1, 4096 iterations, key > 1 block", + R(OFPBKDF2((OFPBKDF2Parameters){ + .HMAC = HMAC, + .iterations = 4096, + .salt = (unsigned char *)"saltSALTsaltSALTsalt" + "SALTsaltSALTsalt", + .saltLength = 36, + .password = "passwordPASSWORDpassword", + .passwordLength = 24, + .key = key, + .keyLength = 25, + .allowsSwappableMemory = true + })) && + memcmp(key, "\x3D\x2E\xEC\x4F\xE4\x1C\x84\x9B\x80\xC8\xD8\x36\x62" + "\xC0\xE4\x4A\x8B\x29\x1A\x96\x4C\xF2\xF0\x70\x38", 25) == 0) + + TEST(@"PBKDF2-SHA1, 4096 iterations, key < 1 block", + R(OFPBKDF2((OFPBKDF2Parameters){ + .HMAC = HMAC, + .iterations = 4096, + .salt = (unsigned char *)"sa\0lt", + .saltLength = 5, + .password = "pass\0word", + .passwordLength = 9, + .key = key, + .keyLength = 16, + .allowsSwappableMemory = true + })) && memcmp(key, "\x56\xFA\x6A\xA7\x55\x48\x09\x9D\xCC\x37\xD7" + "\xF0\x34\x25\xE0\xC3", 16) == 0) + + objc_autoreleasePoolPop(pool); +} +@end Index: tests/OFPluginTests.m ================================================================== --- tests/OFPluginTests.m +++ tests/OFPluginTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -20,26 +18,39 @@ #import "TestsAppDelegate.h" #import "plugin/TestPlugin.h" #ifndef OF_IOS -# define PLUGIN_PATH @"plugin/TestPlugin" +static OFString *const pluginName = @"plugin/TestPlugin"; #else -# define PLUGIN_PATH @"PlugIns/TestPlugin" +static OFString *const pluginName = @"PlugIns/TestPlugin"; #endif -static OFString *module = @"OFPlugin"; +static OFString *const module = @"OFPlugin"; @implementation TestsAppDelegate (OFPluginTests) - (void)pluginTests { void *pool = objc_autoreleasePoolPush(); - TestPlugin *plugin; + OFString *path; + OFPlugin *plugin; + Class (*class)(void); + TestPlugin *test; + + TEST(@"+[pathForName:]", (path = [OFPlugin pathForName: pluginName])) + + TEST(@"+[pluginWithPath:]", (plugin = [OFPlugin pluginWithPath: path])) - TEST(@"+[pluginFromFile:]", - (plugin = [OFPlugin pluginFromFile: PLUGIN_PATH])) + TEST(@"-[addressForSymbol:]", + (class = (Class (*)(void))(uintptr_t) + [plugin addressForSymbol: @"class"])) - TEST(@"TestPlugin's -[test:]", [plugin test: 1234] == 2468) + test = [[class() alloc] init]; + @try { + TEST(@"TestPlugin's -[test:]", [test test: 1234] == 2468) + } @finally { + [test release]; + } objc_autoreleasePoolPop(pool); } @end Index: tests/OFPropertyListTests.m ================================================================== --- tests/OFPropertyListTests.m +++ tests/OFPropertyListTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -25,23 +23,23 @@ @"\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">" \ @"\n" \ x @"\n" \ @"" -static OFString *module = @"OFPropertyList"; -static OFString *PLIST1 = PLIST(@"Hello"); -static OFString *PLIST2 = PLIST( +static OFString *const module = @"OFPropertyList"; +static OFString *const PLIST1 = PLIST(@"Hello"); +static OFString *const PLIST2 = PLIST( @"" @" Hello" @" V29ybGQh" @" 2018-03-14T12:34:56Z" @" " @" " @" 12.25" @" -10" @""); -static OFString *PLIST3 = PLIST( +static OFString *const PLIST3 = PLIST( @"" @" array" @" " @" Hello" @" V29ybGQh" @@ -59,12 +57,11 @@ - (void)propertyListTests { void *pool = objc_autoreleasePoolPush(); OFArray *array = [OFArray arrayWithObjects: @"Hello", - [OFData dataWithItems: "World!" - count: 6], + [OFData dataWithItems: "World!" count: 6], [OFDate dateWithTimeIntervalSince1970: 1521030896], [OFNumber numberWithBool: true], [OFNumber numberWithBool: false], [OFNumber numberWithFloat: 12.25f], [OFNumber numberWithInt: -10], Index: tests/OFRIPEMD160HashTests.m ================================================================== --- tests/OFRIPEMD160HashTests.m +++ tests/OFRIPEMD160HashTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -19,46 +17,44 @@ #include #import "TestsAppDelegate.h" -static OFString *module = @"OFRIPEMD160Hash"; +static OFString *const module = @"OFRIPEMD160Hash"; -const uint8_t testfile_rmd160[20] = +const uint8_t testFileRIPEMD160[20] = "\x46\x02\x97\xF5\x85\xDF\xB9\x21\x00\xC8\xF9\x87\xC6\xEC\x84\x0D\xCE" "\xE6\x08\x8B"; @implementation TestsAppDelegate (OFRIPEMD160HashTests) - (void)RIPEMD160HashTests { void *pool = objc_autoreleasePoolPush(); - OFRIPEMD160Hash *rmd160, *copy; - OFFile *f = [OFFile fileWithPath: @"testfile.bin" - mode: @"r"]; - - TEST(@"+[cryptoHashWithAllowsSwappableMemory:]", - (rmd160 = [OFRIPEMD160Hash - cryptoHashWithAllowsSwappableMemory: true])) - - while (!f.atEndOfStream) { - char buf[64]; - size_t len = [f readIntoBuffer: buf - length: 64]; - [rmd160 updateWithBuffer: buf - length: len]; - } - [f close]; - - TEST(@"-[copy]", (copy = [[rmd160 copy] autorelease])) + OFRIPEMD160Hash *RIPEMD160, *RIPEMD160Copy; + OFFile *file = [OFFile fileWithPath: @"testfile.bin" mode: @"r"]; + + TEST(@"+[hashWithAllowsSwappableMemory:]", + (RIPEMD160 = [OFRIPEMD160Hash hashWithAllowsSwappableMemory: true])) + + while (!file.atEndOfStream) { + char buffer[64]; + size_t length = [file readIntoBuffer: buffer length: 64]; + [RIPEMD160 updateWithBuffer: buffer length: length]; + } + [file close]; + + TEST(@"-[copy]", (RIPEMD160Copy = [[RIPEMD160 copy] autorelease])) + + TEST(@"-[calculate]", + R([RIPEMD160 calculate]) && R([RIPEMD160Copy calculate])) TEST(@"-[digest]", - memcmp(rmd160.digest, testfile_rmd160, 20) == 0 && - memcmp(copy.digest, testfile_rmd160, 20) == 0) + memcmp(RIPEMD160.digest, testFileRIPEMD160, 20) == 0 && + memcmp(RIPEMD160Copy.digest, testFileRIPEMD160, 20) == 0) EXPECT_EXCEPTION(@"Detect invalid call of " @"-[updateWithBuffer:length]", OFHashAlreadyCalculatedException, - [rmd160 updateWithBuffer: "" - length: 1]) + [RIPEMD160 updateWithBuffer: "" length: 1]) objc_autoreleasePoolPop(pool); } @end DELETED tests/OFSCTPSocketTests.m Index: tests/OFSCTPSocketTests.m ================================================================== --- tests/OFSCTPSocketTests.m +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "TestsAppDelegate.h" - -static OFString *module = @"OFSCTPSocket"; - -@implementation TestsAppDelegate (OFSCTPSocketTests) -- (void)SCTPSocketTests -{ - void *pool = objc_autoreleasePoolPush(); - OFSCTPSocket *server, *client = nil, *accepted; - uint16_t port; - char buf[6]; - - TEST(@"+[socket]", (server = [OFSCTPSocket socket]) && - (client = [OFSCTPSocket socket])) - - @try { - TEST(@"-[bindToHost:port:]", - (port = [server bindToHost: @"127.0.0.1" - port: 0])) - } @catch (OFBindFailedException *e) { - switch (e.errNo) { - case EPROTONOSUPPORT: - [of_stdout setForegroundColor: [OFColor lime]]; - [of_stdout writeLine: - @"[OFSCTPSocket] -[bindToHost:port:]: " - @"SCTP unsupported, skipping tests"]; - break; - default: - @throw e; - } - - objc_autoreleasePoolPop(pool); - return; - } - - TEST(@"-[listen]", R([server listen])) - - TEST(@"-[connectToHost:port:]", - R([client connectToHost: @"127.0.0.1" - port: port])) - - TEST(@"-[accept]", (accepted = [server accept])) - - TEST(@"-[remoteAddress]", - [of_socket_address_ip_string(accepted.remoteAddress, NULL) - isEqual: @"127.0.0.1"]) - - TEST(@"-[sendBuffer:length:]", R([client sendBuffer: "Hello!" - length: 6])) - - TEST(@"-[receiveIntoBuffer:length:]", [accepted receiveIntoBuffer: buf - length: 6] && - !memcmp(buf, "Hello!", 6)) - - objc_autoreleasePoolPop(pool); -} -@end Index: tests/OFSHA1HashTests.m ================================================================== --- tests/OFSHA1HashTests.m +++ tests/OFSHA1HashTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -19,45 +17,43 @@ #include #import "TestsAppDelegate.h" -static OFString *module = @"OFSHA1Hash"; +static OFString *const module = @"OFSHA1Hash"; -const uint8_t testfile_sha1[20] = +const uint8_t testFileSHA1[20] = "\xC9\x9A\xB8\x7E\x1E\xC8\xEC\x65\xD5\xEB\xE4\x2E\x0D\xA6\x80\x96\xF5" "\x94\xE7\x17"; @implementation TestsAppDelegate (SHA1HashTests) - (void)SHA1HashTests { void *pool = objc_autoreleasePoolPush(); - OFSHA1Hash *sha1, *copy; - OFFile *f = [OFFile fileWithPath: @"testfile.bin" - mode: @"r"]; - - TEST(@"+[cryptoHashWithAllowsSwappableMemory:]", - (sha1 = [OFSHA1Hash cryptoHashWithAllowsSwappableMemory: true])) - - while (!f.atEndOfStream) { - char buf[64]; - size_t len = [f readIntoBuffer: buf - length: 64]; - [sha1 updateWithBuffer: buf - length: len]; - } - [f close]; - - TEST(@"-[copy]", (copy = [[sha1 copy] autorelease])) + OFSHA1Hash *SHA1, *SHA1Copy; + OFFile *file = [OFFile fileWithPath: @"testfile.bin" mode: @"r"]; + + TEST(@"+[hashWithAllowsSwappableMemory:]", + (SHA1 = [OFSHA1Hash hashWithAllowsSwappableMemory: true])) + + while (!file.atEndOfStream) { + char buffer[64]; + size_t length = [file readIntoBuffer: buffer length: 64]; + [SHA1 updateWithBuffer: buffer length: length]; + } + [file close]; + + TEST(@"-[copy]", (SHA1Copy = [[SHA1 copy] autorelease])) + + TEST(@"-[calculate]", R([SHA1 calculate]) && R([SHA1Copy calculate])) TEST(@"-[digest]", - memcmp(sha1.digest, testfile_sha1, 20) == 0 && - memcmp(copy.digest, testfile_sha1, 20) == 0) + memcmp(SHA1.digest, testFileSHA1, 20) == 0 && + memcmp(SHA1Copy.digest, testFileSHA1, 20) == 0) EXPECT_EXCEPTION(@"Detect invalid call of " @"-[updateWithBuffer:length:]", OFHashAlreadyCalculatedException, - [sha1 updateWithBuffer: "" - length: 1]) + [SHA1 updateWithBuffer: "" length: 1]) objc_autoreleasePoolPop(pool); } @end Index: tests/OFSHA224HashTests.m ================================================================== --- tests/OFSHA224HashTests.m +++ tests/OFSHA224HashTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -19,45 +17,44 @@ #include #import "TestsAppDelegate.h" -static OFString *module = @"OFSHA224Hash"; +static OFString *const module = @"OFSHA224Hash"; -const uint8_t testfile_sha224[28] = +const uint8_t testFileSHA224[28] = "\x27\x69\xD8\x04\x2D\x0F\xCA\x84\x6C\xF1\x62\x44\xBA\x0C\xBD\x46\x64" "\x5F\x4F\x20\x02\x4D\x15\xED\x1C\x61\x1F\xF7"; @implementation TestsAppDelegate (SHA224HashTests) - (void)SHA224HashTests { void *pool = objc_autoreleasePoolPush(); - OFSHA224Hash *sha224, *copy; - OFFile *f = [OFFile fileWithPath: @"testfile.bin" - mode: @"r"]; - - TEST(@"+[cryptoHashWithAllowsSwappableMemory:]", - (sha224 = [OFSHA224Hash cryptoHashWithAllowsSwappableMemory: true])) - - while (!f.atEndOfStream) { - char buf[64]; - size_t len = [f readIntoBuffer: buf - length: 64]; - [sha224 updateWithBuffer: buf - length: len]; - } - [f close]; - - TEST(@"-[copy]", (copy = [[sha224 copy] autorelease])) + OFSHA224Hash *SHA224, *SHA224Copy; + OFFile *file = [OFFile fileWithPath: @"testfile.bin" mode: @"r"]; + + TEST(@"+[hashWithAllowsSwappableMemory:]", + (SHA224 = [OFSHA224Hash hashWithAllowsSwappableMemory: true])) + + while (!file.atEndOfStream) { + char buffer[64]; + size_t length = [file readIntoBuffer: buffer length: 64]; + [SHA224 updateWithBuffer: buffer length: length]; + } + [file close]; + + TEST(@"-[copy]", (SHA224Copy = [[SHA224 copy] autorelease])) + + TEST(@"-[calculate]", + R([SHA224 calculate]) && R([SHA224Copy calculate])) TEST(@"-[digest]", - memcmp(sha224.digest, testfile_sha224, 28) == 0 && - memcmp(copy.digest, testfile_sha224, 28) == 0) + memcmp(SHA224.digest, testFileSHA224, 28) == 0 && + memcmp(SHA224Copy.digest, testFileSHA224, 28) == 0) EXPECT_EXCEPTION(@"Detect invalid call of " @"-[updateWithBuffer:length:]", OFHashAlreadyCalculatedException, - [sha224 updateWithBuffer: "" - length: 1]) + [SHA224 updateWithBuffer: "" length: 1]) objc_autoreleasePoolPop(pool); } @end Index: tests/OFSHA256HashTests.m ================================================================== --- tests/OFSHA256HashTests.m +++ tests/OFSHA256HashTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -19,45 +17,44 @@ #include #import "TestsAppDelegate.h" -static OFString *module = @"OFSHA256Hash"; +static OFString *const module = @"OFSHA256Hash"; -const uint8_t testfile_sha256[32] = +const uint8_t testFileSHA256[32] = "\x1A\x02\xD6\x46\xF5\xA6\xBA\xAA\xFF\x7F\xD5\x87\xBA\xC3\xF6\xC6\xB5" "\x67\x93\x8F\x0F\x44\x90\xB8\xF5\x35\x89\xF0\x5A\x23\x7F\x69"; @implementation TestsAppDelegate (SHA256HashTests) - (void)SHA256HashTests { void *pool = objc_autoreleasePoolPush(); - OFSHA256Hash *sha256, *copy; - OFFile *f = [OFFile fileWithPath: @"testfile.bin" - mode: @"r"]; - - TEST(@"+[cryptoHashWithAllowsSwappableMemory:]", - (sha256 = [OFSHA256Hash cryptoHashWithAllowsSwappableMemory: true])) - - while (!f.atEndOfStream) { - char buf[64]; - size_t len = [f readIntoBuffer: buf - length: 64]; - [sha256 updateWithBuffer: buf - length: len]; - } - [f close]; - - TEST(@"-[copy]", (copy = [[sha256 copy] autorelease])) + OFSHA256Hash *SHA256, *SHA256Copy; + OFFile *file = [OFFile fileWithPath: @"testfile.bin" mode: @"r"]; + + TEST(@"+[hashWithAllowsSwappableMemory:]", + (SHA256 = [OFSHA256Hash hashWithAllowsSwappableMemory: true])) + + while (!file.atEndOfStream) { + char buffer[64]; + size_t length = [file readIntoBuffer: buffer length: 64]; + [SHA256 updateWithBuffer: buffer length: length]; + } + [file close]; + + TEST(@"-[copy]", (SHA256Copy = [[SHA256 copy] autorelease])) + + TEST(@"-[calculate]", + R([SHA256 calculate]) && R([SHA256Copy calculate])) TEST(@"-[digest]", - memcmp(sha256.digest, testfile_sha256, 32) == 0 && - memcmp(copy.digest, testfile_sha256, 32) == 0) + memcmp(SHA256.digest, testFileSHA256, 32) == 0 && + memcmp(SHA256Copy.digest, testFileSHA256, 32) == 0) EXPECT_EXCEPTION(@"Detect invalid call of " @"-[updateWithBuffer:length:]", OFHashAlreadyCalculatedException, - [sha256 updateWithBuffer: "" - length: 1]) + [SHA256 updateWithBuffer: "" length: 1]) objc_autoreleasePoolPop(pool); } @end Index: tests/OFSHA384HashTests.m ================================================================== --- tests/OFSHA384HashTests.m +++ tests/OFSHA384HashTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -19,46 +17,45 @@ #include #import "TestsAppDelegate.h" -static OFString *module = @"OFSHA384Hash"; +static OFString *const module = @"OFSHA384Hash"; -const uint8_t testfile_sha384[48] = +const uint8_t testFileSHA384[48] = "\x7E\xDE\x62\xE2\x10\xA5\x1E\x18\x8A\x11\x7F\x78\xD7\xC7\x55\xB6\x43" "\x94\x1B\xD2\x78\x5C\xCF\xF3\x8A\xB8\x98\x22\xC7\x0E\xFE\xF1\xEC\x53" "\xE9\x1A\xB3\x51\x70\x8C\x1F\x3F\x56\x12\x44\x01\x91\x54"; @implementation TestsAppDelegate (SHA384HashTests) - (void)SHA384HashTests { void *pool = objc_autoreleasePoolPush(); - OFSHA384Hash *sha384, *copy; - OFFile *f = [OFFile fileWithPath: @"testfile.bin" - mode: @"r"]; - - TEST(@"+[cryptoHashWithAllowsSwappableMemory:]", - (sha384 = [OFSHA384Hash cryptoHashWithAllowsSwappableMemory: true])) - - while (!f.atEndOfStream) { - char buf[128]; - size_t len = [f readIntoBuffer: buf - length: 128]; - [sha384 updateWithBuffer: buf - length: len]; - } - [f close]; - - TEST(@"-[copy]", (copy = [[sha384 copy] autorelease])) + OFSHA384Hash *SHA384, *SHA384Copy; + OFFile *file = [OFFile fileWithPath: @"testfile.bin" mode: @"r"]; + + TEST(@"+[hashWithAllowsSwappableMemory:]", + (SHA384 = [OFSHA384Hash hashWithAllowsSwappableMemory: true])) + + while (!file.atEndOfStream) { + char buffer[128]; + size_t length = [file readIntoBuffer: buffer length: 128]; + [SHA384 updateWithBuffer: buffer length: length]; + } + [file close]; + + TEST(@"-[copy]", (SHA384Copy = [[SHA384 copy] autorelease])) + + TEST(@"-[calculate]", + R([SHA384 calculate]) && R([SHA384Copy calculate])) TEST(@"-[digest]", - memcmp(sha384.digest, testfile_sha384, 48) == 0 && - memcmp(copy.digest, testfile_sha384, 48) == 0) + memcmp(SHA384.digest, testFileSHA384, 48) == 0 && + memcmp(SHA384Copy.digest, testFileSHA384, 48) == 0) EXPECT_EXCEPTION(@"Detect invalid call of " @"-[updateWithBuffer:length:]", OFHashAlreadyCalculatedException, - [sha384 updateWithBuffer: "" - length: 1]) + [SHA384 updateWithBuffer: "" length: 1]) objc_autoreleasePoolPop(pool); } @end Index: tests/OFSHA512HashTests.m ================================================================== --- tests/OFSHA512HashTests.m +++ tests/OFSHA512HashTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -19,47 +17,46 @@ #include #import "TestsAppDelegate.h" -static OFString *module = @"OFSHA512Hash"; +static OFString *const module = @"OFSHA512Hash"; -const uint8_t testfile_sha512[64] = +const uint8_t testFileSHA512[64] = "\x8F\x36\x6E\x3C\x19\x4B\xBB\xC7\x82\xAA\xCD\x7D\x55\xA2\xD3\x29\x29" "\x97\x6A\x3F\xEB\x9B\xB2\xCB\x75\xC9\xEC\xC8\x10\x07\xD6\x07\x31\x4A" "\xB1\x30\x97\x82\x58\xA5\x1F\x71\x42\xE6\x56\x07\x99\x57\xB2\xB8\x3B" "\xA1\x8A\x41\x64\x33\x69\x21\x8C\x2A\x44\x6D\xF2\xA0"; @implementation TestsAppDelegate (SHA512HashTests) - (void)SHA512HashTests { void *pool = objc_autoreleasePoolPush(); - OFSHA512Hash *sha512, *copy; - OFFile *f = [OFFile fileWithPath: @"testfile.bin" - mode: @"r"]; - - TEST(@"+[cryptoHashWithAllowsSwappableMemory:]", - (sha512 = [OFSHA512Hash cryptoHashWithAllowsSwappableMemory: true])) - - while (!f.atEndOfStream) { - char buf[128]; - size_t len = [f readIntoBuffer: buf - length: 128]; - [sha512 updateWithBuffer: buf - length: len]; - } - [f close]; - - TEST(@"-[copy]", (copy = [[sha512 copy] autorelease])) + OFSHA512Hash *SHA512, *SHA512Copy; + OFFile *file = [OFFile fileWithPath: @"testfile.bin" mode: @"r"]; + + TEST(@"+[hashWithAllowsSwappableMemory:]", + (SHA512 = [OFSHA512Hash hashWithAllowsSwappableMemory: true])) + + while (!file.atEndOfStream) { + char buffer[128]; + size_t length = [file readIntoBuffer: buffer length: 128]; + [SHA512 updateWithBuffer: buffer length: length]; + } + [file close]; + + TEST(@"-[copy]", (SHA512Copy = [[SHA512 copy] autorelease])) + + TEST(@"-[calculate]", + R([SHA512 calculate]) && R([SHA512Copy calculate])) TEST(@"-[digest]", - memcmp(sha512.digest, testfile_sha512, 64) == 0 && - memcmp(copy.digest, testfile_sha512, 64) == 0) + memcmp(SHA512.digest, testFileSHA512, 64) == 0 && + memcmp(SHA512Copy.digest, testFileSHA512, 64) == 0) EXPECT_EXCEPTION(@"Detect invalid call of " @"-[updateWithBuffer:length:]", OFHashAlreadyCalculatedException, - [sha512 updateWithBuffer: "" - length: 1]) + [SHA512 updateWithBuffer: "" length: 1]) objc_autoreleasePoolPop(pool); } @end Index: tests/OFSPXSocketTests.m ================================================================== --- tests/OFSPXSocketTests.m +++ tests/OFSPXSocketTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -19,11 +17,11 @@ #include #import "TestsAppDelegate.h" -static OFString *module = @"OFSPXSocket"; +static OFString *const module = @"OFSPXSocket"; @interface SPXSocketDelegate: OFObject { @public OFSequencedPacketSocket *_expectedServerSocket; @@ -39,11 +37,11 @@ @implementation SPXSocketDelegate - (bool)socket: (OFSequencedPacketSocket *)sock didAcceptSocket: (OFSequencedPacketSocket *)accepted exception: (id)exception { - OF_ENSURE(!_accepted); + OFEnsure(!_accepted); _accepted = (sock == _expectedServerSocket && accepted != nil && exception == nil); if (_accepted && _connected) @@ -56,11 +54,11 @@ didConnectToNode: (unsigned char [IPX_NODE_LEN])node network: (uint32_t)network port: (uint16_t)port exception: (id)exception { - OF_ENSURE(!_connected); + OFEnsure(!_connected); _connected = (sock == _expectedClientSocket && memcmp(node, _expectedNode, IPX_NODE_LEN) == 0 && network == _expectedNetwork && port == _expectedPort && exception == nil); @@ -72,13 +70,13 @@ @implementation TestsAppDelegate (OFSPXSocketTests) - (void)SPXSocketTests { void *pool = objc_autoreleasePoolPush(); - OFSPXSocket *sockClient, *sockServer, *sockAccepted;; - of_socket_address_t address1; - const of_socket_address_t *address2; + OFSPXSocket *sockClient, *sockServer = nil, *sockAccepted; + OFSocketAddress address1; + const OFSocketAddress *address2; unsigned char node[IPX_NODE_LEN], node2[IPX_NODE_LEN]; uint32_t network; uint16_t port; char buffer[5]; SPXSocketDelegate *delegate; @@ -90,25 +88,25 @@ TEST(@"-[bindToPort:]", R(address1 = [sockServer bindToPort: 0])) } @catch (OFBindFailedException *e) { switch (e.errNo) { case EAFNOSUPPORT: - [of_stdout setForegroundColor: [OFColor lime]]; - [of_stdout writeLine: - @"[OFSPXSocket] -[bindToPort:]: " + [OFStdOut setForegroundColor: [OFColor lime]]; + [OFStdOut writeLine: + @"\r[OFSPXSocket] -[bindToPort:]: " @"IPX unsupported, skipping tests"]; break; case ESOCKTNOSUPPORT: - [of_stdout setForegroundColor: [OFColor lime]]; - [of_stdout writeLine: - @"[OFSPXSocket] -[bindToPort:]: " + [OFStdOut setForegroundColor: [OFColor lime]]; + [OFStdOut writeLine: + @"\r[OFSPXSocket] -[bindToPort:]: " @"SPX unsupported, skipping tests"]; break; case EADDRNOTAVAIL: - [of_stdout setForegroundColor: [OFColor lime]]; - [of_stdout writeLine: - @"[OFSPXSocket] -[bindToPort:]: " + [OFStdOut setForegroundColor: [OFColor lime]]; + [OFStdOut writeLine: + @"\r[OFSPXSocket] -[bindToPort:]: " @"IPX not configured, skipping tests"]; break; default: @throw e; } @@ -115,37 +113,33 @@ objc_autoreleasePoolPop(pool); return; } - of_socket_address_get_ipx_node(&address1, node); - network = of_socket_address_get_ipx_network(&address1); - port = of_socket_address_get_port(&address1); + OFSocketAddressIPXNode(&address1, node); + network = OFSocketAddressIPXNetwork(&address1); + port = OFSocketAddressPort(&address1); TEST(@"-[listen]", R([sockServer listen])) TEST(@"-[connectToNode:network:port:]", - R([sockClient connectToNode: node - network: network - port: port])) + R([sockClient connectToNode: node network: network port: port])) TEST(@"-[accept]", (sockAccepted = [sockServer accept])) TEST(@"-[sendBuffer:length:]", - R([sockAccepted sendBuffer: "Hello" - length: 5])) + R([sockAccepted sendBuffer: "Hello" length: 5])) TEST(@"-[receiveIntoBuffer:length:]", - [sockClient receiveIntoBuffer: buffer - length: 5] == 5 && + [sockClient receiveIntoBuffer: buffer length: 5] == 5 && memcmp(buffer, "Hello", 5) == 0) TEST(@"-[remoteAddress]", (address2 = sockAccepted.remoteAddress) && - R(of_socket_address_get_ipx_node(address2, node2)) && + R(OFSocketAddressIPXNode(address2, node2)) && memcmp(node, node2, IPX_NODE_LEN) == 0 && - of_socket_address_get_ipx_network(address2) == network) + OFSocketAddressIPXNetwork(address2) == network) delegate = [[[SPXSocketDelegate alloc] init] autorelease]; sockServer = [OFSPXSocket socket]; delegate->_expectedServerSocket = sockServer; @@ -157,15 +151,15 @@ address1 = [sockServer bindToPort: 0]; [sockServer listen]; [sockServer asyncAccept]; - of_socket_address_get_ipx_node(&address1, node); + OFSocketAddressIPXNode(&address1, node); memcpy(delegate->_expectedNode, node, IPX_NODE_LEN); delegate->_expectedNetwork = network = - of_socket_address_get_ipx_network(&address1); - delegate->_expectedPort = port = of_socket_address_get_port(&address1); + OFSocketAddressIPXNetwork(&address1); + delegate->_expectedPort = port = OFSocketAddressPort(&address1); @try { [sockClient asyncConnectToNode: node network: network port: port]; @@ -176,13 +170,13 @@ TEST(@"-[asyncAccept] & -[asyncConnectToNode:network:port:]", delegate->_accepted && delegate->_connected) } @catch (OFObserveFailedException *e) { switch (e.errNo) { case ENOTSOCK: - [of_stdout setForegroundColor: [OFColor lime]]; - [of_stdout writeLine: - @"[OFSPXSocket] -[asyncAccept] & " + [OFStdOut setForegroundColor: [OFColor lime]]; + [OFStdOut writeLine: + @"\r[OFSPXSocket] -[asyncAccept] & " @"-[asyncConnectToNode:network:port:]: select() " @"not supported for SPX, skipping test"]; break; default: @throw e; Index: tests/OFSPXStreamSocketTests.m ================================================================== --- tests/OFSPXStreamSocketTests.m +++ tests/OFSPXStreamSocketTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -19,11 +17,11 @@ #include #import "TestsAppDelegate.h" -static OFString *module = @"OFSPXStreamSocket"; +static OFString *const module = @"OFSPXStreamSocket"; @interface SPXStreamSocketDelegate: OFObject { @public OFStreamSocket *_expectedServerSocket; @@ -39,11 +37,11 @@ @implementation SPXStreamSocketDelegate - (bool)socket: (OFStreamSocket *)sock didAcceptSocket: (OFStreamSocket *)accepted exception: (id)exception { - OF_ENSURE(!_accepted); + OFEnsure(!_accepted); _accepted = (sock == _expectedServerSocket && accepted != nil && exception == nil); if (_accepted && _connected) @@ -56,11 +54,11 @@ didConnectToNode: (unsigned char [IPX_NODE_LEN])node network: (uint32_t)network port: (uint16_t)port exception: (id)exception { - OF_ENSURE(!_connected); + OFEnsure(!_connected); _connected = (sock == _expectedClientSocket && memcmp(node, _expectedNode, IPX_NODE_LEN) == 0 && network == _expectedNetwork && port == _expectedPort && exception == nil); @@ -72,13 +70,13 @@ @implementation TestsAppDelegate (OFSPXStreamSocketTests) - (void)SPXStreamSocketTests { void *pool = objc_autoreleasePoolPush(); - OFSPXStreamSocket *sockClient, *sockServer, *sockAccepted;; - of_socket_address_t address1; - const of_socket_address_t *address2; + OFSPXStreamSocket *sockClient, *sockServer = nil, *sockAccepted; + OFSocketAddress address1; + const OFSocketAddress *address2; unsigned char node[IPX_NODE_LEN], node2[IPX_NODE_LEN]; uint32_t network; uint16_t port; char buffer[5]; SPXStreamSocketDelegate *delegate; @@ -90,25 +88,25 @@ TEST(@"-[bindToPort:]", R(address1 = [sockServer bindToPort: 0])) } @catch (OFBindFailedException *e) { switch (e.errNo) { case EAFNOSUPPORT: - [of_stdout setForegroundColor: [OFColor lime]]; - [of_stdout writeLine: - @"[OFSPXStreamSocket] -[bindToPort:]: " + [OFStdOut setForegroundColor: [OFColor lime]]; + [OFStdOut writeLine: + @"\r[OFSPXStreamSocket] -[bindToPort:]: " @"IPX unsupported, skipping tests"]; break; case ESOCKTNOSUPPORT: - [of_stdout setForegroundColor: [OFColor lime]]; - [of_stdout writeLine: - @"[OFSPXStreamSocket] -[bindToPort:]: " + [OFStdOut setForegroundColor: [OFColor lime]]; + [OFStdOut writeLine: + @"\r[OFSPXStreamSocket] -[bindToPort:]: " @"SPX unsupported, skipping tests"]; break; case EADDRNOTAVAIL: - [of_stdout setForegroundColor: [OFColor lime]]; - [of_stdout writeLine: - @"[OFSPXStreamSocket] -[bindToPort:]: " + [OFStdOut setForegroundColor: [OFColor lime]]; + [OFStdOut writeLine: + @"\r[OFSPXStreamSocket] -[bindToPort:]: " @"IPX not configured, skipping tests"]; break; default: @throw e; } @@ -115,41 +113,36 @@ objc_autoreleasePoolPop(pool); return; } - of_socket_address_get_ipx_node(&address1, node); - network = of_socket_address_get_ipx_network(&address1); - port = of_socket_address_get_port(&address1); + OFSocketAddressIPXNode(&address1, node); + network = OFSocketAddressIPXNetwork(&address1); + port = OFSocketAddressPort(&address1); TEST(@"-[listen]", R([sockServer listen])) TEST(@"-[connectToNode:network:port:]", - R([sockClient connectToNode: node - network: network - port: port])) + R([sockClient connectToNode: node network: network port: port])) TEST(@"-[accept]", (sockAccepted = [sockServer accept])) /* Test reassembly (this would not work with OFSPXSocket) */ TEST(@"-[writeBuffer:length:]", - R([sockAccepted writeBuffer: "Hello" - length: 5])) + R([sockAccepted writeBuffer: "Hello" length: 5])) TEST(@"-[readIntoBuffer:length:]", - [sockClient readIntoBuffer: buffer - length: 2] == 2 && + [sockClient readIntoBuffer: buffer length: 2] == 2 && memcmp(buffer, "He", 2) == 0 && - [sockClient readIntoBuffer: buffer - length: 3] == 3 && + [sockClient readIntoBuffer: buffer length: 3] == 3 && memcmp(buffer, "llo", 3) == 0) TEST(@"-[remoteAddress]", (address2 = sockAccepted.remoteAddress) && - R(of_socket_address_get_ipx_node(address2, node2)) && + R(OFSocketAddressIPXNode(address2, node2)) && memcmp(node, node2, IPX_NODE_LEN) == 0 && - of_socket_address_get_ipx_network(address2) == network) + OFSocketAddressIPXNetwork(address2) == network) delegate = [[[SPXStreamSocketDelegate alloc] init] autorelease]; sockServer = [OFSPXStreamSocket socket]; delegate->_expectedServerSocket = sockServer; @@ -161,15 +154,15 @@ address1 = [sockServer bindToPort: 0]; [sockServer listen]; [sockServer asyncAccept]; - of_socket_address_get_ipx_node(&address1, node); + OFSocketAddressIPXNode(&address1, node); memcpy(delegate->_expectedNode, node, IPX_NODE_LEN); delegate->_expectedNetwork = network = - of_socket_address_get_ipx_network(&address1); - delegate->_expectedPort = port = of_socket_address_get_port(&address1); + OFSocketAddressIPXNetwork(&address1); + delegate->_expectedPort = port = OFSocketAddressPort(&address1); @try { [sockClient asyncConnectToNode: node network: network port: port]; @@ -180,13 +173,13 @@ TEST(@"-[asyncAccept] & -[asyncConnectToNode:network:port:]", delegate->_accepted && delegate->_connected) } @catch (OFObserveFailedException *e) { switch (e.errNo) { case ENOTSOCK: - [of_stdout setForegroundColor: [OFColor lime]]; - [of_stdout writeLine: - @"[OFSPXStreamSocket] -[asyncAccept] & " + [OFStdOut setForegroundColor: [OFColor lime]]; + [OFStdOut writeLine: + @"\r[OFSPXStreamSocket] -[asyncAccept] & " @"-[asyncConnectToNode:network:port:]: select() " @"not supported for SPX, skipping test"]; break; default: @throw e; ADDED tests/OFScryptTests.m Index: tests/OFScryptTests.m ================================================================== --- /dev/null +++ tests/OFScryptTests.m @@ -0,0 +1,223 @@ +/* + * 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 "TestsAppDelegate.h" + +static OFString *const module = @"OFScrypt"; +/* Test vectors form RFC 7914 */ +static const unsigned char salsa20Input[64] = { + 0x7E, 0x87, 0x9A, 0x21, 0x4F, 0x3E, 0xC9, 0x86, 0x7C, 0xA9, 0x40, 0xE6, + 0x41, 0x71, 0x8F, 0x26, 0xBA, 0xEE, 0x55, 0x5B, 0x8C, 0x61, 0xC1, 0xB5, + 0x0D, 0xF8, 0x46, 0x11, 0x6D, 0xCD, 0x3B, 0x1D, 0xEE, 0x24, 0xF3, 0x19, + 0xDF, 0x9B, 0x3D, 0x85, 0x14, 0x12, 0x1E, 0x4B, 0x5A, 0xC5, 0xAA, 0x32, + 0x76, 0x02, 0x1D, 0x29, 0x09, 0xC7, 0x48, 0x29, 0xED, 0xEB, 0xC6, 0x8D, + 0xB8, 0xB8, 0xC2, 0x5E +}; +static const unsigned char salsa20Output[64] = { + 0xA4, 0x1F, 0x85, 0x9C, 0x66, 0x08, 0xCC, 0x99, 0x3B, 0x81, 0xCA, 0xCB, + 0x02, 0x0C, 0xEF, 0x05, 0x04, 0x4B, 0x21, 0x81, 0xA2, 0xFD, 0x33, 0x7D, + 0xFD, 0x7B, 0x1C, 0x63, 0x96, 0x68, 0x2F, 0x29, 0xB4, 0x39, 0x31, 0x68, + 0xE3, 0xC9, 0xE6, 0xBC, 0xFE, 0x6B, 0xC5, 0xB7, 0xA0, 0x6D, 0x96, 0xBA, + 0xE4, 0x24, 0xCC, 0x10, 0x2C, 0x91, 0x74, 0x5C, 0x24, 0xAD, 0x67, 0x3D, + 0xC7, 0x61, 0x8F, 0x81 +}; +static const union { + unsigned char uc[128]; + uint32_t u32[32]; +} blockMixInput = { .uc = { + 0xF7, 0xCE, 0x0B, 0x65, 0x3D, 0x2D, 0x72, 0xA4, 0x10, 0x8C, 0xF5, 0xAB, + 0xE9, 0x12, 0xFF, 0xDD, 0x77, 0x76, 0x16, 0xDB, 0xBB, 0x27, 0xA7, 0x0E, + 0x82, 0x04, 0xF3, 0xAE, 0x2D, 0x0F, 0x6F, 0xAD, 0x89, 0xF6, 0x8F, 0x48, + 0x11, 0xD1, 0xE8, 0x7B, 0xCC, 0x3B, 0xD7, 0x40, 0x0A, 0x9F, 0xFD, 0x29, + 0x09, 0x4F, 0x01, 0x84, 0x63, 0x95, 0x74, 0xF3, 0x9A, 0xE5, 0xA1, 0x31, + 0x52, 0x17, 0xBC, 0xD7, + 0x89, 0x49, 0x91, 0x44, 0x72, 0x13, 0xBB, 0x22, 0x6C, 0x25, 0xB5, 0x4D, + 0xA8, 0x63, 0x70, 0xFB, 0xCD, 0x98, 0x43, 0x80, 0x37, 0x46, 0x66, 0xBB, + 0x8F, 0xFC, 0xB5, 0xBF, 0x40, 0xC2, 0x54, 0xB0, 0x67, 0xD2, 0x7C, 0x51, + 0xCE, 0x4A, 0xD5, 0xFE, 0xD8, 0x29, 0xC9, 0x0B, 0x50, 0x5A, 0x57, 0x1B, + 0x7F, 0x4D, 0x1C, 0xAD, 0x6A, 0x52, 0x3C, 0xDA, 0x77, 0x0E, 0x67, 0xBC, + 0xEA, 0xAF, 0x7E, 0x89 +}}; +static const unsigned char blockMixOutput[128] = { + 0xA4, 0x1F, 0x85, 0x9C, 0x66, 0x08, 0xCC, 0x99, 0x3B, 0x81, 0xCA, 0xCB, + 0x02, 0x0C, 0xEF, 0x05, 0x04, 0x4B, 0x21, 0x81, 0xA2, 0xFD, 0x33, 0x7D, + 0xFD, 0x7B, 0x1C, 0x63, 0x96, 0x68, 0x2F, 0x29, 0xB4, 0x39, 0x31, 0x68, + 0xE3, 0xC9, 0xE6, 0xBC, 0xFE, 0x6B, 0xC5, 0xB7, 0xA0, 0x6D, 0x96, 0xBA, + 0xE4, 0x24, 0xCC, 0x10, 0x2C, 0x91, 0x74, 0x5C, 0x24, 0xAD, 0x67, 0x3D, + 0xC7, 0x61, 0x8F, 0x81, + 0x20, 0xED, 0xC9, 0x75, 0x32, 0x38, 0x81, 0xA8, 0x05, 0x40, 0xF6, 0x4C, + 0x16, 0x2D, 0xCD, 0x3C, 0x21, 0x07, 0x7C, 0xFE, 0x5F, 0x8D, 0x5F, 0xE2, + 0xB1, 0xA4, 0x16, 0x8F, 0x95, 0x36, 0x78, 0xB7, 0x7D, 0x3B, 0x3D, 0x80, + 0x3B, 0x60, 0xE4, 0xAB, 0x92, 0x09, 0x96, 0xE5, 0x9B, 0x4D, 0x53, 0xB6, + 0x5D, 0x2A, 0x22, 0x58, 0x77, 0xD5, 0xED, 0xF5, 0x84, 0x2C, 0xB9, 0xF1, + 0x4E, 0xEF, 0xE4, 0x25 +}; +static const unsigned char ROMixInput[128] = { + 0xF7, 0xCE, 0x0B, 0x65, 0x3D, 0x2D, 0x72, 0xA4, 0x10, 0x8C, 0xF5, 0xAB, + 0xE9, 0x12, 0xFF, 0xDD, 0x77, 0x76, 0x16, 0xDB, 0xBB, 0x27, 0xA7, 0x0E, + 0x82, 0x04, 0xF3, 0xAE, 0x2D, 0x0F, 0x6F, 0xAD, 0x89, 0xF6, 0x8F, 0x48, + 0x11, 0xD1, 0xE8, 0x7B, 0xCC, 0x3B, 0xD7, 0x40, 0x0A, 0x9F, 0xFD, 0x29, + 0x09, 0x4F, 0x01, 0x84, 0x63, 0x95, 0x74, 0xF3, 0x9A, 0xE5, 0xA1, 0x31, + 0x52, 0x17, 0xBC, 0xD7, 0x89, 0x49, 0x91, 0x44, 0x72, 0x13, 0xBB, 0x22, + 0x6C, 0x25, 0xB5, 0x4D, 0xA8, 0x63, 0x70, 0xFB, 0xCD, 0x98, 0x43, 0x80, + 0x37, 0x46, 0x66, 0xBB, 0x8F, 0xFC, 0xB5, 0xBF, 0x40, 0xC2, 0x54, 0xB0, + 0x67, 0xD2, 0x7C, 0x51, 0xCE, 0x4A, 0xD5, 0xFE, 0xD8, 0x29, 0xC9, 0x0B, + 0x50, 0x5A, 0x57, 0x1B, 0x7F, 0x4D, 0x1C, 0xAD, 0x6A, 0x52, 0x3C, 0xDA, + 0x77, 0x0E, 0x67, 0xBC, 0xEA, 0xAF, 0x7E, 0x89 +}; +static const unsigned char ROMixOutput[128] = { + 0x79, 0xCC, 0xC1, 0x93, 0x62, 0x9D, 0xEB, 0xCA, 0x04, 0x7F, 0x0B, 0x70, + 0x60, 0x4B, 0xF6, 0xB6, 0x2C, 0xE3, 0xDD, 0x4A, 0x96, 0x26, 0xE3, 0x55, + 0xFA, 0xFC, 0x61, 0x98, 0xE6, 0xEA, 0x2B, 0x46, 0xD5, 0x84, 0x13, 0x67, + 0x3B, 0x99, 0xB0, 0x29, 0xD6, 0x65, 0xC3, 0x57, 0x60, 0x1F, 0xB4, 0x26, + 0xA0, 0xB2, 0xF4, 0xBB, 0xA2, 0x00, 0xEE, 0x9F, 0x0A, 0x43, 0xD1, 0x9B, + 0x57, 0x1A, 0x9C, 0x71, 0xEF, 0x11, 0x42, 0xE6, 0x5D, 0x5A, 0x26, 0x6F, + 0xDD, 0xCA, 0x83, 0x2C, 0xE5, 0x9F, 0xAA, 0x7C, 0xAC, 0x0B, 0x9C, 0xF1, + 0xBE, 0x2B, 0xFF, 0xCA, 0x30, 0x0D, 0x01, 0xEE, 0x38, 0x76, 0x19, 0xC4, + 0xAE, 0x12, 0xFD, 0x44, 0x38, 0xF2, 0x03, 0xA0, 0xE4, 0xE1, 0xC4, 0x7E, + 0xC3, 0x14, 0x86, 0x1F, 0x4E, 0x90, 0x87, 0xCB, 0x33, 0x39, 0x6A, 0x68, + 0x73, 0xE8, 0xF9, 0xD2, 0x53, 0x9A, 0x4B, 0x8E +}; +static const unsigned char testVector1[64] = { + 0x77, 0xD6, 0x57, 0x62, 0x38, 0x65, 0x7B, 0x20, 0x3B, 0x19, 0xCA, 0x42, + 0xC1, 0x8A, 0x04, 0x97, 0xF1, 0x6B, 0x48, 0x44, 0xE3, 0x07, 0x4A, 0xE8, + 0xDF, 0xDF, 0xFA, 0x3F, 0xED, 0xE2, 0x14, 0x42, 0xFC, 0xD0, 0x06, 0x9D, + 0xED, 0x09, 0x48, 0xF8, 0x32, 0x6A, 0x75, 0x3A, 0x0F, 0xC8, 0x1F, 0x17, + 0xE8, 0xD3, 0xE0, 0xFB, 0x2E, 0x0D, 0x36, 0x28, 0xCF, 0x35, 0xE2, 0x0C, + 0x38, 0xD1, 0x89, 0x06 +}; +static const unsigned char testVector2[64] = { + 0xFD, 0xBA, 0xBE, 0x1C, 0x9D, 0x34, 0x72, 0x00, 0x78, 0x56, 0xE7, 0x19, + 0x0D, 0x01, 0xE9, 0xFE, 0x7C, 0x6A, 0xD7, 0xCB, 0xC8, 0x23, 0x78, 0x30, + 0xE7, 0x73, 0x76, 0x63, 0x4B, 0x37, 0x31, 0x62, 0x2E, 0xAF, 0x30, 0xD9, + 0x2E, 0x22, 0xA3, 0x88, 0x6F, 0xF1, 0x09, 0x27, 0x9D, 0x98, 0x30, 0xDA, + 0xC7, 0x27, 0xAF, 0xB9, 0x4A, 0x83, 0xEE, 0x6D, 0x83, 0x60, 0xCB, 0xDF, + 0xA2, 0xCC, 0x06, 0x40 +}; +/* The third test vector is too expensive for m68k. */ +#ifndef OF_M68K +static const unsigned char testVector3[64] = { + 0x70, 0x23, 0xBD, 0xCB, 0x3A, 0xFD, 0x73, 0x48, 0x46, 0x1C, 0x06, 0xCD, + 0x81, 0xFD, 0x38, 0xEB, 0xFD, 0xA8, 0xFB, 0xBA, 0x90, 0x4F, 0x8E, 0x3E, + 0xA9, 0xB5, 0x43, 0xF6, 0x54, 0x5D, 0xA1, 0xF2, 0xD5, 0x43, 0x29, 0x55, + 0x61, 0x3F, 0x0F, 0xCF, 0x62, 0xD4, 0x97, 0x05, 0x24, 0x2A, 0x9A, 0xF9, + 0xE6, 0x1E, 0x85, 0xDC, 0x0D, 0x65, 0x1E, 0x40, 0xDF, 0xCF, 0x01, 0x7B, + 0x45, 0x57, 0x58, 0x87 +}; +#endif +/* The forth test vector is too expensive to include it in the tests. */ +#if 0 +static const unsigned char testVector4[64] = { + 0x21, 0x01, 0xCB, 0x9B, 0x6A, 0x51, 0x1A, 0xAE, 0xAD, 0xDB, 0xBE, 0x09, + 0xCF, 0x70, 0xF8, 0x81, 0xEC, 0x56, 0x8D, 0x57, 0x4A, 0x2F, 0xFD, 0x4D, + 0xAB, 0xE5, 0xEE, 0x98, 0x20, 0xAD, 0xAA, 0x47, 0x8E, 0x56, 0xFD, 0x8F, + 0x4B, 0xA5, 0xD0, 0x9F, 0xFA, 0x1C, 0x6D, 0x92, 0x7C, 0x40, 0xF4, 0xC3, + 0x37, 0x30, 0x40, 0x49, 0xE8, 0xA9, 0x52, 0xFB, 0xCB, 0xF4, 0x5C, 0x6F, + 0xA7, 0x7A, 0x41, 0xA4 +}; +#endif + +@implementation TestsAppDelegate (OFScryptTests) +- (void)scryptTests +{ + void *pool = objc_autoreleasePoolPush(); + uint32_t salsa20Buffer[16]; + uint32_t blockMixBuffer[32]; + uint32_t ROMixBuffer[32], ROMixTmp[17 * 32]; + unsigned char output[64]; + + TEST(@"Salsa20/8 Core", + R(memcpy(salsa20Buffer, salsa20Input, 64)) && + R(OFSalsa20_8Core(salsa20Buffer)) && + memcmp(salsa20Buffer, salsa20Output, 64) == 0) + + TEST(@"Block mix", + R(OFScryptBlockMix(blockMixBuffer, blockMixInput.u32, 1)) && + memcmp(blockMixBuffer, blockMixOutput, 128) == 0) + + TEST(@"ROMix", + R(memcpy(ROMixBuffer, ROMixInput, 128)) && + R(OFScryptROMix(ROMixBuffer, 1, 16, ROMixTmp)) && + memcmp(ROMixBuffer, ROMixOutput, 128) == 0) + + TEST(@"scrypt test vector #1", + R(OFScrypt((OFScryptParameters){ + .blockSize = 1, + .costFactor = 16, + .parallelization = 1, + .salt = (unsigned char *)"", + .saltLength = 0, + .password = "", + .passwordLength = 0, + .key = output, + .keyLength = 64, + .allowsSwappableMemory = true + })) && memcmp(output, testVector1, 64) == 0) + + TEST(@"scrypt test vector #2", + R(OFScrypt((OFScryptParameters){ + .blockSize = 8, + .costFactor = 1024, + .parallelization = 16, + .salt = (unsigned char *)"NaCl", + .saltLength = 4, + .password = "password", + .passwordLength = 8, + .key = output, + .keyLength = 64, + .allowsSwappableMemory = true + })) && memcmp(output, testVector2, 64) == 0) + + /* The third test vector is too expensive for m68k. */ +#ifndef OF_M68K + TEST(@"scrypt test vector #3", + R(OFScrypt((OFScryptParameters){ + .blockSize = 8, + .costFactor = 16384, + .parallelization = 1, + .salt = (unsigned char *)"SodiumChloride", + .saltLength = 14, + .password = "pleaseletmein", + .passwordLength = 13, + .key = output, + .keyLength = 64, + .allowsSwappableMemory = true + })) && memcmp(output, testVector3, 64) == 0) +#endif + + /* The forth test vector is too expensive to include it in the tests. */ +#if 0 + TEST(@"scrypt test vector #4", + R(OFScrypt((OFScryptParameters){ + .blockSize = 8, + .costFactor = 1048576, + .parallelization = 1, + .salt = (unsigned char *)"SodiumChloride", + .saltLength = 14, + .password = "pleaseletmein", + .passwordLength = 13, + .key = output, + .keyLength = 64, + .allowsSwappableMemory = true + })) && memcmp(output, testVector4, 64) == 0) +#endif + + objc_autoreleasePoolPop(pool); +} +@end Index: tests/OFSerializationTests.m ================================================================== --- tests/OFSerializationTests.m +++ tests/OFSerializationTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -17,54 +15,57 @@ #include "config.h" #import "TestsAppDelegate.h" -static OFString *module = @"OFSerialization"; +static OFString *const module = @"OFSerialization"; @implementation TestsAppDelegate (OFSerializationTests) - (void)serializationTests { void *pool = objc_autoreleasePoolPush(); - OFMutableDictionary *d = [OFMutableDictionary dictionary]; - OFMutableArray *a = [OFMutableArray array]; - OFList *l = [OFList list]; + OFMutableDictionary *dict = [OFMutableDictionary dictionary]; + OFMutableArray *array = [OFMutableArray array]; + OFList *list = [OFList list]; OFData *data; - OFString *s; - - [a addObject: @"Qu\"xbar\ntest"]; - [a addObject: [OFNumber numberWithInt: 1234]]; - [a addObject: [OFNumber numberWithDouble: 1234.5678]]; - [a addObject: [OFMutableString stringWithString: @"asd"]]; - [a addObject: [OFDate dateWithTimeIntervalSince1970: 1234.5678]]; - - [d setObject: @"Hello" - forKey: a]; - [d setObject: @"B\"la" - forKey: @"Blub"]; - - [l appendObject: @"Hello"]; - [l appendObject: @"Wo\rld!\nHow are you?"]; - [l appendObject: [OFURL URLWithString: @"https://objfw.nil.im/"]]; - [l appendObject: + 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: [OFURL URLWithString: @"https://objfw.nil.im/"]]; + [list appendObject: [OFXMLElement elementWithXMLString: @""]]; - [l appendObject: [OFSet setWithObjects: @"foo", @"foo", @"bar", nil]]; - [l appendObject: + [list appendObject: + [OFSet setWithObjects: @"foo", @"foo", @"bar", nil]]; + [list appendObject: [OFCountedSet setWithObjects: @"foo", @"foo", @"bar", nil]]; - [d setObject: @"list" - forKey: l]; + [dict setObject: @"list" forKey: list]; data = [OFData dataWithItems: "0123456789:; + * 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 @@ -21,11 +19,11 @@ #import "OFSet.h" #import "OFMapTableSet.h" #import "OFMutableMapTableSet.h" -static OFString *module = nil; +static OFString *module; @interface SimpleSet: OFSet { OFMutableSet *_set; } @@ -79,12 +77,11 @@ } return self; } -- (instancetype)initWithObject: (id)firstObject - arguments: (va_list)arguments +- (instancetype)initWithObject: (id)firstObject arguments: (va_list)arguments { self = [super init]; @try { _set = [[OFMutableSet alloc] initWithObject: firstObject @@ -145,11 +142,11 @@ if (existed) _mutations++; } -- (int)countByEnumeratingWithState: (of_fast_enumeration_state_t *)state +- (int)countByEnumeratingWithState: (OFFastEnumerationState *)state objects: (id *)objects count: (int)count { int ret = [_set countByEnumeratingWithState: state objects: objects @@ -160,12 +157,11 @@ return ret; } @end @implementation TestsAppDelegate (OFSetTests) -- (void)setTestsWithClass: (Class)setClass - mutableClass: (Class)mutableSetClass +- (void)setTestsWithClass: (Class)setClass mutableClass: (Class)mutableSetClass { void *pool = objc_autoreleasePoolPush(); OFSet *set1, *set2; OFMutableSet *mutableSet; bool ok; ADDED tests/OFSocketTests.m Index: tests/OFSocketTests.m ================================================================== --- /dev/null +++ tests/OFSocketTests.m @@ -0,0 +1,199 @@ +/* + * 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" + +#define COMPARE_V6(a, a0, a1, a2, a3, a4, a5, a6, a7) \ + (a.sockaddr.in6.sin6_addr.s6_addr[0] == (a0 >> 8) && \ + a.sockaddr.in6.sin6_addr.s6_addr[1] == (a0 & 0xFF) && \ + a.sockaddr.in6.sin6_addr.s6_addr[2] == (a1 >> 8) && \ + a.sockaddr.in6.sin6_addr.s6_addr[3] == (a1 & 0xFF) && \ + a.sockaddr.in6.sin6_addr.s6_addr[4] == (a2 >> 8) && \ + a.sockaddr.in6.sin6_addr.s6_addr[5] == (a2 & 0xFF) && \ + a.sockaddr.in6.sin6_addr.s6_addr[6] == (a3 >> 8) && \ + a.sockaddr.in6.sin6_addr.s6_addr[7] == (a3 & 0xFF) && \ + a.sockaddr.in6.sin6_addr.s6_addr[8] == (a4 >> 8) && \ + a.sockaddr.in6.sin6_addr.s6_addr[9] == (a4 & 0xFF) && \ + a.sockaddr.in6.sin6_addr.s6_addr[10] == (a5 >> 8) && \ + a.sockaddr.in6.sin6_addr.s6_addr[11] == (a5 & 0xFF) && \ + a.sockaddr.in6.sin6_addr.s6_addr[12] == (a6 >> 8) && \ + a.sockaddr.in6.sin6_addr.s6_addr[13] == (a6 & 0xFF) && \ + a.sockaddr.in6.sin6_addr.s6_addr[14] == (a7 >> 8) && \ + a.sockaddr.in6.sin6_addr.s6_addr[15] == (a7 & 0xFF)) +#define SET_V6(a, a0, a1, a2, a3, a4, a5, a6, a7) \ + a.sockaddr.in6.sin6_addr.s6_addr[0] = a0 >> 8; \ + a.sockaddr.in6.sin6_addr.s6_addr[1] = a0 & 0xFF; \ + a.sockaddr.in6.sin6_addr.s6_addr[2] = a1 >> 8; \ + a.sockaddr.in6.sin6_addr.s6_addr[3] = a1 & 0xFF; \ + a.sockaddr.in6.sin6_addr.s6_addr[4] = a2 >> 8; \ + a.sockaddr.in6.sin6_addr.s6_addr[5] = a2 & 0xFF; \ + a.sockaddr.in6.sin6_addr.s6_addr[6] = a3 >> 8; \ + a.sockaddr.in6.sin6_addr.s6_addr[7] = a3 & 0xFF; \ + a.sockaddr.in6.sin6_addr.s6_addr[8] = a4 >> 8; \ + a.sockaddr.in6.sin6_addr.s6_addr[9] = a4 & 0xFF; \ + a.sockaddr.in6.sin6_addr.s6_addr[10] = a5 >> 8; \ + a.sockaddr.in6.sin6_addr.s6_addr[11] = a5 & 0xFF; \ + a.sockaddr.in6.sin6_addr.s6_addr[12] = a6 >> 8; \ + a.sockaddr.in6.sin6_addr.s6_addr[13] = a6 & 0xFF; \ + a.sockaddr.in6.sin6_addr.s6_addr[14] = a7 >> 8; \ + a.sockaddr.in6.sin6_addr.s6_addr[15] = a7 & 0xFF; + +static OFString *const module = @"OFSocket"; + +@implementation TestsAppDelegate (OFSocketTests) +- (void)socketTests +{ + void *pool = objc_autoreleasePoolPush(); + OFSocketAddress addr; + + TEST(@"Parsing an IPv4", + R(addr = OFSocketAddressParseIP(@"127.0.0.1", 1234)) && + OFFromBigEndian32(addr.sockaddr.in.sin_addr.s_addr) == 0x7F000001 && + OFFromBigEndian16(addr.sockaddr.in.sin_port) == 1234) + + EXPECT_EXCEPTION(@"Refusing invalid IPv4 #1", OFInvalidFormatException, + OFSocketAddressParseIP(@"127.0.0.0.1", 1234)) + + EXPECT_EXCEPTION(@"Refusing invalid IPv4 #2", OFInvalidFormatException, + OFSocketAddressParseIP(@"127.0.0.256", 1234)) + + EXPECT_EXCEPTION(@"Refusing invalid IPv4 #3", OFInvalidFormatException, + OFSocketAddressParseIP(@"127.0.0. 1", 1234)) + + EXPECT_EXCEPTION(@"Refusing invalid IPv4 #4", OFInvalidFormatException, + OFSocketAddressParseIP(@" 127.0.0.1", 1234)) + + EXPECT_EXCEPTION(@"Refusing invalid IPv4 #5", OFInvalidFormatException, + 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(@"Converting an IPv4 to a string", + [OFSocketAddressString(&addr) isEqual: @"127.0.0.1"]) + + TEST(@"Parsing an IPv6 #1", + R(addr = OFSocketAddressParseIP( + @"1122:3344:5566:7788:99aa:bbCc:ddee:ff00", 1234)) && + COMPARE_V6(addr, + 0x1122, 0x3344, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0xDDEE, 0xFF00) && + OFFromBigEndian16(addr.sockaddr.in6.sin6_port) == 1234) + + TEST(@"Parsing an IPv6 #2", + R(addr = OFSocketAddressParseIP(@"::", 1234)) && + COMPARE_V6(addr, 0, 0, 0, 0, 0, 0, 0, 0) && + OFFromBigEndian16(addr.sockaddr.in6.sin6_port) == 1234) + + TEST(@"Parsing an IPv6 #3", + R(addr = OFSocketAddressParseIP(@"aaAa::bBbb", 1234)) && + COMPARE_V6(addr, 0xAAAA, 0, 0, 0, 0, 0, 0, 0xBBBB) && + OFFromBigEndian16(addr.sockaddr.in6.sin6_port) == 1234) + + TEST(@"Parsing an IPv6 #4", + R(addr = OFSocketAddressParseIP(@"aaAa::", 1234)) && + COMPARE_V6(addr, 0xAAAA, 0, 0, 0, 0, 0, 0, 0) && + OFFromBigEndian16(addr.sockaddr.in6.sin6_port) == 1234) + + 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) + + EXPECT_EXCEPTION(@"Refusing invalid IPv6 #1", OFInvalidFormatException, + OFSocketAddressParseIP(@"1:::2", 1234)) + + EXPECT_EXCEPTION(@"Refusing invalid IPv6 #2", OFInvalidFormatException, + OFSocketAddressParseIP(@"1: ::2", 1234)) + + EXPECT_EXCEPTION(@"Refusing invalid IPv6 #3", OFInvalidFormatException, + OFSocketAddressParseIP(@"1:: :2", 1234)) + + EXPECT_EXCEPTION(@"Refusing invalid IPv6 #4", OFInvalidFormatException, + OFSocketAddressParseIP(@"1::2::3", 1234)) + + EXPECT_EXCEPTION(@"Refusing invalid IPv6 #5", OFInvalidFormatException, + OFSocketAddressParseIP(@"10000::1", 1234)) + + EXPECT_EXCEPTION(@"Refusing invalid IPv6 #6", OFInvalidFormatException, + OFSocketAddressParseIP(@"::10000", 1234)) + + EXPECT_EXCEPTION(@"Refusing invalid IPv6 #7", OFInvalidFormatException, + OFSocketAddressParseIP(@"::1::", 1234)) + + EXPECT_EXCEPTION(@"Refusing invalid IPv6 #8", OFInvalidFormatException, + OFSocketAddressParseIP(@"1:2:3:4:5:6:7:", 1234)) + + EXPECT_EXCEPTION(@"Refusing invalid IPv6 #9", OFInvalidFormatException, + 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) + + SET_V6(addr, 0, 0, 0, 0, 0, 0, 0, 0) + TEST(@"Converting an IPv6 to a string #1", + [OFSocketAddressString(&addr) isEqual: @"::"]) + + SET_V6(addr, 0, 0, 0, 0, 0, 0, 0, 1) + TEST(@"Converting an IPv6 to a string #2", + [OFSocketAddressString(&addr) isEqual: @"::1"]) + + SET_V6(addr, 1, 0, 0, 0, 0, 0, 0, 0) + TEST(@"Converting an IPv6 to a string #3", + [OFSocketAddressString(&addr) isEqual: @"1::"]) + + SET_V6(addr, + 0x1122, 0x3344, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0xDDEE, 0xFF00) + TEST(@"Converting an IPv6 to a string #4", + [OFSocketAddressString(&addr) + isEqual: @"1122:3344:5566:7788:99aa:bbcc:ddee:ff00"]) + + SET_V6(addr, 0x1122, 0x3344, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0xDDEE, 0) + TEST(@"Converting an IPv6 to a string #5", + [OFSocketAddressString(&addr) + isEqual: @"1122:3344:5566:7788:99aa:bbcc:ddee:0"]) + + SET_V6(addr, 0x1122, 0x3344, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0, 0) + TEST(@"Converting an IPv6 to a string #6", + [OFSocketAddressString(&addr) + isEqual: @"1122:3344:5566:7788:99aa:bbcc::"]) + + SET_V6(addr, 0, 0x3344, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0xDDEE, 0xFF00) + TEST(@"Converting an IPv6 to a string #7", + [OFSocketAddressString(&addr) + isEqual: @"0:3344:5566:7788:99aa:bbcc:ddee:ff00"]) + + SET_V6(addr, 0, 0, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0xDDEE, 0xFF00) + TEST(@"Converting an IPv6 to a string #8", + [OFSocketAddressString(&addr) + isEqual: @"::5566:7788:99aa:bbcc:ddee:ff00"]) + + SET_V6(addr, 0, 0, 0x5566, 0, 0, 0, 0xDDEE, 0xFF00) + TEST(@"Converting an IPv6 to a string #9", + [OFSocketAddressString(&addr) isEqual: @"0:0:5566::ddee:ff00"]) + + SET_V6(addr, 0, 0, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0, 0) + TEST(@"Converting an IPv6 to a string #10", + [OFSocketAddressString(&addr) + isEqual: @"::5566:7788:99aa:bbcc:0:0"]) + + objc_autoreleasePoolPop(pool); +} +@end Index: tests/OFStreamTests.m ================================================================== --- tests/OFStreamTests.m +++ tests/OFStreamTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -17,26 +15,25 @@ #include "config.h" #import "TestsAppDelegate.h" -static OFString *module = @"OFStream"; +static OFString *const module = @"OFStream"; -@interface StreamTester: OFStream +@interface StreamTest: OFStream { int state; } @end -@implementation StreamTester +@implementation StreamTest - (bool)lowlevelIsAtEndOfStream { return (state > 1); } -- (size_t)lowlevelReadIntoBuffer: (void *)buffer - length: (size_t)size +- (size_t)lowlevelReadIntoBuffer: (void *)buffer length: (size_t)size { size_t pageSize = [OFSystemInfo pageSize]; switch (state) { case 0: @@ -65,20 +62,25 @@ @implementation TestsAppDelegate (OFStreamTests) - (void)streamTests { void *pool = objc_autoreleasePoolPush(); size_t pageSize = [OFSystemInfo pageSize]; - StreamTester *t = [[[StreamTester alloc] init] autorelease]; - OFString *str; - char *cstr; - - cstr = [t allocMemoryWithSize: pageSize - 2]; - memset(cstr, 'X', pageSize - 3); - cstr[pageSize - 3] = '\0'; - - TEST(@"-[readLine]", [[t readLine] isEqual: @"foo"] && - [(str = [t readLine]) length] == pageSize - 3 && - !strcmp(str.UTF8String, cstr)) + StreamTest *test = [[[StreamTest alloc] init] autorelease]; + OFString *string; + char *cString; + + cString = OFAllocMemory(pageSize - 2, 1); + memset(cString, 'X', pageSize - 3); + cString[pageSize - 3] = '\0'; + + TEST(@"-[readLine] #1", [[test readLine] isEqual: @"foo"]) + + string = [test readLine]; + TEST(@"-[readLine] #2", string != nil && + string.length == pageSize - 3 && + !strcmp(string.UTF8String, cString)) + + OFFreeMemory(cString); objc_autoreleasePoolPop(pool); } @end Index: tests/OFStringTests.m ================================================================== --- tests/OFStringTests.m +++ tests/OFStringTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -25,26 +23,30 @@ #import "OFString.h" #import "OFMutableUTF8String.h" #import "OFUTF8String.h" -static OFString *module = nil; -static OFString *whitespace[] = { +#ifndef INFINITY +# define INFINITY __builtin_inf() +#endif + +static OFString *module; +static OFString *const whitespace[] = { @" \r \t\n\t \tasd \t \t\t\r\n", @" \t\t \t\t \t \t" }; -static of_unichar_t ucstr[] = { +static const OFUnichar unicharString[] = { 0xFEFF, 'f', 0xF6, 0xF6, 'b', 0xE4, 'r', 0x1F03A, 0 }; -static of_unichar_t sucstr[] = { +static const OFUnichar swappedUnicharString[] = { 0xFFFE0000, 0x66000000, 0xF6000000, 0xF6000000, 0x62000000, 0xE4000000, 0x72000000, 0x3AF00100, 0 }; -static uint16_t utf16str[] = { +static const OFChar16 char16String[] = { 0xFEFF, 'f', 0xF6, 0xF6, 'b', 0xE4, 'r', 0xD83C, 0xDC3A, 0 }; -static uint16_t sutf16str[] = { +static const OFChar16 swappedChar16String[] = { 0xFFFE, 0x6600, 0xF600, 0xF600, 0x6200, 0xE400, 0x7200, 0x3CD8, 0x3ADC, 0 }; @interface SimpleString: OFString @@ -87,11 +89,11 @@ return self; } - (instancetype)initWithCString: (const char *)cString - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding length: (size_t)length { self = [super init]; @try { @@ -104,13 +106,13 @@ } return self; } -- (instancetype)initWithUTF16String: (const of_char16_t *)UTF16String +- (instancetype)initWithUTF16String: (const OFChar16 *)UTF16String length: (size_t)length - byteOrder: (of_byte_order_t)byteOrder + byteOrder: (OFByteOrder)byteOrder { self = [super init]; @try { _string = [[OFMutableString alloc] @@ -123,13 +125,13 @@ } return self; } -- (instancetype)initWithUTF32String: (const of_char32_t *)UTF32String +- (instancetype)initWithUTF32String: (const OFChar32 *)UTF32String length: (size_t)length - byteOrder: (of_byte_order_t)byteOrder + byteOrder: (OFByteOrder)byteOrder { self = [super init]; @try { _string = [[OFMutableString alloc] @@ -165,11 +167,11 @@ [_string release]; [super dealloc]; } -- (of_unichar_t)characterAtIndex: (size_t)idx +- (OFUnichar)characterAtIndex: (size_t)idx { return [_string characterAtIndex: idx]; } - (size_t)length @@ -183,15 +185,14 @@ { if (self == [SimpleMutableString class]) [self inheritMethodsFromClass: [SimpleString class]]; } -- (void)replaceCharactersInRange: (of_range_t)range +- (void)replaceCharactersInRange: (OFRange)range withString: (OFString *)string { - [_string replaceCharactersInRange: range - withString: string]; + [_string replaceCharactersInRange: range withString: string]; } @end @interface EntityHandler: OFObject @end @@ -210,158 +211,167 @@ @implementation TestsAppDelegate (OFStringTests) - (void)stringTestsWithClass: (Class)stringClass mutableClass: (Class)mutableStringClass { void *pool = objc_autoreleasePoolPush(); - OFMutableString *s[3]; - OFString *is; - OFArray *a; + OFMutableString *mutableString1, *mutableString2, *mutableString3; + OFString *string; + OFArray *array; size_t i; - const of_unichar_t *ua; - const uint16_t *u16a; - OFCharacterSet *cs; - EntityHandler *h; + const OFUnichar *characters; + const uint16_t *UTF16Characters; + OFCharacterSet *characterSet; + EntityHandler *entityHandler; #ifdef OF_HAVE_BLOCKS __block int j; __block bool ok; #endif #define C(s) ((OFString *)[stringClass stringWithString: s]) - s[0] = [mutableStringClass stringWithString: @"täs€"]; - s[1] = [mutableStringClass string]; - s[2] = [[s[0] copy] autorelease]; - - TEST(@"-[isEqual:]", [s[0] isEqual: s[2]] && - ![s[0] isEqual: [[[OFObject alloc] init] autorelease]]) - - TEST(@"-[compare:]", [s[0] compare: s[2]] == OF_ORDERED_SAME && - [s[0] compare: @""] != OF_ORDERED_SAME && - [C(@"") compare: @"a"] == OF_ORDERED_ASCENDING && - [C(@"a") compare: @"b"] == OF_ORDERED_ASCENDING && - [C(@"cd") compare: @"bc"] == OF_ORDERED_DESCENDING && - [C(@"ä") compare: @"ö"] == OF_ORDERED_ASCENDING && - [C(@"€") compare: @"ß"] == OF_ORDERED_DESCENDING && - [C(@"aa") compare: @"z"] == OF_ORDERED_ASCENDING) + mutableString1 = [mutableStringClass stringWithString: @"täs€"]; + mutableString2 = [mutableStringClass string]; + mutableString3 = [[mutableString1 copy] autorelease]; + + TEST(@"-[isEqual:]", [mutableString1 isEqual: mutableString3] && + ![mutableString1 isEqual: [[[OFObject alloc] init] autorelease]]) + + TEST(@"-[compare:]", + [mutableString1 compare: mutableString3] == OFOrderedSame && + [mutableString1 compare: @""] != OFOrderedSame && + [C(@"") compare: @"a"] == OFOrderedAscending && + [C(@"a") compare: @"b"] == OFOrderedAscending && + [C(@"cd") compare: @"bc"] == OFOrderedDescending && + [C(@"ä") compare: @"ö"] == OFOrderedAscending && + [C(@"€") compare: @"ß"] == OFOrderedDescending && + [C(@"aa") compare: @"z"] == OFOrderedAscending) #ifdef OF_HAVE_UNICODE_TABLES TEST(@"-[caseInsensitiveCompare:]", - [C(@"a") caseInsensitiveCompare: @"A"] == OF_ORDERED_SAME && - [C(@"Ä") caseInsensitiveCompare: @"ä"] == OF_ORDERED_SAME && - [C(@"я") caseInsensitiveCompare: @"Я"] == OF_ORDERED_SAME && - [C(@"€") caseInsensitiveCompare: @"ß"] == OF_ORDERED_DESCENDING && - [C(@"ß") caseInsensitiveCompare: @"→"] == OF_ORDERED_ASCENDING && - [C(@"AA") caseInsensitiveCompare: @"z"] == OF_ORDERED_ASCENDING && + [C(@"a") caseInsensitiveCompare: @"A"] == OFOrderedSame && + [C(@"Ä") caseInsensitiveCompare: @"ä"] == OFOrderedSame && + [C(@"я") caseInsensitiveCompare: @"Я"] == OFOrderedSame && + [C(@"€") caseInsensitiveCompare: @"ß"] == OFOrderedDescending && + [C(@"ß") caseInsensitiveCompare: @"→"] == OFOrderedAscending && + [C(@"AA") caseInsensitiveCompare: @"z"] == OFOrderedAscending && [[stringClass stringWithUTF8String: "ABC"] caseInsensitiveCompare: [stringClass stringWithUTF8String: "AbD"]] == [C(@"abc") compare: @"abd"]) #else TEST(@"-[caseInsensitiveCompare:]", - [C(@"a") caseInsensitiveCompare: @"A"] == OF_ORDERED_SAME && - [C(@"AA") caseInsensitiveCompare: @"z"] == OF_ORDERED_ASCENDING && + [C(@"a") caseInsensitiveCompare: @"A"] == OFOrderedSame && + [C(@"AA") caseInsensitiveCompare: @"z"] == OFOrderedAscending && [[stringClass stringWithUTF8String: "ABC"] caseInsensitiveCompare: [stringClass stringWithUTF8String: "AbD"]] == [C(@"abc") compare: @"abd"]) #endif TEST(@"-[hash] is the same if -[isEqual:] is true", - s[0].hash == s[2].hash) + mutableString1.hash == mutableString3.hash) - TEST(@"-[description]", [s[0].description isEqual: s[0]]) + TEST(@"-[description]", + [mutableString1.description isEqual: mutableString1]) TEST(@"-[appendString:] and -[appendUTF8String:]", - R([s[1] appendUTF8String: "1𝄞"]) && R([s[1] appendString: @"3"]) && - R([s[0] appendString: s[1]]) && [s[0] isEqual: @"täs€1𝄞3"]) + R([mutableString2 appendUTF8String: "1𝄞"]) && + R([mutableString2 appendString: @"3"]) && + R([mutableString1 appendString: mutableString2]) && + [mutableString1 isEqual: @"täs€1𝄞3"]) TEST(@"-[appendCharacters:length:]", - R([s[1] appendCharacters: ucstr + 6 - length: 2]) && [s[1] isEqual: @"1𝄞3r🀺"]) - - TEST(@"-[length]", s[0].length == 7) - TEST(@"-[UTF8StringLength]", s[0].UTF8StringLength == 13) - TEST(@"-[hash]", s[0].hash == 0x705583C0) - - TEST(@"-[characterAtIndex:]", [s[0] characterAtIndex: 0] == 't' && - [s[0] characterAtIndex: 1] == 0xE4 && - [s[0] characterAtIndex: 3] == 0x20AC && - [s[0] characterAtIndex: 5] == 0x1D11E) + R([mutableString2 appendCharacters: unicharString + 6 length: 2]) && + [mutableString2 isEqual: @"1𝄞3r🀺"]) + + TEST(@"-[length]", mutableString1.length == 7) + TEST(@"-[UTF8StringLength]", mutableString1.UTF8StringLength == 13) + TEST(@"-[hash]", mutableString1.hash == 0x705583C0) + + TEST(@"-[characterAtIndex:]", + [mutableString1 characterAtIndex: 0] == 't' && + [mutableString1 characterAtIndex: 1] == 0xE4 && + [mutableString1 characterAtIndex: 3] == 0x20AC && + [mutableString1 characterAtIndex: 5] == 0x1D11E) EXPECT_EXCEPTION(@"Detect out of range in -[characterAtIndex:]", - OFOutOfRangeException, [s[0] characterAtIndex: 7]) + OFOutOfRangeException, [mutableString1 characterAtIndex: 7]) - TEST(@"-[reverse]", R([s[0] reverse]) && [s[0] isEqual: @"3𝄞1€sät"]) + TEST(@"-[reverse]", + R([mutableString1 reverse]) && [mutableString1 isEqual: @"3𝄞1€sät"]) - s[1] = [mutableStringClass stringWithString: @"abc"]; + mutableString2 = [mutableStringClass stringWithString: @"abc"]; #ifdef OF_HAVE_UNICODE_TABLES - TEST(@"-[uppercase]", R([s[0] uppercase]) && - [s[0] isEqual: @"3𝄞1€SÄT"] && - R([s[1] uppercase]) && [s[1] isEqual: @"ABC"]) + TEST(@"-[uppercase]", R([mutableString1 uppercase]) && + [mutableString1 isEqual: @"3𝄞1€SÄT"] && + R([mutableString2 uppercase]) && [mutableString2 isEqual: @"ABC"]) - TEST(@"-[lowercase]", R([s[0] lowercase]) && - [s[0] isEqual: @"3𝄞1€sät"] && - R([s[1] lowercase]) && [s[1] isEqual: @"abc"]) + TEST(@"-[lowercase]", R([mutableString1 lowercase]) && + [mutableString1 isEqual: @"3𝄞1€sät"] && + R([mutableString2 lowercase]) && [mutableString2 isEqual: @"abc"]) TEST(@"-[uppercaseString]", - [[s[0] uppercaseString] isEqual: @"3𝄞1€SÄT"]) + [[mutableString1 uppercaseString] isEqual: @"3𝄞1€SÄT"]) - TEST(@"-[lowercaseString]", R([s[0] uppercase]) && - [[s[0] lowercaseString] isEqual: @"3𝄞1€sät"]) + TEST(@"-[lowercaseString]", R([mutableString1 uppercase]) && + [[mutableString1 lowercaseString] isEqual: @"3𝄞1€sät"]) TEST(@"-[capitalizedString]", [C(@"džbla tdžst TDŽST").capitalizedString isEqual: @"Džbla Tdžst Tdžst"]) #else - TEST(@"-[uppercase]", R([s[0] uppercase]) && - [s[0] isEqual: @"3𝄞1€SäT"] && - R([s[1] uppercase]) && [s[1] isEqual: @"ABC"]) - - TEST(@"-[lowercase]", R([s[0] lowercase]) && - [s[0] isEqual: @"3𝄞1€sät"] && - R([s[1] lowercase]) && [s[1] isEqual: @"abc"]) - - TEST(@"-[uppercaseString]", [s[0].uppercaseString isEqual: @"3𝄞1€SäT"]) - - TEST(@"-[lowercaseString]", R([s[0] uppercase]) && - [s[0].lowercaseString isEqual: @"3𝄞1€sät"]) + TEST(@"-[uppercase]", R([mutableString1 uppercase]) && + [mutableString1 isEqual: @"3𝄞1€SäT"] && + R([mutableString2 uppercase]) && [mutableString2 isEqual: @"ABC"]) + + TEST(@"-[lowercase]", R([mutableString1 lowercase]) && + [mutableString1 isEqual: @"3𝄞1€sät"] && + R([mutableString2 lowercase]) && [mutableString2 isEqual: @"abc"]) + + TEST(@"-[uppercaseString]", + [mutableString1.uppercaseString isEqual: @"3𝄞1€SäT"]) + + TEST(@"-[lowercaseString]", + R([mutableString1 uppercase]) && + [mutableString1.lowercaseString isEqual: @"3𝄞1€sät"]) TEST(@"-[capitalizedString]", [C(@"džbla tdžst TDŽST").capitalizedString isEqual: @"džbla Tdžst TDŽst"]) #endif TEST(@"+[stringWithUTF8String:length:]", - (s[0] = [mutableStringClass stringWithUTF8String: "\xEF\xBB\xBF" - "foobar" - length: 6]) && - [s[0] isEqual: @"foo"]) + (mutableString1 = [mutableStringClass + stringWithUTF8String: "\xEF\xBB\xBF" "foobar" + length: 6]) && + [mutableString1 isEqual: @"foo"]) TEST(@"+[stringWithUTF16String:]", - (is = [stringClass stringWithUTF16String: utf16str]) && - [is isEqual: @"fööbär🀺"] && - (is = [stringClass stringWithUTF16String: sutf16str]) && - [is isEqual: @"fööbär🀺"]) + (string = [stringClass stringWithUTF16String: char16String]) && + [string isEqual: @"fööbär🀺"] && + (string = [stringClass stringWithUTF16String: + swappedChar16String]) && [string isEqual: @"fööbär🀺"]) TEST(@"+[stringWithUTF32String:]", - (is = [stringClass stringWithUTF32String: ucstr]) && - [is isEqual: @"fööbär🀺"] && - (is = [stringClass stringWithUTF32String: sucstr]) && - [is isEqual: @"fööbär🀺"]) + (string = [stringClass stringWithUTF32String: unicharString]) && + [string isEqual: @"fööbär🀺"] && + (string = [stringClass stringWithUTF32String: + swappedUnicharString]) && [string isEqual: @"fööbär🀺"]) #ifdef OF_HAVE_FILES - TEST(@"+[stringWithContentsOfFile:encoding]", (is = [stringClass + TEST(@"+[stringWithContentsOfFile:encoding]", (string = [stringClass stringWithContentsOfFile: @"testfile.txt" - encoding: OF_STRING_ENCODING_ISO_8859_1]) && - [is isEqual: @"testäöü"]) + encoding: OFStringEncodingISO8859_1]) && + [string isEqual: @"testäöü"]) - TEST(@"+[stringWithContentsOfURL:encoding]", (is = [stringClass + TEST(@"+[stringWithContentsOfURL:encoding]", (string = [stringClass stringWithContentsOfURL: [OFURL fileURLWithPath: @"testfile.txt"] - encoding: OF_STRING_ENCODING_ISO_8859_1]) && - [is isEqual: @"testäöü"]) + encoding: OFStringEncodingISO8859_1]) && + [string isEqual: @"testäöü"]) #endif TEST(@"-[appendUTFString:length:]", - R([s[0] appendUTF8String: "\xEF\xBB\xBF" "barqux" - length: 6]) && [s[0] isEqual: @"foobar"]) + R([mutableString1 appendUTF8String: "\xEF\xBB\xBF" "barqux" + length: 6]) && + [mutableString1 isEqual: @"foobar"]) EXPECT_EXCEPTION(@"Detection of invalid UTF-8 encoding #1", OFInvalidEncodingException, [stringClass stringWithUTF8String: "\xE0\x80"]) EXPECT_EXCEPTION(@"Detection of invalid UTF-8 encoding #2", @@ -368,174 +378,173 @@ OFInvalidEncodingException, [stringClass stringWithUTF8String: "\xF0\x80\x80\xC0"]) TEST(@"Conversion of ISO 8859-1 to Unicode", [[stringClass stringWithCString: "\xE4\xF6\xFC" - encoding: OF_STRING_ENCODING_ISO_8859_1] + encoding: OFStringEncodingISO8859_1] isEqual: @"äöü"]) #ifdef HAVE_ISO_8859_15 TEST(@"Conversion of ISO 8859-15 to Unicode", [[stringClass stringWithCString: "\xA4\xA6\xA8\xB4\xB8\xBC\xBD\xBE" - encoding: OF_STRING_ENCODING_ISO_8859_15] + encoding: OFStringEncodingISO8859_15] isEqual: @"€ŠšŽžŒœŸ"]) #endif #ifdef HAVE_WINDOWS_1252 TEST(@"Conversion of Windows 1252 to Unicode", [[stringClass stringWithCString: "\x80\x82\x83\x84\x85\x86\x87\x88" "\x89\x8A\x8B\x8C\x8E\x91\x92\x93" "\x94\x95\x96\x97\x98\x99\x9A\x9B" "\x9C\x9E\x9F" - encoding: OF_STRING_ENCODING_WINDOWS_1252] + encoding: OFStringEncodingWindows1252] isEqual: @"€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ"]) #endif #ifdef HAVE_CODEPAGE_437 TEST(@"Conversion of Codepage 437 to Unicode", [[stringClass stringWithCString: "\xB0\xB1\xB2\xDB" - encoding: OF_STRING_ENCODING_CODEPAGE_437] + encoding: OFStringEncodingCodepage437] isEqual: @"░▒▓█"]) #endif TEST(@"Conversion of Unicode to ASCII #1", !strcmp([C(@"This is a test") cStringWithEncoding: - OF_STRING_ENCODING_ASCII], "This is a test")) + OFStringEncodingASCII], "This is a test")) EXPECT_EXCEPTION(@"Conversion of Unicode to ASCII #2", OFInvalidEncodingException, [C(@"This is a tést") - cStringWithEncoding: OF_STRING_ENCODING_ASCII]) + cStringWithEncoding: OFStringEncodingASCII]) TEST(@"Conversion of Unicode to ISO-8859-1 #1", !strcmp([C(@"This is ä test") cStringWithEncoding: - OF_STRING_ENCODING_ISO_8859_1], "This is \xE4 test")) + OFStringEncodingISO8859_1], "This is \xE4 test")) EXPECT_EXCEPTION(@"Conversion of Unicode to ISO-8859-1 #2", OFInvalidEncodingException, [C(@"This is ä t€st") cStringWithEncoding: - OF_STRING_ENCODING_ISO_8859_1]) + OFStringEncodingISO8859_1]) #ifdef HAVE_ISO_8859_15 TEST(@"Conversion of Unicode to ISO-8859-15 #1", !strcmp([C(@"This is ä t€st") cStringWithEncoding: - OF_STRING_ENCODING_ISO_8859_15], "This is \xE4 t\xA4st")) + OFStringEncodingISO8859_15], "This is \xE4 t\xA4st")) EXPECT_EXCEPTION(@"Conversion of Unicode to ISO-8859-15 #2", OFInvalidEncodingException, [C(@"This is ä t€st…") cStringWithEncoding: - OF_STRING_ENCODING_ISO_8859_15]) + OFStringEncodingISO8859_15]) #endif #ifdef HAVE_WINDOWS_1252 TEST(@"Conversion of Unicode to Windows-1252 #1", !strcmp([C(@"This is ä t€st…") cStringWithEncoding: - OF_STRING_ENCODING_WINDOWS_1252], "This is \xE4 t\x80st\x85")) + OFStringEncodingWindows1252], "This is \xE4 t\x80st\x85")) EXPECT_EXCEPTION(@"Conversion of Unicode to Windows-1252 #2", OFInvalidEncodingException, [C(@"This is ä t€st…‼") - cStringWithEncoding: OF_STRING_ENCODING_WINDOWS_1252]) + cStringWithEncoding: OFStringEncodingWindows1252]) #endif #ifdef HAVE_CODEPAGE_437 TEST(@"Conversion of Unicode to Codepage 437 #1", !strcmp([C(@"Tést strîng ░▒▓") cStringWithEncoding: - OF_STRING_ENCODING_CODEPAGE_437], "T\x82st str\x8Cng \xB0\xB1\xB2")) + OFStringEncodingCodepage437], "T\x82st str\x8Cng \xB0\xB1\xB2")) EXPECT_EXCEPTION(@"Conversion of Unicode to Codepage 437 #2", OFInvalidEncodingException, [C(@"T€st strîng ░▒▓") - cStringWithEncoding: OF_STRING_ENCODING_CODEPAGE_437]) + cStringWithEncoding: OFStringEncodingCodepage437]) #endif TEST(@"Lossy conversion of Unicode to ASCII", !strcmp([C(@"This is a tést") lossyCStringWithEncoding: - OF_STRING_ENCODING_ASCII], "This is a t?st")) + OFStringEncodingASCII], "This is a t?st")) TEST(@"Lossy conversion of Unicode to ISO-8859-1", !strcmp([C(@"This is ä t€st") lossyCStringWithEncoding: - OF_STRING_ENCODING_ISO_8859_1], "This is \xE4 t?st")) + OFStringEncodingISO8859_1], "This is \xE4 t?st")) #ifdef HAVE_ISO_8859_15 TEST(@"Lossy conversion of Unicode to ISO-8859-15", !strcmp([C(@"This is ä t€st…") lossyCStringWithEncoding: - OF_STRING_ENCODING_ISO_8859_15], "This is \xE4 t\xA4st?")) + OFStringEncodingISO8859_15], "This is \xE4 t\xA4st?")) #endif #ifdef HAVE_WINDOWS_1252 TEST(@"Lossy conversion of Unicode to Windows-1252", !strcmp([C(@"This is ä t€st…‼") lossyCStringWithEncoding: - OF_STRING_ENCODING_WINDOWS_1252], "This is \xE4 t\x80st\x85?")) + OFStringEncodingWindows1252], "This is \xE4 t\x80st\x85?")) #endif #ifdef HAVE_CODEPAGE_437 TEST(@"Lossy conversion of Unicode to Codepage 437", !strcmp([C(@"T€st strîng ░▒▓") lossyCStringWithEncoding: - OF_STRING_ENCODING_CODEPAGE_437], "T?st str\x8Cng \xB0\xB1\xB2")) + OFStringEncodingCodepage437], "T?st str\x8Cng \xB0\xB1\xB2")) #endif TEST(@"+[stringWithFormat:]", - [(s[0] = [mutableStringClass stringWithFormat: @"%@:%d", @"test", - 123]) + [(mutableString1 = [mutableStringClass stringWithFormat: @"%@:%d", + @"test", + 123]) isEqual: @"test:123"]) TEST(@"-[appendFormat:]", - R(([s[0] appendFormat: @"%02X", 15])) && - [s[0] isEqual: @"test:1230F"]) + R(([mutableString1 appendFormat: @"%02X", 15])) && + [mutableString1 isEqual: @"test:1230F"]) TEST(@"-[rangeOfString:]", [C(@"𝄞öö") rangeOfString: @"öö"].location == 1 && [C(@"𝄞öö") rangeOfString: @"ö"].location == 1 && [C(@"𝄞öö") rangeOfString: @"𝄞"].location == 0 && - [C(@"𝄞öö") rangeOfString: @"x"].location == OF_NOT_FOUND && + [C(@"𝄞öö") rangeOfString: @"x"].location == OFNotFound && [C(@"𝄞öö") rangeOfString: @"öö" - options: OF_STRING_SEARCH_BACKWARDS].location == 1 && + options: OFStringSearchBackwards].location == 1 && [C(@"𝄞öö") rangeOfString: @"ö" - options: OF_STRING_SEARCH_BACKWARDS].location == 2 && + options: OFStringSearchBackwards].location == 2 && [C(@"𝄞öö") rangeOfString: @"𝄞" - options: OF_STRING_SEARCH_BACKWARDS].location == 0 && + options: OFStringSearchBackwards].location == 0 && [C(@"𝄞öö") rangeOfString: @"x" - options: OF_STRING_SEARCH_BACKWARDS].location == OF_NOT_FOUND) + options: OFStringSearchBackwards].location == OFNotFound) EXPECT_EXCEPTION( @"Detect out of range in -[rangeOfString:options:range:]", OFOutOfRangeException, - [C(@"𝄞öö") rangeOfString: @"ö" - options: 0 - range: of_range(3, 1)]) + [C(@"𝄞öö") rangeOfString: @"ö" options: 0 range: OFRangeMake(3, 1)]) - cs = [OFCharacterSet characterSetWithCharactersInString: @"cđ"]; + characterSet = + [OFCharacterSet characterSetWithCharactersInString: @"cđ"]; TEST(@"-[indexOfCharacterFromSet:]", - [C(@"abcđabcđe") indexOfCharacterFromSet: cs] == 2 && - [C(@"abcđabcđë") - indexOfCharacterFromSet: cs - options: OF_STRING_SEARCH_BACKWARDS] == 7 && - [C(@"abcđabcđë") - indexOfCharacterFromSet: cs - options: 0 - range: of_range(4, 4)] == 6 && - [C(@"abcđabcđëf") - indexOfCharacterFromSet: cs - options: 0 - range: of_range(8, 2)] == OF_NOT_FOUND) + [C(@"abcđabcđe") indexOfCharacterFromSet: characterSet] == 2 && + [C(@"abcđabcđë") + indexOfCharacterFromSet: characterSet + options: OFStringSearchBackwards] == 7 && + [C(@"abcđabcđë") indexOfCharacterFromSet: characterSet + options: 0 + range: OFRangeMake(4, 4)] == 6 && + [C(@"abcđabcđëf") + indexOfCharacterFromSet: characterSet + options: 0 + range: OFRangeMake(8, 2)] == OFNotFound) EXPECT_EXCEPTION( @"Detect out of range in -[indexOfCharacterFromSet:options:range:]", OFOutOfRangeException, - [C(@"𝄞öö") indexOfCharacterFromSet: cs + [C(@"𝄞öö") indexOfCharacterFromSet: characterSet options: 0 - range: of_range(3, 1)]) + range: OFRangeMake(3, 1)]) TEST(@"-[substringWithRange:]", - [[C(@"𝄞öö") substringWithRange: of_range(1, 1)] isEqual: @"ö"] && - [[C(@"𝄞öö") substringWithRange: of_range(3, 0)] isEqual: @""]) + [[C(@"𝄞öö") substringWithRange: OFRangeMake(1, 1)] isEqual: @"ö"] && + [[C(@"𝄞öö") substringWithRange: OFRangeMake(3, 0)] isEqual: @""]) EXPECT_EXCEPTION(@"Detect out of range in -[substringWithRange:] #1", OFOutOfRangeException, - [C(@"𝄞öö") substringWithRange: of_range(2, 2)]) + [C(@"𝄞öö") substringWithRange: OFRangeMake(2, 2)]) EXPECT_EXCEPTION(@"Detect out of range in -[substringWithRange:] #2", OFOutOfRangeException, - [C(@"𝄞öö") substringWithRange: of_range(4, 0)]) + [C(@"𝄞öö") substringWithRange: OFRangeMake(4, 0)]) TEST(@"-[stringByAppendingString:]", [[C(@"foo") stringByAppendingString: @"bar"] isEqual: @"foobar"]) TEST(@"-[stringByPrependingString:]", @@ -563,28 +572,30 @@ TEST(@"-[isAbsolutePath]", C(@"/foo").absolutePath && C(@"/foo/bar").absolutePath && !C(@"foo/bar").absolutePath && !C(@"foo").absolutePath) # endif - s[0] = [mutableStringClass stringWithString: @"foo"]; -# if defined(OF_WINDOWS) || defined(OF_MSDOS) - [s[0] appendString: @"\\"]; -# else - [s[0] appendString: @"/"]; -# endif - [s[0] appendString: @"bar"]; - s[1] = [mutableStringClass stringWithString: s[0]]; -# if defined(OF_WINDOWS) || defined(OF_MSDOS) - [s[1] appendString: @"\\"]; -# else - [s[1] appendString: @"/"]; -# endif - is = [stringClass stringWithString: s[1]]; - [s[1] appendString: @"baz"]; - TEST(@"-[stringByAppendingPathComponent:]", - [[s[0] stringByAppendingPathComponent: @"baz"] isEqual: s[1]] && - [[is stringByAppendingPathComponent: @"baz"] isEqual: s[1]]) + mutableString1 = [mutableStringClass stringWithString: @"foo"]; +# if defined(OF_WINDOWS) || defined(OF_MSDOS) + [mutableString1 appendString: @"\\"]; +# else + [mutableString1 appendString: @"/"]; +# endif + [mutableString1 appendString: @"bar"]; + mutableString2 = [mutableStringClass stringWithString: mutableString1]; +# if defined(OF_WINDOWS) || defined(OF_MSDOS) + [mutableString2 appendString: @"\\"]; +# else + [mutableString2 appendString: @"/"]; +# endif + string = [stringClass stringWithString: mutableString2]; + [mutableString2 appendString: @"baz"]; + TEST(@"-[stringByAppendingPathComponent:]", + [[mutableString1 stringByAppendingPathComponent: @"baz"] + isEqual: mutableString2] && + [[string stringByAppendingPathComponent: @"baz"] + isEqual: mutableString2]) #endif TEST(@"-[hasPrefix:]", [C(@"foobar") hasPrefix: @"foo"] && ![C(@"foobar") hasPrefix: @"foobar0"]) @@ -591,58 +602,62 @@ TEST(@"-[hasSuffix:]", [C(@"foobar") hasSuffix: @"bar"] && ![C(@"foobar") hasSuffix: @"foobar0"]) i = 0; TEST(@"-[componentsSeparatedByString:]", - (a = [C(@"fooXXbarXXXXbazXXXX") + (array = [C(@"fooXXbarXXXXbazXXXX") componentsSeparatedByString: @"XX"]) && - [[a objectAtIndex: i++] isEqual: @"foo"] && - [[a objectAtIndex: i++] isEqual: @"bar"] && - [[a objectAtIndex: i++] isEqual: @""] && - [[a objectAtIndex: i++] isEqual: @"baz"] && - [[a objectAtIndex: i++] isEqual: @""] && - [[a objectAtIndex: i++] isEqual: @""] && - a.count == i) + [[array objectAtIndex: i++] isEqual: @"foo"] && + [[array objectAtIndex: i++] isEqual: @"bar"] && + [[array objectAtIndex: i++] isEqual: @""] && + [[array objectAtIndex: i++] isEqual: @"baz"] && + [[array objectAtIndex: i++] isEqual: @""] && + [[array objectAtIndex: i++] isEqual: @""] && + array.count == i && + (array = [C(@"foo") componentsSeparatedByString: @""]) && + [[array objectAtIndex: 0] isEqual: @"foo"] && + array.count == 1) i = 0; TEST(@"-[componentsSeparatedByString:options:]", - (a = [C(@"fooXXbarXXXXbazXXXX") + (array = [C(@"fooXXbarXXXXbazXXXX") componentsSeparatedByString: @"XX" - options: OF_STRING_SKIP_EMPTY]) && - [[a objectAtIndex: i++] isEqual: @"foo"] && - [[a objectAtIndex: i++] isEqual: @"bar"] && - [[a objectAtIndex: i++] isEqual: @"baz"] && - a.count == i) + options: OFStringSkipEmptyComponents]) && + [[array objectAtIndex: i++] isEqual: @"foo"] && + [[array objectAtIndex: i++] isEqual: @"bar"] && + [[array objectAtIndex: i++] isEqual: @"baz"] && + array.count == i) - cs = [OFCharacterSet characterSetWithCharactersInString: @"XYZ"]; + characterSet = + [OFCharacterSet characterSetWithCharactersInString: @"XYZ"]; i = 0; TEST(@"-[componentsSeparatedByCharactersInSet:]", - (a = [C(@"fooXYbarXYZXbazXYXZx") - componentsSeparatedByCharactersInSet: cs]) && - [[a objectAtIndex: i++] isEqual: @"foo"] && - [[a objectAtIndex: i++] isEqual: @""] && - [[a objectAtIndex: i++] isEqual: @"bar"] && - [[a objectAtIndex: i++] isEqual: @""] && - [[a objectAtIndex: i++] isEqual: @""] && - [[a objectAtIndex: i++] isEqual: @""] && - [[a objectAtIndex: i++] isEqual: @"baz"] && - [[a objectAtIndex: i++] isEqual: @""] && - [[a objectAtIndex: i++] isEqual: @""] && - [[a objectAtIndex: i++] isEqual: @""] && - [[a objectAtIndex: i++] isEqual: @"x"] && - a.count == i) + (array = [C(@"fooXYbarXYZXbazXYXZx") + componentsSeparatedByCharactersInSet: characterSet]) && + [[array objectAtIndex: i++] isEqual: @"foo"] && + [[array objectAtIndex: i++] isEqual: @""] && + [[array objectAtIndex: i++] isEqual: @"bar"] && + [[array objectAtIndex: i++] isEqual: @""] && + [[array objectAtIndex: i++] isEqual: @""] && + [[array objectAtIndex: i++] isEqual: @""] && + [[array objectAtIndex: i++] isEqual: @"baz"] && + [[array objectAtIndex: i++] isEqual: @""] && + [[array objectAtIndex: i++] isEqual: @""] && + [[array objectAtIndex: i++] isEqual: @""] && + [[array objectAtIndex: i++] isEqual: @"x"] && + array.count == i) i = 0; TEST(@"-[componentsSeparatedByCharactersInSet:options:]", - (a = [C(@"fooXYbarXYZXbazXYXZ") - componentsSeparatedByCharactersInSet: cs - options: OF_STRING_SKIP_EMPTY]) && - [[a objectAtIndex: i++] isEqual: @"foo"] && - [[a objectAtIndex: i++] isEqual: @"bar"] && - [[a objectAtIndex: i++] isEqual: @"baz"] && - a.count == i) + (array = [C(@"fooXYbarXYZXbazXYXZ") + componentsSeparatedByCharactersInSet: characterSet + options: OFStringSkipEmptyComponents]) && + [[array objectAtIndex: i++] isEqual: @"foo"] && + [[array objectAtIndex: i++] isEqual: @"bar"] && + [[array objectAtIndex: i++] isEqual: @"baz"] && + array.count == i) #ifdef OF_HAVE_FILES # if defined(OF_WINDOWS) TEST(@"+[pathWithComponents:]", [[stringClass pathWithComponents: [OFArray arrayWithObjects: @@ -743,151 +758,151 @@ # endif # if defined(OF_WINDOWS) TEST(@"-[pathComponents]", /* c:/tmp */ - (a = C(@"c:/tmp").pathComponents) && a.count == 2 && - [[a objectAtIndex: 0] isEqual: @"c:/"] && - [[a objectAtIndex: 1] isEqual: @"tmp"] && + (array = C(@"c:/tmp").pathComponents) && array.count == 2 && + [[array objectAtIndex: 0] isEqual: @"c:/"] && + [[array objectAtIndex: 1] isEqual: @"tmp"] && /* c:\tmp\ */ - (a = C(@"c:\\tmp\\").pathComponents) && a.count == 2 && - [[a objectAtIndex: 0] isEqual: @"c:\\"] && - [[a objectAtIndex: 1] isEqual: @"tmp"] && + (array = C(@"c:\\tmp\\").pathComponents) && array.count == 2 && + [[array objectAtIndex: 0] isEqual: @"c:\\"] && + [[array objectAtIndex: 1] isEqual: @"tmp"] && /* c:\ */ - (a = C(@"c:\\").pathComponents) && a.count == 1 && - [[a objectAtIndex: 0] isEqual: @"c:\\"] && + (array = C(@"c:\\").pathComponents) && array.count == 1 && + [[array objectAtIndex: 0] isEqual: @"c:\\"] && /* c:/ */ - (a = C(@"c:/").pathComponents) && a.count == 1 && - [[a objectAtIndex: 0] isEqual: @"c:/"] && + (array = C(@"c:/").pathComponents) && array.count == 1 && + [[array objectAtIndex: 0] isEqual: @"c:/"] && /* c: */ - (a = C(@"c:").pathComponents) && a.count == 1 && - [[a objectAtIndex: 0] isEqual: @"c:"] && + (array = C(@"c:").pathComponents) && array.count == 1 && + [[array objectAtIndex: 0] isEqual: @"c:"] && /* foo\bar */ - (a = C(@"foo\\bar").pathComponents) && a.count == 2 && - [[a objectAtIndex: 0] isEqual: @"foo"] && - [[a objectAtIndex: 1] isEqual: @"bar"] && + (array = C(@"foo\\bar").pathComponents) && array.count == 2 && + [[array objectAtIndex: 0] isEqual: @"foo"] && + [[array objectAtIndex: 1] isEqual: @"bar"] && /* foo\bar/baz/ */ - (a = C(@"foo\\bar/baz/").pathComponents) && a.count == 3 && - [[a objectAtIndex: 0] isEqual: @"foo"] && - [[a objectAtIndex: 1] isEqual: @"bar"] && - [[a objectAtIndex: 2] isEqual: @"baz"] && + (array = C(@"foo\\bar/baz/").pathComponents) && array.count == 3 && + [[array objectAtIndex: 0] isEqual: @"foo"] && + [[array objectAtIndex: 1] isEqual: @"bar"] && + [[array objectAtIndex: 2] isEqual: @"baz"] && /* foo\/ */ - (a = C(@"foo\\/").pathComponents) && a.count == 1 && - [[a objectAtIndex: 0] isEqual: @"foo"] && + (array = C(@"foo\\/").pathComponents) && array.count == 1 && + [[array objectAtIndex: 0] isEqual: @"foo"] && /* \\foo\bar */ - (a = C(@"\\\\foo\\bar").pathComponents) && a.count == 3 && - [[a objectAtIndex: 0] isEqual: @"\\\\"] && - [[a objectAtIndex: 1] isEqual: @"foo"] && - [[a objectAtIndex: 2] isEqual: @"bar"] && + (array = C(@"\\\\foo\\bar").pathComponents) && array.count == 3 && + [[array objectAtIndex: 0] isEqual: @"\\\\"] && + [[array objectAtIndex: 1] isEqual: @"foo"] && + [[array objectAtIndex: 2] isEqual: @"bar"] && C(@"").pathComponents.count == 0) # elif defined(OF_MSDOS) TEST(@"-[pathComponents]", /* c:/tmp */ - (a = C(@"c:/tmp").pathComponents) && a.count == 2 && - [[a objectAtIndex: 0] isEqual: @"c:/"] && - [[a objectAtIndex: 1] isEqual: @"tmp"] && + (array = C(@"c:/tmp").pathComponents) && array.count == 2 && + [[array objectAtIndex: 0] isEqual: @"c:/"] && + [[array objectAtIndex: 1] isEqual: @"tmp"] && /* c:\tmp\ */ - (a = C(@"c:\\tmp\\").pathComponents) && a.count == 2 && - [[a objectAtIndex: 0] isEqual: @"c:\\"] && - [[a objectAtIndex: 1] isEqual: @"tmp"] && + (array = C(@"c:\\tmp\\").pathComponents) && array.count == 2 && + [[array objectAtIndex: 0] isEqual: @"c:\\"] && + [[array objectAtIndex: 1] isEqual: @"tmp"] && /* c:\ */ - (a = C(@"c:\\").pathComponents) && a.count == 1 && - [[a objectAtIndex: 0] isEqual: @"c:\\"] && + (array = C(@"c:\\").pathComponents) && array.count == 1 && + [[array objectAtIndex: 0] isEqual: @"c:\\"] && /* c:/ */ - (a = C(@"c:/").pathComponents) && a.count == 1 && - [[a objectAtIndex: 0] isEqual: @"c:/"] && + (array = C(@"c:/").pathComponents) && array.count == 1 && + [[array objectAtIndex: 0] isEqual: @"c:/"] && /* c: */ - (a = C(@"c:").pathComponents) && a.count == 1 && - [[a objectAtIndex: 0] isEqual: @"c:"] && + (array = C(@"c:").pathComponents) && array.count == 1 && + [[array objectAtIndex: 0] isEqual: @"c:"] && /* foo\bar */ - (a = C(@"foo\\bar").pathComponents) && a.count == 2 && - [[a objectAtIndex: 0] isEqual: @"foo"] && - [[a objectAtIndex: 1] isEqual: @"bar"] && + (array = C(@"foo\\bar").pathComponents) && array.count == 2 && + [[array objectAtIndex: 0] isEqual: @"foo"] && + [[array objectAtIndex: 1] isEqual: @"bar"] && /* foo\bar/baz/ */ - (a = C(@"foo\\bar/baz/").pathComponents) && a.count == 3 && - [[a objectAtIndex: 0] isEqual: @"foo"] && - [[a objectAtIndex: 1] isEqual: @"bar"] && - [[a objectAtIndex: 2] isEqual: @"baz"] && + (array = C(@"foo\\bar/baz/").pathComponents) && array.count == 3 && + [[array objectAtIndex: 0] isEqual: @"foo"] && + [[array objectAtIndex: 1] isEqual: @"bar"] && + [[array objectAtIndex: 2] isEqual: @"baz"] && /* foo\/ */ - (a = C(@"foo\\/").pathComponents) && a.count == 1 && - [[a objectAtIndex: 0] isEqual: @"foo"] && + (array = C(@"foo\\/").pathComponents) && array.count == 1 && + [[array objectAtIndex: 0] isEqual: @"foo"] && C(@"").pathComponents.count == 0) # elif defined(OF_AMIGAOS) TEST(@"-[pathComponents]", /* dh0:tmp */ - (a = C(@"dh0:tmp").pathComponents) && a.count == 2 && - [[a objectAtIndex: 0] isEqual: @"dh0:"] && - [[a objectAtIndex: 1] isEqual: @"tmp"] && + (array = C(@"dh0:tmp").pathComponents) && array.count == 2 && + [[array objectAtIndex: 0] isEqual: @"dh0:"] && + [[array objectAtIndex: 1] isEqual: @"tmp"] && /* dh0:tmp/ */ - (a = C(@"dh0:tmp/").pathComponents) && a.count == 2 && - [[a objectAtIndex: 0] isEqual: @"dh0:"] && - [[a objectAtIndex: 1] isEqual: @"tmp"] && + (array = C(@"dh0:tmp/").pathComponents) && array.count == 2 && + [[array objectAtIndex: 0] isEqual: @"dh0:"] && + [[array objectAtIndex: 1] isEqual: @"tmp"] && /* dh0: */ - (a = C(@"dh0:/").pathComponents) && a.count == 2 && - [[a objectAtIndex: 0] isEqual: @"dh0:"] && - [[a objectAtIndex: 1] isEqual: @"/"] && + (array = C(@"dh0:/").pathComponents) && array.count == 2 && + [[array objectAtIndex: 0] isEqual: @"dh0:"] && + [[array objectAtIndex: 1] isEqual: @"/"] && /* foo/bar */ - (a = C(@"foo/bar").pathComponents) && a.count == 2 && - [[a objectAtIndex: 0] isEqual: @"foo"] && - [[a objectAtIndex: 1] isEqual: @"bar"] && + (array = C(@"foo/bar").pathComponents) && array.count == 2 && + [[array objectAtIndex: 0] isEqual: @"foo"] && + [[array objectAtIndex: 1] isEqual: @"bar"] && /* foo/bar/baz/ */ - (a = C(@"foo/bar/baz/").pathComponents) && a.count == 3 && - [[a objectAtIndex: 0] isEqual: @"foo"] && - [[a objectAtIndex: 1] isEqual: @"bar"] && - [[a objectAtIndex: 2] isEqual: @"baz"] && + (array = C(@"foo/bar/baz/").pathComponents) && array.count == 3 && + [[array objectAtIndex: 0] isEqual: @"foo"] && + [[array objectAtIndex: 1] isEqual: @"bar"] && + [[array objectAtIndex: 2] isEqual: @"baz"] && /* foo// */ - (a = C(@"foo//").pathComponents) && a.count == 2 && - [[a objectAtIndex: 0] isEqual: @"foo"] && - [[a objectAtIndex: 1] isEqual: @"/"] && + (array = C(@"foo//").pathComponents) && array.count == 2 && + [[array objectAtIndex: 0] isEqual: @"foo"] && + [[array objectAtIndex: 1] isEqual: @"/"] && C(@"").pathComponents.count == 0) # elif defined(OF_NINTENDO_3DS) || defined(OF_WII) TEST(@"-[pathComponents]", /* sdmc:/tmp */ - (a = C(@"sdmc:/tmp").pathComponents) && a.count == 2 && - [[a objectAtIndex: 0] isEqual: @"sdmc:"] && - [[a objectAtIndex: 1] isEqual: @"tmp"] && + (array = C(@"sdmc:/tmp").pathComponents) && array.count == 2 && + [[array objectAtIndex: 0] isEqual: @"sdmc:"] && + [[array objectAtIndex: 1] isEqual: @"tmp"] && /* sdmc:/ */ - (a = C(@"sdmc:/").pathComponents) && a.count == 1 && - [[a objectAtIndex: 0] isEqual: @"sdmc:"] && + (array = C(@"sdmc:/").pathComponents) && array.count == 1 && + [[array objectAtIndex: 0] isEqual: @"sdmc:"] && /* foo/bar */ - (a = C(@"foo/bar").pathComponents) && a.count == 2 && - [[a objectAtIndex: 0] isEqual: @"foo"] && - [[a objectAtIndex: 1] isEqual: @"bar"] && + (array = C(@"foo/bar").pathComponents) && array.count == 2 && + [[array objectAtIndex: 0] isEqual: @"foo"] && + [[array objectAtIndex: 1] isEqual: @"bar"] && /* foo/bar/baz/ */ - (a = C(@"foo/bar/baz/").pathComponents) && a.count == 3 && - [[a objectAtIndex: 0] isEqual: @"foo"] && - [[a objectAtIndex: 1] isEqual: @"bar"] && - [[a objectAtIndex: 2] isEqual: @"baz"] && + (array = C(@"foo/bar/baz/").pathComponents) && array.count == 3 && + [[array objectAtIndex: 0] isEqual: @"foo"] && + [[array objectAtIndex: 1] isEqual: @"bar"] && + [[array objectAtIndex: 2] isEqual: @"baz"] && /* foo// */ - (a = C(@"foo//").pathComponents) && a.count == 1 && - [[a objectAtIndex: 0] isEqual: @"foo"] && + (array = C(@"foo//").pathComponents) && array.count == 1 && + [[array objectAtIndex: 0] isEqual: @"foo"] && C(@"").pathComponents.count == 0) # else TEST(@"-[pathComponents]", /* /tmp */ - (a = C(@"/tmp").pathComponents) && a.count == 2 && - [[a objectAtIndex: 0] isEqual: @"/"] && - [[a objectAtIndex: 1] isEqual: @"tmp"] && + (array = C(@"/tmp").pathComponents) && array.count == 2 && + [[array objectAtIndex: 0] isEqual: @"/"] && + [[array objectAtIndex: 1] isEqual: @"tmp"] && /* /tmp/ */ - (a = C(@"/tmp/").pathComponents) && a.count == 2 && - [[a objectAtIndex: 0] isEqual: @"/"] && - [[a objectAtIndex: 1] isEqual: @"tmp"] && + (array = C(@"/tmp/").pathComponents) && array.count == 2 && + [[array objectAtIndex: 0] isEqual: @"/"] && + [[array objectAtIndex: 1] isEqual: @"tmp"] && /* / */ - (a = C(@"/").pathComponents) && a.count == 1 && - [[a objectAtIndex: 0] isEqual: @"/"] && + (array = C(@"/").pathComponents) && array.count == 1 && + [[array objectAtIndex: 0] isEqual: @"/"] && /* foo/bar */ - (a = C(@"foo/bar").pathComponents) && a.count == 2 && - [[a objectAtIndex: 0] isEqual: @"foo"] && - [[a objectAtIndex: 1] isEqual: @"bar"] && + (array = C(@"foo/bar").pathComponents) && array.count == 2 && + [[array objectAtIndex: 0] isEqual: @"foo"] && + [[array objectAtIndex: 1] isEqual: @"bar"] && /* foo/bar/baz/ */ - (a = C(@"foo/bar/baz/").pathComponents) && a.count == 3 && - [[a objectAtIndex: 0] isEqual: @"foo"] && - [[a objectAtIndex: 1] isEqual: @"bar"] && - [[a objectAtIndex: 2] isEqual: @"baz"] && + (array = C(@"foo/bar/baz/").pathComponents) && array.count == 3 && + [[array objectAtIndex: 0] isEqual: @"foo"] && + [[array objectAtIndex: 1] isEqual: @"bar"] && + [[array objectAtIndex: 2] isEqual: @"baz"] && /* foo// */ - (a = C(@"foo//").pathComponents) && a.count == 1 && - [[a objectAtIndex: 0] isEqual: @"foo"] && + (array = C(@"foo//").pathComponents) && array.count == 1 && + [[array objectAtIndex: 0] isEqual: @"foo"] && C(@"").pathComponents.count == 0) # endif # if defined(OF_WINDOWS) TEST(@"-[lastPathComponent]", @@ -1074,10 +1089,11 @@ C(@"\r\n+123 ").longLongValue == 123 && C(@"-500\t").longLongValue == -500 && [C(@"-0x10\t") longLongValueWithBase: 0] == -0x10 && C(@"\t\t\r\n").longLongValue == 0 && [C(@"123f") longLongValueWithBase: 16] == 0x123f && + [C(@"-1234") longLongValueWithBase: 0] == -1234 && [C(@"\t\n0xABcd\r") longLongValueWithBase: 0] == 0xABCD && [C(@"1234567") longLongValueWithBase: 8] == 01234567 && [C(@"\r\n0123") longLongValueWithBase: 0] == 0123 && [C(@"765\t") longLongValueWithBase: 8] == 0765 && [C(@"\t\t\r\n") longLongValueWithBase: 8] == 0) @@ -1085,10 +1101,11 @@ TEST(@"-[unsignedLongLongValue]", C(@"1234").unsignedLongLongValue == 1234 && C(@"\r\n+123 ").unsignedLongLongValue == 123 && C(@"\t\t\r\n").unsignedLongLongValue == 0 && [C(@"123f") unsignedLongLongValueWithBase: 16] == 0x123f && + [C(@"1234") unsignedLongLongValueWithBase: 0] == 1234 && [C(@"\t\n0xABcd\r") unsignedLongLongValueWithBase: 0] == 0xABCD && [C(@"1234567") unsignedLongLongValueWithBase: 8] == 01234567 && [C(@"\r\n0123") unsignedLongLongValueWithBase: 0] == 0123 && [C(@"765\t") unsignedLongLongValueWithBase: 8] == 0765 && [C(@"\t\t\r\n") unsignedLongLongValueWithBase: 8] == 0) @@ -1099,18 +1116,19 @@ */ TEST(@"-[floatValue]", C(@"\t-0.25 ").floatValue == -0.25 && C(@"\r\n\tINF\t\n").floatValue == INFINITY && C(@"\r -INFINITY\n").floatValue == -INFINITY && - isnan(C(@" NAN\t\t").floatValue)) + isnan(C(@" NAN\t\t").floatValue) && + isnan(C(@" -NaN\t\t").floatValue)) -#if !defined(OF_ANDROID) && !defined(OF_SOLARIS) && !defined(OF_DJGPP) && \ - !defined(OF_AMIGAOS_M68K) +#if !defined(OF_ANDROID) && !defined(OF_SOLARIS) && !defined(OF_HPUX) && \ + !defined(OF_DJGPP) && !defined(OF_AMIGAOS_M68K) # define INPUT @"\t-0x1.FFFFFFFFFFFFFP-1020 " # define EXPECTED -0x1.FFFFFFFFFFFFFP-1020 #else -/* Android, Solaris, DJGPP and AmigaOS3 do not accept 0x for strtod() */ +/* Android, Solaris, HP-UX, DJGPP and AmigaOS 3 do not accept 0x for strtod() */ # if (!defined(OF_SOLARIS) || !defined(OF_X86)) && !defined(OF_AMIGAOS_M68K) # define INPUT @"\t-0.123456789 " # define EXPECTED -0.123456789 # else /* @@ -1177,176 +1195,192 @@ OFOutOfRangeException, [C(@"0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" @"0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF") unsignedLongLongValueWithBase: 16]) - TEST(@"-[characters]", (ua = C(@"fööbär🀺").characters) && - !memcmp(ua, ucstr + 1, sizeof(ucstr) - 8)) + TEST(@"-[characters]", (characters = C(@"fööbär🀺").characters) && + !memcmp(characters, unicharString + 1, sizeof(unicharString) - 8)) #ifdef OF_BIG_ENDIAN -# define SWAPPED_BYTE_ORDER OF_BYTE_ORDER_LITTLE_ENDIAN +# define swappedByteOrder OFByteOrderLittleEndian #else -# define SWAPPED_BYTE_ORDER OF_BYTE_ORDER_BIG_ENDIAN +# define swappedByteOrder OFByteOrderBigEndian #endif - TEST(@"-[UTF16String]", (u16a = C(@"fööbär🀺").UTF16String) && - !memcmp(u16a, utf16str + 1, of_string_utf16_length(utf16str) * 2) && - (u16a = [C(@"fööbär🀺") - UTF16StringWithByteOrder: SWAPPED_BYTE_ORDER]) && - !memcmp(u16a, sutf16str + 1, of_string_utf16_length(sutf16str) * 2)) + TEST(@"-[UTF16String]", (UTF16Characters = C(@"fööbär🀺").UTF16String) && + !memcmp(UTF16Characters, char16String + 1, + OFUTF16StringLength(char16String) * 2) && + (UTF16Characters = [C(@"fööbär🀺") + UTF16StringWithByteOrder: swappedByteOrder]) && + !memcmp(UTF16Characters, swappedChar16String + 1, + OFUTF16StringLength(swappedChar16String) * 2)) TEST(@"-[UTF16StringLength]", C(@"fööbär🀺").UTF16StringLength == 8) - TEST(@"-[UTF32String]", (ua = C(@"fööbär🀺").UTF32String) && - !memcmp(ua, ucstr + 1, of_string_utf32_length(ucstr) * 4) && - (ua = [C(@"fööbär🀺") UTF32StringWithByteOrder: - SWAPPED_BYTE_ORDER]) && - !memcmp(ua, sucstr + 1, of_string_utf32_length(sucstr) * 4)) -#undef SWAPPED_BYTE_ORDER - - TEST(@"-[MD5Hash]", [C(@"asdfoobar").MD5Hash + TEST(@"-[UTF32String]", (characters = C(@"fööbär🀺").UTF32String) && + !memcmp(characters, unicharString + 1, + OFUTF32StringLength(unicharString) * 4) && + (characters = [C(@"fööbär🀺") UTF32StringWithByteOrder: + swappedByteOrder]) && + !memcmp(characters, swappedUnicharString + 1, + OFUTF32StringLength(swappedUnicharString) * 4)) +#undef swappedByteOrder + + TEST(@"-[stringByMD5Hashing]", [C(@"asdfoobar").stringByMD5Hashing isEqual: @"184dce2ec49b5422c7cfd8728864db4c"]) - TEST(@"-[RIPEMD160Hash]", [C(@"asdfoobar").RIPEMD160Hash + TEST(@"-[stringByRIPEMD160Hashing]", + [C(@"asdfoobar").stringByRIPEMD160Hashing isEqual: @"021d773b0fac06eb6755ca6aa58a580c980f7f13"]) - TEST(@"-[SHA1Hash]", [C(@"asdfoobar").SHA1Hash + TEST(@"-[stringBySHA1Hashing]", [C(@"asdfoobar").stringBySHA1Hashing isEqual: @"f5f81ac0a8b5cbfdc4585ec1ad32e7b3a12b9b49"]) - TEST(@"-[SHA224Hash]", [C(@"asdfoobar").SHA224Hash - isEqual: - @"5a06822dcbd5a874f67d062b80b9d8a9cb9b5b303960b9da9290c192"]) - - TEST(@"-[SHA256Hash]", [C(@"asdfoobar").SHA256Hash isEqual: - @"28e65b1dcd7f6ce2ea6277b15f87b913" - @"628b5500bf7913a2bbf4cedcfa1215f6"]) - - TEST(@"-[SHA384Hash]", [C(@"asdfoobar").SHA384Hash isEqual: - @"73286da882ffddca2f45e005cfa6b44f3fc65bfb26db1d08" - @"7ded2f9c279e5addf8be854044bca0cece073fce28eec7d9"]) - - TEST(@"-[SHA512Hash]", [C(@"asdfoobar").SHA512Hash isEqual: - @"0464c427da158b02161bb44a3090bbfc594611ef6a53603640454b56412a9247c" - @"3579a329e53a5dc74676b106755e3394f9454a2d42273242615d32f80437d61"]) - - cs = [OFCharacterSet characterSetWithCharactersInString: @"abfo'_~$🍏"]; + TEST(@"-[stringBySHA224Hashing]", [C(@"asdfoobar").stringBySHA224Hashing + isEqual: @"5a06822dcbd5a874f67d062b80b9d8a9cb9b5b303960b9da9290c192" + ]) + + TEST(@"-[stringBySHA256Hashing]", [C(@"asdfoobar").stringBySHA256Hashing + isEqual: @"28e65b1dcd7f6ce2ea6277b15f87b913628b5500bf7913a2bbf4cedc" + @"fa1215f6"]) + + TEST(@"-[stringBySHA384Hashing]", [C(@"asdfoobar").stringBySHA384Hashing + isEqual: @"73286da882ffddca2f45e005cfa6b44f3fc65bfb26db1d087ded2f9c" + @"279e5addf8be854044bca0cece073fce28eec7d9"]) + + TEST(@"-[stringBySHA512Hashing]", [C(@"asdfoobar").stringBySHA512Hashing + isEqual: @"0464c427da158b02161bb44a3090bbfc594611ef6a53603640454b56" + @"412a9247c3579a329e53a5dc74676b106755e3394f9454a2d4227324" + @"2615d32f80437d61"]) + + characterSet = + [OFCharacterSet characterSetWithCharactersInString: @"abfo'_~$🍏"]; TEST(@"-[stringByURLEncodingWithAllowedCharacters:]", [[C(@"foo\"ba'_~$]🍏🍌") stringByURLEncodingWithAllowedCharacters: - cs] isEqual: @"foo%22ba'_~$%5D🍏%F0%9F%8D%8C"]) + characterSet] isEqual: @"foo%22ba'_~$%5D🍏%F0%9F%8D%8C"]) TEST(@"-[stringByURLDecoding]", [C(@"foo%20bar%22+%24%F0%9F%8D%8C").stringByURLDecoding isEqual: @"foo bar\"+$🍌"]) TEST(@"-[insertString:atIndex:]", - (s[0] = [mutableStringClass stringWithString: @"𝄞öööbä€"]) && - R([s[0] insertString: @"äöü" - atIndex: 3]) && - [s[0] isEqual: @"𝄞ööäöüöbä€"]) + (mutableString1 = [mutableStringClass + stringWithString: @"𝄞öööbä€"]) && + R([mutableString1 insertString: @"äöü" atIndex: 3]) && + [mutableString1 isEqual: @"𝄞ööäöüöbä€"]) EXPECT_EXCEPTION(@"Detect invalid format in -[stringByURLDecoding] " @"#1", OFInvalidFormatException, [C(@"foo%xbar") stringByURLDecoding]) EXPECT_EXCEPTION(@"Detect invalid encoding in -[stringByURLDecoding] " @"#2", OFInvalidEncodingException, [C(@"foo%FFbar") stringByURLDecoding]) TEST(@"-[setCharacter:atIndex:]", - (s[0] = [mutableStringClass stringWithString: @"abäde"]) && - R([s[0] setCharacter: 0xF6 - atIndex: 2]) && - [s[0] isEqual: @"aböde"] && - R([s[0] setCharacter: 'c' - atIndex: 2]) && - [s[0] isEqual: @"abcde"] && - R([s[0] setCharacter: 0x20AC - atIndex: 3]) && - [s[0] isEqual: @"abc€e"] && - R([s[0] setCharacter: 'x' - atIndex: 1]) && - [s[0] isEqual: @"axc€e"]) + (mutableString1 = [mutableStringClass + stringWithString: @"abäde"]) && + R([mutableString1 setCharacter: 0xF6 atIndex: 2]) && + [mutableString1 isEqual: @"aböde"] && + R([mutableString1 setCharacter: 'c' atIndex: 2]) && + [mutableString1 isEqual: @"abcde"] && + R([mutableString1 setCharacter: 0x20AC atIndex: 3]) && + [mutableString1 isEqual: @"abc€e"] && + R([mutableString1 setCharacter: 'x' atIndex: 1]) && + [mutableString1 isEqual: @"axc€e"]) TEST(@"-[deleteCharactersInRange:]", - (s[0] = [mutableStringClass stringWithString: @"𝄞öööbä€"]) && - R([s[0] deleteCharactersInRange: of_range(1, 3)]) && - [s[0] isEqual: @"𝄞bä€"] && - R([s[0] deleteCharactersInRange: of_range(0, 4)]) && - [s[0] isEqual: @""]) + (mutableString1 = [mutableStringClass + stringWithString: @"𝄞öööbä€"]) && + R([mutableString1 deleteCharactersInRange: OFRangeMake(1, 3)]) && + [mutableString1 isEqual: @"𝄞bä€"] && + R([mutableString1 deleteCharactersInRange: OFRangeMake(0, 4)]) && + [mutableString1 isEqual: @""]) TEST(@"-[replaceCharactersInRange:withString:]", - (s[0] = [mutableStringClass stringWithString: @"𝄞öööbä€"]) && - R([s[0] replaceCharactersInRange: of_range(1, 3) - withString: @"äöüß"]) && - [s[0] isEqual: @"𝄞äöüßbä€"] && - R([s[0] replaceCharactersInRange: of_range(4, 2) - withString: @"b"]) && - [s[0] isEqual: @"𝄞äöübä€"] && - R([s[0] replaceCharactersInRange: of_range(0, 7) - withString: @""]) && - [s[0] isEqual: @""]) + (mutableString1 = [mutableStringClass + stringWithString: @"𝄞öööbä€"]) && + R([mutableString1 replaceCharactersInRange: OFRangeMake(1, 3) + withString: @"äöüß"]) && + [mutableString1 isEqual: @"𝄞äöüßbä€"] && + R([mutableString1 replaceCharactersInRange: OFRangeMake(4, 2) + withString: @"b"]) && + [mutableString1 isEqual: @"𝄞äöübä€"] && + R([mutableString1 replaceCharactersInRange: OFRangeMake(0, 7) + withString: @""]) && + [mutableString1 isEqual: @""]) EXPECT_EXCEPTION(@"Detect OoR in -[deleteCharactersInRange:] #1", OFOutOfRangeException, { - s[0] = [mutableStringClass stringWithString: @"𝄞öö"]; - [s[0] deleteCharactersInRange: of_range(2, 2)]; + mutableString1 = [mutableStringClass stringWithString: @"𝄞öö"]; + [mutableString1 deleteCharactersInRange: OFRangeMake(2, 2)]; }) EXPECT_EXCEPTION(@"Detect OoR in -[deleteCharactersInRange:] #2", OFOutOfRangeException, - [s[0] deleteCharactersInRange: of_range(4, 0)]) + [mutableString1 deleteCharactersInRange: OFRangeMake(4, 0)]) EXPECT_EXCEPTION(@"Detect OoR in " @"-[replaceCharactersInRange:withString:] #1", OFOutOfRangeException, - [s[0] replaceCharactersInRange: of_range(2, 2) - withString: @""]) + [mutableString1 replaceCharactersInRange: OFRangeMake(2, 2) + withString: @""]) EXPECT_EXCEPTION(@"Detect OoR in " @"-[replaceCharactersInRange:withString:] #2", OFOutOfRangeException, - [s[0] replaceCharactersInRange: of_range(4, 0) - withString: @""]) + [mutableString1 replaceCharactersInRange: OFRangeMake(4, 0) + withString: @""]) TEST(@"-[replaceOccurrencesOfString:withString:]", - (s[0] = [mutableStringClass stringWithString: + (mutableString1 = [mutableStringClass stringWithString: @"asd fo asd fofo asd"]) && - R([s[0] replaceOccurrencesOfString: @"fo" - withString: @"foo"]) && - [s[0] isEqual: @"asd foo asd foofoo asd"] && - (s[0] = [mutableStringClass stringWithString: @"XX"]) && - R([s[0] replaceOccurrencesOfString: @"X" - withString: @"XX"]) && - [s[0] isEqual: @"XXXX"]) + R([mutableString1 replaceOccurrencesOfString: @"fo" + withString: @"foo"]) && + [mutableString1 isEqual: @"asd foo asd foofoo asd"] && + (mutableString1 = [mutableStringClass stringWithString: @"XX"]) && + R([mutableString1 replaceOccurrencesOfString: @"X" + withString: @"XX"]) && + [mutableString1 isEqual: @"XXXX"]) TEST(@"-[replaceOccurrencesOfString:withString:options:range:]", - (s[0] = [mutableStringClass stringWithString: - @"foofoobarfoobarfoo"]) && - R([s[0] replaceOccurrencesOfString: @"oo" - withString: @"óò" - options: 0 - range: of_range(2, 15)]) && - [s[0] isEqual: @"foofóòbarfóòbarfoo"]) + (mutableString1 = [mutableStringClass stringWithString: + @"foofoobarfoobarfoo"]) && R([mutableString1 + replaceOccurrencesOfString: @"oo" + withString: @"óò" + options: 0 + range: OFRangeMake(2, 15)]) && + [mutableString1 isEqual: @"foofóòbarfóòbarfoo"]) TEST(@"-[deleteLeadingWhitespaces]", - (s[0] = [mutableStringClass stringWithString: whitespace[0]]) && - R([s[0] deleteLeadingWhitespaces]) && - [s[0] isEqual: @"asd \t \t\t\r\n"] && - (s[0] = [mutableStringClass stringWithString: whitespace[1]]) && - R([s[0] deleteLeadingWhitespaces]) && [s[0] isEqual: @""]) + (mutableString1 = [mutableStringClass + stringWithString: whitespace[0]]) && + R([mutableString1 deleteLeadingWhitespaces]) && + [mutableString1 isEqual: @"asd \t \t\t\r\n"] && + (mutableString1 = [mutableStringClass + stringWithString: whitespace[1]]) && + R([mutableString1 deleteLeadingWhitespaces]) && + [mutableString1 isEqual: @""]) TEST(@"-[deleteTrailingWhitespaces]", - (s[0] = [mutableStringClass stringWithString: whitespace[0]]) && - R([s[0] deleteTrailingWhitespaces]) && - [s[0] isEqual: @" \r \t\n\t \tasd"] && - (s[0] = [mutableStringClass stringWithString: whitespace[1]]) && - R([s[0] deleteTrailingWhitespaces]) && [s[0] isEqual: @""]) + (mutableString1 = [mutableStringClass + stringWithString: whitespace[0]]) && + R([mutableString1 deleteTrailingWhitespaces]) && + [mutableString1 isEqual: @" \r \t\n\t \tasd"] && + (mutableString1 = [mutableStringClass + stringWithString: whitespace[1]]) && + R([mutableString1 deleteTrailingWhitespaces]) && + [mutableString1 isEqual: @""]) TEST(@"-[deleteEnclosingWhitespaces]", - (s[0] = [mutableStringClass stringWithString: whitespace[0]]) && - R([s[0] deleteEnclosingWhitespaces]) && [s[0] isEqual: @"asd"] && - (s[0] = [mutableStringClass stringWithString: whitespace[1]]) && - R([s[0] deleteEnclosingWhitespaces]) && [s[0] isEqual: @""]) + (mutableString1 = [mutableStringClass + stringWithString: whitespace[0]]) && + R([mutableString1 deleteEnclosingWhitespaces]) && + [mutableString1 isEqual: @"asd"] && + (mutableString1 = [mutableStringClass + stringWithString: whitespace[1]]) && + R([mutableString1 deleteEnclosingWhitespaces]) && + [mutableString1 isEqual: @""]) #ifdef OF_HAVE_UNICODE_TABLES TEST(@"-[decomposedStringWithCanonicalMapping]", [C(@"H\xC3\xA4llj\xC3\xB6").decomposedStringWithCanonicalMapping isEqual: @"H\x61\xCC\x88llj\x6F\xCC\x88"]); @@ -1355,15 +1389,15 @@ [C(@"H\xC3\xA4llj\xC3\xB6").decomposedStringWithCompatibilityMapping isEqual: @"H\x61\xCC\x88llj\x6F\xCC\x88"]); #endif TEST(@"-[stringByXMLEscaping]", - (is = C(@" &world'\"!&").stringByXMLEscaping) && - [is isEqual: @"<hello> &world'"!&"]) + (string = C(@" &world'\"!&").stringByXMLEscaping) && + [string isEqual: @"<hello> &world'"!&"]) TEST(@"-[stringByXMLUnescaping]", - [is.stringByXMLUnescaping isEqual: @" &world'\"!&"] && + [string.stringByXMLUnescaping isEqual: @" &world'\"!&"] && [C(@"y").stringByXMLUnescaping isEqual: @"y"] && [C(@"ä").stringByXMLUnescaping isEqual: @"ä"] && [C(@"€").stringByXMLUnescaping isEqual: @"€"] && [C(@"𝄞").stringByXMLUnescaping isEqual: @"𝄞"]) @@ -1381,18 +1415,18 @@ EXPECT_EXCEPTION(@"Detect invalid entities in -[stringByXMLUnescaping] " @"#5", OFInvalidFormatException, [C(@"&#xg;") stringByXMLUnescaping]) TEST(@"-[stringByXMLUnescapingWithDelegate:]", - (h = [[[EntityHandler alloc] init] autorelease]) && - [[C(@"x&foo;y") stringByXMLUnescapingWithDelegate: h] + (entityHandler = [[[EntityHandler alloc] init] autorelease]) && + [[C(@"x&foo;y") stringByXMLUnescapingWithDelegate: entityHandler] isEqual: @"xbary"]) #ifdef OF_HAVE_BLOCKS TEST(@"-[stringByXMLUnescapingWithBlock:]", [[C(@"x&foo;y") stringByXMLUnescapingWithBlock: - ^ OFString *(OFString *str, OFString *entity) { + ^ OFString *(OFString *str, OFString *entity) { if ([entity isEqual: @"foo"]) return @"bar"; return nil; }] isEqual: @"xbary"]) Index: tests/OFSystemInfoTests.m ================================================================== --- tests/OFSystemInfoTests.m +++ tests/OFSystemInfoTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -25,96 +23,96 @@ void *pool = objc_autoreleasePoolPush(); #ifdef OF_HAVE_FILES OFString *userConfigPath, *userDataPath; #endif - [of_stdout setForegroundColor: [OFColor lime]]; + [OFStdOut setForegroundColor: [OFColor lime]]; - [of_stdout writeFormat: @"[OFSystemInfo] Page size: %zd\n", + [OFStdOut writeFormat: @"[OFSystemInfo] Page size: %zd\n", [OFSystemInfo pageSize]]; - [of_stdout writeFormat: @"[OFSystemInfo] Number of CPUs: %zd\n", + [OFStdOut writeFormat: @"[OFSystemInfo] Number of CPUs: %zd\n", [OFSystemInfo numberOfCPUs]]; - [of_stdout writeFormat: @"[OFSystemInfo] ObjFW version: %@\n", + [OFStdOut writeFormat: @"[OFSystemInfo] ObjFW version: %@\n", [OFSystemInfo ObjFWVersion]]; - [of_stdout writeFormat: @"[OFSystemInfo] ObjFW version major: %u\n", + [OFStdOut writeFormat: @"[OFSystemInfo] ObjFW version major: %u\n", [OFSystemInfo ObjFWVersionMajor]]; - [of_stdout writeFormat: @"[OFSystemInfo] ObjFW version minor: %u\n", + [OFStdOut writeFormat: @"[OFSystemInfo] ObjFW version minor: %u\n", [OFSystemInfo ObjFWVersionMinor]]; - [of_stdout writeFormat: @"[OFSystemInfo] Operating system name: %@\n", + [OFStdOut writeFormat: @"[OFSystemInfo] Operating system name: %@\n", [OFSystemInfo operatingSystemName]]; - [of_stdout writeFormat: + [OFStdOut writeFormat: @"[OFSystemInfo] Operating system version: %@\n", [OFSystemInfo operatingSystemVersion]]; #ifdef OF_HAVE_FILES @try { userConfigPath = [OFSystemInfo userConfigPath]; } @catch (OFNotImplementedException *e) { userConfigPath = @"Not implemented"; } - [of_stdout writeFormat: @"[OFSystemInfo] User config path: %@\n", + [OFStdOut writeFormat: @"[OFSystemInfo] User config path: %@\n", userConfigPath]; @try { userDataPath = [OFSystemInfo userDataPath]; } @catch (OFNotImplementedException *e) { userDataPath = @"Not implemented"; } - [of_stdout writeFormat: @"[OFSystemInfo] User data path: %@\n", + [OFStdOut writeFormat: @"[OFSystemInfo] User data path: %@\n", userDataPath]; #endif - [of_stdout writeFormat: @"[OFSystemInfo] CPU vendor: %@\n", + [OFStdOut writeFormat: @"[OFSystemInfo] CPU vendor: %@\n", [OFSystemInfo CPUVendor]]; - [of_stdout writeFormat: @"[OFSystemInfo] CPU model: %@\n", + [OFStdOut writeFormat: @"[OFSystemInfo] CPU model: %@\n", [OFSystemInfo CPUModel]]; #if defined(OF_X86_64) || defined(OF_X86) - [of_stdout writeFormat: @"[OFSystemInfo] Supports MMX: %d\n", + [OFStdOut writeFormat: @"[OFSystemInfo] Supports MMX: %d\n", [OFSystemInfo supportsMMX]]; - [of_stdout writeFormat: @"[OFSystemInfo] Supports SSE: %d\n", + [OFStdOut writeFormat: @"[OFSystemInfo] Supports SSE: %d\n", [OFSystemInfo supportsSSE]]; - [of_stdout writeFormat: @"[OFSystemInfo] Supports SSE2: %d\n", + [OFStdOut writeFormat: @"[OFSystemInfo] Supports SSE2: %d\n", [OFSystemInfo supportsSSE2]]; - [of_stdout writeFormat: @"[OFSystemInfo] Supports SSE3: %d\n", + [OFStdOut writeFormat: @"[OFSystemInfo] Supports SSE3: %d\n", [OFSystemInfo supportsSSE3]]; - [of_stdout writeFormat: @"[OFSystemInfo] Supports SSSE3: %d\n", + [OFStdOut writeFormat: @"[OFSystemInfo] Supports SSSE3: %d\n", [OFSystemInfo supportsSSSE3]]; - [of_stdout writeFormat: @"[OFSystemInfo] Supports SSE4.1: %d\n", + [OFStdOut writeFormat: @"[OFSystemInfo] Supports SSE4.1: %d\n", [OFSystemInfo supportsSSE41]]; - [of_stdout writeFormat: @"[OFSystemInfo] Supports SSE4.2: %d\n", + [OFStdOut writeFormat: @"[OFSystemInfo] Supports SSE4.2: %d\n", [OFSystemInfo supportsSSE42]]; - [of_stdout writeFormat: @"[OFSystemInfo] Supports AVX: %d\n", + [OFStdOut writeFormat: @"[OFSystemInfo] Supports AVX: %d\n", [OFSystemInfo supportsAVX]]; - [of_stdout writeFormat: @"[OFSystemInfo] Supports AVX2: %d\n", + [OFStdOut writeFormat: @"[OFSystemInfo] Supports AVX2: %d\n", [OFSystemInfo supportsAVX2]]; - [of_stdout writeFormat: @"[OFSystemInfo] Supports AES-NI: %d\n", + [OFStdOut writeFormat: @"[OFSystemInfo] Supports AES-NI: %d\n", [OFSystemInfo supportsAESNI]]; - [of_stdout writeFormat: @"[OFSystemInfo] Supports SHA extensions: %d\n", + [OFStdOut writeFormat: @"[OFSystemInfo] Supports SHA extensions: %d\n", [OFSystemInfo supportsSHAExtensions]]; #endif #ifdef OF_POWERPC - [of_stdout writeFormat: @"[OFSystemInfo] Supports AltiVec: %d\n", + [OFStdOut writeFormat: @"[OFSystemInfo] Supports AltiVec: %d\n", [OFSystemInfo supportsAltiVec]]; #endif objc_autoreleasePoolPop(pool); } @end Index: tests/OFTCPSocketTests.m ================================================================== --- tests/OFTCPSocketTests.m +++ tests/OFTCPSocketTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -19,43 +17,41 @@ #include #import "TestsAppDelegate.h" -static OFString *module = @"OFTCPSocket"; +static OFString *const module = @"OFTCPSocket"; @implementation TestsAppDelegate (OFTCPSocketTests) - (void)TCPSocketTests { void *pool = objc_autoreleasePoolPush(); OFTCPSocket *server, *client = nil, *accepted; uint16_t port; - char buf[6]; + char buffer[6]; TEST(@"+[socket]", (server = [OFTCPSocket socket]) && (client = [OFTCPSocket socket])) TEST(@"-[bindToHost:port:]", - (port = [server bindToHost: @"127.0.0.1" - port: 0])) + (port = [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: port])) TEST(@"-[accept]", (accepted = [server accept])) TEST(@"-[remoteAddress]", - [of_socket_address_ip_string(accepted.remoteAddress, NULL) + [OFSocketAddressString(accepted.remoteAddress) isEqual: @"127.0.0.1"]) - TEST(@"-[writeString:]", [client writeString: @"Hello!"]) + TEST(@"-[writeString:]", R([client writeString: @"Hello!"])) - TEST(@"-[readIntoBuffer:length:]", [accepted readIntoBuffer: buf - length: 6] && - !memcmp(buf, "Hello!", 6)) + TEST(@"-[readIntoBuffer:length:]", + [accepted readIntoBuffer: buffer length: 6] && + !memcmp(buffer, "Hello!", 6)) objc_autoreleasePoolPop(pool); } @end Index: tests/OFThreadTests.m ================================================================== --- tests/OFThreadTests.m +++ tests/OFThreadTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -17,39 +15,39 @@ #include "config.h" #import "TestsAppDelegate.h" -static OFString *module = @"OFThread"; +static OFString *const module = @"OFThread"; @interface TestThread: OFThread @end @implementation TestThread - (id)main { - [[OFThread threadDictionary] setObject: @"bar" - forKey: @"foo"]; + [[OFThread threadDictionary] setObject: @"bar" forKey: @"foo"]; + OFEnsure([[[OFThread threadDictionary] + objectForKey: @"foo"] isEqual: @"bar"]); return @"success"; } @end @implementation TestsAppDelegate (OFThreadTests) - (void)threadTests { void *pool = objc_autoreleasePoolPush(); - TestThread *t; - OFMutableDictionary *d; - - TEST(@"+[thread]", (t = [TestThread thread])) - - TEST(@"-[start]", R([t start])) - - TEST(@"-[join]", [[t join] isEqual: @"success"]) - - TEST(@"-[threadDictionary]", (d = [OFThread threadDictionary]) && - [d objectForKey: @"foo"] == nil) + TestThread *thread; + + TEST(@"+[thread]", (thread = [TestThread thread])) + + TEST(@"-[start]", R([thread start])) + + TEST(@"-[join]", [[thread join] isEqual: @"success"]) + + TEST(@"-[threadDictionary]", + [[OFThread threadDictionary] objectForKey: @"foo"] == nil) objc_autoreleasePoolPop(pool); } @end Index: tests/OFUDPSocketTests.m ================================================================== --- tests/OFUDPSocketTests.m +++ tests/OFUDPSocketTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -19,55 +17,49 @@ #include #import "TestsAppDelegate.h" -static OFString *module = @"OFUDPSocket"; +static OFString *const module = @"OFUDPSocket"; @implementation TestsAppDelegate (OFUDPSocketTests) - (void)UDPSocketTests { void *pool = objc_autoreleasePoolPush(); OFUDPSocket *sock; - uint16_t port1, port2; - of_socket_address_t addr1, addr2, addr3; + uint16_t port1; + OFSocketAddress addr1, addr2, addr3; char buf[6]; - OFString *host; TEST(@"+[socket]", (sock = [OFUDPSocket socket])) TEST(@"-[bindToHost:port:]", - (port1 = [sock bindToHost: @"127.0.0.1" - port: 0])) + (port1 = [sock bindToHost: @"127.0.0.1" port: 0])) - addr1 = of_socket_address_parse_ip(@"127.0.0.1", port1); + addr1 = OFSocketAddressParseIP(@"127.0.0.1", port1); TEST(@"-[sendBuffer:length:receiver:]", - R([sock sendBuffer: "Hello" - length: 6 - receiver: &addr1])) + R([sock sendBuffer: "Hello" length: 6 receiver: &addr1])) TEST(@"-[receiveIntoBuffer:length:sender:]", - [sock receiveIntoBuffer: buf - length: 6 - sender: &addr2] == 6 && + [sock receiveIntoBuffer: buf length: 6 sender: &addr2] == 6 && !memcmp(buf, "Hello", 6) && - (host = of_socket_address_ip_string(&addr2, &port2)) && - [host isEqual: @"127.0.0.1"] && port2 == port1) + [OFSocketAddressString(&addr2) isEqual: @"127.0.0.1"] && + OFSocketAddressPort(&addr2) == port1) - addr3 = of_socket_address_parse_ip(@"127.0.0.1", port1 + 1); + 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. */ - TEST(@"of_socket_address_equal()", - of_socket_address_equal(&addr1, &addr2) && - !of_socket_address_equal(&addr1, &addr3)) + TEST(@"OFSocketAddressEqual()", + OFSocketAddressEqual(&addr1, &addr2) && + !OFSocketAddressEqual(&addr1, &addr3)) - TEST(@"of_socket_address_hash()", - of_socket_address_hash(&addr1) == of_socket_address_hash(&addr2) && - of_socket_address_hash(&addr1) != of_socket_address_hash(&addr3)) + TEST(@"OFSocketAddressHash()", + OFSocketAddressHash(&addr1) == OFSocketAddressHash(&addr2) && + OFSocketAddressHash(&addr1) != OFSocketAddressHash(&addr3)) objc_autoreleasePoolPop(pool); } @end ADDED tests/OFUNIXDatagramSocketTests.m Index: tests/OFUNIXDatagramSocketTests.m ================================================================== --- /dev/null +++ tests/OFUNIXDatagramSocketTests.m @@ -0,0 +1,89 @@ +/* + * 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 "TestsAppDelegate.h" + +static OFString *const module = @"OFUNIXDatagramSocket"; + +@implementation TestsAppDelegate (OFUNIXDatagramSocketTests) +- (void)UNIXDatagramSocketTests +{ + void *pool = objc_autoreleasePoolPush(); + OFString *path; + OFUNIXDatagramSocket *sock; + OFSocketAddress address1, address2; + char buffer[5]; + +#if defined(OF_HAVE_FILES) && !defined(OF_IOS) + path = [[OFSystemInfo temporaryDirectoryPath] + stringByAppendingPathComponent: [[OFUUID UUID] UUIDString]]; +#else + /* + * We can have sockets, including UNIX sockets, while file support is + * disabled. + * + * We also use this code path for iOS, as the temporaryDirectoryPath is + * too long on the iOS simulator. + */ + path = [OFString stringWithFormat: @"/tmp/%@", + [[OFUUID UUID] UUIDString]]; +#endif + + TEST(@"+[socket]", (sock = [OFUNIXDatagramSocket socket])) + + @try { + TEST(@"-[bindToPath:]", R(address1 = [sock bindToPath: path])) + } @catch (OFBindFailedException *e) { + switch (e.errNo) { + case EAFNOSUPPORT: + case EPERM: + [OFStdOut setForegroundColor: [OFColor lime]]; + [OFStdOut writeLine: + @"\r[OFUNIXDatagramSocket] -[bindToPath:]: " + @"UNIX datagram sockets unsupported, skipping " + @"tests"]; + + objc_autoreleasePoolPop(pool); + return; + default: + @throw e; + } + } + + @try { + 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)) + } @finally { +#ifdef OF_HAVE_FILES + [[OFFileManager defaultManager] removeItemAtPath: path]; +#endif + } + + objc_autoreleasePoolPop(pool); +} +@end ADDED tests/OFUNIXStreamSocketTests.m Index: tests/OFUNIXStreamSocketTests.m ================================================================== --- /dev/null +++ tests/OFUNIXStreamSocketTests.m @@ -0,0 +1,93 @@ +/* + * 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 "TestsAppDelegate.h" + +static OFString *const module = @"OFUNIXStreamSocket"; + +@implementation TestsAppDelegate (OFUNIXStreamSocketTests) +- (void)UNIXStreamSocketTests +{ + void *pool = objc_autoreleasePoolPush(); + OFString *path; + OFUNIXStreamSocket *sockClient, *sockServer, *sockAccepted; + char buffer[5]; + +#if defined(OF_HAVE_FILES) && !defined(OF_IOS) + path = [[OFSystemInfo temporaryDirectoryPath] + stringByAppendingPathComponent: [[OFUUID UUID] UUIDString]]; +#else + /* + * We can have sockets, including UNIX sockets, while file support is + * disabled. + * + * We also use this code path for iOS, as the temporaryDirectoryPath is + * too long on the iOS simulator. + */ + path = [OFString stringWithFormat: @"/tmp/%@", + [[OFUUID UUID] UUIDString]]; +#endif + + TEST(@"+[socket]", (sockClient = [OFUNIXStreamSocket socket]) && + (sockServer = [OFUNIXStreamSocket socket])) + + @try { + TEST(@"-[bindToPath:]", R([sockServer bindToPath: path])) + } @catch (OFBindFailedException *e) { + switch (e.errNo) { + case EAFNOSUPPORT: + case EPERM: + [OFStdOut setForegroundColor: [OFColor lime]]; + [OFStdOut writeLine: + @"\r[OFUNIXStreamSocket] -[bindToPath:]: " + @"UNIX stream sockets unsupported, skipping tests"]; + + objc_autoreleasePoolPop(pool); + return; + default: + @throw e; + } + } + + @try { + TEST(@"-[listen]", R([sockServer listen])) + + TEST(@"-[connectToPath:]", + R([sockClient connectToPath: path])) + + TEST(@"-[accept]", (sockAccepted = [sockServer accept])) + + TEST(@"-[writeBuffer:length:]", + R([sockAccepted writeBuffer: "Hello" length: 5])) + + TEST(@"-[readIntoBuffer:length:]", + [sockClient readIntoBuffer: buffer length: 5] == 5 && + memcmp(buffer, "Hello", 5) == 0) + + TEST(@"-[remoteAddress]", + OFSocketAddressUNIXPath(sockAccepted.remoteAddress) == nil) + } @finally { +#ifdef OF_HAVE_FILES + [[OFFileManager defaultManager] removeItemAtPath: path]; +#endif + } + + objc_autoreleasePoolPop(pool); +} +@end Index: tests/OFURLTests.m ================================================================== --- tests/OFURLTests.m +++ tests/OFURLTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -17,29 +15,29 @@ #include "config.h" #import "TestsAppDelegate.h" -static OFString *module = @"OFURL"; -static OFString *url_str = @"ht%3atp://us%3Aer:p%40w@ho%3Ast:1234/" +static OFString *const module = @"OFURL"; +static OFString *URLString = @"ht%3atp://us%3Aer:p%40w@ho%3Ast:1234/" @"pa%3Fth?que%23ry=1&f%26oo=b%3dar#frag%23ment"; @implementation TestsAppDelegate (OFURLTests) - (void)URLTests { void *pool = objc_autoreleasePoolPush(); - OFURL *u1, *u2, *u3, *u4, *u5, *u6, *u7; - OFMutableURL *mu; + OFURL *URL1, *URL2, *URL3, *URL4, *URL5, *URL6, *URL7; + OFMutableURL *mutableURL; TEST(@"+[URLWithString:]", - R(u1 = [OFURL URLWithString: url_str]) && - R(u2 = [OFURL URLWithString: @"http://foo:80"]) && - R(u3 = [OFURL URLWithString: @"http://bar/"]) && - R(u4 = [OFURL URLWithString: @"file:///etc/passwd"]) && - R(u5 = [OFURL URLWithString: @"http://foo/bar/qux/foo%2fbar"]) && - R(u6 = [OFURL URLWithString: @"https://[12:34::56:abcd]/"]) && - R(u7 = [OFURL URLWithString: @"https://[12:34::56:abcd]:234/"])) + R(URL1 = [OFURL URLWithString: URLString]) && + R(URL2 = [OFURL URLWithString: @"http://foo:80"]) && + R(URL3 = [OFURL URLWithString: @"http://bar/"]) && + R(URL4 = [OFURL URLWithString: @"file:///etc/passwd"]) && + R(URL5 = [OFURL URLWithString: @"http://foo/bar/qux/foo%2fbar"]) && + R(URL6 = [OFURL URLWithString: @"https://[12:34::56:abcd]/"]) && + R(URL7 = [OFURL URLWithString: @"https://[12:34::56:abcd]:234/"])) EXPECT_EXCEPTION(@"+[URLWithString:] fails with invalid characters #1", OFInvalidFormatException, [OFURL URLWithString: @"ht,tp://foo"]) @@ -70,21 +68,20 @@ EXPECT_EXCEPTION(@"+[URLWithString:] fails with invalid characters #8", OFInvalidFormatException, [OFURL URLWithString: @"https://[f]:f/"]) TEST(@"+[URLWithString:relativeToURL:]", - [[[OFURL URLWithString: @"/foo" - relativeToURL: u1] string] isEqual: - @"ht%3atp://us%3Aer:p%40w@ho%3Ast:1234/foo"] && + [[[OFURL URLWithString: @"/foo" relativeToURL: URL1] string] + isEqual: @"ht%3atp://us%3Aer:p%40w@ho%3Ast:1234/foo"] && [[[OFURL URLWithString: @"foo/bar?q" relativeToURL: [OFURL URLWithString: @"http://h/qux/quux"]] string] isEqual: @"http://h/qux/foo/bar?q"] && [[[OFURL URLWithString: @"foo/bar" relativeToURL: [OFURL URLWithString: @"http://h/qux/?x"]] string] isEqual: @"http://h/qux/foo/bar"] && [[[OFURL URLWithString: @"http://foo/?q" - relativeToURL: u1] string] isEqual: @"http://foo/?q"] && + relativeToURL: URL1] string] isEqual: @"http://foo/?q"] && [[[OFURL URLWithString: @"foo" relativeToURL: [OFURL URLWithString: @"http://foo/bar"]] string] isEqual: @"http://foo/foo"] && [[[OFURL URLWithString: @"foo" relativeToURL: [OFURL URLWithString: @"http://foo"]] @@ -91,30 +88,26 @@ string] isEqual: @"http://foo/foo"]) EXPECT_EXCEPTION( @"+[URLWithString:relativeToURL:] fails with invalid characters #1", OFInvalidFormatException, - [OFURL URLWithString: @"`" - relativeToURL: u1]) + [OFURL URLWithString: @"`" relativeToURL: URL1]) EXPECT_EXCEPTION( @"+[URLWithString:relativeToURL:] fails with invalid characters #2", OFInvalidFormatException, - [OFURL URLWithString: @"/`" - relativeToURL: u1]) + [OFURL URLWithString: @"/`" relativeToURL: URL1]) EXPECT_EXCEPTION( @"+[URLWithString:relativeToURL:] fails with invalid characters #3", OFInvalidFormatException, - [OFURL URLWithString: @"?`" - relativeToURL: u1]) + [OFURL URLWithString: @"?`" relativeToURL: URL1]) EXPECT_EXCEPTION( @"+[URLWithString:relativeToURL:] fails with invalid characters #4", OFInvalidFormatException, - [OFURL URLWithString: @"#`" - relativeToURL: u1]) + [OFURL URLWithString: @"#`" relativeToURL: URL1]) #ifdef OF_HAVE_FILES TEST(@"+[fileURLWithPath:]", [[[OFURL fileURLWithPath: @"testfile.txt"] fileSystemRepresentation] isEqual: [[OFFileManager defaultManager].currentDirectoryPath @@ -140,34 +133,35 @@ [tmp.fileSystemRepresentation isEqual: @"\\\\test"]) # endif #endif TEST(@"-[string]", - [u1.string isEqual: url_str] && - [u2.string isEqual: @"http://foo:80"] && - [u3.string isEqual: @"http://bar/"] && - [u4.string isEqual: @"file:///etc/passwd"]) + [URL1.string isEqual: URLString] && + [URL2.string isEqual: @"http://foo:80"] && + [URL3.string isEqual: @"http://bar/"] && + [URL4.string isEqual: @"file:///etc/passwd"]) TEST(@"-[scheme]", - [u1.scheme isEqual: @"ht:tp"] && [u4.scheme isEqual: @"file"]) + [URL1.scheme isEqual: @"ht:tp"] && [URL4.scheme isEqual: @"file"]) - TEST(@"-[user]", [u1.user isEqual: @"us:er"] && u4.user == nil) + TEST(@"-[user]", [URL1.user isEqual: @"us:er"] && URL4.user == nil) TEST(@"-[password]", - [u1.password isEqual: @"p@w"] && u4.password == nil) - TEST(@"-[host]", [u1.host isEqual: @"ho:st"] && - [u6.host isEqual: @"12:34::56:abcd"] && - [u7.host isEqual: @"12:34::56:abcd"]) - TEST(@"-[port]", u1.port.unsignedShortValue == 1234 && - [u4 port] == nil && u7.port.unsignedShortValue == 234) + [URL1.password isEqual: @"p@w"] && URL4.password == nil) + TEST(@"-[host]", [URL1.host isEqual: @"ho:st"] && + [URL6.host isEqual: @"12:34::56:abcd"] && + [URL7.host isEqual: @"12:34::56:abcd"]) + TEST(@"-[port]", URL1.port.unsignedShortValue == 1234 && + [URL4 port] == nil && URL7.port.unsignedShortValue == 234) TEST(@"-[path]", - [u1.path isEqual: @"/pa?th"] && [u4.path isEqual: @"/etc/passwd"]) + [URL1.path isEqual: @"/pa?th"] && + [URL4.path isEqual: @"/etc/passwd"]) TEST(@"-[pathComponents]", - [u1.pathComponents isEqual: + [URL1.pathComponents isEqual: [OFArray arrayWithObjects: @"/", @"pa?th", nil]] && - [u4.pathComponents isEqual: + [URL4.pathComponents isEqual: [OFArray arrayWithObjects: @"/", @"etc", @"passwd", nil]] && - [u5.pathComponents isEqual: + [URL5.pathComponents isEqual: [OFArray arrayWithObjects: @"/", @"bar", @"qux", @"foo/bar", nil]]) TEST(@"-[lastPathComponent]", [[[OFURL URLWithString: @"http://host/foo//bar/baz"] lastPathComponent] isEqual: @"baz"] && [[[OFURL URLWithString: @"http://host/foo//bar/baz/"] @@ -174,141 +168,150 @@ lastPathComponent] isEqual: @"baz"] && [[[OFURL URLWithString: @"http://host/foo/"] lastPathComponent] isEqual: @"foo"] && [[[OFURL URLWithString: @"http://host/"] lastPathComponent] isEqual: @"/"] && - [u5.lastPathComponent isEqual: @"foo/bar"]) + [URL5.lastPathComponent isEqual: @"foo/bar"]) TEST(@"-[query]", - [u1.query isEqual: @"que#ry=1&f&oo=b=ar"] && u4.query == nil) + [URL1.query isEqual: @"que#ry=1&f&oo=b=ar"] && URL4.query == nil) TEST(@"-[queryDictionary]", - [u1.queryDictionary isEqual: + [URL1.queryDictionary isEqual: [OFDictionary dictionaryWithKeysAndObjects: @"que#ry", @"1", @"f&oo", @"b=ar", nil]]); TEST(@"-[fragment]", - [u1.fragment isEqual: @"frag#ment"] && u4.fragment == nil) - - TEST(@"-[copy]", R(u4 = [[u1 copy] autorelease])) - - TEST(@"-[isEqual:]", [u1 isEqual: u4] && ![u2 isEqual: u3] && - [[OFURL URLWithString: @"HTTP://bar/"] isEqual: u3]) - - TEST(@"-[hash:]", u1.hash == u4.hash && u2.hash != u3.hash) + [URL1.fragment isEqual: @"frag#ment"] && URL4.fragment == nil) + + TEST(@"-[copy]", R(URL4 = [[URL1 copy] autorelease])) + + TEST(@"-[isEqual:]", [URL1 isEqual: URL4] && ![URL2 isEqual: URL3] && + [[OFURL URLWithString: @"HTTP://bar/"] isEqual: URL3]) + + TEST(@"-[hash:]", URL1.hash == URL4.hash && URL2.hash != URL3.hash) EXPECT_EXCEPTION(@"Detection of invalid format", OFInvalidFormatException, [OFURL URLWithString: @"http"]) - mu = [OFMutableURL URL]; + mutableURL = [OFMutableURL URL]; TEST(@"-[setScheme:]", - (mu.scheme = @"ht:tp") && [mu.URLEncodedScheme isEqual: @"ht%3Atp"]) + (mutableURL.scheme = @"ht:tp") && + [mutableURL.URLEncodedScheme isEqual: @"ht%3Atp"]) TEST(@"-[setURLEncodedScheme:]", - (mu.URLEncodedScheme = @"ht%3Atp") && [mu.scheme isEqual: @"ht:tp"]) + (mutableURL.URLEncodedScheme = @"ht%3Atp") && + [mutableURL.scheme isEqual: @"ht:tp"]) EXPECT_EXCEPTION( @"-[setURLEncodedScheme:] with invalid characters fails", - OFInvalidFormatException, mu.URLEncodedScheme = @"~") - - TEST(@"-[setHost:]", - (mu.host = @"ho:st") && [mu.URLEncodedHost isEqual: @"ho%3Ast"] && - (mu.host = @"12:34:ab") && - [mu.URLEncodedHost isEqual: @"[12:34:ab]"] && - (mu.host = @"12:34:aB") && - [mu.URLEncodedHost isEqual: @"[12:34:aB]"] && - (mu.host = @"12:34:g") && - [mu.URLEncodedHost isEqual: @"12%3A34%3Ag"]) - - TEST(@"-[setURLEncodedHost:]", - (mu.URLEncodedHost = @"ho%3Ast") && [mu.host isEqual: @"ho:st"] && - (mu.URLEncodedHost = @"[12:34]") && [mu.host isEqual: @"12:34"] && - (mu.URLEncodedHost = @"[12::ab]") && [mu.host isEqual: @"12::ab"]) - - EXPECT_EXCEPTION(@"-[setURLEncodedHost:] with invalid characters fails" - " #1", OFInvalidFormatException, mu.URLEncodedHost = @"/") - - EXPECT_EXCEPTION(@"-[setURLEncodedHost:] with invalid characters fails" - " #2", OFInvalidFormatException, mu.URLEncodedHost = @"[12:34") - - EXPECT_EXCEPTION(@"-[setURLEncodedHost:] with invalid characters fails" - " #3", OFInvalidFormatException, mu.URLEncodedHost = @"[a::g]") - - TEST(@"-[setUser:]", - (mu.user = @"us:er") && [mu.URLEncodedUser isEqual: @"us%3Aer"]) - - TEST(@"-[setURLEncodedUser:]", - (mu.URLEncodedUser = @"us%3Aer") && [mu.user isEqual: @"us:er"]) - - EXPECT_EXCEPTION(@"-[setURLEncodedUser:] with invalid characters fails", - OFInvalidFormatException, mu.URLEncodedHost = @"/") - - TEST(@"-[setPassword:]", - (mu.password = @"pass:word") && - [mu.URLEncodedPassword isEqual: @"pass%3Aword"]) - - TEST(@"-[setURLEncodedPassword:]", - (mu.URLEncodedPassword = @"pass%3Aword") && - [mu.password isEqual: @"pass:word"]) + OFInvalidFormatException, mutableURL.URLEncodedScheme = @"~") + + TEST(@"-[setHost:]", + (mutableURL.host = @"ho:st") && + [mutableURL.URLEncodedHost isEqual: @"ho%3Ast"] && + (mutableURL.host = @"12:34:ab") && + [mutableURL.URLEncodedHost isEqual: @"[12:34:ab]"] && + (mutableURL.host = @"12:34:aB") && + [mutableURL.URLEncodedHost isEqual: @"[12:34:aB]"] && + (mutableURL.host = @"12:34:g") && + [mutableURL.URLEncodedHost isEqual: @"12%3A34%3Ag"]) + + TEST(@"-[setURLEncodedHost:]", + (mutableURL.URLEncodedHost = @"ho%3Ast") && + [mutableURL.host isEqual: @"ho:st"] && + (mutableURL.URLEncodedHost = @"[12:34]") && + [mutableURL.host isEqual: @"12:34"] && + (mutableURL.URLEncodedHost = @"[12::ab]") && + [mutableURL.host isEqual: @"12::ab"]) + + EXPECT_EXCEPTION(@"-[setURLEncodedHost:] with invalid characters fails" + " #1", OFInvalidFormatException, mutableURL.URLEncodedHost = @"/") + + EXPECT_EXCEPTION(@"-[setURLEncodedHost:] with invalid characters fails" + " #2", OFInvalidFormatException, + mutableURL.URLEncodedHost = @"[12:34") + + EXPECT_EXCEPTION(@"-[setURLEncodedHost:] with invalid characters fails" + " #3", OFInvalidFormatException, + mutableURL.URLEncodedHost = @"[a::g]") + + TEST(@"-[setUser:]", + (mutableURL.user = @"us:er") && + [mutableURL.URLEncodedUser isEqual: @"us%3Aer"]) + + TEST(@"-[setURLEncodedUser:]", + (mutableURL.URLEncodedUser = @"us%3Aer") && + [mutableURL.user isEqual: @"us:er"]) + + EXPECT_EXCEPTION(@"-[setURLEncodedUser:] with invalid characters fails", + OFInvalidFormatException, mutableURL.URLEncodedHost = @"/") + + TEST(@"-[setPassword:]", + (mutableURL.password = @"pass:word") && + [mutableURL.URLEncodedPassword isEqual: @"pass%3Aword"]) + + TEST(@"-[setURLEncodedPassword:]", + (mutableURL.URLEncodedPassword = @"pass%3Aword") && + [mutableURL.password isEqual: @"pass:word"]) EXPECT_EXCEPTION( @"-[setURLEncodedPassword:] with invalid characters fails", - OFInvalidFormatException, mu.URLEncodedPassword = @"/") + OFInvalidFormatException, mutableURL.URLEncodedPassword = @"/") TEST(@"-[setPath:]", - (mu.path = @"pa/th@?") && [mu.URLEncodedPath isEqual: @"pa/th@%3F"]) + (mutableURL.path = @"pa/th@?") && + [mutableURL.URLEncodedPath isEqual: @"pa/th@%3F"]) TEST(@"-[setURLEncodedPath:]", - (mu.URLEncodedPath = @"pa/th@%3F") && [mu.path isEqual: @"pa/th@?"]) + (mutableURL.URLEncodedPath = @"pa/th@%3F") && + [mutableURL.path isEqual: @"pa/th@?"]) EXPECT_EXCEPTION(@"-[setURLEncodedPath:] with invalid characters fails", - OFInvalidFormatException, mu.URLEncodedPath = @"?") + OFInvalidFormatException, mutableURL.URLEncodedPath = @"?") TEST(@"-[setQuery:]", - (mu.query = @"que/ry?#") && - [mu.URLEncodedQuery isEqual: @"que/ry?%23"]) + (mutableURL.query = @"que/ry?#") && + [mutableURL.URLEncodedQuery isEqual: @"que/ry?%23"]) TEST(@"-[setURLEncodedQuery:]", - (mu.URLEncodedQuery = @"que/ry?%23") && - [mu.query isEqual: @"que/ry?#"]) + (mutableURL.URLEncodedQuery = @"que/ry?%23") && + [mutableURL.query isEqual: @"que/ry?#"]) EXPECT_EXCEPTION( @"-[setURLEncodedQuery:] with invalid characters fails", - OFInvalidFormatException, mu.URLEncodedQuery = @"`") + OFInvalidFormatException, mutableURL.URLEncodedQuery = @"`") TEST(@"-[setQueryDictionary:]", - (mu.queryDictionary = [OFDictionary dictionaryWithKeysAndObjects: + (mutableURL.queryDictionary = + [OFDictionary dictionaryWithKeysAndObjects: @"foo&bar", @"baz=qux", @"f=oobar", @"b&azqux", nil]) && - [mu.URLEncodedQuery isEqual: + [mutableURL.URLEncodedQuery isEqual: @"foo%26bar=baz%3Dqux&f%3Doobar=b%26azqux"]) TEST(@"-[setFragment:]", - (mu.fragment = @"frag/ment?#") && - [mu.URLEncodedFragment isEqual: @"frag/ment?%23"]) + (mutableURL.fragment = @"frag/ment?#") && + [mutableURL.URLEncodedFragment isEqual: @"frag/ment?%23"]) TEST(@"-[setURLEncodedFragment:]", - (mu.URLEncodedFragment = @"frag/ment?%23") && - [mu.fragment isEqual: @"frag/ment?#"]) + (mutableURL.URLEncodedFragment = @"frag/ment?%23") && + [mutableURL.fragment isEqual: @"frag/ment?#"]) EXPECT_EXCEPTION( @"-[setURLEncodedFragment:] with invalid characters fails", - OFInvalidFormatException, mu.URLEncodedFragment = @"`") + OFInvalidFormatException, mutableURL.URLEncodedFragment = @"`") TEST(@"-[URLByAppendingPathComponent:isDirectory:]", [[[OFURL URLWithString: @"file:///foo/bar"] - URLByAppendingPathComponent: @"qux" - isDirectory: false] isEqual: + URLByAppendingPathComponent: @"qux" isDirectory: false] isEqual: [OFURL URLWithString: @"file:///foo/bar/qux"]] && [[[OFURL URLWithString: @"file:///foo/bar/"] - URLByAppendingPathComponent: @"qux" - isDirectory: false] isEqual: + URLByAppendingPathComponent: @"qux" isDirectory: false] isEqual: [OFURL URLWithString: @"file:///foo/bar/qux"]] && [[[OFURL URLWithString: @"file:///foo/bar/"] - URLByAppendingPathComponent: @"qu?x" - isDirectory: false] isEqual: + URLByAppendingPathComponent: @"qu?x" isDirectory: false] isEqual: [OFURL URLWithString: @"file:///foo/bar/qu%3Fx"]] && [[[OFURL URLWithString: @"file:///foo/bar/"] - URLByAppendingPathComponent: @"qu?x" - isDirectory: true] isEqual: + URLByAppendingPathComponent: @"qu?x" isDirectory: true] isEqual: [OFURL URLWithString: @"file:///foo/bar/qu%3Fx/"]]) TEST(@"-[URLByStandardizingPath]", [[[OFURL URLWithString: @"http://foo/bar/.."] URLByStandardizingPath] isEqual: Index: tests/OFValueTests.m ================================================================== --- tests/OFValueTests.m +++ tests/OFValueTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -19,39 +17,36 @@ #include #import "TestsAppDelegate.h" -static OFString *module = @"OFValue"; +static OFString *const module = @"OFValue"; @implementation TestsAppDelegate (OFValueTests) - (void)valueTests { void *pool = objc_autoreleasePoolPush(); - of_range_t range = of_range(1, 64), range2; - of_point_t point = of_point(1.5f, 3.0f), point2; - of_dimension_t dimension = of_dimension(4.5f, 5.0f), dimension2; - of_rectangle_t rectangle = of_rectangle(1.5f, 3.0f, 4.5f, 6.0f); - of_rectangle_t rectangle2; + OFRange range = OFRangeMake(1, 64), range2; + OFPoint point = OFPointMake(1.5f, 3.0f), point2; + OFSize size = OFSizeMake(4.5f, 5.0f), size2; + OFRect rect = OFRectMake(1.5f, 3.0f, 4.5f, 6.0f), rect2; OFValue *value; void *pointer = &value; TEST(@"+[valueWithBytes:objCType:]", (value = [OFValue valueWithBytes: &range - objCType: @encode(of_range_t)])) + objCType: @encode(OFRange)])) - TEST(@"-[objCType]", strcmp(value.objCType, @encode(of_range_t)) == 0) + TEST(@"-[objCType]", strcmp(value.objCType, @encode(OFRange)) == 0) TEST(@"-[getValue:size:]", - R([value getValue: &range2 - size: sizeof(of_range_t)]) && - of_range_equal(range2, range)) + R([value getValue: &range2 size: sizeof(OFRange)]) && + OFRangeEqual(range2, range)) EXPECT_EXCEPTION(@"-[getValue:size:] with wrong size throws", OFOutOfRangeException, - [value getValue: &range - size: sizeof(of_range_t) - 1]) + [value getValue: &range size: sizeof(OFRange) - 1]) TEST(@"+[valueWithPointer:]", (value = [OFValue valueWithPointer: pointer])) TEST(@"-[pointerValue]", @@ -79,20 +74,19 @@ TEST(@"+[valueWithRange:]", (value = [OFValue valueWithRange: range])) TEST(@"-[rangeValue]", - of_range_equal(value.rangeValue, range) && + OFRangeEqual(value.rangeValue, range) && (value = [OFValue valueWithBytes: &range - objCType: @encode(of_range_t)]) && - of_range_equal(value.rangeValue, range)) + objCType: @encode(OFRange)]) && + OFRangeEqual(value.rangeValue, range)) TEST(@"-[getValue:size:] for OFRangeValue", (value = [OFValue valueWithRange: range]) && - R([value getValue: &range2 - size: sizeof(range2)]) && - of_range_equal(range2, range)) + R([value getValue: &range2 size: sizeof(range2)]) && + OFRangeEqual(range2, range)) EXPECT_EXCEPTION(@"-[rangeValue] with wrong size throws", OFOutOfRangeException, [[OFValue valueWithBytes: "a" objCType: @encode(char)] rangeValue]) @@ -99,77 +93,70 @@ TEST(@"+[valueWithPoint:]", (value = [OFValue valueWithPoint: point])) TEST(@"-[pointValue]", - of_point_equal(value.pointValue, point) && + OFPointEqual(value.pointValue, point) && (value = [OFValue valueWithBytes: &point - objCType: @encode(of_point_t)]) && - of_point_equal(value.pointValue, point)) + objCType: @encode(OFPoint)]) && + OFPointEqual(value.pointValue, point)) TEST(@"-[getValue:size:] for OFPointValue", (value = [OFValue valueWithPoint: point]) && - R([value getValue: &point2 - size: sizeof(point2)]) && - of_point_equal(point2, point)) + R([value getValue: &point2 size: sizeof(point2)]) && + OFPointEqual(point2, point)) EXPECT_EXCEPTION(@"-[pointValue] with wrong size throws", OFOutOfRangeException, [[OFValue valueWithBytes: "a" objCType: @encode(char)] pointValue]) - TEST(@"+[valueWithDimension:]", - (value = [OFValue valueWithDimension: dimension])) - - TEST(@"-[dimensionValue]", - of_dimension_equal(value.dimensionValue, dimension) && - (value = [OFValue valueWithBytes: &dimension - objCType: @encode(of_dimension_t)]) && - of_dimension_equal(value.dimensionValue, dimension)) - - TEST(@"-[getValue:size:] for OFDimensionValue", - (value = [OFValue valueWithDimension: dimension]) && - R([value getValue: &dimension2 - size: sizeof(dimension2)]) && - of_dimension_equal(dimension2, dimension)) - - EXPECT_EXCEPTION(@"-[dimensionValue] with wrong size throws", - OFOutOfRangeException, - [[OFValue valueWithBytes: "a" - objCType: @encode(char)] dimensionValue]) - - TEST(@"+[valueWithRectangle:]", - (value = [OFValue valueWithRectangle: rectangle])) - - TEST(@"-[rectangleValue]", - of_rectangle_equal(value.rectangleValue, rectangle) && - (value = [OFValue valueWithBytes: &rectangle - objCType: @encode(of_rectangle_t)]) && - of_rectangle_equal(value.rectangleValue, rectangle)) - - TEST(@"-[getValue:size:] for OFRectangleValue", - (value = [OFValue valueWithRectangle: rectangle]) && - R([value getValue: &rectangle2 - size: sizeof(rectangle2)]) && - of_rectangle_equal(rectangle2, rectangle)) - - EXPECT_EXCEPTION(@"-[rectangleValue] with wrong size throws", - OFOutOfRangeException, - [[OFValue valueWithBytes: "a" - objCType: @encode(char)] rectangleValue]) - - TEST(@"-[isEqual:]", - [[OFValue valueWithRectangle: rectangle] - isEqual: [OFValue valueWithBytes: &rectangle - objCType: @encode(of_rectangle_t)]] && - ![[OFValue valueWithBytes: "a" - objCType: @encode(signed char)] - isEqual: [OFValue valueWithBytes: "a" - objCType: @encode(unsigned char)]] && - ![[OFValue valueWithBytes: "a" - objCType: @encode(char)] - isEqual: [OFValue valueWithBytes: "b" - objCType: @encode(char)]]) + TEST(@"+[valueWithSize:]", + (value = [OFValue valueWithSize: size])) + + TEST(@"-[sizeValue]", + OFSizeEqual(value.sizeValue, size) && + (value = [OFValue valueWithBytes: &size + objCType: @encode(OFSize)]) && + OFSizeEqual(value.sizeValue, size)) + + TEST(@"-[getValue:size:] for OFSizeValue", + (value = [OFValue valueWithSize: size]) && + R([value getValue: &size2 size: sizeof(size2)]) && + OFSizeEqual(size2, size)) + + EXPECT_EXCEPTION(@"-[sizeValue] with wrong size throws", + OFOutOfRangeException, + [[OFValue valueWithBytes: "a" + objCType: @encode(char)] sizeValue]) + + TEST(@"+[valueWithRect:]", + (value = [OFValue valueWithRect: rect])) + + TEST(@"-[rectValue]", + OFRectEqual(value.rectValue, rect) && + (value = [OFValue valueWithBytes: &rect + objCType: @encode(OFRect)]) && + OFRectEqual(value.rectValue, rect)) + + TEST(@"-[getValue:size:] for OFRectValue", + (value = [OFValue valueWithRect: rect]) && + R([value getValue: &rect2 size: sizeof(rect2)]) && + OFRectEqual(rect2, rect)) + + EXPECT_EXCEPTION(@"-[rectValue] with wrong size throws", + OFOutOfRangeException, + [[OFValue valueWithBytes: "a" objCType: @encode(char)] rectValue]) + + TEST(@"-[isEqual:]", + [[OFValue valueWithRect: rect] + isEqual: [OFValue valueWithBytes: &rect + objCType: @encode(OFRect)]] && + ![[OFValue valueWithBytes: "a" objCType: @encode(signed char)] + isEqual: [OFValue valueWithBytes: "a" + objCType: @encode(unsigned char)]] && + ![[OFValue valueWithBytes: "a" objCType: @encode(char)] + isEqual: [OFValue valueWithBytes: "b" objCType: @encode(char)]]) objc_autoreleasePoolPop(pool); } @end Index: tests/OFWindowsRegistryKeyTests.m ================================================================== --- tests/OFWindowsRegistryKeyTests.m +++ tests/OFWindowsRegistryKeyTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -17,19 +15,18 @@ #include "config.h" #import "TestsAppDelegate.h" -static OFString *module = @"OFWindowsRegistryKey"; +static OFString *const module = @"OFWindowsRegistryKey"; @implementation TestsAppDelegate (OFWindowsRegistryKeyTests) - (void)windowsRegistryKeyTests { void *pool = objc_autoreleasePoolPush(); - OFData *data = [OFData dataWithItems: "abcdef" - count: 6]; - OFWindowsRegistryKey *softwareKey, *ObjFWKey; + OFData *data = [OFData dataWithItems: "abcdef" count: 6]; + OFWindowsRegistryKey *softwareKey, *objFWKey; DWORD type; TEST(@"+[OFWindowsRegistryKey classesRootKey]", [OFWindowsRegistryKey classesRootKey]) @@ -43,48 +40,47 @@ [OFWindowsRegistryKey localMachineKey]) TEST(@"+[OFWindowsRegistryKey usersKey]", [OFWindowsRegistryKey usersKey]) - TEST(@"-[openSubkeyAtPath:securityAndAccessRights:]", + TEST(@"-[openSubkeyAtPath:securityAndAccessRights:] #1", (softwareKey = [[OFWindowsRegistryKey currentUserKey] openSubkeyAtPath: @"Software" - securityAndAccessRights: KEY_ALL_ACCESS]) && + securityAndAccessRights: KEY_ALL_ACCESS])) + + EXPECT_EXCEPTION(@"-[openSubkeyAtPath:securityAndAccessRights:] #2", + OFOpenWindowsRegistryKeyFailedException, [[OFWindowsRegistryKey currentUserKey] openSubkeyAtPath: @"nonexistent" - securityAndAccessRights: KEY_ALL_ACCESS] == nil) + securityAndAccessRights: KEY_ALL_ACCESS]) TEST(@"-[createSubkeyAtPath:securityAndAccessRights:]", - (ObjFWKey = [softwareKey createSubkeyAtPath: @"ObjFW" + (objFWKey = [softwareKey createSubkeyAtPath: @"ObjFW" securityAndAccessRights: KEY_ALL_ACCESS])) - TEST(@"-[setData:forValue:type:]", - R([ObjFWKey setData: data - forValue: @"data" - type: REG_BINARY])) - - TEST(@"-[dataForValue:subkeyPath:flags:type:]", - [[ObjFWKey dataForValue: @"data" - type: &type] isEqual: data] && + TEST(@"-[setData:forValueNamed:type:]", + R([objFWKey setData: data forValueNamed: @"data" type: REG_BINARY])) + + TEST(@"-[dataForValueNamed:subkeyPath:flags:type:]", + [[objFWKey dataForValueNamed: @"data" type: &type] isEqual: data] && type == REG_BINARY) - TEST(@"-[setString:forValue:type:]", - R([ObjFWKey setString: @"foobar" - forValue: @"string"]) && - R([ObjFWKey setString: @"%PATH%;foo" - forValue: @"expand" + TEST(@"-[setString:forValueNamed:type:]", + R([objFWKey setString: @"foobar" forValueNamed: @"string"]) && + R([objFWKey setString: @"%PATH%;foo" + forValueNamed: @"expand" type: REG_EXPAND_SZ])) TEST(@"-[stringForValue:subkeyPath:]", - [[ObjFWKey stringForValue: @"string"] isEqual: @"foobar"] && - [[ObjFWKey stringForValue: @"expand" - type: &type] isEqual: @"%PATH%;foo"] && + [[objFWKey stringForValueNamed: @"string"] isEqual: @"foobar"] && + [[objFWKey stringForValueNamed: @"expand" type: &type] + isEqual: @"%PATH%;foo"] && type == REG_EXPAND_SZ) - TEST(@"-[deleteValue:]", R([ObjFWKey deleteValue: @"data"])) + TEST(@"-[deleteValueNamed:]", R([objFWKey deleteValueNamed: @"data"])) TEST(@"-[deleteSubkeyAtPath:]", R([softwareKey deleteSubkeyAtPath: @"ObjFW"])) objc_autoreleasePoolPop(pool); } @end Index: tests/OFXMLElementBuilderTests.m ================================================================== --- tests/OFXMLElementBuilderTests.m +++ tests/OFXMLElementBuilderTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -17,48 +15,48 @@ #include "config.h" #import "TestsAppDelegate.h" -static OFString *module = @"OFXMLElementBuilder"; +static OFString *const module = @"OFXMLElementBuilder"; static OFXMLNode *nodes[2]; static size_t i = 0; @implementation TestsAppDelegate (OFXMLElementBuilderTests) - (void)elementBuilder: (OFXMLElementBuilder *)builder didBuildElement: (OFXMLElement *)element { - OF_ENSURE(i == 0); + OFEnsure(i == 0); nodes[i++] = [element retain]; } - (void)elementBuilder: (OFXMLElementBuilder *)builder didBuildParentlessNode: (OFXMLNode *)node { - OF_ENSURE(i == 1); + OFEnsure(i == 1); nodes[i++] = [node retain]; } - (void)XMLElementBuilderTests { void *pool = objc_autoreleasePoolPush(); - OFXMLParser *p = [OFXMLParser parser]; - OFXMLElementBuilder *builder = [OFXMLElementBuilder elementBuilder]; - OFString *str = @"barbaz" + OFXMLParser *parser = [OFXMLParser parser]; + OFXMLElementBuilder *builder = [OFXMLElementBuilder builder]; + OFString *string = @"barbaz" " " ""; - p.delegate = builder; + parser.delegate = builder; builder.delegate = self; TEST(@"Building elements from parsed XML", - R([p parseString: str]) && - nodes[0] != nil && [nodes[0].XMLString isEqual: str] && - R([p parseString: @""]) && + R([parser parseString: string]) && + nodes[0] != nil && [nodes[0].XMLString isEqual: string] && + R([parser parseString: @""]) && nodes[1] != nil && [nodes[1].XMLString isEqual: @""] && i == 2) [nodes[0] release]; [nodes[1] release]; objc_autoreleasePoolPop(pool); } @end Index: tests/OFXMLNodeTests.m ================================================================== --- tests/OFXMLNodeTests.m +++ tests/OFXMLNodeTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -17,116 +15,112 @@ #include "config.h" #import "TestsAppDelegate.h" -static OFString *module = @"OFXMLNode"; +static OFString *module; @implementation TestsAppDelegate (OFXMLNodeTests) - (void)XMLNodeTests { void *pool = objc_autoreleasePoolPush(); - id nodes[4]; - OFArray *a; + id node1, node2, node3, node4; + OFArray *array; + + module = @"OFXMLNode"; TEST(@"+[elementWithName:]", - (nodes[0] = [OFXMLElement elementWithName: @"foo"]) && - [[nodes[0] XMLString] isEqual: @""]) + (node1 = [OFXMLElement elementWithName: @"foo"]) && + [[node1 XMLString] isEqual: @""]) TEST(@"+[elementWithName:stringValue:]", - (nodes[1] = [OFXMLElement elementWithName: @"foo" - stringValue: @"b&ar"]) && - [[nodes[1] XMLString] isEqual: @"b&ar"]) + (node2 = [OFXMLElement elementWithName: @"foo" + stringValue: @"b&ar"]) && + [[node2 XMLString] isEqual: @"b&ar"]) TEST(@"+[elementWithName:namespace:]", - (nodes[2] = [OFXMLElement elementWithName: @"foo" - namespace: @"urn:objfw:test"]) && - R([nodes[2] addAttributeWithName: @"test" - stringValue: @"test"]) && - R([nodes[2] setPrefix: @"objfw-test" - forNamespace: @"urn:objfw:test"]) && - [[nodes[2] XMLString] isEqual: @""] && - (nodes[3] = [OFXMLElement elementWithName: @"foo" - namespace: @"urn:objfw:test"]) && - R([nodes[3] addAttributeWithName: @"test" - stringValue: @"test"]) && - [[nodes[3] XMLString] isEqual: + (node3 = [OFXMLElement elementWithName: @"foo" + namespace: @"urn:objfw:test"]) && + R([node3 addAttributeWithName: @"test" stringValue: @"test"]) && + R([node3 setPrefix: @"objfw-test" + forNamespace: @"urn:objfw:test"]) && + [[node3 XMLString] isEqual: @""] && + (node4 = [OFXMLElement elementWithName: @"foo" + namespace: @"urn:objfw:test"]) && + R([node4 addAttributeWithName: @"test" stringValue: @"test"]) && + [[node4 XMLString] isEqual: @""]) TEST(@"+[elementWithName:namespace:stringValue:]", - (nodes[3] = [OFXMLElement elementWithName: @"foo" - namespace: @"urn:objfw:test" - stringValue: @"x"]) && - R([nodes[3] setPrefix: @"objfw-test" - forNamespace: @"urn:objfw:test"]) && - [[nodes[3] XMLString] isEqual: - @"x"]) + (node4 = [OFXMLElement elementWithName: @"foo" + namespace: @"urn:objfw:test" + stringValue: @"x"]) && + R([node4 setPrefix: @"objfw-test" + forNamespace: @"urn:objfw:test"]) && + [[node4 XMLString] isEqual: @"x"]) TEST(@"+[charactersWithString:]", - (nodes[3] = [OFXMLCharacters charactersWithString: @""]) && - [[nodes[3] XMLString] isEqual: @"<foo>"]) + (node4 = [OFXMLCharacters charactersWithString: @""]) && + [[node4 XMLString] isEqual: @"<foo>"]) TEST(@"+[CDATAWithString:]", - (nodes[3] = [OFXMLCDATA CDATAWithString: @""]) && - [[nodes[3] XMLString] isEqual: @"]]>"]); + (node4 = [OFXMLCDATA CDATAWithString: @""]) && + [[node4 XMLString] isEqual: @"]]>"]); - TEST(@"+[commentWithString:]", - (nodes[3] = [OFXMLComment commentWithString: @" comment "]) && - [[nodes[3] XMLString] isEqual: @""]) + TEST(@"+[commentWithText:]", + (node4 = [OFXMLComment commentWithText: @" comment "]) && + [[node4 XMLString] isEqual: @""]) module = @"OFXMLElement"; TEST(@"-[addAttributeWithName:stringValue:]", - R([nodes[0] addAttributeWithName: @"foo" - stringValue: @"b&ar"]) && - [[nodes[0] XMLString] isEqual: @""] && - R([nodes[1] addAttributeWithName: @"foo" - stringValue: @"b&ar"]) && - [[nodes[1] XMLString] isEqual: - @"b&ar"]) + R([node1 addAttributeWithName: @"foo" stringValue: @"b&ar"]) && + [[node1 XMLString] isEqual: @""] && + R([node2 addAttributeWithName: @"foo" stringValue: @"b&ar"]) && + [[node2 XMLString] isEqual: @"b&ar"]) TEST(@"-[setPrefix:forNamespace:]", - R([nodes[1] setPrefix: @"objfw-test" - forNamespace: @"urn:objfw:test"])) + R([node2 setPrefix: @"objfw-test" + forNamespace: @"urn:objfw:test"])) TEST(@"-[addAttributeWithName:namespace:stringValue:]", - R([nodes[1] addAttributeWithName: @"foo" - namespace: @"urn:objfw:test" - stringValue: @"bar"]) && - R([nodes[1] addAttributeWithName: @"foo" - namespace: @"urn:objfw:test" - stringValue: @"ignored"]) && - [[nodes[1] XMLString] isEqual: + R([node2 addAttributeWithName: @"foo" + namespace: @"urn:objfw:test" + stringValue: @"bar"]) && + R([node2 addAttributeWithName: @"foo" + namespace: @"urn:objfw:test" + stringValue: @"ignored"]) && + [[node2 XMLString] isEqual: @"b&ar"]) TEST(@"-[removeAttributeForName:namespace:]", - R([nodes[1] removeAttributeForName: @"foo"]) && - [[nodes[1] XMLString] isEqual: + R([node2 removeAttributeForName: @"foo"]) && + [[node2 XMLString] isEqual: @"b&ar"] && - R([nodes[1] removeAttributeForName: @"foo" - namespace: @"urn:objfw:test"]) && - [[nodes[1] XMLString] isEqual: @"b&ar"]) + R([node2 removeAttributeForName: @"foo" + namespace: @"urn:objfw:test"]) && + [[node2 XMLString] isEqual: @"b&ar"]) TEST(@"-[addChild:]", - R([nodes[0] addChild: [OFXMLElement elementWithName: @"bar"]]) && - [[nodes[0] XMLString] isEqual: + R([node1 addChild: [OFXMLElement elementWithName: @"bar"]]) && + [[node1 XMLString] isEqual: @""] && - R([nodes[2] addChild: [OFXMLElement elementWithName: @"bar" - namespace: @"urn:objfw:test"]]) && - [[nodes[2] XMLString] isEqual: + R([node3 addChild: [OFXMLElement elementWithName: @"bar" + namespace: @"urn:objfw:test"]]) && + [[node3 XMLString] isEqual: @""]) TEST(@"+[elementWithXMLString:] and -[stringValue]", [[[OFXMLElement elementWithXMLString: @"\r\nfoo" @"bazqux"] stringValue] isEqual: @"foobarbazqux"]) TEST(@"-[elementsForName:namespace:]", - (a = [nodes[2] elementsForName: @"bar" - namespace: @"urn:objfw:test"]) && - a.count == 1 && [[[a firstObject] XMLString] isEqual: + (array = [node3 elementsForName: @"bar" + namespace: @"urn:objfw:test"]) && + array.count == 1 && [[array.firstObject XMLString] isEqual: @""]) TEST(@"-[isEqual:]", [[OFXMLElement elementWithXMLString: @""] isEqual: [OFXMLElement elementWithXMLString: @""]] && Index: tests/OFXMLParserTests.m ================================================================== --- tests/OFXMLParserTests.m +++ tests/OFXMLParserTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -20,98 +18,114 @@ #include #include #import "TestsAppDelegate.h" -static OFString *module = @"OFXMLParser"; +static OFString *const module = @"OFXMLParser"; static int i = 0; -enum event_type { - PROCESSING_INSTRUCTIONS, - TAG_OPEN, - TAG_CLOSE, - STRING, - CDATA, - COMMENT +enum EventType { + eventTypeProcessingInstruction, + eventTypeTagOpen, + eventTypeTagClose, + eventTypeString, + eventTypeCDATA, + eventTypeComment }; @implementation TestsAppDelegate (OFXMLParser) - (void)parser: (OFXMLParser *)parser - didCreateEvent: (enum event_type)type + didCreateEvent: (enum EventType)type name: (OFString *)name prefix: (OFString *)prefix - namespace: (OFString *)ns + namespace: (OFString *)namespace attributes: (OFArray *)attrs string: (OFString *)string { - OFString *msg; + OFString *message; i++; - msg = [OFString stringWithFormat: @"Parsing part #%d", i]; + message = [OFString stringWithFormat: @"Parsing part #%d", i]; switch (i) { case 1: - TEST(msg, type == PROCESSING_INSTRUCTIONS && - [string isEqual: @"xml version='1.0'"]) + TEST(message, + type == eventTypeProcessingInstruction && + [name isEqual: @"xml"] && + [string isEqual: @"version='1.0'"]) break; case 2: - TEST(msg, type == PROCESSING_INSTRUCTIONS && - [string isEqual: @"p?i"]) + TEST(message, + type == eventTypeProcessingInstruction && + [name isEqual: @"p?i"] && string == nil) break; case 3: - TEST(msg, type == TAG_OPEN && [name isEqual: @"root"] && - prefix == nil && ns == nil && attrs.count == 0) + TEST(message, + type == eventTypeTagOpen && [name isEqual: @"root"] && + prefix == nil && namespace == nil && attrs.count == 0) break; case 4: - TEST(msg, type == STRING && [string isEqual: @"\n\n "]) + TEST(message, + type == eventTypeString && [string isEqual: @"\n\n "]) break; case 5: - TEST(msg, type == CDATA && [string isEqual: @"f<]]]oo]"] && + TEST(message, + type == eventTypeCDATA && [string isEqual: @"f<]]]oo]"] && parser.lineNumber == 3) break; case 6: - TEST(msg, type == TAG_OPEN && [name isEqual: @"bar"] && - prefix == nil && ns == nil && attrs == nil) + TEST(message, + type == eventTypeTagOpen && [name isEqual: @"bar"] && + prefix == nil && namespace == nil && attrs == nil) break; case 7: - TEST(msg, type == TAG_CLOSE && [name isEqual: @"bar"] && - prefix == nil && ns == nil && attrs == nil) + TEST(message, + type == eventTypeTagClose && [name isEqual: @"bar"] && + prefix == nil && namespace == nil && attrs == nil) break; case 8: - TEST(msg, type == STRING && [string isEqual: @"\n "]) + TEST(message, + type == eventTypeString && [string isEqual: @"\n "]) break; case 9: - TEST(msg, type == TAG_OPEN && [name isEqual: @"foobar"] && - prefix == nil && [ns isEqual: @"urn:objfw:test:foobar"] && + TEST(message, + type == eventTypeTagOpen && [name isEqual: @"foobar"] && + prefix == nil && + [namespace isEqual: @"urn:objfw:test:foobar"] && attrs.count == 1 && /* xmlns attr */ [[[attrs objectAtIndex: 0] name] isEqual: @"xmlns"] && [[attrs objectAtIndex: 0] namespace] == nil && [[[attrs objectAtIndex: 0] stringValue] isEqual: @"urn:objfw:test:foobar"]) break; case 10: - TEST(msg, type == STRING && [string isEqual: @"\n "]) + TEST(message, + type == eventTypeString && [string isEqual: @"\n "]) break; case 11: - TEST(msg, type == TAG_OPEN && [name isEqual: @"qux"] && - prefix == nil && [ns isEqual: @"urn:objfw:test:foobar"] && + TEST(message, + type == eventTypeTagOpen && [name isEqual: @"qux"] && + prefix == nil && + [namespace isEqual: @"urn:objfw:test:foobar"] && attrs.count == 1 && /* xmlns:foo attr */ [[[attrs objectAtIndex: 0] name] isEqual: @"foo"] && [[[attrs objectAtIndex: 0] namespace] isEqual: @"http://www.w3.org/2000/xmlns/"] && [[[attrs objectAtIndex: 0] stringValue] isEqual: @"urn:objfw:test:foo"]) break; case 12: - TEST(msg, type == STRING && [string isEqual: @"\n "]) + TEST(message, + type == eventTypeString && [string isEqual: @"\n "]) break; case 13: - TEST(msg, type == TAG_OPEN && [name isEqual: @"bla"] && + TEST(message, + type == eventTypeTagOpen && [name isEqual: @"bla"] && [prefix isEqual: @"foo"] && - [ns isEqual: @"urn:objfw:test:foo"] && + [namespace isEqual: @"urn:objfw:test:foo"] && attrs.count == 2 && /* foo:bla attr */ [[[attrs objectAtIndex: 0] name] isEqual: @"bla"] && [[[attrs objectAtIndex: 0] namespace] isEqual: @"urn:objfw:test:foo"] && @@ -120,15 +134,18 @@ [[[attrs objectAtIndex: 1] name] isEqual: @"blafoo"] && [[attrs objectAtIndex: 1] namespace] == nil && [[[attrs objectAtIndex: 1] stringValue] isEqual: @"foo"]) break; case 14: - TEST(msg, type == STRING && [string isEqual: @"\n "]) + TEST(message, + type == eventTypeString && [string isEqual: @"\n "]) break; case 15: - TEST(msg, type == TAG_OPEN && [name isEqual: @"blup"] && - prefix == nil && [ns isEqual: @"urn:objfw:test:foobar"] && + TEST(message, + type == eventTypeTagOpen && [name isEqual: @"blup"] && + prefix == nil && + [namespace isEqual: @"urn:objfw:test:foobar"] && attrs.count == 2 && /* foo:qux attr */ [[[attrs objectAtIndex: 0] name] isEqual: @"qux"] && [[[attrs objectAtIndex: 0] namespace] isEqual: @"urn:objfw:test:foo"] && @@ -137,20 +154,25 @@ [[[attrs objectAtIndex: 1] name] isEqual: @"quxqux"] && [[attrs objectAtIndex: 1] namespace] == nil && [[[attrs objectAtIndex: 1] stringValue] isEqual: @"test"]) break; case 16: - TEST(msg, type == TAG_CLOSE && [name isEqual: @"blup"] && - prefix == nil && [ns isEqual: @"urn:objfw:test:foobar"]) + TEST(message, + type == eventTypeTagClose && [name isEqual: @"blup"] && + prefix == nil && + [namespace isEqual: @"urn:objfw:test:foobar"]) break; case 17: - TEST(msg, type == STRING && [string isEqual: @"\n "]) + TEST(message, + type == eventTypeString && [string isEqual: @"\n "]) break; case 18: - TEST(msg, type == TAG_OPEN && [name isEqual: @"bla"] && + TEST(message, + type == eventTypeTagOpen && [name isEqual: @"bla"] && [prefix isEqual: @"bla"] && - [ns isEqual: @"urn:objfw:test:bla"] && attrs.count == 3 && + [namespace isEqual: @"urn:objfw:test:bla"] && + attrs.count == 3 && /* xmlns:bla attr */ [[[attrs objectAtIndex: 0] name] isEqual: @"bla"] && [[[attrs objectAtIndex: 0] namespace] isEqual: @"http://www.w3.org/2000/xmlns/"] && [[[attrs objectAtIndex: 0] stringValue] isEqual: @@ -164,20 +186,24 @@ [[[attrs objectAtIndex: 2] namespace] isEqual: @"urn:objfw:test:bla"] && [[[attrs objectAtIndex: 2] stringValue] isEqual: @"blafoo"]) break; case 19: - TEST(msg, type == TAG_CLOSE && [name isEqual: @"bla"] && + TEST(message, + type == eventTypeTagClose && [name isEqual: @"bla"] && [prefix isEqual: @"bla"] && - [ns isEqual: @"urn:objfw:test:bla"]) + [namespace isEqual: @"urn:objfw:test:bla"]) break; case 20: - TEST(msg, type == STRING && [string isEqual: @"\n "]) + TEST(message, + type == eventTypeString && [string isEqual: @"\n "]) break; case 21: - TEST(msg, type == TAG_OPEN && [name isEqual: @"abc"] && - prefix == nil && [ns isEqual: @"urn:objfw:test:abc"] && + TEST(message, + type == eventTypeTagOpen && [name isEqual: @"abc"] && + prefix == nil && + [namespace isEqual: @"urn:objfw:test:abc"] && attrs.count == 3 && /* xmlns attr */ [[[attrs objectAtIndex: 0] name] isEqual: @"xmlns"] && [[attrs objectAtIndex: 0] namespace] == nil && [[[attrs objectAtIndex: 0] stringValue] isEqual: @@ -191,121 +217,132 @@ [[[attrs objectAtIndex: 2] namespace] isEqual: @"urn:objfw:test:foo"] && [[[attrs objectAtIndex: 2] stringValue] isEqual: @"abc"]) break; case 22: - TEST(msg, type == TAG_CLOSE && [name isEqual: @"abc"] && - prefix == nil && [ns isEqual: @"urn:objfw:test:abc"]) - break; - case 23: - TEST(msg, type == STRING && [string isEqual: @"\n "]) - break; - case 24: - TEST(msg, type == TAG_CLOSE && [name isEqual: @"bla"] && - [prefix isEqual: @"foo"] && - [ns isEqual: @"urn:objfw:test:foo"]) - break; - case 25: - TEST(msg, type == STRING && [string isEqual: @"\n "]) - break; - case 26: - TEST(msg, type == COMMENT && [string isEqual: @" commänt "]) - break; - case 27: - TEST(msg, type == STRING && [string isEqual: @"\n "]) - break; - case 28: - TEST(msg, type == TAG_CLOSE && [name isEqual: @"qux"] && - prefix == nil && [ns isEqual: @"urn:objfw:test:foobar"]) - break; - case 29: - TEST(msg, type == STRING && [string isEqual: @"\n "]) - break; - case 30: - TEST(msg, type == TAG_CLOSE && [name isEqual: @"foobar"] && - prefix == nil && [ns isEqual: @"urn:objfw:test:foobar"]) - break; - case 31: - TEST(msg, type == STRING && [string isEqual: @"\n"]) - break; - case 32: - TEST(msg, type == TAG_CLOSE && [name isEqual: @"root"] && - prefix == nil && ns == nil); - break; - } -} - -- (void)parser: (OFXMLParser *)parser - foundProcessingInstructions: (OFString *)pi -{ - [self parser: parser - didCreateEvent: PROCESSING_INSTRUCTIONS - name: nil - prefix: nil - namespace: nil - attributes: nil - string: pi]; + TEST(message, + type == eventTypeTagClose && [name isEqual: @"abc"] && + prefix == nil && [namespace isEqual: @"urn:objfw:test:abc"]) + break; + case 23: + TEST(message, + type == eventTypeString && [string isEqual: @"\n "]) + break; + case 24: + TEST(message, + type == eventTypeTagClose && [name isEqual: @"bla"] && + [prefix isEqual: @"foo"] && + [namespace isEqual: @"urn:objfw:test:foo"]) + break; + case 25: + TEST(message, + type == eventTypeString && [string isEqual: @"\n "]) + break; + case 26: + TEST(message, + type == eventTypeComment && [string isEqual: @" commänt "]) + break; + case 27: + TEST(message, + type == eventTypeString && [string isEqual: @"\n "]) + break; + case 28: + TEST(message, + type == eventTypeTagClose && [name isEqual: @"qux"] && + prefix == nil && + [namespace isEqual: @"urn:objfw:test:foobar"]) + break; + case 29: + TEST(message, + type == eventTypeString && [string isEqual: @"\n "]) + break; + case 30: + TEST(message, + type == eventTypeTagClose && [name isEqual: @"foobar"] && + prefix == nil && + [namespace isEqual: @"urn:objfw:test:foobar"]) + break; + case 31: + TEST(message, + type == eventTypeString && [string isEqual: @"\n"]) + break; + case 32: + TEST(message, + type == eventTypeTagClose && [name isEqual: @"root"] && + prefix == nil && namespace == nil); + break; + } +} + +- (void)parser: (OFXMLParser *)parser + foundProcessingInstructionWithTarget: (OFString *)target + data: (OFString *)data +{ + [self parser: parser + didCreateEvent: eventTypeProcessingInstruction + name: target + prefix: nil + namespace: nil + attributes: nil + string: data]; } - (void)parser: (OFXMLParser *)parser didStartElement: (OFString *)name prefix: (OFString *)prefix - namespace: (OFString *)ns + namespace: (OFString *)namespace attributes: (OFArray *)attrs { [self parser: parser - didCreateEvent: TAG_OPEN + didCreateEvent: eventTypeTagOpen name: name prefix: prefix - namespace: ns + namespace: namespace attributes: attrs string: nil]; } - (void)parser: (OFXMLParser *)parser didEndElement: (OFString *)name prefix: (OFString *)prefix - namespace: (OFString *)ns + namespace: (OFString *)namespace { [self parser: parser - didCreateEvent: TAG_CLOSE + didCreateEvent: eventTypeTagClose name: name prefix: prefix - namespace: ns + namespace: namespace attributes: nil string: nil]; } -- (void)parser: (OFXMLParser *)parser - foundCharacters: (OFString *)string +- (void)parser: (OFXMLParser *)parser foundCharacters: (OFString *)string { [self parser: parser - didCreateEvent: STRING + didCreateEvent: eventTypeString name: nil prefix: nil namespace: nil attributes: nil string: string]; } -- (void)parser: (OFXMLParser *)parser - foundCDATA: (OFString *)cdata +- (void)parser: (OFXMLParser *)parser foundCDATA: (OFString *)CDATA { [self parser: parser - didCreateEvent: CDATA + didCreateEvent: eventTypeCDATA name: nil prefix: nil namespace: nil attributes: nil - string: cdata]; + string: CDATA]; } -- (void)parser: (OFXMLParser *)parser - foundComment: (OFString *)comment +- (void)parser: (OFXMLParser *)parser foundComment: (OFString *)comment { [self parser: parser - didCreateEvent: COMMENT + didCreateEvent: eventTypeComment name: nil prefix: nil namespace: nil attributes: nil string: comment]; @@ -321,11 +358,11 @@ } - (void)XMLParserTests { void *pool = objc_autoreleasePoolPush(); - const char *str = "\xEF\xBB\xBF" + const char *string = "\xEF\xBB\xBF" "\r\r" " \n" " \r\n" " \n" " \n" @@ -337,29 +374,27 @@ " \n" " \n" " \n" ""; OFXMLParser *parser; - size_t j, len; + size_t j, length; TEST(@"+[parser]", (parser = [OFXMLParser parser])) TEST(@"-[setDelegate:]", (parser.delegate = self)) /* Simulate a stream where we only get chunks */ - len = strlen(str); + length = strlen(string); - for (j = 0; j < len; j+= 2) { + for (j = 0; j < length; j+= 2) { if (parser.hasFinishedParsing) abort(); - if (j + 2 > len) - [parser parseBuffer: str + j - length: 1]; + if (j + 2 > length) + [parser parseBuffer: string + j length: 1]; else - [parser parseBuffer: str + j - length: 2]; + [parser parseBuffer: string + j length: 2]; } TEST(@"Checking if everything was parsed", i == 32 && parser.lineNumber == 18) @@ -376,22 +411,22 @@ EXPECT_EXCEPTION(@"Detection of junk after the document #2", OFMalformedXMLException, [parser parseString: @""]) parser = [OFXMLParser parser]; - EXPECT_EXCEPTION(@"Detection of invalid XML processing instructions #2", + EXPECT_EXCEPTION(@"Detection of invalid XML processing instruction #2", OFInvalidEncodingException, [parser parseString: @""]) parser = [OFXMLParser parser]; - EXPECT_EXCEPTION(@"Detection of invalid XML processing instructions #3", + EXPECT_EXCEPTION(@"Detection of invalid XML processing instruction #3", OFMalformedXMLException, [parser parseString: @""]) objc_autoreleasePoolPop(pool); } @end DELETED tests/PBKDF2Tests.m Index: tests/PBKDF2Tests.m ================================================================== --- tests/PBKDF2Tests.m +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 *module = @"PBKDF2"; - -@implementation TestsAppDelegate (PBKDF2Tests) -- (void)PBKDF2Tests -{ - void *pool = objc_autoreleasePoolPush(); - OFHMAC *HMAC = [OFHMAC HMACWithHashClass: [OFSHA1Hash class] - allowsSwappableMemory: true]; - unsigned char key[25]; - - /* Test vectors from RFC 6070 */ - - TEST(@"PBKDF2-SHA1, 1 iteration", - R(of_pbkdf2((of_pbkdf2_parameters_t){ - .HMAC = HMAC, - .iterations = 1, - .salt = (unsigned char *)"salt", - .saltLength = 4, - .password = "password", - .passwordLength = 8, - .key = key, - .keyLength = 20, - .allowsSwappableMemory = true - })) && memcmp(key, "\x0C\x60\xC8\x0F\x96\x1F\x0E\x71\xF3\xA9\xB5" - "\x24\xAF\x60\x12\x06\x2F\xE0\x37\xA6", 20) == 0) - - TEST(@"PBKDF2-SHA1, 2 iterations", - R(of_pbkdf2((of_pbkdf2_parameters_t){ - .HMAC = HMAC, - .iterations = 2, - .salt = (unsigned char *)"salt", - .saltLength = 4, - .password = "password", - .passwordLength = 8, - .key = key, - .keyLength = 20, - .allowsSwappableMemory = true - })) && memcmp(key, "\xEA\x6C\x01\x4D\xC7\x2D\x6F\x8C\xCD\x1E\xD9" - "\x2A\xCE\x1D\x41\xF0\xD8\xDE\x89\x57", 20) == 0) - - TEST(@"PBKDF2-SHA1, 4096 iterations", - R(of_pbkdf2((of_pbkdf2_parameters_t){ - .HMAC = HMAC, - .iterations = 4096, - .salt = (unsigned char *)"salt", - .saltLength = 4, - .password = "password", - .passwordLength = 8, - .key = key, - .keyLength = 20, - .allowsSwappableMemory = true - })) && memcmp(key, "\x4B\x00\x79\x01\xB7\x65\x48\x9A\xBE\xAD\x49" - "\xD9\x26\xF7\x21\xD0\x65\xA4\x29\xC1", 20) == 0) - - /* This test takes too long, even on a fast machine. */ -#if 0 - TEST(@"PBKDF2-SHA1, 16777216 iterations", - R(of_pbkdf2((of_pbkdf2_parameters_t){ - .HMAC = HMAC, - .iterations = 16777216, - .salt = (unsigned char *)"salt", - .saltLength = 4, - .password = "password", - .passwordLength = 8, - .key = key, - .keyLength = 20, - .allowsSwappableMemory = true - })) && memcmp(key, "\xEE\xFE\x3D\x61\xCD\x4D\xA4\xE4\xE9\x94\x5B" - "\x3D\x6B\xA2\x15\x8C\x26\x34\xE9\x84", 20) == 0) -#endif - - TEST(@"PBKDF2-SHA1, 4096 iterations, key > 1 block", - R(of_pbkdf2((of_pbkdf2_parameters_t){ - .HMAC = HMAC, - .iterations = 4096, - .salt = (unsigned char *)"saltSALTsaltSALTsalt" - "SALTsaltSALTsalt", - .saltLength = 36, - .password = "passwordPASSWORDpassword", - .passwordLength = 24, - .key = key, - .keyLength = 25, - .allowsSwappableMemory = true - })) && - memcmp(key, "\x3D\x2E\xEC\x4F\xE4\x1C\x84\x9B\x80\xC8\xD8\x36\x62" - "\xC0\xE4\x4A\x8B\x29\x1A\x96\x4C\xF2\xF0\x70\x38", 25) == 0) - - TEST(@"PBKDF2-SHA1, 4096 iterations, key < 1 block", - R(of_pbkdf2((of_pbkdf2_parameters_t){ - .HMAC = HMAC, - .iterations = 4096, - .salt = (unsigned char *)"sa\0lt", - .saltLength = 5, - .password = "pass\0word", - .passwordLength = 9, - .key = key, - .keyLength = 16, - .allowsSwappableMemory = true - })) && memcmp(key, "\x56\xFA\x6A\xA7\x55\x48\x09\x9D\xCC\x37\xD7" - "\xF0\x34\x25\xE0\xC3", 16) == 0) - - objc_autoreleasePoolPop(pool); -} -@end Index: tests/RuntimeARCTests.m ================================================================== --- tests/RuntimeARCTests.m +++ tests/RuntimeARCTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -17,30 +15,47 @@ #include "config.h" #import "TestsAppDelegate.h" -static OFString *module = @"Runtime (ARC)"; +static OFString *const module = @"Runtime (ARC)"; @interface RuntimeARCTest: OFObject @end @implementation RuntimeARCTest - (instancetype)init { self = [super init]; +#ifdef OF_WINDOWS + /* + * Clang has a bug on Windows where it creates an invalid call into + * objc_retainAutoreleasedReturnValue(). Work around it by not using an + * autoreleased exception. + */ + @throw [[OFException alloc] init]; +#else @throw [OFException exception]; +#endif return self; } @end @implementation TestsAppDelegate (RuntimeARCTests) - (void)runtimeARCTests { id object; + __weak id weak; EXPECT_EXCEPTION(@"Exceptions in init", OFException, object = [[RuntimeARCTest alloc] init]) + + object = [[OFObject alloc] init]; + weak = object; + TEST(@"weakly referencing an object", weak == object) + + object = nil; + TEST(@"weak references becoming nil", weak == nil) } @end Index: tests/RuntimeTests.m ================================================================== --- tests/RuntimeTests.m +++ tests/RuntimeTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -17,11 +15,11 @@ #include "config.h" #import "TestsAppDelegate.h" -static OFString *module = @"Runtime"; +static OFString *const module = @"Runtime"; @interface OFObject (SuperTest) - (id)superTest; @end @@ -63,33 +61,34 @@ @implementation TestsAppDelegate (RuntimeTests) - (void)runtimeTests { void *pool = objc_autoreleasePoolPush(); - RuntimeTest *rt = [[[RuntimeTest alloc] init] autorelease]; - OFString *t, *foo; + RuntimeTest *test = [[[RuntimeTest alloc] init] autorelease]; + OFString *string, *foo; #ifdef OF_OBJFW_RUNTIME - int cid1, cid2; + int classID; uintmax_t value; id object; #endif EXPECT_EXCEPTION(@"Calling a non-existent method via super", - OFNotImplementedException, [rt superTest]) + OFNotImplementedException, [test superTest]) TEST(@"Calling a method via a super with self == nil", - [rt nilSuperTest] == nil) + [test nilSuperTest] == nil) - t = [OFMutableString stringWithString: @"foo"]; + string = [OFMutableString stringWithString: @"foo"]; foo = @"foo"; - [rt setFoo: t]; - TEST(@"copy, nonatomic properties", [rt.foo isEqual: foo] && - rt.foo != foo && rt.foo.retainCount == 1) + test.foo = string; + TEST(@"copy, nonatomic properties", [test.foo isEqual: foo] && + test.foo != foo && test.foo.retainCount == 1) - rt.bar = t; - TEST(@"retain, atomic properties", rt.bar == t && t.retainCount == 3) + test.bar = string; + TEST(@"retain, atomic properties", + test.bar == string && string.retainCount == 3) #ifdef OF_OBJFW_RUNTIME if (sizeof(uintptr_t) == 8) value = 0xDEADBEEFDEADBEF; else if (sizeof(uintptr_t) == 4) @@ -96,18 +95,19 @@ value = 0xDEADBEF; else abort(); TEST(@"Tagged pointers", - (cid1 = objc_registerTaggedPointerClass([OFString class])) != -1 && - (cid2 = objc_registerTaggedPointerClass([OFNumber class])) != -1 && - (object = objc_createTaggedPointer(cid2, (uintptr_t)value)) && + objc_registerTaggedPointerClass([OFString class]) != -1 && + (classID = objc_registerTaggedPointerClass([OFNumber class])) != + -1 && + (object = objc_createTaggedPointer(classID, (uintptr_t)value)) && object_getClass(object) == [OFNumber class] && [object class] == [OFNumber class] && object_getTaggedPointerValue(object) == value && - objc_createTaggedPointer(cid2, UINTPTR_MAX >> 4) != nil && - objc_createTaggedPointer(cid2, (UINTPTR_MAX >> 4) + 1) == nil) + objc_createTaggedPointer(classID, UINTPTR_MAX >> 4) != nil && + objc_createTaggedPointer(classID, (UINTPTR_MAX >> 4) + 1) == nil) #endif objc_autoreleasePoolPop(pool); } @end DELETED tests/ScryptTests.m Index: tests/ScryptTests.m ================================================================== --- tests/ScryptTests.m +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 *module = @"scrypt"; -/* Test vectors form RFC 7914 */ -static const unsigned char salsa20Input[64] = { - 0x7E, 0x87, 0x9A, 0x21, 0x4F, 0x3E, 0xC9, 0x86, 0x7C, 0xA9, 0x40, 0xE6, - 0x41, 0x71, 0x8F, 0x26, 0xBA, 0xEE, 0x55, 0x5B, 0x8C, 0x61, 0xC1, 0xB5, - 0x0D, 0xF8, 0x46, 0x11, 0x6D, 0xCD, 0x3B, 0x1D, 0xEE, 0x24, 0xF3, 0x19, - 0xDF, 0x9B, 0x3D, 0x85, 0x14, 0x12, 0x1E, 0x4B, 0x5A, 0xC5, 0xAA, 0x32, - 0x76, 0x02, 0x1D, 0x29, 0x09, 0xC7, 0x48, 0x29, 0xED, 0xEB, 0xC6, 0x8D, - 0xB8, 0xB8, 0xC2, 0x5E -}; -static const unsigned char salsa20Output[64] = { - 0xA4, 0x1F, 0x85, 0x9C, 0x66, 0x08, 0xCC, 0x99, 0x3B, 0x81, 0xCA, 0xCB, - 0x02, 0x0C, 0xEF, 0x05, 0x04, 0x4B, 0x21, 0x81, 0xA2, 0xFD, 0x33, 0x7D, - 0xFD, 0x7B, 0x1C, 0x63, 0x96, 0x68, 0x2F, 0x29, 0xB4, 0x39, 0x31, 0x68, - 0xE3, 0xC9, 0xE6, 0xBC, 0xFE, 0x6B, 0xC5, 0xB7, 0xA0, 0x6D, 0x96, 0xBA, - 0xE4, 0x24, 0xCC, 0x10, 0x2C, 0x91, 0x74, 0x5C, 0x24, 0xAD, 0x67, 0x3D, - 0xC7, 0x61, 0x8F, 0x81 -}; -static const union { - unsigned char uc[128]; - uint32_t u32[32]; -} blockMixInput = { .uc = { - 0xF7, 0xCE, 0x0B, 0x65, 0x3D, 0x2D, 0x72, 0xA4, 0x10, 0x8C, 0xF5, 0xAB, - 0xE9, 0x12, 0xFF, 0xDD, 0x77, 0x76, 0x16, 0xDB, 0xBB, 0x27, 0xA7, 0x0E, - 0x82, 0x04, 0xF3, 0xAE, 0x2D, 0x0F, 0x6F, 0xAD, 0x89, 0xF6, 0x8F, 0x48, - 0x11, 0xD1, 0xE8, 0x7B, 0xCC, 0x3B, 0xD7, 0x40, 0x0A, 0x9F, 0xFD, 0x29, - 0x09, 0x4F, 0x01, 0x84, 0x63, 0x95, 0x74, 0xF3, 0x9A, 0xE5, 0xA1, 0x31, - 0x52, 0x17, 0xBC, 0xD7, - 0x89, 0x49, 0x91, 0x44, 0x72, 0x13, 0xBB, 0x22, 0x6C, 0x25, 0xB5, 0x4D, - 0xA8, 0x63, 0x70, 0xFB, 0xCD, 0x98, 0x43, 0x80, 0x37, 0x46, 0x66, 0xBB, - 0x8F, 0xFC, 0xB5, 0xBF, 0x40, 0xC2, 0x54, 0xB0, 0x67, 0xD2, 0x7C, 0x51, - 0xCE, 0x4A, 0xD5, 0xFE, 0xD8, 0x29, 0xC9, 0x0B, 0x50, 0x5A, 0x57, 0x1B, - 0x7F, 0x4D, 0x1C, 0xAD, 0x6A, 0x52, 0x3C, 0xDA, 0x77, 0x0E, 0x67, 0xBC, - 0xEA, 0xAF, 0x7E, 0x89 -}}; -static const unsigned char blockMixOutput[128] = { - 0xA4, 0x1F, 0x85, 0x9C, 0x66, 0x08, 0xCC, 0x99, 0x3B, 0x81, 0xCA, 0xCB, - 0x02, 0x0C, 0xEF, 0x05, 0x04, 0x4B, 0x21, 0x81, 0xA2, 0xFD, 0x33, 0x7D, - 0xFD, 0x7B, 0x1C, 0x63, 0x96, 0x68, 0x2F, 0x29, 0xB4, 0x39, 0x31, 0x68, - 0xE3, 0xC9, 0xE6, 0xBC, 0xFE, 0x6B, 0xC5, 0xB7, 0xA0, 0x6D, 0x96, 0xBA, - 0xE4, 0x24, 0xCC, 0x10, 0x2C, 0x91, 0x74, 0x5C, 0x24, 0xAD, 0x67, 0x3D, - 0xC7, 0x61, 0x8F, 0x81, - 0x20, 0xED, 0xC9, 0x75, 0x32, 0x38, 0x81, 0xA8, 0x05, 0x40, 0xF6, 0x4C, - 0x16, 0x2D, 0xCD, 0x3C, 0x21, 0x07, 0x7C, 0xFE, 0x5F, 0x8D, 0x5F, 0xE2, - 0xB1, 0xA4, 0x16, 0x8F, 0x95, 0x36, 0x78, 0xB7, 0x7D, 0x3B, 0x3D, 0x80, - 0x3B, 0x60, 0xE4, 0xAB, 0x92, 0x09, 0x96, 0xE5, 0x9B, 0x4D, 0x53, 0xB6, - 0x5D, 0x2A, 0x22, 0x58, 0x77, 0xD5, 0xED, 0xF5, 0x84, 0x2C, 0xB9, 0xF1, - 0x4E, 0xEF, 0xE4, 0x25 -}; -static const unsigned char ROMixInput[128] = { - 0xF7, 0xCE, 0x0B, 0x65, 0x3D, 0x2D, 0x72, 0xA4, 0x10, 0x8C, 0xF5, 0xAB, - 0xE9, 0x12, 0xFF, 0xDD, 0x77, 0x76, 0x16, 0xDB, 0xBB, 0x27, 0xA7, 0x0E, - 0x82, 0x04, 0xF3, 0xAE, 0x2D, 0x0F, 0x6F, 0xAD, 0x89, 0xF6, 0x8F, 0x48, - 0x11, 0xD1, 0xE8, 0x7B, 0xCC, 0x3B, 0xD7, 0x40, 0x0A, 0x9F, 0xFD, 0x29, - 0x09, 0x4F, 0x01, 0x84, 0x63, 0x95, 0x74, 0xF3, 0x9A, 0xE5, 0xA1, 0x31, - 0x52, 0x17, 0xBC, 0xD7, 0x89, 0x49, 0x91, 0x44, 0x72, 0x13, 0xBB, 0x22, - 0x6C, 0x25, 0xB5, 0x4D, 0xA8, 0x63, 0x70, 0xFB, 0xCD, 0x98, 0x43, 0x80, - 0x37, 0x46, 0x66, 0xBB, 0x8F, 0xFC, 0xB5, 0xBF, 0x40, 0xC2, 0x54, 0xB0, - 0x67, 0xD2, 0x7C, 0x51, 0xCE, 0x4A, 0xD5, 0xFE, 0xD8, 0x29, 0xC9, 0x0B, - 0x50, 0x5A, 0x57, 0x1B, 0x7F, 0x4D, 0x1C, 0xAD, 0x6A, 0x52, 0x3C, 0xDA, - 0x77, 0x0E, 0x67, 0xBC, 0xEA, 0xAF, 0x7E, 0x89 -}; -static const unsigned char ROMixOutput[128] = { - 0x79, 0xCC, 0xC1, 0x93, 0x62, 0x9D, 0xEB, 0xCA, 0x04, 0x7F, 0x0B, 0x70, - 0x60, 0x4B, 0xF6, 0xB6, 0x2C, 0xE3, 0xDD, 0x4A, 0x96, 0x26, 0xE3, 0x55, - 0xFA, 0xFC, 0x61, 0x98, 0xE6, 0xEA, 0x2B, 0x46, 0xD5, 0x84, 0x13, 0x67, - 0x3B, 0x99, 0xB0, 0x29, 0xD6, 0x65, 0xC3, 0x57, 0x60, 0x1F, 0xB4, 0x26, - 0xA0, 0xB2, 0xF4, 0xBB, 0xA2, 0x00, 0xEE, 0x9F, 0x0A, 0x43, 0xD1, 0x9B, - 0x57, 0x1A, 0x9C, 0x71, 0xEF, 0x11, 0x42, 0xE6, 0x5D, 0x5A, 0x26, 0x6F, - 0xDD, 0xCA, 0x83, 0x2C, 0xE5, 0x9F, 0xAA, 0x7C, 0xAC, 0x0B, 0x9C, 0xF1, - 0xBE, 0x2B, 0xFF, 0xCA, 0x30, 0x0D, 0x01, 0xEE, 0x38, 0x76, 0x19, 0xC4, - 0xAE, 0x12, 0xFD, 0x44, 0x38, 0xF2, 0x03, 0xA0, 0xE4, 0xE1, 0xC4, 0x7E, - 0xC3, 0x14, 0x86, 0x1F, 0x4E, 0x90, 0x87, 0xCB, 0x33, 0x39, 0x6A, 0x68, - 0x73, 0xE8, 0xF9, 0xD2, 0x53, 0x9A, 0x4B, 0x8E -}; -static const unsigned char testVector1[64] = { - 0x77, 0xD6, 0x57, 0x62, 0x38, 0x65, 0x7B, 0x20, 0x3B, 0x19, 0xCA, 0x42, - 0xC1, 0x8A, 0x04, 0x97, 0xF1, 0x6B, 0x48, 0x44, 0xE3, 0x07, 0x4A, 0xE8, - 0xDF, 0xDF, 0xFA, 0x3F, 0xED, 0xE2, 0x14, 0x42, 0xFC, 0xD0, 0x06, 0x9D, - 0xED, 0x09, 0x48, 0xF8, 0x32, 0x6A, 0x75, 0x3A, 0x0F, 0xC8, 0x1F, 0x17, - 0xE8, 0xD3, 0xE0, 0xFB, 0x2E, 0x0D, 0x36, 0x28, 0xCF, 0x35, 0xE2, 0x0C, - 0x38, 0xD1, 0x89, 0x06 -}; -static const unsigned char testVector2[64] = { - 0xFD, 0xBA, 0xBE, 0x1C, 0x9D, 0x34, 0x72, 0x00, 0x78, 0x56, 0xE7, 0x19, - 0x0D, 0x01, 0xE9, 0xFE, 0x7C, 0x6A, 0xD7, 0xCB, 0xC8, 0x23, 0x78, 0x30, - 0xE7, 0x73, 0x76, 0x63, 0x4B, 0x37, 0x31, 0x62, 0x2E, 0xAF, 0x30, 0xD9, - 0x2E, 0x22, 0xA3, 0x88, 0x6F, 0xF1, 0x09, 0x27, 0x9D, 0x98, 0x30, 0xDA, - 0xC7, 0x27, 0xAF, 0xB9, 0x4A, 0x83, 0xEE, 0x6D, 0x83, 0x60, 0xCB, 0xDF, - 0xA2, 0xCC, 0x06, 0x40 -}; -static const unsigned char testVector3[64] = { - 0x70, 0x23, 0xBD, 0xCB, 0x3A, 0xFD, 0x73, 0x48, 0x46, 0x1C, 0x06, 0xCD, - 0x81, 0xFD, 0x38, 0xEB, 0xFD, 0xA8, 0xFB, 0xBA, 0x90, 0x4F, 0x8E, 0x3E, - 0xA9, 0xB5, 0x43, 0xF6, 0x54, 0x5D, 0xA1, 0xF2, 0xD5, 0x43, 0x29, 0x55, - 0x61, 0x3F, 0x0F, 0xCF, 0x62, 0xD4, 0x97, 0x05, 0x24, 0x2A, 0x9A, 0xF9, - 0xE6, 0x1E, 0x85, 0xDC, 0x0D, 0x65, 0x1E, 0x40, 0xDF, 0xCF, 0x01, 0x7B, - 0x45, 0x57, 0x58, 0x87 -}; -/* The forth test vector is too expensive to include it in the tests. */ -#if 0 -static const unsigned char testVector4[64] = { - 0x21, 0x01, 0xCB, 0x9B, 0x6A, 0x51, 0x1A, 0xAE, 0xAD, 0xDB, 0xBE, 0x09, - 0xCF, 0x70, 0xF8, 0x81, 0xEC, 0x56, 0x8D, 0x57, 0x4A, 0x2F, 0xFD, 0x4D, - 0xAB, 0xE5, 0xEE, 0x98, 0x20, 0xAD, 0xAA, 0x47, 0x8E, 0x56, 0xFD, 0x8F, - 0x4B, 0xA5, 0xD0, 0x9F, 0xFA, 0x1C, 0x6D, 0x92, 0x7C, 0x40, 0xF4, 0xC3, - 0x37, 0x30, 0x40, 0x49, 0xE8, 0xA9, 0x52, 0xFB, 0xCB, 0xF4, 0x5C, 0x6F, - 0xA7, 0x7A, 0x41, 0xA4 -}; -#endif - -@implementation TestsAppDelegate (ScryptTests) -- (void)scryptTests -{ - void *pool = objc_autoreleasePoolPush(); - uint32_t salsa20Buffer[16]; - uint32_t blockMixBuffer[32]; - uint32_t ROMixBuffer[32], ROMixTmp[17 * 32]; - unsigned char output[64]; - - TEST(@"Salsa20/8 Core", - R(memcpy(salsa20Buffer, salsa20Input, 64)) && - R(of_salsa20_8_core(salsa20Buffer)) && - memcmp(salsa20Buffer, salsa20Output, 64) == 0) - - TEST(@"Block mix", - R(of_scrypt_block_mix(blockMixBuffer, blockMixInput.u32, 1)) && - memcmp(blockMixBuffer, blockMixOutput, 128) == 0) - - TEST(@"ROMix", - R(memcpy(ROMixBuffer, ROMixInput, 128)) && - R(of_scrypt_romix(ROMixBuffer, 1, 16, ROMixTmp)) && - memcmp(ROMixBuffer, ROMixOutput, 128) == 0) - - TEST(@"scrypt test vector #1", - R(of_scrypt((of_scrypt_parameters_t){ - .blockSize = 1, - .costFactor = 16, - .parallelization = 1, - .salt = (unsigned char *)"", - .saltLength = 0, - .password = "", - .passwordLength = 0, - .key = output, - .keyLength = 64, - .allowsSwappableMemory = true - })) && memcmp(output, testVector1, 64) == 0) - - TEST(@"scrypt test vector #2", - R(of_scrypt((of_scrypt_parameters_t){ - .blockSize = 8, - .costFactor = 1024, - .parallelization = 16, - .salt = (unsigned char *)"NaCl", - .saltLength = 4, - .password = "password", - .passwordLength = 8, - .key = output, - .keyLength = 64, - .allowsSwappableMemory = true - })) && memcmp(output, testVector2, 64) == 0) - - TEST(@"scrypt test vector #3", - R(of_scrypt((of_scrypt_parameters_t){ - .blockSize = 8, - .costFactor = 16384, - .parallelization = 1, - .salt = (unsigned char *)"SodiumChloride", - .saltLength = 14, - .password = "pleaseletmein", - .passwordLength = 13, - .key = output, - .keyLength = 64, - .allowsSwappableMemory = true - })) && memcmp(output, testVector3, 64) == 0) - - /* The forth test vector is too expensive to include it in the tests. */ -#if 0 - TEST(@"scrypt test vector #4", - R(of_scrypt((of_scrypt_parameters_t){ - .blockSize = 8, - .costFactor = 1048576, - .parallelization = 1, - .salt = (unsigned char *)"SodiumChloride", - .saltLength = 14, - .password = "pleaseletmein", - .passwordLength = 13, - .key = output, - .keyLength = 64, - .allowsSwappableMemory = true - })) && memcmp(output, testVector4, 64) == 0) -#endif - - objc_autoreleasePoolPop(pool); -} -@end DELETED tests/SocketTests.m Index: tests/SocketTests.m ================================================================== --- tests/SocketTests.m +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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" - -#define COMPARE_V6(a, a0, a1, a2, a3, a4, a5, a6, a7) \ - (a.sockaddr.in6.sin6_addr.s6_addr[0] == (a0 >> 8) && \ - a.sockaddr.in6.sin6_addr.s6_addr[1] == (a0 & 0xFF) && \ - a.sockaddr.in6.sin6_addr.s6_addr[2] == (a1 >> 8) && \ - a.sockaddr.in6.sin6_addr.s6_addr[3] == (a1 & 0xFF) && \ - a.sockaddr.in6.sin6_addr.s6_addr[4] == (a2 >> 8) && \ - a.sockaddr.in6.sin6_addr.s6_addr[5] == (a2 & 0xFF) && \ - a.sockaddr.in6.sin6_addr.s6_addr[6] == (a3 >> 8) && \ - a.sockaddr.in6.sin6_addr.s6_addr[7] == (a3 & 0xFF) && \ - a.sockaddr.in6.sin6_addr.s6_addr[8] == (a4 >> 8) && \ - a.sockaddr.in6.sin6_addr.s6_addr[9] == (a4 & 0xFF) && \ - a.sockaddr.in6.sin6_addr.s6_addr[10] == (a5 >> 8) && \ - a.sockaddr.in6.sin6_addr.s6_addr[11] == (a5 & 0xFF) && \ - a.sockaddr.in6.sin6_addr.s6_addr[12] == (a6 >> 8) && \ - a.sockaddr.in6.sin6_addr.s6_addr[13] == (a6 & 0xFF) && \ - a.sockaddr.in6.sin6_addr.s6_addr[14] == (a7 >> 8) && \ - a.sockaddr.in6.sin6_addr.s6_addr[15] == (a7 & 0xFF)) -#define SET_V6(a, a0, a1, a2, a3, a4, a5, a6, a7) \ - a.sockaddr.in6.sin6_addr.s6_addr[0] = a0 >> 8; \ - a.sockaddr.in6.sin6_addr.s6_addr[1] = a0 & 0xFF; \ - a.sockaddr.in6.sin6_addr.s6_addr[2] = a1 >> 8; \ - a.sockaddr.in6.sin6_addr.s6_addr[3] = a1 & 0xFF; \ - a.sockaddr.in6.sin6_addr.s6_addr[4] = a2 >> 8; \ - a.sockaddr.in6.sin6_addr.s6_addr[5] = a2 & 0xFF; \ - a.sockaddr.in6.sin6_addr.s6_addr[6] = a3 >> 8; \ - a.sockaddr.in6.sin6_addr.s6_addr[7] = a3 & 0xFF; \ - a.sockaddr.in6.sin6_addr.s6_addr[8] = a4 >> 8; \ - a.sockaddr.in6.sin6_addr.s6_addr[9] = a4 & 0xFF; \ - a.sockaddr.in6.sin6_addr.s6_addr[10] = a5 >> 8; \ - a.sockaddr.in6.sin6_addr.s6_addr[11] = a5 & 0xFF; \ - a.sockaddr.in6.sin6_addr.s6_addr[12] = a6 >> 8; \ - a.sockaddr.in6.sin6_addr.s6_addr[13] = a6 & 0xFF; \ - a.sockaddr.in6.sin6_addr.s6_addr[14] = a7 >> 8; \ - a.sockaddr.in6.sin6_addr.s6_addr[15] = a7 & 0xFF; - -static OFString *module = @"Socket"; - -@implementation TestsAppDelegate (SocketTests) -- (void)socketTests -{ - void *pool = objc_autoreleasePoolPush(); - of_socket_address_t addr; - uint16_t port; - - TEST(@"Parsing an IPv4", - R(addr = of_socket_address_parse_ip(@"127.0.0.1", 1234)) && - OF_BSWAP32_IF_LE(addr.sockaddr.in.sin_addr.s_addr) == 0x7F000001 && - OF_BSWAP16_IF_LE(addr.sockaddr.in.sin_port) == 1234) - - EXPECT_EXCEPTION(@"Refusing invalid IPv4 #1", - OFInvalidFormatException, - of_socket_address_parse_ip(@"127.0.0.0.1", 1234)) - - EXPECT_EXCEPTION(@"Refusing invalid IPv4 #2", - OFInvalidFormatException, - of_socket_address_parse_ip(@"127.0.0.256", 1234)) - - EXPECT_EXCEPTION(@"Refusing invalid IPv4 #3", - OFInvalidFormatException, - of_socket_address_parse_ip(@"127.0.0. 1", 1234)) - - EXPECT_EXCEPTION(@"Refusing invalid IPv4 #4", - OFInvalidFormatException, - of_socket_address_parse_ip(@" 127.0.0.1", 1234)) - - EXPECT_EXCEPTION(@"Refusing invalid IPv4 #5", - OFInvalidFormatException, - of_socket_address_parse_ip(@"127.0.a.1", 1234)) - - EXPECT_EXCEPTION(@"Refusing invalid IPv4 #6", - OFInvalidFormatException, - of_socket_address_parse_ip(@"127.0..1", 1234)) - - TEST(@"Converting an IPv4 to a string", - [of_socket_address_ip_string(&addr, &port) isEqual: @"127.0.0.1"] && - port == 1234) - - TEST(@"Parsing an IPv6 #1", - R(addr = of_socket_address_parse_ip( - @"1122:3344:5566:7788:99aa:bbCc:ddee:ff00", 1234)) && - COMPARE_V6(addr, - 0x1122, 0x3344, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0xDDEE, 0xFF00) && - OF_BSWAP16_IF_LE(addr.sockaddr.in6.sin6_port) == 1234) - - TEST(@"Parsing an IPv6 #2", - R(addr = of_socket_address_parse_ip(@"::", 1234)) && - COMPARE_V6(addr, 0, 0, 0, 0, 0, 0, 0, 0) && - OF_BSWAP16_IF_LE(addr.sockaddr.in6.sin6_port) == 1234) - - TEST(@"Parsing an IPv6 #3", - R(addr = of_socket_address_parse_ip(@"aaAa::bBbb", 1234)) && - COMPARE_V6(addr, 0xAAAA, 0, 0, 0, 0, 0, 0, 0xBBBB) && - OF_BSWAP16_IF_LE(addr.sockaddr.in6.sin6_port) == 1234) - - TEST(@"Parsing an IPv6 #4", - R(addr = of_socket_address_parse_ip(@"aaAa::", 1234)) && - COMPARE_V6(addr, 0xAAAA, 0, 0, 0, 0, 0, 0, 0) && - OF_BSWAP16_IF_LE(addr.sockaddr.in6.sin6_port) == 1234) - - TEST(@"Parsing an IPv6 #5", - R(addr = of_socket_address_parse_ip(@"::aaAa", 1234)) && - COMPARE_V6(addr, 0, 0, 0, 0, 0, 0, 0, 0xAAAA) && - OF_BSWAP16_IF_LE(addr.sockaddr.in6.sin6_port) == 1234) - - EXPECT_EXCEPTION(@"Refusing invalid IPv6 #1", - OFInvalidFormatException, - of_socket_address_parse_ip(@"1:::2", 1234)) - - EXPECT_EXCEPTION(@"Refusing invalid IPv6 #2", - OFInvalidFormatException, - of_socket_address_parse_ip(@"1: ::2", 1234)) - - EXPECT_EXCEPTION(@"Refusing invalid IPv6 #3", - OFInvalidFormatException, - of_socket_address_parse_ip(@"1:: :2", 1234)) - - EXPECT_EXCEPTION(@"Refusing invalid IPv6 #4", - OFInvalidFormatException, - of_socket_address_parse_ip(@"1::2::3", 1234)) - - EXPECT_EXCEPTION(@"Refusing invalid IPv6 #5", - OFInvalidFormatException, - of_socket_address_parse_ip(@"10000::1", 1234)) - - EXPECT_EXCEPTION(@"Refusing invalid IPv6 #6", - OFInvalidFormatException, - of_socket_address_parse_ip(@"::10000", 1234)) - - EXPECT_EXCEPTION(@"Refusing invalid IPv6 #7", - OFInvalidFormatException, - of_socket_address_parse_ip(@"::1::", 1234)) - - EXPECT_EXCEPTION(@"Refusing invalid IPv6 #8", - OFInvalidFormatException, - of_socket_address_parse_ip(@"1:2:3:4:5:6:7:", 1234)) - - EXPECT_EXCEPTION(@"Refusing invalid IPv6 #9", - OFInvalidFormatException, - of_socket_address_parse_ip(@"1:2:3:4:5:6:7::", 1234)) - - EXPECT_EXCEPTION(@"Refusing invalid IPv6 #10", - OFInvalidFormatException, - of_socket_address_parse_ip(@"1:2", 1234)) - - SET_V6(addr, 0, 0, 0, 0, 0, 0, 0, 0) - TEST(@"Converting an IPv6 to a string #1", - [of_socket_address_ip_string(&addr, &port) isEqual: @"::"] && - port == 1234) - - SET_V6(addr, 0, 0, 0, 0, 0, 0, 0, 1) - TEST(@"Converting an IPv6 to a string #2", - [of_socket_address_ip_string(&addr, &port) isEqual: @"::1"] && - port == 1234) - - SET_V6(addr, 1, 0, 0, 0, 0, 0, 0, 0) - TEST(@"Converting an IPv6 to a string #3", - [of_socket_address_ip_string(&addr, &port) isEqual: @"1::"] && - port == 1234) - - SET_V6(addr, - 0x1122, 0x3344, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0xDDEE, 0xFF00) - TEST(@"Converting an IPv6 to a string #4", - [of_socket_address_ip_string(&addr, &port) isEqual: - @"1122:3344:5566:7788:99aa:bbcc:ddee:ff00"] && - port == 1234) - - SET_V6(addr, 0x1122, 0x3344, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0xDDEE, 0) - TEST(@"Converting an IPv6 to a string #5", - [of_socket_address_ip_string(&addr, &port) isEqual: - @"1122:3344:5566:7788:99aa:bbcc:ddee:0"] && - port == 1234) - - SET_V6(addr, 0x1122, 0x3344, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0, 0) - TEST(@"Converting an IPv6 to a string #6", - [of_socket_address_ip_string(&addr, &port) isEqual: - @"1122:3344:5566:7788:99aa:bbcc::"] && - port == 1234) - - SET_V6(addr, 0, 0x3344, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0xDDEE, 0xFF00) - TEST(@"Converting an IPv6 to a string #7", - [of_socket_address_ip_string(&addr, &port) isEqual: - @"0:3344:5566:7788:99aa:bbcc:ddee:ff00"] && - port == 1234) - - SET_V6(addr, 0, 0, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0xDDEE, 0xFF00) - TEST(@"Converting an IPv6 to a string #8", - [of_socket_address_ip_string(&addr, &port) isEqual: - @"::5566:7788:99aa:bbcc:ddee:ff00"] && - port == 1234) - - SET_V6(addr, 0, 0, 0x5566, 0, 0, 0, 0xDDEE, 0xFF00) - TEST(@"Converting an IPv6 to a string #9", - [of_socket_address_ip_string(&addr, &port) isEqual: - @"0:0:5566::ddee:ff00"] && - port == 1234) - - SET_V6(addr, 0, 0, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0, 0) - TEST(@"Converting an IPv6 to a string #10", - [of_socket_address_ip_string(&addr, &port) isEqual: - @"::5566:7788:99aa:bbcc:0:0"] && - port == 1234) - - objc_autoreleasePoolPop(pool); -} -@end Index: tests/TestsAppDelegate.h ================================================================== --- tests/TestsAppDelegate.h +++ tests/TestsAppDelegate.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -15,45 +13,39 @@ * file. */ #import "ObjFW.h" -#define TEST(test, ...) \ - { \ - [self outputTesting: test \ - inModule: module]; \ - \ - if (__VA_ARGS__) \ - [self outputSuccess: test \ - inModule: module]; \ - else { \ - [self outputFailure: test \ - inModule: module]; \ - _fails++; \ - } \ - } -#define EXPECT_EXCEPTION(test, exception, code) \ - { \ - bool caught = false; \ - \ - [self outputTesting: test \ - inModule: module]; \ - \ - @try { \ - code; \ - } @catch (exception *e) { \ - caught = true; \ - } \ - \ - if (caught) \ - [self outputSuccess: test \ - inModule: module]; \ - else { \ - [self outputFailure: test \ - inModule: module]; \ - _fails++; \ - } \ +#define TEST(test, ...) \ + { \ + [self outputTesting: test inModule: module]; \ + \ + if (__VA_ARGS__) \ + [self outputSuccess: test inModule: module]; \ + else { \ + [self outputFailure: test inModule: module]; \ + _fails++; \ + } \ + } +#define EXPECT_EXCEPTION(test, exception, code) \ + { \ + bool caught = false; \ + \ + [self outputTesting: test inModule: module]; \ + \ + @try { \ + code; \ + } @catch (exception *e) { \ + caught = true; \ + } \ + \ + if (caught) \ + [self outputSuccess: test inModule: module]; \ + else { \ + [self outputFailure: test inModule: module]; \ + _fails++; \ + } \ } #define R(...) (__VA_ARGS__, 1) @class OFString; @@ -60,24 +52,13 @@ @interface TestsAppDelegate: OFObject { int _fails; } -- (void)outputTesting: (OFString *)test - inModule: (OFString *)module; -- (void)outputSuccess: (OFString *)test - inModule: (OFString *)module; -- (void)outputFailure: (OFString *)test - inModule: (OFString *)module; -@end - -@interface TestsAppDelegate (OFASN1DERParsingTests) -- (void)ASN1DERParsingTests; -@end - -@interface TestsAppDelegate (OFASN1DERRepresentationTests) -- (void)ASN1DERRepresentationTests; +- (void)outputTesting: (OFString *)test inModule: (OFString *)module; +- (void)outputSuccess: (OFString *)test inModule: (OFString *)module; +- (void)outputFailure: (OFString *)test inModule: (OFString *)module; @end @interface TestsAppDelegate (OFArrayTests) - (void)arrayTests; @end @@ -155,18 +136,26 @@ @end @interface TestsAppDelegate (OFMethodSignatureTests) - (void)methodSignatureTests; @end + +@interface TestsAppDelegate (OFNotificationCenterTests) +- (void)notificationCenterTests; +@end @interface TestsAppDelegate (OFNumberTests) - (void)numberTests; @end @interface TestsAppDelegate (OFObjectTests) - (void)objectTests; @end + +@interface TestsAppDelegate (OFPBKDF2Tests) +- (void)PBKDF2Tests; +@end @interface TestsAppDelegate (OFPropertyListTests) - (void)propertyListTests; @end @@ -184,11 +173,11 @@ @interface TestsAppDelegate (OFRIPEMD160HashTests) - (void)RIPEMD160HashTests; @end -@interface TestsAppDelegate (ScryptTests) +@interface TestsAppDelegate (OFScryptTests) - (void)scryptTests; @end @interface TestsAppDelegate (OFSHA1HashTests) - (void)SHA1HashTests; @@ -208,14 +197,10 @@ @interface TestsAppDelegate (OFSHA512HashTests) - (void)SHA512HashTests; @end -@interface TestsAppDelegate (OFSCTPSocketTests) -- (void)SCTPSocketTests; -@end - @interface TestsAppDelegate (OFSPXSocketTests) - (void)SPXSocketTests; @end @interface TestsAppDelegate (OFSPXStreamSocketTests) @@ -235,10 +220,14 @@ @end @interface TestsAppDelegate (OFHMACTests) - (void)HMACTests; @end + +@interface TestsAppDelegate (OFSocketTests) +- (void)socketTests; +@end @interface TestsAppDelegate (OFStreamTests) - (void)streamTests; @end @@ -255,10 +244,18 @@ @end @interface TestsAppDelegate (OFUDPSocketTests) - (void)UDPSocketTests; @end + +@interface TestsAppDelegate (OFUNIXDatagramSocketTests) +- (void)UNIXDatagramSocketTests; +@end + +@interface TestsAppDelegate (OFUNIXStreamSocketTests) +- (void)UNIXStreamSocketTests; +@end @interface TestsAppDelegate (OFURLTests) - (void)URLTests; @end @@ -280,13 +277,5 @@ @interface TestsAppDelegate (OFXMLParserTests) - (void)XMLParserTests; @end - -@interface TestsAppDelegate (PBKDF2Tests) -- (void)PBKDF2Tests; -@end - -@interface TestsAppDelegate (SocketTests) -- (void)socketTests; -@end Index: tests/TestsAppDelegate.m ================================================================== --- tests/TestsAppDelegate.m +++ tests/TestsAppDelegate.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -51,24 +49,26 @@ # define id id_3ds # include <3ds.h> # undef id #endif +extern unsigned long OFHashSeed; + #ifdef OF_PSP static int -exit_cb(int arg1, int arg2, void *arg) +exitCallback(int arg1, int arg2, void *arg) { sceKernelExitGame(); return 0; } static int -callback_thread(SceSize args, void *argp) +threadCallback(SceSize args, void *argp) { sceKernelRegisterExitCallback( - sceKernelCreateCallback("Exit Callback", exit_cb, NULL)); + sceKernelCreateCallback("Exit Callback", exitCallback, NULL)); sceKernelSleepThreadCB(); return 0; } #endif @@ -83,18 +83,18 @@ #if defined(OF_OBJFW_RUNTIME) && !defined(OF_WINDOWS) && !defined(OF_AMIGAOS) /* * This does not work on Win32 if ObjFW is built as a DLL. * * On AmigaOS, some destructors need to be able to send messages. - * Calling objc_exit() via atexit() would result in the runtime being + * Calling objc_deinit() via atexit() would result in the runtime being * destructed before for the destructors ran. */ - atexit(objc_exit); + atexit(objc_deinit); #endif /* We need deterministic hashes for tests */ - of_hash_seed = 0; + OFHashSeed = 0; #ifdef OF_WII GXRModeObj *rmode; void *xfb; @@ -120,11 +120,11 @@ pspDebugScreenInit(); sceCtrlSetSamplingCycle(0); sceCtrlSetSamplingMode(PSP_CTRL_MODE_DIGITAL); - if ((tid = sceKernelCreateThread("update_thread", callback_thread, + if ((tid = sceKernelCreateThread("update_thread", threadCallback, 0x11, 0xFA0, 0, 0)) >= 0) sceKernelStartThread(tid, 0, 0); #endif #ifdef OF_NINTENDO_DS @@ -139,26 +139,26 @@ #endif #if defined(OF_WII) || defined(OF_PSP) || defined(OF_NINTENDO_DS) || \ defined(OF_NINTENDO_3DS) @try { - return of_application_main(&argc, &argv, + return OFApplicationMain(&argc, &argv, [[TestsAppDelegate alloc] init]); } @catch (id e) { OFString *string = [OFString stringWithFormat: @"\nRuntime error: Unhandled exception:\n%@\n", e]; OFString *backtrace = [OFString stringWithFormat: @"\nBacktrace:\n %@\n\n", [[e backtrace] componentsJoinedByString: @"\n "]]; - [of_stdout setForegroundColor: [OFColor red]]; - [of_stdout writeString: string]; - [of_stdout writeString: backtrace]; + [OFStdOut setForegroundColor: [OFColor red]]; + [OFStdOut writeString: string]; + [OFStdOut writeString: backtrace]; # if defined(OF_WII) - [of_stdout reset]; - [of_stdout writeString: @"Press home button to exit!"]; + [OFStdOut reset]; + [OFStdOut writeString: @"Press home button to exit!"]; for (;;) { WPAD_ScanPads(); if (WPAD_ButtonsDown(0) & WPAD_BUTTON_HOME) @@ -167,22 +167,22 @@ VIDEO_WaitVSync(); } # elif defined(OF_PSP) sceKernelSleepThreadCB(); # elif defined(OF_NINTENDO_DS) - [of_stdout reset]; - [of_stdout writeString: @"Press start button to exit!"]; + [OFStdOut reset]; + [OFStdOut writeString: @"Press start button to exit!"]; for (;;) { swiWaitForVBlank(); scanKeys(); if (keysDown() & KEY_START) [OFApplication terminateWithStatus: 1]; } # elif defined(OF_NINTENDO_3DS) - [of_stdout reset]; - [of_stdout writeString: @"Press start button to exit!"]; + [OFStdOut reset]; + [OFStdOut writeString: @"Press start button to exit!"]; for (;;) { hidScanInput(); if (hidKeysDown() & KEY_START) @@ -193,48 +193,44 @@ # else abort(); # endif } #else - return of_application_main(&argc, &argv, - [[TestsAppDelegate alloc] init]); + return OFApplicationMain(&argc, &argv, [[TestsAppDelegate alloc] init]); #endif } @implementation TestsAppDelegate -- (void)outputTesting: (OFString *)test - inModule: (OFString *)module -{ - if (of_stdout.hasTerminal) { - [of_stdout setForegroundColor: [OFColor yellow]]; - [of_stdout writeFormat: @"[%@] %@: testing...", module, test]; - } else - [of_stdout writeFormat: @"[%@] %@: ", module, test]; -} - -- (void)outputSuccess: (OFString *)test - inModule: (OFString *)module -{ - if (of_stdout.hasTerminal) { - [of_stdout setForegroundColor: [OFColor lime]]; - [of_stdout eraseLine]; - [of_stdout writeFormat: @"\r[%@] %@: ok\n", module, test]; - } else - [of_stdout writeLine: @"ok"]; -} - -- (void)outputFailure: (OFString *)test - inModule: (OFString *)module -{ - if (of_stdout.hasTerminal) { - [of_stdout setForegroundColor: [OFColor red]]; - [of_stdout eraseLine]; - [of_stdout writeFormat: @"\r[%@] %@: failed\n", module, test]; - -#ifdef OF_WII - [of_stdout reset]; - [of_stdout writeLine: @"Press A to continue!"]; +- (void)outputTesting: (OFString *)test inModule: (OFString *)module +{ + if (OFStdOut.hasTerminal) { + [OFStdOut setForegroundColor: [OFColor yellow]]; + [OFStdOut writeFormat: @"[%@] %@: testing...", module, test]; + } else + [OFStdOut writeFormat: @"[%@] %@: ", module, test]; +} + +- (void)outputSuccess: (OFString *)test inModule: (OFString *)module +{ + if (OFStdOut.hasTerminal) { + [OFStdOut setForegroundColor: [OFColor lime]]; + [OFStdOut eraseLine]; + [OFStdOut writeFormat: @"\r[%@] %@: ok\n", module, test]; + } else + [OFStdOut writeLine: @"ok"]; +} + +- (void)outputFailure: (OFString *)test inModule: (OFString *)module +{ + if (OFStdOut.hasTerminal) { + [OFStdOut setForegroundColor: [OFColor red]]; + [OFStdOut eraseLine]; + [OFStdOut writeFormat: @"\r[%@] %@: failed\n", module, test]; + +#ifdef OF_WII + [OFStdOut reset]; + [OFStdOut writeLine: @"Press A to continue!"]; for (;;) { WPAD_ScanPads(); if (WPAD_ButtonsDown(0) & WPAD_BUTTON_A) @@ -242,12 +238,12 @@ VIDEO_WaitVSync(); } #endif #ifdef OF_PSP - [of_stdout reset]; - [of_stdout writeLine: @"Press X to continue!"]; + [OFStdOut reset]; + [OFStdOut writeLine: @"Press X to continue!"]; for (;;) { SceCtrlData pad; sceCtrlReadBufferPositive(&pad, 1); @@ -259,23 +255,23 @@ } } } #endif #ifdef OF_NINTENDO_DS - [of_stdout reset]; - [of_stdout writeString: @"Press A to continue!"]; + [OFStdOut reset]; + [OFStdOut writeString: @"Press A to continue!"]; for (;;) { swiWaitForVBlank(); scanKeys(); if (keysDown() & KEY_A) break; } #endif #ifdef OF_NINTENDO_3DS - [of_stdout reset]; - [of_stdout writeString: @"Press A to continue!"]; + [OFStdOut reset]; + [OFStdOut writeString: @"Press A to continue!"]; for (;;) { hidScanInput(); if (hidKeysDown() & KEY_A) @@ -283,15 +279,15 @@ gspWaitForVBlank(); } #endif - [of_stdout writeString: @"\r"]; - [of_stdout reset]; - [of_stdout eraseLine]; + [OFStdOut writeString: @"\r"]; + [OFStdOut reset]; + [OFStdOut eraseLine]; } else - [of_stdout writeLine: @"failed"]; + [OFStdOut writeLine: @"failed"]; } - (void)applicationDidFinishLaunching { #if defined(OF_IOS) && defined(OF_HAVE_FILES) @@ -299,11 +295,11 @@ CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(mainBundle); UInt8 resourcesPath[PATH_MAX]; if (!CFURLGetFileSystemRepresentation(resourcesURL, true, resourcesPath, PATH_MAX)) { - [of_stderr writeString: @"Failed to locate resources!\n"]; + [OFStdErr writeString: @"Failed to locate resources!\n"]; [OFApplication terminateWithStatus: 1]; } [[OFFileManager defaultManager] changeCurrentDirectoryPath: [OFString stringWithUTF8String: (const char *)resourcesPath]]; @@ -333,10 +329,11 @@ [self setTests]; [self dateTests]; [self valueTests]; [self numberTests]; [self streamTests]; + [self notificationCenterTests]; #ifdef OF_HAVE_FILES [self MD5HashTests]; [self RIPEMD160HashTests]; [self SHA1HashTests]; [self SHA224HashTests]; @@ -352,18 +349,19 @@ #endif #ifdef OF_HAVE_SOCKETS [self socketTests]; [self TCPSocketTests]; [self UDPSocketTests]; -# ifdef OF_HAVE_SCTP - [self SCTPSocketTests]; -# endif # ifdef OF_HAVE_IPX [self IPXSocketTests]; [self SPXSocketTests]; [self SPXStreamSocketTests]; # endif +# ifdef OF_HAVE_UNIX_SOCKETS + [self UNIXDatagramSocketTests]; + [self UNIXStreamSocketTests]; +# endif [self kernelEventObserverTests]; #endif #ifdef OF_HAVE_THREADS [self threadTests]; #endif @@ -381,12 +379,10 @@ #ifdef OF_HAVE_FILES [self serializationTests]; #endif [self JSONTests]; [self propertyListTests]; - [self ASN1DERParsingTests]; - [self ASN1DERRepresentationTests]; #if defined(OF_HAVE_PLUGINS) [self pluginTests]; #endif #ifdef OF_WINDOWS [self windowsRegistryKeyTests]; @@ -396,17 +392,17 @@ [self DNSResolverTests]; #endif [self systemInfoTests]; [self localeTests]; - [of_stdout reset]; + [OFStdOut reset]; #if defined(OF_IOS) - [of_stdout writeFormat: @"%d tests failed!", _fails]; + [OFStdOut writeFormat: @"%d tests failed!", _fails]; [OFApplication terminateWithStatus: _fails]; #elif defined(OF_WII) - [of_stdout writeString: @"Press home button to exit!"]; + [OFStdOut writeString: @"Press home button to exit!"]; for (;;) { WPAD_ScanPads(); if (WPAD_ButtonsDown(0) & WPAD_BUTTON_HOME) @@ -413,24 +409,24 @@ [OFApplication terminateWithStatus: _fails]; VIDEO_WaitVSync(); } #elif defined(OF_PSP) - [of_stdout writeFormat: @"%d tests failed!", _fails]; + [OFStdOut writeFormat: @"%d tests failed!", _fails]; sceKernelSleepThreadCB(); #elif defined(OF_NINTENDO_DS) - [of_stdout writeString: @"Press start button to exit!"]; + [OFStdOut writeString: @"Press start button to exit!"]; for (;;) { swiWaitForVBlank(); scanKeys(); if (keysDown() & KEY_START) [OFApplication terminateWithStatus: _fails]; } #elif defined(OF_NINTENDO_3DS) - [of_stdout writeString: @"Press start button to exit!"]; + [OFStdOut writeString: @"Press start button to exit!"]; for (;;) { hidScanInput(); if (hidKeysDown() & KEY_START) Index: tests/iOS.xcodeproj/project.pbxproj ================================================================== --- tests/iOS.xcodeproj/project.pbxproj +++ tests/iOS.xcodeproj/project.pbxproj @@ -133,11 +133,11 @@ /* Begin PBXProject section */ 4BEBFB532013934E002E8710 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0920; + LastUpgradeCheck = 1330; ORGANIZATIONNAME = "Jonathan Schleifer"; TargetAttributes = { 4BEBFB5A2013934E002E8710 = { CreatedOnToolsVersion = 9.2; ProvisioningStyle = Automatic; @@ -200,17 +200,19 @@ CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -255,17 +257,19 @@ CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; Index: tests/objc_sync/Makefile ================================================================== --- tests/objc_sync/Makefile +++ tests/objc_sync/Makefile @@ -3,31 +3,31 @@ PROG_NOINST = objc_sync${PROG_SUFFIX} SRCS = test.m include ../../buildsys.mk -post-all: ${RUN_TESTS} - .PHONY: run run: rm -f libobjfw.so.${OBJFW_LIB_MAJOR} rm -f libobjfw.so.${OBJFW_LIB_MAJOR_MINOR} - rm -f objfw.dll libobjfw.${OBJFW_LIB_MAJOR}.dylib + 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.dll libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib + 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.dll; then \ - ${LN_S} ../../src/objfw.dll objfw.dll; \ + 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 @@ -37,12 +37,13 @@ ${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.dll; then \ - ${LN_S} ../../src/runtime/objfwrt.dll objfwrt.dll; \ + 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 @@ -53,15 +54,19 @@ 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}; \ - rm -f objfw.so.${OBJFW_LIB_MAJOR_MINOR} objfw.dll; \ + 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 objfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR} objfwrt.dll; \ + 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/runtime -I../.. -LIBS := -L../../src -lobjfw -L../../src/runtime ${RUNTIME_LIBS} ${LIBS} +LIBS := -L../../src -lobjfw \ + -L../../src/runtime -L../../src/runtime/linklib ${RUNTIME_LIBS} \ + ${LIBS} LD = ${OBJC} Index: tests/objc_sync/test.m ================================================================== --- tests/objc_sync/test.m +++ tests/objc_sync/test.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: tests/plugin/TestPlugin.h ================================================================== --- tests/plugin/TestPlugin.h +++ tests/plugin/TestPlugin.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -13,10 +11,10 @@ * 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 "OFPlugin.h" +#import "OFObject.h" -@interface TestPlugin: OFPlugin +@interface TestPlugin: OFObject - (int)test: (int)num; @end Index: tests/plugin/TestPlugin.m ================================================================== --- tests/plugin/TestPlugin.m +++ tests/plugin/TestPlugin.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -28,16 +26,16 @@ if (class == Nil) /* * musl has broken dlclose(): Instead of calling the destructor * on dlclose(), they call it on exit(). This of course means - * that our tests might have already called objc_exit() and the - * class is already gone. + * that our tests might have already called objc_deinit() and + * the class is already gone. */ return; - objc_unregister_class(class); + objc_unregisterClass(class); } #endif @implementation TestPlugin - (int)test: (int)num @@ -44,10 +42,10 @@ { return num * 2; } @end -id -init_plugin(void) +Class +class(void) { - return [[[TestPlugin alloc] init] autorelease]; + return [TestPlugin class]; } Index: tests/serialization.xml ================================================================== --- tests/serialization.xml +++ tests/serialization.xml @@ -1,8 +1,14 @@ + + 01234567-89ab-cdef-fedc-ba9876543210 + + + uuid + Blub B"la Index: tests/terminal/Makefile ================================================================== --- tests/terminal/Makefile +++ tests/terminal/Makefile @@ -3,31 +3,31 @@ PROG_NOINST = terminal_tests${PROG_SUFFIX} SRCS = TerminalTests.m include ../../buildsys.mk -post-all: ${RUN_TESTS} - .PHONY: run run: rm -f libobjfw.so.${OBJFW_LIB_MAJOR} rm -f libobjfw.so.${OBJFW_LIB_MAJOR_MINOR} - rm -f objfw.dll libobjfw.${OBJFW_LIB_MAJOR}.dylib + 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.dll libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib + 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.dll; then \ - ${LN_S} ../../src/objfw.dll objfw.dll; \ + 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 @@ -37,12 +37,13 @@ ${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.dll; then \ - ${LN_S} ../../src/runtime/objfwrt.dll objfwrt.dll; \ + 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 @@ -53,15 +54,19 @@ 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}; \ - rm -f objfw.so.${OBJFW_LIB_MAJOR_MINOR} objfw.dll; \ + 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 objfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR} objfwrt.dll; \ + 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} +LIBS := -L../../src -lobjfw \ + -L../../src/runtime -L../../src/runtime/linklib ${RUNTIME_LIBS} \ + ${LIBS} LD = ${OBJC} Index: tests/terminal/TerminalTests.m ================================================================== --- tests/terminal/TerminalTests.m +++ tests/terminal/TerminalTests.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -38,84 +36,84 @@ [OFColor yellow], [OFColor navy], [OFColor blue], [OFColor teal], [OFColor aqua], nil]; size_t i; OFEnumerator OF_GENERIC(OFColor *) *reverseEnumerator; - [of_stdout writeFormat: @"%dx%d\n", of_stdout.columns, of_stdout.rows]; + [OFStdOut writeFormat: @"%dx%d\n", OFStdOut.columns, OFStdOut.rows]; i = 0; for (OFColor *color in colors) { - [of_stdout setForegroundColor: color]; - [of_stdout writeFormat: @"%zx", i++]; + [OFStdOut setForegroundColor: color]; + [OFStdOut writeFormat: @"%zx", i++]; } - [of_stdout reset]; - [of_stdout writeLine: @"R"]; + [OFStdOut reset]; + [OFStdOut writeLine: @"R"]; i = 0; for (OFColor *color in colors) { - [of_stdout setBackgroundColor: color]; - [of_stdout writeFormat: @"%zx", i++]; + [OFStdOut setBackgroundColor: color]; + [OFStdOut writeFormat: @"%zx", i++]; } - [of_stdout reset]; - [of_stdout writeLine: @"R"]; + [OFStdOut reset]; + [OFStdOut writeLine: @"R"]; i = 0; reverseEnumerator = [colors.reversedArray objectEnumerator]; for (OFColor *color in colors) { - [of_stdout setForegroundColor: color]; - [of_stdout setBackgroundColor: [reverseEnumerator nextObject]]; - [of_stdout writeFormat: @"%zx", i++]; + [OFStdOut setForegroundColor: color]; + [OFStdOut setBackgroundColor: [reverseEnumerator nextObject]]; + [OFStdOut writeFormat: @"%zx", i++]; } - [of_stdout reset]; - [of_stdout writeLine: @"R"]; + [OFStdOut reset]; + [OFStdOut writeLine: @"R"]; for (i = 0; i < colors.count * 2; i++) { if (i % 2) - [of_stdout setBackgroundColor: [colors objectAtIndex: + [OFStdOut setBackgroundColor: [colors objectAtIndex: ((i / 2) + 2) % colors.count]]; else - [of_stdout setForegroundColor: + [OFStdOut setForegroundColor: [colors objectAtIndex: i / 2]]; - [of_stdout writeFormat: @"%zx", i / 2]; - } - [of_stdout reset]; - [of_stdout writeLine: @"R"]; - - [of_stdout writeLine: @"Press return"]; - [of_stdin readLine]; - - [of_stdout setBackgroundColor: [OFColor green]]; - [of_stdout writeString: @"Hello!"]; - [OFThread sleepForTimeInterval: 2]; - [of_stdout eraseLine]; - [of_stdout writeString: @"World!"]; - [OFThread sleepForTimeInterval: 2]; - - [of_stdout clear]; - [OFThread sleepForTimeInterval: 2]; - - [of_stdout setCursorPosition: of_point(5, 3)]; - [of_stdout writeString: @"Text at (5, 3)"]; - [OFThread sleepForTimeInterval: 2]; - - [of_stdout setRelativeCursorPosition: of_point(-2, 0)]; - [OFThread sleepForTimeInterval: 2]; - [of_stdout setRelativeCursorPosition: of_point(2, 0)]; - [OFThread sleepForTimeInterval: 2]; - [of_stdout setRelativeCursorPosition: of_point(0, -2)]; - [OFThread sleepForTimeInterval: 2]; - [of_stdout setRelativeCursorPosition: of_point(0, 2)]; - [OFThread sleepForTimeInterval: 2]; - [of_stdout setRelativeCursorPosition: of_point(1, 1)]; - [OFThread sleepForTimeInterval: 2]; - [of_stdout setRelativeCursorPosition: of_point(-1, -1)]; - [OFThread sleepForTimeInterval: 2]; - - [of_stdout setCursorColumn: 2]; - [OFThread sleepForTimeInterval: 2]; - - [of_stdout reset]; + [OFStdOut writeFormat: @"%zx", i / 2]; + } + [OFStdOut reset]; + [OFStdOut writeLine: @"R"]; + + [OFStdOut writeLine: @"Press return"]; + [OFStdIn readLine]; + + [OFStdOut setBackgroundColor: [OFColor green]]; + [OFStdOut writeString: @"Hello!"]; + [OFThread sleepForTimeInterval: 2]; + [OFStdOut eraseLine]; + [OFStdOut writeString: @"World!"]; + [OFThread sleepForTimeInterval: 2]; + + [OFStdOut clear]; + [OFThread sleepForTimeInterval: 2]; + + [OFStdOut setCursorPosition: OFPointMake(5, 3)]; + [OFStdOut writeString: @"Text at (5, 3)"]; + [OFThread sleepForTimeInterval: 2]; + + [OFStdOut setRelativeCursorPosition: OFPointMake(-2, 0)]; + [OFThread sleepForTimeInterval: 2]; + [OFStdOut setRelativeCursorPosition: OFPointMake(2, 0)]; + [OFThread sleepForTimeInterval: 2]; + [OFStdOut setRelativeCursorPosition: OFPointMake(0, -2)]; + [OFThread sleepForTimeInterval: 2]; + [OFStdOut setRelativeCursorPosition: OFPointMake(0, 2)]; + [OFThread sleepForTimeInterval: 2]; + [OFStdOut setRelativeCursorPosition: OFPointMake(1, 1)]; + [OFThread sleepForTimeInterval: 2]; + [OFStdOut setRelativeCursorPosition: OFPointMake(-1, -1)]; + [OFThread sleepForTimeInterval: 2]; + + [OFStdOut setCursorColumn: 2]; + [OFThread sleepForTimeInterval: 2]; + + [OFStdOut reset]; [OFApplication terminate]; } @end Index: utils/Makefile ================================================================== --- utils/Makefile +++ utils/Makefile @@ -2,11 +2,10 @@ SUBDIRS += ${OFARC} \ ${OFDNS} \ ${OFHASH} \ ${OFHTTP} \ - ${OFSOCK} \ completions include ../buildsys.mk DISTCLEAN = objfw-config Index: utils/objfw-compile ================================================================== --- utils/objfw-compile +++ utils/objfw-compile @@ -1,10 +1,8 @@ #!/bin/sh # -# Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, -# 2018, 2019, 2020 -# Jonathan Schleifer +# 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 @@ -30,14 +28,14 @@ parse_packages() { packages="" while test x"$1" != "x"; do case "$1" in - --package) - shift - packages="$packages --package $1" - ;; + --package) + shift + packages="$packages --package $1" + ;; esac shift done } parse_packages "$@" @@ -122,141 +120,140 @@ out_prefix="" out_suffix="" while test x"$1" != "x"; do case "$1" in - -o|--out) - shift - out="$1" - ;; - --lib) - if test x"$plugin" = x"yes"; then - echo "You can't use --lib and --plugin!" - exit 1 - fi - - shift - - if ! echo "$1" | grep "^[0-9]\+\.[0-9]\+$" >/dev/null - then - echo "$1 is not a valid library version!" - exit 1 - fi - - export LIB_MAJOR="${1%.*}" - export LIB_MINOR="${1#*.}" - - lib="yes" - OBJCFLAGS="$OBJCFLAGS $($OBJFW_CONFIG --lib-cflags)" - out_prefix="$($OBJFW_CONFIG --lib-prefix)" - out_suffix="$($OBJFW_CONFIG --lib-suffix)" - ;; - --package) - # Already included into the flags. - shift - ;; - --plugin) - if test x"$lib" = x"yes"; then - echo "You can't use --lib and --plugin!" - exit 1 - fi - - plugin="yes" - OBJCFLAGS="$OBJCFLAGS $($OBJFW_CONFIG --plugin-cflags)" - LDFLAGS="$LDFLAGS $($OBJFW_CONFIG --plugin-ldflags)" - out_suffix="$($OBJFW_CONFIG --plugin-suffix)" - ;; - --arc) - OBJCFLAGS="$OBJCFLAGS $($OBJFW_CONFIG --arc)" - ;; - --builddir) - shift - builddir="$1" - ;; - -D) - shift - CPPFLAGS="$CPPFLAGS -D$1" - ;; - -D*) - CPPFLAGS="$CPPFLAGS $1" - ;; - -framework) - shift - LIBS="$LIBS -framework $1" - ;; - -f*) - OBJCFLAGS="$OBJCFLAGS $1" - ;; - -F) - shift - LIBS="$LIBS -F$1" - ;; - -F*) - LIBS="$LIBS $1" - ;; - -g*) - OBJCFLAGS="$OBJCFLAGS $1" - ;; - -I) - shift - CPPFLAGS="$CPPFLAGS -I$1" - ;; - -I*) - CPPFLAGS="$CPPFLAGS $1" - ;; - -l) - shift - LIBS="$LIBS -l$1" - ;; - -l*) - LIBS="$LIBS $1" - ;; - -L) - shift - LIBS="$LIBS -L$1" - ;; - -L*) - LIBS="$LIBS $1" - ;; - -m*) - OBJCFLAGS="$OBJCFLAGS $1" - ;; - -O*) - OBJCFLAGS="$OBJCFLAGS $1" - ;; - -pthread) - OBJCFLAGS="$OBJCFLAGS $1" - LDFLAGS="$LDFLAGS $1" - ;; - -std=*) - OBJCFLAGS="$OBJCFLAGS $1" - ;; - -Wl,*) - LDFLAGS="$LDFLAGS $1" - ;; - -W*) - OBJCFLAGS="$OBJCFLAGS $1" - ;; - --help) - show_help - exit 0 - ;; - -*) - echo "Unknown option: $1" - exit 1 - ;; - *.m) - srcs="$srcs $1" - ;; - *.mm) - srcs="$srcs $1" - link_stdcpp="yes" - ;; - *) - echo "Only .m and .mm files can be compiled!" 1>&2 - exit 1 - ;; + -o|--out) + shift + out="$1" + ;; + --lib) + if test x"$plugin" = x"yes"; then + echo "You can't use --lib and --plugin!" + exit 1 + fi + + shift + + if ! echo "$1" | grep "^[0-9]\+\.[0-9]\+$" >/dev/null; then + echo "$1 is not a valid library version!" + exit 1 + fi + + export LIB_MAJOR="${1%.*}" + export LIB_MINOR="${1#*.}" + + lib="yes" + OBJCFLAGS="$OBJCFLAGS $($OBJFW_CONFIG --lib-cflags)" + out_prefix="$($OBJFW_CONFIG --lib-prefix)" + out_suffix="$($OBJFW_CONFIG --lib-suffix)" + ;; + --package) + # Already included into the flags. + shift + ;; + --plugin) + if test x"$lib" = x"yes"; then + echo "You can't use --lib and --plugin!" + exit 1 + fi + + plugin="yes" + OBJCFLAGS="$OBJCFLAGS $($OBJFW_CONFIG --plugin-cflags)" + LDFLAGS="$LDFLAGS $($OBJFW_CONFIG --plugin-ldflags)" + out_suffix="$($OBJFW_CONFIG --plugin-suffix)" + ;; + --arc) + OBJCFLAGS="$OBJCFLAGS $($OBJFW_CONFIG --arc)" + ;; + --builddir) + shift + builddir="$1" + ;; + -D) + shift + CPPFLAGS="$CPPFLAGS -D$1" + ;; + -D*) + CPPFLAGS="$CPPFLAGS $1" + ;; + -framework) + shift + LIBS="$LIBS -framework $1" + ;; + -f*) + OBJCFLAGS="$OBJCFLAGS $1" + ;; + -F) + shift + LIBS="$LIBS -F$1" + ;; + -F*) + LIBS="$LIBS $1" + ;; + -g*) + OBJCFLAGS="$OBJCFLAGS $1" + ;; + -I) + shift + CPPFLAGS="$CPPFLAGS -I$1" + ;; + -I*) + CPPFLAGS="$CPPFLAGS $1" + ;; + -l) + shift + LIBS="$LIBS -l$1" + ;; + -l*) + LIBS="$LIBS $1" + ;; + -L) + shift + LIBS="$LIBS -L$1" + ;; + -L*) + LIBS="$LIBS $1" + ;; + -m*) + OBJCFLAGS="$OBJCFLAGS $1" + ;; + -O*) + OBJCFLAGS="$OBJCFLAGS $1" + ;; + -pthread) + OBJCFLAGS="$OBJCFLAGS $1" + LDFLAGS="$LDFLAGS $1" + ;; + -std=*) + OBJCFLAGS="$OBJCFLAGS $1" + ;; + -Wl,*) + LDFLAGS="$LDFLAGS $1" + ;; + -W*) + OBJCFLAGS="$OBJCFLAGS $1" + ;; + --help) + show_help + exit 0 + ;; + -*) + echo "Unknown option: $1" + exit 1 + ;; + *.m) + srcs="$srcs $1" + ;; + *.mm) + srcs="$srcs $1" + link_stdcpp="yes" + ;; + *) + echo "Only .m and .mm files can be compiled!" 1>&2 + exit 1 + ;; esac shift done @@ -264,51 +261,51 @@ echo "No output name specified! Use -o or --out!" exit 1 fi case "$builddir" in - "") - ;; - */) - ;; - *) - builddir="$builddir/" - ;; +"") + ;; +*/) + ;; +*) + builddir="$builddir/" + ;; esac for i in $srcs; do case $i in - *.m) - if test x"$lib" = x"yes"; then - obj="$builddir${i%.m}.lib.o" - elif test x"$plugin" = x"yes"; then - obj="$builddir${i%.m}.plugin.o" - else - obj="$builddir${i%.m}.o" - fi - ;; - *.mm) - if test x"$lib" = x"yes"; then - obj="$builddir${i%.mm}.lib.o" - elif test x"$plugin" = x"yes"; then - obj="$builddir${i%.mm}.plugin.o" - else - obj="$builddir${i%.mm}.o" - fi - ;; + *.m) + if test x"$lib" = x"yes"; then + obj="$builddir${i%.m}.lib.o" + elif test x"$plugin" = x"yes"; then + obj="$builddir${i%.m}.plugin.o" + else + obj="$builddir${i%.m}.o" + fi + ;; + *.mm) + if test x"$lib" = x"yes"; then + obj="$builddir${i%.mm}.lib.o" + elif test x"$plugin" = x"yes"; then + obj="$builddir${i%.mm}.plugin.o" + else + obj="$builddir${i%.mm}.o" + fi + ;; esac objs="$objs $obj" build="no" - deps=$($OBJC -E -M $CPPFLAGS $OBJCFLAGS $i | - sed 's/.*: //' | sed 's/\\//g') - if test -f "$obj"; then + if test ! -f "$obj" -o "$i" -nt "$obj"; then + build="yes" + else + deps=$($OBJC -E -M $CPPFLAGS $OBJCFLAGS $i | + sed 's/.*: //' | sed 's/\\//g') for dep in $deps; do test "$dep" -nt $obj && build="yes" done - else - build="yes" fi if test x"$build" = x"yes"; then link="yes" status_compiling $i Index: utils/objfw-config.in ================================================================== --- utils/objfw-config.in +++ utils/objfw-config.in @@ -1,10 +1,8 @@ #!/bin/sh # -# Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, -# 2018, 2019, 2020 -# Jonathan Schleifer +# 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 @@ -96,14 +94,14 @@ } parse_packages() { while test x"$1" != "x"; do case "$1" in - --package) - shift - package_depends_on "$1" - ;; + --package) + shift + package_depends_on "$1" + ;; esac shift done } parse_packages "$@" @@ -118,118 +116,114 @@ fi } while test x"$1" != "x"; do case "$1" in - --all) - output_flag "$CFLAGS $CPPFLAGS $CXXFLAGS $OBJCFLAGS" - output_flag "$LDFLAGS $LDFLAGS_REEXPORT $LDFLAGS_RPATH" - output_flag "$LIBS" - ;; - --arc) - output_flag "-fobjc-arc -fobjc-arc-exceptions" - ;; - --cflags) - output_flag "$CFLAGS" - ;; - --cppflags) - output_flag "$CPPFLAGS" - ;; - --cxxflags) - output_flag "$CXXFLAGS" - ;; - --framework-libs) - output_flag "$FRAMEWORK_LIBS" - ;; - --help) - show_help 0 - ;; - --objc) - output_flag "$OBJC" - ;; - --objcflags) - output_flag "$OBJCFLAGS" - ;; - --libs) - output_flag "$LIBS" - ;; - --lib-cflags) - if test x"$LIB_MAJOR" = x"" -o x"$LIB_MINOR" = x""; then - echo "LIB_MAJOR and LIB_MINOR need to be set!" \ - 1>&2 - exit 1 - fi - - output_flag "$LIB_CFLAGS" - ;; - --lib-ldflags) - if test x"$SHARED_LIB" = x"" -o x"$LIB_MAJOR" = x"" \ - -o x"$LIB_MINOR" = x""; then - printf "SHARED_LIB, LIB_MAJOR and " 2>&1 - echo "LIB_MINOR need to be set!" 1>&2 - exit 1 - fi - - output_flag "$LIB_LDFLAGS" - ;; - --lib-prefix) - if test x"$LIB_MAJOR" = x"" -o x"$LIB_MINOR" = x""; then - echo "LIB_MAJOR and LIB_MINOR need to be set!" \ - 1>&2 - exit 1 - fi - - output_flag "$LIB_PREFIX" - ;; - --lib-suffix) - if test x"$LIB_MAJOR" = x"" -o x"$LIB_MINOR" = x""; then - echo "LIB_MAJOR and LIB_MINOR need to be set!" \ - 1>&2 - exit 1 - fi - - output_flag "$LIB_SUFFIX" - ;; - --ldflags) - output_flag "$LDFLAGS" - ;; - --reexport) - output_flag "$LDFLAGS_REEXPORT" - ;; - --rpath) - output_flag "$LDFLAGS_RPATH" - ;; - --package) - # Already included into the flags. - shift - ;; - --packages-dir) - output_flag "$packagesdir" - ;; - --plugin-cflags) - output_flag "$PLUGIN_CFLAGS" - ;; - --plugin-ldflags) - output_flag "$PLUGIN_LDFLAGS" - ;; - --plugin-suffix) - output_flag "$PLUGIN_SUFFIX" - ;; - --prog-suffix) - output_flag "$PROG_SUFFIX" - ;; - --static-libs) - output_flag "$STATIC_LIBS" - ;; - --version) - output_flag "$VERSION" - ;; - *) - echo "Invalid option: $1" 1>&2 - exit 1 - ;; + --all) + output_flag "$CFLAGS $CPPFLAGS $CXXFLAGS $OBJCFLAGS" + output_flag "$LDFLAGS $LDFLAGS_REEXPORT $LDFLAGS_RPATH $LIBS" + ;; + --arc) + output_flag "-fobjc-arc -fobjc-arc-exceptions" + ;; + --cflags) + output_flag "$CFLAGS" + ;; + --cppflags) + output_flag "$CPPFLAGS" + ;; + --cxxflags) + output_flag "$CXXFLAGS" + ;; + --framework-libs) + output_flag "$FRAMEWORK_LIBS" + ;; + --help) + show_help 0 + ;; + --objc) + output_flag "$OBJC" + ;; + --objcflags) + output_flag "$OBJCFLAGS" + ;; + --libs) + output_flag "$LIBS" + ;; + --lib-cflags) + if test x"$LIB_MAJOR" = x"" -o x"$LIB_MINOR" = x""; then + echo "LIB_MAJOR and LIB_MINOR need to be set!" 1>&2 + exit 1 + fi + + output_flag "$LIB_CFLAGS" + ;; + --lib-ldflags) + if test x"$SHARED_LIB" = x"" -o x"$LIB_MAJOR" = x"" \ + -o x"$LIB_MINOR" = x""; then + printf "SHARED_LIB, LIB_MAJOR and " 2>&1 + echo "LIB_MINOR need to be set!" 1>&2 + exit 1 + fi + + output_flag "$LIB_LDFLAGS" + ;; + --lib-prefix) + if test x"$LIB_MAJOR" = x"" -o x"$LIB_MINOR" = x""; then + echo "LIB_MAJOR and LIB_MINOR need to be set!" 1>&2 + exit 1 + fi + + output_flag "$LIB_PREFIX" + ;; + --lib-suffix) + if test x"$LIB_MAJOR" = x"" -o x"$LIB_MINOR" = x""; then + echo "LIB_MAJOR and LIB_MINOR need to be set!" 1>&2 + exit 1 + fi + + output_flag "$LIB_SUFFIX" + ;; + --ldflags) + output_flag "$LDFLAGS" + ;; + --reexport) + output_flag "$LDFLAGS_REEXPORT" + ;; + --rpath) + output_flag "$LDFLAGS_RPATH" + ;; + --package) + # Already included into the flags. + shift + ;; + --packages-dir) + output_flag "$packagesdir" + ;; + --plugin-cflags) + output_flag "$PLUGIN_CFLAGS" + ;; + --plugin-ldflags) + output_flag "$PLUGIN_LDFLAGS" + ;; + --plugin-suffix) + output_flag "$PLUGIN_SUFFIX" + ;; + --prog-suffix) + output_flag "$PROG_SUFFIX" + ;; + --static-libs) + output_flag "$STATIC_LIBS" + ;; + --version) + output_flag "$VERSION" + ;; + *) + echo "Invalid option: $1" 1>&2 + exit 1 + ;; esac shift done test x"$flag_printed" = x"yes" && echo exit 0 Index: utils/objfw-new ================================================================== --- utils/objfw-new +++ utils/objfw-new @@ -14,14 +14,14 @@ name="$2" test -z "$name" && show_help case "$1" in - app) - test -f "$name.m" && already_exists "$name.m" +app) + test -f "$name.m" && already_exists "$name.m" - cat >"$name.m" <<__EOF__ + cat >"$name.m" <<__EOF__ #import @interface $name: OFObject @end @@ -32,16 +32,16 @@ { [OFApplication terminate]; } @end __EOF__ - ;; - class) - test -f "$name.h" && already_exists "$name.h" - test -f "$name.m" && already_exists "$name.m" + ;; +class) + test -f "$name.h" && already_exists "$name.h" + test -f "$name.m" && already_exists "$name.m" - cat >"$name.h" <<__EOF__ + cat >"$name.h" <<__EOF__ #import @interface $name: OFObject @end __EOF__ @@ -49,10 +49,10 @@ #import "$name.h" @implementation $name @end __EOF__ - ;; - *) - show_help - ;; + ;; +*) + show_help + ;; esac Index: utils/ofarc/Archive.h ================================================================== --- utils/ofarc/Archive.h +++ utils/ofarc/Archive.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -20,15 +18,15 @@ #import "OFArray.h" @protocol Archive + (instancetype)archiveWithStream: (OF_KINDOF(OFStream *))stream mode: (OFString *)mode - encoding: (of_string_encoding_t)encoding; + encoding: (OFStringEncoding)encoding; - (instancetype)initWithStream: (OF_KINDOF(OFStream *))stream mode: (OFString *)mode - encoding: (of_string_encoding_t)encoding; + encoding: (OFStringEncoding)encoding; - (void)listFiles; - (void)extractFiles: (OFArray OF_GENERIC(OFString *) *)files; - (void)printFiles: (OFArray OF_GENERIC(OFString *) *)files; @optional - (void)addFiles: (OFArray OF_GENERIC(OFString *) *)files; @end Index: utils/ofarc/GZIPArchive.h ================================================================== --- utils/ofarc/GZIPArchive.h +++ utils/ofarc/GZIPArchive.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: utils/ofarc/GZIPArchive.m ================================================================== --- utils/ofarc/GZIPArchive.m +++ utils/ofarc/GZIPArchive.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -30,14 +28,14 @@ static void setPermissions(OFString *destination, OFString *source) { #ifdef OF_FILE_MANAGER_SUPPORTS_PERMISSIONS OFFileManager *fileManager = [OFFileManager defaultManager]; - of_file_attributes_t attributes = - [fileManager attributesOfItemAtPath: source]; - of_file_attribute_key_t key = of_file_attribute_key_posix_permissions; - of_file_attributes_t destinationAttributes = [OFDictionary + OFFileAttributes attributes = [fileManager + attributesOfItemAtPath: source]; + OFFileAttributeKey key = OFFilePOSIXPermissions; + OFFileAttributes destinationAttributes = [OFDictionary dictionaryWithObject: [attributes objectForKey: key] forKey: key]; [fileManager setAttributes: destinationAttributes ofItemAtPath: destination]; @@ -46,18 +44,18 @@ static void setModificationDate(OFString *path, OFGZIPStream *stream) { OFDate *modificationDate = stream.modificationDate; - of_file_attributes_t attributes; + OFFileAttributes attributes; if (modificationDate == nil) return; attributes = [OFDictionary dictionaryWithObject: modificationDate - forKey: of_file_attribute_key_modification_date]; + forKey: OFFileModificationDate]; [[OFFileManager defaultManager] setAttributes: attributes ofItemAtPath: path]; } @implementation GZIPArchive @@ -67,20 +65,20 @@ app = (OFArc *)[OFApplication sharedApplication].delegate; } + (instancetype)archiveWithStream: (OF_KINDOF(OFStream *))stream mode: (OFString *)mode - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding { return [[[self alloc] initWithStream: stream mode: mode encoding: encoding] autorelease]; } - (instancetype)initWithStream: (OF_KINDOF(OFStream *))stream mode: (OFString *)mode - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding { self = [super init]; @try { _stream = [[OFGZIPStream alloc] initWithStream: stream @@ -100,11 +98,11 @@ [super dealloc]; } - (void)listFiles { - [of_stderr writeLine: OF_LOCALIZED(@"cannot_list_gz", + [OFStdErr writeLine: OF_LOCALIZED(@"cannot_list_gz", @"Cannot list files of a .gz archive!")]; app->_exitStatus = 1; } - (void)extractFiles: (OFArray OF_GENERIC(OFString *) *)files @@ -111,11 +109,11 @@ { OFString *fileName; OFFile *output; if (files.count != 0) { - [of_stderr writeLine: + [OFStdErr writeLine: OF_LOCALIZED(@"cannot_extract_specific_file_from_gz", @"Cannot extract a specific file of a .gz archive!")]; app->_exitStatus = 1; return; } @@ -122,20 +120,18 @@ fileName = app->_archivePath.lastPathComponent .stringByDeletingPathExtension; if (app->_outputLevel >= 0) - [of_stdout writeString: OF_LOCALIZED(@"extracting_file", + [OFStdOut writeString: OF_LOCALIZED(@"extracting_file", @"Extracting %[file]...", @"file", fileName)]; - if (![app shouldExtractFile: fileName - outFileName: fileName]) + if (![app shouldExtractFile: fileName outFileName: fileName]) return; - output = [OFFile fileWithPath: fileName - mode: @"w"]; + output = [OFFile fileWithPath: fileName mode: @"w"]; setPermissions(fileName, app->_archivePath); while (!_stream.atEndOfStream) { ssize_t length = [app copyBlockFromStream: _stream toStream: output @@ -149,12 +145,12 @@ [output close]; setModificationDate(fileName, _stream); if (app->_outputLevel >= 0) { - [of_stdout writeString: @"\r"]; - [of_stdout writeLine: OF_LOCALIZED(@"extracting_file_done", + [OFStdOut writeString: @"\r"]; + [OFStdOut writeLine: OF_LOCALIZED(@"extracting_file_done", @"Extracting %[file]... done", @"file", fileName)]; } } @@ -162,24 +158,24 @@ { OFString *fileName = app->_archivePath.lastPathComponent .stringByDeletingPathExtension; if (files.count > 0) { - [of_stderr writeLine: OF_LOCALIZED( + [OFStdErr writeLine: OF_LOCALIZED( @"cannot_print_specific_file_from_gz", @"Cannot print a specific file of a .gz archive!")]; app->_exitStatus = 1; return; } while (!_stream.atEndOfStream) { ssize_t length = [app copyBlockFromStream: _stream - toStream: of_stdout + toStream: OFStdOut fileName: fileName]; if (length < 0) { app->_exitStatus = 1; return; } } } @end Index: utils/ofarc/LHAArchive.h ================================================================== --- utils/ofarc/LHAArchive.h +++ utils/ofarc/LHAArchive.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: utils/ofarc/LHAArchive.m ================================================================== --- utils/ofarc/LHAArchive.m +++ utils/ofarc/LHAArchive.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -48,13 +46,13 @@ return; mode = [OFNumber numberWithUnsignedShort: mode.unsignedShortValue & 0777]; - of_file_attributes_t attributes = [OFDictionary + OFFileAttributes attributes = [OFDictionary dictionaryWithObject: mode - forKey: of_file_attribute_key_posix_permissions]; + forKey: OFFilePOSIXPermissions]; [[OFFileManager defaultManager] setAttributes: attributes ofItemAtPath: path]; #endif } @@ -61,11 +59,11 @@ static void setModificationDate(OFString *path, OFLHAArchiveEntry *entry) { OFDate *modificationDate = entry.modificationDate; - of_file_attributes_t attributes; + OFFileAttributes attributes; if (modificationDate == nil) { /* * Fall back to the original date if we have no modification * date, as the modification date is a UNIX extension. @@ -76,11 +74,11 @@ return; } attributes = [OFDictionary dictionaryWithObject: modificationDate - forKey: of_file_attribute_key_modification_date]; + forKey: OFFileModificationDate]; [[OFFileManager defaultManager] setAttributes: attributes ofItemAtPath: path]; } @implementation LHAArchive @@ -90,28 +88,28 @@ app = (OFArc *)[OFApplication sharedApplication].delegate; } + (instancetype)archiveWithStream: (OF_KINDOF(OFStream *))stream mode: (OFString *)mode - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding { return [[[self alloc] initWithStream: stream mode: mode encoding: encoding] autorelease]; } - (instancetype)initWithStream: (OF_KINDOF(OFStream *))stream mode: (OFString *)mode - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding { self = [super init]; @try { _archive = [[OFLHAArchive alloc] initWithStream: stream mode: mode]; - if (encoding != OF_STRING_ENCODING_AUTODETECT) + if (encoding != OFStringEncodingAutodetect) _archive.encoding = encoding; } @catch (id e) { [self release]; @throw e; } @@ -131,11 +129,11 @@ OFLHAArchiveEntry *entry; while ((entry = [_archive nextEntry]) != nil) { void *pool = objc_autoreleasePoolPush(); - [of_stdout writeLine: entry.fileName]; + [OFStdOut writeLine: entry.fileName]; if (app->_outputLevel >= 1) { OFString *date = [entry.date localDateStringWithFormat: @"%Y-%m-%d %H:%M:%S"]; OFString *compressedSize = [OFString stringWithFormat: @@ -143,78 +141,78 @@ OFString *uncompressedSize = [OFString stringWithFormat: @"%" PRIu32, entry.uncompressedSize]; OFString *CRC16 = [OFString stringWithFormat: @"%04" PRIX16, entry.CRC16]; - [of_stdout writeString: @"\t"]; - [of_stdout writeLine: OF_LOCALIZED( + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED( @"list_compressed_size", @"[" @" 'Compressed: '," @" [" @" {'size == 1': '1 byte'}," @" {'': '%[size] bytes'}" @" ]" @"]".objectByParsingJSON, @"size", compressedSize)]; - [of_stdout writeString: @"\t"]; - [of_stdout writeLine: OF_LOCALIZED( + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED( @"list_uncompressed_size", @"[" @" 'Uncompressed: '," @" [" @" {'size == 1': '1 byte'}," @" {'': '%[size] bytes'}" @" ]" @"]".objectByParsingJSON, @"size", uncompressedSize)]; - [of_stdout writeString: @"\t"]; - [of_stdout writeLine: OF_LOCALIZED( + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED( @"list_compression_method", @"Compression method: %[method]", @"method", entry.compressionMethod)]; - [of_stdout writeString: @"\t"]; - [of_stdout writeLine: OF_LOCALIZED(@"list_crc16", + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED(@"list_crc16", @"CRC16: %[crc16]", @"crc16", CRC16)]; - [of_stdout writeString: @"\t"]; - [of_stdout writeLine: OF_LOCALIZED(@"list_date", + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED(@"list_date", @"Date: %[date]", @"date", date)]; if (entry.mode != nil) { OFString *modeString = [OFString stringWithFormat: @"%ho", entry.mode.unsignedShortValue]; - [of_stdout writeString: @"\t"]; - [of_stdout writeLine: OF_LOCALIZED(@"list_mode", + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED(@"list_mode", @"Mode: %[mode]", @"mode", modeString)]; } if (entry.UID != nil) { - [of_stdout writeString: @"\t"]; - [of_stdout writeLine: OF_LOCALIZED(@"list_uid", + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED(@"list_uid", @"UID: %[uid]", @"uid", entry.UID)]; } if (entry.GID != nil) { - [of_stdout writeString: @"\t"]; - [of_stdout writeLine: OF_LOCALIZED(@"list_gid", + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED(@"list_gid", @"GID: %[gid]", @"gid", entry.GID)]; } if (entry.owner != nil) { - [of_stdout writeString: @"\t"]; - [of_stdout writeLine: OF_LOCALIZED( + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED( @"list_owner", @"Owner: %[owner]", @"owner", entry.owner)]; } if (entry.group != nil) { - [of_stdout writeString: @"\t"]; - [of_stdout writeLine: OF_LOCALIZED( + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED( @"list_group", @"Group: %[group]", @"group", entry.group)]; } @@ -221,23 +219,23 @@ if (app->_outputLevel >= 2) { OFString *headerLevel = [OFString stringWithFormat: @"%" PRIu8, entry.headerLevel]; - [of_stdout writeString: @"\t"]; - [of_stdout writeLine: OF_LOCALIZED( + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED( @"list_header_level", @"Header level: %[level]", @"level", headerLevel)]; if (entry.operatingSystemIdentifier != '\0') { OFString *OSID = [OFString stringWithFormat: @"%c", entry.operatingSystemIdentifier]; - [of_stdout writeString: @"\t"]; - [of_stdout writeLine: OF_LOCALIZED( + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED( @"list_osid", @"Operating system identifier: " "%[osid]", @"osid", OSID)]; } @@ -244,12 +242,12 @@ if (entry.modificationDate != nil) { OFString *modificationDate = entry.modificationDate.description; - [of_stdout writeString: @"\t"]; - [of_stdout writeLine: OF_LOCALIZED( + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED( @"list_modification_date", @"Modification date: %[date]", @"date", modificationDate)]; } } @@ -256,12 +254,12 @@ if (app->_outputLevel >= 3) { OFString *extensions = indent(entry.extensions.description); - [of_stdout writeString: @"\t"]; - [of_stdout writeLine: OF_LOCALIZED( + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED( @"list_extensions", @"Extensions: %[extensions]", @"extensions", extensions)]; } } @@ -292,21 +290,21 @@ [missing removeObject: fileName]; outFileName = [app safeLocalPathForPath: fileName]; if (outFileName == nil) { - [of_stderr writeLine: OF_LOCALIZED( + [OFStdErr writeLine: OF_LOCALIZED( @"refusing_to_extract_file", @"Refusing to extract %[file]!", @"file", fileName)]; app->_exitStatus = 1; goto outer_loop_end; } if (app->_outputLevel >= 0) - [of_stdout writeString: OF_LOCALIZED(@"extracting_file", + [OFStdOut writeString: OF_LOCALIZED(@"extracting_file", @"Extracting %[file]...", @"file", fileName)]; if ([fileName hasSuffix: @"/"]) { [fileManager createDirectoryAtPath: outFileName @@ -313,12 +311,12 @@ createParents: true]; setPermissions(outFileName, entry); setModificationDate(outFileName, entry); if (app->_outputLevel >= 0) { - [of_stdout writeString: @"\r"]; - [of_stdout writeLine: OF_LOCALIZED( + [OFStdOut writeString: @"\r"]; + [OFStdOut writeLine: OF_LOCALIZED( @"extracting_file_done", @"Extracting %[file]... done", @"file", fileName)]; } @@ -328,17 +326,15 @@ directory = outFileName.stringByDeletingLastPathComponent; if (![fileManager directoryExistsAtPath: directory]) [fileManager createDirectoryAtPath: directory createParents: true]; - if (![app shouldExtractFile: fileName - outFileName: outFileName]) + if (![app shouldExtractFile: fileName outFileName: outFileName]) goto outer_loop_end; stream = [_archive streamForReadingCurrentEntry]; - output = [OFFile fileWithPath: outFileName - mode: @"w"]; + output = [OFFile fileWithPath: outFileName mode: @"w"]; setPermissions(outFileName, entry); while (!stream.atEndOfStream) { ssize_t length = [app copyBlockFromStream: stream toStream: output @@ -358,12 +354,12 @@ percent = newPercent; percentString = [OFString stringWithFormat: @"%3u", percent]; - [of_stdout writeString: @"\r"]; - [of_stdout writeString: OF_LOCALIZED( + [OFStdOut writeString: @"\r"]; + [OFStdOut writeString: OF_LOCALIZED( @"extracting_file_percent", @"Extracting %[file]... %[percent]%", @"file", fileName, @"percent", percentString)]; } @@ -371,12 +367,12 @@ [output close]; setModificationDate(outFileName, entry); if (app->_outputLevel >= 0) { - [of_stdout writeString: @"\r"]; - [of_stdout writeLine: OF_LOCALIZED( + [OFStdOut writeString: @"\r"]; + [OFStdOut writeLine: OF_LOCALIZED( @"extracting_file_done", @"Extracting %[file]... done", @"file", fileName)]; } @@ -384,11 +380,11 @@ objc_autoreleasePoolPop(pool); } if (missing.count > 0) { for (OFString *file in missing) - [of_stderr writeLine: OF_LOCALIZED( + [OFStdErr writeLine: OF_LOCALIZED( @"file_not_in_archive", @"File %[file] is not in the archive!", @"file", file)]; app->_exitStatus = 1; @@ -399,11 +395,11 @@ { OFMutableSet *files; OFLHAArchiveEntry *entry; if (files_.count < 1) { - [of_stderr writeLine: OF_LOCALIZED(@"print_no_file_specified", + [OFStdErr writeLine: OF_LOCALIZED(@"print_no_file_specified", @"Need one or more files to print!")]; app->_exitStatus = 1; return; } @@ -418,11 +414,11 @@ stream = [_archive streamForReadingCurrentEntry]; while (!stream.atEndOfStream) { ssize_t length = [app copyBlockFromStream: stream - toStream: of_stdout + toStream: OFStdOut fileName: fileName]; if (length < 0) { app->_exitStatus = 1; return; @@ -435,11 +431,11 @@ if (files.count == 0) break; } for (OFString *file in files) { - [of_stderr writeLine: OF_LOCALIZED(@"file_not_in_archive", + [OFStdErr writeLine: OF_LOCALIZED(@"file_not_in_archive", @"File %[file] is not in the archive!", @"file", file)]; app->_exitStatus = 1; } } @@ -447,25 +443,25 @@ - (void)addFiles: (OFArray OF_GENERIC(OFString *) *)files { OFFileManager *fileManager = [OFFileManager defaultManager]; if (files.count < 1) { - [of_stderr writeLine: OF_LOCALIZED(@"add_no_file_specified", + [OFStdErr writeLine: OF_LOCALIZED(@"add_no_file_specified", @"Need one or more files to add!")]; app->_exitStatus = 1; return; } for (OFString *fileName in files) { void *pool = objc_autoreleasePoolPush(); - of_file_attributes_t attributes; - of_file_type_t type; + OFFileAttributes attributes; + OFFileAttributeType type; OFMutableLHAArchiveEntry *entry; OFStream *output; if (app->_outputLevel >= 0) - [of_stdout writeString: OF_LOCALIZED(@"adding_file", + [OFStdOut writeString: OF_LOCALIZED(@"adding_file", @"Adding %[file]...", @"file", fileName)]; attributes = [fileManager attributesOfItemAtPath: fileName]; type = attributes.fileType; @@ -476,24 +472,29 @@ attributes.filePOSIXPermissions]; #endif entry.date = attributes.fileModificationDate; #ifdef OF_FILE_MANAGER_SUPPORTS_OWNER - entry.UID = - [OFNumber numberWithUnsignedLong: attributes.filePOSIXUID]; - entry.GID = - [OFNumber numberWithUnsignedLong: attributes.filePOSIXGID]; - entry.owner = attributes.fileOwner; - entry.group = attributes.fileGroup; + entry.UID = [OFNumber numberWithUnsignedLong: + attributes.fileOwnerAccountID]; + entry.GID = [OFNumber numberWithUnsignedLong: + attributes.fileGroupOwnerAccountID]; + entry.owner = attributes.fileOwnerAccountName; + entry.group = attributes.fileGroupOwnerAccountName; #endif - if ([type isEqual: of_file_type_directory]) + if ([type isEqual: OFFileTypeDirectory]) { entry.compressionMethod = @"-lhd-"; + + if (![entry.fileName hasSuffix: @"/"]) + entry.fileName = [entry.fileName + stringByAppendingString: @"/"]; + } output = [_archive streamForWritingEntry: entry]; - if ([type isEqual: of_file_type_regular]) { + if ([type isEqual: OFFileTypeRegular]) { unsigned long long written = 0; unsigned long long size = attributes.fileSize; int8_t percent = -1, newPercent; OFFile *input = [OFFile fileWithPath: fileName @@ -520,23 +521,23 @@ percent = newPercent; percentString = [OFString stringWithFormat: @"%3u", percent]; - [of_stdout writeString: @"\r"]; - [of_stdout writeString: OF_LOCALIZED( + [OFStdOut writeString: @"\r"]; + [OFStdOut writeString: OF_LOCALIZED( @"adding_file_percent", @"Adding %[file]... %[percent]%", @"file", fileName, @"percent", percentString)]; } } } if (app->_outputLevel >= 0) { - [of_stdout writeString: @"\r"]; - [of_stdout writeLine: OF_LOCALIZED( + [OFStdOut writeString: @"\r"]; + [OFStdOut writeLine: OF_LOCALIZED( @"adding_file_done", @"Adding %[file]... done", @"file", fileName)]; } Index: utils/ofarc/OFArc.h ================================================================== --- utils/ofarc/OFArc.h +++ utils/ofarc/OFArc.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -39,15 +37,15 @@ } - (id )openArchiveWithPath: (OFString *)path type: (OFString *)type mode: (char)mode - encoding: (of_string_encoding_t)encoding; + encoding: (OFStringEncoding)encoding; - (bool)shouldExtractFile: (OFString *)fileName outFileName: (OFString *)outFileName; - (ssize_t)copyBlockFromStream: (OFStream *)input toStream: (OFStream *)output fileName: (OFString *)fileName; - (nullable OFString *)safeLocalPathForPath: (OFString *)path; @end OF_ASSUME_NONNULL_END Index: utils/ofarc/OFArc.m ================================================================== --- utils/ofarc/OFArc.m +++ utils/ofarc/OFArc.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -42,11 +40,11 @@ #import "OFOpenItemFailedException.h" #import "OFReadFailedException.h" #import "OFSeekFailedException.h" #import "OFWriteFailedException.h" -#define BUFFER_SIZE 4096 +#define bufferSize 4096 OF_APPLICATION_DELEGATE(OFArc) static void help(OFStream *stream, bool full, int status) @@ -81,19 +79,19 @@ [OFApplication terminateWithStatus: status]; } static void -mutuallyExclusiveError(of_unichar_t shortOption1, OFString *longOption1, - of_unichar_t shortOption2, OFString *longOption2) +mutuallyExclusiveError(OFUnichar shortOption1, OFString *longOption1, + OFUnichar shortOption2, OFString *longOption2) { OFString *shortOption1Str = [OFString stringWithFormat: @"%C", shortOption1]; OFString *shortOption2Str = [OFString stringWithFormat: @"%C", shortOption2]; - [of_stderr writeLine: OF_LOCALIZED(@"2_options_mutually_exclusive", + [OFStdErr writeLine: OF_LOCALIZED(@"2_options_mutually_exclusive", @"Error: -%[shortopt1] / --%[longopt1] and " @"-%[shortopt2] / --%[longopt2] " @"are mutually exclusive!", @"shortopt1", shortOption1Str, @"longopt1", longOption1, @@ -101,15 +99,15 @@ @"longopt2", longOption2)]; [OFApplication terminateWithStatus: 1]; } static void -mutuallyExclusiveError5(of_unichar_t shortOption1, OFString *longOption1, - of_unichar_t shortOption2, OFString *longOption2, - of_unichar_t shortOption3, OFString *longOption3, - of_unichar_t shortOption4, OFString *longOption4, - of_unichar_t shortOption5, OFString *longOption5) +mutuallyExclusiveError5(OFUnichar shortOption1, OFString *longOption1, + OFUnichar shortOption2, OFString *longOption2, + OFUnichar shortOption3, OFString *longOption3, + OFUnichar shortOption4, OFString *longOption4, + OFUnichar shortOption5, OFString *longOption5) { OFString *shortOption1Str = [OFString stringWithFormat: @"%C", shortOption1]; OFString *shortOption2Str = [OFString stringWithFormat: @"%C", shortOption2]; @@ -118,11 +116,11 @@ OFString *shortOption4Str = [OFString stringWithFormat: @"%C", shortOption4]; OFString *shortOption5Str = [OFString stringWithFormat: @"%C", shortOption5]; - [of_stderr writeLine: OF_LOCALIZED(@"5_options_mutually_exclusive", + [OFStdErr writeLine: OF_LOCALIZED(@"5_options_mutually_exclusive", @"Error: -%[shortopt1] / --%[longopt1], " @"-%[shortopt2] / --%[longopt2], -%[shortopt3] / --%[longopt3], " @"-%[shortopt4] / --%[longopt4] and\n" @" -%[shortopt5] / --%[longopt5] are mutually exclusive!", @"shortopt1", shortOption1Str, @@ -139,21 +137,42 @@ } static void writingNotSupported(OFString *type) { - [of_stderr writeLine: OF_LOCALIZED( + [OFStdErr writeLine: OF_LOCALIZED( @"writing_not_supported", @"Writing archives of type %[type] is not (yet) supported!", @"type", type)]; } + +static void +addFiles(id archive, OFArray OF_GENERIC(OFString *) *files) +{ + OFMutableArray *expandedFiles = + [OFMutableArray arrayWithCapacity: files.count]; + OFFileManager *fileManager = [OFFileManager defaultManager]; + + for (OFString *file in files) { + OFFileAttributes attributes = + [fileManager attributesOfItemAtPath: file]; + + if ([attributes.fileType isEqual: OFFileTypeDirectory]) + [expandedFiles addObjectsFromArray: + [fileManager subpathsOfDirectoryAtPath: file]]; + else + [expandedFiles addObject: file]; + } + + [archive addFiles: expandedFiles]; +} @implementation OFArc - (void)applicationDidFinishLaunching { OFString *outputDir, *encodingString, *type; - const of_options_parser_option_t options[] = { + const OFOptionsParserOption options[] = { { 'a', @"append", 0, NULL, NULL }, { 'c', @"create", 0, NULL, NULL }, { 'C', @"directory", 1, NULL, &outputDir }, { 'E', @"encoding", 1, NULL, &encodingString }, { 'f', @"force", 0, NULL, NULL }, @@ -165,12 +184,12 @@ { 't', @"type", 1, NULL, &type }, { 'v', @"verbose", 0, NULL, NULL }, { 'x', @"extract", 0, NULL, NULL }, { '\0', nil, 0, NULL, NULL } }; - of_unichar_t option, mode = '\0'; - of_string_encoding_t encoding = OF_STRING_ENCODING_AUTODETECT; + OFUnichar option, mode = '\0'; + OFStringEncoding encoding = OFStringEncodingAutodetect; OFOptionsParser *optionsParser; OFArray OF_GENERIC(OFString *) *remainingArguments, *files; id archive; #ifdef OF_HAVE_SANDBOX @@ -182,11 +201,11 @@ sandbox.allowsChangingFileAttributes = true; sandbox.allowsUserDatabaseReading = true; /* Dropped after parsing options */ sandbox.allowsUnveil = true; - [OFApplication activateSandbox: sandbox]; + [OFApplication of_activateSandbox: sandbox]; #endif #ifndef OF_AMIGAOS [OFLocale addLanguageDirectory: @LANGUAGE_DIR]; #else @@ -238,34 +257,34 @@ 'x', @"extract"); mode = option; break; case 'h': - help(of_stdout, true, 0); + help(OFStdOut, true, 0); break; case '=': - [of_stderr writeLine: OF_LOCALIZED( + [OFStdErr writeLine: OF_LOCALIZED( @"option_takes_no_argument", @"%[prog]: Option --%[opt] takes no argument", @"prog", [OFApplication programName], @"opt", optionsParser.lastLongOption)]; [OFApplication terminateWithStatus: 1]; break; case ':': if (optionsParser.lastLongOption != nil) - [of_stderr writeLine: OF_LOCALIZED( + [OFStdErr writeLine: OF_LOCALIZED( @"long_option_requires_argument", @"%[prog]: Option --%[opt] requires an " @"argument", @"prog", [OFApplication programName], @"opt", optionsParser.lastLongOption)]; else { OFString *optStr = [OFString stringWithFormat: @"%C", optionsParser.lastOption]; - [of_stderr writeLine: OF_LOCALIZED( + [OFStdErr writeLine: OF_LOCALIZED( @"option_requires_argument", @"%[prog]: Option -%[opt] requires an " @"argument", @"prog", [OFApplication programName], @"opt", optStr)]; @@ -273,20 +292,20 @@ [OFApplication terminateWithStatus: 1]; break; case '?': if (optionsParser.lastLongOption != nil) - [of_stderr writeLine: OF_LOCALIZED( + [OFStdErr writeLine: OF_LOCALIZED( @"unknown_long_option", @"%[prog]: Unknown option: --%[opt]", @"prog", [OFApplication programName], @"opt", optionsParser.lastLongOption)]; else { OFString *optStr = [OFString stringWithFormat: @"%C", optionsParser.lastOption]; - [of_stderr writeLine: OF_LOCALIZED( + [OFStdErr writeLine: OF_LOCALIZED( @"unknown_option", @"%[prog]: Unknown option: -%[opt]", @"prog", [OFApplication programName], @"opt", optStr)]; } @@ -296,13 +315,13 @@ } } @try { if (encodingString != nil) - encoding = of_string_parse_encoding(encodingString); + encoding = OFStringEncodingParseName(encodingString); } @catch (OFInvalidArgumentException *e) { - [of_stderr writeLine: OF_LOCALIZED( + [OFStdErr writeLine: OF_LOCALIZED( @"invalid_encoding", @"%[prog]: Invalid encoding: %[encoding]", @"prog", [OFApplication programName], @"encoding", encodingString)]; @@ -313,47 +332,46 @@ switch (mode) { case 'a': case 'c': if (remainingArguments.count < 1) - help(of_stderr, false, 1); + help(OFStdErr, false, 1); files = [remainingArguments objectsInRange: - of_range(1, remainingArguments.count - 1)]; + OFRangeMake(1, remainingArguments.count - 1)]; #ifdef OF_HAVE_SANDBOX if (![remainingArguments.firstObject isEqual: @"-"]) [sandbox unveilPath: remainingArguments.firstObject permissions: (mode == 'a' ? @"rwc" : @"wc")]; for (OFString *path in files) - [sandbox unveilPath: path - permissions: @"r"]; + [sandbox unveilPath: path permissions: @"r"]; sandbox.allowsUnveil = false; - [OFApplication activateSandbox: sandbox]; + [OFApplication of_activateSandbox: sandbox]; #endif archive = [self openArchiveWithPath: remainingArguments.firstObject type: type mode: mode encoding: encoding]; - [archive addFiles: files]; + addFiles(archive, files); break; case 'l': if (remainingArguments.count != 1) - help(of_stderr, false, 1); + help(OFStdErr, false, 1); #ifdef OF_HAVE_SANDBOX if (![remainingArguments.firstObject isEqual: @"-"]) [sandbox unveilPath: remainingArguments.firstObject permissions: @"r"]; sandbox.allowsUnveil = false; - [OFApplication activateSandbox: sandbox]; + [OFApplication of_activateSandbox: sandbox]; #endif archive = [self openArchiveWithPath: remainingArguments.firstObject type: type @@ -362,23 +380,23 @@ [archive listFiles]; break; case 'p': if (remainingArguments.count < 1) - help(of_stderr, false, 1); + help(OFStdErr, false, 1); #ifdef OF_HAVE_SANDBOX if (![remainingArguments.firstObject isEqual: @"-"]) [sandbox unveilPath: remainingArguments.firstObject permissions: @"r"]; sandbox.allowsUnveil = false; - [OFApplication activateSandbox: sandbox]; + [OFApplication of_activateSandbox: sandbox]; #endif files = [remainingArguments objectsInRange: - of_range(1, remainingArguments.count - 1)]; + OFRangeMake(1, remainingArguments.count - 1)]; archive = [self openArchiveWithPath: remainingArguments.firstObject type: type mode: mode @@ -386,34 +404,36 @@ [archive printFiles: files]; break; case 'x': if (remainingArguments.count < 1) - help(of_stderr, false, 1); + help(OFStdErr, false, 1); files = [remainingArguments objectsInRange: - of_range(1, remainingArguments.count - 1)]; + OFRangeMake(1, remainingArguments.count - 1)]; #ifdef OF_HAVE_SANDBOX if (![remainingArguments.firstObject isEqual: @"-"]) [sandbox unveilPath: remainingArguments.firstObject permissions: @"r"]; if (files.count > 0) for (OFString *path in files) - [sandbox unveilPath: path - permissions: @"wc"]; + [sandbox unveilPath: path permissions: @"wc"]; else { - OFString *path = (outputDir != nil - ? outputDir : OF_PATH_CURRENT_DIRECTORY); + OFString *path = outputDir; + + if (path == nil) + path = [[OFFileManager defaultManager] + currentDirectoryPath]; + /* We need 'r' to change the directory to it. */ - [sandbox unveilPath: path - permissions: @"rwc"]; + [sandbox unveilPath: path permissions: @"rwc"]; } sandbox.allowsUnveil = false; - [OFApplication activateSandbox: sandbox]; + [OFApplication of_activateSandbox: sandbox]; #endif archive = [self openArchiveWithPath: remainingArguments.firstObject type: type @@ -435,43 +455,43 @@ [archive extractFiles: files]; } @catch (OFCreateDirectoryFailedException *e) { OFString *error = [OFString stringWithCString: strerror(e.errNo) encoding: [OFLocale encoding]]; - [of_stderr writeString: @"\r"]; - [of_stderr writeLine: OF_LOCALIZED( + [OFStdErr writeString: @"\r"]; + [OFStdErr writeLine: OF_LOCALIZED( @"failed_to_create_directory", @"Failed to create directory %[dir]: %[error]", @"dir", e.URL.fileSystemRepresentation, @"error", error)]; _exitStatus = 1; } @catch (OFOpenItemFailedException *e) { OFString *error = [OFString stringWithCString: strerror(e.errNo) encoding: [OFLocale encoding]]; - [of_stderr writeString: @"\r"]; - [of_stderr writeLine: OF_LOCALIZED( + [OFStdErr writeString: @"\r"]; + [OFStdErr writeLine: OF_LOCALIZED( @"failed_to_open_file", @"Failed to open file %[file]: %[error]", @"file", e.path, @"error", error)]; _exitStatus = 1; } break; default: - help(of_stderr, true, 1); + help(OFStdErr, true, 1); break; } [OFApplication terminateWithStatus: _exitStatus]; } - (id )openArchiveWithPath: (OFString *)path type: (OFString *)type mode: (char)mode - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding { OFString *modeString, *fileModeString; OFStream *file = nil; id archive = nil; @@ -500,30 +520,29 @@ if ([path isEqual: @"-"]) { switch (mode) { case 'a': case 'c': - file = of_stdout; + file = OFStdOut; break; case 'l': case 'p': case 'x': - file = of_stdin; + file = OFStdIn; break; default: @throw [OFInvalidArgumentException exception]; } } else { @try { - file = [OFFile fileWithPath: path - mode: fileModeString]; + file = [OFFile fileWithPath: path mode: fileModeString]; } @catch (OFOpenItemFailedException *e) { OFString *error = [OFString stringWithCString: strerror(e.errNo) encoding: [OFLocale encoding]]; - [of_stderr writeString: @"\r"]; - [of_stderr writeLine: OF_LOCALIZED( + [OFStdErr writeString: @"\r"]; + [OFStdErr writeLine: OF_LOCALIZED( @"failed_to_open_file", @"Failed to open file %[file]: %[error]", @"file", e.path, @"error", error)]; [OFApplication terminateWithStatus: 1]; @@ -568,11 +587,11 @@ } else if ([type isEqual: @"zip"]) archive = [ZIPArchive archiveWithStream: file mode: modeString encoding: encoding]; else { - [of_stderr writeLine: OF_LOCALIZED( + [OFStdErr writeLine: OF_LOCALIZED( @"unknown_archive_type", @"Unknown archive type: %[type]", @"type", type)]; goto error; } @@ -586,26 +605,26 @@ @throw e; } @catch (OFReadFailedException *e) { OFString *error = [OFString stringWithCString: strerror(e.errNo) encoding: [OFLocale encoding]]; - [of_stderr writeLine: OF_LOCALIZED(@"failed_to_read_file", + [OFStdErr writeLine: OF_LOCALIZED(@"failed_to_read_file", @"Failed to read file %[file]: %[error]", @"file", path, @"error", error)]; goto error; } @catch (OFSeekFailedException *e) { OFString *error = [OFString stringWithCString: strerror(e.errNo) encoding: [OFLocale encoding]]; - [of_stderr writeLine: OF_LOCALIZED(@"failed_to_seek_in_file", + [OFStdErr writeLine: OF_LOCALIZED(@"failed_to_seek_in_file", @"Failed to seek in file %[file]: %[error]", @"file", path, @"error", error)]; goto error; } @catch (OFInvalidFormatException *e) { - [of_stderr writeLine: OF_LOCALIZED( + [OFStdErr writeLine: OF_LOCALIZED( @"file_is_not_a_valid_archive", @"File %[file] is not a valid archive!", @"file", path)]; goto error; } @@ -635,28 +654,28 @@ ![[OFFileManager defaultManager] fileExistsAtPath: outFileName]) return true; if (_overwrite == -1) { if (_outputLevel >= 0) { - [of_stdout writeString: @" "]; - [of_stdout writeLine: + [OFStdOut writeString: @" "]; + [OFStdOut writeLine: OF_LOCALIZED(@"file_skipped", @"skipped")]; } return false; } do { - [of_stderr writeString: @"\r"]; - [of_stderr writeString: OF_LOCALIZED(@"ask_overwrite", + [OFStdErr writeString: @"\r"]; + [OFStdErr writeString: OF_LOCALIZED(@"ask_overwrite", @"Overwrite %[file]? [ynAN?]", @"file", fileName)]; - [of_stderr writeString: @" "]; + [OFStdErr writeString: @" "]; - line = [of_stdin readLine]; + line = [OFStdIn readLine]; if ([line isEqual: @"?"]) - [of_stderr writeLine: OF_LOCALIZED( + [OFStdErr writeLine: OF_LOCALIZED( @"ask_overwrite_help", @" y: yes\n" @" n: no\n" @" A: always\n" @" N: never")]; @@ -668,19 +687,19 @@ else if ([line isEqual: @"N"]) _overwrite = -1; if ([line isEqual: @"n"] || [line isEqual: @"N"]) { if (_outputLevel >= 0) - [of_stdout writeLine: OF_LOCALIZED(@"skipping_file", + [OFStdOut writeLine: OF_LOCALIZED(@"skipping_file", @"Skipping %[file]...", @"file", fileName)]; return false; } if (_outputLevel >= 0) - [of_stdout writeString: OF_LOCALIZED(@"extracting_file", + [OFStdOut writeString: OF_LOCALIZED(@"extracting_file", @"Extracting %[file]...", @"file", fileName)]; return true; } @@ -687,37 +706,35 @@ - (ssize_t)copyBlockFromStream: (OFStream *)input toStream: (OFStream *)output fileName: (OFString *)fileName { - char buffer[BUFFER_SIZE]; + char buffer[bufferSize]; size_t length; @try { - length = [input readIntoBuffer: buffer - length: BUFFER_SIZE]; + length = [input readIntoBuffer: buffer length: bufferSize]; } @catch (OFReadFailedException *e) { OFString *error = [OFString stringWithCString: strerror(e.errNo) encoding: [OFLocale encoding]]; - [of_stdout writeString: @"\r"]; - [of_stderr writeLine: OF_LOCALIZED(@"failed_to_read_file", + [OFStdOut writeString: @"\r"]; + [OFStdErr writeLine: OF_LOCALIZED(@"failed_to_read_file", @"Failed to read file %[file]: %[error]", @"file", fileName, @"error", error)]; return -1; } @try { - [output writeBuffer: buffer - length: length]; + [output writeBuffer: buffer length: length]; } @catch (OFWriteFailedException *e) { OFString *error = [OFString stringWithCString: strerror(e.errNo) encoding: [OFLocale encoding]]; - [of_stdout writeString: @"\r"]; - [of_stderr writeLine: OF_LOCALIZED(@"failed_to_write_file", + [OFStdOut writeString: @"\r"]; + [OFStdErr writeLine: OF_LOCALIZED(@"failed_to_write_file", @"Failed to write file %[file]: %[error]", @"file", fileName, @"error", error)]; return -1; } Index: utils/ofarc/TarArchive.h ================================================================== --- utils/ofarc/TarArchive.h +++ utils/ofarc/TarArchive.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: utils/ofarc/TarArchive.m ================================================================== --- utils/ofarc/TarArchive.m +++ utils/ofarc/TarArchive.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -34,13 +32,13 @@ static void setPermissions(OFString *path, OFTarArchiveEntry *entry) { #ifdef OF_FILE_MANAGER_SUPPORTS_PERMISSIONS OFNumber *mode = [OFNumber numberWithUnsignedShort: entry.mode & 0777]; - of_file_attributes_t attributes = [OFDictionary + OFFileAttributes attributes = [OFDictionary dictionaryWithObject: mode - forKey: of_file_attribute_key_posix_permissions]; + forKey: OFFilePOSIXPermissions]; [[OFFileManager defaultManager] setAttributes: attributes ofItemAtPath: path]; #endif } @@ -47,18 +45,18 @@ static void setModificationDate(OFString *path, OFTarArchiveEntry *entry) { OFDate *modificationDate = entry.modificationDate; - of_file_attributes_t attributes; + OFFileAttributes attributes; if (modificationDate == nil) return; attributes = [OFDictionary dictionaryWithObject: modificationDate - forKey: of_file_attribute_key_modification_date]; + forKey: OFFileModificationDate]; [[OFFileManager defaultManager] setAttributes: attributes ofItemAtPath: path]; } @implementation TarArchive @@ -68,28 +66,28 @@ app = (OFArc *)[OFApplication sharedApplication].delegate; } + (instancetype)archiveWithStream: (OF_KINDOF(OFStream *))stream mode: (OFString *)mode - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding { return [[[self alloc] initWithStream: stream mode: mode encoding: encoding] autorelease]; } - (instancetype)initWithStream: (OF_KINDOF(OFStream *))stream mode: (OFString *)mode - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding { self = [super init]; @try { _archive = [[OFTarArchive alloc] initWithStream: stream mode: mode]; - if (encoding != OF_STRING_ENCODING_AUTODETECT) + if (encoding != OFStringEncodingAutodetect) _archive.encoding = encoding; } @catch (id e) { [self release]; @throw e; } @@ -109,11 +107,11 @@ OFTarArchiveEntry *entry; while ((entry = [_archive nextEntry]) != nil) { void *pool = objc_autoreleasePoolPush(); - [of_stdout writeLine: entry.fileName]; + [OFStdOut writeLine: entry.fileName]; if (app->_outputLevel >= 1) { OFString *date = [entry.modificationDate localDateStringWithFormat: @"%Y-%m-%d %H:%M:%S"]; OFString *size = [OFString stringWithFormat: @@ -123,143 +121,143 @@ OFString *UID = [OFString stringWithFormat: @"%u", entry.UID]; OFString *GID = [OFString stringWithFormat: @"%u", entry.GID]; - [of_stdout writeString: @"\t"]; - [of_stdout writeLine: OF_LOCALIZED(@"list_size", + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED(@"list_size", @"[" @" 'Size: '," @" [" @" {'size == 1': '1 byte'}," @" {'': '%[size] bytes'}" @" ]" @"]".objectByParsingJSON, @"size", size)]; - [of_stdout writeString: @"\t"]; - [of_stdout writeLine: OF_LOCALIZED(@"list_mode", + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED(@"list_mode", @"Mode: %[mode]", @"mode", mode)]; - [of_stdout writeString: @"\t"]; - [of_stdout writeLine: OF_LOCALIZED(@"list_uid", + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED(@"list_uid", @"UID: %[uid]", @"uid", UID)]; - [of_stdout writeString: @"\t"]; - [of_stdout writeLine: OF_LOCALIZED(@"list_gid", + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED(@"list_gid", @"GID: %[gid]", @"gid", GID)]; if (entry.owner != nil) { - [of_stdout writeString: @"\t"]; - [of_stdout writeLine: OF_LOCALIZED( + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED( @"list_owner", @"Owner: %[owner]", @"owner", entry.owner)]; } if (entry.group != nil) { - [of_stdout writeString: @"\t"]; - [of_stdout writeLine: OF_LOCALIZED( + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED( @"list_group", @"Group: %[group]", @"group", entry.group)]; } - [of_stdout writeString: @"\t"]; - [of_stdout writeLine: OF_LOCALIZED( + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED( @"list_modification_date", @"Modification date: %[date]", @"date", date)]; } if (app->_outputLevel >= 2) { - [of_stdout writeString: @"\t"]; - - switch (entry.type) { - case OF_TAR_ARCHIVE_ENTRY_TYPE_FILE: - [of_stdout writeLine: OF_LOCALIZED( - @"list_type_normal", - @"Type: Normal file")]; - break; - case OF_TAR_ARCHIVE_ENTRY_TYPE_LINK: - [of_stdout writeLine: OF_LOCALIZED( - @"list_type_hardlink", - @"Type: Hard link")]; - [of_stdout writeString: @"\t"]; - [of_stdout writeLine: OF_LOCALIZED( - @"list_link_target", - @"Target file name: %[target]", - @"target", entry.targetFileName)]; - break; - case OF_TAR_ARCHIVE_ENTRY_TYPE_SYMLINK: - [of_stdout writeLine: OF_LOCALIZED( - @"list_type_symlink", - @"Type: Symbolic link")]; - [of_stdout writeString: @"\t"]; - [of_stdout writeLine: OF_LOCALIZED( - @"list_link_target", - @"Target file name: %[target]", - @"target", entry.targetFileName)]; - break; - case OF_TAR_ARCHIVE_ENTRY_TYPE_CHARACTER_DEVICE: { - OFString *majorString = [OFString - stringWithFormat: @"%d", entry.deviceMajor]; - OFString *minorString = [OFString - stringWithFormat: @"%d", entry.deviceMinor]; - - [of_stdout writeLine: OF_LOCALIZED( - @"list_type_character_device", - @"Type: Character device")]; - [of_stdout writeString: @"\t"]; - [of_stdout writeLine: OF_LOCALIZED( - @"list_device_major", - @"Device major: %[major]", - @"major", majorString)]; - [of_stdout writeString: @"\t"]; - [of_stdout writeLine: OF_LOCALIZED( - @"list_device_minor", - @"Device minor: %[minor]", - @"minor", minorString)]; - break; - } - case OF_TAR_ARCHIVE_ENTRY_TYPE_BLOCK_DEVICE: { - OFString *majorString = [OFString - stringWithFormat: @"%d", entry.deviceMajor]; - OFString *minorString = [OFString - stringWithFormat: @"%d", entry.deviceMinor]; - - [of_stdout writeLine: OF_LOCALIZED( - @"list_type_block_device", - @"Type: Block device")]; - [of_stdout writeString: @"\t"]; - [of_stdout writeLine: OF_LOCALIZED( - @"list_device_major", - @"Device major: %[major]", - @"major", majorString)]; - [of_stdout writeString: @"\t"]; - [of_stdout writeLine: OF_LOCALIZED( - @"list_device_minor", - @"Device minor: %[minor]", - @"minor", minorString)]; - break; - } - case OF_TAR_ARCHIVE_ENTRY_TYPE_DIRECTORY: - [of_stdout writeLine: OF_LOCALIZED( - @"list_type_directory", - @"Type: Directory")]; - break; - case OF_TAR_ARCHIVE_ENTRY_TYPE_FIFO: - [of_stdout writeLine: OF_LOCALIZED( - @"list_type_fifo", - @"Type: FIFO")]; - break; - case OF_TAR_ARCHIVE_ENTRY_TYPE_CONTIGUOUS_FILE: - [of_stdout writeLine: OF_LOCALIZED( - @"list_type_contiguous_file", - @"Type: Contiguous file")]; - break; - default: - [of_stdout writeLine: OF_LOCALIZED( + [OFStdOut writeString: @"\t"]; + + switch (entry.type) { + case OFTarArchiveEntryTypeFile: + [OFStdOut writeLine: OF_LOCALIZED( + @"list_type_normal", + @"Type: Normal file")]; + break; + case OFTarArchiveEntryTypeLink: + [OFStdOut writeLine: OF_LOCALIZED( + @"list_type_hardlink", + @"Type: Hard link")]; + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED( + @"list_link_target", + @"Target file name: %[target]", + @"target", entry.targetFileName)]; + break; + case OFTarArchiveEntryTypeSymlink: + [OFStdOut writeLine: OF_LOCALIZED( + @"list_type_symlink", + @"Type: Symbolic link")]; + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED( + @"list_link_target", + @"Target file name: %[target]", + @"target", entry.targetFileName)]; + break; + case OFTarArchiveEntryTypeCharacterDevice: { + OFString *majorString = [OFString + stringWithFormat: @"%d", entry.deviceMajor]; + OFString *minorString = [OFString + stringWithFormat: @"%d", entry.deviceMinor]; + + [OFStdOut writeLine: OF_LOCALIZED( + @"list_type_character_device", + @"Type: Character device")]; + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED( + @"list_device_major", + @"Device major: %[major]", + @"major", majorString)]; + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED( + @"list_device_minor", + @"Device minor: %[minor]", + @"minor", minorString)]; + break; + } + case OFTarArchiveEntryTypeBlockDevice: { + OFString *majorString = [OFString + stringWithFormat: @"%d", entry.deviceMajor]; + OFString *minorString = [OFString + stringWithFormat: @"%d", entry.deviceMinor]; + + [OFStdOut writeLine: OF_LOCALIZED( + @"list_type_block_device", + @"Type: Block device")]; + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED( + @"list_device_major", + @"Device major: %[major]", + @"major", majorString)]; + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED( + @"list_device_minor", + @"Device minor: %[minor]", + @"minor", minorString)]; + break; + } + case OFTarArchiveEntryTypeDirectory: + [OFStdOut writeLine: OF_LOCALIZED( + @"list_type_directory", + @"Type: Directory")]; + break; + case OFTarArchiveEntryTypeFIFO: + [OFStdOut writeLine: OF_LOCALIZED( + @"list_type_fifo", + @"Type: FIFO")]; + break; + case OFTarArchiveEntryTypeContiguousFile: + [OFStdOut writeLine: OF_LOCALIZED( + @"list_type_contiguous_file", + @"Type: Contiguous file")]; + break; + default: + [OFStdOut writeLine: OF_LOCALIZED( @"list_type_unknown", @"Type: Unknown")]; break; } } @@ -277,24 +275,24 @@ OFTarArchiveEntry *entry; while ((entry = [_archive nextEntry]) != nil) { void *pool = objc_autoreleasePoolPush(); OFString *fileName = entry.fileName; - of_tar_archive_entry_type_t type = entry.type; + OFTarArchiveEntryType type = entry.type; OFString *outFileName, *directory; OFFile *output; OFStream *stream; uint64_t written = 0, size = entry.size; int8_t percent = -1, newPercent; if (!all && ![files containsObject: fileName]) continue; - if (type != OF_TAR_ARCHIVE_ENTRY_TYPE_FILE && - type != OF_TAR_ARCHIVE_ENTRY_TYPE_DIRECTORY) { + if (type != OFTarArchiveEntryTypeFile && + type != OFTarArchiveEntryTypeDirectory) { if (app->_outputLevel >= 0) - [of_stdout writeLine: OF_LOCALIZED( + [OFStdOut writeLine: OF_LOCALIZED( @"skipping_file", @"Skipping %[file]...", @"file", fileName)]; continue; } @@ -301,35 +299,35 @@ [missing removeObject: fileName]; outFileName = [app safeLocalPathForPath: fileName]; if (outFileName == nil) { - [of_stderr writeLine: OF_LOCALIZED( + [OFStdErr writeLine: OF_LOCALIZED( @"refusing_to_extract_file", @"Refusing to extract %[file]!", @"file", fileName)]; app->_exitStatus = 1; goto outer_loop_end; } if (app->_outputLevel >= 0) - [of_stdout writeString: OF_LOCALIZED(@"extracting_file", + [OFStdOut writeString: OF_LOCALIZED(@"extracting_file", @"Extracting %[file]...", @"file", fileName)]; - if (type == OF_TAR_ARCHIVE_ENTRY_TYPE_DIRECTORY || - (type == OF_TAR_ARCHIVE_ENTRY_TYPE_FILE && + if (type == OFTarArchiveEntryTypeDirectory || + (type == OFTarArchiveEntryTypeFile && [fileName hasSuffix: @"/"])) { [fileManager createDirectoryAtPath: outFileName createParents: true]; setPermissions(outFileName, entry); setModificationDate(outFileName, entry); if (app->_outputLevel >= 0) { - [of_stdout writeString: @"\r"]; - [of_stdout writeLine: OF_LOCALIZED( + [OFStdOut writeString: @"\r"]; + [OFStdOut writeLine: OF_LOCALIZED( @"extracting_file_done", @"Extracting %[file]... done", @"file", fileName)]; } @@ -339,17 +337,15 @@ directory = outFileName.stringByDeletingLastPathComponent; if (![fileManager directoryExistsAtPath: directory]) [fileManager createDirectoryAtPath: directory createParents: true]; - if (![app shouldExtractFile: fileName - outFileName: outFileName]) + if (![app shouldExtractFile: fileName outFileName: outFileName]) goto outer_loop_end; stream = [_archive streamForReadingCurrentEntry]; - output = [OFFile fileWithPath: outFileName - mode: @"w"]; + output = [OFFile fileWithPath: outFileName mode: @"w"]; setPermissions(outFileName, entry); while (!stream.atEndOfStream) { ssize_t length = [app copyBlockFromStream: stream toStream: output @@ -369,12 +365,12 @@ percent = newPercent; percentString = [OFString stringWithFormat: @"%3u", percent]; - [of_stdout writeString: @"\r"]; - [of_stdout writeString: OF_LOCALIZED( + [OFStdOut writeString: @"\r"]; + [OFStdOut writeString: OF_LOCALIZED( @"extracting_file_percent", @"Extracting %[file]... %[percent]%", @"file", fileName, @"percent", percentString)]; } @@ -382,12 +378,12 @@ [output close]; setModificationDate(outFileName, entry); if (app->_outputLevel >= 0) { - [of_stdout writeString: @"\r"]; - [of_stdout writeLine: OF_LOCALIZED( + [OFStdOut writeString: @"\r"]; + [OFStdOut writeLine: OF_LOCALIZED( @"extracting_file_done", @"Extracting %[file]... done", @"file", fileName)]; } @@ -395,11 +391,11 @@ objc_autoreleasePoolPop(pool); } if (missing.count > 0) { for (OFString *file in missing) - [of_stderr writeLine: OF_LOCALIZED( + [OFStdErr writeLine: OF_LOCALIZED( @"file_not_in_archive", @"File %[file] is not in the archive!", @"file", file)]; app->_exitStatus = 1; @@ -410,11 +406,11 @@ { OFMutableSet *files; OFTarArchiveEntry *entry; if (files_.count < 1) { - [of_stderr writeLine: OF_LOCALIZED(@"print_no_file_specified", + [OFStdErr writeLine: OF_LOCALIZED(@"print_no_file_specified", @"Need one or more files to print!")]; app->_exitStatus = 1; return; } @@ -429,11 +425,11 @@ stream = [_archive streamForReadingCurrentEntry]; while (!stream.atEndOfStream) { ssize_t length = [app copyBlockFromStream: stream - toStream: of_stdout + toStream: OFStdOut fileName: fileName]; if (length < 0) { app->_exitStatus = 1; return; @@ -446,11 +442,11 @@ if (files.count == 0) break; } for (OFString *file in files) { - [of_stderr writeLine: OF_LOCALIZED(@"file_not_in_archive", + [OFStdErr writeLine: OF_LOCALIZED(@"file_not_in_archive", @"File %[file] is not in the archive!", @"file", file)]; app->_exitStatus = 1; } } @@ -458,25 +454,25 @@ - (void)addFiles: (OFArray OF_GENERIC(OFString *) *)files { OFFileManager *fileManager = [OFFileManager defaultManager]; if (files.count < 1) { - [of_stderr writeLine: OF_LOCALIZED(@"add_no_file_specified", + [OFStdErr writeLine: OF_LOCALIZED(@"add_no_file_specified", @"Need one or more files to add!")]; app->_exitStatus = 1; return; } for (OFString *fileName in files) { void *pool = objc_autoreleasePoolPush(); - of_file_attributes_t attributes; - of_file_type_t type; + OFFileAttributes attributes; + OFFileAttributeType type; OFMutableTarArchiveEntry *entry; OFStream *output; if (app->_outputLevel >= 0) - [of_stdout writeString: OF_LOCALIZED(@"adding_file", + [OFStdOut writeString: OF_LOCALIZED(@"adding_file", @"Adding %[file]...", @"file", fileName)]; attributes = [fileManager attributesOfItemAtPath: fileName]; type = attributes.fileType; @@ -487,33 +483,33 @@ #endif entry.size = attributes.fileSize; entry.modificationDate = attributes.fileModificationDate; #ifdef OF_FILE_MANAGER_SUPPORTS_OWNER - entry.UID = attributes.filePOSIXUID; - entry.GID = attributes.filePOSIXGID; - entry.owner = attributes.fileOwner; - entry.group = attributes.fileGroup; + entry.UID = attributes.fileOwnerAccountID; + entry.GID = attributes.fileGroupOwnerAccountID; + entry.owner = attributes.fileOwnerAccountName; + entry.group = attributes.fileGroupOwnerAccountName; #endif - if ([type isEqual: of_file_type_regular]) - entry.type = OF_TAR_ARCHIVE_ENTRY_TYPE_FILE; - else if ([type isEqual: of_file_type_directory]) { - entry.type = OF_TAR_ARCHIVE_ENTRY_TYPE_DIRECTORY; + if ([type isEqual: OFFileTypeRegular]) + entry.type = OFTarArchiveEntryTypeFile; + else if ([type isEqual: OFFileTypeDirectory]) { + entry.type = OFTarArchiveEntryTypeDirectory; entry.size = 0; - } else if ([type isEqual: of_file_type_symbolic_link]) { - entry.type = OF_TAR_ARCHIVE_ENTRY_TYPE_SYMLINK; + } else if ([type isEqual: OFFileTypeSymbolicLink]) { + entry.type = OFTarArchiveEntryTypeSymlink; entry.targetFileName = attributes.fileSymbolicLinkDestination; entry.size = 0; } [entry makeImmutable]; output = [_archive streamForWritingEntry: entry]; - if (entry.type == OF_TAR_ARCHIVE_ENTRY_TYPE_FILE) { + if (entry.type == OFTarArchiveEntryTypeFile) { uint64_t written = 0, size = entry.size; int8_t percent = -1, newPercent; OFFile *input = [OFFile fileWithPath: fileName mode: @"r"]; @@ -539,23 +535,23 @@ percent = newPercent; percentString = [OFString stringWithFormat: @"%3u", percent]; - [of_stdout writeString: @"\r"]; - [of_stdout writeString: OF_LOCALIZED( + [OFStdOut writeString: @"\r"]; + [OFStdOut writeString: OF_LOCALIZED( @"adding_file_percent", @"Adding %[file]... %[percent]%", @"file", fileName, @"percent", percentString)]; } } } if (app->_outputLevel >= 0) { - [of_stdout writeString: @"\r"]; - [of_stdout writeLine: OF_LOCALIZED( + [OFStdOut writeString: @"\r"]; + [OFStdOut writeLine: OF_LOCALIZED( @"adding_file_done", @"Adding %[file]... done", @"file", fileName)]; } Index: utils/ofarc/ZIPArchive.h ================================================================== --- utils/ofarc/ZIPArchive.h +++ utils/ofarc/ZIPArchive.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 Index: utils/ofarc/ZIPArchive.m ================================================================== --- utils/ofarc/ZIPArchive.m +++ utils/ofarc/ZIPArchive.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -41,18 +39,16 @@ static void setPermissions(OFString *path, OFZIPArchiveEntry *entry) { #ifdef OF_FILE_MANAGER_SUPPORTS_PERMISSIONS if ((entry.versionMadeBy >> 8) == - OF_ZIP_ARCHIVE_ENTRY_ATTR_COMPAT_UNIX) { + OFZIPArchiveEntryAttributeCompatibilityUNIX) { OFNumber *mode = [OFNumber numberWithUnsignedShort: (entry.versionSpecificAttributes >> 16) & 0777]; - of_file_attribute_key_t key = - of_file_attribute_key_posix_permissions; - of_file_attributes_t attributes = [OFDictionary + OFFileAttributes attributes = [OFDictionary dictionaryWithObject: mode - forKey: key]; + forKey: OFFilePOSIXPermissions]; [[OFFileManager defaultManager] setAttributes: attributes ofItemAtPath: path]; } #endif @@ -60,18 +56,18 @@ static void setModificationDate(OFString *path, OFZIPArchiveEntry *entry) { OFDate *modificationDate = entry.modificationDate; - of_file_attributes_t attributes; + OFFileAttributes attributes; if (modificationDate == nil) return; attributes = [OFDictionary dictionaryWithObject: modificationDate - forKey: of_file_attribute_key_modification_date]; + forKey: OFFileModificationDate]; [[OFFileManager defaultManager] setAttributes: attributes ofItemAtPath: path]; } @implementation ZIPArchive @@ -81,20 +77,20 @@ app = (OFArc *)[OFApplication sharedApplication].delegate; } + (instancetype)archiveWithStream: (OF_KINDOF(OFStream *))stream mode: (OFString *)mode - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding { return [[[self alloc] initWithStream: stream mode: mode encoding: encoding] autorelease]; } - (instancetype)initWithStream: (OF_KINDOF(OFStream *))stream mode: (OFString *)mode - encoding: (of_string_encoding_t)encoding + encoding: (OFStringEncoding)encoding { self = [super init]; @try { _archive = [[OFZIPArchive alloc] initWithStream: stream @@ -117,90 +113,91 @@ - (void)listFiles { for (OFZIPArchiveEntry *entry in _archive.entries) { void *pool = objc_autoreleasePoolPush(); - [of_stdout writeLine: entry.fileName]; + [OFStdOut writeLine: entry.fileName]; if (app->_outputLevel >= 1) { OFString *compressedSize = [OFString stringWithFormat: @"%" PRIu64, entry.compressedSize]; OFString *uncompressedSize = [OFString stringWithFormat: @"%" PRIu64, entry.uncompressedSize]; OFString *compressionMethod = - of_zip_archive_entry_compression_method_to_string( + OFZIPArchiveEntryCompressionMethodName( entry.compressionMethod); OFString *CRC32 = [OFString stringWithFormat: @"%08" PRIX32, entry.CRC32]; OFString *modificationDate = [entry.modificationDate localDateStringWithFormat: @"%Y-%m-%d %H:%M:%S"]; - [of_stdout writeString: @"\t"]; - [of_stdout writeLine: OF_LOCALIZED( + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED( @"list_compressed_size", @"[" @" 'Compressed: '," @" [" @" {'size == 1': '1 byte'}," @" {'': '%[size] bytes'}" @" ]" @"]".objectByParsingJSON, @"size", compressedSize)]; - [of_stdout writeString: @"\t"]; - [of_stdout writeLine: OF_LOCALIZED( + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED( @"list_uncompressed_size", @"[" @" 'Uncompressed: '," @" [" @" {'size == 1': '1 byte'}," @" {'': '%[size] bytes'}" @" ]" @"]".objectByParsingJSON, @"size", uncompressedSize)]; - [of_stdout writeString: @"\t"]; - [of_stdout writeLine: OF_LOCALIZED( + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED( @"list_compression_method", @"Compression method: %[method]", @"method", compressionMethod)]; - [of_stdout writeString: @"\t"]; - [of_stdout writeLine: OF_LOCALIZED(@"list_crc32", + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED(@"list_crc32", @"CRC32: %[crc32]", @"crc32", CRC32)]; - [of_stdout writeString: @"\t"]; - [of_stdout writeLine: OF_LOCALIZED( + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED( @"list_modification_date", @"Modification date: %[date]", @"date", modificationDate)]; if (app->_outputLevel >= 2) { uint16_t versionMadeBy = entry.versionMadeBy; + OFZIPArchiveEntryAttributeCompatibility UNIX = + OFZIPArchiveEntryAttributeCompatibilityUNIX; - [of_stdout writeString: @"\t"]; - [of_stdout writeLine: OF_LOCALIZED( + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED( @"list_version_made_by", @"Version made by: %[version]", @"version", - of_zip_archive_entry_version_to_string( + OFZIPArchiveEntryVersionToString( versionMadeBy))]; - [of_stdout writeString: @"\t"]; - [of_stdout writeLine: OF_LOCALIZED( + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED( @"list_min_version_needed", @"Minimum version needed: %[version]", @"version", - of_zip_archive_entry_version_to_string( + OFZIPArchiveEntryVersionToString( entry.minVersionNeeded))]; - if ((versionMadeBy >> 8) == - OF_ZIP_ARCHIVE_ENTRY_ATTR_COMPAT_UNIX) { + if ((versionMadeBy >> 8) == UNIX) { uint32_t mode = entry .versionSpecificAttributes >> 16; OFString *modeString = [OFString stringWithFormat: @"%06o", mode]; - [of_stdout writeString: @"\t"]; - [of_stdout writeLine: OF_LOCALIZED( + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED( @"list_mode", @"Mode: %[mode]", @"mode", modeString)]; } } @@ -207,29 +204,29 @@ if (app->_outputLevel >= 3) { OFString *GPBF = [OFString stringWithFormat: @"%04" PRIx16, entry.generalPurposeBitFlag]; - [of_stdout writeString: @"\t"]; - [of_stdout writeLine: OF_LOCALIZED( + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED( @"list_general_purpose_bit_flag", @"General purpose bit flag: %[gpbf]", @"gpbf", GPBF)]; if (entry.extraField != nil) { - [of_stdout writeString: @"\t"]; - [of_stdout writeLine: OF_LOCALIZED( + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED( @"list_extra_field", @"Extra field: %[extra]", @"extra", entry.extraField.description)]; } } if (entry.fileComment.length > 0) { - [of_stdout writeString: @"\t"]; - [of_stdout writeLine: OF_LOCALIZED( + [OFStdOut writeString: @"\t"]; + [OFStdOut writeLine: OF_LOCALIZED( @"list_comment", @"Comment: %[comment]", @"comment", entry.fileComment)]; } } @@ -259,21 +256,21 @@ [missing removeObject: fileName]; outFileName = [app safeLocalPathForPath: fileName]; if (outFileName == nil) { - [of_stderr writeLine: OF_LOCALIZED( + [OFStdErr writeLine: OF_LOCALIZED( @"refusing_to_extract_file", @"Refusing to extract %[file]!", @"file", fileName)]; app->_exitStatus = 1; goto outer_loop_end; } if (app->_outputLevel >= 0) - [of_stdout writeString: OF_LOCALIZED(@"extracting_file", + [OFStdOut writeString: OF_LOCALIZED(@"extracting_file", @"Extracting %[file]...", @"file", fileName)]; if ([fileName hasSuffix: @"/"]) { [fileManager createDirectoryAtPath: outFileName @@ -280,12 +277,12 @@ createParents: true]; setPermissions(outFileName, entry); setModificationDate(outFileName, entry); if (app->_outputLevel >= 0) { - [of_stdout writeString: @"\r"]; - [of_stdout writeLine: OF_LOCALIZED( + [OFStdOut writeString: @"\r"]; + [OFStdOut writeLine: OF_LOCALIZED( @"extracting_file_done", @"Extracting %[file]... done", @"file", fileName)]; } @@ -295,17 +292,15 @@ directory = outFileName.stringByDeletingLastPathComponent; if (![fileManager directoryExistsAtPath: directory]) [fileManager createDirectoryAtPath: directory createParents: true]; - if (![app shouldExtractFile: fileName - outFileName: outFileName]) + if (![app shouldExtractFile: fileName outFileName: outFileName]) goto outer_loop_end; stream = [_archive streamForReadingFile: fileName]; - output = [OFFile fileWithPath: outFileName - mode: @"w"]; + output = [OFFile fileWithPath: outFileName mode: @"w"]; setPermissions(outFileName, entry); while (!stream.atEndOfStream) { ssize_t length = [app copyBlockFromStream: stream toStream: output @@ -325,12 +320,12 @@ percent = newPercent; percentString = [OFString stringWithFormat: @"%3u", percent]; - [of_stdout writeString: @"\r"]; - [of_stdout writeString: OF_LOCALIZED( + [OFStdOut writeString: @"\r"]; + [OFStdOut writeString: OF_LOCALIZED( @"extracting_file_percent", @"Extracting %[file]... %[percent]%", @"file", fileName, @"percent", percentString)]; } @@ -338,12 +333,12 @@ [output close]; setModificationDate(outFileName, entry); if (app->_outputLevel >= 0) { - [of_stdout writeString: @"\r"]; - [of_stdout writeLine: OF_LOCALIZED( + [OFStdOut writeString: @"\r"]; + [OFStdOut writeLine: OF_LOCALIZED( @"extracting_file_done", @"Extracting %[file]... done", @"file", fileName)]; } @@ -351,11 +346,11 @@ objc_autoreleasePoolPop(pool); } if (missing.count > 0) { for (OFString *file in missing) - [of_stderr writeLine: OF_LOCALIZED( + [OFStdErr writeLine: OF_LOCALIZED( @"file_not_in_archive", @"File %[file] is not in the archive!", @"file", file)]; app->_exitStatus = 1; @@ -365,11 +360,11 @@ - (void)printFiles: (OFArray OF_GENERIC(OFString *) *)files { OFStream *stream; if (files.count < 1) { - [of_stderr writeLine: OF_LOCALIZED(@"print_no_file_specified", + [OFStdErr writeLine: OF_LOCALIZED(@"print_no_file_specified", @"Need one or more files to print!")]; app->_exitStatus = 1; return; } @@ -376,11 +371,11 @@ for (OFString *path in files) { @try { stream = [_archive streamForReadingFile: path]; } @catch (OFOpenItemFailedException *e) { if (e.errNo == ENOENT) { - [of_stderr writeLine: OF_LOCALIZED( + [OFStdErr writeLine: OF_LOCALIZED( @"file_not_in_archive", @"File %[file] is not in the archive!", @"file", e.path)]; app->_exitStatus = 1; continue; @@ -389,11 +384,11 @@ @throw e; } while (!stream.atEndOfStream) { ssize_t length = [app copyBlockFromStream: stream - toStream: of_stdout + toStream: OFStdOut fileName: path]; if (length < 0) { app->_exitStatus = 1; return; @@ -407,21 +402,21 @@ - (void)addFiles: (OFArray OF_GENERIC(OFString *) *)files { OFFileManager *fileManager = [OFFileManager defaultManager]; if (files.count < 1) { - [of_stderr writeLine: OF_LOCALIZED(@"add_no_file_specified", + [OFStdErr writeLine: OF_LOCALIZED(@"add_no_file_specified", @"Need one or more files to add!")]; app->_exitStatus = 1; return; } for (OFString *localFileName in files) { void *pool = objc_autoreleasePoolPush(); OFArray OF_GENERIC (OFString *) *components; OFString *fileName; - of_file_attributes_t attributes; + OFFileAttributes attributes; bool isDirectory = false; OFMutableZIPArchiveEntry *entry; unsigned long long size; OFStream *output; @@ -429,17 +424,17 @@ fileName = [components componentsJoinedByString: @"/"]; attributes = [fileManager attributesOfItemAtPath: localFileName]; - if ([attributes.fileType isEqual: of_file_type_directory]) { + if ([attributes.fileType isEqual: OFFileTypeDirectory]) { isDirectory = true; fileName = [fileName stringByAppendingString: @"/"]; } if (app->_outputLevel >= 0) - [of_stdout writeString: OF_LOCALIZED(@"adding_file", + [OFStdOut writeString: OF_LOCALIZED(@"adding_file", @"Adding %[file]...", @"file", fileName)]; entry = [OFMutableZIPArchiveEntry entryWithFileName: fileName]; @@ -449,11 +444,11 @@ entry.compressedSize = (int64_t)size; entry.uncompressedSize = (int64_t)size; entry.compressionMethod = - OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_NONE; + OFZIPArchiveEntryCompressionMethodNone; entry.modificationDate = attributes.fileModificationDate; [entry makeImmutable]; output = [_archive streamForWritingEntry: entry]; @@ -486,23 +481,23 @@ percent = newPercent; percentString = [OFString stringWithFormat: @"%3u", percent]; - [of_stdout writeString: @"\r"]; - [of_stdout writeString: OF_LOCALIZED( + [OFStdOut writeString: @"\r"]; + [OFStdOut writeString: OF_LOCALIZED( @"adding_file_percent", @"Adding %[file]... %[percent]%", @"file", fileName, @"percent", percentString)]; } } } if (app->_outputLevel >= 0) { - [of_stdout writeString: @"\r"]; - [of_stdout writeLine: OF_LOCALIZED( + [OFStdOut writeString: @"\r"]; + [OFStdOut writeLine: OF_LOCALIZED( @"adding_file_done", @"Adding %[file]... done", @"file", fileName)]; } Index: utils/ofdns/OFDNS.m ================================================================== --- utils/ofdns/OFDNS.m +++ utils/ofdns/OFDNS.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -35,11 +33,11 @@ OF_APPLICATION_DELEGATE(OFDNS) static void help(OFStream *stream, bool full, int status) { - [of_stderr writeLine: + [OFStdErr writeLine: OF_LOCALIZED(@"usage", @"Usage: %[prog] -[chst] domain1 [domain2 ...]", @"prog", [OFApplication programName])]; if (full) { @@ -67,13 +65,13 @@ exception: (id)exception { _inFlight--; if (exception == nil) - [of_stdout writeFormat: @"%@\n", response]; + [OFStdOut writeFormat: @"%@\n", response]; else { - [of_stderr writeLine: OF_LOCALIZED( + [OFStdErr writeLine: OF_LOCALIZED( @"failed_to_resolve", @"Failed to resolve: %[exception]", @"exception", exception)]; _errors++; } @@ -83,23 +81,23 @@ } - (void)applicationDidFinishLaunching { OFString *DNSClassString, *server; - const of_options_parser_option_t options[] = { + const OFOptionsParserOption options[] = { { 'c', @"class", 1, NULL, &DNSClassString }, { 'h', @"help", 0, NULL, NULL }, { 's', @"server", 1, NULL, &server }, { 't', @"type", 1, NULL, NULL }, { '\0', nil, 0, NULL, NULL } }; OFMutableArray OF_GENERIC(OFString *) *recordTypes; OFOptionsParser *optionsParser; - of_unichar_t option; + OFUnichar option; OFArray OF_GENERIC(OFString *) *remainingArguments; OFDNSResolver *resolver; - of_dns_class_t DNSClass; + OFDNSClass DNSClass; #ifdef OF_HAVE_FILES # ifndef OF_AMIGAOS [OFLocale addLanguageDirectory: @LANGUAGE_DIR]; # else @@ -111,11 +109,11 @@ OFSandbox *sandbox = [[OFSandbox alloc] init]; @try { sandbox.allowsStdIO = true; sandbox.allowsDNS = true; - [OFApplication activateSandbox: sandbox]; + [OFApplication of_activateSandbox: sandbox]; } @finally { [sandbox release]; } #endif @@ -126,25 +124,25 @@ switch (option) { case 't': [recordTypes addObject: optionsParser.argument]; break; case 'h': - help(of_stdout, true, 0); + help(OFStdOut, true, 0); break; case ':': if (optionsParser.lastLongOption != nil) - [of_stderr writeLine: OF_LOCALIZED( + [OFStdErr writeLine: OF_LOCALIZED( @"long_option_required_argument", @"%[prog]: Option --%[opt] requires an " @"argument", @"prog", [OFApplication programName], @"opt", optionsParser.lastLongOption)]; else { OFString *optStr = [OFString stringWithFormat: @"%C", optionsParser.lastOption]; - [of_stderr writeLine: OF_LOCALIZED( + [OFStdErr writeLine: OF_LOCALIZED( @"option_requires_argument", @"%[prog]: Option -%[opt] requires an " @"argument", @"prog", [OFApplication programName], @"opt", optStr)]; @@ -152,20 +150,20 @@ [OFApplication terminateWithStatus: 1]; break; case '?': if (optionsParser.lastLongOption != nil) - [of_stderr writeLine: OF_LOCALIZED( + [OFStdErr writeLine: OF_LOCALIZED( @"unknown_long_option", @"%[prog]: Unknown option: --%[opt]", @"prog", [OFApplication programName], @"opt", optionsParser.lastLongOption)]; else { OFString *optStr = [OFString stringWithFormat: @"%C", optionsParser.lastOption]; - [of_stderr writeLine: OF_LOCALIZED( + [OFStdErr writeLine: OF_LOCALIZED( @"Unknown_option", @"%[prog]: Unknown option: -%[opt]", @"prog", [OFApplication programName], @"opt", optStr)]; } @@ -176,16 +174,15 @@ } remainingArguments = optionsParser.remainingArguments; if (remainingArguments.count < 1) - help(of_stderr, false, 1); + help(OFStdErr, false, 1); resolver = [OFDNSResolver resolver]; DNSClass = (DNSClassString != nil - ? of_dns_class_parse(DNSClassString) - : OF_DNS_CLASS_IN); + ? OFDNSClassParseName(DNSClassString) : OFDNSClassIN); if (recordTypes.count == 0) [recordTypes addObject: @"ALL"]; if (server != nil) { @@ -193,19 +190,18 @@ resolver.nameServers = [OFArray arrayWithObject: server]; } for (OFString *domainName in remainingArguments) { for (OFString *recordTypeString in recordTypes) { - of_dns_record_type_t recordType = - of_dns_record_type_parse(recordTypeString); + OFDNSRecordType recordType = + OFDNSRecordTypeParseName(recordTypeString); OFDNSQuery *query = [OFDNSQuery queryWithDomainName: domainName DNSClass: DNSClass recordType: recordType]; _inFlight++; - [resolver asyncPerformQuery: query - delegate: self]; + [resolver asyncPerformQuery: query delegate: self]; } } } @end Index: utils/ofhash/OFHash.m ================================================================== --- utils/ofhash/OFHash.m +++ utils/ofhash/OFHash.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -42,39 +40,42 @@ OF_APPLICATION_DELEGATE(OFHash) static void help(void) { - [of_stderr writeLine: OF_LOCALIZED(@"usage", - @"Usage: %[prog] [--md5|--ripemd160|--sha1|--sha224|--sha256|" - @"--sha384|--sha512] file1 [file2 ...]", + [OFStdErr writeLine: OF_LOCALIZED(@"usage", + @"Usage: %[prog] [--md5] [--ripemd160] [--sha1] [--sha224] " + @"[--sha256] [--sha384] [--sha512] file1 [file2 ...]", @"prog", [OFApplication programName])]; [OFApplication terminateWithStatus: 1]; } static void -printHash(OFString *algo, OFString *path, id hash) +printHash(OFString *algo, OFString *path, id hash) { - const unsigned char *digest = hash.digest; size_t digestSize = hash.digestSize; + const unsigned char *digest; + + [hash calculate]; + digest = hash.digest; - [of_stdout writeFormat: @"%@ ", algo]; + [OFStdOut writeFormat: @"%@ ", algo]; for (size_t i = 0; i < digestSize; i++) - [of_stdout writeFormat: @"%02x", digest[i]]; + [OFStdOut writeFormat: @"%02x", digest[i]]; - [of_stdout writeFormat: @" %@\n", path]; + [OFStdOut writeFormat: @" %@\n", path]; } @implementation OFHash - (void)applicationDidFinishLaunching { int exitStatus = 0; bool calculateMD5, calculateRIPEMD160, calculateSHA1, calculateSHA224; bool calculateSHA256, calculateSHA384, calculateSHA512; - const of_options_parser_option_t options[] = { + const OFOptionsParserOption options[] = { { '\0', @"md5", 0, &calculateMD5, NULL }, { '\0', @"ripemd160", 0, &calculateRIPEMD160, NULL }, { '\0', @"sha1", 0, &calculateSHA1, NULL }, { '\0', @"sha224", 0, &calculateSHA224, NULL }, { '\0', @"sha256", 0, &calculateSHA256, NULL }, @@ -82,11 +83,11 @@ { '\0', @"sha512", 0, &calculateSHA512, NULL }, { '\0', nil, 0, NULL, NULL } }; OFOptionsParser *optionsParser = [OFOptionsParser parserWithOptions: options]; - of_unichar_t option; + OFUnichar option; OFMD5Hash *MD5Hash = nil; OFRIPEMD160Hash *RIPEMD160Hash = nil; OFSHA1Hash *SHA1Hash = nil; OFSHA224Hash *SHA224Hash = nil; OFSHA256Hash *SHA256Hash = nil; @@ -101,19 +102,19 @@ while ((option = [optionsParser nextOption]) != '\0') { switch (option) { case '?': if (optionsParser.lastLongOption != nil) - [of_stderr writeLine: + [OFStdErr writeLine: OF_LOCALIZED(@"unknown_long_option", @"%[prog]: Unknown option: --%[opt]", @"prog", [OFApplication programName], @"opt", optionsParser.lastLongOption)]; else { OFString *optStr = [OFString stringWithFormat: @"%c", optionsParser.lastOption]; - [of_stderr writeLine: + [OFStdErr writeLine: OF_LOCALIZED(@"unknown_option", @"%[prog]: Unknown option: -%[opt]", @"prog", [OFApplication programName], @"opt", optStr)]; } @@ -129,17 +130,15 @@ sandbox.allowsStdIO = true; sandbox.allowsReadingFiles = true; sandbox.allowsUserDatabaseReading = true; for (OFString *path in optionsParser.remainingArguments) - [sandbox unveilPath: path - permissions: @"r"]; + [sandbox unveilPath: path permissions: @"r"]; + + [sandbox unveilPath: @LANGUAGE_DIR permissions: @"r"]; - [sandbox unveilPath: @LANGUAGE_DIR - permissions: @"r"]; - - [OFApplication activateSandbox: sandbox]; + [OFApplication of_activateSandbox: sandbox]; } @finally { [sandbox release]; } #endif @@ -150,46 +149,40 @@ if (optionsParser.remainingArguments.count < 1) help(); if (calculateMD5) - MD5Hash = [OFMD5Hash cryptoHashWithAllowsSwappableMemory: true]; + MD5Hash = [OFMD5Hash hashWithAllowsSwappableMemory: true]; if (calculateRIPEMD160) RIPEMD160Hash = - [OFRIPEMD160Hash cryptoHashWithAllowsSwappableMemory: true]; + [OFRIPEMD160Hash hashWithAllowsSwappableMemory: true]; if (calculateSHA1) - SHA1Hash = - [OFSHA1Hash cryptoHashWithAllowsSwappableMemory: true]; + SHA1Hash = [OFSHA1Hash hashWithAllowsSwappableMemory: true]; if (calculateSHA224) - SHA224Hash = - [OFSHA224Hash cryptoHashWithAllowsSwappableMemory: true]; + SHA224Hash = [OFSHA224Hash hashWithAllowsSwappableMemory: true]; if (calculateSHA256) - SHA256Hash = - [OFSHA256Hash cryptoHashWithAllowsSwappableMemory: true]; + SHA256Hash = [OFSHA256Hash hashWithAllowsSwappableMemory: true]; if (calculateSHA384) - SHA384Hash = - [OFSHA384Hash cryptoHashWithAllowsSwappableMemory: true]; + SHA384Hash = [OFSHA384Hash hashWithAllowsSwappableMemory: true]; if (calculateSHA512) - SHA512Hash = - [OFSHA512Hash cryptoHashWithAllowsSwappableMemory: true]; + SHA512Hash = [OFSHA512Hash hashWithAllowsSwappableMemory: true]; for (OFString *path in optionsParser.remainingArguments) { void *pool = objc_autoreleasePoolPush(); OFStream *file; if ([path isEqual: @"-"]) - file = of_stdin; + file = OFStdIn; else { @try { - file = [OFFile fileWithPath: path - mode: @"r"]; + file = [OFFile fileWithPath: path mode: @"r"]; } @catch (OFOpenItemFailedException *e) { OFString *error = [OFString stringWithCString: strerror(e.errNo) encoding: [OFLocale encoding]]; - [of_stderr writeLine: OF_LOCALIZED( + [OFStdErr writeLine: OF_LOCALIZED( @"failed_to_open_file", @"Failed to open file %[file]: %[error]", @"file", e.path, @"error", error)]; @@ -216,11 +209,11 @@ } @catch (OFReadFailedException *e) { OFString *error = [OFString stringWithCString: strerror(e.errNo) encoding: [OFLocale encoding]]; - [of_stderr writeLine: OF_LOCALIZED( + [OFStdErr writeLine: OF_LOCALIZED( @"failed_to_read_file", @"Failed to read %[file]: %[error]", @"file", path, @"error", error)]; Index: utils/ofhash/lang/de.json ================================================================== --- utils/ofhash/lang/de.json +++ utils/ofhash/lang/de.json @@ -1,9 +1,9 @@ { "usage": [ - "Benutzung: %[prog] [--md5|--ripemd160|--sha1|--sha224|--sha256|", - "--sha384|--sha512] datei1 [datei2 ...]" + "Benutzung: %[prog] [--md5] [--ripemd160] [--sha1] [--sha224] ", + "[--sha256] [--sha384] [--sha512] datei1 [datei2 ...]" ], "unknown_long_option": "%[prog]: Unbekannte Option: --%[opt]", "unknown_option": "%[prog]: Unbekannte Option: -%[opt]", "failed_to_open_file": "Fehler beim Öffnen der Datei %[file]: %[error]", "failed_to_read_file": "Fehler beim Lesen der Datei %[file]: %[error]" Index: utils/ofhttp/Makefile ================================================================== --- utils/ofhttp/Makefile +++ utils/ofhttp/Makefile @@ -13,12 +13,15 @@ ${PROG}: ${LIBOBJFW_DEP_LVL2} ${LIBOBJFWRT_DEP_LVL2} CPPFLAGS += -I../../src \ -I../../src/runtime \ -I../../src/exceptions \ + -I../../src/tls \ -I../.. \ - -DLANGUAGE_DIR=\"${datadir}/ofhttp/lang\" -LIBS := -L../../src -lobjfw \ + -DLANGUAGE_DIR='"${datadir}/ofhttp/lang"' \ + -DLIB_PREFIX='"${LIB_PREFIX}"' \ + -DLIB_SUFFIX='"${LIB_SUFFIX}"' +LIBS := -L../../src -L../../src/tls ${OFHTTP_LIBS} -lobjfw \ -L../../src/runtime -L../../src/runtime/linklib ${RUNTIME_LIBS} \ ${LIBS} LD = ${OBJC} LDFLAGS += ${LDFLAGS_RPATH} Index: utils/ofhttp/OFHTTP.m ================================================================== --- utils/ofhttp/OFHTTP.m +++ utils/ofhttp/OFHTTP.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -33,12 +31,16 @@ #endif #import "OFSandbox.h" #import "OFStdIOStream.h" #import "OFSystemInfo.h" #import "OFTCPSocket.h" -#import "OFTLSSocket.h" +#import "OFTLSStream.h" #import "OFURL.h" + +#ifdef HAVE_TLS_SUPPORT +# import "ObjFWTLS.h" +#endif #import "OFConnectionFailedException.h" #import "OFHTTPRequestFailedException.h" #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" @@ -64,12 +66,13 @@ size_t _URLIndex; int _errorCode; OFString *_outputPath, *_currentFileName; bool _continue, _force, _detectFileName, _detectFileNameRequest; bool _detectedFileName, _quiet, _verbose, _insecure, _ignoreStatus; + bool _useUnicode; OFStream *_body; - of_http_request_method_t _method; + OFHTTPRequestMethod _method; OFMutableDictionary *_clientHeaders; OFHTTPClient *_HTTPClient; char *_buffer; OFStream *_output; unsigned long long _received, _length, _resumedFrom; @@ -76,17 +79,25 @@ ProgressBar *_progressBar; } - (void)downloadNextURL; @end + +#ifdef HAVE_TLS_SUPPORT +void +_reference_to_ObjFWTLS(void) +{ + _ObjFWTLS_reference = 1; +} +#endif OF_APPLICATION_DELEGATE(OFHTTP) static void help(OFStream *stream, bool full, int status) { - [of_stderr writeLine: + [OFStdErr writeLine: OF_LOCALIZED(@"usage", @"Usage: %[prog] -[cehHmoOPqv] url1 [url2 ...]", @"prog", [OFApplication programName])]; if (full) { @@ -131,18 +142,18 @@ { void *pool; const char *UTF8String; size_t UTF8StringLength; enum { - DISPOSITION_TYPE, - DISPOSITION_TYPE_SEMICOLON, - DISPOSITION_PARAM_NAME_SKIP_SPACE, - DISPOSITION_PARAM_NAME, - DISPOSITION_PARAM_VALUE, - DISPOSITION_PARAM_QUOTED, - DISPOSITION_PARAM_UNQUOTED, - DISPOSITION_EXPECT_SEMICOLON + stateDispositionType, + stateDispositionTypeSemicolon, + stateDispositionParamNameSkipSpace, + stateDispositionParamName, + stateDispositionParamValue, + stateDispositionParamQuoted, + stateDispositionParamUnquoted, + stateDispositionExpectSemicolon } state; size_t last; OFString *type = nil, *paramName = nil, *paramValue; OFMutableDictionary *params; OFString *fileName; @@ -152,76 +163,76 @@ pool = objc_autoreleasePoolPush(); UTF8String = contentDisposition.UTF8String; UTF8StringLength = contentDisposition.UTF8StringLength; - state = DISPOSITION_TYPE; + state = stateDispositionType; params = [OFMutableDictionary dictionary]; last = 0; for (size_t i = 0; i < UTF8StringLength; i++) { switch (state) { - case DISPOSITION_TYPE: + case stateDispositionType: if (UTF8String[i] == ';' || UTF8String[i] == ' ') { type = [OFString stringWithUTF8String: UTF8String length: i]; state = (UTF8String[i] == ';' - ? DISPOSITION_PARAM_NAME_SKIP_SPACE - : DISPOSITION_TYPE_SEMICOLON); + ? stateDispositionParamNameSkipSpace + : stateDispositionTypeSemicolon); last = i + 1; } break; - case DISPOSITION_TYPE_SEMICOLON: + case stateDispositionTypeSemicolon: if (UTF8String[i] == ';') { - state = DISPOSITION_PARAM_NAME_SKIP_SPACE; + state = stateDispositionParamNameSkipSpace; last = i + 1; } else if (UTF8String[i] != ' ') { objc_autoreleasePoolPop(pool); return nil; } break; - case DISPOSITION_PARAM_NAME_SKIP_SPACE: + case stateDispositionParamNameSkipSpace: if (UTF8String[i] != ' ') { - state = DISPOSITION_PARAM_NAME; + state = stateDispositionParamName; last = i; i--; } break; - case DISPOSITION_PARAM_NAME: + case stateDispositionParamName: if (UTF8String[i] == '=') { paramName = [OFString stringWithUTF8String: UTF8String + last length: i - last]; - state = DISPOSITION_PARAM_VALUE; + state = stateDispositionParamValue; } break; - case DISPOSITION_PARAM_VALUE: + case stateDispositionParamValue: if (UTF8String[i] == '"') { - state = DISPOSITION_PARAM_QUOTED; + state = stateDispositionParamQuoted; last = i + 1; } else { - state = DISPOSITION_PARAM_UNQUOTED; + state = stateDispositionParamUnquoted; last = i; i--; } break; - case DISPOSITION_PARAM_QUOTED: + case stateDispositionParamQuoted: if (UTF8String[i] == '"') { paramValue = [OFString stringWithUTF8String: UTF8String + last length: i - last]; [params setObject: paramValue forKey: paramName.lowercaseString]; - state = DISPOSITION_EXPECT_SEMICOLON; + state = stateDispositionExpectSemicolon; } break; - case DISPOSITION_PARAM_UNQUOTED: + case stateDispositionParamUnquoted: if (UTF8String[i] <= 31 || UTF8String[i] >= 127) return nil; switch (UTF8String[i]) { case ' ': case '"': case '(': case ')': case ',': @@ -235,34 +246,34 @@ length: i - last]; [params setObject: paramValue forKey: paramName.lowercaseString]; - state = DISPOSITION_PARAM_NAME_SKIP_SPACE; + state = stateDispositionParamNameSkipSpace; break; } break; - case DISPOSITION_EXPECT_SEMICOLON: + case stateDispositionExpectSemicolon: if (UTF8String[i] == ';') { - state = DISPOSITION_PARAM_NAME_SKIP_SPACE; + state = stateDispositionParamNameSkipSpace; last = i + 1; } else if (UTF8String[i] != ' ') { objc_autoreleasePoolPop(pool); return nil; } break; } } - if (state == DISPOSITION_PARAM_UNQUOTED) { + if (state == stateDispositionParamUnquoted) { paramValue = [OFString stringWithUTF8String: UTF8String + last length: UTF8StringLength - last]; [params setObject: paramValue forKey: paramName.lowercaseString]; - } else if (state != DISPOSITION_EXPECT_SEMICOLON) { + } else if (state != stateDispositionExpectSemicolon) { objc_autoreleasePoolPop(pool); return nil; } if (![type isEqual: @"attachment"] || @@ -277,36 +288,25 @@ objc_autoreleasePoolPop(pool); return [fileName autorelease]; } @implementation OFHTTP -#ifdef OF_HAVE_PLUGINS -+ (void)initialize -{ - if (self != [OFHTTP class]) - return; - - /* Opportunistically try loading ObjOpenSSL and ignore any errors. */ - of_dlopen(@"objopenssl", OF_RTLD_LAZY); -} -#endif - - (instancetype)init { self = [super init]; @try { - _method = OF_HTTP_REQUEST_METHOD_GET; + _method = OFHTTPRequestMethodGet; _clientHeaders = [[OFMutableDictionary alloc] initWithObject: @"OFHTTP" forKey: @"User-Agent"]; _HTTPClient = [[OFHTTPClient alloc] init]; _HTTPClient.delegate = self; - _buffer = [self allocMemoryWithSize: [OFSystemInfo pageSize]]; + _buffer = OFAllocMemory(1, [OFSystemInfo pageSize]); } @catch (id e) { [self release]; @throw e; } @@ -316,12 +316,12 @@ - (void)addHeader: (OFString *)header { size_t pos = [header rangeOfString: @":"].location; OFString *name, *value; - if (pos == OF_NOT_FOUND) { - [of_stderr writeLine: OF_LOCALIZED(@"invalid_input_header", + if (pos == OFNotFound) { + [OFStdErr writeLine: OF_LOCALIZED(@"invalid_input_header", @"%[prog]: Headers must to be in format name:value!", @"prog", [OFApplication programName])]; [OFApplication terminateWithStatus: 1]; } @@ -329,12 +329,11 @@ .stringByDeletingEnclosingWhitespaces; value = [header substringFromIndex: pos + 1] .stringByDeletingEnclosingWhitespaces; - [_clientHeaders setObject: value - forKey: name]; + [_clientHeaders setObject: value forKey: name]; } - (void)setBody: (OFString *)path { OFString *contentLength = nil; @@ -341,14 +340,13 @@ [_body release]; _body = nil; if ([path isEqual: @"-"]) - _body = [of_stdin copy]; + _body = [OFStdIn copy]; else { - _body = [[OFFile alloc] initWithPath: path - mode: @"r"]; + _body = [[OFFile alloc] initWithPath: path mode: @"r"]; @try { unsigned long long fileSize = [[OFFileManager defaultManager] attributesOfItemAtPath: path].fileSize; @@ -371,13 +369,13 @@ void *pool = objc_autoreleasePoolPush(); method = method.uppercaseString; @try { - _method = of_http_request_method_from_string(method); + _method = OFHTTPRequestMethodParseName(method); } @catch (OFInvalidArgumentException *e) { - [of_stderr writeLine: OF_LOCALIZED(@"invalid_input_method", + [OFStdErr writeLine: OF_LOCALIZED(@"invalid_input_method", @"%[prog]: Invalid request method %[method]!", @"prog", [OFApplication programName], @"method", method)]; [OFApplication terminateWithStatus: 1]; } @@ -388,15 +386,15 @@ - (void)setProxy: (OFString *)proxy { @try { size_t pos = [proxy rangeOfString: @":" - options: OF_STRING_SEARCH_BACKWARDS].location; + options: OFStringSearchBackwards].location; OFString *host; unsigned long long port; - if (pos == OF_NOT_FOUND) + if (pos == OFNotFound) @throw [OFInvalidFormatException exception]; host = [proxy substringToIndex: pos]; port = [proxy substringFromIndex: pos + 1] .unsignedLongLongValue; @@ -405,21 +403,21 @@ @throw [OFOutOfRangeException exception]; [OFTCPSocket setSOCKS5Host: host]; [OFTCPSocket setSOCKS5Port: (uint16_t)port]; } @catch (OFInvalidFormatException *e) { - [of_stderr writeLine: OF_LOCALIZED(@"invalid_input_proxy", + [OFStdErr writeLine: OF_LOCALIZED(@"invalid_input_proxy", @"%[prog]: Proxy must to be in format host:port!", @"prog", [OFApplication programName])]; [OFApplication terminateWithStatus: 1]; } } - (void)applicationDidFinishLaunching { OFString *outputPath; - const of_options_parser_option_t options[] = { + const OFOptionsParserOption options[] = { { 'b', @"body", 1, NULL, NULL }, { 'c', @"continue", 0, &_continue, NULL }, { 'f', @"force", 0, &_force, NULL }, { 'h', @"help", 0, NULL, NULL }, { 'H', @"header", 1, NULL, NULL }, @@ -432,11 +430,11 @@ { '\0', @"insecure", 0, &_insecure, NULL }, { '\0', @"ignore-status", 0, &_ignoreStatus, NULL }, { '\0', nil, 0, NULL, NULL } }; OFOptionsParser *optionsParser; - of_unichar_t option; + OFUnichar option; #ifdef OF_HAVE_SANDBOX OFSandbox *sandbox = [OFSandbox sandbox]; sandbox.allowsStdIO = true; sandbox.allowsReadingFiles = true; @@ -447,11 +445,11 @@ sandbox.allowsUserDatabaseReading = true; sandbox.allowsTTY = true; /* Dropped after parsing options */ sandbox.allowsUnveil = true; - [OFApplication activateSandbox: sandbox]; + [OFApplication of_activateSandbox: sandbox]; #endif #ifndef OF_AMIGAOS [OFLocale addLanguageDirectory: @LANGUAGE_DIR]; #else @@ -463,11 +461,11 @@ switch (option) { case 'b': [self setBody: optionsParser.argument]; break; case 'h': - help(of_stdout, true, 0); + help(OFStdOut, true, 0); break; case 'H': [self addHeader: optionsParser.argument]; break; case 'm': @@ -476,21 +474,21 @@ case 'P': [self setProxy: optionsParser.argument]; break; case ':': if (optionsParser.lastLongOption != nil) - [of_stderr writeLine: + [OFStdErr writeLine: OF_LOCALIZED(@"long_argument_missing", @"%[prog]: Argument for option --%[opt] " @"missing" @"prog", [OFApplication programName], @"opt", optionsParser.lastLongOption)]; else { OFString *optStr = [OFString stringWithFormat: @"%c", optionsParser.lastOption]; - [of_stderr writeLine: + [OFStdErr writeLine: OF_LOCALIZED(@"argument_missing", @"%[prog]: Argument for option -%[opt] " @"missing", @"prog", [OFApplication programName], @"opt", optStr)]; @@ -497,30 +495,30 @@ } [OFApplication terminateWithStatus: 1]; break; case '=': - [of_stderr writeLine: + [OFStdErr writeLine: OF_LOCALIZED(@"option_takes_no_argument", @"%[prog]: Option --%[opt] takes no argument", @"prog", [OFApplication programName], @"opt", optionsParser.lastLongOption)]; [OFApplication terminateWithStatus: 1]; break; case '?': if (optionsParser.lastLongOption != nil) - [of_stderr writeLine: + [OFStdErr writeLine: OF_LOCALIZED(@"unknown_long_option", @"%[prog]: Unknown option: --%[opt]", @"prog", [OFApplication programName], @"opt", optionsParser.lastLongOption)]; else { OFString *optStr = [OFString stringWithFormat: @"%c", optionsParser.lastOption]; - [of_stderr writeLine: + [OFStdErr writeLine: OF_LOCALIZED(@"unknown_option", @"%[prog]: Unknown option: -%[opt]", @"prog", [OFApplication programName], @"opt", optStr)]; } @@ -529,46 +527,50 @@ break; } } #ifdef OF_HAVE_SANDBOX - [sandbox unveilPath: (outputPath != nil - ? outputPath : OF_PATH_CURRENT_DIRECTORY) - permissions: (_continue ? @"rwc" : @"wc")]; - /* In case we use ObjOpenSSL for https later */ - [sandbox unveilPath: @"/etc/ssl" - permissions: @"r"]; + if (outputPath != nil) + [sandbox unveilPath: outputPath + permissions: (_continue ? @"rwc" : @"wc")]; + else + [sandbox unveilPath: [[OFFileManager defaultManager] + currentDirectoryPath] + permissions: (_continue ? @"rwc" : @"wc")]; + + /* In case we use OpenSSL for HTTPS later */ + [sandbox unveilPath: @"/etc/ssl" permissions: @"r"]; sandbox.allowsUnveil = false; - [OFApplication activateSandbox: sandbox]; + [OFApplication of_activateSandbox: sandbox]; #endif _outputPath = [outputPath copy]; _URLs = [optionsParser.remainingArguments copy]; if (_URLs.count < 1) - help(of_stderr, false, 1); + help(OFStdErr, false, 1); if (_quiet && _verbose) { - [of_stderr writeLine: OF_LOCALIZED(@"quiet_xor_verbose", + [OFStdErr writeLine: OF_LOCALIZED(@"quiet_xor_verbose", @"%[prog]: -q / --quiet and -v / --verbose are mutually " @"exclusive!", @"prog", [OFApplication programName])]; [OFApplication terminateWithStatus: 1]; } if (_outputPath != nil && _detectFileName) { - [of_stderr writeLine: OF_LOCALIZED( + [OFStdErr writeLine: OF_LOCALIZED( @"output_xor_detect_filename", @"%[prog]: -o / --output and -O / --detect-filename are " @"mutually exclusive!", @"prog", [OFApplication programName])]; [OFApplication terminateWithStatus: 1]; } if (_outputPath != nil && _URLs.count > 1) { - [of_stderr writeLine: + [OFStdErr writeLine: OF_LOCALIZED(@"output_only_with_one_url", @"%[prog]: Cannot use -o / --output when more than one URL " @"has been specified!", @"prog", [OFApplication programName])]; [OFApplication terminateWithStatus: 1]; @@ -575,36 +577,36 @@ } if (_insecure) _HTTPClient.allowsInsecureRedirects = true; - [self performSelector: @selector(downloadNextURL) - afterDelay: 0]; +#ifdef OF_WINDOWS + _useUnicode = [OFSystemInfo isWindowsNT]; +#else + _useUnicode = ([OFLocale encoding] == OFStringEncodingUTF8); +#endif + + [self performSelector: @selector(downloadNextURL) afterDelay: 0]; } -- (void)client: (OFHTTPClient *)client - didCreateSocket: (OFTCPSocket *)sock - request: (OFHTTPRequest *)request +- (void)client: (OFHTTPClient *)client + didCreateTLSStream: (OFTLSStream *)stream + request: (OFHTTPRequest *)request { - if (_insecure && [sock respondsToSelector: - @selector(setVerifiesCertificates:)]) - ((id )sock).verifiesCertificates = false; + /* Use setter instead of property access to work around GCC bug. */ + [stream setVerifiesCertificates: !_insecure]; } - (void)client: (OFHTTPClient *)client wantsRequestBody: (OFStream *)body request: (OFHTTPRequest *)request { /* TODO: Do asynchronously and print status */ while (!_body.atEndOfStream) { char buffer[4096]; - size_t length; - - length = [_body readIntoBuffer: buffer - length: 4096]; - [body writeBuffer: buffer - length: length]; + size_t length = [_body readIntoBuffer: buffer length: 4096]; + [body writeBuffer: buffer length: length]; } } - (bool)client: (OFHTTPClient *)client shouldFollowRedirect: (OFURL *)URL @@ -620,18 +622,21 @@ OFEnumerator *objectEnumerator = [headers objectEnumerator]; OFString *key, *object; while ((key = [keyEnumerator nextObject]) != nil && (object = [objectEnumerator nextObject]) != nil) - [of_stdout writeFormat: @" %@: %@\n", - key, object]; + [OFStdOut writeFormat: @" %@: %@\n", key, object]; objc_autoreleasePoolPop(pool); } - if (!_quiet) - [of_stdout writeFormat: @"☇ %@", URL.string]; + if (!_quiet) { + if (_useUnicode) + [OFStdOut writeFormat: @"☇ %@", URL.string]; + else + [OFStdOut writeFormat: @"< %@", URL.string]; + } _length = 0; return true; } @@ -648,17 +653,17 @@ [_progressBar draw]; [_progressBar release]; _progressBar = nil; if (!_quiet) { - [of_stdout writeString: @"\n "]; - [of_stdout writeLine: OF_LOCALIZED(@"download_error", + [OFStdOut writeString: @"\n "]; + [OFStdOut writeLine: OF_LOCALIZED(@"download_error", @"Error!")]; } URL = [_URLs objectAtIndex: _URLIndex - 1]; - [of_stderr writeLine: OF_LOCALIZED( + [OFStdErr writeLine: OF_LOCALIZED( @"download_failed_exception", @"%[prog]: Failed to download <%[url]>!\n" @" %[exception]", @"prog", [OFApplication programName], @"url", URL, @@ -668,26 +673,24 @@ [self performSelector: @selector(downloadNextURL) afterDelay: 0]; return false; } - _received += length; + [_output writeBuffer: buffer length: length]; - [_output writeBuffer: buffer - length: length]; - + _received += length; [_progressBar setReceived: _received]; if (response.atEndOfStream) { [_progressBar stop]; [_progressBar draw]; [_progressBar release]; _progressBar = nil; if (!_quiet) { - [of_stdout writeString: @"\n "]; - [of_stdout writeLine: + [OFStdOut writeString: @"\n "]; + [OFStdOut writeLine: OF_LOCALIZED(@"download_done", @"Done!")]; } [self performSelector: @selector(downloadNextURL) afterDelay: 0]; @@ -708,11 +711,14 @@ if (!_quiet) { OFString *lengthString = [headers objectForKey: @"Content-Length"]; OFString *type = [headers objectForKey: @"Content-Type"]; - [of_stdout writeFormat: @" ➜ %hd\n", statusCode]; + if (_useUnicode) + [OFStdOut writeFormat: @" ➜ %hd\n", statusCode]; + else + [OFStdOut writeFormat: @" -> %hd\n", statusCode]; if (type == nil) type = OF_LOCALIZED(@"type_unknown", @"unknown"); if (lengthString != nil) { @@ -762,34 +768,37 @@ OFEnumerator OF_GENERIC(OFString *) *objectEnumerator = [headers objectEnumerator]; OFString *key, *object; if (statusCode / 100 == 2 && _currentFileName != nil) { - [of_stdout writeString: @" "]; - [of_stdout writeLine: OF_LOCALIZED( + [OFStdOut writeString: @" "]; + [OFStdOut writeLine: OF_LOCALIZED( @"info_name_unaligned", @"Name: %[name]", @"name", _currentFileName)]; } while ((key = [keyEnumerator nextObject]) != nil && (object = [objectEnumerator nextObject]) != nil) - [of_stdout writeFormat: @" %@: %@\n", - key, object]; + [OFStdOut writeFormat: @" %@: %@\n", + key, object]; objc_autoreleasePoolPop(pool); } else if (statusCode / 100 == 2 && !_detectFileNameRequest) { - [of_stdout writeString: @" "]; - [of_stdout writeLine: OF_LOCALIZED(@"info_name", - @"Name: %[name]", - @"name", _currentFileName)]; - [of_stdout writeString: @" "]; - [of_stdout writeLine: OF_LOCALIZED(@"info_type", + [OFStdOut writeString: @" "]; + + if (_currentFileName != nil) + [OFStdOut writeLine: OF_LOCALIZED(@"info_name", + @"Name: %[name]", + @"name", _currentFileName)]; + + [OFStdOut writeString: @" "]; + [OFStdOut writeLine: OF_LOCALIZED(@"info_type", @"Type: %[type]", @"type", type)]; - [of_stdout writeString: @" "]; - [of_stdout writeLine: OF_LOCALIZED(@"info_size", + [OFStdOut writeString: @" "]; + [OFStdOut writeLine: OF_LOCALIZED(@"info_size", @"Size: %[size]", @"size", lengthString)]; } } } @@ -801,61 +810,62 @@ { if (exception != nil) { if ([exception isKindOfClass: [OFResolveHostFailedException class]]) { if (!_quiet) - [of_stdout writeString: @"\n"]; + [OFStdOut writeString: @"\n"]; - [of_stderr writeLine: + [OFStdErr writeLine: OF_LOCALIZED(@"download_resolve_host_failed", @"%[prog]: Failed to download <%[url]>!\n" @" Failed to resolve host: %[exception]", @"prog", [OFApplication programName], @"url", request.URL.string, @"exception", exception)]; } else if ([exception isKindOfClass: [OFConnectionFailedException class]]) { if (!_quiet) - [of_stdout writeString: @"\n"]; + [OFStdOut writeString: @"\n"]; - [of_stderr writeLine: + [OFStdErr writeLine: OF_LOCALIZED(@"download_failed_connection_failed", @"%[prog]: Failed to download <%[url]>!\n" @" Connection failed: %[exception]", @"prog", [OFApplication programName], @"url", request.URL.string, @"exception", exception)]; } else if ([exception isKindOfClass: [OFInvalidServerReplyException class]]) { if (!_quiet) - [of_stdout writeString: @"\n"]; + [OFStdOut writeString: @"\n"]; - [of_stderr writeLine: OF_LOCALIZED( + [OFStdErr writeLine: OF_LOCALIZED( @"download_failed_invalid_server_reply", @"%[prog]: Failed to download <%[url]>!\n" @" Invalid server reply!", @"prog", [OFApplication programName], @"url", request.URL.string)]; } else if ([exception isKindOfClass: [OFUnsupportedProtocolException class]]) { if (!_quiet) - [of_stdout writeString: @"\n"]; + [OFStdOut writeString: @"\n"]; - [of_stderr writeLine: OF_LOCALIZED(@"no_ssl_library", - @"%[prog]: No TLS library loaded!\n" - @" In order to download via https, you need to " - @"preload an TLS library for ObjFW\n" - @" such as ObjOpenSSL!", + [OFStdErr writeLine: OF_LOCALIZED(@"no_tls_support", + @"%[prog]: No TLS support in ObjFW!\n" + @" In order to download via HTTPS, you need to " + @"either build ObjFW with TLS\n" + @" support or preload a library adding TLS " + @"support to ObjFW!", @"prog", [OFApplication programName])]; } else if ([exception isKindOfClass: [OFReadOrWriteFailedException class]]) { OFString *error = OF_LOCALIZED( @"download_failed_read_or_write_failed_any", @"Read or write failed"); if (!_quiet) - [of_stdout writeString: @"\n"]; + [OFStdOut writeString: @"\n"]; if ([exception isKindOfClass: [OFReadFailedException class]]) error = OF_LOCALIZED( @"download_failed_read_or_write_failed_" @@ -866,11 +876,11 @@ error = OF_LOCALIZED( @"download_failed_read_or_write_failed_" @"write", @"Write failed"); - [of_stderr writeLine: OF_LOCALIZED( + [OFStdErr writeLine: OF_LOCALIZED( @"download_failed_read_or_write_failed", @"%[prog]: Failed to download <%[url]>!\n" @" %[error]: %[exception]", @"prog", [OFApplication programName], @"url", request.URL.string, @@ -886,13 +896,12 @@ goto after_exception_handling; } statusCode = response.statusCode; codeString = [OFString stringWithFormat: @"%hd %@", - statusCode, - of_http_status_code_to_string(statusCode)]; - [of_stderr writeLine: OF_LOCALIZED(@"download_failed", + statusCode, OFHTTPStatusCodeString(statusCode)]; + [OFStdErr writeLine: OF_LOCALIZED(@"download_failed", @"%[prog]: Failed to download <%[url]>!\n" @" HTTP status code: %[code]", @"prog", [OFApplication programName], @"url", request.URL.string, @"code", codeString)]; @@ -904,11 +913,11 @@ afterDelay: 0]; return; } after_exception_handling: - if (_method == OF_HTTP_REQUEST_METHOD_HEAD) + if (_method == OFHTTPRequestMethodHead) goto next; if (_detectFileNameRequest) { _currentFileName = [fileNameFromContentDisposition( [response.headers objectForKey: @"Content-Disposition"]) @@ -922,15 +931,15 @@ afterDelay: 0]; return; } if ([_outputPath isEqual: @"-"]) - _output = of_stdout; + _output = [OFStdOut copy]; else { if (!_continue && !_force && [[OFFileManager defaultManager] fileExistsAtPath: _currentFileName]) { - [of_stderr writeLine: + [OFStdErr writeLine: OF_LOCALIZED(@"output_already_exists", @"%[prog]: File %[filename] already exists!", @"prog", [OFApplication programName], @"filename", _currentFileName)]; @@ -942,11 +951,11 @@ OFString *mode = (response.statusCode == 206 ? @"a" : @"w"); _output = [[OFFile alloc] initWithPath: _currentFileName mode: mode]; } @catch (OFOpenItemFailedException *e) { - [of_stderr writeLine: + [OFStdErr writeLine: OF_LOCALIZED(@"failed_to_open_output", @"%[prog]: Failed to open file %[filename]: " @"%[exception]", @"prog", [OFApplication programName], @"filename", _currentFileName, @@ -958,29 +967,28 @@ } if (!_quiet) { _progressBar = [[ProgressBar alloc] initWithLength: _length - resumedFrom: _resumedFrom]; + resumedFrom: _resumedFrom + useUnicode: _useUnicode]; [_progressBar setReceived: _received]; [_progressBar draw]; } [_currentFileName release]; _currentFileName = nil; response.delegate = self; - [response asyncReadIntoBuffer: _buffer - length: [OFSystemInfo pageSize]]; + [response asyncReadIntoBuffer: _buffer length: [OFSystemInfo pageSize]]; return; next: [_currentFileName release]; _currentFileName = nil; - [self performSelector: @selector(downloadNextURL) - afterDelay: 0]; + [self performSelector: @selector(downloadNextURL) afterDelay: 0]; } - (void)downloadNextURL { OFString *URLString = nil; @@ -988,11 +996,11 @@ OFMutableDictionary *clientHeaders; OFHTTPRequest *request; _received = _length = _resumedFrom = 0; - if (_output != of_stdout) + if (_output != OFStdOut) [_output release]; _output = nil; if (_URLIndex >= _URLs.count) [OFApplication terminateWithStatus: _errorCode]; @@ -999,21 +1007,21 @@ @try { URLString = [_URLs objectAtIndex: _URLIndex++]; URL = [OFURL URLWithString: URLString]; } @catch (OFInvalidFormatException *e) { - [of_stderr writeLine: OF_LOCALIZED(@"invalid_url", + [OFStdErr writeLine: OF_LOCALIZED(@"invalid_url", @"%[prog]: Invalid URL: <%[url]>!", @"prog", [OFApplication programName], @"url", URLString)]; _errorCode = 1; goto next; } if (![URL.scheme isEqual: @"http"] && ![URL.scheme isEqual: @"https"]) { - [of_stderr writeLine: OF_LOCALIZED(@"invalid_scheme", + [OFStdErr writeLine: OF_LOCALIZED(@"invalid_scheme", @"%[prog]: Invalid scheme: <%[url]>!", @"prog", [OFApplication programName], @"url", URLString)]; _errorCode = 1; @@ -1021,16 +1029,20 @@ } clientHeaders = [[_clientHeaders mutableCopy] autorelease]; if (_detectFileName && !_detectedFileName) { - if (!_quiet) - [of_stdout writeFormat: @"⠒ %@", URL.string]; + if (!_quiet) { + if (_useUnicode) + [OFStdOut writeFormat: @"⠒ %@", URL.string]; + else + [OFStdOut writeFormat: @"? %@", URL.string]; + } request = [OFHTTPRequest requestWithURL: URL]; request.headers = clientHeaders; - request.method = OF_HTTP_REQUEST_METHOD_HEAD; + request.method = OFHTTPRequestMethodHead; _detectFileNameRequest = true; [_HTTPClient asyncPerformRequest: request]; return; } @@ -1045,10 +1057,18 @@ _currentFileName = [_outputPath copy]; if (_currentFileName == nil) _currentFileName = [URL.path.lastPathComponent copy]; + if ([_currentFileName isEqual: @"/"]) { + [_currentFileName release]; + _currentFileName = nil; + } + + if (_currentFileName == nil) + _currentFileName = @"unnamed"; + if (_continue) { @try { unsigned long long size = [[OFFileManager defaultManager] attributesOfItemAtPath: _currentFileName].fileSize; @@ -1059,18 +1079,21 @@ _resumedFrom = (unsigned long long)size; range = [OFString stringWithFormat: @"bytes=%jd-", _resumedFrom]; - [clientHeaders setObject: range - forKey: @"Range"]; + [clientHeaders setObject: range forKey: @"Range"]; } @catch (OFRetrieveItemAttributesFailedException *e) { } } - if (!_quiet) - [of_stdout writeFormat: @"⇣ %@", URL.string]; + if (!_quiet) { + if (_useUnicode) + [OFStdOut writeFormat: @"⇣ %@", URL.string]; + else + [OFStdOut writeFormat: @"< %@", URL.string]; + } request = [OFHTTPRequest requestWithURL: URL]; request.headers = clientHeaders; request.method = _method; @@ -1077,9 +1100,8 @@ _detectFileNameRequest = false; [_HTTPClient asyncPerformRequest: request]; return; next: - [self performSelector: @selector(downloadNextURL) - afterDelay: 0]; + [self performSelector: @selector(downloadNextURL) afterDelay: 0]; } @end Index: utils/ofhttp/ProgressBar.h ================================================================== --- utils/ofhttp/ProgressBar.h +++ utils/ofhttp/ProgressBar.h @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -22,10 +20,11 @@ #define BPS_WINDOW_SIZE 10 @interface ProgressBar: OFObject { + bool _useUnicode; unsigned long long _received, _lastReceived, _length, _resumedFrom; OFDate *_startDate, *_lastReceivedDate; OFTimer *_drawTimer, *_BPSTimer; bool _stopped; float _BPS; @@ -33,11 +32,12 @@ float _BPSWindow[BPS_WINDOW_SIZE]; size_t _BPSWindowIndex, _BPSWindowLength; } - (instancetype)initWithLength: (unsigned long long)length - resumedFrom: (unsigned long long)resumedFrom; + resumedFrom: (unsigned long long)resumedFrom + useUnicode: (bool)useUnicode OF_DESIGNATED_INITIALIZER; - (void)setReceived: (unsigned long long)received; - (void)draw; - (void)calculateBPSAndETA; - (void)stop; @end Index: utils/ofhttp/ProgressBar.m ================================================================== --- utils/ofhttp/ProgressBar.m +++ utils/ofhttp/ProgressBar.m @@ -1,9 +1,7 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer + * 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 @@ -24,31 +22,42 @@ #import "OFTimer.h" #import "OFLocale.h" #import "ProgressBar.h" -#define GIBIBYTE (1024 * 1024 * 1024) -#define MEBIBYTE (1024 * 1024) -#define KIBIBYTE (1024) +static const float oneKibibyte = 1024; +static const float oneMebibyte = 1024 * 1024; +static const float oneGibibyte = 1024 * 1024 * 1024; + +static const OFTimeInterval updateInterval = 0.1; + +#ifdef OF_MINT +/* freemint-gcc does not have trunc() */ +# define trunc(x) ((int64_t)(x)) +#endif -#define UPDATE_INTERVAL 0.1 +#ifndef HAVE_TRUNCF +# define truncf(x) trunc(x) +#endif @implementation ProgressBar - (instancetype)initWithLength: (unsigned long long)length resumedFrom: (unsigned long long)resumedFrom + useUnicode: (bool)useUnicode { self = [super init]; @try { void *pool = objc_autoreleasePoolPush(); + _useUnicode = useUnicode; _length = length; _resumedFrom = resumedFrom; _startDate = [[OFDate alloc] init]; _lastReceivedDate = [[OFDate alloc] init]; _drawTimer = [[OFTimer - scheduledTimerWithTimeInterval: UPDATE_INTERVAL + scheduledTimerWithTimeInterval: updateInterval target: self selector: @selector(draw) repeats: true] retain]; _BPSTimer = [[OFTimer scheduledTimerWithTimeInterval: 1.0 @@ -86,11 +95,11 @@ - (void)_drawProgress { float bars, percent; int columns, barWidth; - if ((columns = of_stdout.columns) >= 0) { + if ((columns = OFStdOut.columns) >= 0) { if (columns > 37) barWidth = columns - 37; else barWidth = 0; } else @@ -99,150 +108,174 @@ bars = (float)(_resumedFrom + _received) / (float)(_resumedFrom + _length) * barWidth; percent = (float)(_resumedFrom + _received) / (float)(_resumedFrom + _length) * 100; - [of_stdout writeString: @"\r ▕"]; - - for (size_t i = 0; i < (size_t)bars; i++) - [of_stdout writeString: @"█"]; - if (bars < barWidth) { - float rem = bars - truncf(bars); - - if (rem >= 0.875) - [of_stdout writeString: @"▉"]; - else if (rem >= 0.75) - [of_stdout writeString: @"▊"]; - else if (rem >= 0.625) - [of_stdout writeString: @"▋"]; - else if (rem >= 0.5) - [of_stdout writeString: @"▌"]; - else if (rem >= 0.375) - [of_stdout writeString: @"▍"]; - else if (rem >= 0.25) - [of_stdout writeString: @"▎"]; - else if (rem >= 0.125) - [of_stdout writeString: @"▏"]; - else - [of_stdout writeString: @" "]; - - for (size_t i = 0; i < barWidth - (size_t)bars - 1; i++) - [of_stdout writeString: @" "]; - } - - [of_stdout writeFormat: @"▏ %,6.2f%% ", percent]; + if (_useUnicode) { + [OFStdOut writeString: @"\r ▕"]; + + for (size_t i = 0; i < (size_t)bars; i++) + [OFStdOut writeString: @"█"]; + if (bars < barWidth) { + float rem = bars - truncf(bars); + + if (rem >= 0.875) + [OFStdOut writeString: @"▉"]; + else if (rem >= 0.75) + [OFStdOut writeString: @"▊"]; + else if (rem >= 0.625) + [OFStdOut writeString: @"▋"]; + else if (rem >= 0.5) + [OFStdOut writeString: @"▌"]; + else if (rem >= 0.375) + [OFStdOut writeString: @"▍"]; + else if (rem >= 0.25) + [OFStdOut writeString: @"▎"]; + else if (rem >= 0.125) + [OFStdOut writeString: @"▏"]; + else + [OFStdOut writeString: @" "]; + + for (size_t i = 0; i < barWidth - (size_t)bars - 1; i++) + [OFStdOut writeString: @" "]; + } + + [OFStdOut writeFormat: @"▏ %,6.2f%% ", percent]; + } else { + [OFStdOut writeString: @"\r ["]; + + for (size_t i = 0; i < (size_t)bars; i++) + [OFStdOut writeString: @"#"]; + if (bars < barWidth) { + float rem = bars - truncf(bars); + + if (rem >= 0.75) + [OFStdOut writeString: @"O"]; + else if (rem >= 0.5) + [OFStdOut writeString: @"o"]; + else if (rem >= 0.25) + [OFStdOut writeString: @"."]; + else + [OFStdOut writeString: @" "]; + + for (size_t i = 0; i < barWidth - (size_t)bars - 1; i++) + [OFStdOut writeString: @" "]; + } + + [OFStdOut writeFormat: @"] %,6.2f%% ", percent]; + } if (percent == 100) { double timeInterval = -_startDate.timeIntervalSinceNow; _BPS = (float)_received / (float)timeInterval; _ETA = timeInterval; } if (isinf(_ETA)) - [of_stdout writeString: @"--:--:-- "]; + [OFStdOut writeString: @"--:--:-- "]; else if (_ETA >= 99 * 3600) { OFString *num = [OFString stringWithFormat: @"%,4.2f", _ETA / (24 * 3600)]; - [of_stdout writeString: OF_LOCALIZED(@"eta_days", + [OFStdOut writeString: OF_LOCALIZED(@"eta_days", @"%[num] d ", @"num", num)]; } else - [of_stdout writeFormat: @"%2u:%02u:%02u ", + [OFStdOut writeFormat: @"%2u:%02u:%02u ", (uint8_t)(_ETA / 3600), (uint8_t)(_ETA / 60) % 60, (uint8_t)_ETA % 60]; - if (_BPS >= GIBIBYTE) { + if (_BPS >= oneGibibyte) { OFString *num = [OFString stringWithFormat: - @"%,7.2f", _BPS / GIBIBYTE]; - [of_stdout writeString: OF_LOCALIZED(@"progress_gibs", + @"%,7.2f", _BPS / oneGibibyte]; + [OFStdOut writeString: OF_LOCALIZED(@"progress_gibs", @"%[num] GiB/s", @"num", num)]; - } else if (_BPS >= MEBIBYTE) { + } else if (_BPS >= oneMebibyte) { OFString *num = [OFString stringWithFormat: - @"%,7.2f", _BPS / MEBIBYTE]; - [of_stdout writeString: OF_LOCALIZED(@"progress_mibs", + @"%,7.2f", _BPS / oneMebibyte]; + [OFStdOut writeString: OF_LOCALIZED(@"progress_mibs", @"%[num] MiB/s", @"num", num)]; - } else if (_BPS >= KIBIBYTE) { + } else if (_BPS >= oneKibibyte) { OFString *num = [OFString stringWithFormat: - @"%,7.2f", _BPS / KIBIBYTE]; - [of_stdout writeString: OF_LOCALIZED(@"progress_kibs", + @"%,7.2f", _BPS / oneKibibyte]; + [OFStdOut writeString: OF_LOCALIZED(@"progress_kibs", @"%[num] KiB/s", @"num", num)]; } else { OFString *num = [OFString stringWithFormat: @"%,7.2f", _BPS]; - [of_stdout writeString: OF_LOCALIZED(@"progress_bps", + [OFStdOut writeString: OF_LOCALIZED(@"progress_bps", @"%[num] B/s ", @"num", num)]; } } - (void)_drawReceived { - [of_stdout writeString: @"\r "]; + [OFStdOut writeString: @"\r "]; - if (_resumedFrom + _received >= GIBIBYTE) { + if (_resumedFrom + _received >= oneGibibyte) { OFString *num = [OFString stringWithFormat: - @"%,7.2f", (float)(_resumedFrom + _received) / GIBIBYTE]; - [of_stdout writeString: OF_LOCALIZED(@"progress_gib", + @"%,7.2f", (float)(_resumedFrom + _received) / oneGibibyte]; + [OFStdOut writeString: OF_LOCALIZED(@"progress_gib", @"%[num] GiB", @"num", num)]; - } else if (_resumedFrom + _received >= MEBIBYTE) { + } else if (_resumedFrom + _received >= oneMebibyte) { OFString *num = [OFString stringWithFormat: - @"%,7.2f", (float)(_resumedFrom + _received) / MEBIBYTE]; - [of_stdout writeString: OF_LOCALIZED(@"progress_mib", + @"%,7.2f", (float)(_resumedFrom + _received) / oneMebibyte]; + [OFStdOut writeString: OF_LOCALIZED(@"progress_mib", @"%[num] MiB", @"num", num)]; - } else if (_resumedFrom + _received >= KIBIBYTE) { + } else if (_resumedFrom + _received >= oneKibibyte) { OFString *num = [OFString stringWithFormat: - @"%,7.2f", (float)(_resumedFrom + _received) / KIBIBYTE]; - [of_stdout writeString: OF_LOCALIZED(@"progress_kib", + @"%,7.2f", (float)(_resumedFrom + _received) / oneKibibyte]; + [OFStdOut writeString: OF_LOCALIZED(@"progress_kib", @"%[num] KiB", @"num", num)]; } else { OFString *num = [OFString stringWithFormat: @"%jd", _resumedFrom + _received]; - [of_stdout writeString: OF_LOCALIZED(@"progress_bytes", + [OFStdOut writeString: OF_LOCALIZED(@"progress_bytes", @"[" @" [" @" {'num == 1': '1 byte '}," @" {'': '%[num] bytes'}" @" ]" @"]".objectByParsingJSON, @"num", num)]; } - [of_stdout writeString: @" "]; + [OFStdOut writeString: @" "]; if (_stopped) _BPS = (float)_received / -(float)_startDate.timeIntervalSinceNow; - if (_BPS >= GIBIBYTE) { + if (_BPS >= oneGibibyte) { OFString *num = [OFString stringWithFormat: - @"%,7.2f", _BPS / GIBIBYTE]; - [of_stdout writeString: OF_LOCALIZED(@"progress_gibs", + @"%,7.2f", _BPS / oneGibibyte]; + [OFStdOut writeString: OF_LOCALIZED(@"progress_gibs", @"%[num] GiB/s", @"num", num)]; - } else if (_BPS >= MEBIBYTE) { + } else if (_BPS >= oneMebibyte) { OFString *num = [OFString stringWithFormat: - @"%,7.2f", _BPS / MEBIBYTE]; - [of_stdout writeString: OF_LOCALIZED(@"progress_mibs", + @"%,7.2f", _BPS / oneMebibyte]; + [OFStdOut writeString: OF_LOCALIZED(@"progress_mibs", @"%[num] MiB/s", @"num", num)]; - } else if (_BPS >= KIBIBYTE) { + } else if (_BPS >= oneKibibyte) { OFString *num = [OFString stringWithFormat: - @"%,7.2f", _BPS / KIBIBYTE]; - [of_stdout writeString: OF_LOCALIZED(@"progress_kibs", + @"%,7.2f", _BPS / oneKibibyte]; + [OFStdOut writeString: OF_LOCALIZED(@"progress_kibs", @"%[num] KiB/s", @"num", num)]; } else { OFString *num = [OFString stringWithFormat: @"%,7.2f", _BPS]; - [of_stdout writeString: OF_LOCALIZED(@"progress_bps", + [OFStdOut writeString: OF_LOCALIZED(@"progress_bps", @"%[num] B/s ", @"num", num)]; } } Index: utils/ofhttp/lang/de.json ================================================================== --- utils/ofhttp/lang/de.json +++ utils/ofhttp/lang/de.json @@ -50,15 +50,17 @@ ], "download_failed_invalid_server_reply": [ "%[prog]: Fehler beim Download von <%[url]>!\n", " Ungültige Antwort vom Server!" ], - "no_ssl_library": [ - "%[prog]: Keine TLS-Bibliothek geladen!\n", - " Um Dateien über https zu laden, müssen Sie eine TLS-Bibliothek für ", - "ObjFW,\n", - " wie z.B. ObjOpenSSL, mittels LD_PRELOAD laden." + "no_tls_support": [ + "%[prog]: Keine TLS-Unterstützung in ObjFW!\n", + " Um via HTTPS runterzuladen, müssen Sie entweder ObjFW mit TLS-", + "Unterstützung\n", + " kompilieren oder eine Bibliothek mittels „preoad” laden, welche ", + "TLS-Support\n", + " zu ObjFW hinzufügt!" ], "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": [ DELETED utils/ofsock/Makefile Index: utils/ofsock/Makefile ================================================================== --- utils/ofsock/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -include ../../extra.mk - -PROG = ofsock${PROG_SUFFIX} -SRCS = OFSock.m - -include ../../buildsys.mk - -PACKAGE_NAME = ofsock - -${PROG}: ${LIBOBJFW_DEP_LVL2} ${LIBOBJFWRT_DEP_LVL2} - -CPPFLAGS += -I../../src \ - -I../../src/runtime \ - -I../../src/exceptions \ - -I../.. -LIBS := -L../../src -lobjfw \ - -L../../src/runtime -L../../src/runtime/linklib ${RUNTIME_LIBS} \ - ${LIBS} -LD = ${OBJC} -LDFLAGS += ${LDFLAGS_RPATH} DELETED utils/ofsock/OFSock.m Index: utils/ofsock/OFSock.m ================================================================== --- utils/ofsock/OFSock.m +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019, 2020 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It 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 "OFArray.h" -#import "OFNumber.h" -#import "OFPair.h" -#import "OFStdIOStream.h" -#import "OFStream.h" -#import "OFString.h" -#import "OFTCPSocket.h" -#import "OFURL.h" - -#define BUFFER_LEN 4096 - -@interface OFSock: OFObject -{ - char _buffer[BUFFER_LEN]; - OFMutableArray OF_GENERIC(OFPair OF_GENERIC(OFStream *, OFStream *) *) - *_streams; - int _errors; -} -@end - -OF_APPLICATION_DELEGATE(OFSock) - -static OFPair OF_GENERIC(OFStream *, OFStream *) * -streamFromString(OFString *string) -{ - OFURL *URL; - OFString *scheme; - - if ([string isEqual: @"-"]) - return [OFPair pairWithFirstObject: of_stdin - secondObject: of_stdout]; - - URL = [OFURL URLWithString: string]; - scheme = URL.scheme; - - if ([scheme isEqual: @"tcp"]) { - OFTCPSocket *sock = [OFTCPSocket socket]; - - if (URL.port == nil) { - [of_stderr writeLine: @"Need a port!"]; - [OFApplication terminateWithStatus: 1]; - } - - [sock connectToHost: URL.host - port: URL.port.shortValue]; - - return [OFPair pairWithFirstObject: sock - secondObject: sock]; - } - - [of_stderr writeFormat: @"Invalid protocol: %@\n", scheme]; - [OFApplication terminateWithStatus: 1]; - abort(); -} - -@implementation OFSock -- (void)applicationDidFinishLaunching -{ - OFArray OF_GENERIC(OFString *) *arguments = [OFApplication arguments]; - - if (arguments.count < 1) { - [of_stderr writeLine: @"Need at least one argument!"]; - [OFApplication terminateWithStatus: 1]; - } - - _streams = [[OFMutableArray alloc] init]; - - for (OFString *argument in arguments) { - OFPair *pair = streamFromString(argument); - - [pair.firstObject setDelegate: self]; - - [_streams addObject: pair]; - } - - if (arguments.count == 1) { - of_stdin.delegate = self; - - [_streams addObject: - [OFPair pairWithFirstObject: of_stdin - secondObject: of_stdout]]; - } - - for (OFPair *pair in _streams) - [pair.firstObject asyncReadIntoBuffer: _buffer - length: BUFFER_LEN]; -} - -- (void)removeDeadStream: (OFStream *)stream -{ - size_t count = _streams.count; - - for (size_t i = 0; i < count; i++) { - if ([[_streams objectAtIndex: i] firstObject] == stream) { - [_streams removeObjectAtIndex: i]; - break; - } - } - - if (_streams.count < 2) - [OFApplication terminateWithStatus: _errors]; -} - -- (bool)stream: (OFStream *)stream - didReadIntoBuffer: (void *)buffer - length: (size_t)length - exception: (id)exception -{ - if (exception != nil) { - [of_stderr writeFormat: @"Exception on stream %@: %@\n", - stream, exception]; - _errors++; - [self removeDeadStream: stream]; - return false; - } - - if (stream.atEndOfStream) { - [self removeDeadStream: stream]; - return false; - } - - for (OFPair *pair in _streams) { - if (pair.firstObject == stream) - continue; - - [pair.secondObject writeBuffer: buffer - length: length]; - } - - return true; -} -@end