339 lines
11 KiB
C++
Raw Normal View History

/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, 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; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "msgpack.hpp"
bool MsgPack::get_bool(const void* buffer, const bool inc, bool* value) {
uint8_t v;
if (seek_ptr >= buffer_size) return false; // End of buffer
v = ((uint8_t*)buffer)[seek_ptr];
if (v == MSGPACK_FALSE)
*value = false;
else if (v == MSGPACK_TRUE)
*value = true;
else
return false; // Not a bool
if (inc) seek_ptr++;
return true;
}
bool MsgPack::get_raw_byte(const void* buffer, const bool inc, uint8_t* byte) {
if (seek_ptr >= buffer_size) return false; // End of buffer
*byte = ((uint8_t*)buffer)[seek_ptr];
if (inc) seek_ptr++;
return true;
}
bool MsgPack::get_raw_word(const void* buffer, const bool inc, uint16_t* word) {
if ((seek_ptr + 1) >= buffer_size) return false; // End of buffer
*word = (((uint8_t*)buffer)[seek_ptr] << 8) | ((uint8_t*)buffer)[seek_ptr + 1];
if (inc) seek_ptr += 2;
return true;
}
bool MsgPack::get_u8(const void* buffer, const bool inc, uint8_t* value) {
uint8_t v;
if (seek_ptr >= buffer_size) return false; // End of buffer
v = ((uint8_t*)buffer)[seek_ptr];
if (!(v & 0x80))
*value = ((uint8_t*)buffer)[seek_ptr]; // Fixnum
else if (v == MSGPACK_TYPE_U8)
*value = ((uint8_t*)buffer)[seek_ptr + 1]; // u8
else
return false; // Value isn't a u8 or fixnum
if (inc) seek_ptr++;
return true;
2016-05-16 12:02:45 +02:00
}
// TODO: Typecheck function
bool MsgPack::get_u16(const void* buffer, const bool inc, uint16_t* value) {
uint8_t byte;
if ((seek_ptr + 1) >= buffer_size) return false; // End of buffer
if ((get_raw_byte(buffer, true, &byte)) && (byte != MSGPACK_TYPE_U16)) return false; // Value isn't a u16
*value = (((uint8_t*)buffer)[seek_ptr] << 8) | ((uint8_t*)buffer)[seek_ptr + 1];
if (inc) seek_ptr += 2;
return true;
}
bool MsgPack::get_s32(const void* buffer, const bool inc, int32_t* value) {
uint8_t byte;
if ((seek_ptr + 3) >= buffer_size) return false; // End of buffer
if ((get_raw_byte(buffer, true, &byte)) && (byte != MSGPACK_TYPE_S32)) return false; // Value isn't a s32
*value = (((uint8_t*)buffer)[seek_ptr] << 24) | (((uint8_t*)buffer)[seek_ptr + 1] << 16) |
(((uint8_t*)buffer)[seek_ptr + 2] << 8) | ((uint8_t*)buffer)[seek_ptr + 3];
if (inc) seek_ptr += 4;
return true;
}
bool MsgPack::get_string(const void* buffer, const bool inc, std::string& value) {
size_t length;
uint8_t byte;
// Todo: Set max length !
if ((seek_ptr + 3) >= buffer_size) return false; // End of buffer
if ((get_raw_byte(buffer, true, &byte)) && (byte != MSGPACK_TYPE_STR8) && (byte != MSGPACK_TYPE_STR16)) return false; // Value isn't a str8 or str16
if (byte == MSGPACK_TYPE_STR8) {
if (!get_raw_byte(buffer, true, (uint8_t*)&length)) return false; // Couldn't get str8 length
} else if (byte == MSGPACK_TYPE_STR16) {
if (!get_raw_word(buffer, true, (uint16_t*)&length)) return false; // Couldn't get str16 length
}
memcpy(&value[0], ((uint8_t*)buffer), length); // std::string(
if (inc) seek_ptr += length;
return true;
}
bool MsgPack::init_search(const void* buffer, const size_t size) {
uint8_t byte;
uint16_t map_size;
if (!size) return false;
buffer_size = size;
seek_ptr = 0;
if ((get_raw_byte(buffer, true, &byte)) && (byte != MSGPACK_TYPE_MAP16)) return false; // First record isn't a map16
if (!get_raw_word(buffer, true, &map_size)) return false; // Couldn't get map16 size
if (!map_size) return false;
return true;
}
bool MsgPack::skip(const void* buffer) {
uint8_t byte, c;
size_t length;
if (!get_raw_byte(buffer, true, &byte)) return false; // Couldn't get type
if (!(byte & 0x80)) return true; // Positive fixnum, already skipped by get_raw_byte
if ((byte & 0xE0) == 0xE0) return true; // Negative fixnum, already skipped by get_raw_byte
if ((byte & 0xE0) == 0xA0) { // Fixstr
seek_ptr += (byte & 0x1F);
return true;
}
if ((byte & 0xF0) == 0x80) { // Fixmap
length = (byte & 0x0F) * 2;
for (c = 0; c < length; c++)
skip(buffer);
return true;
}
if ((byte & 0xF0) == 0x90) { // Fixarray
length = byte & 0x0F;
for (c = 0; c < length; c++)
skip(buffer);
return true;
}
switch (byte) {
case MSGPACK_NIL:
case MSGPACK_FALSE:
case MSGPACK_TRUE: // Already skipped by get_raw_byte
break;
case MSGPACK_TYPE_U8:
case MSGPACK_TYPE_S8:
seek_ptr++;
break;
case MSGPACK_TYPE_U16:
case MSGPACK_TYPE_S16:
seek_ptr += 2;
break;
case MSGPACK_TYPE_U32:
case MSGPACK_TYPE_S32:
seek_ptr += 4;
break;
case MSGPACK_TYPE_U64:
case MSGPACK_TYPE_S64:
seek_ptr += 8;
break;
case MSGPACK_TYPE_STR8:
if (!get_raw_byte(buffer, true, (uint8_t*)&length)) return false; // Couldn't get str8 length
seek_ptr += length;
break;
case MSGPACK_TYPE_STR16:
if (!get_raw_word(buffer, true, (uint16_t*)&length)) return false; // Couldn't get str16 length
seek_ptr += length;
break;
case MSGPACK_TYPE_ARR16:
if (!get_raw_word(buffer, true, (uint16_t*)&length)) return false; // Couldn't get arr16 length
for (c = 0; c < length; c++)
skip(buffer);
break;
case MSGPACK_TYPE_MAP16:
if (!get_raw_word(buffer, true, (uint16_t*)&length)) return false; // Couldn't get map16 length
for (c = 0; c < (length * 2); c++)
skip(buffer);
break;
default:
return false; // Type unsupported
}
return true;
}
bool MsgPack::search_key(const void* buffer, const MsgPack::RecID record_id) {
uint8_t byte;
uint16_t key;
while (get_raw_byte(buffer, false, &byte)) {
if (!get_u16(buffer, true, &key)) return false; // Couldn't get key
if (key == record_id) return true; // Found record
if (!skip(buffer)) return false; // Can't skip to next key
};
return false;
}
bool MsgPack::msgpack_get(const void* buffer, const size_t size, const RecID record_id, bool* value) {
init_search(buffer, size);
if (!search_key(buffer, record_id)) return false; // Record not found
if (!get_bool(buffer, false, value)) return false; // Value isn't a bool
return true;
}
bool MsgPack::msgpack_get(const void* buffer, const size_t size, const RecID record_id, uint8_t* value) {
if (!init_search(buffer, size)) return false;
if (!search_key(buffer, record_id)) return false; // Record not found
if (!get_u8(buffer, false, value)) return false; // Value isn't a u8
return true;
}
bool MsgPack::msgpack_get(const void* buffer, const size_t size, const RecID record_id, int64_t* value) {
uint8_t byte;
init_search(buffer, size);
if (!search_key(buffer, record_id)) return false; // Record not found
if ((seek_ptr + 3) >= buffer_size) return false; // End of buffer
if ((get_raw_byte(buffer, true, &byte)) && (byte != MSGPACK_TYPE_S64)) return false; // Value isn't a s64
*value = ((int64_t)((uint8_t*)buffer)[seek_ptr] << 56) | ((int64_t)((uint8_t*)buffer)[seek_ptr + 1] << 48) |
((int64_t)((uint8_t*)buffer)[seek_ptr + 2] << 40) | ((int64_t)((uint8_t*)buffer)[seek_ptr + 3] << 32) |
(((uint8_t*)buffer)[seek_ptr + 4] << 24) | (((uint8_t*)buffer)[seek_ptr + 5] << 16) |
(((uint8_t*)buffer)[seek_ptr + 6] << 8) | ((uint8_t*)buffer)[seek_ptr + 7];
return true;
2016-05-16 12:02:45 +02:00
}
bool MsgPack::msgpack_get(const void* buffer, const size_t size, const RecID record_id, std::string& value) {
init_search(buffer, size);
if (!search_key(buffer, record_id)) return false; // Record not found
if (!get_string(buffer, false, value)) return false; // Value isn't a char array
return true;
}
2016-05-16 12:02:45 +02:00
void MsgPack::msgpack_init(const void* buffer, size_t* ptr) {
((uint8_t*)buffer)[0] = MSGPACK_TYPE_MAP16;
((uint8_t*)buffer)[1] = 0;
((uint8_t*)buffer)[2] = 0;
2016-05-16 12:02:45 +02:00
*ptr = 3;
2016-05-16 12:02:45 +02:00
}
void MsgPack::add_key(const void* buffer, size_t* ptr, const RecID record_id) {
uint16_t key;
((uint8_t*)buffer)[(*ptr)++] = MSGPACK_TYPE_U16;
((uint8_t*)buffer)[(*ptr)++] = record_id >> 8;
((uint8_t*)buffer)[(*ptr)++] = record_id & 0xFF;
// Auto-inc MAP16 size which should be at the beginning of the buffer
key = (((uint8_t*)buffer)[1] << 8) | ((uint8_t*)buffer)[2];
key++;
((uint8_t*)buffer)[1] = key >> 8;
((uint8_t*)buffer)[2] = key & 0xFF;
2016-05-16 12:02:45 +02:00
}
void MsgPack::msgpack_add(const void* buffer, size_t* ptr, const RecID record_id, bool value) {
add_key(buffer, ptr, record_id);
if (value)
((uint8_t*)buffer)[(*ptr)++] = MSGPACK_TRUE;
else
((uint8_t*)buffer)[(*ptr)++] = MSGPACK_FALSE;
2016-05-16 12:02:45 +02:00
}
void MsgPack::msgpack_add(const void* buffer, size_t* ptr, const RecID record_id, uint8_t value) {
add_key(buffer, ptr, record_id);
if (value < 128) {
((uint8_t*)buffer)[(*ptr)++] = value;
} else {
((uint8_t*)buffer)[(*ptr)++] = MSGPACK_TYPE_U8;
((uint8_t*)buffer)[(*ptr)++] = value;
}
2016-05-16 12:02:45 +02:00
}
void MsgPack::msgpack_add(const void* buffer, size_t* ptr, const RecID record_id, int64_t value) {
uint8_t c;
add_key(buffer, ptr, record_id);
((uint8_t*)buffer)[(*ptr)++] = MSGPACK_TYPE_S64;
for (c = 0; c < 8; c++)
((uint8_t*)buffer)[(*ptr)++] = (value >> (8 * (7 - c))) & 0xFF;
2016-05-16 12:02:45 +02:00
}
bool MsgPack::msgpack_add(const void* buffer, size_t* ptr, const RecID record_id, std::string value) {
uint8_t c;
size_t length;
add_key(buffer, ptr, record_id);
length = value.size();
if (length < 32) {
((uint8_t*)buffer)[(*ptr)++] = length | 0xA0; // Fixstr
} else if ((length >= 32) && (length < 256)) {
((uint8_t*)buffer)[(*ptr)++] = MSGPACK_TYPE_STR8;
((uint8_t*)buffer)[(*ptr)++] = length;
} else if ((length >= 256) && (length < 65536)) {
((uint8_t*)buffer)[(*ptr)++] = MSGPACK_TYPE_STR16;
((uint8_t*)buffer)[(*ptr)++] = length >> 8;
((uint8_t*)buffer)[(*ptr)++] = length & 0xFF;
} else {
return false;
}
for (c = 0; c < length; c++)
((uint8_t*)buffer)[(*ptr)++] = value[c];
return true;
}