123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151 |
- /* 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 "benc/Object.h"
- #include "benc/String.h"
- #include "benc/Dict.h"
- #include "benc/List.h"
- #include "benc/serialization/standard/BencMessageReader.h"
- #include "exception/Er.h"
- #include "wire/Message.h"
- #include "util/Base10.h"
- static Er_DEFUN(Object* readGeneric(struct Message* msg, struct Allocator* alloc));
- static Er_DEFUN(int64_t readInt(struct Message* msg, struct Allocator* alloc))
- {
- int64_t num = Er(Base10_read(msg));
- if (Er(Message_epop8(msg)) != 'e') {
- Er_raise(Message_getAlloc(msg), "Int not terminated with 'e'");
- }
- Er_ret(num);
- }
- static Er_DEFUN(String* readString(struct Message* msg, struct Allocator* alloc))
- {
- int64_t len = Er(Base10_read(msg));
- if (len < 0) {
- Er_raise(alloc, "Negative string length");
- }
- if (Er(Message_epop8(msg)) != ':') {
- Er_raise(alloc, "String not deliniated with a ':'");
- }
- if (len > Message_getLength(msg)) {
- Er_raise(alloc, "String too long");
- }
- String* str = String_newBinary(NULL, len, alloc);
- Er(Message_epop(msg, str->bytes, len));
- Er_ret(str);
- }
- static Er_DEFUN(List* readList(struct Message* msg, struct Allocator* alloc))
- {
- struct List_Item* last = NULL;
- for (;;) {
- uint8_t chr = Er(Message_epop8(msg));
- if (chr == 'e') {
- List* out = Allocator_malloc(alloc, sizeof(List));
- *out = last;
- Er_ret(out);
- }
- Er(Message_epush8(msg, chr));
- struct List_Item* item = Allocator_malloc(alloc, sizeof(struct List_Item));
- item->elem = Er(readGeneric(msg, alloc));
- item->next = last;
- last = item;
- }
- }
- static Er_DEFUN(Dict* readDict(struct Message* msg, struct Allocator* alloc))
- {
- struct Dict_Entry* last = NULL;
- for (;;) {
- uint8_t chr = Er(Message_epop8(msg));
- if (chr == 'e') {
- Dict* out = Allocator_malloc(alloc, sizeof(Dict));
- *out = last;
- Er_ret(out);
- }
- Er(Message_epush8(msg, chr));
- struct Dict_Entry* entry = Allocator_malloc(alloc, sizeof(struct Dict_Entry));
- entry->key = Er(readString(msg, alloc));
- entry->val = Er(readGeneric(msg, alloc));
- entry->next = last;
- last = entry;
- }
- }
- static Er_DEFUN(Object* readGeneric(struct Message* msg, struct Allocator* alloc))
- {
- uint8_t chr = Er(Message_epop8(msg));
- Object* out = Allocator_calloc(alloc, sizeof(Object), 1);
- switch (chr) {
- case 'l': {
- out->type = Object_LIST;
- out->as.list = Er(readList(msg, alloc));
- break;
- }
- case 'd': {
- out->type = Object_DICT;
- out->as.dictionary = Er(readDict(msg, alloc));
- break;
- }
- case 'i': {
- out->type = Object_INTEGER;
- out->as.number = Er(readInt(msg, alloc));
- break;
- }
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9': {
- out->type = Object_STRING;
- Er(Message_epush8(msg, chr));
- out->as.string = Er(readString(msg, alloc));
- break;
- }
- default: Er_raise(alloc, "Unexpected character in message [%c]", (char)chr);
- }
- Er_ret(out);
- }
- Er_DEFUN(Dict* BencMessageReader_read(struct Message* msg, struct Allocator* alloc))
- {
- if (Er(Message_epop8h(msg)) != 'd') {
- Er_raise(alloc, "Message does not begin with a 'd' to open the dictionary");
- }
- Dict* out = Er(readDict(msg, alloc));
- Er_ret(out);
- }
- const char* BencMessageReader_readNoExcept(
- struct Message* msg, struct Allocator* alloc, Dict** outPtr)
- {
- struct Er_Ret* er = NULL;
- Dict* out = Er_check(&er, BencMessageReader_read(msg, alloc));
- if (er) {
- return er->message;
- }
- *outPtr = out;
- return NULL;
- }
|