Initialisierung

This commit is contained in:
2020-04-19 14:49:21 +02:00
parent 3fdd1b36fc
commit 9fd48d50e3
293 changed files with 38035 additions and 0 deletions

6
lib/plist/CMakeLists.txt Executable file
View File

@@ -0,0 +1,6 @@
cmake_minimum_required(VERSION 3.4.1)
aux_source_directory(. plist_src)
set(DIR_SRCS ${plist_src})
add_library( plist
STATIC
${DIR_SRCS})

119
lib/plist/base64.c Executable file
View File

@@ -0,0 +1,119 @@
/*
* base64.c
* base64 encode/decode implementation
*
* Copyright (c) 2011 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
*/
#include <string.h>
#include "base64.h"
static const char base64_str[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const char base64_pad = '=';
static const signed char base64_table[256] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
};
size_t base64encode(char *outbuf, const unsigned char *buf, size_t size)
{
if (!outbuf || !buf || (size <= 0)) {
return 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 m;
}
unsigned char *base64decode(const char *buf, size_t *size)
{
if (!buf || !size) return NULL;
size_t len = (*size > 0) ? *size : strlen(buf);
if (len <= 0) return NULL;
unsigned char *outbuf = (unsigned char*)malloc((len/4)*3+3);
const char *ptr = buf;
int p = 0;
int wv, w1, w2, w3, w4;
int tmpval[4];
int tmpcnt = 0;
do {
while (ptr < buf+len && (*ptr == ' ' || *ptr == '\t' || *ptr == '\n' || *ptr == '\r')) {
ptr++;
}
if (*ptr == '\0' || ptr >= buf+len) {
break;
}
if ((wv = base64_table[(int)(unsigned char)*ptr++]) == -1) {
continue;
}
tmpval[tmpcnt++] = wv;
if (tmpcnt == 4) {
tmpcnt = 0;
w1 = tmpval[0];
w2 = tmpval[1];
w3 = tmpval[2];
w4 = tmpval[3];
if (w1 >= 0 && w2 >= 0) {
outbuf[p++] = (unsigned char)(((w1 << 2) + (w2 >> 4)) & 0xFF);
}
if (w2 >= 0 && w3 >= 0) {
outbuf[p++] = (unsigned char)(((w2 << 4) + (w3 >> 2)) & 0xFF);
}
if (w3 >= 0 && w4 >= 0) {
outbuf[p++] = (unsigned char)(((w3 << 6) + w4) & 0xFF);
}
}
} while (1);
outbuf[p] = 0;
*size = p;
return outbuf;
}

28
lib/plist/base64.h Executable file
View File

@@ -0,0 +1,28 @@
/*
* base64.h
* base64 encode/decode implementation
*
* Copyright (c) 2011 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 BASE64_H
#define BASE64_H
#include <stdlib.h>
size_t base64encode(char *outbuf, const unsigned char *buf, size_t size);
unsigned char *base64decode(const char *buf, size_t *size);
#endif

1381
lib/plist/bplist.c Executable file

File diff suppressed because it is too large Load Diff

61
lib/plist/bytearray.c Executable file
View File

@@ -0,0 +1,61 @@
/*
* bytearray.c
* simple byte array implementation
*
* Copyright (c) 2011 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
*/
#include <string.h>
#include "bytearray.h"
#define PAGE_SIZE 4096
bytearray_t *byte_array_new(size_t initial)
{
bytearray_t *a = (bytearray_t*)malloc(sizeof(bytearray_t));
a->capacity = (initial > PAGE_SIZE) ? (initial+(PAGE_SIZE-1)) & (~(PAGE_SIZE-1)) : PAGE_SIZE;
a->data = malloc(a->capacity);
a->len = 0;
return a;
}
void byte_array_free(bytearray_t *ba)
{
if (!ba) return;
if (ba->data) {
free(ba->data);
}
free(ba);
}
void byte_array_grow(bytearray_t *ba, size_t amount)
{
size_t increase = (amount > PAGE_SIZE) ? (amount+(PAGE_SIZE-1)) & (~(PAGE_SIZE-1)) : PAGE_SIZE;
ba->data = realloc(ba->data, ba->capacity + increase);
ba->capacity += increase;
}
void byte_array_append(bytearray_t *ba, void *buf, size_t len)
{
if (!ba || !ba->data || (len <= 0)) return;
size_t remaining = ba->capacity-ba->len;
if (len > remaining) {
size_t needed = len - remaining;
byte_array_grow(ba, needed);
}
memcpy(((char*)ba->data) + ba->len, buf, len);
ba->len += len;
}

36
lib/plist/bytearray.h Executable file
View File

@@ -0,0 +1,36 @@
/*
* bytearray.h
* header file for simple byte array implementation
*
* Copyright (c) 2011 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 BYTEARRAY_H
#define BYTEARRAY_H
#include <stdlib.h>
typedef struct bytearray_t {
void *data;
size_t len;
size_t capacity;
} bytearray_t;
bytearray_t *byte_array_new(size_t initial);
void byte_array_free(bytearray_t *ba);
void byte_array_grow(bytearray_t *ba, size_t amount);
void byte_array_append(bytearray_t *ba, void *buf, size_t len);
#endif

46
lib/plist/cnary.c Executable file
View File

@@ -0,0 +1,46 @@
/*
* cnary.c
*
* Created on: Mar 9, 2011
* Author: posixninja
*
* Copyright (c) 2011 Joshua Hill. 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
*/
#include <stdio.h>
#include "node.h"
int main(int argc, char* argv[]) {
puts("Creating root node");
node_t* root = node_create(NULL, NULL);
puts("Creating child 1 node");
node_t* one = node_create(root, NULL);
puts("Creating child 2 node");
node_t* two = node_create(root, NULL);
puts("Creating child 3 node");
node_t* three = node_create(one, NULL);
puts("Debugging root node");
node_debug(root);
puts("Destroying root node");
node_destroy(root);
return 0;
}

140
lib/plist/hashtable.c Executable file
View File

@@ -0,0 +1,140 @@
/*
* hashtable.c
* really simple hash table implementation
*
* Copyright (c) 2011-2016 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
*/
#include "hashtable.h"
hashtable_t* hash_table_new(hash_func_t hash_func, compare_func_t compare_func, free_func_t free_func)
{
hashtable_t* ht = (hashtable_t*)malloc(sizeof(hashtable_t));
int i;
for (i = 0; i < 4096; i++) {
ht->entries[i] = NULL;
}
ht->count = 0;
ht->hash_func = hash_func;
ht->compare_func = compare_func;
ht->free_func = free_func;
return ht;
}
void hash_table_destroy(hashtable_t *ht)
{
if (!ht) return;
int i = 0;
for (i = 0; i < 4096; i++) {
if (ht->entries[i]) {
hashentry_t* e = ht->entries[i];
while (e) {
if (ht->free_func) {
ht->free_func(e->value);
}
hashentry_t* old = e;
e = e->next;
free(old);
}
}
}
free(ht);
}
void hash_table_insert(hashtable_t* ht, void *key, void *value)
{
if (!ht || !key) return;
unsigned int hash = ht->hash_func(key);
int idx0 = hash & 0xFFF;
// get the idx0 list
hashentry_t* e = ht->entries[idx0];
while (e) {
if (ht->compare_func(e->key, key)) {
// element already present. replace value.
e->value = value;
return;
}
e = e->next;
}
// if we get here, the element is not yet in the list.
// make a new entry.
hashentry_t* entry = (hashentry_t*)malloc(sizeof(hashentry_t));
entry->key = key;
entry->value = value;
if (!ht->entries[idx0]) {
// first entry
entry->next = NULL;
} else {
// add to list
entry->next = ht->entries[idx0];
}
ht->entries[idx0] = entry;
ht->count++;
}
void* hash_table_lookup(hashtable_t* ht, void *key)
{
if (!ht || !key) return NULL;
unsigned int hash = ht->hash_func(key);
int idx0 = hash & 0xFFF;
hashentry_t* e = ht->entries[idx0];
while (e) {
if (ht->compare_func(e->key, key)) {
return e->value;
}
e = e->next;
}
return NULL;
}
void hash_table_remove(hashtable_t* ht, void *key)
{
if (!ht || !key) return;
unsigned int hash = ht->hash_func(key);
int idx0 = hash & 0xFFF;
// get the idx0 list
hashentry_t* e = ht->entries[idx0];
hashentry_t* last = e;
while (e) {
if (ht->compare_func(e->key, key)) {
// found element, remove it from the list
hashentry_t* old = e;
if (e == ht->entries[idx0]) {
ht->entries[idx0] = e->next;
} else {
last->next = e->next;
}
if (ht->free_func) {
ht->free_func(old->value);
}
free(old);
return;
}
last = e;
e = e->next;
}
}

50
lib/plist/hashtable.h Executable file
View File

@@ -0,0 +1,50 @@
/*
* hashtable.h
* header file for really simple hash table implementation
*
* Copyright (c) 2011-2016 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 HASHTABLE_H
#define HASHTABLE_H
#include <stdlib.h>
typedef struct hashentry_t {
void *key;
void *value;
void *next;
} hashentry_t;
typedef unsigned int(*hash_func_t)(const void* key);
typedef int (*compare_func_t)(const void *a, const void *b);
typedef void (*free_func_t)(void *ptr);
typedef struct hashtable_t {
hashentry_t *entries[4096];
size_t count;
hash_func_t hash_func;
compare_func_t compare_func;
free_func_t free_func;
} hashtable_t;
hashtable_t* hash_table_new(hash_func_t hash_func, compare_func_t compare_func, free_func_t free_func);
void hash_table_destroy(hashtable_t *ht);
void hash_table_insert(hashtable_t* ht, void *key, void *value);
void* hash_table_lookup(hashtable_t* ht, void *key);
void hash_table_remove(hashtable_t* ht, void *key);
#endif

47
lib/plist/list.c Executable file
View File

@@ -0,0 +1,47 @@
/*
* list.c
*
* Created on: Mar 8, 2011
* Author: posixninja
*
* Copyright (c) 2011 Joshua Hill. 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
*/
#include <stdio.h>
#include <stdlib.h>
#include "list.h"
void list_init(list_t* list) {
list->next = NULL;
list->prev = list;
}
void list_destroy(list_t* list) {
if(list) {
free(list);
}
}
int list_add(list_t* list, object_t* object) {
return -1;
}
int list_remove(list_t* list, object_t* object) {
return -1;
}

40
lib/plist/list.h Executable file
View File

@@ -0,0 +1,40 @@
/*
* list.h
*
* Created on: Mar 8, 2011
* Author: posixninja
*
* Copyright (c) 2011 Joshua Hill. 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 LIST_H_
#define LIST_H_
#include "object.h"
typedef struct list_t {
void* next;
void* prev;
} list_t;
void list_init(struct list_t* list);
void list_destroy(struct list_t* list);
int list_add(struct list_t* list, struct object_t* object);
int list_remove(struct list_t* list, struct object_t* object);
#endif /* LIST_H_ */

216
lib/plist/node.c Executable file
View File

@@ -0,0 +1,216 @@
/*
* node.c
*
* Created on: Mar 7, 2011
* Author: posixninja
*
* Copyright (c) 2011 Joshua Hill. 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
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "node.h"
#include "node_list.h"
void node_destroy(node_t* node) {
if(!node) return;
if (node->children && node->children->count > 0) {
node_t* ch;
while ((ch = node->children->begin)) {
node_list_remove(node->children, ch);
node_destroy(ch);
}
}
node_list_destroy(node->children);
node->children = NULL;
free(node);
}
node_t* node_create(node_t* parent, void* data) {
int error = 0;
node_t* node = (node_t*) malloc(sizeof(node_t));
if(node == NULL) {
return NULL;
}
memset(node, '\0', sizeof(node_t));
node->data = data;
node->next = NULL;
node->prev = NULL;
node->count = 0;
node->parent = NULL;
node->children = NULL;
// Pass NULL to create a root node
if(parent != NULL) {
// This is a child node so attach it to it's parent
error = node_attach(parent, node);
if(error < 0) {
// Unable to attach nodes
printf("ERROR: %d \"Unable to attach nodes\"\n", error);
node_destroy(node);
return NULL;
}
}
return node;
}
int node_attach(node_t* parent, node_t* child) {
if (!parent || !child) return -1;
child->parent = parent;
if(!parent->children) {
parent->children = node_list_create();
}
int res = node_list_add(parent->children, child);
if (res == 0) {
parent->count++;
}
return res;
}
int node_detach(node_t* parent, node_t* child) {
if (!parent || !child) return -1;
int node_index = node_list_remove(parent->children, child);
if (node_index >= 0) {
parent->count--;
}
return node_index;
}
int node_insert(node_t* parent, unsigned int node_index, node_t* child)
{
if (!parent || !child) return -1;
child->parent = parent;
if(!parent->children) {
parent->children = node_list_create();
}
int res = node_list_insert(parent->children, node_index, child);
if (res == 0) {
parent->count++;
}
return res;
}
static void _node_debug(node_t* node, unsigned int depth) {
unsigned int i = 0;
node_t* current = NULL;
for(i = 0; i < depth; i++) {
printf("\t");
}
if(!node->parent) {
printf("ROOT\n");
}
if(!node->children && node->parent) {
printf("LEAF\n");
} else {
if(node->parent) {
printf("NODE\n");
}
for (current = node_first_child(node); current; current = node_next_sibling(current)) {
_node_debug(current, depth+1);
}
}
}
void node_debug(node_t* node)
{
_node_debug(node, 0);
}
unsigned int node_n_children(struct node_t* node)
{
if (!node) return 0;
return node->count;
}
node_t* node_nth_child(struct node_t* node, unsigned int n)
{
if (!node || !node->children || !node->children->begin) return NULL;
unsigned int node_index = 0;
int found = 0;
node_t *ch;
for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) {
if (node_index++ == n) {
found = 1;
break;
}
}
if (!found) {
return NULL;
}
return ch;
}
node_t* node_first_child(struct node_t* node)
{
if (!node || !node->children) return NULL;
return node->children->begin;
}
node_t* node_prev_sibling(struct node_t* node)
{
if (!node) return NULL;
return node->prev;
}
node_t* node_next_sibling(struct node_t* node)
{
if (!node) return NULL;
return node->next;
}
int node_child_position(struct node_t* parent, node_t* child)
{
if (!parent || !parent->children || !parent->children->begin || !child) return -1;
int node_index = 0;
int found = 0;
node_t *ch;
for (ch = node_first_child(parent); ch; ch = node_next_sibling(ch)) {
if (ch == child) {
found = 1;
break;
}
node_index++;
}
if (!found) {
return -1;
}
return node_index;
}
node_t* node_copy_deep(node_t* node, copy_func_t copy_func)
{
if (!node) return NULL;
void *data = NULL;
if (copy_func) {
data = copy_func(node->data);
}
node_t* copy = node_create(NULL, data);
node_t* ch;
for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) {
node_t* cc = node_copy_deep(ch, copy_func);
node_attach(copy, cc);
}
return copy;
}

65
lib/plist/node.h Executable file
View File

@@ -0,0 +1,65 @@
/*
* node.h
*
* Created on: Mar 7, 2011
* Author: posixninja
*
* Copyright (c) 2011 Joshua Hill. 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 NODE_H_
#define NODE_H_
#include "object.h"
#define NODE_TYPE 1;
struct node_list_t;
// This class implements the abstract iterator class
typedef struct node_t {
// Super class
struct node_t* next;
struct node_t* prev;
unsigned int count;
// Local Members
void *data;
struct node_t* parent;
struct node_list_t* children;
} node_t;
void node_destroy(struct node_t* node);
struct node_t* node_create(struct node_t* parent, void* data);
int node_attach(struct node_t* parent, struct node_t* child);
int node_detach(struct node_t* parent, struct node_t* child);
int node_insert(struct node_t* parent, unsigned int index, struct node_t* child);
unsigned int node_n_children(struct node_t* node);
node_t* node_nth_child(struct node_t* node, unsigned int n);
node_t* node_first_child(struct node_t* node);
node_t* node_prev_sibling(struct node_t* node);
node_t* node_next_sibling(struct node_t* node);
int node_child_position(struct node_t* parent, node_t* child);
typedef void* (*copy_func_t)(const void *src);
node_t* node_copy_deep(node_t* node, copy_func_t copy_func);
void node_debug(struct node_t* node);
#endif /* NODE_H_ */

154
lib/plist/node_list.c Executable file
View File

@@ -0,0 +1,154 @@
/*
* node_list.c
*
* Created on: Mar 8, 2011
* Author: posixninja
*
* Copyright (c) 2011 Joshua Hill. 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
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "list.h"
#include "node.h"
#include "node_list.h"
void node_list_destroy(node_list_t* list) {
if(list != NULL) {
list_destroy((list_t*) list);
}
}
node_list_t* node_list_create() {
node_list_t* list = (node_list_t*) malloc(sizeof(node_list_t));
if(list == NULL) {
return NULL;
}
memset(list, '\0', sizeof(node_list_t));
// Initialize structure
list_init((list_t*) list);
list->count = 0;
return list;
}
int node_list_add(node_list_t* list, node_t* node) {
if (!list || !node) return -1;
// Find the last element in the list
node_t* last = list->end;
// Setup our new node as the new last element
node->next = NULL;
node->prev = last;
// Set the next element of our old "last" element
if (last) {
// but only if the node list is not empty
last->next = node;
}
// Set the lists prev to the new last element
list->end = node;
// Increment our node count for this list
list->count++;
return 0;
}
int node_list_insert(node_list_t* list, unsigned int node_index, node_t* node) {
if (!list || !node) return -1;
if (node_index >= list->count) {
return node_list_add(list, node);
}
// Get the first element in the list
node_t* cur = list->begin;
unsigned int pos = 0;
node_t* prev = NULL;
if (node_index > 0) {
while (pos < node_index) {
prev = cur;
cur = cur->next;
pos++;
}
}
if (prev) {
// Set previous node
node->prev = prev;
// Set next node of our new node to next node of the previous node
node->next = prev->next;
// Set next node of previous node to our new node
prev->next = node;
} else {
node->prev = NULL;
// get old first element in list
node->next = list->begin;
// set new node as first element in list
list->begin = node;
}
if (node->next == NULL) {
// Set the lists prev to the new last element
list->end = node;
} else {
// set prev of the new next element to our node
node->next->prev = node;
}
// Increment our node count for this list
list->count++;
return 0;
}
int node_list_remove(node_list_t* list, node_t* node) {
if (!list || !node) return -1;
if (list->count == 0) return -1;
int node_index = 0;
node_t* n;
for (n = list->begin; n; n = n->next) {
if (node == n) {
node_t* newnode = node->next;
if (node->prev) {
node->prev->next = newnode;
if (newnode) {
newnode->prev = node->prev;
} else {
// last element in the list
list->end = node->prev;
}
} else {
// we just removed the first element
if (newnode) {
newnode->prev = NULL;
}
list->begin = newnode;
}
list->count--;
return node_index;
}
node_index++;
}
return -1;
}

47
lib/plist/node_list.h Executable file
View File

@@ -0,0 +1,47 @@
/*
* node_list.h
*
* Created on: Mar 8, 2011
* Author: posixninja
*
* Copyright (c) 2011 Joshua Hill. 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 NODE_LIST_H_
#define NODE_LIST_H_
struct node_t;
// This class implements the list_t abstract class
typedef struct node_list_t {
// list_t members
struct node_t* begin;
struct node_t* end;
// node_list_t members
unsigned int count;
} node_list_t;
void node_list_destroy(struct node_list_t* list);
struct node_list_t* node_list_create();
int node_list_add(node_list_t* list, node_t* node);
int node_list_insert(node_list_t* list, unsigned int index, node_t* node);
int node_list_remove(node_list_t* list, node_t* node);
#endif /* NODE_LIST_H_ */

41
lib/plist/object.h Executable file
View File

@@ -0,0 +1,41 @@
/*
* object.h
*
* Created on: Mar 8, 2011
* Author: posixninja
*
* Copyright (c) 2011 Joshua Hill. 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 OBJECT_H_
#define OBJECT_H_
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
typedef struct object_t {
void* value;
unsigned int type;
unsigned int size;
} object_t;
#endif /* OBJECT_H_ */

963
lib/plist/plist.c Executable file
View File

@@ -0,0 +1,963 @@
/*
* plist.c
* Builds plist XML structures
*
* Copyright (c) 2009-2016 Nikias Bassen All Rights Reserved.
* Copyright (c) 2010-2015 Martin Szulecki All Rights Reserved.
* Copyright (c) 2008 Zach C. 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
*/
#include <string.h>
#include <assert.h>
#include "plist.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#ifdef WIN32
#include <windows.h>
#else
#include <pthread.h>
#endif
#include "node.h"
#include "hashtable.h"
extern void plist_xml_init(void);
extern void plist_xml_deinit(void);
extern void plist_bin_init(void);
extern void plist_bin_deinit(void);
static void internal_plist_init(void)
{
plist_bin_init();
plist_xml_init();
}
static void internal_plist_deinit(void)
{
plist_bin_deinit();
plist_xml_deinit();
}
#ifdef WIN32
typedef volatile struct {
LONG lock;
int state;
} thread_once_t;
static thread_once_t init_once = {0, 0};
static thread_once_t deinit_once = {0, 0};
void thread_once(thread_once_t *once_control, void (*init_routine)(void))
{
while (InterlockedExchange(&(once_control->lock), 1) != 0) {
Sleep(1);
}
if (!once_control->state) {
once_control->state = 1;
init_routine();
}
InterlockedExchange(&(once_control->lock), 0);
}
BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved)
{
switch (dwReason) {
case DLL_PROCESS_ATTACH:
thread_once(&init_once, internal_plist_init);
break;
case DLL_PROCESS_DETACH:
thread_once(&deinit_once, internal_plist_deinit);
break;
default:
break;
}
return 1;
}
#else
static pthread_once_t init_once = PTHREAD_ONCE_INIT;
static pthread_once_t deinit_once = PTHREAD_ONCE_INIT;
static void __attribute__((constructor)) libplist_initialize(void)
{
pthread_once(&init_once, internal_plist_init);
}
static void __attribute__((destructor)) libplist_deinitialize(void)
{
pthread_once(&deinit_once, internal_plist_deinit);
}
#endif
PLIST_API int plist_is_binary(const char *plist_data, uint32_t length)
{
if (length < 8) {
return 0;
}
return (memcmp(plist_data, "bplist00", 8) == 0);
}
PLIST_API void plist_from_memory(const char *plist_data, uint32_t length, plist_t * plist)
{
if (length < 8) {
*plist = NULL;
return;
}
if (plist_is_binary(plist_data, length)) {
plist_from_bin(plist_data, length, plist);
} else {
plist_from_xml(plist_data, length, plist);
}
}
plist_t plist_new_node(plist_data_t data)
{
return (plist_t) node_create(NULL, data);
}
plist_data_t plist_get_data(const plist_t node)
{
if (!node)
return NULL;
return ((node_t*)node)->data;
}
plist_data_t plist_new_plist_data(void)
{
plist_data_t data = (plist_data_t) calloc(sizeof(struct plist_data_s), 1);
return data;
}
static unsigned int dict_key_hash(const void *data)
{
plist_data_t keydata = (plist_data_t)data;
unsigned int hash = 5381;
size_t i;
char *str = keydata->strval;
for (i = 0; i < keydata->length; str++, i++) {
hash = ((hash << 5) + hash) + *str;
}
return hash;
}
static int dict_key_compare(const void* a, const void* b)
{
plist_data_t data_a = (plist_data_t)a;
plist_data_t data_b = (plist_data_t)b;
if (data_a->strval == NULL || data_b->strval == NULL) {
return FALSE;
}
if (data_a->length != data_b->length) {
return FALSE;
}
return (strcmp(data_a->strval, data_b->strval) == 0) ? TRUE : FALSE;
}
void plist_free_data(plist_data_t data)
{
if (data)
{
switch (data->type)
{
case PLIST_KEY:
case PLIST_STRING:
free(data->strval);
break;
case PLIST_DATA:
free(data->buff);
break;
case PLIST_DICT:
hash_table_destroy(data->hashtable);
break;
default:
break;
}
free(data);
}
}
static int plist_free_node(node_t* node)
{
plist_data_t data = NULL;
int node_index = node_detach(node->parent, node);
data = plist_get_data(node);
plist_free_data(data);
node->data = NULL;
node_t *ch;
for (ch = node_first_child(node); ch; ) {
node_t *next = node_next_sibling(ch);
plist_free_node(ch);
ch = next;
}
node_destroy(node);
return node_index;
}
PLIST_API plist_t plist_new_dict(void)
{
plist_data_t data = plist_new_plist_data();
data->type = PLIST_DICT;
return plist_new_node(data);
}
PLIST_API plist_t plist_new_array(void)
{
plist_data_t data = plist_new_plist_data();
data->type = PLIST_ARRAY;
return plist_new_node(data);
}
//These nodes should not be handled by users
static plist_t plist_new_key(const char *val)
{
plist_data_t data = plist_new_plist_data();
data->type = PLIST_KEY;
data->strval = strdup(val);
data->length = strlen(val);
return plist_new_node(data);
}
PLIST_API plist_t plist_new_string(const char *val)
{
plist_data_t data = plist_new_plist_data();
data->type = PLIST_STRING;
data->strval = strdup(val);
data->length = strlen(val);
return plist_new_node(data);
}
PLIST_API plist_t plist_new_bool(uint8_t val)
{
plist_data_t data = plist_new_plist_data();
data->type = PLIST_BOOLEAN;
data->boolval = val;
data->length = sizeof(uint8_t);
return plist_new_node(data);
}
PLIST_API plist_t plist_new_uint(uint64_t val)
{
plist_data_t data = plist_new_plist_data();
data->type = PLIST_UINT;
data->intval = val;
data->length = sizeof(uint64_t);
return plist_new_node(data);
}
PLIST_API plist_t plist_new_uid(uint64_t val)
{
plist_data_t data = plist_new_plist_data();
data->type = PLIST_UID;
data->intval = val;
data->length = sizeof(uint64_t);
return plist_new_node(data);
}
PLIST_API plist_t plist_new_real(double val)
{
plist_data_t data = plist_new_plist_data();
data->type = PLIST_REAL;
data->realval = val;
data->length = sizeof(double);
return plist_new_node(data);
}
PLIST_API plist_t plist_new_data(const char *val, uint64_t length)
{
plist_data_t data = plist_new_plist_data();
data->type = PLIST_DATA;
data->buff = (uint8_t *) malloc(length);
memcpy(data->buff, val, length);
data->length = length;
return plist_new_node(data);
}
PLIST_API plist_t plist_new_date(int32_t sec, int32_t usec)
{
plist_data_t data = plist_new_plist_data();
data->type = PLIST_DATE;
data->realval = (double)sec + (double)usec / 1000000;
data->length = sizeof(double);
return plist_new_node(data);
}
PLIST_API void plist_free(plist_t plist)
{
if (plist)
{
plist_free_node(plist);
}
}
static void plist_copy_node(node_t *node, void *parent_node_ptr)
{
plist_type node_type = PLIST_NONE;
plist_t newnode = NULL;
plist_data_t data = plist_get_data(node);
plist_data_t newdata = plist_new_plist_data();
assert(data); // plist should always have data
memcpy(newdata, data, sizeof(struct plist_data_s));
node_type = plist_get_node_type(node);
switch (node_type) {
case PLIST_DATA:
newdata->buff = (uint8_t *) malloc(data->length);
memcpy(newdata->buff, data->buff, data->length);
break;
case PLIST_KEY:
case PLIST_STRING:
newdata->strval = strdup((char *) data->strval);
break;
case PLIST_DICT:
if (data->hashtable) {
hashtable_t* ht = hash_table_new(dict_key_hash, dict_key_compare, NULL);
assert(ht);
plist_t current = NULL;
for (current = (plist_t)node_first_child(node);
ht && current;
current = (plist_t)node_next_sibling(node_next_sibling(current)))
{
hash_table_insert(ht, ((node_t*)current)->data, node_next_sibling(current));
}
newdata->hashtable = ht;
}
break;
default:
break;
}
newnode = plist_new_node(newdata);
if (*(plist_t*)parent_node_ptr)
{
node_attach(*(plist_t*)parent_node_ptr, newnode);
}
else
{
*(plist_t*)parent_node_ptr = newnode;
}
node_t *ch;
for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) {
plist_copy_node(ch, &newnode);
}
}
PLIST_API plist_t plist_copy(plist_t node)
{
plist_t copied = NULL;
plist_copy_node(node, &copied);
return copied;
}
PLIST_API uint32_t plist_array_get_size(plist_t node)
{
uint32_t ret = 0;
if (node && PLIST_ARRAY == plist_get_node_type(node))
{
ret = node_n_children(node);
}
return ret;
}
PLIST_API plist_t plist_array_get_item(plist_t node, uint32_t n)
{
plist_t ret = NULL;
if (node && PLIST_ARRAY == plist_get_node_type(node))
{
ret = (plist_t)node_nth_child(node, n);
}
return ret;
}
PLIST_API uint32_t plist_array_get_item_index(plist_t node)
{
plist_t father = plist_get_parent(node);
if (PLIST_ARRAY == plist_get_node_type(father))
{
return node_child_position(father, node);
}
return 0;
}
PLIST_API void plist_array_set_item(plist_t node, plist_t item, uint32_t n)
{
if (node && PLIST_ARRAY == plist_get_node_type(node))
{
plist_t old_item = plist_array_get_item(node, n);
if (old_item)
{
int idx = plist_free_node(old_item);
if (idx < 0) {
node_attach(node, item);
} else {
node_insert(node, idx, item);
}
}
}
return;
}
PLIST_API void plist_array_append_item(plist_t node, plist_t item)
{
if (node && PLIST_ARRAY == plist_get_node_type(node))
{
node_attach(node, item);
}
return;
}
PLIST_API void plist_array_insert_item(plist_t node, plist_t item, uint32_t n)
{
if (node && PLIST_ARRAY == plist_get_node_type(node))
{
node_insert(node, n, item);
}
return;
}
PLIST_API void plist_array_remove_item(plist_t node, uint32_t n)
{
if (node && PLIST_ARRAY == plist_get_node_type(node))
{
plist_t old_item = plist_array_get_item(node, n);
if (old_item)
{
plist_free(old_item);
}
}
return;
}
PLIST_API uint32_t plist_dict_get_size(plist_t node)
{
uint32_t ret = 0;
if (node && PLIST_DICT == plist_get_node_type(node))
{
ret = node_n_children(node) / 2;
}
return ret;
}
PLIST_API void plist_dict_new_iter(plist_t node, plist_dict_iter *iter)
{
if (iter && *iter == NULL)
{
*iter = malloc(sizeof(node_t*));
*((node_t**)(*iter)) = node_first_child(node);
}
return;
}
PLIST_API void plist_dict_next_item(plist_t node, plist_dict_iter iter, char **key, plist_t *val)
{
node_t** iter_node = (node_t**)iter;
if (key)
{
*key = NULL;
}
if (val)
{
*val = NULL;
}
if (node && PLIST_DICT == plist_get_node_type(node) && *iter_node)
{
if (key)
{
plist_get_key_val((plist_t)(*iter_node), key);
}
*iter_node = node_next_sibling(*iter_node);
if (val)
{
*val = (plist_t)(*iter_node);
}
*iter_node = node_next_sibling(*iter_node);
}
return;
}
PLIST_API void plist_dict_get_item_key(plist_t node, char **key)
{
plist_t father = plist_get_parent(node);
if (PLIST_DICT == plist_get_node_type(father))
{
plist_get_key_val( (plist_t) node_prev_sibling(node), key);
}
}
PLIST_API plist_t plist_dict_get_item(plist_t node, const char* key)
{
plist_t ret = NULL;
if (node && PLIST_DICT == plist_get_node_type(node))
{
plist_data_t data = plist_get_data(node);
hashtable_t *ht = (hashtable_t*)data->hashtable;
if (ht) {
struct plist_data_s sdata;
sdata.strval = (char*)key;
sdata.length = strlen(key);
ret = (plist_t)hash_table_lookup(ht, &sdata);
} else {
plist_t current = NULL;
for (current = (plist_t)node_first_child(node);
current;
current = (plist_t)node_next_sibling(node_next_sibling(current)))
{
data = plist_get_data(current);
assert( PLIST_KEY == plist_get_node_type(current) );
if (data && !strcmp(key, data->strval))
{
ret = (plist_t)node_next_sibling(current);
break;
}
}
}
}
return ret;
}
PLIST_API void plist_dict_set_item(plist_t node, const char* key, plist_t item)
{
if (node && PLIST_DICT == plist_get_node_type(node)) {
node_t* old_item = plist_dict_get_item(node, key);
plist_t key_node = NULL;
if (old_item) {
int idx = plist_free_node(old_item);
if (idx < 0) {
node_attach(node, item);
} else {
node_insert(node, idx, item);
}
key_node = node_prev_sibling(item);
} else {
key_node = plist_new_key(key);
node_attach(node, key_node);
node_attach(node, item);
}
hashtable_t *ht = ((plist_data_t)((node_t*)node)->data)->hashtable;
if (ht) {
/* store pointer to item in hash table */
hash_table_insert(ht, (plist_data_t)((node_t*)key_node)->data, item);
} else {
if (((node_t*)node)->count > 500) {
/* make new hash table */
ht = hash_table_new(dict_key_hash, dict_key_compare, NULL);
/* calculate the hashes for all entries we have so far */
plist_t current = NULL;
for (current = (plist_t)node_first_child(node);
ht && current;
current = (plist_t)node_next_sibling(node_next_sibling(current)))
{
hash_table_insert(ht, ((node_t*)current)->data, node_next_sibling(current));
}
((plist_data_t)((node_t*)node)->data)->hashtable = ht;
}
}
}
return;
}
PLIST_API void plist_dict_insert_item(plist_t node, const char* key, plist_t item)
{
plist_dict_set_item(node, key, item);
}
PLIST_API void plist_dict_remove_item(plist_t node, const char* key)
{
if (node && PLIST_DICT == plist_get_node_type(node))
{
plist_t old_item = plist_dict_get_item(node, key);
if (old_item)
{
plist_t key_node = node_prev_sibling(old_item);
hashtable_t* ht = ((plist_data_t)((node_t*)node)->data)->hashtable;
if (ht) {
hash_table_remove(ht, ((node_t*)key_node)->data);
}
plist_free(key_node);
plist_free(old_item);
}
}
return;
}
PLIST_API void plist_dict_merge(plist_t *target, plist_t source)
{
if (!target || !*target || (plist_get_node_type(*target) != PLIST_DICT) || !source || (plist_get_node_type(source) != PLIST_DICT))
return;
char* key = NULL;
plist_dict_iter it = NULL;
plist_t subnode = NULL;
plist_dict_new_iter(source, &it);
if (!it)
return;
do {
plist_dict_next_item(source, it, &key, &subnode);
if (!key)
break;
plist_dict_set_item(*target, key, plist_copy(subnode));
free(key);
key = NULL;
} while (1);
free(it);
}
PLIST_API plist_t plist_access_pathv(plist_t plist, uint32_t length, va_list v)
{
plist_t current = plist;
plist_type type = PLIST_NONE;
uint32_t i = 0;
for (i = 0; i < length && current; i++)
{
type = plist_get_node_type(current);
if (type == PLIST_ARRAY)
{
uint32_t n = va_arg(v, uint32_t);
current = plist_array_get_item(current, n);
}
else if (type == PLIST_DICT)
{
const char* key = va_arg(v, const char*);
current = plist_dict_get_item(current, key);
}
}
return current;
}
PLIST_API plist_t plist_access_path(plist_t plist, uint32_t length, ...)
{
plist_t ret = NULL;
va_list v;
va_start(v, length);
ret = plist_access_pathv(plist, length, v);
va_end(v);
return ret;
}
static void plist_get_type_and_value(plist_t node, plist_type * type, void *value, uint64_t * length)
{
plist_data_t data = NULL;
if (!node)
return;
data = plist_get_data(node);
*type = data->type;
*length = data->length;
switch (*type)
{
case PLIST_BOOLEAN:
*((char *) value) = data->boolval;
break;
case PLIST_UINT:
case PLIST_UID:
*((uint64_t *) value) = data->intval;
break;
case PLIST_REAL:
case PLIST_DATE:
*((double *) value) = data->realval;
break;
case PLIST_KEY:
case PLIST_STRING:
*((char **) value) = strdup(data->strval);
break;
case PLIST_DATA:
*((uint8_t **) value) = (uint8_t *) malloc(*length * sizeof(uint8_t));
memcpy(*((uint8_t **) value), data->buff, *length * sizeof(uint8_t));
break;
case PLIST_ARRAY:
case PLIST_DICT:
default:
break;
}
}
PLIST_API plist_t plist_get_parent(plist_t node)
{
return node ? (plist_t) ((node_t*) node)->parent : NULL;
}
PLIST_API plist_type plist_get_node_type(plist_t node)
{
if (node)
{
plist_data_t data = plist_get_data(node);
if (data)
return data->type;
}
return PLIST_NONE;
}
PLIST_API void plist_get_key_val(plist_t node, char **val)
{
plist_type type = plist_get_node_type(node);
uint64_t length = 0;
if (PLIST_KEY == type)
plist_get_type_and_value(node, &type, (void *) val, &length);
assert(length == strlen(*val));
}
PLIST_API void plist_get_string_val(plist_t node, char **val)
{
plist_type type = plist_get_node_type(node);
uint64_t length = 0;
if (PLIST_STRING == type)
plist_get_type_and_value(node, &type, (void *) val, &length);
assert(length == strlen(*val));
}
PLIST_API void plist_get_bool_val(plist_t node, uint8_t * val)
{
plist_type type = plist_get_node_type(node);
uint64_t length = 0;
if (PLIST_BOOLEAN == type)
plist_get_type_and_value(node, &type, (void *) val, &length);
assert(length == sizeof(uint8_t));
}
PLIST_API void plist_get_uint_val(plist_t node, uint64_t * val)
{
plist_type type = plist_get_node_type(node);
uint64_t length = 0;
if (PLIST_UINT == type)
plist_get_type_and_value(node, &type, (void *) val, &length);
assert(length == sizeof(uint64_t) || length == 16);
}
PLIST_API void plist_get_uid_val(plist_t node, uint64_t * val)
{
plist_type type = plist_get_node_type(node);
uint64_t length = 0;
if (PLIST_UID == type)
plist_get_type_and_value(node, &type, (void *) val, &length);
assert(length == sizeof(uint64_t));
}
PLIST_API void plist_get_real_val(plist_t node, double *val)
{
plist_type type = plist_get_node_type(node);
uint64_t length = 0;
if (PLIST_REAL == type)
plist_get_type_and_value(node, &type, (void *) val, &length);
assert(length == sizeof(double));
}
PLIST_API void plist_get_data_val(plist_t node, char **val, uint64_t * length)
{
plist_type type = plist_get_node_type(node);
if (PLIST_DATA == type)
plist_get_type_and_value(node, &type, (void *) val, length);
}
PLIST_API void plist_get_date_val(plist_t node, int32_t * sec, int32_t * usec)
{
plist_type type = plist_get_node_type(node);
uint64_t length = 0;
double val = 0;
if (PLIST_DATE == type)
plist_get_type_and_value(node, &type, (void *) &val, &length);
assert(length == sizeof(double));
*sec = (int32_t)val;
*usec = (int32_t)fabs((val - (int64_t)val) * 1000000);
}
int plist_data_compare(const void *a, const void *b)
{
plist_data_t val_a = NULL;
plist_data_t val_b = NULL;
if (!a || !b)
return FALSE;
if (!((node_t*) a)->data || !((node_t*) b)->data)
return FALSE;
val_a = plist_get_data((plist_t) a);
val_b = plist_get_data((plist_t) b);
if (val_a->type != val_b->type)
return FALSE;
switch (val_a->type)
{
case PLIST_BOOLEAN:
case PLIST_UINT:
case PLIST_REAL:
case PLIST_DATE:
case PLIST_UID:
if (val_a->length != val_b->length)
return FALSE;
if (val_a->intval == val_b->intval) //it is an union so this is sufficient
return TRUE;
else
return FALSE;
case PLIST_KEY:
case PLIST_STRING:
if (!strcmp(val_a->strval, val_b->strval))
return TRUE;
else
return FALSE;
case PLIST_DATA:
if (val_a->length != val_b->length)
return FALSE;
if (!memcmp(val_a->buff, val_b->buff, val_a->length))
return TRUE;
else
return FALSE;
case PLIST_ARRAY:
case PLIST_DICT:
//compare pointer
if (a == b)
return TRUE;
else
return FALSE;
break;
default:
break;
}
return FALSE;
}
PLIST_API char plist_compare_node_value(plist_t node_l, plist_t node_r)
{
return plist_data_compare(node_l, node_r);
}
static void plist_set_element_val(plist_t node, plist_type type, const void *value, uint64_t length)
{
//free previous allocated buffer
plist_data_t data = plist_get_data(node);
assert(data); // a node should always have data attached
switch (data->type)
{
case PLIST_KEY:
case PLIST_STRING:
free(data->strval);
data->strval = NULL;
break;
case PLIST_DATA:
free(data->buff);
data->buff = NULL;
break;
default:
break;
}
//now handle value
data->type = type;
data->length = length;
switch (type)
{
case PLIST_BOOLEAN:
data->boolval = *((char *) value);
break;
case PLIST_UINT:
case PLIST_UID:
data->intval = *((uint64_t *) value);
break;
case PLIST_REAL:
case PLIST_DATE:
data->realval = *((double *) value);
break;
case PLIST_KEY:
case PLIST_STRING:
data->strval = strdup((char *) value);
break;
case PLIST_DATA:
data->buff = (uint8_t *) malloc(length);
memcpy(data->buff, value, length);
break;
case PLIST_ARRAY:
case PLIST_DICT:
default:
break;
}
}
PLIST_API void plist_set_key_val(plist_t node, const char *val)
{
plist_set_element_val(node, PLIST_KEY, val, strlen(val));
}
PLIST_API void plist_set_string_val(plist_t node, const char *val)
{
plist_set_element_val(node, PLIST_STRING, val, strlen(val));
}
PLIST_API void plist_set_bool_val(plist_t node, uint8_t val)
{
plist_set_element_val(node, PLIST_BOOLEAN, &val, sizeof(uint8_t));
}
PLIST_API void plist_set_uint_val(plist_t node, uint64_t val)
{
plist_set_element_val(node, PLIST_UINT, &val, sizeof(uint64_t));
}
PLIST_API void plist_set_uid_val(plist_t node, uint64_t val)
{
plist_set_element_val(node, PLIST_UID, &val, sizeof(uint64_t));
}
PLIST_API void plist_set_real_val(plist_t node, double val)
{
plist_set_element_val(node, PLIST_REAL, &val, sizeof(double));
}
PLIST_API void plist_set_data_val(plist_t node, const char *val, uint64_t length)
{
plist_set_element_val(node, PLIST_DATA, val, length);
}
PLIST_API void plist_set_date_val(plist_t node, int32_t sec, int32_t usec)
{
double val = (double)sec + (double)usec / 1000000;
plist_set_element_val(node, PLIST_DATE, &val, sizeof(struct timeval));
}

