Refactoring, some enhancements to tl::Variant

- Split binary and regular streams
- Binary serialization of tl::Variant
- Fixing tl::Variant parsable string representation for byte arrays and char
  (Format is '...'b for byte arrays and '.'c for chars).
- tl::to_quoted_string now allows 0 characters in the string
  (escapes to '\000')
This commit is contained in:
Matthias Koefferlein 2026-05-03 16:24:14 +02:00
parent 7f6071db31
commit 1de28f2d6b
14 changed files with 1554 additions and 786 deletions

View File

@ -36,7 +36,7 @@
#include "dbTrans.h"
#include "dbText.h"
#include "tlStream.h"
#include "tlBinaryStream.h"
#include "tlException.h"
namespace db

View File

@ -251,7 +251,7 @@ static gsi::Methods properties_support_methods ()
"convenient than using the layout object and the properties ID to retrieve the property value. "
) +
gsi::method ("to_s", (std::string (T::*) () const) &T::to_string,
"@brief Returns a string representing the polygon\n"
"@brief Returns a string representing the object\n"
) +
gsi::method_ext ("properties", &get_properties_meth_impl<T>,
"@brief Gets the user properties\n"

View File

@ -11,6 +11,7 @@ FORMS =
SOURCES = \
tlAssert.cc \
tlBase64.cc \
tlBinaryStream.cc \
tlColor.cc \
tlClassRegistry.cc \
tlCopyOnWrite.cc \
@ -62,6 +63,7 @@ HEADERS = \
tlAlgorithm.h \
tlAssert.h \
tlBase64.h \
tlBinaryStream.h \
tlColor.h \
tlClassRegistry.h \
tlCopyOnWrite.h \

View File

@ -0,0 +1,691 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2026 Matthias Koefferlein
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "tlBinaryStream.h"
#include <limits>
namespace tl
{
// ---------------------------------------------------------------
// Type codes for Variant serialization
// These type codes are intentionally separated from tl::Variant's
// type codes to allow a backward-compatible serialization scheme.
enum VariantTypeCode
{
var_type_nil = 0,
var_type_bool = 1,
var_type_char = 2,
var_type_schar = 3,
var_type_uchar = 4,
var_type_short = 5,
var_type_ushort = 6,
var_type_int = 7,
var_type_uint = 8,
var_type_long = 9,
var_type_ulong = 10,
var_type_longlong = 11,
var_type_ulonglong = 12,
var_type_id = 13,
var_type_float = 14,
var_type_double = 15,
var_type_string = 16,
var_type_bytes = 17,
var_type_list = 18,
var_type_array = 19,
var_type_other = -1
};
// ---------------------------------------------------------------
class UnexpectedEndOfFileException
: public tl::Exception
{
public:
UnexpectedEndOfFileException (const std::string &f)
: tl::Exception (tl::to_string (tr ("Unexpected end of file in: %s")), f)
{ }
};
class InvalidVariantTypeCode
: public tl::Exception
{
public:
InvalidVariantTypeCode (const std::string &f, int tc)
: tl::Exception (tl::to_string (tr ("Invalid variant type code %d in file: %s - maybe file is too new for this build?")), tc, f)
{ }
};
// ---------------------------------------------------------------
BinaryInputStream::BinaryInputStream (InputStream &stream)
: m_stream (stream)
{
// .. nothing yet ..
}
void
BinaryInputStream::reset ()
{
m_stream.reset ();
}
BinaryInputStream &
BinaryInputStream::operator>> (std::string &v)
{
uint64_t l = 0;
*this >> l;
v.clear ();
v.reserve (l);
size_t chunk_size = 1024, n = l;
while (n > 0) {
size_t chunk_len = std::min (n, chunk_size);
const char *chunk_data = m_stream.get (chunk_len);
if (! chunk_data) {
throw UnexpectedEndOfFileException (source ());
}
v.append (chunk_data, chunk_len);
n -= chunk_len;
}
return *this;
}
BinaryInputStream &
BinaryInputStream::operator>> (std::vector<char> &v)
{
uint64_t l = 0;
*this >> l;
v.clear ();
v.reserve (l);
size_t chunk_size = 1024, n = l;
while (n > 0) {
size_t chunk_len = std::min (n, chunk_size);
const char *chunk_data = m_stream.get (chunk_len);
if (! chunk_data) {
throw UnexpectedEndOfFileException (source ());
}
v.insert (v.end (), chunk_data, chunk_data + chunk_len);
n -= chunk_len;
}
return *this;
}
BinaryInputStream &
BinaryInputStream::operator>> (double &v)
{
const char *chunk_data = m_stream.get (8);
if (! chunk_data) {
throw UnexpectedEndOfFileException (source ());
}
// TODO: for now, we assume that file and memory layout are identical on all platforms
v = *reinterpret_cast<const double *> (chunk_data);
return *this;
}
BinaryInputStream &
BinaryInputStream::operator>> (float &v)
{
const char *chunk_data = m_stream.get (4);
if (! chunk_data) {
throw UnexpectedEndOfFileException (source ());
}
// TODO: for now, we assume that file and memory layout are identical on all platforms
v = *reinterpret_cast<const float *> (chunk_data);
return *this;
}
BinaryInputStream &
BinaryInputStream::operator>> (bool &v)
{
const char *chunk_data = m_stream.get (1);
if (! chunk_data) {
throw UnexpectedEndOfFileException (source ());
}
v = *chunk_data != 0;
return *this;
}
BinaryInputStream &
BinaryInputStream::operator>> (uint8_t &v)
{
const char *chunk_data = m_stream.get (1);
if (! chunk_data) {
throw UnexpectedEndOfFileException (source ());
}
v = (uint8_t) *chunk_data;
return *this;
}
BinaryInputStream &
BinaryInputStream::operator>> (int8_t &v)
{
const char *chunk_data = m_stream.get (1);
if (! chunk_data) {
throw UnexpectedEndOfFileException (source ());
}
v = (int8_t) *chunk_data;
return *this;
}
BinaryInputStream &
BinaryInputStream::operator>> (uint16_t &v)
{
const char *chunk_data = m_stream.get (2);
if (! chunk_data) {
throw UnexpectedEndOfFileException (source ());
}
// TODO: for now, we assume that file and memory layout are identical on all platforms
v = *reinterpret_cast<const uint16_t *> (chunk_data);
return *this;
}
BinaryInputStream &
BinaryInputStream::operator>> (int16_t &v)
{
const char *chunk_data = m_stream.get (2);
if (! chunk_data) {
throw UnexpectedEndOfFileException (source ());
}
// TODO: for now, we assume that file and memory layout are identical on all platforms
v = *reinterpret_cast<const int16_t *> (chunk_data);
return *this;
}
BinaryInputStream &
BinaryInputStream::operator>> (uint32_t &v)
{
const char *chunk_data = m_stream.get (4);
if (! chunk_data) {
throw UnexpectedEndOfFileException (source ());
}
// TODO: for now, we assume that file and memory layout are identical on all platforms
v = *reinterpret_cast<const uint32_t *> (chunk_data);
return *this;
}
BinaryInputStream &
BinaryInputStream::operator>> (int32_t &v)
{
const char *chunk_data = m_stream.get (4);
if (! chunk_data) {
throw UnexpectedEndOfFileException (source ());
}
// TODO: for now, we assume that file and memory layout are identical on all platforms
v = *reinterpret_cast<const int32_t *> (chunk_data);
return *this;
}
BinaryInputStream &
BinaryInputStream::operator>> (uint64_t &v)
{
const char *chunk_data = m_stream.get (8);
if (! chunk_data) {
throw UnexpectedEndOfFileException (source ());
}
// TODO: for now, we assume that file and memory layout are identical on all platforms
v = *reinterpret_cast<const uint64_t *> (chunk_data);
return *this;
}
BinaryInputStream &
BinaryInputStream::operator>> (int64_t &v)
{
const char *chunk_data = m_stream.get (8);
if (! chunk_data) {
throw UnexpectedEndOfFileException (source ());
}
// TODO: for now, we assume that file and memory layout are identical on all platforms
v = *reinterpret_cast<const int64_t *> (chunk_data);
return *this;
}
BinaryInputStream &
BinaryInputStream::operator>> (tl::Variant &v)
{
int16_t var_type = -1;
*this >> var_type;
switch (var_type) {
case VariantTypeCode::var_type_nil:
v = tl::Variant ();
break;
case VariantTypeCode::var_type_bool:
{
bool f = false;
*this >> f;
v = tl::Variant (f);
}
break;
case VariantTypeCode::var_type_char:
{
uint8_t vv = 0;
*this >> vv;
v = tl::Variant ((char) vv);
}
break;
case VariantTypeCode::var_type_schar:
{
int8_t vv = 0;
*this >> vv;
v = tl::Variant ((signed char) vv);
}
break;
case VariantTypeCode::var_type_uchar:
{
uint8_t vv = 0;
*this >> vv;
v = tl::Variant ((unsigned char) vv);
}
break;
case VariantTypeCode::var_type_short:
{
int16_t vv = 0;
*this >> vv;
v = tl::Variant ((short) vv);
}
break;
case VariantTypeCode::var_type_ushort:
{
uint16_t vv = 0;
*this >> vv;
v = tl::Variant ((unsigned short) vv);
}
break;
case VariantTypeCode::var_type_int:
{
int32_t vv = 0;
*this >> vv;
v = tl::Variant ((int) vv);
}
break;
case VariantTypeCode::var_type_uint:
{
uint32_t vv = 0;
*this >> vv;
v = tl::Variant ((unsigned int) vv);
}
break;
case VariantTypeCode::var_type_long:
{
int64_t vv = 0;
*this >> vv;
if (vv >= (int64_t) std::numeric_limits<long>::min () && vv <= (int64_t) std::numeric_limits<long>::max ()) {
v = tl::Variant ((long) vv);
} else {
// Linux to Windows migration
v = tl::Variant ((long long) vv);
}
}
break;
case VariantTypeCode::var_type_ulong:
{
uint64_t vv = 0;
*this >> vv;
if (vv >= (uint64_t) std::numeric_limits<unsigned long>::min () && vv <= (uint64_t) std::numeric_limits<unsigned long>::max ()) {
v = tl::Variant ((unsigned long) vv);
} else {
// Linux to Windows migration
v = tl::Variant ((unsigned long long) vv);
}
}
break;
break;
case VariantTypeCode::var_type_longlong:
{
int64_t vv = 0;
*this >> vv;
v = tl::Variant ((long long) vv);
}
break;
case VariantTypeCode::var_type_ulonglong:
{
uint64_t vv = 0;
*this >> vv;
v = tl::Variant ((unsigned long long) vv);
}
break;
case VariantTypeCode::var_type_id:
{
uint64_t vv = 0;
*this >> vv;
v = tl::Variant ((size_t) vv, true /*as id*/);
}
break;
case VariantTypeCode::var_type_float:
{
float vv = 0;
*this >> vv;
v = tl::Variant (vv);
}
break;
case VariantTypeCode::var_type_double:
{
double vv = 0;
*this >> vv;
v = tl::Variant (vv);
}
break;
case VariantTypeCode::var_type_string:
{
std::string vv;
*this >> vv;
v = tl::Variant (std::move (vv));
}
break;
case VariantTypeCode::var_type_bytes:
{
std::vector<char> vv;
*this >> vv;
v = tl::Variant (std::move (vv));
}
break;
case VariantTypeCode::var_type_list:
{
uint64_t n = 0;
*this >> n;
v = tl::Variant::empty_list ();
v.reserve (n);
while (n-- > 0) {
tl::Variant vv;
*this >> vv;
v.push (std::move (vv));
}
}
break;
case VariantTypeCode::var_type_array:
{
uint64_t n = 0;
*this >> n;
v = tl::Variant::empty_array ();
while (n-- > 0) {
tl::Variant vk, vv;
*this >> vk;
*this >> vv;
v.insert (std::move (vk), std::move (vv));
}
}
break;
case VariantTypeCode::var_type_other:
{
std::string s;
*this >> s;
tl::Extractor ex (s.c_str ());
v = tl::Variant ();
ex.read (v);
}
break;
default:
throw InvalidVariantTypeCode (source (), int (var_type));
}
return *this;
}
// ---------------------------------------------------------------
// BinaryOutputStream implementation
BinaryOutputStream::BinaryOutputStream (OutputStreamBase &delegate)
: OutputStream (delegate, false)
{
// .. nothing yet ..
}
BinaryOutputStream::BinaryOutputStream (OutputStreamBase *delegate)
: OutputStream (delegate, false)
{
// .. nothing yet ..
}
BinaryOutputStream::BinaryOutputStream (const std::string &abstract_path, OutputStreamMode om, int keep_backups)
: OutputStream (abstract_path, om, false, keep_backups)
{
// .. nothing yet ..
}
void
BinaryOutputStream::put_native (const char *s, size_t n)
{
// the native format for a string is a length field (uint64_t) and the bytes
// TODO: for now we assume that the memory layout is the same for all platforms
uint64_t len = uint64_t (n);
put_raw ((const char *) &len, 8);
put_raw (s, n);
}
void
BinaryOutputStream::put_native (const std::string &s)
{
// the native format for a string is a length field (uint64_t) and the bytes
// TODO: for now we assume that the memory layout is the same for all platforms
uint64_t len = uint64_t (s.size ());
put_raw ((const char *) &len, 8);
put_raw (s.c_str (), s.size ());
}
void
BinaryOutputStream::put_native (double v)
{
// TODO: for now we assume that the memory layout is the same for all platforms
put_raw ((const char *) &v, 8);
}
void
BinaryOutputStream::put_native (float v)
{
// TODO: for now we assume that the memory layout is the same for all platforms
put_raw ((const char *) &v, 4);
}
void
BinaryOutputStream::put_native (bool v)
{
char c = v ? 1 : 0;
put_raw (&c, 1);
}
void
BinaryOutputStream::put_native (uint8_t v)
{
put_raw ((const char *) &v, 1);
}
void
BinaryOutputStream::put_native (int8_t v)
{
put_raw ((const char *) &v, 1);
}
void
BinaryOutputStream::put_native (uint16_t v)
{
// TODO: for now we assume that the memory layout is the same for all platforms
put_raw ((const char *) &v, 2);
}
void
BinaryOutputStream::put_native (int16_t v)
{
// TODO: for now we assume that the memory layout is the same for all platforms
put_raw ((const char *) &v, 2);
}
void
BinaryOutputStream::put_native (uint32_t v)
{
// TODO: for now we assume that the memory layout is the same for all platforms
put_raw ((const char *) &v, 4);
}
void
BinaryOutputStream::put_native (int32_t v)
{
// TODO: for now we assume that the memory layout is the same for all platforms
put_raw ((const char *) &v, 4);
}
void
BinaryOutputStream::put_native (uint64_t v)
{
// TODO: for now we assume that the memory layout is the same for all platforms
put_raw ((const char *) &v, 8);
}
void
BinaryOutputStream::put_native (int64_t v)
{
// TODO: for now we assume that the memory layout is the same for all platforms
put_raw ((const char *) &v, 8);
}
void
BinaryOutputStream::put_native (const tl::Variant &v)
{
switch (v.type_code ()) {
case tl::Variant::t_nil:
put_native ((int16_t) VariantTypeCode::var_type_nil);
break;
case tl::Variant::t_bool:
put_native ((int16_t) VariantTypeCode::var_type_bool);
put_native (v.to_bool ());
break;
case tl::Variant::t_char:
put_native ((int16_t) VariantTypeCode::var_type_char);
put_native ((uint8_t) v.to_char ());
break;
case tl::Variant::t_schar:
put_native ((int16_t) VariantTypeCode::var_type_schar);
put_native ((int8_t) v.to_schar ());
break;
case tl::Variant::t_uchar:
put_native ((int16_t) VariantTypeCode::var_type_uchar);
put_native ((uint8_t) v.to_uchar ());
break;
case tl::Variant::t_short:
put_native ((int16_t) VariantTypeCode::var_type_short);
put_native ((int16_t) v.to_short ());
break;
case tl::Variant::t_ushort:
put_native ((int16_t) VariantTypeCode::var_type_ushort);
put_native ((uint16_t) v.to_ushort ());
break;
case tl::Variant::t_int:
put_native ((int16_t) VariantTypeCode::var_type_int);
put_native ((int32_t) v.to_int ());
break;
case tl::Variant::t_uint:
put_native ((int16_t) VariantTypeCode::var_type_uint);
put_native ((uint32_t) v.to_uint ());
break;
case tl::Variant::t_long:
put_native ((int16_t) VariantTypeCode::var_type_long);
// NOTE: "long" is always encoded as 64 bit for compatibility of Windows + Linux
put_native ((int64_t) v.to_long ());
break;
case tl::Variant::t_ulong:
put_native ((int16_t) VariantTypeCode::var_type_ulong);
// NOTE: "ulong" is always encoded as 64 bit for compatibility of Windows + Linux
put_native ((uint64_t) v.to_ulong ());
break;
case tl::Variant::t_longlong:
put_native ((int16_t) VariantTypeCode::var_type_longlong);
put_native ((int64_t) v.to_longlong ());
break;
case tl::Variant::t_ulonglong:
put_native ((int16_t) VariantTypeCode::var_type_ulonglong);
put_native ((uint64_t) v.to_ulonglong ());
break;
case tl::Variant::t_id:
put_native ((int16_t) VariantTypeCode::var_type_id);
// NOTE: "id" is always encoded as 64 bit
put_native ((uint64_t) v.to_id ());
break;
case tl::Variant::t_float:
put_native ((int16_t) VariantTypeCode::var_type_float);
put_native (v.to_float ());
break;
case tl::Variant::t_double:
put_native ((int16_t) VariantTypeCode::var_type_double);
put_native (v.to_double ());
break;
case tl::Variant::t_string:
case tl::Variant::t_stdstring:
put_native ((int16_t) VariantTypeCode::var_type_string);
put_native (v.to_stdstring ());
break;
case tl::Variant::t_bytearray:
#if defined(HAVE_QT)
case tl::Variant::t_qstring:
case tl::Variant::t_qbytearray:
#endif
{
put_native ((int16_t) VariantTypeCode::var_type_bytes);
std::vector<char> bytes = v.to_bytearray ();
put_native (bytes.begin ().operator-> (), bytes.size ());
}
break;
case tl::Variant::t_list:
{
put_native ((int16_t) VariantTypeCode::var_type_list);
put_native ((uint64_t) v.size ());
for (auto i = v.begin (); i != v.end (); ++i) {
put_native (*i);
}
}
break;
case tl::Variant::t_array:
{
put_native ((int16_t) VariantTypeCode::var_type_array);
put_native ((uint64_t) v.array_size ());
for (auto i = v.begin_array (); i != v.end_array (); ++i) {
put_native (i->first);
put_native (i->second);
}
}
break;
default:
put_native ((int16_t) VariantTypeCode::var_type_other);
put_native (v.to_parsable_string ());
break;
}
}
}

View File

@ -0,0 +1,207 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2026 Matthias Koefferlein
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef HDR_tlBinaryStream
#define HDR_tlBinaryStream
#include "tlCommon.h"
#include "tlStream.h"
#include "tlVariant.h"
namespace tl
{
// ---------------------------------------------------------------------------------
/**
* @brief An output stream specialized on binary representation
*/
class TL_PUBLIC BinaryOutputStream
: public OutputStream
{
public:
/**
* @brief Default constructor
*
* This constructor takes a delegate object.
*/
BinaryOutputStream (OutputStreamBase &delegate);
/**
* @brief Default constructor
*
* This constructor takes a delegate object. The stream will own the delegate.
*/
BinaryOutputStream (OutputStreamBase *delegate);
/**
* @brief Open an output stream with the given path and stream mode
*
* This will automatically create a delegate object and delete it later.
*/
BinaryOutputStream (const std::string &abstract_path, OutputStreamMode om = OM_Auto, int keep_backups = 0);
/**
* @brief << operator: inserts character
*/
OutputStream &operator<< (char s)
{
put (&s, 1);
return *this;
}
/**
* @brief << operator: inserts a character
*/
OutputStream &operator<< (unsigned char s)
{
put ((const char *) &s, 1);
return *this;
}
/**
* @brief << operator: inserts a string
*
* In binary mode, the string is inserted as a length/data
* combination. That matches the extraction in BinaryInputStream.
*/
BinaryOutputStream &operator<< (const char *s)
{
put_native (s, strlen (s));
return *this;
}
/**
* @brief << operator: inserts a string
*
* In binary mode, the string is inserted as a length/data
* combination. That matches the extraction in BinaryInputStream.
*/
BinaryOutputStream &operator<< (const std::string &s)
{
put_native (s);
return *this;
}
/**
* @brief << operator: inserts an object supported by "put_native".
*/
template <class T>
BinaryOutputStream &operator<< (const T &t)
{
put_native (t);
return *this;
}
private:
void put_native (const std::string &s);
void put_native (const char *s, size_t n);
void put_native (double v);
void put_native (float v);
void put_native (bool v);
void put_native (uint8_t v);
void put_native (int8_t v);
void put_native (uint16_t v);
void put_native (int16_t v);
void put_native (uint32_t v);
void put_native (int32_t v);
void put_native (uint64_t v);
void put_native (int64_t v);
void put_native (const tl::Variant &v);
void set_as_text (bool f);
// No copying currently
BinaryOutputStream (const BinaryOutputStream &);
BinaryOutputStream &operator= (const BinaryOutputStream &);
};
// ---------------------------------------------------------------------------------
/**
* @brief A binary input stream
*
* This class is put in front of a InputStream to retrieve binary primitives from the stream.
* The binary format corresponds to binary mode of OutputStream.
*/
class TL_PUBLIC BinaryInputStream
{
public:
/**
* @brief Default constructor
*
* This constructor takes a delegate object.
*/
BinaryInputStream (InputStream &stream);
/**
* @brief Gets the raw stream
*/
InputStream &raw_stream ()
{
return m_stream;
}
/**
* @brief Get the source specification
*/
std::string source () const
{
return m_stream.source ();
}
/**
* @brief Gets a value of a specific type
*/
BinaryInputStream &operator>> (std::string &v);
BinaryInputStream &operator>> (std::vector<char> &v);
BinaryInputStream &operator>> (double &v);
BinaryInputStream &operator>> (float &v);
BinaryInputStream &operator>> (bool &v);
BinaryInputStream &operator>> (uint8_t &v);
BinaryInputStream &operator>> (int8_t &v);
BinaryInputStream &operator>> (uint16_t &v);
BinaryInputStream &operator>> (int16_t &v);
BinaryInputStream &operator>> (uint32_t &v);
BinaryInputStream &operator>> (int32_t &v);
BinaryInputStream &operator>> (uint64_t &v);
BinaryInputStream &operator>> (int64_t &v);
BinaryInputStream &operator>> (tl::Variant &v);
/**
* @brief Resets to the initial position
*/
void reset ();
private:
InputStream &m_stream;
// no copying
BinaryInputStream (const BinaryInputStream &);
BinaryInputStream &operator= (const BinaryInputStream &);
};
}
#endif

View File

@ -20,8 +20,6 @@
*/
#include <stddef.h>
#include <ctype.h>
#include <fcntl.h>
@ -133,15 +131,6 @@ public:
{ }
};
class UnexpectedEndOfFileException
: public tl::Exception
{
public:
UnexpectedEndOfFileException (const std::string &f)
: tl::Exception (tl::to_string (tr ("Unexpected end of file: %s")), f)
{ }
};
// ---------------------------------------------------------------
class ZLibFilePrivate
@ -929,183 +918,6 @@ TextInputStream::reset ()
}
}
// ---------------------------------------------------------------
BinaryInputStream::BinaryInputStream (InputStream &stream)
: m_stream (stream)
{
// .. nothing yet ..
}
void
BinaryInputStream::reset ()
{
m_stream.reset ();
}
BinaryInputStream &
BinaryInputStream::operator>> (std::string &v)
{
uint64_t l = 0;
*this >> l;
v.clear ();
v.reserve (l);
size_t chunk_size = 1024, n = l;
while (n > 0) {
size_t chunk_len = std::min (n, chunk_size);
const char *chunk_data = m_stream.get (chunk_len);
if (! chunk_data) {
throw UnexpectedEndOfFileException (source ());
}
v.append (chunk_data, chunk_len);
n -= chunk_len;
}
return *this;
}
BinaryInputStream &
BinaryInputStream::operator>> (double &v)
{
const char *chunk_data = m_stream.get (8);
if (! chunk_data) {
throw UnexpectedEndOfFileException (source ());
}
// TODO: for now, we assume that file and memory layout are identical on all platforms
v = *reinterpret_cast<const double *> (chunk_data);
return *this;
}
BinaryInputStream &
BinaryInputStream::operator>> (float &v)
{
const char *chunk_data = m_stream.get (4);
if (! chunk_data) {
throw UnexpectedEndOfFileException (source ());
}
// TODO: for now, we assume that file and memory layout are identical on all platforms
v = *reinterpret_cast<const float *> (chunk_data);
return *this;
}
BinaryInputStream &
BinaryInputStream::operator>> (bool &v)
{
const char *chunk_data = m_stream.get (1);
if (! chunk_data) {
throw UnexpectedEndOfFileException (source ());
}
v = *chunk_data != 0;
return *this;
}
BinaryInputStream &
BinaryInputStream::operator>> (uint8_t &v)
{
const char *chunk_data = m_stream.get (1);
if (! chunk_data) {
throw UnexpectedEndOfFileException (source ());
}
v = (uint8_t) *chunk_data;
return *this;
}
BinaryInputStream &
BinaryInputStream::operator>> (int8_t &v)
{
const char *chunk_data = m_stream.get (1);
if (! chunk_data) {
throw UnexpectedEndOfFileException (source ());
}
v = (int8_t) *chunk_data;
return *this;
}
BinaryInputStream &
BinaryInputStream::operator>> (uint16_t &v)
{
const char *chunk_data = m_stream.get (2);
if (! chunk_data) {
throw UnexpectedEndOfFileException (source ());
}
// TODO: for now, we assume that file and memory layout are identical on all platforms
v = *reinterpret_cast<const uint16_t *> (chunk_data);
return *this;
}
BinaryInputStream &
BinaryInputStream::operator>> (int16_t &v)
{
const char *chunk_data = m_stream.get (2);
if (! chunk_data) {
throw UnexpectedEndOfFileException (source ());
}
// TODO: for now, we assume that file and memory layout are identical on all platforms
v = *reinterpret_cast<const int16_t *> (chunk_data);
return *this;
}
BinaryInputStream &
BinaryInputStream::operator>> (uint32_t &v)
{
const char *chunk_data = m_stream.get (4);
if (! chunk_data) {
throw UnexpectedEndOfFileException (source ());
}
// TODO: for now, we assume that file and memory layout are identical on all platforms
v = *reinterpret_cast<const uint32_t *> (chunk_data);
return *this;
}
BinaryInputStream &
BinaryInputStream::operator>> (int32_t &v)
{
const char *chunk_data = m_stream.get (4);
if (! chunk_data) {
throw UnexpectedEndOfFileException (source ());
}
// TODO: for now, we assume that file and memory layout are identical on all platforms
v = *reinterpret_cast<const int32_t *> (chunk_data);
return *this;
}
BinaryInputStream &
BinaryInputStream::operator>> (uint64_t &v)
{
const char *chunk_data = m_stream.get (8);
if (! chunk_data) {
throw UnexpectedEndOfFileException (source ());
}
// TODO: for now, we assume that file and memory layout are identical on all platforms
v = *reinterpret_cast<const uint64_t *> (chunk_data);
return *this;
}
BinaryInputStream &
BinaryInputStream::operator>> (int64_t &v)
{
const char *chunk_data = m_stream.get (8);
if (! chunk_data) {
throw UnexpectedEndOfFileException (source ());
}
// TODO: for now, we assume that file and memory layout are identical on all platforms
v = *reinterpret_cast<const int64_t *> (chunk_data);
return *this;
}
// ---------------------------------------------------------------
// InputFile implementation
@ -1479,122 +1291,6 @@ OutputStream::seek (size_t pos)
m_pos = pos;
}
// ---------------------------------------------------------------
// BinaryOutputStream implementation
BinaryOutputStream::BinaryOutputStream (OutputStreamBase &delegate)
: OutputStream (delegate, false)
{
// .. nothing yet ..
}
BinaryOutputStream::BinaryOutputStream (OutputStreamBase *delegate)
: OutputStream (delegate, false)
{
// .. nothing yet ..
}
BinaryOutputStream::BinaryOutputStream (const std::string &abstract_path, OutputStreamMode om, int keep_backups)
: OutputStream (abstract_path, om, false, keep_backups)
{
// .. nothing yet ..
}
void
BinaryOutputStream::put_native (const char *s, size_t n)
{
// the native format for a string is a length field (uint64_t) and the bytes
// TODO: for now we assume that the memory layout is the same for all platforms
uint64_t len = uint64_t (n);
put_raw ((const char *) &len, 8);
put_raw (s, n);
}
void
BinaryOutputStream::put_native (const std::string &s)
{
// the native format for a string is a length field (uint64_t) and the bytes
// TODO: for now we assume that the memory layout is the same for all platforms
uint64_t len = uint64_t (s.size ());
put_raw ((const char *) &len, 8);
put_raw (s.c_str (), s.size ());
}
void
BinaryOutputStream::put_native (double v)
{
// TODO: for now we assume that the memory layout is the same for all platforms
put_raw ((const char *) &v, 8);
}
void
BinaryOutputStream::put_native (float v)
{
// TODO: for now we assume that the memory layout is the same for all platforms
put_raw ((const char *) &v, 4);
}
void
BinaryOutputStream::put_native (bool v)
{
char c = v ? 1 : 0;
put_raw (&c, 1);
}
void
BinaryOutputStream::put_native (uint8_t v)
{
put_raw ((const char *) &v, 1);
}
void
BinaryOutputStream::put_native (int8_t v)
{
put_raw ((const char *) &v, 1);
}
void
BinaryOutputStream::put_native (uint16_t v)
{
// TODO: for now we assume that the memory layout is the same for all platforms
put_raw ((const char *) &v, 2);
}
void
BinaryOutputStream::put_native (int16_t v)
{
// TODO: for now we assume that the memory layout is the same for all platforms
put_raw ((const char *) &v, 2);
}
void
BinaryOutputStream::put_native (uint32_t v)
{
// TODO: for now we assume that the memory layout is the same for all platforms
put_raw ((const char *) &v, 4);
}
void
BinaryOutputStream::put_native (int32_t v)
{
// TODO: for now we assume that the memory layout is the same for all platforms
put_raw ((const char *) &v, 4);
}
void
BinaryOutputStream::put_native (uint64_t v)
{
// TODO: for now we assume that the memory layout is the same for all platforms
put_raw ((const char *) &v, 8);
}
void
BinaryOutputStream::put_native (int64_t v)
{
// TODO: for now we assume that the memory layout is the same for all platforms
put_raw ((const char *) &v, 8);
}
// ---------------------------------------------------------------
// OutputFileBase implementation

