summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/build.yml23
-rw-r--r--Makefile.am7
-rw-r--r--NEWS34
-rw-r--r--README.md193
-rw-r--r--configure.ac27
-rwxr-xr-xgit-version-gen20
-rw-r--r--include/Makefile.am5
-rw-r--r--include/libimobiledevice-glue/cbuf.h8
-rw-r--r--include/libimobiledevice-glue/collection.h14
-rw-r--r--include/libimobiledevice-glue/glue.h37
-rw-r--r--include/libimobiledevice-glue/nskeyedarchive.h90
-rw-r--r--include/libimobiledevice-glue/opack.h5
-rw-r--r--include/libimobiledevice-glue/sha.h86
-rw-r--r--include/libimobiledevice-glue/socket.h36
-rw-r--r--include/libimobiledevice-glue/termcolors.h11
-rw-r--r--include/libimobiledevice-glue/thread.h53
-rw-r--r--include/libimobiledevice-glue/tlv.h15
-rw-r--r--include/libimobiledevice-glue/utils.h38
-rw-r--r--src/Makefile.am5
-rw-r--r--src/cbuf.c6
-rw-r--r--src/collection.c12
-rw-r--r--src/common.h18
-rw-r--r--src/fixedint.h72
-rw-r--r--src/glue.c8
-rw-r--r--src/nskeyedarchive.c1228
-rw-r--r--src/opack.c10
-rw-r--r--src/sha1.c517
-rw-r--r--src/sha256.c265
-rw-r--r--src/sha512.c315
-rw-r--r--src/socket.c394
-rw-r--r--src/termcolors.c10
-rw-r--r--src/thread.c45
-rw-r--r--src/tlv.c14
-rw-r--r--src/utils.c256
34 files changed, 3327 insertions, 550 deletions
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 31341af..1869190 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -1,6 +1,9 @@
name: build
-on: [push]
+on:
+ push:
+ schedule:
+ - cron: '0 0 1 * *'
jobs:
build-linux-ubuntu:
@@ -13,7 +16,7 @@ jobs:
run: |
echo "target_triplet=`gcc -dumpmachine`" >> $GITHUB_ENV
- name: fetch libplist
- uses: dawidd6/action-download-artifact@v2
+ uses: dawidd6/action-download-artifact@v3
with:
github_token: ${{secrets.GITHUB_TOKEN}}
workflow: build.yml
@@ -27,7 +30,7 @@ jobs:
done
sudo cp -r extract/* /
sudo ldconfig
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v4
- name: autogen
run: ./autogen.sh PKG_CONFIG_PATH=/usr/local/lib/pkgconfig LDFLAGS="-Wl,-rpath=/usr/local/lib"
- name: make
@@ -40,7 +43,7 @@ jobs:
DESTDIR=`pwd`/dest make install
tar -C dest -cf libimobiledevice-glue.tar usr
- name: publish artifact
- uses: actions/upload-artifact@v2
+ uses: actions/upload-artifact@v4
with:
name: libimobiledevice-glue-latest_${{env.target_triplet}}
path: libimobiledevice-glue.tar
@@ -56,7 +59,7 @@ jobs:
fi
shell: bash
- name: fetch libplist
- uses: dawidd6/action-download-artifact@v2
+ uses: dawidd6/action-download-artifact@v3
with:
github_token: ${{secrets.GITHUB_TOKEN}}
workflow: build.yml
@@ -69,7 +72,7 @@ jobs:
tar -C extract -xvf $I
done
sudo cp -r extract/* /
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v4
- name: autogen
run: |
SDKDIR=`xcrun --sdk macosx --show-sdk-path`
@@ -93,7 +96,7 @@ jobs:
DESTDIR=`pwd`/dest make install
tar -C dest -cf libimobiledevice-glue.tar usr
- name: publish artifact
- uses: actions/upload-artifact@v2
+ uses: actions/upload-artifact@v4
with:
name: libimobiledevice-glue-latest_macOS
path: libimobiledevice-glue.tar
@@ -129,7 +132,7 @@ jobs:
echo "dest=$dest" >> $GITHUB_ENV
echo "target_triplet=`gcc -dumpmachine`" >> $GITHUB_ENV
- name: fetch libplist
- uses: dawidd6/action-download-artifact@v2
+ uses: dawidd6/action-download-artifact@v3
with:
github_token: ${{secrets.GITHUB_TOKEN}}
workflow: build.yml
@@ -142,7 +145,7 @@ jobs:
tar -C extract -xvf $I
done
cp -r extract/* /
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v4
- name: autogen
run: ./autogen.sh CC=gcc CXX=g++
- name: make
@@ -155,7 +158,7 @@ jobs:
DESTDIR=`pwd`/dest make install
tar -C dest -cf libimobiledevice-glue.tar ${{ env.dest }}
- name: publish artifact
- uses: actions/upload-artifact@v2
+ uses: actions/upload-artifact@v4
with:
name: libimobiledevice-glue-latest_${{ matrix.arch }}-${{ env.dest }}
path: libimobiledevice-glue.tar
diff --git a/Makefile.am b/Makefile.am
index 149678b..96d3c7b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -3,7 +3,12 @@ ACLOCAL_AMFLAGS = -I m4
SUBDIRS = src include
EXTRA_DIST = \
- README.md
+ README.md \
+ git-version-gen
+
+dist-hook:
+ @if ! git diff --quiet; then echo "Uncommitted changes present; not releasing"; exit 1; fi
+ echo $(VERSION) > $(distdir)/.tarball-version
indent:
indent -kr -ut -ts4 -l120 src/*.c src/*.h
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..723ccd5
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,34 @@
+Version 1.3.0
+~~~~~~~~~~~~~
+
+- Changes:
+ * Add SHA-1, SHA-224, SHA-256, SHA-384, and SHA-512 functions to interface
+ * socket: Create an IPv4 compatible IPv6 socket when NULL is passed to socket_create
+ * socket: Haiku compilation fixes
+
+Version 1.2.0
+~~~~~~~~~~~~~
+
+- Changes:
+ * Add helper code to deal with NSKeyedArchiver plist data
+
+- Bugfixes:
+ * socket: Make sure errno is always set on error, and always return a meaningful error code
+
+Version 1.1.0
+~~~~~~~~~~~~~
+
+- Changes:
+ * socket: Use poll() - when available - instead of select()
+ * socket: Allow NULL as address for socket_create() and socket_connect()
+ * win32: Remove windows.h from public headers
+ * Add version function to interface
+
+- Bugfixes:
+ * opack: Fixed 32bit buffer overflow
+ * opack: Fix parsing of 32 and 64 bit packed values
+
+Version 1.0.0
+~~~~~~~~~~~~~
+
+First public release.
diff --git a/README.md b/README.md
index 0b68059..7e8f7b7 100644
--- a/README.md
+++ b/README.md
@@ -5,6 +5,21 @@ Library with common code used by the libraries and tools around the
![](https://github.com/libimobiledevice/libimobiledevice-glue/workflows/build/badge.svg)
+## Table of Contents
+- [Features](#features)
+- [Building](#building)
+ - [Prerequisites](#prerequisites)
+ - [Linux (Debian/Ubuntu based)](#linux-debianubuntu-based)
+ - [macOS](#macos)
+ - [Windows](#windows)
+ - [Configuring the source tree](#configuring-the-source-tree)
+ - [Building and installation](#building-and-installation)
+- [Usage](#usage)
+- [Contributing](#contributing)
+- [Links](#links)
+- [License](#license)
+- [Credits](#credits)
+
## Features
The main functionality provided by this library are **socket** helper
@@ -13,7 +28,7 @@ Besides that it comes with a number of string, file, and plist helper
functions, as well as some other commonly used code that was originally
duplicated in the dedicated projects.
-Test on Linux, macOS, Windows.
+Tested on Linux, macOS, and Windows.
## Projects using this library
@@ -23,48 +38,167 @@ Test on Linux, macOS, Windows.
- [libirecovery](https://github.com/libimobiledevice/libirecovery)
- [idevicerestore](https://github.com/libimobiledevice/idevicerestore)
-## Installation / Getting started
+## Building
+
+### Prerequisites
+
+You need to have a working compiler (gcc/clang) and development environent
+available. This project uses autotools for the build process, allowing to
+have common build steps across different platforms.
+Only the prerequisites differ and they are described in this section.
+
+libimobiledevice-glue requires [libplist](https://github.com/libimobiledevice/libplist).
+Check the [Building](https://github.com/libimobiledevice/libplist?tab=readme-ov-file#building)
+section of the README on how to build it. Note that some platforms might have it as a package.
+
+#### Linux (Debian/Ubuntu based)
+
+* Install all required dependencies and build tools:
+ ```shell
+ sudo apt-get install \
+ build-essential \
+ pkg-config \
+ checkinstall \
+ git \
+ autoconf \
+ automake \
+ libtool-bin \
+ libplist-dev
+ ```
+
+ In case libplist-dev is not available, you can manually build and install it. See note above.
+
+#### macOS
+
+* Make sure the Xcode command line tools are installed. Then, use either [MacPorts](https://www.macports.org/)
+ or [Homebrew](https://brew.sh/) to install `automake`, `autoconf`, `libtool`, etc.
+
+ Using MacPorts:
+ ```shell
+ sudo port install libtool autoconf automake pkgconfig
+ ```
+
+ Using Homebrew:
+ ```shell
+ brew install libtool autoconf automake pkg-config
+ ```
-### Debian / Ubuntu Linux
+#### Windows
+
+* Using [MSYS2](https://www.msys2.org/) is the official way of compiling this project on Windows. Download the MSYS2 installer
+ and follow the installation steps.
+
+ It is recommended to use the _MSYS2 MinGW 64-bit_ shell. Run it and make sure the required dependencies are installed:
+
+ ```shell
+ pacman -S base-devel \
+ git \
+ mingw-w64-x86_64-gcc \
+ make \
+ libtool \
+ autoconf \
+ automake-wrapper \
+ pkg-config
+ ```
+ NOTE: You can use a different shell and different compiler according to your needs. Adapt the above command accordingly.
+
+### Configuring the source tree
+
+You can build the source code from a git checkout, or from a `.tar.bz2` release tarball from [Releases](https://github.com/libimobiledevice/libimobiledevice-glue/releases).
+Before we can build it, the source tree has to be configured for building. The steps depend on where you got the source from.
+
+Since libimobiledevice-glue depends on other packages, you should set the pkg-config environment variable `PKG_CONFIG_PATH`
+accordingly. Make sure to use a path with the same prefix as the dependencies. If they are installed in `/usr/local` you would do
-First install all required dependencies and build tools:
```shell
-sudo apt-get install \
- build-essential \
- pkg-config \
- checkinstall \
- git \
- autoconf \
- automake \
- libtool-bin \
- libplist-dev \
+export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
```
-Then clone the actual project repository:
+* **From git**
+
+ If you haven't done already, clone the actual project repository and change into the directory.
+ ```shell
+ git clone https://github.com/libimobiledevice/libimobiledevice-glue
+ cd libimobiledevice-glue
+ ```
+
+ Configure the source tree for building:
+ ```shell
+ ./autogen.sh
+ ```
+
+* **From release tarball (.tar.bz2)**
+
+ When using an official [release tarball](https://github.com/libimobiledevice/libimobiledevice-glue/releases) (`libimobiledevice-glue-x.y.z.tar.bz2`)
+ the procedure is slightly different.
+
+ Extract the tarball:
+ ```shell
+ tar xjf libimobiledevice-glue-x.y.z.tar.bz2
+ cd libimobiledevice-glue-x.y.z
+ ```
+
+ Configure the source tree for building:
+ ```shell
+ ./configure
+ ```
+
+Both `./configure` and `./autogen.sh` (which generates and calls `configure`) accept a few options, for example `--prefix` to allow
+building for a different target folder. You can simply pass them like this:
+
+```shell
+./autogen.sh --prefix=/usr/local
+```
+or
```shell
-git clone https://github.com/libimobiledevice/libimobiledevice-glue.git
-cd libimobiledevice-glue
+./configure --prefix=/usr/local
```
-Now you can build and install it:
+Once the command is successful, the last few lines of output will look like this:
+```
+[...]
+config.status: creating config.h
+config.status: executing depfiles commands
+config.status: executing libtool commands
+
+Configuration for libimobiledevice-glue 1.0.1:
+-------------------------------------------
+
+ Install prefix: .........: /usr/local
+
+ Now type 'make' to build libimobiledevice-glue 1.0.1,
+ and then 'make install' for installation.
+```
+
+### Building and installation
+
+If you followed all the steps successfully, and `autogen.sh` or `configure` did not print any errors,
+you are ready to build the project. This is simply done with
+
```shell
-./autogen.sh
make
-sudo make install
```
-If you require a custom prefix or other option being passed to `./configure`
-you can pass them directly to `./autogen.sh` like this:
-```bash
-./autogen.sh --prefix=/opt/local
-make
+If no errors are emitted you are ready for installation. Depending on whether
+the current user has permissions to write to the destination directory or not,
+you would either run
+```shell
+make install
+```
+_OR_
+```shell
sudo make install
```
+If you are on Linux, you want to run `sudo ldconfig` after installation to
+make sure the installed libraries are made available.
+
## Usage
This library is directly used by libusbmuxd, libimobiledevice, etc., so there
-is no need to do anything in particular.
+is no need to do anything in particular. Feel free to use it in your project,
+check the header files for available functions. A documentation might be added
+later.
## Contributing
@@ -93,7 +227,7 @@ Please make sure your contribution adheres to:
## License
-This library and utilities are licensed under the [GNU Lesser General Public License v2.1](https://www.gnu.org/licenses/lgpl-2.1.en.html),
+This library is licensed under the [GNU Lesser General Public License v2.1](https://www.gnu.org/licenses/lgpl-2.1.en.html),
also included in the repository in the `COPYING` file.
## Credits
@@ -101,7 +235,8 @@ also included in the repository in the `COPYING` file.
Apple, iPhone, iPad, iPod, iPod Touch, Apple TV, Apple Watch, Mac, iOS,
iPadOS, tvOS, watchOS, and macOS are trademarks of Apple Inc.
-This project is an independent software and has not been authorized, sponsored,
-or otherwise approved by Apple Inc.
+This project is an independent software library and has not been authorized,
+sponsored, or otherwise approved by Apple Inc.
+
+README Updated on: 2024-02-21
-README Updated on: 2022-04-04
diff --git a/configure.ac b/configure.ac
index 4e40db1..cfdcddd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,8 +1,8 @@
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
-AC_PREREQ(2.68)
-AC_INIT([libimobiledevice-glue], [1.0.0], [https://github.com/libimobiledevice/libimobiledevice-glue/issues],, [https://libimobiledevice.org])
+AC_PREREQ([2.68])
+AC_INIT([libimobiledevice-glue], [m4_esyscmd(./git-version-gen $RELEASE_VERSION)], [https://github.com/libimobiledevice/libimobiledevice-glue/issues], [], [https://libimobiledevice.org])
AM_INIT_AUTOMAKE([dist-bzip2 no-dist-gzip check-news])
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES])
AC_CONFIG_SRCDIR([src/])
@@ -15,10 +15,15 @@ dnl libtool versioning
# changes to the signature and the semantic)
# ? :+1 : ? == just internal changes
# CURRENT : REVISION : AGE
-LIBIMOBILEDEVICE_GLUE_SO_VERSION=0:0:0
+LIBIMOBILEDEVICE_GLUE_SO_VERSION=3:0:3
+
+# Check if we have a version defined
+if test -z $PACKAGE_VERSION; then
+ AC_MSG_ERROR([PACKAGE_VERSION is not defined. Make sure to configure a source tree checked out from git or that .tarball-version is present.])
+fi
dnl Minimum package versions
-LIBPLIST_VERSION=2.2.0
+LIBPLIST_VERSION=2.3.0
AC_SUBST(LIBIMOBILEDEVICE_GLUE_SO_VERSION)
AC_SUBST(LIBPLIST_VERSION)
@@ -44,7 +49,9 @@ AC_TYPE_UINT32_T
AC_TYPE_UINT8_T
# Checks for library functions.
-AC_CHECK_FUNCS([asprintf strcasecmp strdup strerror strndup stpcpy vasprintf getifaddrs])
+AC_CHECK_FUNCS([asprintf strcasecmp strdup strerror strndup stpcpy vasprintf getifaddrs poll])
+# Checks for additional library requirements
+AC_SEARCH_LIBS(socket, network)
AC_CHECK_HEADER(endian.h, [ac_cv_have_endian_h="yes"], [ac_cv_have_endian_h="no"])
if test "x$ac_cv_have_endian_h" = "xno"; then
@@ -105,12 +112,12 @@ fi
AC_CHECK_MEMBER(struct dirent.d_type, AC_DEFINE(HAVE_DIRENT_D_TYPE, 1, [define if struct dirent has member d_type]),, [#include <dirent.h>])
AS_COMPILER_FLAGS(GLOBAL_CFLAGS, "-Wall -Wextra -Wmissing-declarations -Wredundant-decls -Wshadow -Wpointer-arith -Wwrite-strings -Wswitch-default -Wno-unused-parameter -fsigned-char -fvisibility=hidden")
-AC_SUBST(GLOBAL_CFLAGS)
-case "$GLOBAL_CFLAGS" in
- *-fvisibility=hidden*)
- AC_DEFINE([HAVE_FVISIBILITY], [1], [Define if compiled with -fvisibility=hidden])
-esac
+if test "x$enable_static" = "xyes" -a "x$enable_shared" = "xno"; then
+ GLOBAL_CFLAGS+=" -DLIMD_GLUE_STATIC"
+fi
+
+AC_SUBST(GLOBAL_CFLAGS)
# check for large file support
AC_SYS_LARGEFILE
diff --git a/git-version-gen b/git-version-gen
new file mode 100755
index 0000000..d868952
--- /dev/null
+++ b/git-version-gen
@@ -0,0 +1,20 @@
+#!/bin/sh
+SRCDIR=`dirname $0`
+if test -n "$1"; then
+ VER=$1
+else
+ if test -r "${SRCDIR}/.git" && test -x "`which git`" ; then
+ git update-index -q --refresh
+ if ! VER=`git describe --tags --dirty 2>/dev/null`; then
+ COMMIT=`git rev-parse --short HEAD`
+ DIRTY=`git diff --quiet HEAD || echo "-dirty"`
+ VER=`sed -n '1,/RE/s/Version \(.*\)/\1/p' ${SRCDIR}/NEWS`-git-${COMMIT}${DIRTY}
+ fi
+ else
+ if test -f "${SRCDIR}/.tarball-version"; then
+ VER=`cat "${SRCDIR}/.tarball-version"`
+ fi
+ fi
+fi
+VER=`printf %s "$VER" | head -n1`
+printf %s "$VER"
diff --git a/include/Makefile.am b/include/Makefile.am
index a071583..624814e 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -2,11 +2,14 @@ EXTRA_DIST = \
endianness.h
nobase_include_HEADERS = \
+ libimobiledevice-glue/glue.h \
libimobiledevice-glue/socket.h \
libimobiledevice-glue/thread.h \
libimobiledevice-glue/utils.h \
+ libimobiledevice-glue/nskeyedarchive.h \
libimobiledevice-glue/collection.h \
libimobiledevice-glue/termcolors.h \
libimobiledevice-glue/cbuf.h \
libimobiledevice-glue/opack.h \
- libimobiledevice-glue/tlv.h
+ libimobiledevice-glue/tlv.h \
+ libimobiledevice-glue/sha.h
diff --git a/include/libimobiledevice-glue/cbuf.h b/include/libimobiledevice-glue/cbuf.h
index 01e2f43..2463af7 100644
--- a/include/libimobiledevice-glue/cbuf.h
+++ b/include/libimobiledevice-glue/cbuf.h
@@ -22,14 +22,16 @@
#ifndef __CBUF_H
#define __CBUF_H
+#include <libimobiledevice-glue/glue.h>
+
struct char_buf {
unsigned char* data;
unsigned int length;
unsigned int capacity;
};
-struct char_buf* char_buf_new();
-void char_buf_free(struct char_buf* cbuf);
-void char_buf_append(struct char_buf* cbuf, unsigned int length, unsigned char* data);
+LIMD_GLUE_API struct char_buf* char_buf_new();
+LIMD_GLUE_API void char_buf_free(struct char_buf* cbuf);
+LIMD_GLUE_API void char_buf_append(struct char_buf* cbuf, unsigned int length, unsigned char* data);
#endif /* __CBUF_H */
diff --git a/include/libimobiledevice-glue/collection.h b/include/libimobiledevice-glue/collection.h
index df1680c..46ef461 100644
--- a/include/libimobiledevice-glue/collection.h
+++ b/include/libimobiledevice-glue/collection.h
@@ -22,17 +22,19 @@
#ifndef COLLECTION_H
#define COLLECTION_H
+#include <libimobiledevice-glue/glue.h>
+
struct collection {
void **list;
int capacity;
};
-void collection_init(struct collection *col);
-void collection_add(struct collection *col, void *element);
-int collection_remove(struct collection *col, void *element);
-int collection_count(struct collection *col);
-void collection_free(struct collection *col);
-void collection_copy(struct collection *dest, struct collection *src);
+LIMD_GLUE_API void collection_init(struct collection *col);
+LIMD_GLUE_API void collection_add(struct collection *col, void *element);
+LIMD_GLUE_API int collection_remove(struct collection *col, void *element);
+LIMD_GLUE_API int collection_count(struct collection *col);
+LIMD_GLUE_API void collection_free(struct collection *col);
+LIMD_GLUE_API void collection_copy(struct collection *dest, struct collection *src);
#define MERGE_(a,b) a ## _ ## b
#define LABEL_(a,b) MERGE_(a, b)
diff --git a/include/libimobiledevice-glue/glue.h b/include/libimobiledevice-glue/glue.h
new file mode 100644
index 0000000..e1e9900
--- /dev/null
+++ b/include/libimobiledevice-glue/glue.h
@@ -0,0 +1,37 @@
+/*
+ * glue.h
+ * Common definitions
+ *
+ * Copyright (c) 2024 Nikias Bassen, All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __GLUE_H
+#define __GLUE_H
+
+#ifndef LIMD_GLUE_API
+ #ifdef LIMD_GLUE_STATIC
+ #define LIMD_GLUE_API
+ #elif defined(_WIN32)
+ #define LIMD_GLUE_API __declspec(dllimport)
+ #else
+ #define LIMD_GLUE_API
+ #endif
+#endif
+
+LIMD_GLUE_API const char* libimobiledevice_glue_version();
+
+#endif
diff --git a/include/libimobiledevice-glue/nskeyedarchive.h b/include/libimobiledevice-glue/nskeyedarchive.h
new file mode 100644
index 0000000..5aad4d6
--- /dev/null
+++ b/include/libimobiledevice-glue/nskeyedarchive.h
@@ -0,0 +1,90 @@
+/*
+ * nskeyedarchive.h
+ * Helper code to work with plist files containing NSKeyedArchiver data.
+ *
+ * Copyright (c) 2019 Nikias Bassen, All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef __NSKEYEDARCHIVE_H
+#define __NSKEYEDARCHIVE_H
+
+#include <stdint.h>
+#include <libimobiledevice-glue/glue.h>
+#include <plist/plist.h>
+
+enum nskeyedarchive_class_type_t {
+ NSTYPE_INTEGER = 1,
+ NSTYPE_BOOLEAN,
+ NSTYPE_CHARS,
+ NSTYPE_STRING,
+ NSTYPE_REAL,
+ NSTYPE_ARRAY,
+ NSTYPE_DATA,
+ NSTYPE_INTREF,
+ NSTYPE_NSMUTABLESTRING,
+ NSTYPE_NSSTRING,
+ NSTYPE_NSMUTABLEARRAY,
+ NSTYPE_NSARRAY,
+ NSTYPE_NSMUTABLEDICTIONARY,
+ NSTYPE_NSDICTIONARY,
+ NSTYPE_NSDATE,
+ NSTYPE_NSURL,
+ NSTYPE_NSMUTABLEDATA,
+ NSTYPE_NSDATA,
+ NSTYPE_NSKEYEDARCHIVE,
+ NSTYPE_FROM_PLIST
+};
+
+typedef struct nskeyedarchive_st *nskeyedarchive_t;
+
+LIMD_GLUE_API nskeyedarchive_t nskeyedarchive_new(void);
+LIMD_GLUE_API nskeyedarchive_t nskeyedarchive_new_from_plist(plist_t plist);
+LIMD_GLUE_API nskeyedarchive_t nskeyedarchive_new_from_data(const void* data, uint32_t size);
+LIMD_GLUE_API void nskeyedarchive_free(nskeyedarchive_t ka);
+
+LIMD_GLUE_API void nskeyedarchive_set_top_ref_key_name(nskeyedarchive_t ka, const char* keyname);
+
+LIMD_GLUE_API uint64_t nskeyedarchive_add_top_class(nskeyedarchive_t ka, const char* classname, ...) __attribute__ ((sentinel(0)));
+LIMD_GLUE_API void nskeyedarchive_add_top_class_uid(nskeyedarchive_t ka, uint64_t uid);
+LIMD_GLUE_API void nskeyedarchive_append_class(nskeyedarchive_t ka, const char* classname, ...) __attribute__ ((sentinel(0)));
+LIMD_GLUE_API void nskeyedarchive_append_object(nskeyedarchive_t ka, plist_t object);
+
+LIMD_GLUE_API void nskeyedarchive_nsarray_append_item(nskeyedarchive_t ka, uint64_t uid, enum nskeyedarchive_class_type_t type, ...);
+LIMD_GLUE_API void nskeyedarchive_nsdictionary_add_item(nskeyedarchive_t ka, uint64_t uid, const char* key, enum nskeyedarchive_class_type_t type, ...);
+
+LIMD_GLUE_API void nskeyedarchive_append_class_type_v(nskeyedarchive_t ka, enum nskeyedarchive_class_type_t type, va_list* va);
+LIMD_GLUE_API void nskeyedarchive_append_class_type(nskeyedarchive_t ka, enum nskeyedarchive_class_type_t type, ...);
+
+LIMD_GLUE_API void nskeyedarchive_merge_object(nskeyedarchive_t ka, nskeyedarchive_t pka, plist_t object);
+
+LIMD_GLUE_API void nskeyedarchive_print(nskeyedarchive_t ka);
+LIMD_GLUE_API plist_t nskeyedarchive_get_plist_ref(nskeyedarchive_t ka);
+LIMD_GLUE_API plist_t nskeyedarchive_get_object_by_uid(nskeyedarchive_t ka, uint64_t uid);
+LIMD_GLUE_API plist_t nskeyedarchive_get_class_by_uid(nskeyedarchive_t ka, uint64_t uid);
+LIMD_GLUE_API plist_t nskeyedarchive_get_objects(nskeyedarchive_t ka);
+
+LIMD_GLUE_API uint64_t nskeyedarchive_get_class_uid(nskeyedarchive_t ka, const char* classref);
+LIMD_GLUE_API const char* nskeyedarchive_get_classname(nskeyedarchive_t ka, uint64_t uid);
+
+LIMD_GLUE_API void nskeyedarchive_set_class_property(nskeyedarchive_t ka, uint64_t uid, const char* propname, enum nskeyedarchive_class_type_t proptype, ...);
+LIMD_GLUE_API int nskeyedarchive_get_class_uint64_property(nskeyedarchive_t ka, uint64_t uid, const char* propname, uint64_t* value);
+LIMD_GLUE_API int nskeyedarchive_get_class_int_property(nskeyedarchive_t ka, uint64_t uid, const char* propname, int* value);
+LIMD_GLUE_API int nskeyedarchive_get_class_string_property(nskeyedarchive_t ka, uint64_t uid, const char* propname, char** value);
+LIMD_GLUE_API int nskeyedarchive_get_class_property(nskeyedarchive_t ka, uint64_t uid, const char* propname, plist_t* value);
+
+LIMD_GLUE_API plist_t nskeyedarchive_to_plist(nskeyedarchive_t ka);
+
+#endif
diff --git a/include/libimobiledevice-glue/opack.h b/include/libimobiledevice-glue/opack.h
index 43b1d1d..2d7a94a 100644
--- a/include/libimobiledevice-glue/opack.h
+++ b/include/libimobiledevice-glue/opack.h
@@ -21,9 +21,10 @@
#ifndef __OPACK_H
#define __OPACK_H
+#include <libimobiledevice-glue/glue.h>
#include <plist/plist.h>
-void opack_encode_from_plist(plist_t plist, unsigned char** out, unsigned int* out_len);
-int opack_decode_to_plist(unsigned char* buf, unsigned int buf_len, plist_t* plist_out);
+LIMD_GLUE_API void opack_encode_from_plist(plist_t plist, unsigned char** out, unsigned int* out_len);
+LIMD_GLUE_API int opack_decode_to_plist(unsigned char* buf, unsigned int buf_len, plist_t* plist_out);
#endif /* __OPACK_H */
diff --git a/include/libimobiledevice-glue/sha.h b/include/libimobiledevice-glue/sha.h
new file mode 100644
index 0000000..3a00578
--- /dev/null
+++ b/include/libimobiledevice-glue/sha.h
@@ -0,0 +1,86 @@
+#ifndef __SHA_H
+#define __SHA_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <libimobiledevice-glue/glue.h>
+
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+/* SHA-1 */
+typedef struct sha1_context_ {
+ uint64_t length;
+ uint32_t state[5];
+ size_t curlen;
+ unsigned char buf[64];
+} sha1_context;
+
+#define SHA1_DIGEST_LENGTH 20
+
+LIMD_GLUE_API int sha1_init(sha1_context * md);
+LIMD_GLUE_API int sha1_final(sha1_context * md, unsigned char *out);
+LIMD_GLUE_API int sha1_update(sha1_context * md, const void *data, size_t inlen);
+LIMD_GLUE_API int sha1(const unsigned char *message, size_t message_len, unsigned char *out);
+
+/* SHA-256 */
+typedef struct sha256_context_ {
+ uint64_t length;
+ uint32_t state[8];
+ size_t curlen;
+ unsigned char buf[64];
+ int num_dwords;
+} sha256_context;
+
+#define SHA256_DIGEST_LENGTH 32
+
+LIMD_GLUE_API int sha256_init(sha256_context * md);
+LIMD_GLUE_API int sha256_final(sha256_context * md, unsigned char *out);
+LIMD_GLUE_API int sha256_update(sha256_context * md, const void *data, size_t inlen);
+LIMD_GLUE_API int sha256(const unsigned char *message, size_t message_len, unsigned char *out);
+
+/* SHA-224 */
+#define sha224_context sha256_context
+
+#define SHA224_DIGEST_LENGTH 28
+
+LIMD_GLUE_API int sha224_init(sha224_context * md);
+LIMD_GLUE_API int sha224_final(sha224_context * md, unsigned char *out);
+LIMD_GLUE_API int sha224_update(sha224_context * md, const void *data, size_t inlen);
+LIMD_GLUE_API int sha224(const unsigned char *message, size_t message_len, unsigned char *out);
+
+/* SHA-512 */
+typedef struct sha512_context_ {
+ uint64_t length, state[8];
+ size_t curlen;
+ unsigned char buf[128];
+ int num_qwords;
+} sha512_context;
+
+#define SHA512_DIGEST_LENGTH 64
+
+LIMD_GLUE_API int sha512_init(sha512_context * md);
+LIMD_GLUE_API int sha512_final(sha512_context * md, unsigned char *out);
+LIMD_GLUE_API int sha512_update(sha512_context * md, const void *data, size_t inlen);
+LIMD_GLUE_API int sha512(const unsigned char *message, size_t message_len, unsigned char *out);
+
+/* SHA-384 */
+#define sha384_context sha512_context
+
+#define SHA384_DIGEST_LENGTH 48
+
+LIMD_GLUE_API int sha384_init(sha384_context * md);
+LIMD_GLUE_API int sha384_final(sha384_context * md, unsigned char *out);
+LIMD_GLUE_API int sha384_update(sha384_context * md, const void *data, size_t inlen);
+LIMD_GLUE_API int sha384(const unsigned char *message, size_t message_len, unsigned char *out);
+
+#endif
diff --git a/include/libimobiledevice-glue/socket.h b/include/libimobiledevice-glue/socket.h
index 53f58b8..39391c6 100644
--- a/include/libimobiledevice-glue/socket.h
+++ b/include/libimobiledevice-glue/socket.h
@@ -41,30 +41,32 @@ typedef enum fd_mode fd_mode;
#include <sys/socket.h>
#endif
+#include <libimobiledevice-glue/glue.h>
+
#ifndef WIN32
-int socket_create_unix(const char *filename);
-int socket_connect_unix(const char *filename);
+LIMD_GLUE_API int socket_create_unix(const char *filename);
+LIMD_GLUE_API int socket_connect_unix(const char *filename);
#endif
-int socket_create(const char *addr, uint16_t port);
-int socket_connect_addr(struct sockaddr *addr, uint16_t port);
-int socket_connect(const char *addr, uint16_t port);
-int socket_check_fd(int fd, fd_mode fdm, unsigned int timeout);
-int socket_accept(int fd, uint16_t port);
+LIMD_GLUE_API int socket_create(const char *addr, uint16_t port);
+LIMD_GLUE_API int socket_connect_addr(struct sockaddr *addr, uint16_t port);
+LIMD_GLUE_API int socket_connect(const char *addr, uint16_t port);
+LIMD_GLUE_API int socket_check_fd(int fd, fd_mode fdm, unsigned int timeout);
+LIMD_GLUE_API int socket_accept(int fd, uint16_t port);
-int socket_shutdown(int fd, int how);
-int socket_close(int fd);
+LIMD_GLUE_API int socket_shutdown(int fd, int how);
+LIMD_GLUE_API int socket_close(int fd);
-int socket_receive(int fd, void *data, size_t length);
-int socket_peek(int fd, void *data, size_t length);
-int socket_receive_timeout(int fd, void *data, size_t length, int flags, unsigned int timeout);
-int socket_send(int fd, void *data, size_t length);
+LIMD_GLUE_API int socket_receive(int fd, void *data, size_t length);
+LIMD_GLUE_API int socket_peek(int fd, void *data, size_t length);
+LIMD_GLUE_API int socket_receive_timeout(int fd, void *data, size_t length, int flags, unsigned int timeout);
+LIMD_GLUE_API int socket_send(int fd, void *data, size_t length);
-int socket_get_socket_port(int fd, uint16_t *port);
+LIMD_GLUE_API int socket_get_socket_port(int fd, uint16_t *port);
-void socket_set_verbose(int level);
+LIMD_GLUE_API void socket_set_verbose(int level);
-const char *socket_addr_to_string(struct sockaddr *addr, char *addr_out, size_t addr_out_size);
+LIMD_GLUE_API const char *socket_addr_to_string(struct sockaddr *addr, char *addr_out, size_t addr_out_size);
-int get_primary_mac_address(unsigned char mac_addr_buf[6]);
+LIMD_GLUE_API int get_primary_mac_address(unsigned char mac_addr_buf[6]);
#endif /* SOCKET_SOCKET_H */
diff --git a/include/libimobiledevice-glue/termcolors.h b/include/libimobiledevice-glue/termcolors.h
index 3e03e97..d7799c3 100644
--- a/include/libimobiledevice-glue/termcolors.h
+++ b/include/libimobiledevice-glue/termcolors.h
@@ -26,6 +26,7 @@
#include <stdarg.h>
#include <stdio.h>
+#include <libimobiledevice-glue/glue.h>
#define COLOR_RESET "\e[m"
#define STYLE_NORMAL "\e[0m"
@@ -74,14 +75,14 @@
#define BG_DEFAULT "\e[49m"
/* automatically called by library constructor */
-void term_colors_init();
+LIMD_GLUE_API void term_colors_init();
/* enable / disable terminal colors */
-void term_colors_set_enabled(int en);
+LIMD_GLUE_API void term_colors_set_enabled(int en);
/* color-aware *printf variants */
-int cprintf(const char* fmt, ...);
-int cfprintf(FILE* stream, const char* fmt, ...);
-int cvfprintf(FILE* stream, const char* fmt, va_list vargs);
+LIMD_GLUE_API int cprintf(const char* fmt, ...);
+LIMD_GLUE_API int cfprintf(FILE* stream, const char* fmt, ...);
+LIMD_GLUE_API int cvfprintf(FILE* stream, const char* fmt, va_list vargs);
#endif
diff --git a/include/libimobiledevice-glue/thread.h b/include/libimobiledevice-glue/thread.h
index 2aadc6e..76646b8 100644
--- a/include/libimobiledevice-glue/thread.h
+++ b/include/libimobiledevice-glue/thread.h
@@ -23,16 +23,31 @@
#define __THREAD_H
#include <stddef.h>
+#include <libimobiledevice-glue/glue.h>
#ifdef WIN32
-#include <windows.h>
+typedef void* HANDLE;
typedef HANDLE THREAD_T;
-typedef CRITICAL_SECTION mutex_t;
+#pragma pack(push, 8)
+struct _CRITICAL_SECTION_ST {
+ void* DebugInfo;
+ long LockCount;
+ long RecursionCount;
+ HANDLE OwningThread;
+ HANDLE LockSemaphore;
+#if defined(_WIN64)
+ unsigned __int64 SpinCount;
+#else
+ unsigned long SpinCount;
+#endif
+};
+#pragma pack(pop)
+typedef struct _CRITICAL_SECTION_ST mutex_t;
typedef struct {
HANDLE sem;
} cond_t;
typedef volatile struct {
- LONG lock;
+ long lock;
int state;
} thread_once_t;
#define THREAD_ONCE_INIT {0, 0}
@@ -53,13 +68,13 @@ typedef pthread_once_t thread_once_t;
typedef void* (*thread_func_t)(void* data);
-int thread_new(THREAD_T* thread, thread_func_t thread_func, void* data);
-void thread_detach(THREAD_T thread);
-void thread_free(THREAD_T thread);
-int thread_join(THREAD_T thread);
-int thread_alive(THREAD_T thread);
+LIMD_GLUE_API int thread_new(THREAD_T* thread, thread_func_t thread_func, void* data);
+LIMD_GLUE_API void thread_detach(THREAD_T thread);
+LIMD_GLUE_API void thread_free(THREAD_T thread);
+LIMD_GLUE_API int thread_join(THREAD_T thread);
+LIMD_GLUE_API int thread_alive(THREAD_T thread);
-int thread_cancel(THREAD_T thread);
+LIMD_GLUE_API int thread_cancel(THREAD_T thread);
#ifdef WIN32
#undef HAVE_THREAD_CLEANUP
@@ -71,17 +86,17 @@ int thread_cancel(THREAD_T thread);
#endif
#endif
-void mutex_init(mutex_t* mutex);
-void mutex_destroy(mutex_t* mutex);
-void mutex_lock(mutex_t* mutex);
-void mutex_unlock(mutex_t* mutex);
+LIMD_GLUE_API void mutex_init(mutex_t* mutex);
+LIMD_GLUE_API void mutex_destroy(mutex_t* mutex);
+LIMD_GLUE_API void mutex_lock(mutex_t* mutex);
+LIMD_GLUE_API void mutex_unlock(mutex_t* mutex);
-void thread_once(thread_once_t *once_control, void (*init_routine)(void));
+LIMD_GLUE_API void thread_once(thread_once_t *once_control, void (*init_routine)(void));
-void cond_init(cond_t* cond);
-void cond_destroy(cond_t* cond);
-int cond_signal(cond_t* cond);
-int cond_wait(cond_t* cond, mutex_t* mutex);
-int cond_wait_timeout(cond_t* cond, mutex_t* mutex, unsigned int timeout_ms);
+LIMD_GLUE_API void cond_init(cond_t* cond);
+LIMD_GLUE_API void cond_destroy(cond_t* cond);
+LIMD_GLUE_API int cond_signal(cond_t* cond);
+LIMD_GLUE_API int cond_wait(cond_t* cond, mutex_t* mutex);
+LIMD_GLUE_API int cond_wait_timeout(cond_t* cond, mutex_t* mutex, unsigned int timeout_ms);
#endif
diff --git a/include/libimobiledevice-glue/tlv.h b/include/libimobiledevice-glue/tlv.h
index 895c883..42be4f6 100644
--- a/include/libimobiledevice-glue/tlv.h
+++ b/include/libimobiledevice-glue/tlv.h
@@ -22,6 +22,7 @@
#define __TLV_H
#include <stdint.h>
+#include <libimobiledevice-glue/glue.h>
struct tlv_buf {
unsigned char* data;
@@ -30,13 +31,13 @@ struct tlv_buf {
};
typedef struct tlv_buf* tlv_buf_t;
-tlv_buf_t tlv_buf_new();
-void tlv_buf_free(tlv_buf_t tlv);
+LIMD_GLUE_API tlv_buf_t tlv_buf_new();
+LIMD_GLUE_API void tlv_buf_free(tlv_buf_t tlv);
-void tlv_buf_append(tlv_buf_t tlv, uint8_t tag, unsigned int length, void* data);
-unsigned char* tlv_get_data_ptr(const void* tlv_data, void* tlv_end, uint8_t tag, uint8_t* length);
-int tlv_data_get_uint(const void* tlv_data, unsigned int tlv_length, uint8_t tag, uint64_t* value);
-int tlv_data_get_uint8(const void* tlv_data, unsigned int tlv_length, uint8_t tag, uint8_t* value);
-int tlv_data_copy_data(const void* tlv_data, unsigned int tlv_length, uint8_t tag, void** out, unsigned int* out_len);
+LIMD_GLUE_API void tlv_buf_append(tlv_buf_t tlv, uint8_t tag, unsigned int length, void* data);
+LIMD_GLUE_API unsigned char* tlv_get_data_ptr(const void* tlv_data, void* tlv_end, uint8_t tag, uint8_t* length);
+LIMD_GLUE_API int tlv_data_get_uint(const void* tlv_data, unsigned int tlv_length, uint8_t tag, uint64_t* value);
+LIMD_GLUE_API int tlv_data_get_uint8(const void* tlv_data, unsigned int tlv_length, uint8_t tag, uint8_t* value);
+LIMD_GLUE_API int tlv_data_copy_data(const void* tlv_data, unsigned int tlv_length, uint8_t tag, void** out, unsigned int* out_len);
#endif /* __TLV_H */
diff --git a/include/libimobiledevice-glue/utils.h b/include/libimobiledevice-glue/utils.h
index b8513c0..355f1da 100644
--- a/include/libimobiledevice-glue/utils.h
+++ b/include/libimobiledevice-glue/utils.h
@@ -25,38 +25,20 @@
#ifndef __UTILS_H
#define __UTILS_H
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#ifdef WIN32
-#include <windows.h>
-#endif
-
#include <stdio.h>
-#include <plist/plist.h>
+#include <stdint.h>
+#include <libimobiledevice-glue/glue.h>
#define MAC_EPOCH 978307200
-char *string_concat(const char *str, ...);
-char *string_append(char *str, ...);
-char *string_build_path(const char *elem, ...);
-char *string_format_size(uint64_t size);
-char *string_toupper(char *str);
-char *generate_uuid(void);
-
-int buffer_read_from_filename(const char *filename, char **buffer, uint64_t *length);
-int buffer_write_to_filename(const char *filename, const char *buffer, uint64_t length);
-
-enum plist_format_t {
- PLIST_FORMAT_XML,
- PLIST_FORMAT_BINARY
-};
-
-int plist_read_from_filename(plist_t *plist, const char *filename);
-int plist_write_to_filename(plist_t plist, const char *filename, enum plist_format_t format);
+LIMD_GLUE_API char *string_concat(const char *str, ...);
+LIMD_GLUE_API char *string_append(char *str, ...);
+LIMD_GLUE_API char *string_build_path(const char *elem, ...);
+LIMD_GLUE_API char *string_format_size(uint64_t size);
+LIMD_GLUE_API char *string_toupper(char *str);
+LIMD_GLUE_API char *generate_uuid(void);
-void plist_print_to_stream(plist_t plist, FILE* stream);
-void plist_print_to_stream_with_indentation(plist_t plist, FILE* stream, unsigned int indentation);
+LIMD_GLUE_API int buffer_read_from_filename(const char *filename, char **buffer, uint64_t *length);
+LIMD_GLUE_API int buffer_write_to_filename(const char *filename, const char *buffer, uint64_t length);
#endif
diff --git a/src/Makefile.am b/src/Makefile.am
index b709103..0089b5d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -12,11 +12,16 @@ libimobiledevice_glue_1_0_la_SOURCES = \
socket.c \
thread.c \
utils.c \
+ nskeyedarchive.c \
collection.c \
termcolors.c \
cbuf.c \
opack.c \
tlv.c \
+ sha1.c \
+ sha256.c \
+ sha512.c \
+ fixedint.h \
common.h
if WIN32
diff --git a/src/cbuf.c b/src/cbuf.c
index c7c931f..0beeb2a 100644
--- a/src/cbuf.c
+++ b/src/cbuf.c
@@ -30,7 +30,7 @@
#include "common.h"
#include "libimobiledevice-glue/cbuf.h"
-LIBIMOBILEDEVICE_GLUE_API struct char_buf* char_buf_new()
+struct char_buf* char_buf_new()
{
struct char_buf* cbuf = (struct char_buf*)malloc(sizeof(struct char_buf));
cbuf->capacity = 256;
@@ -39,7 +39,7 @@ LIBIMOBILEDEVICE_GLUE_API struct char_buf* char_buf_new()
return cbuf;
}
-LIBIMOBILEDEVICE_GLUE_API void char_buf_free(struct char_buf* cbuf)
+void char_buf_free(struct char_buf* cbuf)
{
if (cbuf) {
free(cbuf->data);
@@ -47,7 +47,7 @@ LIBIMOBILEDEVICE_GLUE_API void char_buf_free(struct char_buf* cbuf)
}
}
-LIBIMOBILEDEVICE_GLUE_API void char_buf_append(struct char_buf* cbuf, unsigned int length, unsigned char* data)
+void char_buf_append(struct char_buf* cbuf, unsigned int length, unsigned char* data)
{
if (!cbuf || !cbuf->data) {
return;
diff --git a/src/collection.c b/src/collection.c
index ef47217..0744427 100644
--- a/src/collection.c
+++ b/src/collection.c
@@ -37,7 +37,7 @@
#define CAPACITY_STEP 8
-LIBIMOBILEDEVICE_GLUE_API void collection_init(struct collection *col)
+void collection_init(struct collection *col)
{
col->list = malloc(sizeof(void *) * CAPACITY_STEP);
assert(col->list);
@@ -45,14 +45,14 @@ LIBIMOBILEDEVICE_GLUE_API void collection_init(struct collection *col)
col->capacity = CAPACITY_STEP;
}
-LIBIMOBILEDEVICE_GLUE_API void collection_free(struct collection *col)
+void collection_free(struct collection *col)
{
free(col->list);
col->list = NULL;
col->capacity = 0;
}
-LIBIMOBILEDEVICE_GLUE_API void collection_add(struct collection *col, void *element)
+void collection_add(struct collection *col, void *element)
{
int i;
for(i=0; i<col->capacity; i++) {
@@ -69,7 +69,7 @@ LIBIMOBILEDEVICE_GLUE_API void collection_add(struct collection *col, void *elem
col->capacity += CAPACITY_STEP;
}
-LIBIMOBILEDEVICE_GLUE_API int collection_remove(struct collection *col, void *element)
+int collection_remove(struct collection *col, void *element)
{
int i;
for(i=0; i<col->capacity; i++) {
@@ -82,7 +82,7 @@ LIBIMOBILEDEVICE_GLUE_API int collection_remove(struct collection *col, void *el
return -1;
}
-LIBIMOBILEDEVICE_GLUE_API int collection_count(struct collection *col)
+int collection_count(struct collection *col)
{
int i, cnt = 0;
for(i=0; i<col->capacity; i++) {
@@ -92,7 +92,7 @@ LIBIMOBILEDEVICE_GLUE_API int collection_count(struct collection *col)
return cnt;
}
-LIBIMOBILEDEVICE_GLUE_API void collection_copy(struct collection *dest, struct collection *src)
+void collection_copy(struct collection *dest, struct collection *src)
{
if (!dest || !src) return;
dest->capacity = src->capacity;
diff --git a/src/common.h b/src/common.h
index bd22e3d..94b5fdd 100644
--- a/src/common.h
+++ b/src/common.h
@@ -25,14 +25,18 @@
#include <config.h>
#endif
-#ifdef WIN32
-#define LIBIMOBILEDEVICE_GLUE_API __declspec( dllexport )
+#ifdef LIMD_GLUE_STATIC
+ #define LIMD_GLUE_API
+#elif defined(_WIN32)
+ #define LIMD_GLUE_API __declspec( dllexport )
#else
-#ifdef HAVE_FVISIBILITY
-#define LIBIMOBILEDEVICE_GLUE_API __attribute__((visibility("default")))
-#else
-#define LIBIMOBILEDEVICE_GLUE_API
-#endif
+ #if __GNUC__ >= 4
+ #define LIMD_GLUE_API __attribute__((visibility("default")))
+ #else
+ #define LIMD_GLUE_API
+ #endif
#endif
+#include "libimobiledevice-glue/glue.h"
+
#endif
diff --git a/src/fixedint.h b/src/fixedint.h
new file mode 100644
index 0000000..1a8745b
--- /dev/null
+++ b/src/fixedint.h
@@ -0,0 +1,72 @@
+/*
+ Portable header to provide the 32 and 64 bits type.
+
+ Not a compatible replacement for <stdint.h>, do not blindly use it as such.
+*/
+
+#if ((defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) || (defined(__WATCOMC__) && (defined(_STDINT_H_INCLUDED) || __WATCOMC__ >= 1250)) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_) || defined(__UINT_FAST64_TYPE__)) )) && !defined(FIXEDINT_H_INCLUDED)
+ #include <stdint.h>
+ #define FIXEDINT_H_INCLUDED
+
+ #if defined(__WATCOMC__) && __WATCOMC__ >= 1250 && !defined(UINT64_C)
+ #include <limits.h>
+ #define UINT64_C(x) (x + (UINT64_MAX - UINT64_MAX))
+ #endif
+#endif
+
+
+#ifndef FIXEDINT_H_INCLUDED
+ #define FIXEDINT_H_INCLUDED
+
+ #include <limits.h>
+
+ /* (u)int32_t */
+ #ifndef uint32_t
+ #if (ULONG_MAX == 0xffffffffUL)
+ typedef unsigned long uint32_t;
+ #elif (UINT_MAX == 0xffffffffUL)
+ typedef unsigned int uint32_t;
+ #elif (USHRT_MAX == 0xffffffffUL)
+ typedef unsigned short uint32_t;
+ #endif
+ #endif
+
+
+ #ifndef int32_t
+ #if (LONG_MAX == 0x7fffffffL)
+ typedef signed long int32_t;
+ #elif (INT_MAX == 0x7fffffffL)
+ typedef signed int int32_t;
+ #elif (SHRT_MAX == 0x7fffffffL)
+ typedef signed short int32_t;
+ #endif
+ #endif
+
+
+ /* (u)int64_t */
+ #if (defined(__STDC__) && defined(__STDC_VERSION__) && __STDC__ && __STDC_VERSION__ >= 199901L)
+ typedef long long int64_t;
+ typedef unsigned long long uint64_t;
+
+ #define UINT64_C(v) v ##ULL
+ #define INT64_C(v) v ##LL
+ #elif defined(__GNUC__)
+ __extension__ typedef long long int64_t;
+ __extension__ typedef unsigned long long uint64_t;
+
+ #define UINT64_C(v) v ##ULL
+ #define INT64_C(v) v ##LL
+ #elif defined(__MWERKS__) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) || defined(__APPLE_CC__) || defined(_LONG_LONG) || defined(_CRAYC)
+ typedef long long int64_t;
+ typedef unsigned long long uint64_t;
+
+ #define UINT64_C(v) v ##ULL
+ #define INT64_C(v) v ##LL
+ #elif (defined(__WATCOMC__) && defined(__WATCOM_INT64__)) || (defined(_MSC_VER) && _INTEGRAL_MAX_BITS >= 64) || (defined(__BORLANDC__) && __BORLANDC__ > 0x460) || defined(__alpha) || defined(__DECC)
+ typedef __int64 int64_t;
+ typedef unsigned __int64 uint64_t;
+
+ #define UINT64_C(v) v ##UI64
+ #define INT64_C(v) v ##I64
+ #endif
+#endif
diff --git a/src/glue.c b/src/glue.c
index 7970679..1499a0d 100644
--- a/src/glue.c
+++ b/src/glue.c
@@ -78,3 +78,11 @@ BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved)
#else
#warning No compiler support for constructor/destructor attributes, some features might not be available.
#endif
+
+const char* libimobiledevice_glue_version()
+{
+#ifndef PACKAGE_VERSION
+#error PACKAGE_VERSION is not defined!
+#endif
+ return PACKAGE_VERSION;
+}
diff --git a/src/nskeyedarchive.c b/src/nskeyedarchive.c
new file mode 100644
index 0000000..b3dbdc4
--- /dev/null
+++ b/src/nskeyedarchive.c
@@ -0,0 +1,1228 @@
+/*
+ * nskeyedarchive.c
+ * Helper code to work with plist files containing NSKeyedArchiver data.
+ *
+ * Copyright (c) 2019 Nikias Bassen, All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <plist/plist.h>
+#include "common.h"
+#include "libimobiledevice-glue/nskeyedarchive.h"
+
+#define NS_KEYED_ARCHIVER_NAME "NSKeyedArchiver"
+#define NS_KEYED_ARCHIVER_VERSION 100000
+
+struct nskeyedarchive_st {
+ plist_t dict;
+ uint64_t uid;
+};
+
+nskeyedarchive_t nskeyedarchive_new(void)
+{
+ plist_t dict = plist_new_dict();
+ plist_dict_set_item(dict, "$version", plist_new_uint(NS_KEYED_ARCHIVER_VERSION));
+ plist_t objects = plist_new_array();
+ plist_array_append_item(objects, plist_new_string("$null"));
+ plist_dict_set_item(dict, "$objects", objects);
+ plist_dict_set_item(dict, "$archiver", plist_new_string(NS_KEYED_ARCHIVER_NAME));
+
+ nskeyedarchive_t nskeyed = (nskeyedarchive_t)malloc(sizeof(struct nskeyedarchive_st));
+ nskeyed->dict = dict;
+ nskeyed->uid = 1;
+ return nskeyed;
+}
+
+void nskeyedarchive_free(nskeyedarchive_t ka)
+{
+ if (ka) {
+ if (ka->dict) {
+ plist_free(ka->dict);
+ }
+ free(ka);
+ }
+}
+
+void nskeyedarchive_set_top_ref_key_name(nskeyedarchive_t ka, const char* keyname)
+{
+ if (!ka) {
+ return;
+ }
+ plist_t top = plist_dict_get_item(ka->dict, "$top");
+ if (top) {
+ plist_dict_iter iter = NULL;
+ plist_dict_new_iter(top, &iter);
+ if (iter) {
+ plist_t node = NULL;
+ char* keyn = NULL;
+ plist_dict_next_item(top, iter, &keyn, &node);
+ plist_t keynode = plist_dict_item_get_key(node);
+ plist_set_key_val(keynode, keyname);
+ free(keyn);
+ free(iter);
+ }
+ }
+}
+
+plist_t nskeyedarchive_get_objects(nskeyedarchive_t ka)
+{
+ plist_t objects = plist_dict_get_item(ka->dict, "$objects");
+ if (!objects || (plist_get_node_type(objects) != PLIST_ARRAY)) {
+ fprintf(stderr, "ERROR: $objects node not found!\n");
+ return NULL;
+ }
+
+ return objects;
+}
+
+plist_t nskeyedarchive_get_object_by_uid(nskeyedarchive_t ka, uint64_t uid)
+{
+ plist_t objects = nskeyedarchive_get_objects(ka);
+ if (!objects) {
+ return NULL;
+ }
+
+ plist_t obj = plist_array_get_item(objects, (uint32_t)uid);
+ if (!obj) {
+ fprintf(stderr, "ERROR: unable to get object node with uid %llu\n", (long long)uid);
+ return NULL;
+ }
+
+ return obj;
+}
+
+plist_t nskeyedarchive_get_class_by_uid(nskeyedarchive_t ka, uint64_t uid)
+{
+ plist_t ret = nskeyedarchive_get_object_by_uid(ka, uid);
+ if (ret && (plist_get_node_type(ret) != PLIST_DICT)) {
+ fprintf(stderr, "ERROR: the uid %llu does not reference a valid class with node type PLIST_DICT!\n", (long long)uid);
+ return NULL;
+ }
+
+ return ret;
+}
+
+void nskeyedarchive_append_object(nskeyedarchive_t ka, plist_t object)
+{
+ plist_t objects = nskeyedarchive_get_objects(ka);
+ if (objects && plist_get_node_type(objects) != PLIST_ARRAY) {
+ fprintf(stderr, "ERROR: unable to append object\n");
+ return;
+ }
+
+ plist_array_append_item(objects, object);
+}
+
+static void nskeyedarchive_append_class_v(nskeyedarchive_t ka, const char* classname, va_list* va)
+{
+ if (!ka) {
+ fprintf(stderr, "%s: ERROR: invalid keyed archive!\n", __func__);
+ return;
+ } else if (!classname) {
+ fprintf(stderr, "%s: ERROR: missing classname!\n", __func__);
+ return;
+ }
+
+ char* arg = NULL;
+ plist_t classes = NULL;
+ do {
+ arg = (char*)va_arg(*va, char*);
+ if (!arg) {
+ break;
+ }
+ if (!classes) {
+ classes = plist_new_array();
+ plist_array_append_item(classes, plist_new_string(classname));
+ }
+ plist_array_append_item(classes, plist_new_string(arg));
+ } while (arg);
+
+ plist_t cls = plist_new_dict();
+ plist_dict_set_item(cls, "$class", plist_new_uid(++ka->uid));
+
+ nskeyedarchive_append_object(ka, cls);
+
+ cls = plist_new_dict();
+ if (classes) {
+ plist_dict_set_item(cls, "$classes", classes);
+ }
+ plist_dict_set_item(cls, "$classname", plist_new_string(classname));
+
+ nskeyedarchive_append_object(ka, cls);
+}
+
+void nskeyedarchive_append_class(nskeyedarchive_t ka, const char* classname, ...)
+{
+ if (!ka) {
+ fprintf(stderr, "%s: ERROR: invalid keyed archive!\n", __func__);
+ return;
+ } else if (!classname) {
+ fprintf(stderr, "%s: ERROR: missing classname!\n", __func__);
+ return;
+ }
+
+ va_list va;
+ va_start(va, classname);
+ nskeyedarchive_append_class_v(ka, classname, &va);
+ va_end(va);
+}
+
+void nskeyedarchive_add_top_class_uid(nskeyedarchive_t ka, uint64_t uid)
+{
+ plist_t top = plist_dict_get_item(ka->dict, "$top");
+ if (!top) {
+ top = plist_new_dict();
+ plist_dict_set_item(top, "$0", plist_new_uid(uid));
+ plist_dict_set_item(ka->dict, "$top", top);
+ } else {
+ uint32_t num = plist_dict_get_size(top);
+ char newkey[8];
+ sprintf(newkey, "$%d", num);
+ plist_dict_set_item(top, newkey, plist_new_uid(uid));
+ }
+}
+
+uint64_t nskeyedarchive_add_top_class(nskeyedarchive_t ka, const char* classname, ...)
+{
+ if (!ka) {
+ fprintf(stderr, "%s: ERROR: invalid keyed archive!\n", __func__);
+ return 0;
+ } else if (!classname) {
+ fprintf(stderr, "%s: ERROR: missing classname!\n", __func__);
+ return 0;
+ }
+
+ uint64_t uid = ka->uid;
+
+ va_list va;
+ va_start(va, classname);
+ nskeyedarchive_append_class_v(ka, classname, &va);
+ va_end(va);
+
+ nskeyedarchive_add_top_class_uid(ka, uid);
+ return uid;
+}
+
+static void nskeyedarchive_set_class_property_v(nskeyedarchive_t ka, uint64_t uid, const char* propname, enum nskeyedarchive_class_type_t proptype, va_list* va);
+
+static void nskeyedarchive_nsarray_append(nskeyedarchive_t ka, plist_t array, enum nskeyedarchive_class_type_t type, ...);
+
+static void nskeyedarchive_nsarray_append_v(nskeyedarchive_t ka, plist_t array, enum nskeyedarchive_class_type_t type, va_list* va)
+{
+ if (!ka) {
+ fprintf(stderr, "%s: ERROR: invalid keyed archive!\n", __func__);
+ return;
+ } else if (!array) {
+ fprintf(stderr, "%s: ERROR: missing plist!\n", __func__);
+ return;
+ }
+
+ uint64_t newuid;
+
+ switch (type) {
+ case NSTYPE_INTEGER:
+ plist_array_append_item(array, plist_new_uint(va_arg(*va, int)));
+ break;
+ case NSTYPE_INTREF:
+ plist_array_append_item(array, plist_new_uid(++ka->uid));
+ nskeyedarchive_append_object(ka, plist_new_uint(va_arg(*va, int)));
+ break;
+ case NSTYPE_BOOLEAN:
+ plist_array_append_item(array, plist_new_uid(++ka->uid));
+ nskeyedarchive_append_object(ka, plist_new_bool(va_arg(*va, int)));
+ break;
+ case NSTYPE_CHARS:
+ plist_array_append_item(array, plist_new_string(va_arg(*va, char*)));
+ break;
+ case NSTYPE_STRING:
+ plist_array_append_item(array, plist_new_uid(++ka->uid));
+ nskeyedarchive_append_object(ka, plist_new_string(va_arg(*va, char*)));
+ break;
+ case NSTYPE_REAL:
+ plist_array_append_item(array, plist_new_uid(++ka->uid));
+ nskeyedarchive_append_object(ka, plist_new_real(va_arg(*va, double)));
+ break;
+ case NSTYPE_NSMUTABLESTRING:
+ case NSTYPE_NSSTRING:
+ plist_array_append_item(array, plist_new_uid(++ka->uid));
+ newuid = ka->uid;
+ if (type == NSTYPE_NSMUTABLESTRING) {
+ nskeyedarchive_append_class(ka, "NSMutableString", "NSString", "NSObject", NULL);
+ } else {
+ nskeyedarchive_append_class(ka, "NSString", "NSObject", NULL);
+ }
+ nskeyedarchive_set_class_property(ka, newuid, "NS.string", NSTYPE_CHARS, va_arg(*va, char*));
+ break;
+ case NSTYPE_NSMUTABLEARRAY:
+ case NSTYPE_NSARRAY:
+ plist_array_append_item(array, plist_new_uid(++ka->uid));
+ newuid = ka->uid;
+ if (type == NSTYPE_NSMUTABLEARRAY) {
+ nskeyedarchive_append_class(ka, "NSMutableArray", "NSArray", "NSObject", NULL);
+ } else {
+ nskeyedarchive_append_class(ka, "NSArray", "NSObject", NULL);
+ }
+ {
+ plist_t arr = plist_new_array();
+ do {
+ int ptype = va_arg(*va, int);
+ if (ptype == 0)
+ break;
+ nskeyedarchive_nsarray_append_v(ka, arr, ptype, va);
+ } while (1);
+ nskeyedarchive_set_class_property(ka, newuid, "NS.objects", NSTYPE_ARRAY, arr);
+ plist_free(arr);
+ }
+ break;
+ case NSTYPE_NSMUTABLEDICTIONARY:
+ case NSTYPE_NSDICTIONARY:
+ plist_array_append_item(array, plist_new_uid(++ka->uid));
+ newuid = ka->uid;
+ if (type == NSTYPE_NSMUTABLEDICTIONARY) {
+ nskeyedarchive_append_class(ka, "NSMutableDictionary", "NSDictionary", "NSObject", NULL);
+ } else {
+ nskeyedarchive_append_class(ka, "NSDictionary", "NSObject", NULL);
+ }
+ {
+ plist_t keyarr = plist_new_array();
+ plist_t valarr = plist_new_array();
+ do {
+ char* key = va_arg(*va, char*);
+ if (!key)
+ break;
+ int ptype = va_arg(*va, int);
+ if (ptype == 0)
+ break;
+ nskeyedarchive_nsarray_append(ka, keyarr, NSTYPE_STRING, key);
+ nskeyedarchive_nsarray_append_v(ka, valarr, ptype, va);
+ } while (1);
+ nskeyedarchive_set_class_property(ka, newuid, "NS.keys", NSTYPE_ARRAY, keyarr);
+ nskeyedarchive_set_class_property(ka, newuid, "NS.objects", NSTYPE_ARRAY, valarr);
+ plist_free(keyarr);
+ plist_free(valarr);
+ }
+ break;
+ case NSTYPE_NSDATE:
+ plist_array_append_item(array, plist_new_uid(++ka->uid));
+ newuid = ka->uid;
+ nskeyedarchive_append_class(ka, "NSDate", "NSObject", NULL);
+ nskeyedarchive_set_class_property(ka, newuid, "NS.time", NSTYPE_REAL, va_arg(*va, double));
+ break;
+ case NSTYPE_NSMUTABLEDATA:
+ case NSTYPE_NSDATA:
+ plist_array_append_item(array, plist_new_uid(++ka->uid));
+ newuid = ka->uid;
+ nskeyedarchive_append_class(ka, "NSMutableData", "NSData", "NSObject", NULL);
+ nskeyedarchive_set_class_property(ka, newuid, "NS.data", NSTYPE_DATA, va_arg(*va, char*));
+ break;
+ case NSTYPE_NSURL:
+ plist_array_append_item(array, plist_new_uid(++ka->uid));
+ newuid = ka->uid;
+ nskeyedarchive_append_class(ka, "NSURL", "NSObject", NULL);
+ {
+ int ptype = va_arg(*va, int);
+ if (ptype == 0)
+ break;
+ nskeyedarchive_set_class_property_v(ka, newuid, "NS.base", ptype, va);
+ ptype = va_arg(*va, int);
+ if (ptype == 0)
+ break;
+ nskeyedarchive_set_class_property_v(ka, newuid, "NS.relative", ptype, va);
+ }
+ break;
+ case NSTYPE_NSKEYEDARCHIVE:
+ {
+ nskeyedarchive_t pka = va_arg(*va, nskeyedarchive_t);
+ if (!pka) {
+ fprintf(stderr, "%s: ERROR: no nskeyedarchive argument given for type NSTYPE_NSKEYEDARCHIVE\n", __func__);
+ return;
+ }
+ uint64_t top = nskeyedarchive_get_class_uid(pka, NULL);
+ if (top != 0) {
+ plist_array_append_item(array, plist_new_uid(++ka->uid));
+
+ plist_t object = nskeyedarchive_get_object_by_uid(pka, top);
+ if (!object) {
+ fprintf(stderr, "%s: ERROR: can't get object for uid %lld\n", __func__, (long long)top);
+ return;
+ }
+
+ plist_t objcopy = plist_copy(object);
+ nskeyedarchive_append_object(ka, objcopy);
+ nskeyedarchive_merge_object(ka, pka, objcopy);
+ }
+ }
+ break;
+ case NSTYPE_FROM_PLIST:
+ {
+ plist_t plist = va_arg(*va, plist_t);
+ if (!plist) {
+ fprintf(stderr, "%s: ERROR: no plist argument given for NSTYPE_PLIST\n", __func__);
+ return;
+ }
+ switch (plist_get_node_type(plist)) {
+ case PLIST_STRING:
+ {
+ char* str = NULL;
+ plist_get_string_val(plist, &str);
+ nskeyedarchive_nsarray_append(ka, array, NSTYPE_NSMUTABLESTRING, str, NULL);
+ } break;
+ case PLIST_DICT:
+ {
+ plist_array_append_item(array, plist_new_uid(++ka->uid));
+ newuid = ka->uid;
+ nskeyedarchive_append_class(ka, "NSDictionary", "NSObject", NULL);
+
+ plist_t keyarr = plist_new_array();
+ plist_t valarr = plist_new_array();
+
+ plist_dict_iter iter = NULL;
+ plist_dict_new_iter(plist, &iter);
+
+ char *key = NULL;
+ plist_t node = NULL;
+
+ do {
+ plist_dict_next_item(plist, iter, &key, &node);
+ if (key) {
+ int ptype = 0;
+ uint8_t bv = 0;
+ uint64_t u64val = 0;
+ int intval = 0;
+ char *str = NULL;
+ void *val = NULL;
+ nskeyedarchive_nsarray_append(ka, keyarr, NSTYPE_STRING, key);
+ switch (plist_get_node_type(node)) {
+ case PLIST_BOOLEAN: {
+ ptype = NSTYPE_BOOLEAN;
+ plist_get_bool_val(node, &bv);
+ intval = bv;
+ val = &intval;
+ } break;
+ case PLIST_UINT:
+ ptype = NSTYPE_INTEGER;
+ plist_get_uint_val(node, &u64val);
+ val = &u64val;
+ break;
+ case PLIST_STRING:
+ ptype = NSTYPE_STRING;
+ plist_get_string_val(node, &str);
+ val = str;
+ break;
+ default:
+ fprintf(stderr, "Unhandled plist type when parsing plist_dict\n");
+ break;
+ }
+ nskeyedarchive_nsarray_append(ka, valarr, ptype, val);
+ }
+ free(key);
+ } while (node);
+
+ free(iter);
+
+ nskeyedarchive_set_class_property(ka, newuid, "NS.keys", NSTYPE_ARRAY, keyarr);
+ nskeyedarchive_set_class_property(ka, newuid, "NS.objects", NSTYPE_ARRAY, valarr);
+ plist_free(keyarr);
+ plist_free(valarr);
+ } break;
+ default:
+ fprintf(stderr, "%s: ERROR: unhandled plist type %d\n", __func__, plist_get_node_type(plist));
+ return;
+ }
+ }
+ break;
+ default:
+ fprintf(stderr, "%s: unexpected type %d\n", __func__, type);
+ break;
+ }
+}
+
+static void nskeyedarchive_nsarray_append(nskeyedarchive_t ka, plist_t array, enum nskeyedarchive_class_type_t type, ...)
+{
+ va_list va;
+ va_start(va, type);
+ nskeyedarchive_nsarray_append_v(ka, array, type, &va);
+ va_end(va);
+}
+
+void nskeyedarchive_nsarray_append_item(nskeyedarchive_t ka, uint64_t uid, enum nskeyedarchive_class_type_t type, ...)
+{
+ if (!ka) {
+ return;
+ }
+ plist_t objects = NULL;
+ nskeyedarchive_get_class_property(ka, uid, "NS.objects", &objects);
+ if (!objects) {
+ fprintf(stderr, "ERROR: invalid NSArray object in archive: missing NS.objects property\n");
+ return;
+ }
+ va_list va;
+ va_start(va, type);
+ nskeyedarchive_nsarray_append_v(ka, objects, type, &va);
+ va_end(va);
+}
+
+void nskeyedarchive_nsdictionary_add_item(nskeyedarchive_t ka, uint64_t uid, const char* key, enum nskeyedarchive_class_type_t type, ...)
+{
+ if (!ka) {
+ return;
+ }
+ plist_t keys = NULL;
+ nskeyedarchive_get_class_property(ka, uid, "NS.keys", &keys);
+ if (!keys) {
+ fprintf(stderr, "ERROR: invalid NSDictionary object in archive: missing NS.keys property\n");
+ return;
+ }
+ plist_t objects = NULL;
+ nskeyedarchive_get_class_property(ka, uid, "NS.objects", &objects);
+ if (!objects) {
+ fprintf(stderr, "ERROR: invalid NSDictionary object in archive: missing NS.objects property\n");
+ return;
+ }
+ va_list va;
+ va_start(va, type);
+ nskeyedarchive_nsarray_append(ka, keys, NSTYPE_STRING, key);
+ nskeyedarchive_nsarray_append_v(ka, objects, type, &va);
+ va_end(va);
+}
+
+void nskeyedarchive_append_class_type_v(nskeyedarchive_t ka, enum nskeyedarchive_class_type_t type, va_list* va)
+{
+ uint64_t newuid = 0;
+
+ switch (type) {
+ case NSTYPE_INTEGER:
+ fprintf(stderr, "%s: ERROR: NSTYPE_INTEGER is not an object type, can't add it as class!.\n", __func__);
+ break;
+ case NSTYPE_INTREF:
+ nskeyedarchive_append_object(ka, plist_new_uint(va_arg(*va, int)));
+ break;
+ case NSTYPE_BOOLEAN:
+ nskeyedarchive_append_object(ka, plist_new_bool(va_arg(*va, int)));
+ break;
+ case NSTYPE_CHARS:
+ fprintf(stderr, "%s: ERROR: NSTYPE_CHARS is not an object type, can't add it as class!\n", __func__);
+ break;
+ case NSTYPE_STRING:
+ {
+ char* strval = va_arg(*va, char*);
+ if (strval) {
+ if (strcmp(strval, "$null") != 0) {
+ nskeyedarchive_append_object(ka, plist_new_string(strval));
+ } else {
+ // make $null the top class if required
+ plist_t top = plist_dict_get_item(ka->dict, "$top");
+ if (!top) {
+ top = plist_new_dict();
+ plist_dict_set_item(top, "$0", plist_new_uid(0));
+ plist_dict_set_item(ka->dict, "$top", top);
+ }
+ }
+ }
+ }
+ break;
+ case NSTYPE_REAL:
+ nskeyedarchive_append_object(ka, plist_new_real(va_arg(*va, double)));
+ break;
+ case NSTYPE_ARRAY:
+ fprintf(stderr, "%s: ERROR: NSTYPE_ARRAY is not an object type, can't add it as class!\n", __func__);
+ return;
+ case NSTYPE_NSMUTABLESTRING:
+ case NSTYPE_NSSTRING:
+ newuid = ka->uid;
+ if (type == NSTYPE_NSMUTABLESTRING) {
+ nskeyedarchive_append_class(ka, "NSMutableString", "NSString", "NSObject", NULL);
+ } else {
+ nskeyedarchive_append_class(ka, "NSString", "NSObject", NULL);
+ }
+ nskeyedarchive_set_class_property(ka, newuid, "NS.string", NSTYPE_STRING, va_arg(*va, char*));
+ break;
+ case NSTYPE_NSMUTABLEARRAY:
+ case NSTYPE_NSARRAY:
+ newuid = ka->uid;
+ if (type == NSTYPE_NSMUTABLEARRAY) {
+ nskeyedarchive_append_class(ka, "NSMutableArray", "NSArray", "NSObject", NULL);
+ } else {
+ nskeyedarchive_append_class(ka, "NSArray", "NSObject", NULL);
+ }
+ {
+ plist_t arr = plist_new_array();
+ do {
+ int ptype = va_arg(*va, int);
+ if (ptype == 0)
+ break;
+ nskeyedarchive_nsarray_append_v(ka, arr, ptype, va);
+ } while (1);
+ nskeyedarchive_set_class_property(ka, newuid, "NS.objects", NSTYPE_ARRAY, arr);
+ plist_free(arr);
+ }
+ break;
+ case NSTYPE_NSMUTABLEDICTIONARY:
+ case NSTYPE_NSDICTIONARY:
+ newuid = ka->uid;
+ if (type == NSTYPE_NSMUTABLEDICTIONARY) {
+ nskeyedarchive_append_class(ka, "NSMutableDictionary", "NSDictionary", "NSObject", NULL);
+ } else {
+ nskeyedarchive_append_class(ka, "NSDictionary", "NSObject", NULL);
+ }
+ {
+ plist_t keyarr = plist_new_array();
+ plist_t valarr = plist_new_array();
+ do {
+ char* key = va_arg(*va, char*);
+ if (!key)
+ break;
+ int ptype = va_arg(*va, int);
+ if (ptype == 0)
+ break;
+ nskeyedarchive_nsarray_append(ka, keyarr, NSTYPE_STRING, key);
+ nskeyedarchive_nsarray_append_v(ka, valarr, ptype, va);
+ } while (1);
+ nskeyedarchive_set_class_property(ka, newuid, "NS.keys", NSTYPE_ARRAY, keyarr);
+ nskeyedarchive_set_class_property(ka, newuid, "NS.objects", NSTYPE_ARRAY, valarr);
+ plist_free(keyarr);
+ plist_free(valarr);
+ }
+ break;
+ case NSTYPE_NSDATE:
+ newuid = ka->uid;
+ nskeyedarchive_append_class(ka, "NSDate", "NSObject", NULL);
+ nskeyedarchive_set_class_property(ka, newuid, "NS.time", NSTYPE_REAL, va_arg(*va, double));
+ break;
+ case NSTYPE_NSMUTABLEDATA:
+ case NSTYPE_NSDATA:
+ newuid = ka->uid;
+ nskeyedarchive_append_class(ka, "NSMutableData", "NSData", "NSObject", NULL);
+ nskeyedarchive_set_class_property(ka, newuid, "NS.data", NSTYPE_DATA, va_arg(*va, char*));
+ break;
+ case NSTYPE_NSURL:
+ newuid = ka->uid;
+ nskeyedarchive_append_class(ka, "NSURL", "NSObject", NULL);
+ {
+ int ptype = va_arg(*va, int);
+ if (ptype == 0)
+ break;
+ nskeyedarchive_set_class_property_v(ka, newuid, "NS.base", ptype, va);
+ ptype = va_arg(*va, int);
+ if (ptype == 0)
+ break;
+ nskeyedarchive_set_class_property_v(ka, newuid, "NS.relative", ptype, va);
+ }
+ break;
+ default:
+ fprintf(stderr, "unexpected class type %d\n", type);
+ return;
+ }
+
+ plist_t top = plist_dict_get_item(ka->dict, "$top");
+ if (!top) {
+ top = plist_new_dict();
+ plist_dict_set_item(top, "$0", plist_new_uid(1));
+ plist_dict_set_item(ka->dict, "$top", top);
+ }
+}
+
+void nskeyedarchive_append_class_type(nskeyedarchive_t ka, enum nskeyedarchive_class_type_t type, ...)
+{
+ if (!ka) {
+ fprintf(stderr, "%s: ERROR: invalid keyed archive!\n", __func__);
+ return;
+ } else if (!type) {
+ fprintf(stderr, "%s: ERROR: invalid class type!\n", __func__);
+ return;
+ }
+
+ va_list va;
+ va_start(va, type);
+ nskeyedarchive_append_class_type_v(ka, type, &va);
+ va_end(va);
+}
+
+void nskeyedarchive_merge_object(nskeyedarchive_t ka, nskeyedarchive_t pka, plist_t object)
+{
+ if (!ka || !pka || !object) {
+ return;
+ }
+
+ switch (plist_get_node_type(object)) {
+ case PLIST_DICT:
+ {
+ plist_dict_iter iter = NULL;
+ plist_dict_new_iter(object, &iter);
+ if (iter) {
+ plist_t val;
+ char* key;
+ do {
+ key = NULL;
+ val = NULL;
+ plist_dict_next_item(object, iter, &key, &val);
+ if (key) {
+ switch (plist_get_node_type(val)) {
+ case PLIST_UID:
+ {
+ uint64_t thisuid = 0;
+ plist_get_uid_val(val, &thisuid);
+ if (thisuid > 0) {
+ // remap thisuid to ka->uid+1
+ plist_t nextobj = nskeyedarchive_get_object_by_uid(pka, thisuid);
+ plist_set_uid_val(val, ++ka->uid);
+ plist_t nextcopy = plist_copy(nextobj);
+ nskeyedarchive_append_object(ka, nextcopy);
+ nskeyedarchive_merge_object(ka, pka, nextcopy);
+ }
+ }
+ break;
+ case PLIST_DICT:
+ case PLIST_ARRAY:
+ nskeyedarchive_merge_object(ka, pka, val);
+ break;
+ default:
+ break;
+ }
+ free(key);
+ }
+ } while (val);
+ free(iter);
+ }
+ }
+ break;
+ case PLIST_ARRAY:
+ {
+ uint32_t i;
+ for (i = 0; i < plist_array_get_size(object); i++) {
+ plist_t val = plist_array_get_item(object, i);
+ switch (plist_get_node_type(val)) {
+ case PLIST_UID:
+ {
+ uint64_t thisuid = 0;
+ plist_get_uid_val(val, &thisuid);
+ if (thisuid > 0) {
+ // remap thisuid to ka->uid+1
+ plist_t nextobj = nskeyedarchive_get_object_by_uid(pka, thisuid);
+ plist_set_uid_val(val, ++ka->uid);
+ plist_t nextcopy = plist_copy(nextobj);
+ nskeyedarchive_append_object(ka, nextcopy);
+ nskeyedarchive_merge_object(ka, pka, nextcopy);
+ }
+ }
+ break;
+ case PLIST_ARRAY:
+ case PLIST_DICT:
+ nskeyedarchive_merge_object(ka, pka, val);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+}
+
+static void nskeyedarchive_set_class_property_v(nskeyedarchive_t ka, uint64_t uid, const char* propname, enum nskeyedarchive_class_type_t proptype, va_list* va)
+{
+ plist_t a = nskeyedarchive_get_class_by_uid(ka, uid);
+ if (a == NULL)
+ return;
+
+ uint64_t newuid;
+
+ switch (proptype) {
+ case NSTYPE_INTEGER:
+ plist_dict_set_item(a, propname, plist_new_uint(va_arg(*va, int)));
+ break;
+ case NSTYPE_INTREF:
+ plist_dict_set_item(a, propname, plist_new_uid(++ka->uid));
+ nskeyedarchive_append_object(ka, plist_new_uint(va_arg(*va, int)));
+ break;
+ case NSTYPE_BOOLEAN:
+ plist_dict_set_item(a, propname, plist_new_uid(++ka->uid));
+ nskeyedarchive_append_object(ka, plist_new_bool(va_arg(*va, int)));
+ break;
+ case NSTYPE_CHARS:
+ plist_dict_set_item(a, propname, plist_new_string(va_arg(*va, char*)));
+ break;
+ case NSTYPE_STRING:
+ {
+ char* strval = va_arg(*va, char*);
+ if (strval && (strcmp(strval, "$null") == 0)) {
+ plist_dict_set_item(a, propname, plist_new_uid(0));
+ } else {
+ plist_dict_set_item(a, propname, plist_new_uid(++ka->uid));
+ nskeyedarchive_append_object(ka, plist_new_string(strval));
+ }
+ }
+ break;
+ case NSTYPE_REAL:
+ plist_dict_set_item(a, propname, plist_new_uid(++ka->uid));
+ nskeyedarchive_append_class_type_v(ka, proptype, va);
+ break;
+ case NSTYPE_ARRAY:
+ plist_dict_set_item(a, propname, plist_copy(va_arg(*va, plist_t)));
+ break;
+ case NSTYPE_NSMUTABLESTRING:
+ case NSTYPE_NSSTRING:
+ plist_dict_set_item(a, propname, plist_new_uid(++ka->uid));
+ nskeyedarchive_append_class_type_v(ka, proptype, va);
+ break;
+ case NSTYPE_NSMUTABLEARRAY:
+ case NSTYPE_NSARRAY:
+ plist_dict_set_item(a, propname, plist_new_uid(++ka->uid));
+ nskeyedarchive_append_class_type_v(ka, proptype, va);
+ break;
+ case NSTYPE_NSMUTABLEDICTIONARY:
+ case NSTYPE_NSDICTIONARY:
+ plist_dict_set_item(a, propname, plist_new_uid(++ka->uid));
+ nskeyedarchive_append_class_type_v(ka, proptype, va);
+ break;
+ case NSTYPE_NSDATE:
+ plist_dict_set_item(a, propname, plist_new_uid(++ka->uid));
+ nskeyedarchive_append_class_type_v(ka, proptype, va);
+ break;
+ case NSTYPE_NSMUTABLEDATA:
+ case NSTYPE_NSDATA:
+ plist_dict_set_item(a, propname, plist_new_uid(++ka->uid));
+ nskeyedarchive_append_class_type_v(ka, proptype, va);
+ break;
+ case NSTYPE_NSURL:
+ plist_dict_set_item(a, propname, plist_new_uid(++ka->uid));
+ nskeyedarchive_append_class_type_v(ka, proptype, va);
+ break;
+ case NSTYPE_NSKEYEDARCHIVE:
+ {
+ nskeyedarchive_t pka = va_arg(*va, nskeyedarchive_t);
+ if (!pka) {
+ fprintf(stderr, "%s: ERROR: no nskeyedarchive argument given for type NSTYPE_NSKEYEDARCHIVE\n", __func__);
+ return;
+ }
+ uint64_t top = nskeyedarchive_get_class_uid(pka, NULL);
+ if (top != 0) {
+ plist_t object = nskeyedarchive_get_object_by_uid(pka, top);
+ if (!object) {
+ fprintf(stderr, "%s: ERROR: can't get object for uid %lld\n", __func__, (long long)top);
+ return;
+ }
+
+ plist_dict_set_item(a, propname, plist_new_uid(++ka->uid));
+ plist_t objcopy = plist_copy(object);
+ nskeyedarchive_append_object(ka, objcopy);
+ nskeyedarchive_merge_object(ka, pka, objcopy);
+ } else {
+ plist_dict_set_item(a, propname, plist_new_uid(0));
+ }
+ }
+ break;
+ case NSTYPE_FROM_PLIST:
+ {
+ plist_t plist = va_arg(*va, plist_t);
+ if (!plist) {
+ fprintf(stderr, "%s: ERROR: no plist argument given for NSTYPE_PLIST\n", __func__);
+ return;
+ }
+ switch (plist_get_node_type(plist)) {
+ case PLIST_ARRAY:
+ plist_dict_set_item(a, propname, plist_new_uid(++ka->uid));
+ newuid = ka->uid;
+ nskeyedarchive_append_class(ka, "NSMutableArray", "NSArray", "NSObject", NULL);
+ {
+ plist_t arr = plist_new_array();
+ uint32_t ai;
+ for (ai = 0; ai < plist_array_get_size(plist); ai++) {
+ plist_t ae = plist_array_get_item(plist, ai);
+ nskeyedarchive_nsarray_append(ka, arr, NSTYPE_FROM_PLIST, ae);
+ }
+ nskeyedarchive_set_class_property(ka, newuid, "NS.objects", NSTYPE_ARRAY, arr);
+ }
+ break;
+ default:
+ fprintf(stderr, "%s: sorry, plist type %d is not implemented for conversion.\n", __func__, plist_get_node_type(plist));
+ break;
+ }
+ }
+ break;
+ default:
+ fprintf(stderr, "unexpected property type %d\n", proptype);
+ break;
+ }
+}
+
+void nskeyedarchive_set_class_property(nskeyedarchive_t ka, uint64_t uid, const char* propname, enum nskeyedarchive_class_type_t proptype, ...)
+{
+ plist_t a = nskeyedarchive_get_class_by_uid(ka, uid);
+ if (a == NULL) {
+ return;
+ }
+
+ va_list va;
+ va_start(va, proptype);
+ nskeyedarchive_set_class_property_v(ka, uid, propname, proptype, &va);
+ va_end(va);
+}
+
+
+void nskeyedarchive_print(nskeyedarchive_t ka)
+{
+ char* xml = NULL;
+ uint32_t xlen = 0;
+ plist_to_xml(ka->dict, &xml, &xlen);
+ puts(xml);
+ free(xml);
+}
+
+plist_t nskeyedarchive_get_plist_ref(nskeyedarchive_t ka)
+{
+ return ka->dict;
+}
+
+nskeyedarchive_t nskeyedarchive_new_from_plist(plist_t plist)
+{
+ if (!plist || (plist_get_node_type(plist) != PLIST_DICT)) {
+ fprintf(stderr, "%s: ERROR: invalid parameter, PLIST_DICT expected\n", __func__);
+ return NULL;
+ }
+
+ plist_t node;
+ char* strval = NULL;
+ uint64_t uintval = 0;
+
+ // check for $archiver key
+ node = plist_dict_get_item(plist, "$archiver");
+ if (node && (plist_get_node_type(node) == PLIST_STRING)) {
+ plist_get_string_val(node, &strval);
+ }
+ if (!strval || (strcmp(strval, "NSKeyedArchiver") != 0)) {
+ fprintf(stderr, "%s: ERROR: plist is not in NSKeyedArchiver format ($archiver key not found or invalid)!\n", __func__);
+ if (strval)
+ free(strval);
+ return NULL;
+ }
+ if (strval)
+ free(strval);
+ strval = NULL;
+
+ // check for $version key
+ node = plist_dict_get_item(plist, "$version");
+ if (node && (plist_get_node_type(node) == PLIST_UINT)) {
+ plist_get_uint_val(node, &uintval);
+ }
+ if (uintval != 100000) {
+ fprintf(stderr, "%s: ERROR: unexpected NSKeyedArchiver version encountered (%lld != 100000)!\n", __func__, (long long int)uintval);
+ return NULL;
+ }
+ uintval = 0;
+
+ // check for $top key
+ node = plist_dict_get_item(plist, "$top");
+ if (!node || (plist_get_node_type(node) != PLIST_DICT)) {
+ fprintf(stderr, "%s: ERROR: $top node not found\n", __func__);
+ return NULL;
+ }
+ plist_t topuid = plist_dict_get_item(node, "$0");
+ if (!topuid) {
+ topuid = plist_dict_get_item(node, "root");
+ }
+ if (!topuid || (plist_get_node_type(topuid) != PLIST_UID)) {
+ fprintf(stderr, "%s: ERROR: uid '$0' or 'root' not found in $top dict!\n", __func__);
+ return NULL;
+ }
+
+ uintval = -1LL;
+ plist_get_uid_val(topuid, (uint64_t*)&uintval);
+
+ if (uintval == (uint64_t)-1LL) {
+ fprintf(stderr, "%s: ERROR: could not get UID value.\n", __func__);
+ return NULL;
+ }
+
+ // check for $objects key
+ plist_t objects = plist_dict_get_item(plist, "$objects");
+ if (!objects || (plist_get_node_type(objects) != PLIST_ARRAY)) {
+ fprintf(stderr, "%s: ERROR: $objects node not found!\n", __func__);
+ return NULL;
+ }
+ plist_t obj = plist_array_get_item(objects, (uint32_t)uintval);
+ if (!obj) {
+ fprintf(stderr, "%s: ERROR: can't get object node\n", __func__);
+ return NULL;
+ }
+
+ nskeyedarchive_t archive = (nskeyedarchive_t)malloc(sizeof(struct nskeyedarchive_st));
+ archive->dict = plist_copy(plist);
+ archive->uid = plist_array_get_size(objects) - 1;
+
+ return archive;
+}
+
+nskeyedarchive_t nskeyedarchive_new_from_data(const void* data, uint32_t size)
+{
+ if (!data || (size < 8)) {
+ fprintf(stderr, "%s: ERROR: invalid parameter\n", __func__);
+ return NULL;
+ }
+
+
+ plist_t plist = NULL;
+ if (memcmp(data, "bplist00", 8) == 0) {
+ plist_from_bin(data, size, &plist);
+ } else if ((memcmp(data, "<?xml", 5) == 0) || (memcmp(data, "<plist", 6) == 0)) {
+ plist_from_xml(data, size, &plist);
+ } else {
+ // fail silently
+ return NULL;
+ }
+ if (!plist) {
+ fprintf(stderr, "%s: ERROR: Can't parse plist from data\n", __func__);
+ return NULL;
+ }
+
+ nskeyedarchive_t ka = nskeyedarchive_new_from_plist(plist);
+ plist_free(plist);
+ return ka;
+}
+
+uint64_t nskeyedarchive_get_class_uid(nskeyedarchive_t ka, const char* classref)
+{
+ uint64_t uintval = -1LL;
+ if (!ka) {
+ return uintval;
+ }
+ if (!ka->dict) {
+ return uintval;
+ }
+
+ plist_t node;
+
+ node = plist_dict_get_item(ka->dict, "$top");
+ if (!node || (plist_get_node_type(node) != PLIST_DICT)) {
+ fprintf(stderr, "%s: ERROR: $top node not found\n", __func__);
+ return 0;
+ }
+ plist_t topuid = plist_dict_get_item(node, (classref) ? classref : "$0");
+ if (!topuid && !classref) {
+ topuid = plist_dict_get_item(node, "root");
+ }
+ if (!topuid || (plist_get_node_type(topuid) != PLIST_UID)) {
+ fprintf(stderr, "%s: ERROR: uid for '%s' not found in $top dict!\n", __func__, classref);
+ return 0;
+ }
+
+ plist_get_uid_val(topuid, (uint64_t*)&uintval);
+
+ return uintval;
+}
+
+const char* nskeyedarchive_get_classname(nskeyedarchive_t ka, uint64_t uid)
+{
+ if (!ka) {
+ return NULL;
+ }
+ if (!ka->dict) {
+ return NULL;
+ }
+
+ plist_t obj = nskeyedarchive_get_object_by_uid(ka, uid);
+ if (!obj) {
+ return NULL;
+ }
+
+ plist_t classuid = plist_dict_get_item(obj, "$class");
+ if (plist_get_node_type(classuid) != PLIST_UID) {
+ fprintf(stderr, "ERROR: $class is not a uid node\n");
+ return NULL;
+ }
+
+ uint64_t uintval = 0;
+ plist_get_uid_val(classuid, &uintval);
+ if (uintval == 0) {
+ fprintf(stderr, "ERROR: can't get $class uid val\n");
+ return NULL;
+ }
+
+ plist_t cls = nskeyedarchive_get_class_by_uid(ka, uintval);
+ if (!cls) {
+ return NULL;
+ }
+
+ plist_t classname = plist_dict_get_item(cls, "$classname");
+ if (!classname || (plist_get_node_type(classname) != PLIST_STRING)) {
+ fprintf(stderr, "ERROR: invalid $classname in class dict\n");
+ return NULL;
+ }
+
+ return plist_get_string_ptr(classname, NULL);
+}
+
+int nskeyedarchive_get_class_property(nskeyedarchive_t ka, uint64_t uid, const char* propname, plist_t* value)
+{
+ if (!ka || !ka->dict || !value) {
+ return -1;
+ }
+
+ plist_t obj = nskeyedarchive_get_class_by_uid(ka, uid);
+ if (!obj) {
+ return -1;
+ }
+
+ *value = plist_dict_get_item(obj, propname);
+ if (!*value) {
+ return -1;
+ }
+
+ return 0;
+}
+
+int nskeyedarchive_get_class_uint64_property(nskeyedarchive_t ka, uint64_t uid, const char* propname, uint64_t* value)
+{
+ plist_t prop = NULL;
+
+ nskeyedarchive_get_class_property(ka, uid, propname, &prop);
+ if (!prop) {
+ fprintf(stderr, "%s: ERROR: no such property '%s'\n", __func__, propname);
+ return -1;
+ }
+
+ if (plist_get_node_type(prop) == PLIST_UID) {
+ uint64_t uintval = 0;
+ plist_get_uid_val(prop, &uintval);
+ prop = nskeyedarchive_get_object_by_uid(ka, uintval);
+ }
+
+ if (plist_get_node_type(prop) != PLIST_UINT) {
+ fprintf(stderr, "%s: ERROR: property '%s' is not of type integer.\n", __func__, propname);
+ return -1;
+ }
+
+ plist_get_uint_val(prop, value);
+
+ return 0;
+}
+
+int nskeyedarchive_get_class_int_property(nskeyedarchive_t ka, uint64_t uid, const char* propname, int* value)
+{
+ uint64_t uintval = 0;
+ int res = nskeyedarchive_get_class_uint64_property(ka, uid, propname, &uintval);
+ if (res < 0) {
+ return res;
+ }
+ *value = (int)uintval;
+ return 0;
+}
+
+int nskeyedarchive_get_class_string_property(nskeyedarchive_t ka, uint64_t uid, const char* propname, char** value)
+{
+ plist_t node = NULL;
+
+ nskeyedarchive_get_class_property(ka, uid, propname, &node);
+ if (!node || (plist_get_node_type(node) != PLIST_UID)) {
+ return -1;
+ }
+
+ uint64_t uintval = 0;
+ plist_get_uid_val(node, &uintval);
+
+ plist_t prop = nskeyedarchive_get_object_by_uid(ka, uintval);
+ if (!prop || (plist_get_node_type(prop) != PLIST_STRING)) {
+ fprintf(stderr, "%s: ERROR: property '%s' is not a string\n", __func__, propname);
+ return -1;
+ }
+
+ plist_get_string_val(prop, value);
+
+ return 0;
+}
+
+static plist_t _nska_parse_object(nskeyedarchive_t ka, uint64_t uid)
+{
+ plist_t obj = nskeyedarchive_get_object_by_uid(ka, uid);
+ switch (plist_get_node_type(obj)) {
+ case PLIST_BOOLEAN:
+ case PLIST_INT:
+ case PLIST_STRING:
+ return plist_copy(obj);
+ default:
+ break;
+ }
+
+ const char* clsn = nskeyedarchive_get_classname(ka, uid);
+ plist_t pl = NULL;
+ if (!strcmp(clsn, "NSMutableDictionary") || !strcmp(clsn, "NSDictionary")) {
+ plist_t keys = NULL;
+ nskeyedarchive_get_class_property(ka, uid, "NS.keys", &keys);
+ plist_t vals = NULL;
+ nskeyedarchive_get_class_property(ka, uid, "NS.objects", &vals);
+
+ uint32_t count = plist_array_get_size(keys);
+ if (count != plist_array_get_size(vals)) {
+ printf("ERROR: %s: inconsistent number of keys vs. values in dictionary object\n", __func__);
+ return NULL;
+ }
+ pl = plist_new_dict();
+ uint32_t i = 0;
+ for (i = 0; i < count; i++) {
+ plist_t knode = plist_array_get_item(keys, i);
+ plist_t vnode = plist_array_get_item(vals, i);
+
+ uint64_t subuid = 0;
+ plist_get_uid_val(knode, &subuid);
+ plist_t newkey = _nska_parse_object(ka, subuid);
+
+ subuid = 0;
+ plist_get_uid_val(vnode, &subuid);
+ plist_t newval = _nska_parse_object(ka, subuid);
+
+ if (!PLIST_IS_STRING(newkey)) {
+ printf("ERROR: %s: key node is not of string type.\n", __func__);
+ return NULL;
+ }
+
+ plist_dict_set_item(pl, plist_get_string_ptr(newkey, NULL), newval);
+ plist_free(newkey);
+ }
+ } else if (!strcmp(clsn, "NSMutableArray") || !strcmp(clsn, "NSArray")) {
+ plist_t vals = NULL;
+ nskeyedarchive_get_class_property(ka, uid, "NS.objects", &vals);
+
+ uint32_t count = plist_array_get_size(vals);
+ pl = plist_new_array();
+ uint32_t i = 0;
+ for (i = 0; i < count; i++) {
+ plist_t vnode = plist_array_get_item(vals, i);
+ uint64_t subuid = 0;
+ plist_get_uid_val(vnode, &subuid);
+ plist_t newval = _nska_parse_object(ka, subuid);
+ plist_array_append_item(pl, newval);
+ }
+ } else {
+ printf("ERROR: %s: unhandled class type '%s'\n", __func__, clsn);
+ }
+ return pl;
+}
+
+plist_t nskeyedarchive_to_plist(nskeyedarchive_t ka)
+{
+ uint64_t obj_uid = nskeyedarchive_get_class_uid(ka, NULL);
+ return _nska_parse_object(ka, obj_uid);
+}
diff --git a/src/opack.c b/src/opack.c
index 9e7fa73..8a9264a 100644
--- a/src/opack.c
+++ b/src/opack.c
@@ -206,7 +206,7 @@ static void opack_encode_node(plist_t node, struct char_buf* cbuf)
if (len >> 32) {
uint8_t blen = 0x94;
char_buf_append(cbuf, 1, &blen);
- uint32_t u64val = htole64(len);
+ uint64_t u64val = htole64(len);
char_buf_append(cbuf, 8, (unsigned char*)&u64val);
} else {
uint8_t blen = 0x93;
@@ -237,7 +237,7 @@ static void opack_encode_node(plist_t node, struct char_buf* cbuf)
}
}
-LIBIMOBILEDEVICE_GLUE_API void opack_encode_from_plist(plist_t plist, unsigned char** out, unsigned int* out_len)
+void opack_encode_from_plist(plist_t plist, unsigned char** out, unsigned int* out_len)
{
if (!plist || !out || !out_len) {
return;
@@ -304,11 +304,11 @@ static int opack_decode_obj(unsigned char** p, unsigned char* end, plist_t* plis
} else if (type == 0x32) {
uint32_t u32val = *(uint32_t*)*p;
value = (int32_t)le32toh(u32val);
- (p)+=4;
+ (*p)+=4;
} else if (type == 0x33) {
uint64_t u64val = *(uint64_t*)*p;
value = le64toh(u64val);
- (p)+=8;
+ (*p)+=8;
} else {
fprintf(stderr, "%s: ERROR: Invalid encoded byte '%02x'\n", __func__, type);
*p = end;
@@ -462,7 +462,7 @@ static int opack_decode_obj(unsigned char** p, unsigned char* end, plist_t* plis
return 0;
}
-LIBIMOBILEDEVICE_GLUE_API int opack_decode_to_plist(unsigned char* buf, unsigned int buf_len, plist_t* plist_out)
+int opack_decode_to_plist(unsigned char* buf, unsigned int buf_len, plist_t* plist_out)
{
if (!buf || buf_len == 0 || !plist_out) {
return -1;
diff --git a/src/sha1.c b/src/sha1.c
new file mode 100644
index 0000000..46bb8c0
--- /dev/null
+++ b/src/sha1.c
@@ -0,0 +1,517 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtomcrypt.com
+ */
+
+#include "common.h"
+#include "libimobiledevice-glue/sha.h"
+
+#include "fixedint.h"
+
+#define ROLc(x, y) \
+ ( (((unsigned long)(x)<<(unsigned long)((y)&31)) | \
+ (((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
+#define ROL ROLc
+
+#define STORE32H(x, y) \
+ { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \
+ (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); }
+
+#define LOAD32H(x, y) \
+ { x = ((unsigned long)((y)[0] & 255)<<24) | \
+ ((unsigned long)((y)[1] & 255)<<16) | \
+ ((unsigned long)((y)[2] & 255)<<8) | \
+ ((unsigned long)((y)[3] & 255)); }
+
+#define STORE64H(x, y) \
+ { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \
+ (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \
+ (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \
+ (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); }
+
+#define F0(x,y,z) (z ^ (x & (y ^ z)))
+#define F1(x,y,z) (x ^ y ^ z)
+#define F2(x,y,z) ((x & y) | (z & (x | y)))
+#define F3(x,y,z) (x ^ y ^ z)
+#ifndef MIN
+ #define MIN(x, y) ( ((x)<(y))?(x):(y) )
+#endif
+
+static int sha1_compress(sha1_context *md, unsigned char *buf)
+{
+ uint32_t a,b,c,d,e,W[80],i;
+ uint32_t t;
+ /* copy the state into 512-bits into W[0..15] */
+ for (i = 0; i < 16; i++) {
+ LOAD32H(W[i], buf + (4*i));
+ }
+ /* copy state */
+ a = md->state[0];
+ b = md->state[1];
+ c = md->state[2];
+ d = md->state[3];
+ e = md->state[4];
+ /* expand it */
+ for (i = 16; i < 80; i++) {
+ W[i] = ROL(W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16], 1);
+ }
+ /* compress */
+ /* round one */
+ #define FF0(a,b,c,d,e,i) e = (ROLc(a, 5) + F0(b,c,d) + e + W[i] + 0x5a827999UL); b = ROLc(b, 30);
+ #define FF1(a,b,c,d,e,i) e = (ROLc(a, 5) + F1(b,c,d) + e + W[i] + 0x6ed9eba1UL); b = ROLc(b, 30);
+ #define FF2(a,b,c,d,e,i) e = (ROLc(a, 5) + F2(b,c,d) + e + W[i] + 0x8f1bbcdcUL); b = ROLc(b, 30);
+ #define FF3(a,b,c,d,e,i) e = (ROLc(a, 5) + F3(b,c,d) + e + W[i] + 0xca62c1d6UL); b = ROLc(b, 30);
+
+ for (i = 0; i < 20; ) {
+ FF0(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t;
+ }
+ for (; i < 40; ) {
+ FF1(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t;
+ }
+ for (; i < 60; ) {
+ FF2(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t;
+ }
+ for (; i < 80; ) {
+ FF3(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t;
+ }
+
+ #undef FF0
+ #undef FF1
+ #undef FF2
+ #undef FF3
+
+ /* store */
+ md->state[0] = md->state[0] + a;
+ md->state[1] = md->state[1] + b;
+ md->state[2] = md->state[2] + c;
+ md->state[3] = md->state[3] + d;
+ md->state[4] = md->state[4] + e;
+ return 0;
+}
+
+/**
+ Initialize the hash state
+ @param md The hash state you wish to initialize
+ @return 0 if successful
+*/
+int sha1_init(sha1_context * md)
+{
+ if (md == NULL) return 1;
+ md->state[0] = 0x67452301UL;
+ md->state[1] = 0xefcdab89UL;
+ md->state[2] = 0x98badcfeUL;
+ md->state[3] = 0x10325476UL;
+ md->state[4] = 0xc3d2e1f0UL;
+ md->curlen = 0;
+ md->length = 0;
+ return 0;
+}
+
+/**
+ Process a block of memory though the hash
+ @param md The hash state
+ @param data The data to hash
+ @param inlen The length of the data (octets)
+ @return 0 if successful
+*/
+int sha1_update (sha1_context * md, const void *data, size_t inlen)
+{
+ const unsigned char* in = (const unsigned char*)data;
+ size_t n;
+ size_t i;
+ int err;
+ if (md == NULL) return 1;
+ if (in == NULL) return 1;
+ if (md->curlen > sizeof(md->buf)) {
+ return 1;
+ }
+ while (inlen > 0) {
+ if (md->curlen == 0 && inlen >= 64) {
+ if ((err = sha1_compress (md, (unsigned char *)in)) != 0) {
+ return err;
+ }
+ md->length += 64 * 8;
+ in += 64;
+ inlen -= 64;
+ } else {
+ n = MIN(inlen, (64 - md->curlen));
+
+ for (i = 0; i < n; i++) {
+ md->buf[i + md->curlen] = in[i];
+ }
+
+
+ md->curlen += n;
+ in += n;
+ inlen -= n;
+ if (md->curlen == 64) {
+ if ((err = sha1_compress (md, md->buf)) != 0) {
+ return err;
+ }
+ md->length += 8*64;
+ md->curlen = 0;
+ }
+ }
+ }
+ return 0;
+}
+
+/**
+ Terminate the hash to get the digest
+ @param md The hash state
+ @param out [out] The destination of the hash (20 bytes)
+ @return 0 if successful
+*/
+int sha1_final(sha1_context * md, unsigned char *out)
+{
+ int i;
+ if (md == NULL) return 1;
+ if (out == NULL) return 1;
+ if (md->curlen >= sizeof(md->buf)) {
+ return 1;
+ }
+ /* increase the length of the message */
+ md->length += md->curlen * 8;
+ /* append the '1' bit */
+ md->buf[md->curlen++] = (unsigned char)0x80;
+ /* if the length is currently above 56 bytes we append zeros
+ * then compress. Then we can fall back to padding zeros and length
+ * encoding like normal.
+ */
+ if (md->curlen > 56) {
+ while (md->curlen < 64) {
+ md->buf[md->curlen++] = (unsigned char)0;
+ }
+ sha1_compress(md, md->buf);
+ md->curlen = 0;
+ }
+ /* pad upto 56 bytes of zeroes */
+ while (md->curlen < 56) {
+ md->buf[md->curlen++] = (unsigned char)0;
+ }
+ /* store length */
+ STORE64H(md->length, md->buf+56);
+ sha1_compress(md, md->buf);
+ /* copy output */
+ for (i = 0; i < 5; i++) {
+ STORE32H(md->state[i], out+(4*i));
+ }
+ return 0;
+}
+
+int sha1(const unsigned char *message, size_t message_len, unsigned char *out)
+{
+ sha1_context ctx;
+ int ret;
+ if ((ret = sha1_init(&ctx))) return ret;
+ if ((ret = sha1_update(&ctx, message, message_len))) return ret;
+ if ((ret = sha1_final(&ctx, out))) return ret;
+ return 0;
+}
+
+#if 0
+
+/*
+SHA-1 in C
+By Steve Reid <steve@edmweb.com>
+100% Public Domain
+Test Vectors (from FIPS PUB 180-1)
+"abc"
+ A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+ 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+A million repetitions of "a"
+ 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+*/
+
+/* #define LITTLE_ENDIAN * This should be #define'd already, if true. */
+/* #define SHA1HANDSOFF * Copies data before messing with it. */
+
+#define SHA1HANDSOFF
+
+#include <stdio.h>
+#include <string.h>
+
+/* for uint32_t */
+#include <stdint.h>
+
+#include "common.h"
+#include "libimobiledevice-glue/sha.h"
+
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+/* blk0() and blk() perform the initial expand. */
+/* I got the idea of expanding during the round function from SSLeay */
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
+ |(rol(block->l[i],8)&0x00FF00FF))
+#elif BYTE_ORDER == BIG_ENDIAN
+#define blk0(i) block->l[i]
+#else
+#error "Endianness not defined!"
+#endif
+#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
+ ^block->l[(i+2)&15]^block->l[i&15],1))
+
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
+#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
+#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+
+
+/* Hash a single 512-bit block. This is the core of the algorithm. */
+
+static void SHA1Transform(
+ uint32_t state[5],
+ const unsigned char buffer[64]
+)
+{
+ uint32_t a, b, c, d, e;
+
+ typedef union
+ {
+ unsigned char c[64];
+ uint32_t l[16];
+ } CHAR64LONG16;
+
+#ifdef SHA1HANDSOFF
+ CHAR64LONG16 block[1]; /* use array to appear as a pointer */
+
+ memcpy(block, buffer, 64);
+#else
+ /* The following had better never be used because it causes the
+ * pointer-to-const buffer to be cast into a pointer to non-const.
+ * And the result is written through. I threw a "const" in, hoping
+ * this will cause a diagnostic.
+ */
+ CHAR64LONG16 *block = (const CHAR64LONG16 *) buffer;
+#endif
+ /* Copy context->state[] to working vars */
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+ e = state[4];
+ /* 4 rounds of 20 operations each. Loop unrolled. */
+ R0(a, b, c, d, e, 0);
+ R0(e, a, b, c, d, 1);
+ R0(d, e, a, b, c, 2);
+ R0(c, d, e, a, b, 3);
+ R0(b, c, d, e, a, 4);
+ R0(a, b, c, d, e, 5);
+ R0(e, a, b, c, d, 6);
+ R0(d, e, a, b, c, 7);
+ R0(c, d, e, a, b, 8);
+ R0(b, c, d, e, a, 9);
+ R0(a, b, c, d, e, 10);
+ R0(e, a, b, c, d, 11);
+ R0(d, e, a, b, c, 12);
+ R0(c, d, e, a, b, 13);
+ R0(b, c, d, e, a, 14);
+ R0(a, b, c, d, e, 15);
+ R1(e, a, b, c, d, 16);
+ R1(d, e, a, b, c, 17);
+ R1(c, d, e, a, b, 18);
+ R1(b, c, d, e, a, 19);
+ R2(a, b, c, d, e, 20);
+ R2(e, a, b, c, d, 21);
+ R2(d, e, a, b, c, 22);
+ R2(c, d, e, a, b, 23);
+ R2(b, c, d, e, a, 24);
+ R2(a, b, c, d, e, 25);
+ R2(e, a, b, c, d, 26);
+ R2(d, e, a, b, c, 27);
+ R2(c, d, e, a, b, 28);
+ R2(b, c, d, e, a, 29);
+ R2(a, b, c, d, e, 30);
+ R2(e, a, b, c, d, 31);
+ R2(d, e, a, b, c, 32);
+ R2(c, d, e, a, b, 33);
+ R2(b, c, d, e, a, 34);
+ R2(a, b, c, d, e, 35);
+ R2(e, a, b, c, d, 36);
+ R2(d, e, a, b, c, 37);
+ R2(c, d, e, a, b, 38);
+ R2(b, c, d, e, a, 39);
+ R3(a, b, c, d, e, 40);
+ R3(e, a, b, c, d, 41);
+ R3(d, e, a, b, c, 42);
+ R3(c, d, e, a, b, 43);
+ R3(b, c, d, e, a, 44);
+ R3(a, b, c, d, e, 45);
+ R3(e, a, b, c, d, 46);
+ R3(d, e, a, b, c, 47);
+ R3(c, d, e, a, b, 48);
+ R3(b, c, d, e, a, 49);
+ R3(a, b, c, d, e, 50);
+ R3(e, a, b, c, d, 51);
+ R3(d, e, a, b, c, 52);
+ R3(c, d, e, a, b, 53);
+ R3(b, c, d, e, a, 54);
+ R3(a, b, c, d, e, 55);
+ R3(e, a, b, c, d, 56);
+ R3(d, e, a, b, c, 57);
+ R3(c, d, e, a, b, 58);
+ R3(b, c, d, e, a, 59);
+ R4(a, b, c, d, e, 60);
+ R4(e, a, b, c, d, 61);
+ R4(d, e, a, b, c, 62);
+ R4(c, d, e, a, b, 63);
+ R4(b, c, d, e, a, 64);
+ R4(a, b, c, d, e, 65);
+ R4(e, a, b, c, d, 66);
+ R4(d, e, a, b, c, 67);
+ R4(c, d, e, a, b, 68);
+ R4(b, c, d, e, a, 69);
+ R4(a, b, c, d, e, 70);
+ R4(e, a, b, c, d, 71);
+ R4(d, e, a, b, c, 72);
+ R4(c, d, e, a, b, 73);
+ R4(b, c, d, e, a, 74);
+ R4(a, b, c, d, e, 75);
+ R4(e, a, b, c, d, 76);
+ R4(d, e, a, b, c, 77);
+ R4(c, d, e, a, b, 78);
+ R4(b, c, d, e, a, 79);
+ /* Add the working vars back into context.state[] */
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+ state[4] += e;
+ /* Wipe variables */
+ a = b = c = d = e = 0;
+#ifdef SHA1HANDSOFF
+ memset(block, '\0', sizeof(block));
+#endif
+}
+
+
+/* SHA1Init - Initialize new context */
+
+void sha1_init(
+ sha1_context * context
+)
+{
+ /* SHA1 initialization constants */
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xEFCDAB89;
+ context->state[2] = 0x98BADCFE;
+ context->state[3] = 0x10325476;
+ context->state[4] = 0xC3D2E1F0;
+ context->count[0] = context->count[1] = 0;
+}
+
+
+/* Run your data through this. */
+
+void sha1_update(
+ sha1_context * context,
+ const void *data,
+ size_t len
+)
+{
+ size_t i;
+
+ size_t j;
+
+ j = context->count[0];
+ if ((context->count[0] += len << 3) < j)
+ context->count[1]++;
+ context->count[1] += (len >> 29);
+ j = (j >> 3) & 63;
+ if ((j + len) > 63)
+ {
+ memcpy(&context->buffer[j], data, (i = 64 - j));
+ SHA1Transform(context->state, context->buffer);
+ for (; i + 63 < len; i += 64)
+ {
+ SHA1Transform(context->state, (unsigned char*)data + i);
+ }
+ j = 0;
+ }
+ else
+ i = 0;
+ memcpy(&context->buffer[j], (unsigned char*)data + i, len - i);
+}
+
+
+/* Add padding and return the message digest. */
+
+void sha1_final(
+ sha1_context * context,
+ unsigned char digest[20]
+)
+{
+ unsigned i;
+
+ unsigned char finalcount[8];
+
+ unsigned char c;
+
+#if 0 /* untested "improvement" by DHR */
+ /* Convert context->count to a sequence of bytes
+ * in finalcount. Second element first, but
+ * big-endian order within element.
+ * But we do it all backwards.
+ */
+ unsigned char *fcp = &finalcount[8];
+
+ for (i = 0; i < 2; i++)
+ {
+ uint32_t t = context->count[i];
+
+ int j;
+
+ for (j = 0; j < 4; t >>= 8, j++)
+ *--fcp = (unsigned char) t}
+#else
+ for (i = 0; i < 8; i++)
+ {
+ finalcount[i] = (unsigned char) ((context->count[(i >= 4 ? 0 : 1)] >> ((3 - (i & 3)) * 8)) & 255); /* Endian independent */
+ }
+#endif
+ c = 0200;
+ sha1_update(context, &c, 1);
+ while ((context->count[0] & 504) != 448)
+ {
+ c = 0000;
+ sha1_update(context, &c, 1);
+ }
+ sha1_update(context, finalcount, 8); /* Should cause a SHA1Transform() */
+ for (i = 0; i < 20; i++)
+ {
+ digest[i] = (unsigned char)
+ ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255);
+ }
+ /* Wipe variables */
+ memset(context, '\0', sizeof(*context));
+ memset(&finalcount, '\0', sizeof(finalcount));
+}
+
+void sha1(
+ const unsigned char *str,
+ size_t len,
+ unsigned char *hash_out
+)
+{
+ sha1_context ctx;
+ size_t ii;
+
+ sha1_init(&ctx);
+ for (ii=0; ii<len; ii+=1)
+ sha1_update(&ctx, str + ii, 1);
+ sha1_final(&ctx, hash_out);
+}
+
+
+#endif
diff --git a/src/sha256.c b/src/sha256.c
new file mode 100644
index 0000000..71be516
--- /dev/null
+++ b/src/sha256.c
@@ -0,0 +1,265 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtomcrypt.com
+ */
+
+#include "common.h"
+#include "libimobiledevice-glue/sha.h"
+
+#include "fixedint.h"
+
+/* the K array */
+static const uint32_t K[64] = {
+ 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL,
+ 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL,
+ 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL,
+ 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
+ 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL,
+ 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL,
+ 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL,
+ 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
+ 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL,
+ 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL,
+ 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL,
+ 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
+ 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
+};
+
+/* Various logical functions */
+
+#define RORc(x, y) \
+ ( ((((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)((y)&31)) | \
+ ((unsigned long)(x)<<(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
+
+#define STORE32H(x, y) \
+ { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \
+ (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); }
+
+#define LOAD32H(x, y) \
+ { x = ((unsigned long)((y)[0] & 255)<<24) | \
+ ((unsigned long)((y)[1] & 255)<<16) | \
+ ((unsigned long)((y)[2] & 255)<<8) | \
+ ((unsigned long)((y)[3] & 255)); }
+
+#define STORE64H(x, y) \
+ { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \
+ (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \
+ (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \
+ (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); }
+
+#define Ch(x,y,z) (z ^ (x & (y ^ z)))
+#define Maj(x,y,z) (((x | y) & z) | (x & y))
+#define S(x, n) RORc((x),(n))
+#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n))
+#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22))
+#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25))
+#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3))
+#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10))
+#ifndef MIN
+ #define MIN(x, y) ( ((x)<(y))?(x):(y) )
+#endif
+
+/* compress 256-bits */
+static int sha256_compress(sha256_context * md, unsigned char *buf)
+{
+ uint32_t S[8], W[64], t0, t1;
+ uint32_t t;
+ int i;
+ /* copy state into S */
+ for (i = 0; i < 8; i++) {
+ S[i] = md->state[i];
+ }
+ /* copy the state into 512-bits into W[0..15] */
+ for (i = 0; i < 16; i++) {
+ LOAD32H(W[i], buf + (4*i));
+ }
+ /* fill W[16..63] */
+ for (i = 16; i < 64; i++) {
+ W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16];
+ }
+ /* Compress */
+ #define RND(a,b,c,d,e,f,g,h,i) \
+ t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \
+ t1 = Sigma0(a) + Maj(a, b, c); \
+ d += t0; \
+ h = t0 + t1;
+ for (i = 0; i < 64; ++i) {
+ RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i);
+ t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4];
+ S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t;
+ }
+ #undef RND
+ /* feedback */
+ for (i = 0; i < 8; i++) {
+ md->state[i] = md->state[i] + S[i];
+ }
+ return 0;
+}
+
+/**
+ Initialize the hash state
+ @param md The hash state you wish to initialize
+ @return CRYPT_OK if successful
+*/
+int sha256_init(sha256_context * md)
+{
+ if (md == NULL) return 1;
+ md->curlen = 0;
+ md->length = 0;
+ md->state[0] = 0x6A09E667UL;
+ md->state[1] = 0xBB67AE85UL;
+ md->state[2] = 0x3C6EF372UL;
+ md->state[3] = 0xA54FF53AUL;
+ md->state[4] = 0x510E527FUL;
+ md->state[5] = 0x9B05688CUL;
+ md->state[6] = 0x1F83D9ABUL;
+ md->state[7] = 0x5BE0CD19UL;
+ md->num_dwords = 8;
+ return 0;
+}
+
+/**
+ Process a block of memory though the hash
+ @param md The hash state
+ @param data The data to hash
+ @param inlen The length of the data (octets)
+ @return 0 if successful
+*/
+int sha256_update (sha256_context * md, const void *data, size_t inlen)
+{
+ const unsigned char* in = (const unsigned char*)data;
+ size_t n;
+ size_t i;
+ int err;
+ if (md == NULL) return 1;
+ if (in == NULL) return 1;
+ if (md->curlen > sizeof(md->buf)) {
+ return 1;
+ }
+ while (inlen > 0) {
+ if (md->curlen == 0 && inlen >= 64) {
+ if ((err = sha256_compress (md, (unsigned char *)in)) != 0) {
+ return err;
+ }
+ md->length += 64 * 8;
+ in += 64;
+ inlen -= 64;
+ } else {
+ n = MIN(inlen, (64 - md->curlen));
+
+ for (i = 0; i < n; i++) {
+ md->buf[i + md->curlen] = in[i];
+ }
+
+
+ md->curlen += n;
+ in += n;
+ inlen -= n;
+ if (md->curlen == 64) {
+ if ((err = sha256_compress (md, md->buf)) != 0) {
+ return err;
+ }
+ md->length += 8*64;
+ md->curlen = 0;
+ }
+ }
+ }
+ return 0;
+}
+
+/**
+ Terminate the hash to get the digest
+ @param md The hash state
+ @param out [out] The destination of the hash (32 bytes)
+ @return 0 if successful
+*/
+int sha256_final(sha256_context * md, unsigned char *out)
+{
+ int i;
+ if (md == NULL) return 1;
+ if (out == NULL) return 1;
+ if (md->curlen >= sizeof(md->buf)) {
+ return 1;
+ }
+ /* increase the length of the message */
+ md->length += md->curlen * 8;
+ /* append the '1' bit */
+ md->buf[md->curlen++] = (unsigned char)0x80;
+ /* if the length is currently above 56 bytes we append zeros
+ * then compress. Then we can fall back to padding zeros and length
+ * encoding like normal.
+ */
+ if (md->curlen > 56) {
+ while (md->curlen < 64) {
+ md->buf[md->curlen++] = (unsigned char)0;
+ }
+ sha256_compress(md, md->buf);
+ md->curlen = 0;
+ }
+ /* pad upto 56 bytes of zeroes */
+ while (md->curlen < 56) {
+ md->buf[md->curlen++] = (unsigned char)0;
+ }
+ /* store length */
+ STORE64H(md->length, md->buf+56);
+ sha256_compress(md, md->buf);
+ /* copy output */
+ for (i = 0; i < md->num_dwords; i++) {
+ STORE32H(md->state[i], out+(4*i));
+ }
+ return 0;
+}
+
+int sha256(const unsigned char *message, size_t message_len, unsigned char *out)
+{
+ sha256_context ctx;
+ int ret;
+ if ((ret = sha256_init(&ctx))) return ret;
+ if ((ret = sha256_update(&ctx, message, message_len))) return ret;
+ if ((ret = sha256_final(&ctx, out))) return ret;
+ return 0;
+}
+
+int sha224_init(sha224_context * md) {
+ if (md == NULL) return 1;
+
+ md->curlen = 0;
+ md->length = 0;
+ md->state[0] = 0xc1059ed8UL;
+ md->state[1] = 0x367cd507UL;
+ md->state[2] = 0x3070dd17UL;
+ md->state[3] = 0xf70e5939UL;
+ md->state[4] = 0xffc00b31UL;
+ md->state[5] = 0x68581511UL;
+ md->state[6] = 0x64f98fa7UL;
+ md->state[7] = 0xbefa4fa4UL;
+ md->num_dwords = 6;
+
+ return 0;
+}
+
+int sha224_update(sha224_context * md, const void *data, size_t inlen)
+{
+ return sha256_update(md, data, inlen);
+}
+
+int sha224_final(sha224_context * md, unsigned char* out)
+{
+ return sha256_final(md, out);
+}
+
+int sha224(const unsigned char *message, size_t message_len, unsigned char *out)
+{
+ sha224_context ctx;
+ int ret;
+ if ((ret = sha224_init(&ctx))) return ret;
+ if ((ret = sha224_update(&ctx, message, message_len))) return ret;
+ if ((ret = sha224_final(&ctx, out))) return ret;
+ return 0;
+}
diff --git a/src/sha512.c b/src/sha512.c
new file mode 100644
index 0000000..62c7159
--- /dev/null
+++ b/src/sha512.c
@@ -0,0 +1,315 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ */
+
+#include "fixedint.h"
+
+#include "common.h"
+#include "libimobiledevice-glue/sha.h"
+
+/* the K array */
+static const uint64_t K[80] = {
+ UINT64_C(0x428a2f98d728ae22), UINT64_C(0x7137449123ef65cd),
+ UINT64_C(0xb5c0fbcfec4d3b2f), UINT64_C(0xe9b5dba58189dbbc),
+ UINT64_C(0x3956c25bf348b538), UINT64_C(0x59f111f1b605d019),
+ UINT64_C(0x923f82a4af194f9b), UINT64_C(0xab1c5ed5da6d8118),
+ UINT64_C(0xd807aa98a3030242), UINT64_C(0x12835b0145706fbe),
+ UINT64_C(0x243185be4ee4b28c), UINT64_C(0x550c7dc3d5ffb4e2),
+ UINT64_C(0x72be5d74f27b896f), UINT64_C(0x80deb1fe3b1696b1),
+ UINT64_C(0x9bdc06a725c71235), UINT64_C(0xc19bf174cf692694),
+ UINT64_C(0xe49b69c19ef14ad2), UINT64_C(0xefbe4786384f25e3),
+ UINT64_C(0x0fc19dc68b8cd5b5), UINT64_C(0x240ca1cc77ac9c65),
+ UINT64_C(0x2de92c6f592b0275), UINT64_C(0x4a7484aa6ea6e483),
+ UINT64_C(0x5cb0a9dcbd41fbd4), UINT64_C(0x76f988da831153b5),
+ UINT64_C(0x983e5152ee66dfab), UINT64_C(0xa831c66d2db43210),
+ UINT64_C(0xb00327c898fb213f), UINT64_C(0xbf597fc7beef0ee4),
+ UINT64_C(0xc6e00bf33da88fc2), UINT64_C(0xd5a79147930aa725),
+ UINT64_C(0x06ca6351e003826f), UINT64_C(0x142929670a0e6e70),
+ UINT64_C(0x27b70a8546d22ffc), UINT64_C(0x2e1b21385c26c926),
+ UINT64_C(0x4d2c6dfc5ac42aed), UINT64_C(0x53380d139d95b3df),
+ UINT64_C(0x650a73548baf63de), UINT64_C(0x766a0abb3c77b2a8),
+ UINT64_C(0x81c2c92e47edaee6), UINT64_C(0x92722c851482353b),
+ UINT64_C(0xa2bfe8a14cf10364), UINT64_C(0xa81a664bbc423001),
+ UINT64_C(0xc24b8b70d0f89791), UINT64_C(0xc76c51a30654be30),
+ UINT64_C(0xd192e819d6ef5218), UINT64_C(0xd69906245565a910),
+ UINT64_C(0xf40e35855771202a), UINT64_C(0x106aa07032bbd1b8),
+ UINT64_C(0x19a4c116b8d2d0c8), UINT64_C(0x1e376c085141ab53),
+ UINT64_C(0x2748774cdf8eeb99), UINT64_C(0x34b0bcb5e19b48a8),
+ UINT64_C(0x391c0cb3c5c95a63), UINT64_C(0x4ed8aa4ae3418acb),
+ UINT64_C(0x5b9cca4f7763e373), UINT64_C(0x682e6ff3d6b2b8a3),
+ UINT64_C(0x748f82ee5defb2fc), UINT64_C(0x78a5636f43172f60),
+ UINT64_C(0x84c87814a1f0ab72), UINT64_C(0x8cc702081a6439ec),
+ UINT64_C(0x90befffa23631e28), UINT64_C(0xa4506cebde82bde9),
+ UINT64_C(0xbef9a3f7b2c67915), UINT64_C(0xc67178f2e372532b),
+ UINT64_C(0xca273eceea26619c), UINT64_C(0xd186b8c721c0c207),
+ UINT64_C(0xeada7dd6cde0eb1e), UINT64_C(0xf57d4f7fee6ed178),
+ UINT64_C(0x06f067aa72176fba), UINT64_C(0x0a637dc5a2c898a6),
+ UINT64_C(0x113f9804bef90dae), UINT64_C(0x1b710b35131c471b),
+ UINT64_C(0x28db77f523047d84), UINT64_C(0x32caab7b40c72493),
+ UINT64_C(0x3c9ebe0a15c9bebc), UINT64_C(0x431d67c49c100d4c),
+ UINT64_C(0x4cc5d4becb3e42b6), UINT64_C(0x597f299cfc657e2a),
+ UINT64_C(0x5fcb6fab3ad6faec), UINT64_C(0x6c44198c4a475817)
+};
+
+/* Various logical functions */
+
+#define ROR64c(x, y) \
+ ( ((((x)&UINT64_C(0xFFFFFFFFFFFFFFFF))>>((uint64_t)(y)&UINT64_C(63))) | \
+ ((x)<<((uint64_t)(64-((y)&UINT64_C(63)))))) & UINT64_C(0xFFFFFFFFFFFFFFFF))
+
+#define STORE64H(x, y) \
+ { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \
+ (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \
+ (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \
+ (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); }
+
+#define LOAD64H(x, y) \
+ { x = (((uint64_t)((y)[0] & 255))<<56)|(((uint64_t)((y)[1] & 255))<<48) | \
+ (((uint64_t)((y)[2] & 255))<<40)|(((uint64_t)((y)[3] & 255))<<32) | \
+ (((uint64_t)((y)[4] & 255))<<24)|(((uint64_t)((y)[5] & 255))<<16) | \
+ (((uint64_t)((y)[6] & 255))<<8)|(((uint64_t)((y)[7] & 255))); }
+
+
+#define Ch(x,y,z) (z ^ (x & (y ^ z)))
+#define Maj(x,y,z) (((x | y) & z) | (x & y))
+#define S(x, n) ROR64c(x, n)
+#define R(x, n) (((x) &UINT64_C(0xFFFFFFFFFFFFFFFF))>>((uint64_t)n))
+#define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39))
+#define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41))
+#define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7))
+#define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6))
+#ifndef MIN
+ #define MIN(x, y) ( ((x)<(y))?(x):(y) )
+#endif
+
+/* compress 1024-bits */
+static int sha512_compress(sha512_context *md, unsigned char *buf)
+{
+ uint64_t S[8], W[80], t0, t1;
+ int i;
+
+ /* copy state into S */
+ for (i = 0; i < 8; i++) {
+ S[i] = md->state[i];
+ }
+
+ /* copy the state into 1024-bits into W[0..15] */
+ for (i = 0; i < 16; i++) {
+ LOAD64H(W[i], buf + (8*i));
+ }
+
+ /* fill W[16..79] */
+ for (i = 16; i < 80; i++) {
+ W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16];
+ }
+
+ /* Compress */
+ #define RND(a,b,c,d,e,f,g,h,i) \
+ t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \
+ t1 = Sigma0(a) + Maj(a, b, c);\
+ d += t0; \
+ h = t0 + t1;
+
+ for (i = 0; i < 80; i += 8) {
+ RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i+0);
+ RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],i+1);
+ RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],i+2);
+ RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],i+3);
+ RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],i+4);
+ RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],i+5);
+ RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],i+6);
+ RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],i+7);
+ }
+
+ #undef RND
+
+ /* feedback */
+ for (i = 0; i < 8; i++) {
+ md->state[i] = md->state[i] + S[i];
+ }
+
+ return 0;
+}
+
+
+/**
+ Initialize the hash state
+ @param md The hash state you wish to initialize
+ @return 0 if successful
+*/
+int sha512_init(sha512_context * md) {
+ if (md == NULL) return 1;
+
+ md->curlen = 0;
+ md->length = 0;
+ md->state[0] = UINT64_C(0x6a09e667f3bcc908);
+ md->state[1] = UINT64_C(0xbb67ae8584caa73b);
+ md->state[2] = UINT64_C(0x3c6ef372fe94f82b);
+ md->state[3] = UINT64_C(0xa54ff53a5f1d36f1);
+ md->state[4] = UINT64_C(0x510e527fade682d1);
+ md->state[5] = UINT64_C(0x9b05688c2b3e6c1f);
+ md->state[6] = UINT64_C(0x1f83d9abfb41bd6b);
+ md->state[7] = UINT64_C(0x5be0cd19137e2179);
+ md->num_qwords = 8;
+
+ return 0;
+}
+
+/**
+ Process a block of memory though the hash
+ @param md The hash state
+ @param data The data to hash
+ @param inlen The length of the data (octets)
+ @return 0 if successful
+*/
+int sha512_update (sha512_context * md, const void *data, size_t inlen)
+{
+ const unsigned char* in = (const unsigned char*)data;
+ size_t n;
+ size_t i;
+ int err;
+ if (md == NULL) return 1;
+ if (in == NULL) return 1;
+ if (md->curlen > sizeof(md->buf)) {
+ return 1;
+ }
+ while (inlen > 0) {
+ if (md->curlen == 0 && inlen >= 128) {
+ if ((err = sha512_compress (md, (unsigned char *)in)) != 0) {
+ return err;
+ }
+ md->length += 128 * 8;
+ in += 128;
+ inlen -= 128;
+ } else {
+ n = MIN(inlen, (128 - md->curlen));
+
+ for (i = 0; i < n; i++) {
+ md->buf[i + md->curlen] = in[i];
+ }
+
+
+ md->curlen += n;
+ in += n;
+ inlen -= n;
+ if (md->curlen == 128) {
+ if ((err = sha512_compress (md, md->buf)) != 0) {
+ return err;
+ }
+ md->length += 8*128;
+ md->curlen = 0;
+ }
+ }
+ }
+ return 0;
+}
+
+/**
+ Terminate the hash to get the digest
+ @param md The hash state
+ @param out [out] The destination of the hash (64 bytes)
+ @return 0 if successful
+*/
+int sha512_final(sha512_context * md, unsigned char *out)
+{
+ int i;
+
+ if (md == NULL) return 1;
+ if (out == NULL) return 1;
+
+ if (md->curlen >= sizeof(md->buf)) {
+ return 1;
+ }
+
+ /* increase the length of the message */
+ md->length += md->curlen * UINT64_C(8);
+
+ /* append the '1' bit */
+ md->buf[md->curlen++] = (unsigned char)0x80;
+
+ /* if the length is currently above 112 bytes we append zeros
+ * then compress. Then we can fall back to padding zeros and length
+ * encoding like normal.
+ */
+ if (md->curlen > 112) {
+ while (md->curlen < 128) {
+ md->buf[md->curlen++] = (unsigned char)0;
+ }
+ sha512_compress(md, md->buf);
+ md->curlen = 0;
+ }
+
+ /* pad upto 120 bytes of zeroes
+ * note: that from 112 to 120 is the 64 MSB of the length. We assume that you won't hash
+ * > 2^64 bits of data... :-)
+ */
+ while (md->curlen < 120) {
+ md->buf[md->curlen++] = (unsigned char)0;
+ }
+
+ /* store length */
+ STORE64H(md->length, md->buf+120);
+ sha512_compress(md, md->buf);
+
+ /* copy output */
+ for (i = 0; i < md->num_qwords; i++) {
+ STORE64H(md->state[i], out+(8*i));
+ }
+
+ return 0;
+}
+
+int sha512(const unsigned char *message, size_t message_len, unsigned char *out)
+{
+ sha512_context ctx;
+ int ret;
+ if ((ret = sha512_init(&ctx))) return ret;
+ if ((ret = sha512_update(&ctx, message, message_len))) return ret;
+ if ((ret = sha512_final(&ctx, out))) return ret;
+ return 0;
+}
+
+int sha384_init(sha384_context * md) {
+ if (md == NULL) return 1;
+
+ md->curlen = 0;
+ md->length = 0;
+ md->state[0] = UINT64_C(0xcbbb9d5dc1059ed8);
+ md->state[1] = UINT64_C(0x629a292a367cd507);
+ md->state[2] = UINT64_C(0x9159015a3070dd17);
+ md->state[3] = UINT64_C(0x152fecd8f70e5939);
+ md->state[4] = UINT64_C(0x67332667ffc00b31);
+ md->state[5] = UINT64_C(0x8eb44a8768581511);
+ md->state[6] = UINT64_C(0xdb0c2e0d64f98fa7);
+ md->state[7] = UINT64_C(0x47b5481dbefa4fa4);
+ md->num_qwords = 6;
+
+ return 0;
+}
+
+int sha384_update(sha384_context * md, const void *data, size_t inlen)
+{
+ return sha512_update(md, data, inlen);
+}
+
+int sha384_final(sha384_context * md, unsigned char* out)
+{
+ return sha512_final(md, out);
+}
+
+int sha384(const unsigned char *message, size_t message_len, unsigned char *out)
+{
+ sha384_context ctx;
+ int ret;
+ if ((ret = sha384_init(&ctx))) return ret;
+ if ((ret = sha384_update(&ctx, message, message_len))) return ret;
+ if ((ret = sha384_final(&ctx, out))) return ret;
+ return 0;
+}
diff --git a/src/socket.c b/src/socket.c
index 1029a71..3375e5b 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -55,7 +55,7 @@ static int wsa_init = 0;
#ifdef AF_INET6
#include <net/if.h>
#include <ifaddrs.h>
-#if defined (__APPLE__) || defined (__FreeBSD__)
+#if defined (__APPLE__) || defined (__FreeBSD__) || defined (__HAIKU__)
#include <net/if_dl.h>
#endif
#ifdef __linux__
@@ -65,6 +65,9 @@ static int wsa_init = 0;
#endif
#include "common.h"
#include "libimobiledevice-glue/socket.h"
+#ifdef HAVE_POLL
+#include <sys/poll.h>
+#endif
#define RECV_TIMEOUT 20000
#define SEND_TIMEOUT 10000
@@ -82,12 +85,12 @@ static int wsa_init = 0;
static int verbose = 0;
-LIBIMOBILEDEVICE_GLUE_API void socket_set_verbose(int level)
+void socket_set_verbose(int level)
{
verbose = level;
}
-LIBIMOBILEDEVICE_GLUE_API const char *socket_addr_to_string(struct sockaddr *addr, char *addr_out, size_t addr_out_size)
+const char *socket_addr_to_string(struct sockaddr *addr, char *addr_out, size_t addr_out_size)
{
#ifdef WIN32
WSADATA wsa_data;
@@ -140,8 +143,186 @@ LIBIMOBILEDEVICE_GLUE_API const char *socket_addr_to_string(struct sockaddr *add
return NULL;
}
+enum poll_status
+{
+ poll_status_success,
+ poll_status_timeout,
+ poll_status_error
+};
+
+#ifdef WIN32
+static inline __attribute__((always_inline)) int WSAError_to_errno(int wsaerr)
+{
+ switch (wsaerr) {
+ case WSAEINVAL:
+ return EINVAL;
+ case WSAENOTSOCK:
+ return ENOTSOCK;
+ case WSAENOTCONN:
+ return ENOTCONN;
+ case WSAESHUTDOWN:
+ return ENOTCONN;
+ case WSAECONNRESET:
+ return ECONNRESET;
+ case WSAECONNABORTED:
+ return ECONNABORTED;
+ case WSAECONNREFUSED:
+ return ECONNREFUSED;
+ case WSAENETDOWN:
+ return ENETDOWN;
+ case WSAENETRESET:
+ return ENETRESET;
+ case WSAEHOSTUNREACH:
+ return EHOSTUNREACH;
+ case WSAETIMEDOUT:
+ return ETIMEDOUT;
+ case WSAEWOULDBLOCK:
+ return EWOULDBLOCK;
+ case WSAEINPROGRESS:
+ return EINPROGRESS;
+ case WSAENOBUFS:
+ return ENOBUFS;
+ case WSAEINTR:
+ return EINTR;
+ case WSAEACCES:
+ return EACCES;
+ case WSAEFAULT:
+ return EFAULT;
+ default:
+ break;
+ }
+ return wsaerr;
+}
+#endif
+
+// timeout of -1 means infinity
+static inline __attribute__((always_inline)) enum poll_status poll_wrapper(int fd, fd_mode mode, int timeout)
+{
+#ifdef HAVE_POLL
+ // https://man7.org/linux/man-pages/man2/select.2.html
+ // Correspondence between select() and poll() notifications
+ // #define POLLIN_SET (EPOLLRDNORM | EPOLLRDBAND | EPOLLIN |
+ // EPOLLHUP | EPOLLERR)
+ // /* Ready for reading */
+ // #define POLLOUT_SET (EPOLLWRBAND | EPOLLWRNORM | EPOLLOUT |
+ // EPOLLERR)
+ // /* Ready for writing */
+ // #define POLLEX_SET (EPOLLPRI)
+ // /* Exceptional condition */
+
+ short events;
+ switch (mode) {
+ case FDM_READ:
+ events = POLLRDNORM | POLLRDBAND | POLLIN | POLLHUP | POLLERR;
+ break;
+ case FDM_WRITE:
+ events = POLLWRBAND | POLLWRNORM | POLLOUT | POLLERR;
+ break;
+ case FDM_EXCEPT:
+ events = POLLPRI;
+ break;
+ default:
+ if (verbose >= 2)
+ fprintf(stderr, "%s: fd_mode %d unsupported\n", __func__, mode);
+ return poll_status_error;
+ }
+ while (1) {
+ struct pollfd pfd = {
+ .fd = fd,
+ .events = events,
+ };
+ switch (poll(&pfd, 1, timeout)) {
+ case 1:
+ if((pfd.revents & (POLLNVAL | POLLERR)) != 0)
+ {
+ if (verbose >= 2)
+ fprintf(stderr, "%s: poll unexpected events: %d\n", __func__, (int)pfd.revents);
+ return poll_status_error;
+ }
+ return poll_status_success;
+ case 0:
+ return poll_status_timeout;
+ case -1:
+ if(errno == EINTR)
+ {
+ if (verbose >= 2)
+ fprintf(stderr, "%s: EINTR\n", __func__);
+ continue;
+ }
+ // fallthrough
+ default:
+ if (verbose >= 2)
+ fprintf(stderr, "%s: poll failed: %s\n", __func__, strerror(errno));
+ return poll_status_error;
+ }
+ }
+#else
+ fd_set fds;
+ int sret;
+ int eagain;
+ struct timeval to;
+ struct timeval *pto;
+
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+
+ sret = poll_status_error;
+
+ do {
+ if (timeout > 0) {
+ to.tv_sec = (time_t) (timeout / 1000);
+ to.tv_usec = (time_t) ((timeout - (to.tv_sec * 1000)) * 1000);
+ pto = &to;
+ } else {
+ pto = NULL;
+ }
+ eagain = 0;
+ switch (mode) {
+ case FDM_READ:
+ sret = select(fd + 1, &fds, NULL, NULL, pto);
+ break;
+ case FDM_WRITE:
+ sret = select(fd + 1, NULL, &fds, NULL, pto);
+ break;
+ case FDM_EXCEPT:
+ sret = select(fd + 1, NULL, NULL, &fds, pto);
+ break;
+ default:
+ if (verbose >= 2)
+ fprintf(stderr, "%s: fd_mode %d unsupported\n", __func__, mode);
+ return poll_status_error;
+ }
+
+ if (sret == 1) {
+ return poll_status_success;
+ } else if (sret == 0) {
+ return poll_status_timeout;
+ } else {
+ switch (errno) {
+ case EINTR:
+ // interrupt signal in select
+ if (verbose >= 2)
+ fprintf(stderr, "%s: EINTR\n", __func__);
+ eagain = 1;
+ break;
+ case EAGAIN:
+ if (verbose >= 2)
+ fprintf(stderr, "%s: EAGAIN\n", __func__);
+ break;
+ default:
+ if (verbose >= 2)
+ fprintf(stderr, "%s: select failed: %s\n", __func__, strerror(errno));
+ return poll_status_error;
+ }
+ }
+ } while (eagain);
+
+ return sret;
+#endif
+}
+
#ifndef WIN32
-LIBIMOBILEDEVICE_GLUE_API int socket_create_unix(const char *filename)
+int socket_create_unix(const char *filename)
{
struct sockaddr_un name;
int sock;
@@ -187,7 +368,7 @@ LIBIMOBILEDEVICE_GLUE_API int socket_create_unix(const char *filename)
return sock;
}
-LIBIMOBILEDEVICE_GLUE_API int socket_connect_unix(const char *filename)
+int socket_connect_unix(const char *filename)
{
struct sockaddr_un name;
int sfd = -1;
@@ -246,20 +427,22 @@ LIBIMOBILEDEVICE_GLUE_API int socket_connect_unix(const char *filename)
break;
}
if (errno == EINPROGRESS) {
- fd_set fds;
- FD_ZERO(&fds);
- FD_SET(sfd, &fds);
-
- struct timeval timeout;
- timeout.tv_sec = CONNECT_TIMEOUT / 1000;
- timeout.tv_usec = (CONNECT_TIMEOUT - (timeout.tv_sec * 1000)) * 1000;
- if (select(sfd + 1, NULL, &fds, NULL, &timeout) == 1) {
+ if (poll_wrapper(sfd, FDM_WRITE, CONNECT_TIMEOUT) == poll_status_success) {
int so_error;
socklen_t len = sizeof(so_error);
getsockopt(sfd, SOL_SOCKET, SO_ERROR, (void*)&so_error, &len);
if (so_error == 0) {
+ errno = 0;
break;
}
+ errno = so_error;
+ } else {
+ int so_error = 0;
+ socklen_t len = sizeof(so_error);
+ getsockopt(sfd, SOL_SOCKET, SO_ERROR, (void*)&so_error, &len);
+ if (so_error != 0) {
+ errno = so_error;
+ }
}
}
socket_close(sfd);
@@ -276,10 +459,11 @@ LIBIMOBILEDEVICE_GLUE_API int socket_connect_unix(const char *filename)
}
#endif
-LIBIMOBILEDEVICE_GLUE_API int socket_create(const char* addr, uint16_t port)
+int socket_create(const char* addr, uint16_t port)
{
int sfd = -1;
int yes = 1;
+ int no = 0;
struct addrinfo hints;
struct addrinfo *result, *rp;
char portstr[8];
@@ -303,9 +487,6 @@ LIBIMOBILEDEVICE_GLUE_API int socket_create(const char* addr, uint16_t port)
sprintf(portstr, "%d", port);
- if (!addr) {
- addr = "localhost";
- }
res = getaddrinfo(addr, portstr, &hints, &result);
if (res != 0) {
fprintf(stderr, "%s: getaddrinfo: %s\n", __func__, gai_strerror(res));
@@ -334,7 +515,7 @@ LIBIMOBILEDEVICE_GLUE_API int socket_create(const char* addr, uint16_t port)
#if defined(AF_INET6) && defined(IPV6_V6ONLY)
if (rp->ai_family == AF_INET6) {
- if (setsockopt(sfd, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&yes, sizeof(int)) == -1) {
+ if (setsockopt(sfd, IPPROTO_IPV6, IPV6_V6ONLY, (addr) ? (void*)&yes : (void*)&no, sizeof(int)) == -1) {
perror("setsockopt() IPV6_V6ONLY");
}
}
@@ -699,7 +880,7 @@ static int getifaddrs(struct ifaddrs** ifap)
#endif
#endif
-LIBIMOBILEDEVICE_GLUE_API int get_primary_mac_address(unsigned char mac_addr_buf[6])
+int get_primary_mac_address(unsigned char mac_addr_buf[6])
{
int result = -1;
struct ifaddrs *ifaddr = NULL, *ifa = NULL;
@@ -714,13 +895,13 @@ LIBIMOBILEDEVICE_GLUE_API int get_primary_mac_address(unsigned char mac_addr_buf
if (ifa->ifa_flags & IFF_LOOPBACK) {
continue;
}
-#if defined(__APPLE__) || defined (__FreeBSD__)
+#if defined(__APPLE__) || defined (__FreeBSD__) || defined (__HAIKU__)
if (ifa->ifa_addr->sa_family != AF_LINK) {
continue;
}
#if defined (__APPLE__)
if (!strcmp(ifa->ifa_name, "en0")) {
-#elif defined (__FreeBSD__)
+#elif defined (__FreeBSD__) || defined (__HAIKU__)
{
#endif
memcpy(mac_addr_buf, (unsigned char *)LLADDR((struct sockaddr_dl *)(ifa)->ifa_addr), 6);
@@ -742,6 +923,12 @@ LIBIMOBILEDEVICE_GLUE_API int get_primary_mac_address(unsigned char mac_addr_buf
result = 0;
break;
}
+#elif defined(__CYGWIN__)
+ if (ifa->ifa_data) {
+ memcpy(mac_addr_buf, ((struct ifaddrs_hwdata *)ifa->ifa_data)->ifa_hwaddr.sa_data, 6);
+ result = 0;
+ break;
+ }
#else
#error get_primary_mac_address is not supported on this platform.
#endif
@@ -787,10 +974,12 @@ static int32_t _sockaddr_in6_scope_id(struct sockaddr_in6* addr)
continue;
}
+#ifndef __HAIKU__
/* skip if not running */
if ((ifa->ifa_flags & IFF_RUNNING) == 0) {
continue;
}
+#endif
struct sockaddr_in6* addr_in = (struct sockaddr_in6*)ifa->ifa_addr;
@@ -840,7 +1029,7 @@ static int32_t _sockaddr_in6_scope_id(struct sockaddr_in6* addr)
}
#endif
-LIBIMOBILEDEVICE_GLUE_API int socket_connect_addr(struct sockaddr* addr, uint16_t port)
+int socket_connect_addr(struct sockaddr* addr, uint16_t port)
{
int sfd = -1;
int yes = 1;
@@ -924,14 +1113,7 @@ LIBIMOBILEDEVICE_GLUE_API int socket_connect_addr(struct sockaddr* addr, uint16_
if (errno == EINPROGRESS)
#endif
{
- fd_set fds;
- FD_ZERO(&fds);
- FD_SET(sfd, &fds);
-
- struct timeval timeout;
- timeout.tv_sec = CONNECT_TIMEOUT / 1000;
- timeout.tv_usec = (CONNECT_TIMEOUT - (timeout.tv_sec * 1000)) * 1000;
- if (select(sfd + 1, NULL, &fds, NULL, &timeout) == 1) {
+ if (poll_wrapper(sfd, FDM_WRITE, CONNECT_TIMEOUT) == poll_status_success) {
int so_error;
socklen_t len = sizeof(so_error);
getsockopt(sfd, SOL_SOCKET, SO_ERROR, (void*)&so_error, &len);
@@ -939,7 +1121,20 @@ LIBIMOBILEDEVICE_GLUE_API int socket_connect_addr(struct sockaddr* addr, uint16_
errno = 0;
break;
}
+#ifdef WIN32
+ so_error = WSAError_to_errno(so_error);
+#endif
errno = so_error;
+ } else {
+ int so_error = 0;
+ socklen_t len = sizeof(so_error);
+ getsockopt(sfd, SOL_SOCKET, SO_ERROR, (void*)&so_error, &len);
+ if (so_error != 0) {
+#ifdef WIN32
+ so_error = WSAError_to_errno(so_error);
+#endif
+ errno = so_error;
+ }
}
}
socket_close(sfd);
@@ -970,7 +1165,7 @@ LIBIMOBILEDEVICE_GLUE_API int socket_connect_addr(struct sockaddr* addr, uint16_
return sfd;
}
-LIBIMOBILEDEVICE_GLUE_API int socket_connect(const char *addr, uint16_t port)
+int socket_connect(const char *addr, uint16_t port)
{
int sfd = -1;
int yes = 1;
@@ -993,11 +1188,6 @@ LIBIMOBILEDEVICE_GLUE_API int socket_connect(const char *addr, uint16_t port)
int flags = 0;
#endif
- if (!addr) {
- errno = EINVAL;
- return -1;
- }
-
memset(&hints, '\0', sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
@@ -1048,20 +1238,28 @@ LIBIMOBILEDEVICE_GLUE_API int socket_connect(const char *addr, uint16_t port)
if (errno == EINPROGRESS)
#endif
{
- fd_set fds;
- FD_ZERO(&fds);
- FD_SET(sfd, &fds);
-
- struct timeval timeout;
- timeout.tv_sec = CONNECT_TIMEOUT / 1000;
- timeout.tv_usec = (CONNECT_TIMEOUT - (timeout.tv_sec * 1000)) * 1000;
- if (select(sfd + 1, NULL, &fds, NULL, &timeout) == 1) {
+ if (poll_wrapper(sfd, FDM_WRITE, CONNECT_TIMEOUT) == poll_status_success) {
int so_error;
socklen_t len = sizeof(so_error);
getsockopt(sfd, SOL_SOCKET, SO_ERROR, (void*)&so_error, &len);
if (so_error == 0) {
+ errno = 0;
break;
}
+#ifdef WIN32
+ so_error = WSAError_to_errno(so_error);
+#endif
+ errno = so_error;
+ } else {
+ int so_error = 0;
+ socklen_t len = sizeof(so_error);
+ getsockopt(sfd, SOL_SOCKET, SO_ERROR, (void*)&so_error, &len);
+ if (so_error != 0) {
+#ifdef WIN32
+ so_error = WSAError_to_errno(so_error);
+#endif
+ errno = so_error;
+ }
}
}
socket_close(sfd);
@@ -1090,75 +1288,39 @@ LIBIMOBILEDEVICE_GLUE_API int socket_connect(const char *addr, uint16_t port)
return sfd;
}
-LIBIMOBILEDEVICE_GLUE_API int socket_check_fd(int fd, fd_mode fdm, unsigned int timeout)
+int socket_check_fd(int fd, fd_mode fdm, unsigned int timeout)
{
- fd_set fds;
- int sret;
- int eagain;
- struct timeval to;
- struct timeval *pto;
-
if (fd < 0) {
if (verbose >= 2)
fprintf(stderr, "ERROR: invalid fd in check_fd %d\n", fd);
- return -1;
+ return -EINVAL;
}
- FD_ZERO(&fds);
- FD_SET(fd, &fds);
-
- sret = -1;
-
- do {
- if (timeout > 0) {
- to.tv_sec = (time_t) (timeout / 1000);
- to.tv_usec = (time_t) ((timeout - (to.tv_sec * 1000)) * 1000);
- pto = &to;
- } else {
- pto = NULL;
- }
- eagain = 0;
- switch (fdm) {
- case FDM_READ:
- sret = select(fd + 1, &fds, NULL, NULL, pto);
- break;
- case FDM_WRITE:
- sret = select(fd + 1, NULL, &fds, NULL, pto);
- break;
- case FDM_EXCEPT:
- sret = select(fd + 1, NULL, NULL, &fds, pto);
- break;
- default:
- return -1;
- }
+ int timeout_ms;
+ if (timeout > 0) {
+ timeout_ms = (int)timeout;
+ if (timeout_ms <= 0)
+ timeout_ms = -1;
+ } else {
+ timeout_ms = -1;
+ }
- if (sret < 0) {
- switch (errno) {
- case EINTR:
- // interrupt signal in select
- if (verbose >= 2)
- fprintf(stderr, "%s: EINTR\n", __func__);
- eagain = 1;
- break;
- case EAGAIN:
- if (verbose >= 2)
- fprintf(stderr, "%s: EAGAIN\n", __func__);
- break;
- default:
- if (verbose >= 2)
- fprintf(stderr, "%s: select failed: %s\n", __func__,
- strerror(errno));
- return -1;
- }
- } else if (sret == 0) {
+ switch (poll_wrapper(fd, fdm, timeout_ms)) {
+ case poll_status_success:
+ return 1;
+ case poll_status_timeout:
return -ETIMEDOUT;
- }
- } while (eagain);
+ case poll_status_error:
+ default:
+ if (verbose >= 2)
+ fprintf(stderr, "%s: poll_wrapper failed\n", __func__);
+ return -ECONNRESET;
+ }
- return sret;
+ return -ECONNRESET;
}
-LIBIMOBILEDEVICE_GLUE_API int socket_accept(int fd, uint16_t port)
+int socket_accept(int fd, uint16_t port)
{
#ifdef WIN32
int addr_len;
@@ -1174,12 +1336,12 @@ LIBIMOBILEDEVICE_GLUE_API int socket_accept(int fd, uint16_t port)
return result;
}
-LIBIMOBILEDEVICE_GLUE_API int socket_shutdown(int fd, int how)
+int socket_shutdown(int fd, int how)
{
return shutdown(fd, how);
}
-LIBIMOBILEDEVICE_GLUE_API int socket_close(int fd) {
+int socket_close(int fd) {
#ifdef WIN32
return closesocket(fd);
#else
@@ -1187,17 +1349,17 @@ LIBIMOBILEDEVICE_GLUE_API int socket_close(int fd) {
#endif
}
-LIBIMOBILEDEVICE_GLUE_API int socket_receive(int fd, void *data, size_t length)
+int socket_receive(int fd, void *data, size_t length)
{
return socket_receive_timeout(fd, data, length, 0, RECV_TIMEOUT);
}
-LIBIMOBILEDEVICE_GLUE_API int socket_peek(int fd, void *data, size_t length)
+int socket_peek(int fd, void *data, size_t length)
{
return socket_receive_timeout(fd, data, length, MSG_PEEK, RECV_TIMEOUT);
}
-LIBIMOBILEDEVICE_GLUE_API int socket_receive_timeout(int fd, void *data, size_t length, int flags, unsigned int timeout)
+int socket_receive_timeout(int fd, void *data, size_t length, int flags, unsigned int timeout)
{
int res;
int result;
@@ -1209,19 +1371,22 @@ LIBIMOBILEDEVICE_GLUE_API int socket_receive_timeout(int fd, void *data, size_t
}
// if we get here, there _is_ data available
result = recv(fd, data, length, flags);
- if (res > 0 && result == 0) {
+ if (result == 0) {
// but this is an error condition
if (verbose >= 3)
fprintf(stderr, "%s: fd=%d recv returned 0\n", __func__, fd);
return -ECONNRESET;
}
if (result < 0) {
+#ifdef WIN32
+ errno = WSAError_to_errno(WSAGetLastError());
+#endif
return -errno;
}
return result;
}
-LIBIMOBILEDEVICE_GLUE_API int socket_send(int fd, void *data, size_t length)
+int socket_send(int fd, void *data, size_t length)
{
int flags = 0;
int res = socket_check_fd(fd, FDM_WRITE, SEND_TIMEOUT);
@@ -1231,10 +1396,17 @@ LIBIMOBILEDEVICE_GLUE_API int socket_send(int fd, void *data, size_t length)
#ifdef MSG_NOSIGNAL
flags |= MSG_NOSIGNAL;
#endif
- return send(fd, data, length, flags);
+ int s = (int)send(fd, data, length, flags);
+ if (s < 0) {
+#ifdef WIN32
+ errno = WSAError_to_errno(WSAGetLastError());
+#endif
+ return -errno;
+ }
+ return s;
}
-LIBIMOBILEDEVICE_GLUE_API int socket_get_socket_port(int fd, uint16_t *port)
+int socket_get_socket_port(int fd, uint16_t *port)
{
#ifdef WIN32
int addr_len;
diff --git a/src/termcolors.c b/src/termcolors.c
index 710c9df..5c436f2 100644
--- a/src/termcolors.c
+++ b/src/termcolors.c
@@ -92,7 +92,7 @@ static int bgcolor_map[8] = {
static int WIN32_LEGACY_MODE = 0;
#endif
-LIBIMOBILEDEVICE_GLUE_API void term_colors_init()
+void term_colors_init()
{
#ifdef WIN32
DWORD conmode = 0;
@@ -126,12 +126,12 @@ LIBIMOBILEDEVICE_GLUE_API void term_colors_init()
}
}
-LIBIMOBILEDEVICE_GLUE_API void term_colors_set_enabled(int en)
+void term_colors_set_enabled(int en)
{
use_colors = en;
}
-LIBIMOBILEDEVICE_GLUE_API int cvfprintf(FILE* stream, const char* fmt, va_list vargs)
+int cvfprintf(FILE* stream, const char* fmt, va_list vargs)
{
int res = 0;
int colorize = use_colors;
@@ -298,7 +298,7 @@ LIBIMOBILEDEVICE_GLUE_API int cvfprintf(FILE* stream, const char* fmt, va_list v
return res;
}
-LIBIMOBILEDEVICE_GLUE_API int cfprintf(FILE* stream, const char* fmt, ...)
+int cfprintf(FILE* stream, const char* fmt, ...)
{
int res = 0;
va_list va;
@@ -308,7 +308,7 @@ LIBIMOBILEDEVICE_GLUE_API int cfprintf(FILE* stream, const char* fmt, ...)
return res;
}
-LIBIMOBILEDEVICE_GLUE_API int cprintf(const char* fmt, ...)
+int cprintf(const char* fmt, ...)
{
int res = 0;
va_list va;
diff --git a/src/thread.c b/src/thread.c
index 6efacec..50639dd 100644
--- a/src/thread.c
+++ b/src/thread.c
@@ -22,13 +22,16 @@
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
+#ifdef WIN32
+#include <windows.h>
+#endif
#include "common.h"
#include "libimobiledevice-glue/thread.h"
-LIBIMOBILEDEVICE_GLUE_API int thread_new(THREAD_T *thread, thread_func_t thread_func, void* data)
+int thread_new(THREAD_T *thread, thread_func_t thread_func, void* data)
{
#ifdef WIN32
- HANDLE th = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)thread_func, data, 0, NULL);
+ HANDLE th = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)(void*)thread_func, data, 0, NULL);
if (th == NULL) {
return -1;
}
@@ -40,7 +43,7 @@ LIBIMOBILEDEVICE_GLUE_API int thread_new(THREAD_T *thread, thread_func_t thread_
#endif
}
-LIBIMOBILEDEVICE_GLUE_API void thread_detach(THREAD_T thread)
+void thread_detach(THREAD_T thread)
{
#ifdef WIN32
CloseHandle(thread);
@@ -49,14 +52,14 @@ LIBIMOBILEDEVICE_GLUE_API void thread_detach(THREAD_T thread)
#endif
}
-LIBIMOBILEDEVICE_GLUE_API void thread_free(THREAD_T thread)
+void thread_free(THREAD_T thread)
{
#ifdef WIN32
CloseHandle(thread);
#endif
}
-LIBIMOBILEDEVICE_GLUE_API int thread_join(THREAD_T thread)
+int thread_join(THREAD_T thread)
{
/* wait for thread to complete */
#ifdef WIN32
@@ -66,7 +69,7 @@ LIBIMOBILEDEVICE_GLUE_API int thread_join(THREAD_T thread)
#endif
}
-LIBIMOBILEDEVICE_GLUE_API int thread_alive(THREAD_T thread)
+int thread_alive(THREAD_T thread)
{
if (!thread)
return 0;
@@ -77,7 +80,7 @@ LIBIMOBILEDEVICE_GLUE_API int thread_alive(THREAD_T thread)
#endif
}
-LIBIMOBILEDEVICE_GLUE_API int thread_cancel(THREAD_T thread)
+int thread_cancel(THREAD_T thread)
{
#ifdef WIN32
return -1;
@@ -90,43 +93,43 @@ LIBIMOBILEDEVICE_GLUE_API int thread_cancel(THREAD_T thread)
#endif
}
-LIBIMOBILEDEVICE_GLUE_API void mutex_init(mutex_t* mutex)
+void mutex_init(mutex_t* mutex)
{
#ifdef WIN32
- InitializeCriticalSection(mutex);
+ InitializeCriticalSection((LPCRITICAL_SECTION)mutex);
#else
pthread_mutex_init(mutex, NULL);
#endif
}
-LIBIMOBILEDEVICE_GLUE_API void mutex_destroy(mutex_t* mutex)
+void mutex_destroy(mutex_t* mutex)
{
#ifdef WIN32
- DeleteCriticalSection(mutex);
+ DeleteCriticalSection((LPCRITICAL_SECTION)mutex);
#else
pthread_mutex_destroy(mutex);
#endif
}
-LIBIMOBILEDEVICE_GLUE_API void mutex_lock(mutex_t* mutex)
+void mutex_lock(mutex_t* mutex)
{
#ifdef WIN32
- EnterCriticalSection(mutex);
+ EnterCriticalSection((LPCRITICAL_SECTION)mutex);
#else
pthread_mutex_lock(mutex);
#endif
}
-LIBIMOBILEDEVICE_GLUE_API void mutex_unlock(mutex_t* mutex)
+void mutex_unlock(mutex_t* mutex)
{
#ifdef WIN32
- LeaveCriticalSection(mutex);
+ LeaveCriticalSection((LPCRITICAL_SECTION)mutex);
#else
pthread_mutex_unlock(mutex);
#endif
}
-LIBIMOBILEDEVICE_GLUE_API void thread_once(thread_once_t *once_control, void (*init_routine)(void))
+void thread_once(thread_once_t *once_control, void (*init_routine)(void))
{
#ifdef WIN32
while (InterlockedExchange(&(once_control->lock), 1) != 0) {
@@ -142,7 +145,7 @@ LIBIMOBILEDEVICE_GLUE_API void thread_once(thread_once_t *once_control, void (*i
#endif
}
-LIBIMOBILEDEVICE_GLUE_API void cond_init(cond_t* cond)
+void cond_init(cond_t* cond)
{
#ifdef WIN32
cond->sem = CreateSemaphore(NULL, 0, 32767, NULL);
@@ -151,7 +154,7 @@ LIBIMOBILEDEVICE_GLUE_API void cond_init(cond_t* cond)
#endif
}
-LIBIMOBILEDEVICE_GLUE_API void cond_destroy(cond_t* cond)
+void cond_destroy(cond_t* cond)
{
#ifdef WIN32
CloseHandle(cond->sem);
@@ -160,7 +163,7 @@ LIBIMOBILEDEVICE_GLUE_API void cond_destroy(cond_t* cond)
#endif
}
-LIBIMOBILEDEVICE_GLUE_API int cond_signal(cond_t* cond)
+int cond_signal(cond_t* cond)
{
#ifdef WIN32
int result = 0;
@@ -173,7 +176,7 @@ LIBIMOBILEDEVICE_GLUE_API int cond_signal(cond_t* cond)
#endif
}
-LIBIMOBILEDEVICE_GLUE_API int cond_wait(cond_t* cond, mutex_t* mutex)
+int cond_wait(cond_t* cond, mutex_t* mutex)
{
#ifdef WIN32
mutex_unlock(mutex);
@@ -189,7 +192,7 @@ LIBIMOBILEDEVICE_GLUE_API int cond_wait(cond_t* cond, mutex_t* mutex)
#endif
}
-LIBIMOBILEDEVICE_GLUE_API int cond_wait_timeout(cond_t* cond, mutex_t* mutex, unsigned int timeout_ms)
+int cond_wait_timeout(cond_t* cond, mutex_t* mutex, unsigned int timeout_ms)
{
#ifdef WIN32
mutex_unlock(mutex);
diff --git a/src/tlv.c b/src/tlv.c
index d08c8f3..f209a37 100644
--- a/src/tlv.c
+++ b/src/tlv.c
@@ -32,7 +32,7 @@
#include "libimobiledevice-glue/tlv.h"
#include "endianness.h"
-LIBIMOBILEDEVICE_GLUE_API tlv_buf_t tlv_buf_new()
+tlv_buf_t tlv_buf_new()
{
tlv_buf_t tlv = malloc(sizeof(struct tlv_buf));
tlv->capacity = 1024;
@@ -41,7 +41,7 @@ LIBIMOBILEDEVICE_GLUE_API tlv_buf_t tlv_buf_new()
return tlv;
}
-LIBIMOBILEDEVICE_GLUE_API void tlv_buf_free(tlv_buf_t tlv)
+void tlv_buf_free(tlv_buf_t tlv)
{
if (tlv) {
free(tlv->data);
@@ -49,7 +49,7 @@ LIBIMOBILEDEVICE_GLUE_API void tlv_buf_free(tlv_buf_t tlv)
}
}
-LIBIMOBILEDEVICE_GLUE_API void tlv_buf_append(tlv_buf_t tlv, uint8_t tag, unsigned int length, void* data)
+void tlv_buf_append(tlv_buf_t tlv, uint8_t tag, unsigned int length, void* data)
{
if (!tlv || !tlv->data) {
return;
@@ -86,7 +86,7 @@ LIBIMOBILEDEVICE_GLUE_API void tlv_buf_append(tlv_buf_t tlv, uint8_t tag, unsign
tlv->length = p - tlv->data;
}
-LIBIMOBILEDEVICE_GLUE_API unsigned char* tlv_get_data_ptr(const void* tlv_data, void* tlv_end, uint8_t tag, uint8_t* length)
+unsigned char* tlv_get_data_ptr(const void* tlv_data, void* tlv_end, uint8_t tag, uint8_t* length)
{
unsigned char* p = (unsigned char*)tlv_data;
unsigned char* end = (unsigned char*)tlv_end;
@@ -102,7 +102,7 @@ LIBIMOBILEDEVICE_GLUE_API unsigned char* tlv_get_data_ptr(const void* tlv_data,
return NULL;
}
-LIBIMOBILEDEVICE_GLUE_API int tlv_data_get_uint(const void* tlv_data, unsigned int tlv_length, uint8_t tag, uint64_t* value)
+int tlv_data_get_uint(const void* tlv_data, unsigned int tlv_length, uint8_t tag, uint64_t* value)
{
if (!tlv_data || tlv_length < 2 || !value) {
return 0;
@@ -136,7 +136,7 @@ LIBIMOBILEDEVICE_GLUE_API int tlv_data_get_uint(const void* tlv_data, unsigned i
return 1;
}
-LIBIMOBILEDEVICE_GLUE_API int tlv_data_get_uint8(const void* tlv_data, unsigned int tlv_length, uint8_t tag, uint8_t* value)
+int tlv_data_get_uint8(const void* tlv_data, unsigned int tlv_length, uint8_t tag, uint8_t* value)
{
if (!tlv_data || tlv_length < 2 || !value) {
return 0;
@@ -156,7 +156,7 @@ LIBIMOBILEDEVICE_GLUE_API int tlv_data_get_uint8(const void* tlv_data, unsigned
return 1;
}
-LIBIMOBILEDEVICE_GLUE_API int tlv_data_copy_data(const void* tlv_data, unsigned int tlv_length, uint8_t tag, void** out, unsigned int* out_len)
+int tlv_data_copy_data(const void* tlv_data, unsigned int tlv_length, uint8_t tag, void** out, unsigned int* out_len)
{
if (!tlv_data || tlv_length < 2 || !out || !out_len) {
return 0;
diff --git a/src/utils.c b/src/utils.c
index 9baef7e..ad8e9c4 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -3,7 +3,7 @@
* Miscellaneous utilities for string manipulation,
* file I/O and plist helper.
*
- * Copyright (c) 2014-2019 Nikias Bassen, All Rights Reserved.
+ * Copyright (c) 2014-2023 Nikias Bassen, All Rights Reserved.
* Copyright (c) 2013-2014 Martin Szulecki, All Rights Reserved.
* Copyright (c) 2013 Federico Mena Quintero
*
@@ -75,7 +75,7 @@ char *stpcpy(char *s1, const char *s2)
* @return a newly allocated string, or NULL if @str is NULL. This will also
* return NULL and set errno to ENOMEM if memory is exhausted.
*/
-LIBIMOBILEDEVICE_GLUE_API char *string_concat(const char *str, ...)
+char *string_concat(const char *str, ...)
{
size_t len;
va_list args;
@@ -119,7 +119,7 @@ LIBIMOBILEDEVICE_GLUE_API char *string_concat(const char *str, ...)
return result;
}
-LIBIMOBILEDEVICE_GLUE_API char *string_append(char* str, ...)
+char *string_append(char* str, ...)
{
size_t len = 0;
size_t slen;
@@ -163,7 +163,7 @@ LIBIMOBILEDEVICE_GLUE_API char *string_append(char* str, ...)
return result;
}
-LIBIMOBILEDEVICE_GLUE_API char *string_build_path(const char *elem, ...)
+char *string_build_path(const char *elem, ...)
{
if (!elem)
return NULL;
@@ -191,7 +191,7 @@ LIBIMOBILEDEVICE_GLUE_API char *string_build_path(const char *elem, ...)
return out;
}
-LIBIMOBILEDEVICE_GLUE_API char *string_format_size(uint64_t size)
+char *string_format_size(uint64_t size)
{
char buf[80];
double sz;
@@ -213,7 +213,7 @@ LIBIMOBILEDEVICE_GLUE_API char *string_format_size(uint64_t size)
return strdup(buf);
}
-LIBIMOBILEDEVICE_GLUE_API char *string_toupper(char* str)
+char *string_toupper(char* str)
{
char *res = strdup(str);
size_t i;
@@ -229,7 +229,7 @@ static int get_rand(int min, int max)
return retval;
}
-LIBIMOBILEDEVICE_GLUE_API char *generate_uuid()
+char *generate_uuid()
{
const char *chars = "ABCDEF0123456789";
int i = 0;
@@ -251,7 +251,7 @@ LIBIMOBILEDEVICE_GLUE_API char *generate_uuid()
return uuid;
}
-LIBIMOBILEDEVICE_GLUE_API int buffer_read_from_filename(const char *filename, char **buffer, uint64_t *length)
+int buffer_read_from_filename(const char *filename, char **buffer, uint64_t *length)
{
FILE *f;
uint64_t size;
@@ -295,7 +295,7 @@ LIBIMOBILEDEVICE_GLUE_API int buffer_read_from_filename(const char *filename, ch
return ret;
}
-LIBIMOBILEDEVICE_GLUE_API int buffer_write_to_filename(const char *filename, const char *buffer, uint64_t length)
+int buffer_write_to_filename(const char *filename, const char *buffer, uint64_t length)
{
FILE *f;
@@ -318,241 +318,3 @@ LIBIMOBILEDEVICE_GLUE_API int buffer_write_to_filename(const char *filename, con
return 0;
}
}
-
-LIBIMOBILEDEVICE_GLUE_API int plist_read_from_filename(plist_t *plist, const char *filename)
-{
- char *buffer = NULL;
- uint64_t length;
-
- if (!filename)
- return 0;
-
- if (!buffer_read_from_filename(filename, &buffer, &length)) {
- return 0;
- }
-
- plist_from_memory(buffer, length, plist);
-
- free(buffer);
-
- return 1;
-}
-
-LIBIMOBILEDEVICE_GLUE_API int plist_write_to_filename(plist_t plist, const char *filename, enum plist_format_t format)
-{
- char *buffer = NULL;
- uint32_t length;
-
- if (!plist || !filename)
- return 0;
-
- if (format == PLIST_FORMAT_XML)
- plist_to_xml(plist, &buffer, &length);
- else if (format == PLIST_FORMAT_BINARY)
- plist_to_bin(plist, &buffer, &length);
- else
- return 0;
-
- int res = buffer_write_to_filename(filename, buffer, length);
-
- free(buffer);
-
- return res;
-}
-
-static const char base64_str[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-static const char base64_pad = '=';
-
-static char *base64encode(const unsigned char *buf, size_t size)
-{
- if (!buf || !(size > 0)) return NULL;
- int outlen = (size / 3) * 4;
- char *outbuf = (char*)malloc(outlen+5); // 4 spare bytes + 1 for '\0'
- size_t n = 0;
- size_t m = 0;
- unsigned char input[3];
- unsigned int output[4];
- while (n < size) {
- input[0] = buf[n];
- input[1] = (n+1 < size) ? buf[n+1] : 0;
- input[2] = (n+2 < size) ? buf[n+2] : 0;
- output[0] = input[0] >> 2;
- output[1] = ((input[0] & 3) << 4) + (input[1] >> 4);
- output[2] = ((input[1] & 15) << 2) + (input[2] >> 6);
- output[3] = input[2] & 63;
- outbuf[m++] = base64_str[(int)output[0]];
- outbuf[m++] = base64_str[(int)output[1]];
- outbuf[m++] = (n+1 < size) ? base64_str[(int)output[2]] : base64_pad;
- outbuf[m++] = (n+2 < size) ? base64_str[(int)output[3]] : base64_pad;
- n+=3;
- }
- outbuf[m] = 0; // 0-termination!
- return outbuf;
-}
-
-static void plist_node_print_to_stream(plist_t node, int* indent_level, FILE* stream);
-
-static void plist_array_print_to_stream(plist_t node, int* indent_level, FILE* stream)
-{
- /* iterate over items */
- int i, count;
- plist_t subnode = NULL;
-
- count = plist_array_get_size(node);
-
- for (i = 0; i < count; i++) {
- subnode = plist_array_get_item(node, i);
- fprintf(stream, "%*s", *indent_level, "");
- fprintf(stream, "%d: ", i);
- plist_node_print_to_stream(subnode, indent_level, stream);
- }
-}
-
-static void plist_dict_print_to_stream(plist_t node, int* indent_level, FILE* stream)
-{
- /* iterate over key/value pairs */
- plist_dict_iter it = NULL;
-
- char* key = NULL;
- plist_t subnode = NULL;
- plist_dict_new_iter(node, &it);
- plist_dict_next_item(node, it, &key, &subnode);
- while (subnode)
- {
- fprintf(stream, "%*s", *indent_level, "");
- fprintf(stream, "%s", key);
- if (plist_get_node_type(subnode) == PLIST_ARRAY)
- fprintf(stream, "[%d]: ", plist_array_get_size(subnode));
- else
- fprintf(stream, ": ");
- free(key);
- key = NULL;
- plist_node_print_to_stream(subnode, indent_level, stream);
- plist_dict_next_item(node, it, &key, &subnode);
- }
- free(it);
-}
-
-static void plist_node_print_to_stream(plist_t node, int* indent_level, FILE* stream)
-{
- char *s = NULL;
- char *data = NULL;
- double d;
- uint8_t b;
- uint64_t u = 0;
- struct timeval tv = { 0, 0 };
-
- plist_type t;
-
- if (!node)
- return;
-
- t = plist_get_node_type(node);
-
- switch (t) {
- case PLIST_BOOLEAN:
- plist_get_bool_val(node, &b);
- fprintf(stream, "%s\n", (b ? "true" : "false"));
- break;
-
- case PLIST_UINT:
- plist_get_uint_val(node, &u);
- fprintf(stream, "%"PRIu64"\n", u);
- break;
-
- case PLIST_REAL:
- plist_get_real_val(node, &d);
- fprintf(stream, "%f\n", d);
- break;
-
- case PLIST_STRING:
- plist_get_string_val(node, &s);
- fprintf(stream, "%s\n", s);
- free(s);
- break;
-
- case PLIST_KEY:
- plist_get_key_val(node, &s);
- fprintf(stream, "%s: ", s);
- free(s);
- break;
-
- case PLIST_DATA:
- plist_get_data_val(node, &data, &u);
- if (u > 0) {
- s = base64encode((unsigned char*)data, u);
- free(data);
- if (s) {
- fprintf(stream, "%s\n", s);
- free(s);
- } else {
- fprintf(stream, "\n");
- }
- } else {
- fprintf(stream, "\n");
- }
- break;
-
- case PLIST_DATE:
- plist_get_date_val(node, (int32_t*)&tv.tv_sec, (int32_t*)&tv.tv_usec);
- {
- time_t ti = (time_t)tv.tv_sec + MAC_EPOCH;
- struct tm *btime = localtime(&ti);
- if (btime) {
- s = (char*)malloc(24);
- memset(s, 0, 24);
- if (strftime(s, 24, "%Y-%m-%dT%H:%M:%SZ", btime) <= 0) {
- free (s);
- s = NULL;
- }
- }
- }
- if (s) {
- fprintf(stream, "%s\n", s);
- free(s);
- } else {
- fprintf(stream, "\n");
- }
- break;
-
- case PLIST_ARRAY:
- fprintf(stream, "\n");
- (*indent_level)++;
- plist_array_print_to_stream(node, indent_level, stream);
- (*indent_level)--;
- break;
-
- case PLIST_DICT:
- fprintf(stream, "\n");
- (*indent_level)++;
- plist_dict_print_to_stream(node, indent_level, stream);
- (*indent_level)--;
- break;
-
- default:
- break;
- }
-}
-
-LIBIMOBILEDEVICE_GLUE_API void plist_print_to_stream_with_indentation(plist_t plist, FILE* stream, unsigned int indentation)
-{
- if (!plist || !stream)
- return;
-
- int indent = indentation;
- switch (plist_get_node_type(plist)) {
- case PLIST_DICT:
- plist_dict_print_to_stream(plist, &indent, stream);
- break;
- case PLIST_ARRAY:
- plist_array_print_to_stream(plist, &indent, stream);
- break;
- default:
- plist_node_print_to_stream(plist, &indent, stream);
- }
-}
-
-LIBIMOBILEDEVICE_GLUE_API void plist_print_to_stream(plist_t plist, FILE* stream)
-{
- plist_print_to_stream_with_indentation(plist, stream, 0);
-}