74
lib/plist/plist.h Executable file
View File

@@ -0,0 +1,74 @@
/*
* plist.h
* contains structures and the like for plists
*
* Copyright (c) 2008 Zach C. 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 PLIST_H
#define PLIST_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "plist/plist.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#ifdef _MSC_VER
#pragma warning(disable:4996)
#pragma warning(disable:4244)
#endif
#ifdef WIN32
#define PLIST_API __declspec( dllexport )
#else
#ifdef HAVE_FVISIBILITY
#define PLIST_API __attribute__((visibility("default")))
#else
#define PLIST_API
#endif
#endif
struct plist_data_s
{
union
{
char boolval;
uint64_t intval;
double realval;
char *strval;
uint8_t *buff;
void *hashtable;
};
uint64_t length;
plist_type type;
};
typedef struct plist_data_s *plist_data_t;
plist_t plist_new_node(plist_data_t data);
plist_data_t plist_get_data(const plist_t node);
plist_data_t plist_new_plist_data(void);
void plist_free_data(plist_data_t data);
int plist_data_compare(const void *a, const void *b);
#endif

686
lib/plist/plist/plist.h Executable file
View File

@@ -0,0 +1,686 @@
/**
* @file plist/plist.h
* @brief Main include of libplist
* \internal
*
* Copyright (c) 2008 Jonathan Beck 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 LIBPLIST_H
#define LIBPLIST_H
#ifdef __cplusplus
extern "C"
{
#endif
#ifdef _MSC_VER
typedef __int8 int8_t;
typedef __int16 int16_t;
typedef __int32 int32_t;
typedef __int64 int64_t;
typedef unsigned __int8 uint8_t;
typedef unsigned __int16 uint16_t;
typedef unsigned __int32 uint32_t;
typedef unsigned __int64 uint64_t;
#else
#include <stdint.h>
#endif
#ifdef __llvm__
#if defined(__has_extension)
#if (__has_extension(attribute_deprecated_with_message))
#ifndef PLIST_WARN_DEPRECATED
#define PLIST_WARN_DEPRECATED(x) __attribute__((deprecated(x)))
#endif
#else
#ifndef PLIST_WARN_DEPRECATED
#define PLIST_WARN_DEPRECATED(x) __attribute__((deprecated))
#endif
#endif
#else
#ifndef PLIST_WARN_DEPRECATED
#define PLIST_WARN_DEPRECATED(x) __attribute__((deprecated))
#endif
#endif
#elif (__GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ >= 5)))
#ifndef PLIST_WARN_DEPRECATED
#define PLIST_WARN_DEPRECATED(x) __attribute__((deprecated(x)))
#endif
#elif defined(_MSC_VER)
#ifndef PLIST_WARN_DEPRECATED
#define PLIST_WARN_DEPRECATED(x) __declspec(deprecated(x))
#endif
#else
#define PLIST_WARN_DEPRECATED(x)
#pragma message("WARNING: You need to implement DEPRECATED for this compiler")
#endif
#include <sys/types.h>
#include <stdarg.h>
/**
* \mainpage libplist : A library to handle Apple Property Lists
* \defgroup PublicAPI Public libplist API
*/
/*@{*/
/**
* The basic plist abstract data type.
*/
typedef void *plist_t;
/**
* The plist dictionary iterator.
*/
typedef void *plist_dict_iter;
/**
* The enumeration of plist node types.
*/
typedef enum
{
PLIST_BOOLEAN, /**< Boolean, scalar type */
PLIST_UINT, /**< Unsigned integer, scalar type */
PLIST_REAL, /**< Real, scalar type */
PLIST_STRING, /**< ASCII string, scalar type */
PLIST_ARRAY, /**< Ordered array, structured type */
PLIST_DICT, /**< Unordered dictionary (key/value pair), structured type */
PLIST_DATE, /**< Date, scalar type */
PLIST_DATA, /**< Binary data, scalar type */
PLIST_KEY, /**< Key in dictionaries (ASCII String), scalar type */
PLIST_UID, /**< Special type used for 'keyed encoding' */
PLIST_NONE /**< No type */
} plist_type;
/********************************************
* *
* Creation & Destruction *
* *
********************************************/
/**
* Create a new root plist_t type #PLIST_DICT
*
* @return the created plist
* @sa #plist_type
*/
plist_t plist_new_dict(void);
/**
* Create a new root plist_t type #PLIST_ARRAY
*
* @return the created plist
* @sa #plist_type
*/
plist_t plist_new_array(void);
/**
* Create a new plist_t type #PLIST_STRING
*
* @param val the sting value, encoded in UTF8.
* @return the created item
* @sa #plist_type
*/
plist_t plist_new_string(const char *val);
/**
* Create a new plist_t type #PLIST_BOOLEAN
*
* @param val the boolean value, 0 is false, other values are true.
* @return the created item
* @sa #plist_type
*/
plist_t plist_new_bool(uint8_t val);
/**
* Create a new plist_t type #PLIST_UINT
*
* @param val the unsigned integer value
* @return the created item
* @sa #plist_type
*/
plist_t plist_new_uint(uint64_t val);
/**
* Create a new plist_t type #PLIST_REAL
*
* @param val the real value
* @return the created item
* @sa #plist_type
*/
plist_t plist_new_real(double val);
/**
* Create a new plist_t type #PLIST_DATA
*
* @param val the binary buffer
* @param length the length of the buffer
* @return the created item
* @sa #plist_type
*/
plist_t plist_new_data(const char *val, uint64_t length);
/**
* Create a new plist_t type #PLIST_DATE
*
* @param sec the number of seconds since 01/01/2001
* @param usec the number of microseconds
* @return the created item
* @sa #plist_type
*/
plist_t plist_new_date(int32_t sec, int32_t usec);
/**
* Create a new plist_t type #PLIST_UID
*
* @param val the unsigned integer value
* @return the created item
* @sa #plist_type
*/
plist_t plist_new_uid(uint64_t val);
/**
* Destruct a plist_t node and all its children recursively
*
* @param plist the plist to free
*/
void plist_free(plist_t plist);
/**
* Return a copy of passed node and it's children
*
* @param node the plist to copy
* @return copied plist
*/
plist_t plist_copy(plist_t node);
/********************************************
* *
* Array functions *
* *
********************************************/
/**
* Get size of a #PLIST_ARRAY node.
*
* @param node the node of type #PLIST_ARRAY
* @return size of the #PLIST_ARRAY node
*/
uint32_t plist_array_get_size(plist_t node);
/**
* Get the nth item in a #PLIST_ARRAY node.
*
* @param node the node of type #PLIST_ARRAY
* @param n the index of the item to get. Range is [0, array_size[
* @return the nth item or NULL if node is not of type #PLIST_ARRAY
*/
plist_t plist_array_get_item(plist_t node, uint32_t n);
/**
* Get the index of an item. item must be a member of a #PLIST_ARRAY node.
*
* @param node the node
* @return the node index
*/
uint32_t plist_array_get_item_index(plist_t node);
/**
* Set the nth item in a #PLIST_ARRAY node.
* The previous item at index n will be freed using #plist_free
*
* @param node the node of type #PLIST_ARRAY
* @param item the new item at index n. The array is responsible for freeing item when it is no longer needed.
* @param n the index of the item to get. Range is [0, array_size[. Assert if n is not in range.
*/
void plist_array_set_item(plist_t node, plist_t item, uint32_t n);
/**
* Append a new item at the end of a #PLIST_ARRAY node.
*
* @param node the node of type #PLIST_ARRAY
* @param item the new item. The array is responsible for freeing item when it is no longer needed.
*/
void plist_array_append_item(plist_t node, plist_t item);
/**
* Insert a new item at position n in a #PLIST_ARRAY node.
*
* @param node the node of type #PLIST_ARRAY
* @param item the new item to insert. The array is responsible for freeing item when it is no longer needed.
* @param n The position at which the node will be stored. Range is [0, array_size[. Assert if n is not in range.
*/
void plist_array_insert_item(plist_t node, plist_t item, uint32_t n);
/**
* Remove an existing position in a #PLIST_ARRAY node.
* Removed position will be freed using #plist_free.
*
* @param node the node of type #PLIST_ARRAY
* @param n The position to remove. Range is [0, array_size[. Assert if n is not in range.
*/
void plist_array_remove_item(plist_t node, uint32_t n);
/********************************************
* *
* Dictionary functions *
* *
********************************************/
/**
* Get size of a #PLIST_DICT node.
*
* @param node the node of type #PLIST_DICT
* @return size of the #PLIST_DICT node
*/
uint32_t plist_dict_get_size(plist_t node);
/**
* Create an iterator of a #PLIST_DICT node.
* The allocated iterator should be freed with the standard free function.
*
* @param node the node of type #PLIST_DICT
* @param iter iterator of the #PLIST_DICT node
*/
void plist_dict_new_iter(plist_t node, plist_dict_iter *iter);
/**
* Increment iterator of a #PLIST_DICT node.
*
* @param node the node of type #PLIST_DICT
* @param iter iterator of the dictionary
* @param key a location to store the key, or NULL. The caller is responsible
* for freeing the the returned string.
* @param val a location to store the value, or NULL. The caller should *not*
* free the returned value.
*/
void plist_dict_next_item(plist_t node, plist_dict_iter iter, char **key, plist_t *val);
/**
* Get key associated to an item. Item must be member of a dictionary
*
* @param node the node
* @param key a location to store the key. The caller is responsible for freeing the returned string.
*/
void plist_dict_get_item_key(plist_t node, char **key);
/**
* Get the nth item in a #PLIST_DICT node.
*
* @param node the node of type #PLIST_DICT
* @param key the identifier of the item to get.
* @return the item or NULL if node is not of type #PLIST_DICT. The caller should not free
* the returned node.
*/
plist_t plist_dict_get_item(plist_t node, const char* key);
/**
* Set item identified by key in a #PLIST_DICT node.
* The previous item identified by key will be freed using #plist_free.
* If there is no item for the given key a new item will be inserted.
*
* @param node the node of type #PLIST_DICT
* @param item the new item associated to key
* @param key the identifier of the item to set.
*/
void plist_dict_set_item(plist_t node, const char* key, plist_t item);
/**
* Insert a new item into a #PLIST_DICT node.
*
* @deprecated Deprecated. Use plist_dict_set_item instead.
*
* @param node the node of type #PLIST_DICT
* @param item the new item to insert
* @param key The identifier of the item to insert.
*/
PLIST_WARN_DEPRECATED("use plist_dict_set_item instead")
void plist_dict_insert_item(plist_t node, const char* key, plist_t item);
/**
* Remove an existing position in a #PLIST_DICT node.
* Removed position will be freed using #plist_free
*
* @param node the node of type #PLIST_DICT
* @param key The identifier of the item to remove. Assert if identifier is not present.
*/
void plist_dict_remove_item(plist_t node, const char* key);
/**
* Merge a dictionary into another. This will add all key/value pairs
* from the source dictionary to the target dictionary, overwriting
* any existing key/value pairs that are already present in target.
*
* @param target pointer to an existing node of type #PLIST_DICT
* @param source node of type #PLIST_DICT that should be merged into target
*/
void plist_dict_merge(plist_t *target, plist_t source);
/********************************************
* *
* Getters *
* *
********************************************/
/**
* Get the parent of a node
*
* @param node the parent (NULL if node is root)
*/
plist_t plist_get_parent(plist_t node);
/**
* Get the #plist_type of a node.
*
* @param node the node
* @return the type of the node
*/
plist_type plist_get_node_type(plist_t node);
/**
* Get the value of a #PLIST_KEY node.
* This function does nothing if node is not of type #PLIST_KEY
*
* @param node the node
* @param val a pointer to a C-string. This function allocates the memory,
* caller is responsible for freeing it.
*/
void plist_get_key_val(plist_t node, char **val);
/**
* Get the value of a #PLIST_STRING node.
* This function does nothing if node is not of type #PLIST_STRING
*
* @param node the node
* @param val a pointer to a C-string. This function allocates the memory,
* caller is responsible for freeing it. Data is UTF-8 encoded.
*/
void plist_get_string_val(plist_t node, char **val);
/**
* Get the value of a #PLIST_BOOLEAN node.
* This function does nothing if node is not of type #PLIST_BOOLEAN
*
* @param node the node
* @param val a pointer to a uint8_t variable.
*/
void plist_get_bool_val(plist_t node, uint8_t * val);
/**
* Get the value of a #PLIST_UINT node.
* This function does nothing if node is not of type #PLIST_UINT
*
* @param node the node
* @param val a pointer to a uint64_t variable.
*/
void plist_get_uint_val(plist_t node, uint64_t * val);
/**
* Get the value of a #PLIST_REAL node.
* This function does nothing if node is not of type #PLIST_REAL
*
* @param node the node
* @param val a pointer to a double variable.
*/
void plist_get_real_val(plist_t node, double *val);
/**
* Get the value of a #PLIST_DATA node.
* This function does nothing if node is not of type #PLIST_DATA
*
* @param node the node
* @param val a pointer to an unallocated char buffer. This function allocates the memory,
* caller is responsible for freeing it.
* @param length the length of the buffer
*/
void plist_get_data_val(plist_t node, char **val, uint64_t * length);
/**
* Get the value of a #PLIST_DATE node.
* This function does nothing if node is not of type #PLIST_DATE
*
* @param node the node
* @param sec a pointer to an int32_t variable. Represents the number of seconds since 01/01/2001.
* @param usec a pointer to an int32_t variable. Represents the number of microseconds
*/
void plist_get_date_val(plist_t node, int32_t * sec, int32_t * usec);
/**
* Get the value of a #PLIST_UID node.
* This function does nothing if node is not of type #PLIST_UID
*
* @param node the node
* @param val a pointer to a uint64_t variable.
*/
void plist_get_uid_val(plist_t node, uint64_t * val);
/********************************************
* *
* Setters *
* *
********************************************/
/**
* Set the value of a node.
* Forces type of node to #PLIST_KEY
*
* @param node the node
* @param val the key value
*/
void plist_set_key_val(plist_t node, const char *val);
/**
* Set the value of a node.
* Forces type of node to #PLIST_STRING
*
* @param node the node
* @param val the string value. The string is copied when set and will be
* freed by the node.
*/
void plist_set_string_val(plist_t node, const char *val);
/**
* Set the value of a node.
* Forces type of node to #PLIST_BOOLEAN
*
* @param node the node
* @param val the boolean value
*/
void plist_set_bool_val(plist_t node, uint8_t val);
/**
* Set the value of a node.
* Forces type of node to #PLIST_UINT
*
* @param node the node
* @param val the unsigned integer value
*/
void plist_set_uint_val(plist_t node, uint64_t val);
/**
* Set the value of a node.
* Forces type of node to #PLIST_REAL
*
* @param node the node
* @param val the real value
*/
void plist_set_real_val(plist_t node, double val);
/**
* Set the value of a node.
* Forces type of node to #PLIST_DATA
*
* @param node the node
* @param val the binary buffer. The buffer is copied when set and will
* be freed by the node.
* @param length the length of the buffer
*/
void plist_set_data_val(plist_t node, const char *val, uint64_t length);
/**
* Set the value of a node.
* Forces type of node to #PLIST_DATE
*
* @param node the node
* @param sec the number of seconds since 01/01/2001
* @param usec the number of microseconds
*/
void plist_set_date_val(plist_t node, int32_t sec, int32_t usec);
/**
* Set the value of a node.
* Forces type of node to #PLIST_UID
*
* @param node the node
* @param val the unsigned integer value
*/
void plist_set_uid_val(plist_t node, uint64_t val);
/********************************************
* *
* Import & Export *
* *
********************************************/
/**
* Export the #plist_t structure to XML format.
*
* @param plist the root node to export
* @param plist_xml a pointer to a C-string. This function allocates the memory,
* caller is responsible for freeing it. Data is UTF-8 encoded.
* @param length a pointer to an uint32_t variable. Represents the length of the allocated buffer.
*/
void plist_to_xml(plist_t plist, char **plist_xml, uint32_t * length);
/**
* Export the #plist_t structure to binary format.
*
* @param plist the root node to export
* @param plist_bin a pointer to a char* buffer. This function allocates the memory,
* caller is responsible for freeing it.
* @param length a pointer to an uint32_t variable. Represents the length of the allocated buffer.
*/
void plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length);
/**
* Import the #plist_t structure from XML format.
*
* @param plist_xml a pointer to the xml buffer.
* @param length length of the buffer to read.
* @param plist a pointer to the imported plist.
*/
void plist_from_xml(const char *plist_xml, uint32_t length, plist_t * plist);
/**
* Import the #plist_t structure from binary format.
*
* @param plist_bin a pointer to the xml buffer.
* @param length length of the buffer to read.
* @param plist a pointer to the imported plist.
*/
void plist_from_bin(const char *plist_bin, uint32_t length, plist_t * plist);
/**
* Import the #plist_t structure from memory data.
* This method will look at the first bytes of plist_data
* to determine if plist_data contains a binary or XML plist.
*
* @param plist_data a pointer to the memory buffer containing plist data.
* @param length length of the buffer to read.
* @param plist a pointer to the imported plist.
*/
void plist_from_memory(const char *plist_data, uint32_t length, plist_t * plist);
/**
* Test if in-memory plist data is binary or XML
* This method will look at the first bytes of plist_data
* to determine if plist_data contains a binary or XML plist.
* This method is not validating the whole memory buffer to check if the
* content is truly a plist, it's only using some heuristic on the first few
* bytes of plist_data.
*
* @param plist_data a pointer to the memory buffer containing plist data.
* @param length length of the buffer to read.
* @return 1 if the buffer is a binary plist, 0 otherwise.
*/
int plist_is_binary(const char *plist_data, uint32_t length);
/********************************************
* *
* Utils *
* *
********************************************/
/**
* Get a node from its path. Each path element depends on the associated father node type.
* For Dictionaries, var args are casted to const char*, for arrays, var args are caster to uint32_t
* Search is breath first order.
*
* @param plist the node to access result from.
* @param length length of the path to access
* @return the value to access.
*/
plist_t plist_access_path(plist_t plist, uint32_t length, ...);
/**
* Variadic version of #plist_access_path.
*
* @param plist the node to access result from.
* @param length length of the path to access
* @param v list of array's index and dic'st key
* @return the value to access.
*/
plist_t plist_access_pathv(plist_t plist, uint32_t length, va_list v);
/**
* Compare two node values
*
* @param node_l left node to compare
* @param node_r rigth node to compare
* @return TRUE is type and value match, FALSE otherwise.
*/
char plist_compare_node_value(plist_t node_l, plist_t node_r);
#define _PLIST_IS_TYPE(__plist, __plist_type) (__plist && (plist_get_node_type(__plist) == PLIST_##__plist_type))
/* Helper macros for the different plist types */
#define PLIST_IS_BOOLEAN(__plist) _PLIST_IS_TYPE(__plist, BOOLEAN)
#define PLIST_IS_UINT(__plist) _PLIST_IS_TYPE(__plist, UINT)
#define PLIST_IS_REAL(__plist) _PLIST_IS_TYPE(__plist, REAL)
#define PLIST_IS_STRING(__plist) _PLIST_IS_TYPE(__plist, STRING)
#define PLIST_IS_ARRAY(__plist) _PLIST_IS_TYPE(__plist, ARRAY)
#define PLIST_IS_DICT(__plist) _PLIST_IS_TYPE(__plist, DICT)
#define PLIST_IS_DATE(__plist) _PLIST_IS_TYPE(__plist, DATE)
#define PLIST_IS_DATA(__plist) _PLIST_IS_TYPE(__plist, DATA)
#define PLIST_IS_KEY(__plist) _PLIST_IS_TYPE(__plist, KEY)
#define PLIST_IS_UID(__plist) _PLIST_IS_TYPE(__plist, UID)
/*@}*/
#ifdef __cplusplus
}
#endif
#endif