View File

@ -805,69 +805,6 @@ private:
// ---------------------------------------------------------------------------------
/**
* @brief A binary input stream
*
* This class is put in front of a InputStream to retrieve binary primitives from the stream.
* The binary format corresponds to binary mode of OutputStream.
*/
class TL_PUBLIC BinaryInputStream
{
public:
/**
* @brief Default constructor
*
* This constructor takes a delegate object.
*/
BinaryInputStream (InputStream &stream);
/**
* @brief Gets the raw stream
*/
InputStream &raw_stream ()
{
return m_stream;
}
/**
* @brief Get the source specification
*/
std::string source () const
{
return m_stream.source ();
}
/**
* @brief Gets a value of a specific type
*/
BinaryInputStream &operator>> (std::string &v);
BinaryInputStream &operator>> (double &v);
BinaryInputStream &operator>> (float &v);
BinaryInputStream &operator>> (bool &v);
BinaryInputStream &operator>> (uint8_t &v);
BinaryInputStream &operator>> (int8_t &v);
BinaryInputStream &operator>> (uint16_t &v);
BinaryInputStream &operator>> (int16_t &v);
BinaryInputStream &operator>> (uint32_t &v);
BinaryInputStream &operator>> (int32_t &v);
BinaryInputStream &operator>> (uint64_t &v);
BinaryInputStream &operator>> (int64_t &v);
/**
* @brief Resets to the initial position
*/
void reset ();
private:
InputStream &m_stream;
// no copying
BinaryInputStream (const BinaryInputStream &);
BinaryInputStream &operator= (const BinaryInputStream &);
};
// ---------------------------------------------------------------------------------
/**
* @brief The output stream delegate base class
*
@ -1537,111 +1474,6 @@ private:
OutputStream &operator= (const OutputStream &);
};
// ---------------------------------------------------------------------------------
/**
* @brief An output stream specialized on binary representation
*/
class TL_PUBLIC BinaryOutputStream
: public OutputStream
{
public:
/**
* @brief Default constructor
*
* This constructor takes a delegate object.
*/
BinaryOutputStream (OutputStreamBase &delegate);
/**
* @brief Default constructor
*
* This constructor takes a delegate object. The stream will own the delegate.
*/
BinaryOutputStream (OutputStreamBase *delegate);
/**
* @brief Open an output stream with the given path and stream mode
*
* This will automatically create a delegate object and delete it later.
*/
BinaryOutputStream (const std::string &abstract_path, OutputStreamMode om = OM_Auto, int keep_backups = 0);
/**
* @brief << operator: inserts character
*/
OutputStream &operator<< (char s)
{
put (&s, 1);
return *this;
}
/**
* @brief << operator: inserts a character
*/
OutputStream &operator<< (unsigned char s)
{
put ((const char *) &s, 1);
return *this;
}
/**
* @brief << operator: inserts a string
*
* In binary mode, the string is inserted as a length/data
* combination. That matches the extraction in BinaryInputStream.
*/
BinaryOutputStream &operator<< (const char *s)
{
put_native (s, strlen (s));
return *this;
}
/**
* @brief << operator: inserts a string
*
* In binary mode, the string is inserted as a length/data
* combination. That matches the extraction in BinaryInputStream.
*/
BinaryOutputStream &operator<< (const std::string &s)
{
put_native (s);
return *this;
}
/**
* @brief << operator: inserts an object supported by "put_native".
*/
template <class T>
BinaryOutputStream &operator<< (const T &t)
{
put_native (t);
return *this;
}
private:
void put_native (const std::string &s);
void put_native (const char *s, size_t n);
void put_native (double v);
void put_native (float v);
void put_native (bool v);
void put_native (uint8_t v);
void put_native (int8_t v);
void put_native (uint16_t v);
void put_native (int16_t v);
void put_native (uint32_t v);
void put_native (int32_t v);
void put_native (uint64_t v);
void put_native (int64_t v);
void set_as_text (bool f);
// No copying currently
BinaryOutputStream (const BinaryOutputStream &);
BinaryOutputStream &operator= (const BinaryOutputStream &);
};
}
#endif

