// This file may be redistributed and modified only under the terms of
// the GNU Lesser General Public License (See COPYING for details).
// Copyright (C) 2000-2001 Stefanus Du Toit, Michael Day
#include <Atlas/Codecs/Packed.h>
#include <iostream>
#include <cstdlib>
namespace Atlas { namespace Codecs {
Packed::Packed(std::iostream& s, Atlas::Bridge & b)
: m_socket(s), m_bridge(b)
{
m_state.push(PARSE_STREAM);
}
void Packed::parseStream(char next)
{
switch (next)
{
case '[':
m_bridge.streamMessage();
m_state.push(PARSE_MAP);
break;
default:
// FIXME signal error here
// unexpected character
break;
}
}
void Packed::parseMap(char next)
{
switch (next)
{
case ']':
m_bridge.mapEnd();
m_state.pop();
break;
case '[':
m_state.push(PARSE_MAP);
m_state.push(PARSE_MAP_BEGIN);
m_state.push(PARSE_NAME);
break;
case '(':
m_state.push(PARSE_LIST);
m_state.push(PARSE_LIST_BEGIN);
m_state.push(PARSE_NAME);
break;
case '$':
m_state.push(PARSE_STRING);
m_state.push(PARSE_NAME);
break;
case '@':
m_state.push(PARSE_INT);
m_state.push(PARSE_NAME);
break;
case '#':
m_state.push(PARSE_FLOAT);
m_state.push(PARSE_NAME);
break;
default:
// FIXME signal error here
// unexpected character
break;
}
}
void Packed::parseList(char next)
{
switch (next)
{
case ')':
m_bridge.listEnd();
m_state.pop();
break;
case '[':
m_bridge.listMapItem();
m_state.push(PARSE_MAP);
break;
case '(':
m_bridge.listListItem();
m_state.push(PARSE_LIST);
break;
case '$':
m_state.push(PARSE_STRING);
break;
case '@':
m_state.push(PARSE_INT);
break;
case '#':
m_state.push(PARSE_FLOAT);
break;
default:
// FIXME signal error here
// unexpected character
break;
}
}
void Packed::parseMapBegin(char next)
{
m_bridge.mapMapItem(hexDecode(m_name));
m_socket.putback(next);
m_state.pop();
m_name.erase();
}
void Packed::parseListBegin(char next)
{
m_bridge.mapListItem(hexDecode(m_name));
m_socket.putback(next);
m_state.pop();
m_name.erase();
}
void Packed::parseInt(char next)
{
switch (next)
{
case '[':
case ']':
case '(':
case ')':
case '$':
case '@':
case '#':
m_socket.putback(next);
m_state.pop();
if (m_state.top() == PARSE_MAP)
{
m_bridge.mapIntItem(hexDecode(m_name), atol(m_data.c_str()));
m_name.erase();
}
else if (m_state.top() == PARSE_LIST)
{
m_bridge.listIntItem(atol(m_data.c_str()));
}
else
{
// FIXME some kind of sanity checking assertion here
}
m_data.erase();
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '-':
case '+':
m_data += next;
break;
default:
// FIXME signal error here
// unexpected character
break;
}
}
void Packed::parseFloat(char next)
{
switch (next)
{
case '[':
case ']':
case '(':
case ')':
case '$':
case '@':
case '#':
m_socket.putback(next);
m_state.pop();
if (m_state.top() == PARSE_MAP)
{
m_bridge.mapFloatItem(hexDecode(m_name), atof(m_data.c_str()));
m_name.erase();
}
else if (m_state.top() == PARSE_LIST)
{
m_bridge.listFloatItem(atof(m_data.c_str()));
}
else
{
// FIXME some kind of sanity checking assertion here
}
m_data.erase();
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '.':
case '-':
case '+':
case 'e':
case 'E':
m_data += next;
break;
default:
// FIXME signal error here
// unexpected character
break;
}
}
void Packed::parseString(char next)
{
switch (next)
{
case '[':
case ']':
case '(':
case ')':
case '$':
case '@':
case '#':
m_socket.putback(next);
m_state.pop();
if (m_state.top() == PARSE_MAP)
{
m_bridge.mapStringItem(hexDecode(m_name), hexDecode(m_data));
m_name.erase();
}
else if (m_state.top() == PARSE_LIST)
{
m_bridge.listStringItem(hexDecode(m_data));
}
else
{
// FIXME some kind of sanity checking assertion here
}
m_data.erase();
break;
case '=':
// FIXME signal error here
// unexpected character
break;
default:
m_data += next;
break;
}
}
void Packed::parseName(char next)
{
switch (next)
{
case '=':
m_state.pop();
break;
case '[':
case ']':
case '(':
case ')':
case '$':
case '@':
case '#':
// FIXME signal error here
// unexpected character
break;
default:
m_name += next;
break;
}
}
void Packed::poll(bool can_read)
{
if (!can_read) return;
m_socket.peek();
std::streamsize count;
while ((count = m_socket.rdbuf()->in_avail()) > 0) {
for (int i = 0; i < count; ++i) {
int next = m_socket.rdbuf()->sbumpc();
switch (m_state.top())
{
case PARSE_STREAM: parseStream(next); break;
case PARSE_MAP: parseMap(next); break;
case PARSE_LIST: parseList(next); break;
case PARSE_MAP_BEGIN: parseMapBegin(next); break;
case PARSE_LIST_BEGIN: parseListBegin(next); break;
case PARSE_INT: parseInt(next); break;
case PARSE_FLOAT: parseFloat(next); break;
case PARSE_STRING: parseString(next); break;
case PARSE_NAME: parseName(next); break;
}
}
}
}
void Packed::streamBegin()
{
m_bridge.streamBegin();
}
void Packed::streamMessage()
{
m_socket << '[';
}
void Packed::streamEnd()
{
m_bridge.streamEnd();
}
void Packed::mapMapItem(const std::string& name)
{
m_socket << '[' << hexEncode(name) << '=';
}
void Packed::mapListItem(const std::string& name)
{
m_socket << '(' << hexEncode(name) << '=';
}
void Packed::mapIntItem(const std::string& name, long data)
{
m_socket << '@' << hexEncode(name) << '=' << data;
}
void Packed::mapFloatItem(const std::string& name, double data)
{
m_socket << '#' << hexEncode(name) << '=' << data;
}
void Packed::mapStringItem(const std::string& name, const std::string& data)
{
m_socket << '$' << hexEncode(name) << '=' << hexEncode(data);
}
void Packed::mapEnd()
{
m_socket << ']';
}
void Packed::listMapItem()
{
m_socket << '[';
}
void Packed::listListItem()
{
m_socket << '(';
}
void Packed::listIntItem(long data)
{
m_socket << '@' << data;
}
void Packed::listFloatItem(double data)
{
m_socket << '#' << data;
}
void Packed::listStringItem(const std::string& data)
{
m_socket << '$' << hexEncode(data);
}
void Packed::listEnd()
{
m_socket << ')';
}
} } // namespace Atlas::Codecs
syntax highlighted by Code2HTML, v. 0.9.1