~timkross/cjdns/cjdns

« back to all changes in this revision

Viewing changes to libbenc/benc_dict.c

  • Committer: cjdelisle
  • Date: 2011-02-16 23:03:00 UTC
  • Revision ID: git-v1:d475c9c10adc25590bea5e7dc5383b32f66d5eb8
First commit for cjdns.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include "bencode.h"
 
2
 
 
3
benc_dict_entry_t * benc_dict_entry_new(benc_dict_entry_t *next, benc_bstr_t *k, bobj_t *v);
 
4
bobj_t * benc_dict_entry_free_return_val(benc_dict_entry_t *d);
 
5
 
 
6
void benc_dict_free(benc_dict_entry_t *head)
 
7
{
 
8
    benc_dict_entry_t *curr = head;
 
9
    benc_dict_entry_t *tmp;
 
10
    while (NULL != curr)
 
11
    {
 
12
        tmp = curr->next;
 
13
        bobj_t *val = benc_dict_entry_free_return_val(curr);
 
14
        bobj_free(val);
 
15
        curr = tmp;
 
16
    }
 
17
}
 
18
 
 
19
size_t benc_dict_repsize(benc_dict_entry_t *head)
 
20
{
 
21
    size_t repsize = 2;
 
22
    benc_dict_entry_t *curr = head;
 
23
    while (NULL != curr)
 
24
    {
 
25
        repsize += benc_bstr_repsize(curr->key);
 
26
        repsize += bobj_repsize(curr->val);
 
27
        curr = curr->next;
 
28
    }
 
29
    return repsize;
 
30
}
 
31
 
 
32
void benc_dict_encode(bbuf_t *b, benc_dict_entry_t *head)
 
33
{
 
34
    benc_dict_entry_t *curr = head;
 
35
    *(b->ptr)++ = 'd';
 
36
    while (NULL != curr)
 
37
    {
 
38
        benc_bstr_encode(b, curr->key);
 
39
        bobj_encode(b, curr->val);
 
40
        curr = curr->next;
 
41
    }
 
42
    *(b->ptr)++ = 'e';
 
43
}
 
44
 
 
45
bool benc_dict_decode(bbuf_t *b, benc_dict_entry_t **head_p)
 
46
{
 
47
    bbuf_inc_ptr(b);
 
48
    benc_dict_entry_t **prev_p, *curr;
 
49
    prev_p = head_p;
 
50
    while (*(b->ptr) != 'e')
 
51
    {
 
52
        benc_bstr_t *key = NULL;
 
53
        if (!benc_bstr_decode(b, &key))
 
54
        {
 
55
            BENC_LOG_EXCEPTION("couldn't read dict key");
 
56
            return false;
 
57
        }
 
58
        bobj_t *val = bdec_mem(b);
 
59
        if (NULL == val)
 
60
        {
 
61
            BENC_LOG_EXCEPTION("couldn't read dict value");
 
62
            return false;
 
63
        }
 
64
        curr = benc_dict_entry_new(NULL, key, val);
 
65
        *prev_p = curr;
 
66
        prev_p = &(curr->next);
 
67
    }
 
68
    bbuf_inc_ptr(b);
 
69
    return true;
 
70
}
 
71
 
 
72
/** @see bencode.h */
 
73
int benc_dict_print(struct Writer* writer,
 
74
                    size_t padSpaceCount,
 
75
                    benc_dict_entry_t* head)
 
76
{
 
77
    char* thirtyTwoSpaces = "                                ";
 
78
    int padCounter = 0;
 
79
    #define PAD(padSpaces)                                                  \
 
80
        while (32 < padSpaces + padCounter) {                               \
 
81
            writer->write(thirtyTwoSpaces, 32, writer);                     \
 
82
            padCounter += 32;                                               \
 
83
        }                                                                   \
 
84
        writer->write(thirtyTwoSpaces, padSpaces - padCounter, writer)
 
85
 
 
86
    writer->write("{\n", 2, writer);
 
87
 
 
88
    benc_dict_entry_t* entry = head;
 
89
    while (entry != NULL) {
 
90
        PAD(padSpaceCount + 2);
 
91
        benc_bstr_print(writer, entry->key);
 
92
        writer->write(" : ", 3, writer);        
 
93
        benc_bobj_print(writer, padSpaceCount + 2, entry->val);
 
94
        entry = entry->next;
 
95
        if (entry != NULL) {
 
96
            writer->write(",\n", 2, writer);
 
97
        }
 
98
    }
 
99
 
 
100
    writer->write("\n", 1, writer);
 
101
    PAD(padSpaceCount);
 
102
    return writer->write("}", 1, writer);
 
103
 
 
104
    #undef PAD
 
105
}
 
106
 
 
107
/** @see bencode.h */
 
108
int benc_dict_serialize(struct Writer* writer,
 
109
                        benc_dict_entry_t* head)
 
110
{
 
111
    benc_dict_entry_t* entry = head;
 
112
    writer->write("d", 1, writer);
 
113
    while (entry != NULL)
 
114
    {
 
115
        benc_bstr_serialize(writer, entry->key);
 
116
        bobj_serialize(writer, entry->val);
 
117
        entry = entry->next;
 
118
    }
 
119
    return writer->write("e", 1, writer);
 
120
}
 
121
 
 
122
/** @see bencode.h */
 
123
int benc_dict_parse(struct Reader* reader,
 
124
                    struct MemAllocator* allocator,
 
125
                    benc_dict_entry_t** headPointer)
 