View File

@ -651,7 +651,7 @@ to_quoted_string (const std::string &s)
std::string r;
r.reserve (s.size () + 2);
r += '\'';
for (const char *c = s.c_str (); *c; ++c) {
for (auto c = s.begin (); c != s.end (); ++c) {
if (*c == '\'' || *c == '\\') {
r += '\\';
r += *c;

View File

@ -315,6 +315,12 @@ Variant::Variant (const std::vector<char> &ba)
m_var.m_bytearray = new std::vector<char> (ba);
}
Variant::Variant (std::vector<char> &&ba)
: m_type (t_bytearray), m_string (0)
{
m_var.m_bytearray = new std::vector<char> (ba);
}
#if defined(HAVE_QT)
Variant::Variant (const QByteArray &qba)
@ -530,6 +536,12 @@ Variant::Variant (const std::string &s)
m_var.m_stdstring = new std::string (s);
}
Variant::Variant (std::string &&s)
: m_type (t_stdstring), m_string (0)
{
m_var.m_stdstring = new std::string (s);
}
Variant::Variant (const char *s)
: m_type (s != 0 ? t_string : t_nil)
{
@ -645,6 +657,12 @@ Variant::Variant (const Variant &v)
operator= (v);
}
Variant::Variant (Variant &&v)
: m_type (t_nil), m_string (0)
{
swap (v);
}
Variant::~Variant ()
{
reset ();
@ -713,6 +731,20 @@ Variant::operator= (const std::string &s)
return *this;
}
Variant &
Variant::operator= (std::string &&s)
{
if (m_type == t_stdstring && &s == m_var.m_stdstring) {
// we are assigning to ourselves
} else {
std::string *snew = new std::string (s);
reset ();
m_type = t_stdstring;
m_var.m_stdstring = snew;
}
return *this;
}
Variant &
Variant::operator= (const std::vector<char> &s)
{
@ -727,6 +759,20 @@ Variant::operator= (const std::vector<char> &s)
return *this;
}
Variant &
Variant::operator= (std::vector<char> &&s)
{
if (m_type == t_bytearray && &s == m_var.m_bytearray) {
// we are assigning to ourselves
} else {
std::vector<char> *snew = new std::vector<char> (s);
reset ();
m_type = t_bytearray;
m_var.m_bytearray = snew;
}
return *this;
}
#if defined(HAVE_QT)
Variant &
@ -900,6 +946,13 @@ Variant::operator= (__int128 l)
}
#endif
Variant &
Variant::operator= (Variant &&v)
{
swap (v);
return *this;
}
Variant &
Variant::operator= (const Variant &v)
{
@ -1958,7 +2011,7 @@ Variant::to_string () const
} else if (m_type == t_float) {
r = tl::to_string (m_var.m_float, 7);
} else if (m_type == t_char) {
r = tl::to_string ((int) m_var.m_char);
r += m_var.m_char;
} else if (m_type == t_schar) {
r = tl::to_string ((int) m_var.m_schar);
} else if (m_type == t_uchar) {
@ -2602,12 +2655,10 @@ Variant::to_parsable_string () const
return "nil";
} else if (is_stdstring ()) {
return tl::to_quoted_string (*m_var.m_stdstring);
#if defined(HAVE_QT)
} else if (is_cstring () || is_qstring () || is_qbytearray () || is_bytearray ()) {
#else
} else if (is_cstring () || is_bytearray ()) {
#endif
return tl::to_quoted_string (to_string ());
} else if (is_a_string ()) {
return tl::to_quoted_string (to_stdstring ());
} else if (is_a_bytearray ()) {
return tl::to_quoted_string (to_stdstring ()) + "b";
} else if (is_list ()) {
std::string r = "(";
for (tl::Variant::const_iterator l = begin (); l != end (); ++l) {
@ -2630,6 +2681,10 @@ Variant::to_parsable_string () const
}
r += "}";
return r;
} else if (is_char ()) {
std::string s;
s += to_char ();
return tl::to_quoted_string (s) + "c";
} else if (is_id ()) {
return "[id" + tl::to_string (m_var.m_id) + "]";
} else if (is_user ()) {
@ -3049,7 +3104,15 @@ TL_PUBLIC bool test_extractor_impl (tl::Extractor &ex, tl::Variant &v)
} else if (ex.try_read_word_or_quoted (s)) {
v = tl::Variant (s);
if (ex.test ("c") || ex.test ("C")) {
v = s.empty () ? tl::Variant () : tl::Variant ((char) s.front ());
} else if (ex.test ("b") || ex.test ("B")) {
std::vector<char> cv (s.begin (), s.end ());
v = tl::Variant (std::move (cv));
} else {
v = tl::Variant (s);
}
return true;
} else {

View File

@ -205,11 +205,21 @@ public:
*/
Variant (const tl::Variant &d);
/**
* @brief Move ctor
*/
Variant (tl::Variant &&d);
/**
* @brief Initialize the Variant with a std::vector<char>
*/
Variant (const std::vector<char> &s);
/**
* @brief Initialize the Variant with a std::vector<char> (move semantics)
*/
Variant (std::vector<char> &&s);
#if defined(HAVE_QT)
/**
* @brief Initialize the Variant with a QByteArray
@ -234,6 +244,11 @@ public:
*/
Variant (const std::string &s);
/**
* @brief Initialize the Variant with "string" (move semantics)
*/
Variant (std::string &&s);
/**
* @brief Initialize the Variant with "string"
*/
@ -466,6 +481,15 @@ public:
m_var.m_list = new std::vector<tl::Variant> (list);
}
/**
* @brief Initialize the Variant with an explicit vector of variants (move semantics)
*/
Variant (std::vector<tl::Variant> &&list)
: m_type (t_list), m_string (0)
{
m_var.m_list = new std::vector<tl::Variant> (list);
}
/**
* @brief Initialize the Variant with an explicit map of variants
*/
@ -475,6 +499,15 @@ public:
m_var.m_array = new std::map<tl::Variant, tl::Variant> (map);
}
/**
* @brief Initialize the Variant with an explicit map of variants (move semantics)
*/
Variant (std::map<tl::Variant, tl::Variant> &&map)
: m_type (t_array), m_string (0)
{
m_var.m_array = new std::map<tl::Variant, tl::Variant> (map);
}
/**
* @brief Initialize the Variant with a list
*/
@ -546,6 +579,11 @@ public:
*/
Variant &operator= (const Variant &v);
/**
* @brief Assignment (move)
*/
Variant &operator= (Variant &&v);
/**
* @brief Assignment of a string
*/
@ -568,11 +606,21 @@ public:
*/
Variant &operator= (const std::string &v);
/**
* @brief Assignment of a string (move)
*/
Variant &operator= (std::string &&v);
/**
* @brief Assignment of a STL byte array
*/
Variant &operator= (const std::vector<char> &v);
/**
* @brief Assignment of a STL byte array (move)
*/
Variant &operator= (std::vector<char> &&v);
/**
* @brief Assignment of a double
*/
@ -1173,6 +1221,15 @@ public:
m_var.m_list->push_back (v);
}
/**
* @brief Add a element to the list (move semantics)
*/
void push (tl::Variant &&v)
{
tl_assert (m_type == t_list);
m_var.m_list->push_back (v);
}
/**
* @brief Get the back element of the list
*/
@ -1280,6 +1337,15 @@ public:
m_var.m_array->insert (std::make_pair (k, v));
}
/**
* @brief Insert an element into the array (move semantics)
*/
void insert (tl::Variant &&k, tl::Variant &&v)
{
tl_assert (m_type == t_array);
m_var.m_array->insert (std::make_pair (k, v));
}
/**
* @brief Returns the value for the given key or 0 if the variant is not an array or does not contain the key
*/

