/* libobby - Network text editing library
* Copyright (C) 2005 0x539 dev group
*
* 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 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, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <fstream>
#include "common.hpp"
#include "format_string.hpp"
#include "serialise/error.hpp"
#include "serialise/parser.hpp"
obby::serialise::parser::parser()
{
}
void obby::serialise::parser::deserialise(const std::string& file)
{
std::ifstream in(file.c_str() );
if(!in)
{
obby::format_string str(_(
"Could not open file '%0%' for reading"
) );
str << file;
throw error(str.str(), 0);
}
deserialise(in);
}
void obby::serialise::parser::deserialise(std::istream& stream)
{
const unsigned int bufsize = 1024;
char readbuf[bufsize];
std::string result;
// Initial preallocation
result.reserve(bufsize << 3);
#ifdef WIN32
// Other effort (see below) seems not to work on WIN32, the eofflag is
// set after the first 1024 Bytes have been read. Is this a bug in
// mingw?
std::string line;
while(std::getline(stream, line) )
{
// More preallocation, if the following line exceeds the
// current capacity
if(result.capacity() < result.length() + bufsize)
result.reserve(result.capacity() * 2);
result += line;
result += '\n';
}
#else
while(stream)
{
// More preallocation, if the following 1024 byte exceeds the
// current capacity
if(result.capacity() < result.length() + bufsize)
result.reserve(result.capacity() * 2);
// Read data, append to resulting string
stream.read(readbuf, bufsize);
result.append(readbuf, stream.gcount() );
}
#endif
deserialise_memory(result);
}
void obby::serialise::parser::deserialise_memory(const std::string& mem)
{
token_list list;
list.deserialise(mem);
token_list::iterator iter = list.begin();
// Get initial '!'
if(iter->get_type() != token::TYPE_EXCLAMATION)
{
throw error(
_("Expected initial exclamation mark"),
iter->get_line()
);
}
list.next_token(iter);
// Read document type
if(iter->get_type() != token::TYPE_IDENTIFIER)
{
throw error(
_("Expected document type after '!'"),
iter->get_line()
);
}
m_type = iter->get_text();
list.next_token(iter);
// Get indentation for following object
if(iter->get_type() != token::TYPE_INDENTATION)
{
throw error(
_("Expected newline after document type"),
iter->get_line()
);
}
// Must be top-level (indentation == 0)
if(iter->get_text().length() > 0)
{
throw error(
_("Expected top-level object after document type"),
iter->get_line()
);
}
list.next_token(iter);
// Root object should follow
if(iter->get_type() != token::TYPE_IDENTIFIER)
{
throw error(
_("Expected root object after document type"),
iter->get_line()
);
}
m_object.deserialise(list, iter);
// Must be EOF now
if(iter != list.end() )
{
format_string str(_("Expected end of input instead of '%0%'") );
str << iter->get_text();
throw error(str.str(), iter->get_line() );
}
}
void obby::serialise::parser::serialise(const std::string& file) const
{
std::ofstream out(file.c_str() );
if(!out)
{
obby::format_string str(
_("Could not open file '%0%' for writing")
);
str << file;
throw std::runtime_error(str.str() );
}
serialise(out);
}
void obby::serialise::parser::serialise(std::ostream& stream) const
{
// Get string
std::string result;
serialise_memory(result);
// Write it into the file
stream << result;
stream.flush();
}
void obby::serialise::parser::serialise_memory(std::string& mem) const
{
// Empty list
token_list list;
// Add document type
list.add(token::TYPE_EXCLAMATION, "!", 0);
list.add(token::TYPE_IDENTIFIER, m_type, 0);
// Add top-level indentation
list.add(token::TYPE_INDENTATION, "", 0);
// Serialise root object with its children
m_object.serialise(list);
list.serialise(mem);
}
const std::string& obby::serialise::parser::get_type() const
{
return m_type;
}
void obby::serialise::parser::set_type(const std::string& type)
{
m_type = type;
}
const obby::serialise::object& obby::serialise::parser::get_root() const
{
return m_object;
}
obby::serialise::object& obby::serialise::parser::get_root()
{
return m_object;
}
syntax highlighted by Code2HTML, v. 0.9.1