61
lib/plist/ptrarray.c Executable file
View File

@@ -0,0 +1,61 @@
/*
* ptrarray.c
* simple pointer array implementation
*
* Copyright (c) 2011 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
*/
#include "ptrarray.h"
ptrarray_t *ptr_array_new(int capacity)
{
ptrarray_t *pa = (ptrarray_t*)malloc(sizeof(ptrarray_t));
pa->pdata = (void**)malloc(sizeof(void*) * capacity);
pa->capacity = capacity;
pa->capacity_step = (capacity > 4096) ? 4096 : capacity;
pa->len = 0;
return pa;
}
void ptr_array_free(ptrarray_t *pa)
{
if (!pa) return;
if (pa->pdata) {
free(pa->pdata);
}
free(pa);
}
void ptr_array_add(ptrarray_t *pa, void *data)
{
if (!pa || !pa->pdata || !data) return;
size_t remaining = pa->capacity-pa->len;
if (remaining == 0) {
pa->pdata = realloc(pa->pdata, sizeof(void*) * (pa->capacity + pa->capacity_step));
pa->capacity += pa->capacity_step;
}
pa->pdata[pa->len] = data;
pa->len++;
}
void* ptr_array_index(ptrarray_t *pa, size_t array_index)
{
if (!pa) return NULL;
if (array_index >= pa->len) {
return NULL;
}
return pa->pdata[array_index];
}