View File

@ -0,0 +1,425 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2026 Matthias Koefferlein
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "tlBinaryStream.h"
#include "tlUnitTest.h"
std::string s2string (tl::OutputMemoryStream &osm)
{
std::string res;
size_t n = osm.size ();
const char *d = osm.data ();
for (size_t i = 0; i < n; ++i, ++d) {
if (i > 0) {
res += ",";
}
res += tl::sprintf ("0x%02x", int ((unsigned char) *d));
}
return res;
}
TEST(BinaryStreams1)
{
tl::OutputMemoryStream osm;
tl::BinaryOutputStream os (osm);
os << (double) 0.17;
os.flush ();
EXPECT_EQ (s2string (osm), "0xc3,0xf5,0x28,0x5c,0x8f,0xc2,0xc5,0x3f");
tl::InputMemoryStream ism (osm.data (), osm.size ());
tl::InputStream is (ism);
tl::BinaryInputStream bis (is);
double x = 0.0;
bis >> x;
EXPECT_EQ (tl::to_string (x), "0.17");
}
TEST(BinaryStreams2)
{
tl::OutputMemoryStream osm;
tl::BinaryOutputStream os (osm);
os << (float) 0.17;
os.flush ();
EXPECT_EQ (s2string (osm), "0x7b,0x14,0x2e,0x3e");
tl::InputMemoryStream ism (osm.data (), osm.size ());
tl::InputStream is (ism);
tl::BinaryInputStream bis (is);
float x = 0.0;
bis >> x;
EXPECT_EQ (tl::to_string (x), "0.17");
}
TEST(BinaryStreams3)
{
tl::OutputMemoryStream osm;
tl::BinaryOutputStream os (osm);
os << std::string ("ABC");
os.flush ();
EXPECT_EQ (s2string (osm), "0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x41,0x42,0x43");
tl::InputMemoryStream ism (osm.data (), osm.size ());
tl::InputStream is (ism);
tl::BinaryInputStream bis (is);
std::string x;
bis >> x;
EXPECT_EQ (x, "ABC");
}
TEST(BinaryStreams4)
{
tl::OutputMemoryStream osm;
tl::BinaryOutputStream os (osm);
os << "ABC";
os.flush ();
EXPECT_EQ (s2string (osm), "0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x41,0x42,0x43");
tl::InputMemoryStream ism (osm.data (), osm.size ());
tl::InputStream is (ism);
tl::BinaryInputStream bis (is);
std::string x;
bis >> x;
EXPECT_EQ (x, "ABC");
}
TEST(BinaryStreams5)
{
tl::OutputMemoryStream osm;
tl::BinaryOutputStream os (osm);
os << uint8_t (17);
os.flush ();
EXPECT_EQ (s2string (osm), "0x11");
tl::InputMemoryStream ism (osm.data (), osm.size ());
tl::InputStream is (ism);
tl::BinaryInputStream bis (is);
uint8_t x;
bis >> x;
EXPECT_EQ (x, 17);
}
TEST(BinaryStreams6)
{
tl::OutputMemoryStream osm;
tl::BinaryOutputStream os (osm);
os << int8_t (17);
os.flush ();
EXPECT_EQ (s2string (osm), "0x11");
tl::InputMemoryStream ism (osm.data (), osm.size ());
tl::InputStream is (ism);
tl::BinaryInputStream bis (is);
int8_t x;
bis >> x;
EXPECT_EQ (x, 17);
}
TEST(BinaryStreams7)
{
tl::OutputMemoryStream osm;
tl::BinaryOutputStream os (osm);
os << uint16_t (1742);
os.flush ();
EXPECT_EQ (s2string (osm), "0xce,0x06");
tl::InputMemoryStream ism (osm.data (), osm.size ());
tl::InputStream is (ism);
tl::BinaryInputStream bis (is);
uint16_t x;
bis >> x;
EXPECT_EQ (x, 1742);
}
TEST(BinaryStreams8)
{
tl::OutputMemoryStream osm;
tl::BinaryOutputStream os (osm);
os << int16_t (1742);
os.flush ();
EXPECT_EQ (s2string (osm), "0xce,0x06");
tl::InputMemoryStream ism (osm.data (), osm.size ());
tl::InputStream is (ism);
tl::BinaryInputStream bis (is);
int16_t x;
bis >> x;
EXPECT_EQ (x, 1742);
}
TEST(BinaryStreams9)
{
tl::OutputMemoryStream osm;
tl::BinaryOutputStream os (osm);
os << uint32_t (17420000);
os.flush ();
EXPECT_EQ (s2string (osm), "0xe0,0xce,0x09,0x01");
tl::InputMemoryStream ism (osm.data (), osm.size ());
tl::InputStream is (ism);
tl::BinaryInputStream bis (is);
uint32_t x;
bis >> x;
EXPECT_EQ (x, 17420000u);
}
TEST(BinaryStreams10)
{
tl::OutputMemoryStream osm;
tl::BinaryOutputStream os (osm);
os << int32_t (17420000);
os.flush ();
EXPECT_EQ (s2string (osm), "0xe0,0xce,0x09,0x01");
tl::InputMemoryStream ism (osm.data (), osm.size ());
tl::InputStream is (ism);
tl::BinaryInputStream bis (is);
int32_t x;
bis >> x;
EXPECT_EQ (x, 17420000);
}
TEST(BinaryStreams11)
{
tl::OutputMemoryStream osm;
tl::BinaryOutputStream os (osm);
os << uint64_t (174200000000l);
os.flush ();
EXPECT_EQ (s2string (osm), "0x00,0x0e,0x21,0x8f,0x28,0x00,0x00,0x00");
tl::InputMemoryStream ism (osm.data (), osm.size ());
tl::InputStream is (ism);
tl::BinaryInputStream bis (is);
uint64_t x;
bis >> x;
EXPECT_EQ (x, 174200000000lu);
}
TEST(BinaryStreams12)
{
tl::OutputMemoryStream osm;
tl::BinaryOutputStream os (osm);
os << int64_t (174200000000l);
os.flush ();
EXPECT_EQ (s2string (osm), "0x00,0x0e,0x21,0x8f,0x28,0x00,0x00,0x00");
tl::InputMemoryStream ism (osm.data (), osm.size ());
tl::InputStream is (ism);
tl::BinaryInputStream bis (is);
int64_t x;
bis >> x;
EXPECT_EQ (x, 174200000000l);
}
TEST(BinaryStreams13)
{
tl::OutputMemoryStream osm;
tl::BinaryOutputStream os (osm);
os << true;
os << false;
os.flush ();
EXPECT_EQ (s2string (osm), "0x01,0x00");
tl::InputMemoryStream ism (osm.data (), osm.size ());
tl::InputStream is (ism);
tl::BinaryInputStream bis (is);
bool x = false, y = false;
bis >> x >> y;
EXPECT_EQ (x, true);
EXPECT_EQ (y, false);
}
TEST(BinaryStreamsCombined)
{
tl::OutputMemoryStream osm;
tl::BinaryOutputStream os (osm);
os << "ABC" << 17.0 << "XUV" << (int32_t) 42;
os.flush ();
tl::InputMemoryStream ism (osm.data (), osm.size ());
tl::InputStream is (ism);
tl::BinaryInputStream bis (is);
std::string a, c;
double b = 0.0;
int32_t d = 0;
bis >> a >> b >> c >> d;
EXPECT_EQ (a, "ABC");
EXPECT_EQ (b, 17.0);
EXPECT_EQ (c, "XUV");
EXPECT_EQ (d, 42);
}
TEST(BinaryStreamsVariants)
{
tl::OutputMemoryStream osm;
tl::BinaryOutputStream os (osm);
std::vector<char> bytes = { 'X', 'U', 'V' };
os << tl::Variant ("ABC")
<< tl::Variant ()
<< tl::Variant (bytes)
<< tl::Variant ((float) 42.5)
<< tl::Variant ((double) -17.5)
<< tl::Variant ((char) 'x')
<< tl::Variant ((unsigned char) 'u')
<< tl::Variant ((signed char) 'v')
<< tl::Variant ((short) 17)
<< tl::Variant ((unsigned short) 42)
<< tl::Variant ((int) 18)
<< tl::Variant ((unsigned int) 43)
<< tl::Variant ((long) 19)
<< tl::Variant ((unsigned long) 44)
<< tl::Variant ((long long) 20)
<< tl::Variant ((unsigned long long) 45)
<< tl::Variant ((size_t) 202, true /*id*/);
os.flush ();
tl::InputMemoryStream ism (osm.data (), osm.size ());
tl::InputStream is (ism);
tl::BinaryInputStream bis (is);
tl::Variant v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17;
bis >> v1 >> v2 >> v3 >> v4 >> v5 >> v6 >> v7 >> v8 >> v9 >> v10 >> v11 >> v12 >> v13 >> v14 >> v15 >> v16 >> v17;
EXPECT_EQ (v1.to_parsable_string (), "'ABC'");
EXPECT_EQ (v2.to_parsable_string (), "nil");
EXPECT_EQ (v3.to_parsable_string (), "'XUV'b");
EXPECT_EQ (v3.type_code (), tl::Variant::t_bytearray);
EXPECT_EQ (v4.to_parsable_string (), "##42.5");
EXPECT_EQ (v5.to_parsable_string (), "##-17.5");
EXPECT_EQ (v6.to_parsable_string (), "'x'c");
EXPECT_EQ (v7.to_parsable_string (), "#u117");
EXPECT_EQ (v8.to_parsable_string (), "#118");
EXPECT_EQ (v9.to_parsable_string (), "#17");
EXPECT_EQ (v10.to_parsable_string (), "#u42");
EXPECT_EQ (v11.to_parsable_string (), "#18");
EXPECT_EQ (v12.to_parsable_string (), "#u43");
EXPECT_EQ (v13.to_parsable_string (), "#19");
EXPECT_EQ (v14.to_parsable_string (), "#u44");
EXPECT_EQ (v15.to_parsable_string (), "#l20");
EXPECT_EQ (v16.to_parsable_string (), "#lu45");
EXPECT_EQ (v17.to_parsable_string (), "[id202]");
}
TEST(BinaryStreamsVariantList)
{
tl::OutputMemoryStream osm;
tl::BinaryOutputStream os (osm);
std::vector<tl::Variant> list = { 5.5, -17, "ABC" };
os << tl::Variant (list);
os.flush ();
tl::InputMemoryStream ism (osm.data (), osm.size ());
tl::InputStream is (ism);
tl::BinaryInputStream bis (is);
tl::Variant v1;
bis >> v1;
EXPECT_EQ (v1.to_parsable_string (), "(##5.5,#-17,'ABC')");
}
TEST(BinaryStreamsVariantArray)
{
tl::OutputMemoryStream osm;
tl::BinaryOutputStream os (osm);
std::vector<std::pair<tl::Variant, tl::Variant> > a = { { 1, 5.5 }, { 2, -17 }, { "id", "ABC" } };
std::map<tl::Variant, tl::Variant> array (a.begin (), a.end ());
os << tl::Variant (array);
os.flush ();
tl::InputMemoryStream ism (osm.data (), osm.size ());
tl::InputStream is (ism);
tl::BinaryInputStream bis (is);
tl::Variant v1;
bis >> v1;
EXPECT_EQ (v1.to_parsable_string (), "{#1=>##5.5,#2=>#-17,'id'=>'ABC'}");
}

