summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/build.yml23
-rw-r--r--Makefile.am7
-rw-r--r--NEWS26
-rw-r--r--README.md193
-rw-r--r--configure.ac25
-rwxr-xr-xgit-version-gen20
-rw-r--r--include/Makefile.am2
-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/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.am1
-rw-r--r--src/cbuf.c6
-rw-r--r--src/collection.c12
-rw-r--r--src/common.h18
-rw-r--r--src/glue.c8
-rw-r--r--src/nskeyedarchive.c1228
-rw-r--r--src/opack.c10
-rw-r--r--src/socket.c383
-rw-r--r--src/termcolors.c10
-rw-r--r--src/thread.c45
-rw-r--r--src/tlv.c14
-rw-r--r--src/utils.c256
29 files changed, 2049 insertions, 545 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..3407124
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,26 @@
+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..7aac157 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=2:0:2
+
+# 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,7 @@ 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])
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 +110,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..7aca2a0 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -2,9 +2,11 @@ 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 \
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/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..0db7ede 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -12,6 +12,7 @@ libimobiledevice_glue_1_0_la_SOURCES = \
socket.c \
thread.c \
utils.c \
+ nskeyedarchive.c \
collection.c \
termcolors.c \
cbuf.c \
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/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/socket.c b/src/socket.c
index 1029a71..5276b1e 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -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,7 +459,7 @@ 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;
@@ -303,9 +486,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));
@@ -699,7 +879,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;
@@ -742,6 +922,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
@@ -840,7 +1026,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 +1110,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 +1118,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 +1162,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 +1185,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 +1235,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 +1285,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 +1333,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 +1346,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 +1368,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 +1393,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);
-}