36
lib/plist/ptrarray.h Executable file
View File

@@ -0,0 +1,36 @@
/*
* ptrarray.h
* header file for simple pointer array implementation
*
* Copyright (c) 2011 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 PTRARRAY_H
#define PTRARRAY_H
#include <stdlib.h>
typedef struct ptrarray_t {
void **pdata;
size_t len;
size_t capacity;
size_t capacity_step;
} ptrarray_t;
ptrarray_t *ptr_array_new(int capacity);
void ptr_array_free(ptrarray_t *pa);
void ptr_array_add(ptrarray_t *pa, void *data);
void* ptr_array_index(ptrarray_t *pa, size_t index);
#endif

34
lib/plist/strbuf.h Executable file
View File

@@ -0,0 +1,34 @@
/*
* strbuf.h
* header file for simple string buffer, using the bytearray as underlying
* structure.
*
* Copyright (c) 2016 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 STRBUF_H
#define STRBUF_H
#include <stdlib.h>
#include "bytearray.h"
typedef struct bytearray_t strbuf_t;
#define str_buf_new(__sz) byte_array_new(__sz)
#define str_buf_free(__ba) byte_array_free(__ba)
#define str_buf_grow(__ba, __am) byte_array_grow(__ba, __am)
#define str_buf_append(__ba, __str, __len) byte_array_append(__ba, (void*)(__str), __len)
#endif

812
lib/plist/time64.c Executable file
View File

@@ -0,0 +1,812 @@
/*
Copyright (c) 2007-2010 Michael G Schwern
This software originally derived from Paul Sheer's pivotal_gmtime_r.c.
The MIT License:
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/*
Programmers who have available to them 64-bit time values as a 'long
long' type can use localtime64_r() and gmtime64_r() which correctly
converts the time even on 32-bit systems. Whether you have 64-bit time
values will depend on the operating system.
localtime64_r() is a 64-bit equivalent of localtime_r().
gmtime64_r() is a 64-bit equivalent of gmtime_r().
*/
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include "time64.h"
#include "time64_limits.h"
static const char days_in_month[2][12] = {
{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
};
static const short julian_days_by_month[2][12] = {
{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
{0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335},
};
static char wday_name[7][4] = {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};
static char mon_name[12][4] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
static const short length_of_year[2] = { 365, 366 };
/* Some numbers relating to the gregorian cycle */
static const Year years_in_gregorian_cycle = 400;
#define days_in_gregorian_cycle ((365 * 400) + 100 - 4 + 1)
static const Time64_T seconds_in_gregorian_cycle = days_in_gregorian_cycle * 60LL * 60LL * 24LL;
/* Year range we can trust the time funcitons with */
#define MAX_SAFE_YEAR 2037
#define MIN_SAFE_YEAR 1971
/* 28 year Julian calendar cycle */
#define SOLAR_CYCLE_LENGTH 28
/* Year cycle from MAX_SAFE_YEAR down. */
static const short safe_years_high[SOLAR_CYCLE_LENGTH] = {
2016, 2017, 2018, 2019,
2020, 2021, 2022, 2023,
2024, 2025, 2026, 2027,
2028, 2029, 2030, 2031,
2032, 2033, 2034, 2035,
2036, 2037, 2010, 2011,
2012, 2013, 2014, 2015
};
/* Year cycle from MIN_SAFE_YEAR up */
static const int safe_years_low[SOLAR_CYCLE_LENGTH] = {
1996, 1997, 1998, 1971,
1972, 1973, 1974, 1975,
1976, 1977, 1978, 1979,
1980, 1981, 1982, 1983,
1984, 1985, 1986, 1987,
1988, 1989, 1990, 1991,
1992, 1993, 1994, 1995,
};
/* This isn't used, but it's handy to look at */
#if 0
static const char dow_year_start[SOLAR_CYCLE_LENGTH] = {
5, 0, 1, 2, /* 0 2016 - 2019 */
3, 5, 6, 0, /* 4 */
1, 3, 4, 5, /* 8 1996 - 1998, 1971*/
6, 1, 2, 3, /* 12 1972 - 1975 */
4, 6, 0, 1, /* 16 */
2, 4, 5, 6, /* 20 2036, 2037, 2010, 2011 */
0, 2, 3, 4 /* 24 2012, 2013, 2014, 2015 */
};
#endif
/* Let's assume people are going to be looking for dates in the future.
Let's provide some cheats so you can skip ahead.
This has a 4x speed boost when near 2008.
*/
/* Number of days since epoch on Jan 1st, 2008 GMT */
#define CHEAT_DAYS (1199145600 / 24 / 60 / 60)
#define CHEAT_YEARS 108
#define IS_LEAP(n) ((!(((n) + 1900) % 400) || (!(((n) + 1900) % 4) && (((n) + 1900) % 100))) != 0)
#define WRAP(a,b,m) ((a) = ((a) < 0 ) ? ((b)--, (a) + (m)) : (a))
#ifdef USE_SYSTEM_LOCALTIME
# define SHOULD_USE_SYSTEM_LOCALTIME(a) ( \
(a) <= SYSTEM_LOCALTIME_MAX && \
(a) >= SYSTEM_LOCALTIME_MIN \
)
#else
# define SHOULD_USE_SYSTEM_LOCALTIME(a) (0)
#endif
#ifdef USE_SYSTEM_GMTIME
# define SHOULD_USE_SYSTEM_GMTIME(a) ( \
(a) <= SYSTEM_GMTIME_MAX && \
(a) >= SYSTEM_GMTIME_MIN \
)
#else
# define SHOULD_USE_SYSTEM_GMTIME(a) (0)
#endif
/* Multi varadic macros are a C99 thing, alas */
#ifdef TIME_64_DEBUG
# define TIME64_TRACE(format) (fprintf(stderr, format))
# define TIME64_TRACE1(format, var1) (fprintf(stderr, format, var1))
# define TIME64_TRACE2(format, var1, var2) (fprintf(stderr, format, var1, var2))
# define TIME64_TRACE3(format, var1, var2, var3) (fprintf(stderr, format, var1, var2, var3))
#else
# define TIME64_TRACE(format) ((void)0)
# define TIME64_TRACE1(format, var1) ((void)0)
# define TIME64_TRACE2(format, var1, var2) ((void)0)
# define TIME64_TRACE3(format, var1, var2, var3) ((void)0)
#endif
static int is_exception_century(Year year)
{
int is_exception = ((year % 100 == 0) && !(year % 400 == 0));
TIME64_TRACE1("# is_exception_century: %s\n", is_exception ? "yes" : "no");
return(is_exception);
}
/* Compare two dates.
The result is like cmp.
Ignores things like gmtoffset and dst
*/
static int cmp_date( const struct TM* left, const struct tm* right ) {
if( left->tm_year > right->tm_year )
return 1;
else if( left->tm_year < right->tm_year )
return -1;
if( left->tm_mon > right->tm_mon )
return 1;
else if( left->tm_mon < right->tm_mon )
return -1;
if( left->tm_mday > right->tm_mday )
return 1;
else if( left->tm_mday < right->tm_mday )
return -1;
if( left->tm_hour > right->tm_hour )
return 1;
else if( left->tm_hour < right->tm_hour )
return -1;
if( left->tm_min > right->tm_min )
return 1;
else if( left->tm_min < right->tm_min )
return -1;
if( left->tm_sec > right->tm_sec )
return 1;
else if( left->tm_sec < right->tm_sec )
return -1;
return 0;
}
/* Check if a date is safely inside a range.
The intention is to check if its a few days inside.
*/
static int date_in_safe_range( const struct TM* date, const struct tm* min, const struct tm* max ) {
if( cmp_date(date, min) == -1 )
return 0;
if( cmp_date(date, max) == 1 )
return 0;
return 1;
}
/* timegm() is not in the C or POSIX spec, but it is such a useful
extension I would be remiss in leaving it out. Also I need it
for localtime64()
*/
Time64_T timegm64(const struct TM *date) {
Time64_T days = 0;
Time64_T seconds = 0;
Year year;
Year orig_year = (Year)date->tm_year;
int cycles = 0;
if( orig_year > 100 ) {
cycles = (orig_year - 100) / 400;
orig_year -= cycles * 400;
days += (Time64_T)cycles * days_in_gregorian_cycle;
}
else if( orig_year < -300 ) {
cycles = (orig_year - 100) / 400;
orig_year -= cycles * 400;
days += (Time64_T)cycles * days_in_gregorian_cycle;
}
TIME64_TRACE3("# timegm/ cycles: %d, days: %lld, orig_year: %lld\n", cycles, days, orig_year);
if( orig_year > 70 ) {
year = 70;
while( year < orig_year ) {
days += length_of_year[IS_LEAP(year)];
year++;
}
}
else if ( orig_year < 70 ) {
year = 69;
do {
days -= length_of_year[IS_LEAP(year)];
year--;
} while( year >= orig_year );
}
days += julian_days_by_month[IS_LEAP(orig_year)][date->tm_mon];
days += date->tm_mday - 1;
seconds = days * 60 * 60 * 24;
seconds += date->tm_hour * 60 * 60;
seconds += date->tm_min * 60;
seconds += date->tm_sec;
return(seconds);
}
static int check_tm(struct TM *tm)
{
/* Don't forget leap seconds */
assert(tm->tm_sec >= 0);
assert(tm->tm_sec <= 61);
assert(tm->tm_min >= 0);
assert(tm->tm_min <= 59);
assert(tm->tm_hour >= 0);
assert(tm->tm_hour <= 23);
assert(tm->tm_mday >= 1);
assert(tm->tm_mday <= days_in_month[IS_LEAP(tm->tm_year)][tm->tm_mon]);
assert(tm->tm_mon >= 0);
assert(tm->tm_mon <= 11);
assert(tm->tm_wday >= 0);
assert(tm->tm_wday <= 6);
assert(tm->tm_yday >= 0);
assert(tm->tm_yday <= length_of_year[IS_LEAP(tm->tm_year)]);
#ifdef HAVE_TM_TM_GMTOFF
assert(tm->tm_gmtoff >= -24 * 60 * 60);
assert(tm->tm_gmtoff <= 24 * 60 * 60);
#endif
return 1;
}
/* The exceptional centuries without leap years cause the cycle to
shift by 16
*/
static Year cycle_offset(Year year)
{
const Year start_year = 2000;
Year year_diff = year - start_year;
Year exceptions;
if( year > start_year )
year_diff--;
exceptions = year_diff / 100;
exceptions -= year_diff / 400;
TIME64_TRACE3("# year: %lld, exceptions: %lld, year_diff: %lld\n",
year, exceptions, year_diff);
return exceptions * 16;
}
/* For a given year after 2038, pick the latest possible matching
year in the 28 year calendar cycle.
A matching year...
1) Starts on the same day of the week.
2) Has the same leap year status.
This is so the calendars match up.
Also the previous year must match. When doing Jan 1st you might
wind up on Dec 31st the previous year when doing a -UTC time zone.
Finally, the next year must have the same start day of week. This
is for Dec 31st with a +UTC time zone.
It doesn't need the same leap year status since we only care about
January 1st.
*/
static int safe_year(const Year year)
{
int safe_year= (int)year;
Year year_cycle;
if( year >= MIN_SAFE_YEAR && year <= MAX_SAFE_YEAR ) {
return safe_year;
}
year_cycle = year + cycle_offset(year);
/* safe_years_low is off from safe_years_high by 8 years */
if( year < MIN_SAFE_YEAR )
year_cycle -= 8;
/* Change non-leap xx00 years to an equivalent */
if( is_exception_century(year) )
year_cycle += 11;
/* Also xx01 years, since the previous year will be wrong */
if( is_exception_century(year - 1) )
year_cycle += 17;
year_cycle %= SOLAR_CYCLE_LENGTH;
if( year_cycle < 0 )
year_cycle = SOLAR_CYCLE_LENGTH + year_cycle;
assert( year_cycle >= 0 );
assert( year_cycle < SOLAR_CYCLE_LENGTH );
if( year < MIN_SAFE_YEAR )
safe_year = safe_years_low[year_cycle];
else if( year > MAX_SAFE_YEAR )
safe_year = safe_years_high[year_cycle];
else
assert(0);
TIME64_TRACE3("# year: %lld, year_cycle: %lld, safe_year: %d\n",
year, year_cycle, safe_year);
assert(safe_year <= MAX_SAFE_YEAR && safe_year >= MIN_SAFE_YEAR);
return safe_year;
}
void copy_tm_to_TM64(const struct tm *src, struct TM *dest) {
if( src == NULL ) {
memset(dest, 0, sizeof(*dest));
}
else {
# ifdef USE_TM64
dest->tm_sec = src->tm_sec;
dest->tm_min = src->tm_min;
dest->tm_hour = src->tm_hour;
dest->tm_mday = src->tm_mday;
dest->tm_mon = src->tm_mon;
dest->tm_year = (Year)src->tm_year;
dest->tm_wday = src->tm_wday;
dest->tm_yday = src->tm_yday;
dest->tm_isdst = src->tm_isdst;
# ifdef HAVE_TM_TM_GMTOFF
dest->tm_gmtoff = src->tm_gmtoff;
# endif
# ifdef HAVE_TM_TM_ZONE
dest->tm_zone = src->tm_zone;
# endif
# else
/* They're the same type */
memcpy(dest, src, sizeof(*dest));
# endif
}
}
void copy_TM64_to_tm(const struct TM *src, struct tm *dest) {
if( src == NULL ) {
memset(dest, 0, sizeof(*dest));
}
else {
# ifdef USE_TM64
dest->tm_sec = src->tm_sec;
dest->tm_min = src->tm_min;
dest->tm_hour = src->tm_hour;
dest->tm_mday = src->tm_mday;
dest->tm_mon = src->tm_mon;
dest->tm_year = (int)src->tm_year;
dest->tm_wday = src->tm_wday;
dest->tm_yday = src->tm_yday;
dest->tm_isdst = src->tm_isdst;
# ifdef HAVE_TM_TM_GMTOFF
dest->tm_gmtoff = src->tm_gmtoff;
# endif
# ifdef HAVE_TM_TM_ZONE
dest->tm_zone = src->tm_zone;
# endif
# else
/* They're the same type */
memcpy(dest, src, sizeof(*dest));
# endif
}
}
#ifndef HAVE_LOCALTIME_R
/* Simulate localtime_r() to the best of our ability */
static struct tm * fake_localtime_r(const time_t *time, struct tm *result) {
const struct tm *static_result = localtime(time);
assert(result != NULL);
if( static_result == NULL ) {
memset(result, 0, sizeof(*result));
return NULL;
}
else {
memcpy(result, static_result, sizeof(*result));
return result;
}
}
#endif
#ifndef HAVE_GMTIME_R
/* Simulate gmtime_r() to the best of our ability */
static struct tm * fake_gmtime_r(const time_t *time, struct tm *result) {
const struct tm *static_result = gmtime(time);
assert(result != NULL);
if( static_result == NULL ) {
memset(result, 0, sizeof(*result));
return NULL;
}
else {
memcpy(result, static_result, sizeof(*result));
return result;
}
}
#endif
static Time64_T seconds_between_years(Year left_year, Year right_year) {
int increment = (left_year > right_year) ? 1 : -1;
Time64_T seconds = 0;
int cycles;
if( left_year > 2400 ) {
cycles = (left_year - 2400) / 400;
left_year -= cycles * 400;
seconds += cycles * seconds_in_gregorian_cycle;
}
else if( left_year < 1600 ) {
cycles = (left_year - 1600) / 400;
left_year += cycles * 400;
seconds += cycles * seconds_in_gregorian_cycle;
}
while( left_year != right_year ) {
seconds += length_of_year[IS_LEAP(right_year - 1900)] * 60 * 60 * 24;
right_year += increment;
}
return seconds * increment;
}
Time64_T mktime64(struct TM *input_date) {
struct tm safe_date;
struct TM date;
Time64_T time;
Year year = input_date->tm_year + 1900;
if( date_in_safe_range(input_date, &SYSTEM_MKTIME_MIN, &SYSTEM_MKTIME_MAX) )
{
copy_TM64_to_tm(input_date, &safe_date);
time = (Time64_T)mktime(&safe_date);
/* Correct the possibly out of bound input date */
copy_tm_to_TM64(&safe_date, input_date);
return time;
}
/* Have to make the year safe in date else it won't fit in safe_date */
date = *input_date;
date.tm_year = safe_year(year) - 1900;
copy_TM64_to_tm(&date, &safe_date);
time = (Time64_T)mktime(&safe_date);
/* Correct the user's possibly out of bound input date */
copy_tm_to_TM64(&safe_date, input_date);
time += seconds_between_years(year, (Year)(safe_date.tm_year + 1900));
return time;
}
/* Because I think mktime() is a crappy name */
Time64_T timelocal64(struct TM *date) {
return mktime64(date);
}
struct TM *gmtime64_r (const Time64_T *in_time, struct TM *p)
{
int v_tm_sec, v_tm_min, v_tm_hour, v_tm_mon, v_tm_wday;
Time64_T v_tm_tday;
int leap;
Time64_T m;
Time64_T time = *in_time;
Year year = 70;
int cycles = 0;
assert(p != NULL);
/* Use the system gmtime() if time_t is small enough */
if( SHOULD_USE_SYSTEM_GMTIME(*in_time) ) {
time_t safe_time = (time_t)*in_time;
struct tm safe_date;
GMTIME_R(&safe_time, &safe_date);
copy_tm_to_TM64(&safe_date, p);
assert(check_tm(p));
return p;
}
#ifdef HAVE_TM_TM_GMTOFF
p->tm_gmtoff = 0;
#endif
p->tm_isdst = 0;
#ifdef HAVE_TM_TM_ZONE
p->tm_zone = (char*)"UTC";
#endif
v_tm_sec = (int)(time % 60);
time /= 60;
v_tm_min = (int)(time % 60);
time /= 60;
v_tm_hour = (int)(time % 24);
time /= 24;
v_tm_tday = time;
WRAP (v_tm_sec, v_tm_min, 60);
WRAP (v_tm_min, v_tm_hour, 60);
WRAP (v_tm_hour, v_tm_tday, 24);
v_tm_wday = (int)((v_tm_tday + 4) % 7);
if (v_tm_wday < 0)
v_tm_wday += 7;
m = v_tm_tday;
if (m >= CHEAT_DAYS) {
year = CHEAT_YEARS;
m -= CHEAT_DAYS;
}
if (m >= 0) {
/* Gregorian cycles, this is huge optimization for distant times */
cycles = (int)(m / (Time64_T) days_in_gregorian_cycle);
if( cycles ) {
m -= (cycles * (Time64_T) days_in_gregorian_cycle);
year += (cycles * years_in_gregorian_cycle);
}
/* Years */
leap = IS_LEAP (year);
while (m >= (Time64_T) length_of_year[leap]) {
m -= (Time64_T) length_of_year[leap];
year++;
leap = IS_LEAP (year);
}
/* Months */
v_tm_mon = 0;
while (m >= (Time64_T) days_in_month[leap][v_tm_mon]) {
m -= (Time64_T) days_in_month[leap][v_tm_mon];
v_tm_mon++;
}
} else {
year--;
/* Gregorian cycles */
cycles = (int)((m / (Time64_T) days_in_gregorian_cycle) + 1);
if( cycles ) {
m -= (cycles * (Time64_T) days_in_gregorian_cycle);
year += (cycles * years_in_gregorian_cycle);
}
/* Years */
leap = IS_LEAP (year);
while (m < (Time64_T) -length_of_year[leap]) {
m += (Time64_T) length_of_year[leap];
year--;
leap = IS_LEAP (year);
}
/* Months */
v_tm_mon = 11;
while (m < (Time64_T) -days_in_month[leap][v_tm_mon]) {
m += (Time64_T) days_in_month[leap][v_tm_mon];
v_tm_mon--;
}
m += (Time64_T) days_in_month[leap][v_tm_mon];
}
p->tm_year = year;
if( p->tm_year != year ) {
#ifdef EOVERFLOW
errno = EOVERFLOW;
#endif
return NULL;
}
/* At this point m is less than a year so casting to an int is safe */
p->tm_mday = (int) m + 1;
p->tm_yday = julian_days_by_month[leap][v_tm_mon] + (int)m;
p->tm_sec = v_tm_sec;
p->tm_min = v_tm_min;
p->tm_hour = v_tm_hour;
p->tm_mon = v_tm_mon;
p->tm_wday = v_tm_wday;
assert(check_tm(p));
return p;
}
struct TM *localtime64_r (const Time64_T *time, struct TM *local_tm)
{
time_t safe_time;
struct tm safe_date;
struct TM gm_tm;
Year orig_year;
int month_diff;
assert(local_tm != NULL);
/* Use the system localtime() if time_t is small enough */
if( SHOULD_USE_SYSTEM_LOCALTIME(*time) ) {
safe_time = (time_t)*time;
TIME64_TRACE1("Using system localtime for %lld\n", *time);
LOCALTIME_R(&safe_time, &safe_date);
copy_tm_to_TM64(&safe_date, local_tm);
assert(check_tm(local_tm));
return local_tm;
}
if( gmtime64_r(time, &gm_tm) == NULL ) {
TIME64_TRACE1("gmtime64_r returned null for %lld\n", *time);
return NULL;
}
orig_year = gm_tm.tm_year;
if (gm_tm.tm_year > (2037 - 1900) ||
gm_tm.tm_year < (1970 - 1900)
)
{
TIME64_TRACE1("Mapping tm_year %lld to safe_year\n", (Year)gm_tm.tm_year);
gm_tm.tm_year = safe_year((Year)(gm_tm.tm_year + 1900)) - 1900;
}
safe_time = (time_t)timegm64(&gm_tm);
if( LOCALTIME_R(&safe_time, &safe_date) == NULL ) {
TIME64_TRACE1("localtime_r(%d) returned NULL\n", (int)safe_time);
return NULL;
}
copy_tm_to_TM64(&safe_date, local_tm);
local_tm->tm_year = orig_year;
if( local_tm->tm_year != orig_year ) {
TIME64_TRACE2("tm_year overflow: tm_year %lld, orig_year %lld\n",
(Year)local_tm->tm_year, (Year)orig_year);
#ifdef EOVERFLOW
errno = EOVERFLOW;
#endif
return NULL;
}
month_diff = local_tm->tm_mon - gm_tm.tm_mon;
/* When localtime is Dec 31st previous year and
gmtime is Jan 1st next year.
*/
if( month_diff == 11 ) {
local_tm->tm_year--;
}
/* When localtime is Jan 1st, next year and
gmtime is Dec 31st, previous year.
*/
if( month_diff == -11 ) {
local_tm->tm_year++;
}
/* GMT is Jan 1st, xx01 year, but localtime is still Dec 31st
in a non-leap xx00. There is one point in the cycle
we can't account for which the safe xx00 year is a leap
year. So we need to correct for Dec 31st comming out as
the 366th day of the year.
*/
if( !IS_LEAP(local_tm->tm_year) && local_tm->tm_yday == 365 )
local_tm->tm_yday--;
assert(check_tm(local_tm));
return local_tm;
}
static int valid_tm_wday( const struct TM* date ) {
if( 0 <= date->tm_wday && date->tm_wday <= 6 )
return 1;
else
return 0;
}
static int valid_tm_mon( const struct TM* date ) {
if( 0 <= date->tm_mon && date->tm_mon <= 11 )
return 1;
else
return 0;
}
char *asctime64_r( const struct TM* date, char *result ) {
/* I figure everything else can be displayed, even hour 25, but if
these are out of range we walk off the name arrays */
if( !valid_tm_wday(date) || !valid_tm_mon(date) )
return NULL;
sprintf(result, TM64_ASCTIME_FORMAT,
wday_name[date->tm_wday],
mon_name[date->tm_mon],
date->tm_mday, date->tm_hour,
date->tm_min, date->tm_sec,
1900 + date->tm_year);
return result;
}
char *ctime64_r( const Time64_T* time, char* result ) {
struct TM date;
localtime64_r( time, &date );
return asctime64_r( &date, result );
}