View File

@ -624,304 +624,3 @@ TEST(MatchFormat)
EXPECT_EQ (tl::match_filename_to_format ("abc.TEXT", "Text files (*.txt *.TXT)"), false);
EXPECT_EQ (tl::match_filename_to_format ("abc.TEXT", "Text files (*)"), true);
}
std::string s2string (tl::OutputMemoryStream &osm)
{
std::string res;
size_t n = osm.size ();
const char *d = osm.data ();
for (size_t i = 0; i < n; ++i, ++d) {
if (i > 0) {
res += ",";
}
res += tl::sprintf ("0x%02x", int ((unsigned char) *d));
}
return res;
}
TEST(BinaryStreams1)
{
tl::OutputMemoryStream osm;
tl::BinaryOutputStream os (osm);
os << (double) 0.17;
os.flush ();
EXPECT_EQ (s2string (osm), "0xc3,0xf5,0x28,0x5c,0x8f,0xc2,0xc5,0x3f");
tl::InputMemoryStream ism (osm.data (), osm.size ());
tl::InputStream is (ism);
tl::BinaryInputStream bis (is);
double x = 0.0;
bis >> x;
EXPECT_EQ (tl::to_string (x), "0.17");
}
TEST(BinaryStreams2)
{
tl::OutputMemoryStream osm;
tl::BinaryOutputStream os (osm);
os << (float) 0.17;
os.flush ();
EXPECT_EQ (s2string (osm), "0x7b,0x14,0x2e,0x3e");
tl::InputMemoryStream ism (osm.data (), osm.size ());
tl::InputStream is (ism);
tl::BinaryInputStream bis (is);
float x = 0.0;
bis >> x;
EXPECT_EQ (tl::to_string (x), "0.17");
}
TEST(BinaryStreams3)
{
tl::OutputMemoryStream osm;
tl::BinaryOutputStream os (osm);
os << std::string ("ABC");
os.flush ();
EXPECT_EQ (s2string (osm), "0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x41,0x42,0x43");
tl::InputMemoryStream ism (osm.data (), osm.size ());
tl::InputStream is (ism);
tl::BinaryInputStream bis (is);
std::string x;
bis >> x;
EXPECT_EQ (x, "ABC");
}
TEST(BinaryStreams4)
{
tl::OutputMemoryStream osm;
tl::BinaryOutputStream os (osm);
os << "ABC";
os.flush ();
EXPECT_EQ (s2string (osm), "0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x41,0x42,0x43");
tl::InputMemoryStream ism (osm.data (), osm.size ());
tl::InputStream is (ism);
tl::BinaryInputStream bis (is);
std::string x;
bis >> x;
EXPECT_EQ (x, "ABC");
}
TEST(BinaryStreams5)
{
tl::OutputMemoryStream osm;
tl::BinaryOutputStream os (osm);
os << uint8_t (17);
os.flush ();
EXPECT_EQ (s2string (osm), "0x11");
tl::InputMemoryStream ism (osm.data (), osm.size ());
tl::InputStream is (ism);
tl::BinaryInputStream bis (is);
uint8_t x;
bis >> x;
EXPECT_EQ (x, 17);
}
TEST(BinaryStreams6)
{
tl::OutputMemoryStream osm;
tl::BinaryOutputStream os (osm);
os << int8_t (17);
os.flush ();
EXPECT_EQ (s2string (osm), "0x11");
tl::InputMemoryStream ism (osm.data (), osm.size ());
tl::InputStream is (ism);
tl::BinaryInputStream bis (is);
int8_t x;
bis >> x;
EXPECT_EQ (x, 17);
}
TEST(BinaryStreams7)
{
tl::OutputMemoryStream osm;
tl::BinaryOutputStream os (osm);
os << uint16_t (1742);
os.flush ();
EXPECT_EQ (s2string (osm), "0xce,0x06");
tl::InputMemoryStream ism (osm.data (), osm.size ());
tl::InputStream is (ism);
tl::BinaryInputStream bis (is);
uint16_t x;
bis >> x;
EXPECT_EQ (x, 1742);
}
TEST(BinaryStreams8)
{
tl::OutputMemoryStream osm;
tl::BinaryOutputStream os (osm);
os << int16_t (1742);
os.flush ();
EXPECT_EQ (s2string (osm), "0xce,0x06");
tl::InputMemoryStream ism (osm.data (), osm.size ());
tl::InputStream is (ism);
tl::BinaryInputStream bis (is);
int16_t x;
bis >> x;
EXPECT_EQ (x, 1742);
}
TEST(BinaryStreams9)
{
tl::OutputMemoryStream osm;
tl::BinaryOutputStream os (osm);
os << uint32_t (17420000);
os.flush ();
EXPECT_EQ (s2string (osm), "0xe0,0xce,0x09,0x01");
tl::InputMemoryStream ism (osm.data (), osm.size ());
tl::InputStream is (ism);
tl::BinaryInputStream bis (is);
uint32_t x;
bis >> x;
EXPECT_EQ (x, 17420000u);
}
TEST(BinaryStreams10)
{
tl::OutputMemoryStream osm;
tl::BinaryOutputStream os (osm);
os << int32_t (17420000);
os.flush ();
EXPECT_EQ (s2string (osm), "0xe0,0xce,0x09,0x01");
tl::InputMemoryStream ism (osm.data (), osm.size ());
tl::InputStream is (ism);
tl::BinaryInputStream bis (is);
int32_t x;
bis >> x;
EXPECT_EQ (x, 17420000);
}
TEST(BinaryStreams11)
{
tl::OutputMemoryStream osm;
tl::BinaryOutputStream os (osm);
os << uint64_t (174200000000l);
os.flush ();
EXPECT_EQ (s2string (osm), "0x00,0x0e,0x21,0x8f,0x28,0x00,0x00,0x00");
tl::InputMemoryStream ism (osm.data (), osm.size ());
tl::InputStream is (ism);
tl::BinaryInputStream bis (is);
uint64_t x;
bis >> x;
EXPECT_EQ (x, 174200000000lu);
}
TEST(BinaryStreams12)
{
tl::OutputMemoryStream osm;
tl::BinaryOutputStream os (osm);
os << int64_t (174200000000l);
os.flush ();
EXPECT_EQ (s2string (osm), "0x00,0x0e,0x21,0x8f,0x28,0x00,0x00,0x00");
tl::InputMemoryStream ism (osm.data (), osm.size ());
tl::InputStream is (ism);
tl::BinaryInputStream bis (is);
int64_t x;
bis >> x;
EXPECT_EQ (x, 174200000000l);
}
TEST(BinaryStreams13)
{
tl::OutputMemoryStream osm;
tl::BinaryOutputStream os (osm);
os << true;
os << false;
os.flush ();
EXPECT_EQ (s2string (osm), "0x01,0x00");
tl::InputMemoryStream ism (osm.data (), osm.size ());
tl::InputStream is (ism);
tl::BinaryInputStream bis (is);
bool x = false, y = false;
bis >> x >> y;
EXPECT_EQ (x, true);
EXPECT_EQ (y, false);
}
TEST(BinaryStreamsCombined)
{
tl::OutputMemoryStream osm;
tl::BinaryOutputStream os (osm);
os << "ABC" << 17.0 << "XUV" << (int32_t) 42;
os.flush ();
tl::InputMemoryStream ism (osm.data (), osm.size ());
tl::InputStream is (ism);
tl::BinaryInputStream bis (is);
std::string a, c;
double b = 0.0;
int32_t d = 0;
bis >> a >> b >> c >> d;
EXPECT_EQ (a, "ABC");
EXPECT_EQ (b, 17.0);
EXPECT_EQ (c, "XUV");
EXPECT_EQ (d, 42);
}

