mirror of
https://github.com/cjdelisle/cjdns
synced 2025-10-06 00:32:50 +02:00
220 lines
6.3 KiB
C
220 lines
6.3 KiB
C
/* vim: set expandtab ts=4 sw=4: */
|
|
/*
|
|
* You may redistribute this program and/or modify it under the terms of
|
|
* the GNU General Public License as published by the Free Software Foundation,
|
|
* either version 3 of the License, or (at your option) any later version.
|
|
*
|
|
* This program 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 General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
#include "memory/Allocator.h"
|
|
#include "benc/Dict.h"
|
|
#include "benc/String.h"
|
|
|
|
#include <stddef.h>
|
|
|
|
int32_t Dict_size(const Dict* dictionary)
|
|
{
|
|
if (dictionary != NULL) {
|
|
struct Dict_Entry* entry = *dictionary;
|
|
int32_t i;
|
|
for (i = 0; entry != NULL; i++) {
|
|
entry = entry->next;
|
|
}
|
|
return i;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static Object* lookupObject(const Dict* dictionary, const String* key)
|
|
{
|
|
if (dictionary == NULL || key == NULL) {
|
|
return NULL;
|
|
}
|
|
const struct Dict_Entry* curr = *dictionary;
|
|
while (curr != NULL) {
|
|
if (String_equals(key, curr->key)) {
|
|
return curr->val;
|
|
}
|
|
|
|
curr = curr->next;
|
|
}
|
|
|
|
/* key not found */
|
|
return NULL;
|
|
}
|
|
|
|
/** @see Object.h */
|
|
int64_t* Dict_getInt(const Dict* dictionary, const String* key)
|
|
{
|
|
Object* obj = lookupObject(dictionary, key);
|
|
if (obj == NULL || obj->type != Object_INTEGER) {
|
|
return NULL;
|
|
}
|
|
return &(obj->as.number);
|
|
}
|
|
|
|
/** @see Object.h */
|
|
String* Dict_getString(const Dict* dictionary, const String* key)
|
|
{
|
|
Object* obj = lookupObject(dictionary, key);
|
|
if (obj == NULL || obj->type != Object_STRING) {
|
|
return NULL;
|
|
}
|
|
return obj->as.string;
|
|
}
|
|
|
|
/** @see Object.h */
|
|
Dict* Dict_getDict(const Dict* dictionary, const String* key)
|
|
{
|
|
Object* obj = lookupObject(dictionary, key);
|
|
if (obj == NULL || obj->type != Object_DICT) {
|
|
return NULL;
|
|
}
|
|
return obj->as.dictionary;
|
|
}
|
|
|
|
/** @see Object.h */
|
|
List* Dict_getList(const Dict* dictionary, const String* key)
|
|
{
|
|
Object* obj = lookupObject(dictionary, key);
|
|
if (obj == NULL || obj->type != Object_LIST) {
|
|
return NULL;
|
|
}
|
|
return obj->as.list;
|
|
}
|
|
|
|
/** @see Object.h */
|
|
Dict* Dict_new(struct Allocator* allocator)
|
|
{
|
|
return Allocator_calloc(allocator, sizeof(Dict), 1);
|
|
}
|
|
|
|
/**
|
|
* Put a key:value pair into a dictionary.
|
|
* NOTE: This will not copy the given object,
|
|
* only add a pointer to it in the dictionary.
|
|
* If dictionary is NULL then a new dictionary will be created and returned.
|
|
*
|
|
* @param dictionary this must be a bencoded dictionary or NULL, if NULL then a new dictionary
|
|
is made.
|
|
* @param key the reference key to use for putting the entry in the dictionary.
|
|
* @param value the value to insert with the key.
|
|
* @param allocator the means to get memory for storing the dictionary entry wrapper.
|
|
* @return if the dictionary parameter is NULL then this will be the newly created dictionary.
|
|
* Otherwise: if the key already exists in the dictionary then the value which was
|
|
* displaced by the put, if not then NULL.
|
|
*/
|
|
static Object* putObject(Dict* dictionary,
|
|
const String* key,
|
|
Object* value,
|
|
struct Allocator* allocator)
|
|
{
|
|
struct Dict_Entry** prev_p = dictionary;
|
|
struct Dict_Entry* current = *dictionary;
|
|
while (current != NULL) {
|
|
int cmp = String_compare(key, current->key);
|
|
if (cmp < 0) {
|
|
break;
|
|
} else if (cmp == 0) {
|
|
Object* out = current->val;
|
|
current->val = value;
|
|
return out;
|
|
}
|
|
prev_p = &(current->next);
|
|
current = current->next;
|
|
}
|
|
struct Dict_Entry* entry = Allocator_malloc(allocator, sizeof(struct Dict_Entry));
|
|
entry->key = (String*) key; // need to drop the const :(
|
|
entry->val = value;
|
|
entry->next = current;
|
|
*prev_p = entry;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/** @see Object.h */
|
|
Object* Dict_putInt(Dict* dictionary,
|
|
const String* key,
|
|
int64_t value,
|
|
struct Allocator* allocator)
|
|
{
|
|
Object* v = Allocator_clone(allocator, (&(Object) {
|
|
.type = Object_INTEGER,
|
|
.as.number = value
|
|
}));
|
|
return putObject(dictionary, key, v, allocator);
|
|
}
|
|
|
|
/** @see Object.h */
|
|
Object* Dict_putString(Dict* dictionary,
|
|
const String* key,
|
|
String* value,
|
|
struct Allocator* allocator)
|
|
{
|
|
if (key == NULL || value == NULL) {
|
|
return NULL;
|
|
}
|
|
Object* v = Allocator_clone(allocator, (&(Object) {
|
|
.type = Object_STRING,
|
|
.as.string = value
|
|
}));
|
|
return putObject(dictionary, key, v, allocator);
|
|
}
|
|
|
|
/** @see Object.h */
|
|
Object* Dict_putList(Dict* dictionary,
|
|
const String* key,
|
|
List* value,
|
|
struct Allocator* allocator)
|
|
{
|
|
if (key == NULL || value == NULL) {
|
|
return NULL;
|
|
}
|
|
Object* v = Allocator_clone(allocator, (&(Object) {
|
|
.type = Object_LIST,
|
|
/* Lists and dictionaries are double pointers so they have to be loaded. */
|
|
.as.list = value
|
|
}));
|
|
return putObject(dictionary, key, v, allocator);
|
|
}
|
|
|
|
Object* Dict_putDict(Dict* dictionary,
|
|
const String* key,
|
|
Dict* value,
|
|
struct Allocator* allocator)
|
|
{
|
|
if (key == NULL || value == NULL) {
|
|
return NULL;
|
|
}
|
|
Object* v = Allocator_clone(allocator, (&(Object) {
|
|
.type = Object_DICT,
|
|
/* Lists and dictionaries are double pointers so they have to be loaded. */
|
|
.as.dictionary = value
|
|
}));
|
|
return putObject(dictionary, key, v, allocator);
|
|
}
|
|
|
|
/** @see Object.h */
|
|
int32_t Dict_remove(Dict* dictionary, const String* key)
|
|
{
|
|
struct Dict_Entry** prev_p = dictionary;
|
|
struct Dict_Entry* current = *dictionary;
|
|
while (current != NULL) {
|
|
if (String_equals(key, current->key)) {
|
|
*prev_p = current->next;
|
|
return 1;
|
|
}
|
|
|
|
prev_p = &(current->next);
|
|
current = current->next;
|
|
}
|
|
|
|
return 0;
|
|
}
|