81
lib/plist/time64.h Executable file
View File

@@ -0,0 +1,81 @@
#ifndef TIME64_H
# define TIME64_H
#include <time.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
/* Set our custom types */
typedef long long Int64;
typedef Int64 Time64_T;
typedef Int64 Year;
/* A copy of the tm struct but with a 64 bit year */
struct TM64 {
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
Year tm_year;
int tm_wday;
int tm_yday;
int tm_isdst;
#ifdef HAVE_TM_TM_GMTOFF
long tm_gmtoff;
#endif
#ifdef HAVE_TM_TM_ZONE
char *tm_zone;
#endif
};
/* Decide which tm struct to use */
#ifdef USE_TM64
#define TM TM64
#else
#define TM tm
#endif
/* Declare public functions */
struct TM *gmtime64_r (const Time64_T *, struct TM *);
struct TM *localtime64_r (const Time64_T *, struct TM *);
char *asctime64_r (const struct TM *, char *);
char *ctime64_r (const Time64_T*, char*);
Time64_T timegm64 (const struct TM *);
Time64_T mktime64 (struct TM *);
Time64_T timelocal64 (struct TM *);
/* Not everyone has gm/localtime_r(), provide a replacement */
#ifdef HAVE_LOCALTIME_R
# define LOCALTIME_R(clock, result) localtime_r(clock, result)
#else
# define LOCALTIME_R(clock, result) fake_localtime_r(clock, result)
#endif
#ifdef HAVE_GMTIME_R
# define GMTIME_R(clock, result) gmtime_r(clock, result)
#else
# define GMTIME_R(clock, result) fake_gmtime_r(clock, result)
#endif
/* Use a different asctime format depending on how big the year is */
#ifdef USE_TM64
#define TM64_ASCTIME_FORMAT "%.3s %.3s%3d %.2d:%.2d:%.2d %lld\n"
#else
#define TM64_ASCTIME_FORMAT "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n"
#endif
void copy_tm_to_TM64(const struct tm *src, struct TM *dest);
void copy_TM64_to_tm(const struct TM *src, struct tm *dest);
#endif

