mirror of git://git.psyc.eu/libpsyc
227 lines
6.3 KiB
C
227 lines
6.3 KiB
C
/*
|
|
This file is part of libpsyc.
|
|
Copyright (C) 2011,2012 Carlo v. Loesch, Gabor X Toth, Mathias L. Baumann,
|
|
and other contributing authors.
|
|
|
|
libpsyc is free software: you can redistribute it and/or modify it under the
|
|
terms of the GNU Affero General Public License as published by the Free
|
|
Software Foundation, either version 3 of the License, or (at your option) any
|
|
later version. As a special exception, libpsyc is distributed with additional
|
|
permissions to link libpsyc libraries with non-AGPL works.
|
|
|
|
libpsyc 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 Affero General Public License for more
|
|
details.
|
|
|
|
You should have received a copy of the GNU Affero General Public License and
|
|
the linking exception along with libpsyc in a COPYING file.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
|
|
#include "lib.h"
|
|
#include <psyc/packet.h>
|
|
#include <psyc/render.h>
|
|
|
|
inline PsycRenderRC
|
|
psyc_render_elem (PsycElem *elem, char *buffer, size_t buflen)
|
|
{
|
|
size_t cur = 0;
|
|
|
|
if (elem->length > buflen) // return error if element doesn't fit in buffer
|
|
return PSYC_RENDER_ERROR;
|
|
|
|
if (elem->type.length) {
|
|
buffer[cur++] = '=';
|
|
memcpy(buffer + cur, PSYC_S2ARG(elem->type));
|
|
cur += elem->type.length;
|
|
}
|
|
|
|
if (elem->value.length && !(elem->flag & PSYC_ELEM_NO_LENGTH)) {
|
|
if (elem->type.length)
|
|
buffer[cur++] = ':';
|
|
cur += itoa(elem->value.length, buffer + cur, 10);
|
|
}
|
|
|
|
if (elem->value.length) {
|
|
buffer[cur++] = ' ';
|
|
memcpy(buffer + cur, PSYC_S2ARG(elem->value));
|
|
cur += elem->value.length;
|
|
}
|
|
|
|
// Actual length should be equal to pre-calculated length at this point.
|
|
ASSERT(cur == elem->length);
|
|
return PSYC_RENDER_SUCCESS;
|
|
}
|
|
|
|
inline PsycRenderRC
|
|
psyc_render_dict_key (PsycDictKey *elem, char *buffer, size_t buflen)
|
|
{
|
|
size_t cur = 0;
|
|
|
|
if (elem->length > buflen) // return error if element doesn't fit in buffer
|
|
return PSYC_RENDER_ERROR;
|
|
|
|
if (elem->value.length && !(elem->flag & PSYC_ELEM_NO_LENGTH))
|
|
cur += itoa(elem->value.length, buffer + cur, 10);
|
|
|
|
if (elem->value.length) {
|
|
buffer[cur++] = ' ';
|
|
memcpy(buffer + cur, PSYC_S2ARG(elem->value));
|
|
cur += elem->value.length;
|
|
}
|
|
|
|
// Actual length should be equal to pre-calculated length at this point.
|
|
ASSERT(cur == elem->length);
|
|
return PSYC_RENDER_SUCCESS;
|
|
}
|
|
|
|
#ifdef __INLINE_PSYC_RENDER
|
|
extern inline
|
|
#endif
|
|
PsycRenderRC
|
|
psyc_render_list (PsycList *list, char *buffer, size_t buflen)
|
|
{
|
|
size_t i, cur = 0;
|
|
|
|
ASSERT(NULL != list);
|
|
if (list->length > buflen) // return error if list doesn't fit in buffer
|
|
return PSYC_RENDER_ERROR;
|
|
|
|
ASSERT(NULL != buffer);
|
|
if (list->type.length) {
|
|
memcpy(buffer + cur, PSYC_S2ARG(list->type));
|
|
cur += list->type.length;
|
|
}
|
|
|
|
for (i = 0; i < list->num_elems; i++) {
|
|
buffer[cur++] = '|';
|
|
psyc_render_elem(&list->elems[i], buffer + cur, buflen - cur);
|
|
cur += list->elems[i].length;
|
|
}
|
|
|
|
// Actual length should be equal to pre-calculated length at this point.
|
|
ASSERT(cur == list->length);
|
|
return PSYC_RENDER_SUCCESS;
|
|
}
|
|
|
|
#ifdef __INLINE_PSYC_RENDER
|
|
extern inline
|
|
#endif
|
|
PsycRenderRC
|
|
psyc_render_dict (PsycDict *dict, char *buffer, size_t buflen)
|
|
{
|
|
size_t i, cur = 0;
|
|
|
|
if (dict->length > buflen) // return error if dict doesn't fit in buffer
|
|
return PSYC_RENDER_ERROR;
|
|
|
|
if (dict->type.length) {
|
|
memcpy(buffer + cur, PSYC_S2ARG(dict->type));
|
|
cur += dict->type.length;
|
|
}
|
|
|
|
for (i = 0; i < dict->num_elems; i++) {
|
|
buffer[cur++] = '{';
|
|
psyc_render_dict_key(&dict->elems[i].key, buffer + cur, buflen - cur);
|
|
cur += dict->elems[i].key.length;
|
|
|
|
buffer[cur++] = '}';
|
|
psyc_render_elem(&dict->elems[i].value, buffer + cur, buflen - cur);
|
|
cur += dict->elems[i].value.length;
|
|
}
|
|
|
|
// Actual length should be equal to pre-calculated length at this point.
|
|
ASSERT(cur == dict->length);
|
|
return PSYC_RENDER_SUCCESS;
|
|
}
|
|
|
|
inline size_t
|
|
psyc_render_modifier (PsycModifier *mod, char *buffer)
|
|
{
|
|
size_t cur = 0;
|
|
|
|
buffer[cur++] = mod->oper;
|
|
memcpy(buffer + cur, mod->name.data, mod->name.length);
|
|
cur += mod->name.length;
|
|
if (cur == 1)
|
|
return cur; // error, name can't be empty
|
|
|
|
if (mod->value.length
|
|
&& (mod->flag & PSYC_MODIFIER_NEED_LENGTH
|
|
|| mod->flag == PSYC_MODIFIER_CHECK_LENGTH)) {
|
|
buffer[cur++] = ' ';
|
|
cur += itoa(mod->value.length, buffer + cur, 10);
|
|
}
|
|
|
|
buffer[cur++] = '\t';
|
|
memcpy(buffer + cur, mod->value.data, mod->value.length);
|
|
cur += mod->value.length;
|
|
buffer[cur++] = '\n';
|
|
|
|
return cur;
|
|
}
|
|
|
|
#ifdef __INLINE_PSYC_RENDER
|
|
extern inline
|
|
#endif
|
|
PsycRenderRC
|
|
psyc_render (PsycPacket *p, char *buffer, size_t buflen)
|
|
{
|
|
size_t i, cur = 0, len;
|
|
|
|
if (p->length > buflen) // return error if packet doesn't fit in buffer
|
|
return PSYC_RENDER_ERROR;
|
|
|
|
// render routing modifiers
|
|
for (i = 0; i < p->routing.lines; i++) {
|
|
len = psyc_render_modifier(&p->routing.modifiers[i], buffer + cur);
|
|
cur += len;
|
|
if (len <= 1)
|
|
return PSYC_RENDER_ERROR_MODIFIER_NAME_MISSING;
|
|
}
|
|
|
|
// add length if needed
|
|
if (p->contentlen && !(p->flag & PSYC_PACKET_NO_LENGTH))
|
|
cur += itoa(p->contentlen, buffer + cur, 10);
|
|
|
|
if (p->contentlen)
|
|
buffer[cur++] = '\n'; // start of content part if there's content or length
|
|
|
|
if (p->content.length) { // render raw content if present
|
|
memcpy(buffer + cur, p->content.data, p->content.length);
|
|
cur += p->content.length;
|
|
} else {
|
|
if (p->stateop) {
|
|
buffer[cur++] = p->stateop;
|
|
buffer[cur++] = '\n';
|
|
}
|
|
// render entity modifiers
|
|
for (i = 0; i < p->entity.lines; i++)
|
|
cur += psyc_render_modifier(&p->entity.modifiers[i],
|
|
buffer + cur);
|
|
|
|
if (p->method.length) { // add method\n
|
|
memcpy(buffer + cur, p->method.data, p->method.length);
|
|
cur += p->method.length;
|
|
buffer[cur++] = '\n';
|
|
|
|
if (p->data.length) { // add data\n
|
|
memcpy(buffer + cur, p->data.data, p->data.length);
|
|
cur += p->data.length;
|
|
buffer[cur++] = '\n';
|
|
}
|
|
} else if (p->data.length) // error, we have data but no modifier
|
|
return PSYC_RENDER_ERROR_METHOD_MISSING;
|
|
}
|
|
|
|
// add packet delimiter
|
|
buffer[cur++] = PSYC_PACKET_DELIMITER_CHAR;
|
|
buffer[cur++] = '\n';
|
|
|
|
// actual length should be equal to pre-calculated length at this point
|
|
ASSERT(cur == p->length);
|
|
return PSYC_RENDER_SUCCESS;
|
|
}
|