View File

@ -97,6 +97,7 @@ TEST(1)
EXPECT_EQ (v.is_ulong (), false);
EXPECT_EQ (v.is_ulonglong (), false);
EXPECT_EQ (v.is_double (), false);
EXPECT_EQ (v.to_string (), "nil");
EXPECT_EQ (v.to_parsable_string (), "nil");
vv = v;
EXPECT_EQ (vv == v, true);
@ -109,6 +110,43 @@ TEST(1)
EXPECT_EQ (vx == v, true);
}
{
tl::Variant v ((char) '\033');
#if defined(HAVE_QT)
EXPECT_EQ (tl::to_string (v.to_qvariant ().toString ()), "27");
#endif
EXPECT_EQ (v.is_nil (), false);
EXPECT_EQ (v.is_list (), false);
EXPECT_EQ (v.is_cstring (), false);
EXPECT_EQ (v.is_id (), false);
EXPECT_EQ (v.is<short> (), false);
EXPECT_EQ (v.is<unsigned short> (), false);
EXPECT_EQ (v.is<int> (), false);
EXPECT_EQ (v.is<unsigned int> (), false);
EXPECT_EQ (v.is<short> (), false);
EXPECT_EQ (v.is<unsigned short> (), false);
EXPECT_EQ (v.is<unsigned char> (), false);
EXPECT_EQ (v.is<signed char> (), false);
EXPECT_EQ (v.is<long> (), false);
EXPECT_EQ (v.is_char (), true);
EXPECT_EQ (v.is_long (), false);
EXPECT_EQ (v.is_longlong (), false);
EXPECT_EQ (v.is_ulong (), false);
EXPECT_EQ (v.is_ulonglong (), false);
EXPECT_EQ (v.is_double (), false);
EXPECT_EQ (v.to_string (), "\033");
EXPECT_EQ (v.to_parsable_string (), "'\\033'c");
vv = v;
EXPECT_EQ (vv == v, true);
EXPECT_EQ (vv != v, false);
tl::Variant vx;
std::string s (v.to_parsable_string ());
tl::Extractor ex (s.c_str ());
ex.read (vx);
ex.expect_end ();
EXPECT_EQ (vx == v, true);
}
{
tl::Variant v (1ul);
#if defined(HAVE_QT)
@ -123,6 +161,7 @@ TEST(1)
EXPECT_EQ (v.is_long (), false);
EXPECT_EQ (v.is_longlong (), false);
EXPECT_EQ (v.is_double (), false);
EXPECT_EQ (v.to_string (), "1");
EXPECT_EQ (v.to_parsable_string (), "#u1");
EXPECT_EQ (v.to_long (), 1l);
EXPECT_EQ (v.to_longlong (), 1l);
@ -161,6 +200,7 @@ TEST(1)
EXPECT_EQ (v.is_longlong (), false);
EXPECT_EQ (v.is_id (), false);
EXPECT_EQ (v.is_double (), false);
EXPECT_EQ (v.to_string (), "2");
EXPECT_EQ (v.to_parsable_string (), "#u2");
EXPECT_EQ (v.to_long (), 2l);
EXPECT_EQ (v.to_longlong (), 2l);
@ -196,6 +236,7 @@ TEST(1)
EXPECT_EQ (v.is<int> (), true);
EXPECT_EQ (v.is<unsigned int> (), false);
EXPECT_EQ (v.is_double (), false);
EXPECT_EQ (v.to_string (), "1");
EXPECT_EQ (v.to_parsable_string (), "#1");
EXPECT_EQ (v.to_long (), 1l);
EXPECT_EQ (v.to_longlong (), 1l);
@ -236,6 +277,7 @@ TEST(1)
EXPECT_EQ (v.is<unsigned int> (), false);
EXPECT_EQ (v.is<unsigned char> (), false);
EXPECT_EQ (v.is<signed char> (), false);
EXPECT_EQ (v.to_string (), "2");
EXPECT_EQ (v.to_parsable_string (), "#2");
EXPECT_EQ (v.to_long (), 2l);
EXPECT_EQ (v.to_longlong (), 2l);
@ -279,6 +321,7 @@ TEST(1)
EXPECT_EQ (v.is<unsigned char> (), false);
EXPECT_EQ (v.is<signed char> (), false);
EXPECT_EQ (v.is_id (), false);
EXPECT_EQ (v.to_string (), "5");
EXPECT_EQ (v.to_parsable_string (), "##5");
EXPECT_EQ (v.to_double (), 5.0);
EXPECT_EQ (v.to_float (), 5.0);
@ -327,6 +370,7 @@ TEST(1)
EXPECT_EQ (v.is<unsigned char> (), false);
EXPECT_EQ (v.is<signed char> (), false);
EXPECT_EQ (v.is_id (), false);
EXPECT_EQ (v.to_string (), "5");
EXPECT_EQ (v.to_parsable_string (), "##5");
EXPECT_EQ (v.to_double (), 5.0);
EXPECT_EQ (v.to_long (), 5);
@ -386,6 +430,7 @@ TEST(1)
EXPECT_EQ (v.is_longlong (), false);
EXPECT_EQ (v.is_ulonglong (), false);
EXPECT_EQ (v.is_double (), false);
EXPECT_EQ (v.to_string (), "2");
EXPECT_EQ (v.to_parsable_string (), "#2");
vv = v;
EXPECT_EQ (vv == v, true);
@ -419,6 +464,8 @@ TEST(1)
EXPECT_EQ (v.is_nil (), false);
EXPECT_EQ (v.is_list (), false);
EXPECT_EQ (v.is_cstring (), false);
EXPECT_EQ (v.is_bytearray (), false);
EXPECT_EQ (v.is_a_bytearray (), false);
EXPECT_EQ (v.is_id (), false);
EXPECT_EQ (v.is_char (), false);
EXPECT_EQ (v.is_long (), false);
@ -432,6 +479,7 @@ TEST(1)
EXPECT_EQ (v.is<signed char> (), false);
EXPECT_EQ (v.is<long> (), false);
EXPECT_EQ (v.is<unsigned long> (), false);
EXPECT_EQ (v.to_string (), "2");
EXPECT_EQ (v.to_parsable_string (), "#u2");
vv = v;
EXPECT_EQ (vv == v, true);
@ -454,6 +502,39 @@ TEST(1)
EXPECT_EQ (*(long *)v.native_ptr(), 2);
}
{
std::vector<char> bytes = { '"', 'h', 0, '\033', 'a', 'l', 'l', 'O', '"' };
tl::Variant v (std::move (bytes));
#if defined(HAVE_QT)
EXPECT_EQ (tl::Variant (v.to_qvariant ()).to_parsable_string (), "'\"h\\000\\033allO\"'b");
#endif
EXPECT_EQ (v.is_nil (), false);
EXPECT_EQ (v.is_list (), false);
EXPECT_EQ (v.is_cstring (), false);
EXPECT_EQ (v.is_bytearray (), true);
EXPECT_EQ (v.is_a_bytearray (), true);
EXPECT_EQ (v.is_long (), false);
EXPECT_EQ (v.is_ulong (), false);
EXPECT_EQ (v.is_longlong (), false);
EXPECT_EQ (v.is_ulonglong (), false);
EXPECT_EQ (v.is_double (), false);
EXPECT_EQ (v.is_id (), false);
EXPECT_EQ (v.to_parsable_string (), "'\"h\\000\\033allO\"'b");
EXPECT_EQ (v.to_stdstring (), std::string ("\"h\000\033allO\"", 9));
EXPECT_EQ (vv == v, false);
EXPECT_EQ (vv != v, true);
vv = v;
EXPECT_EQ (vv == v, true);
EXPECT_EQ (vv != v, false);
tl::Variant vx;
std::string s (v.to_parsable_string ());
tl::Extractor ex (s.c_str ());
ex.read (vx);
ex.expect_end ();
EXPECT_EQ (vx.is_bytearray (), true);
EXPECT_EQ (vx == v, true);
}
{
tl::Variant v ("hal'l\"o");
#if defined(HAVE_QT)
@ -534,6 +615,7 @@ TEST(1)
EXPECT_EQ (v.is_id (), false);
EXPECT_EQ (v.is_cstring (), false);
EXPECT_EQ (v.is_double (), false);
EXPECT_EQ (v.to_string (), "(1,5,25)");
EXPECT_EQ (v.to_parsable_string (), "(#1,#5,#25)");
EXPECT_EQ (v.get_list ().size (), size_t (3));
EXPECT_EQ (v.begin ()->is_long (), true);
@ -571,6 +653,7 @@ TEST(1)
EXPECT_EQ (v.is_ulonglong (), false);
EXPECT_EQ (v.is_cstring (), false);
EXPECT_EQ (v.is_double (), false);
EXPECT_EQ (v.to_string (), "17");
EXPECT_EQ (v.to_parsable_string (), "#l17");
tl::Variant vx;
std::string s (v.to_parsable_string ());
@ -595,6 +678,7 @@ TEST(1)
EXPECT_EQ (v.is_longlong (), false);
EXPECT_EQ (v.is_cstring (), false);
EXPECT_EQ (v.is_double (), false);
EXPECT_EQ (v.to_string (), "17");
EXPECT_EQ (v.to_parsable_string (), "#lu17");
tl::Variant vx;
std::string s (v.to_parsable_string ());
@ -619,6 +703,7 @@ TEST(1)
EXPECT_EQ (v.is_longlong (), false);
EXPECT_EQ (v.is_cstring (), false);
EXPECT_EQ (v.is_double (), false);
EXPECT_EQ (v.to_string (), "[id17]");
EXPECT_EQ (v.to_parsable_string (), "[id17]");
}
@ -642,6 +727,7 @@ TEST(1)
v.insert (tl::Variant (1), tl::Variant ("A"));
EXPECT_EQ (v.to_parsable_string (), "{#1=>\'A\'}");
v.insert (tl::Variant ("B"), tl::Variant (17));
EXPECT_EQ (v.to_string (), "{1=>A,B=>17}");
EXPECT_EQ (v.to_parsable_string (), "{#1=>\'A\',\'B\'=>#17}");
#if defined(HAVE_QT)
EXPECT_EQ (tl::Variant (v.to_qvariant ()).to_parsable_string (), "{\'1\'=>\'A\',\'B\'=>#17}");
@ -1138,7 +1224,7 @@ TEST(8)
v = tl::Variant (QByteArray ());
EXPECT_EQ (v.to_parsable_string (), "nil");
v = tl::Variant (QByteArray ("abc"));
EXPECT_EQ (v.to_parsable_string (), "'abc'");
EXPECT_EQ (v.to_parsable_string (), "'abc'b");
v = QByteArray ();
EXPECT_EQ (v.to_parsable_string (), "nil");
#endif

View File

@ -9,6 +9,7 @@ include($$PWD/../../lib_ut.pri)
SOURCES = \
tlAlgorithmTests.cc \
tlBase64Tests.cc \
tlBinaryStreamTests.cc \
tlClassRegistryTests.cc \
tlCommandLineParserTests.cc \
tlColorTests.cc \