126
{
 
127
    #define OUT_OF_SPACE_TO_WRITE -1
 
128
    #define OUT_OF_CONTENT_TO_READ -2
 
129
    #define UNPARSABLE -3
 
130
 
 
131
    char nextChar;
 
132
    if (reader->read(&nextChar, 1, reader) < 0) {
 
133
        return OUT_OF_CONTENT_TO_READ;
 
134
    }
 
135
    if (nextChar != 'd') {
 
136
        /* Not a dictionary. */
 
137
        return UNPARSABLE;
 
138
    }
 
139
 
 
140
    benc_bstr_t* key;
 
141
    bobj_t* value;
 
142
    benc_dict_entry_t* entryPointer;
 
143
    benc_dict_entry_t* lastEntryPointer = NULL;
 
144
    int ret;
 
145
 
 
146
    for (;;) {
 
147
        /* Peek at the next char. */
 
148
        if (reader->read(&nextChar, 0, reader) < 0) {
 
149
            /* Ran over read buffer. */
 
150
            return OUT_OF_CONTENT_TO_READ;
 
151
        }
 
152
        if (nextChar == 'e') {
 
153
            /* Got to the end. */
 
154
            break;
 
155
        }
 
156
 
 
157
        /* Get key and value. */
 
158
        ret = benc_bstr_parse(reader, allocator, &key);
 
159
        if (ret != 0) {
 
160
            return ret;
 
161
        }
 
162
        ret = bobj_parse(reader, allocator, &value);
 
163
        if (ret != 0) {
 
164
            return ret;
 
165
        }
 
166
 
 
167
        /* Allocate the entry. */
 
168
        entryPointer = allocator->malloc(sizeof(benc_dict_entry_t), allocator);
 
169
        if (entryPointer == NULL) {
 
170
            return OUT_OF_SPACE_TO_WRITE;
 
171
        }
 
172
 
 
173
        entryPointer->next = lastEntryPointer;
 
174
        entryPointer->key = key;
 
175
        entryPointer->val = value;
 
176
        lastEntryPointer = entryPointer;
 
177
    }
 
178
 
 
179
    /* We got an 'e', leave the pointer on the next char after it. */
 
180
    reader->skip(1, reader);
 
181
 
 
182
    *headPointer = lastEntryPointer;
 
183
 
 
184
    return 0;
 
185
 
 
186
    #undef OUT_OF_SPACE_TO_WRITE
 
187
    #undef OUT_OF_CONTENT_TO_READ
 
188
    #undef UNPARSABLE
 
189
}
 
190
 
 
191
benc_dict_entry_t * benc_dict_entry_new(benc_dict_entry_t *next, benc_bstr_t *key, bobj_t *val)
 
192
{
 
193
    benc_dict_entry_t *d = (benc_dict_entry_t *)malloc(sizeof(benc_dict_entry_t));
 
194
    d->next = next;
 
195
    d->key = key;
 
196
    d->val = val;
 
197
    return d;
 
198
}
 
199
 
 
200
bobj_t * benc_dict_entry_free_return_val(benc_dict_entry_t *d)
 
201
{
 
202
    bobj_t *val = d->val;
 
203
    benc_bstr_free(d->key);
 
204
    free(d);
 
205
    return val;
 
206
}
 
207
 
 
208
bobj_t * bobj_dict_new()
 
209
{
 
210
    bobj_t *obj = bobj_new(BENC_DICT);
 
211
    obj->as.dict = NULL;
 
212
    return obj;
 
213
}
 
214
 
 
215
bobj_t * bobj_dict_lookup(bobj_t *obj, benc_bstr_t *key)
 
216
{
 
217
    if (obj == NULL || key == NULL || obj->type != BENC_DICT) {
 
218
        return NULL;
 
219
    }
 
220
    benc_dict_entry_t *curr = obj->as.dict;
 
221
    while (NULL != curr)
 
222
    {
 
223
        if (0 == benc_bstr_compare(key, curr->key))
 
224
        {
 
225
            return curr->val;
 
226
        }
 
227
        
 
228
        curr = curr->next;
 
229
    }
 
230
    
 
231
    /* key not found */
 
232
    return NULL;
 
233
}
 
234
 
 
235
bool bobj_dict_insert(bobj_t *obj, benc_bstr_t *key, bobj_t *val)
 
236
{
 
237
    benc_dict_entry_t **prev_p = &(obj->as.dict);
 
238
    benc_dict_entry_t *curr = obj->as.dict;
 
239
    while (NULL != curr)
 
240
    {
 
241
        int cmp = benc_bstr_compare(key, curr->key);
 
242
        if (cmp < 0)
 
243
        {
 
244
            break;
 
245
        }
 
246
        else if (cmp == 0)
 
247
        {
 
248
            BENC_LOG_EXCEPTION("dict already contains this key");
 
249
            return false;
 
250
        }
 
251
        
 
252
        prev_p = &(curr->next);
 
253
        curr = curr->next;
 
254
    }
 
255
    
 
256
    *prev_p = benc_dict_entry_new(curr, key, val);
 
257
    return true;
 
258
}
 
259
 
 
260
bobj_t * bobj_dict_remove(bobj_t *obj, benc_bstr_t *key)
 
261
{
 
262
    benc_dict_entry_t **prev_p = &(obj->as.dict);
 
263
    benc_dict_entry_t *curr = obj->as.dict;
 
264
    while (NULL != curr)
 
265
    {
 
266
        if (0 == benc_bstr_compare(key, curr->key))
 
267
        {
 
268
            *prev_p = curr->next;
 
269
            return benc_dict_entry_free_return_val(curr);
 
270
        }
 
271
        
 
272
        prev_p = &(curr->next);
 
273
        curr = curr->next;
 
274
    }
 
275
    
 
276
    BENC_LOG_EXCEPTION("key not found");
 
277
    return NULL;
 
278
}