97
lib/plist/time64_limits.h Executable file
View File

@@ -0,0 +1,97 @@
/*
Maximum and minimum inputs your system's respective time functions
can correctly handle. time64.h will use your system functions if
the input falls inside these ranges and corresponding USE_SYSTEM_*
constant is defined.
*/
#ifndef TIME64_LIMITS_H
#define TIME64_LIMITS_H
#include <time.h>
/* Max/min for localtime() */
#define SYSTEM_LOCALTIME_MAX 2147483647
#define SYSTEM_LOCALTIME_MIN -2147483647-1
/* Max/min for gmtime() */
#define SYSTEM_GMTIME_MAX 2147483647
#define SYSTEM_GMTIME_MIN -2147483647-1
/* Max/min for mktime() */
static const struct tm SYSTEM_MKTIME_MAX = {
7,
14,
19,
18,
0,
138,
1,
17,
0
#ifdef HAVE_TM_TM_GMTOFF
,-28800
#endif
#ifdef HAVE_TM_TM_ZONE
,(char*)"PST"
#endif
};
static const struct tm SYSTEM_MKTIME_MIN = {
52,
45,
12,
13,
11,
1,
5,
346,
0
#ifdef HAVE_TM_TM_GMTOFF
,-28800
#endif
#ifdef HAVE_TM_TM_ZONE
,(char*)"PST"
#endif
};
/* Max/min for timegm() */
#ifdef HAVE_TIMEGM
static const struct tm SYSTEM_TIMEGM_MAX = {
7,
14,
3,
19,
0,
138,
2,
18,
0
#ifdef HAVE_TM_TM_GMTOFF
,0
#endif
#ifdef HAVE_TM_TM_ZONE
,(char*)"UTC"
#endif
};
static const struct tm SYSTEM_TIMEGM_MIN = {
52,
45,
20,
13,
11,
1,
5,
346,
0
#ifdef HAVE_TM_TM_GMTOFF
,0
#endif
#ifdef HAVE_TM_TM_ZONE
,(char*)"UTC"
#endif
};
#endif /* HAVE_TIMEGM */
#endif /* TIME64_LIMITS_H */

1438
lib/plist/xplist.c Executable file

File diff suppressed because it is too large Load Diff