mirror of https://github.com/KLayout/klayout.git
Merge branch 'protobuf-support' into xxx
This commit is contained in:
commit
a566150180
|
|
@ -29,6 +29,7 @@ SOURCES = \
|
|||
tlObject.cc \
|
||||
tlProgress.cc \
|
||||
tlPixelBuffer.cc \
|
||||
tlProtocolBuffer.cc \
|
||||
tlResources.cc \
|
||||
tlScriptError.cc \
|
||||
tlSleep.cc \
|
||||
|
|
@ -85,6 +86,7 @@ HEADERS = \
|
|||
tlObjectCollection.h \
|
||||
tlProgress.h \
|
||||
tlPixelBuffer.h \
|
||||
tlProtocolBuffer.h \
|
||||
tlResources.h \
|
||||
tlReuseVector.h \
|
||||
tlScriptError.h \
|
||||
|
|
|
|||
|
|
@ -0,0 +1,272 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2024 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_tlProtocolBuffer
|
||||
#define HDR_tlProtocolBuffer
|
||||
|
||||
#include "tlCommon.h"
|
||||
#include "tlStream.h"
|
||||
|
||||
namespace tl
|
||||
{
|
||||
|
||||
// Representation of VARINT values
|
||||
typedef size_t pb_varint;
|
||||
|
||||
enum PBWireType
|
||||
{
|
||||
PB_VARINT = 0,
|
||||
PB_I64 = 1,
|
||||
PB_LEN = 2,
|
||||
PB_SGROUP = 3,
|
||||
PB_EGROUP = 4,
|
||||
PB_I32 = 5
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief An exception thrown by the ProtocolBuffer reader on a read error
|
||||
*/
|
||||
class TL_PUBLIC ProtocolBufferReaderError
|
||||
: public tl::Exception
|
||||
{
|
||||
public:
|
||||
ProtocolBufferReaderError (const std::string &msg, size_t position)
|
||||
: tl::Exception (msg), m_position (position)
|
||||
{ }
|
||||
|
||||
virtual std::string msg () const
|
||||
{
|
||||
return basic_msg () + tl::to_string (tr (", at position ") + tl::to_string (m_position));
|
||||
}
|
||||
|
||||
private:
|
||||
size_t m_position;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A reader for ProtocolBuffer files and streams
|
||||
*
|
||||
* This is a low-level decoder for ProtocolBuffer files.
|
||||
*
|
||||
* The following LEN-type related concepts need to be implemented by the client code:
|
||||
* - submessages
|
||||
* - maps
|
||||
* - packed repetitions
|
||||
* - strings
|
||||
*
|
||||
* Unknown tags need to be skipped with "skip".
|
||||
*
|
||||
* Submessages: if a corresponding tag is encountered with "is_seq()" true, the
|
||||
* reader code needs to call "open" to enter the sequence and read tags until
|
||||
* "at_end" is true. Then, call "close" to leave the sequence.
|
||||
*
|
||||
* Packed repetitions: same a submessages, but single values are read
|
||||
* with one of the "read" types.
|
||||
*
|
||||
* Maps are read like submessages with key/values as tags 1 and 2.
|
||||
*
|
||||
* Strings: if a corresponding tag is encountered, use "read(s)" to read
|
||||
* the string. "is_seq()" is required to be true, i.e. wire type is LEN.
|
||||
*/
|
||||
class TL_PUBLIC ProtocolBufferReader
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Creates a ProtocolBuffer parser from the given stream
|
||||
*/
|
||||
ProtocolBufferReader (tl::InputStream &input);
|
||||
|
||||
/**
|
||||
* @brief Reads a new tag
|
||||
*
|
||||
* @returns The message ID
|
||||
*/
|
||||
int read_tag ();
|
||||
|
||||
/**
|
||||
* @brief Gets the current wire type
|
||||
*/
|
||||
PBWireType type () const
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns true, if the current message is a LEN type sequence
|
||||
* Such messages can be read into strings or "open" can be used on them to
|
||||
* open a submessage, map or packed repetition.
|
||||
*/
|
||||
bool is_seq () const
|
||||
{
|
||||
return m_type == PB_LEN;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Skips the current tag
|
||||
*/
|
||||
void skip ();
|
||||
|
||||
/**
|
||||
* @brief Reads a floating-point value from the current message
|
||||
* Throws a reader error if the current tag's value is not compatible with a double value.
|
||||
*/
|
||||
void read (double &d);
|
||||
|
||||
/**
|
||||
* @brief Reads a floating-point value from the current message
|
||||
* Throws a reader error if the current tag's value is not compatible with a float value.
|
||||
*/
|
||||
void read (float &f);
|
||||
|
||||
/**
|
||||
* @brief Reads a string from the current message
|
||||
* Throws a reader error if the current tag's value is not compatible with a string.
|
||||
*/
|
||||
void read (std::string &s);
|
||||
|
||||
/**
|
||||
* @brief Reads a uint32_t value from the current message
|
||||
* Throws a reader error if the current tag's value is not compatible with a uint32_t.
|
||||
*/
|
||||
void read (uint32_t &ui32, bool fixed = false);
|
||||
|
||||
/**
|
||||
* @brief Reads a int32_t value from the current message
|
||||
* Throws a reader error if the current tag's value is not compatible with a int32_t.
|
||||
*/
|
||||
void read (int32_t &i32, bool fixed = false);
|
||||
|
||||
/**
|
||||
* @brief Reads a uint64_t value from the current message
|
||||
* Throws a reader error if the current tag's value is not compatible with a uint64_t.
|
||||
*/
|
||||
void read (uint64_t &ui64, bool fixed = false);
|
||||
|
||||
/**
|
||||
* @brief Reads a int64_t value from the current message
|
||||
* Throws a reader error if the current tag's value is not compatible with a int64_t.
|
||||
*/
|
||||
void read (int64_t &i64, bool fixed = false);
|
||||
|
||||
/**
|
||||
* @brief Reads a boolean value from the current message
|
||||
* Throws a reader error if the current tag's value is not compatible with a bool.
|
||||
*/
|
||||
void read (bool &b);
|
||||
|
||||
/**
|
||||
* @brief Opens a LEN sequence
|
||||
* After calling "open", the parser will continue reading messages, but
|
||||
* "at_end" will report true on the end of the sequence, not at the end of the
|
||||
* file.
|
||||
* Thie method will throw an exception if not in a message of LEN type.
|
||||
*/
|
||||
void open ();
|
||||
|
||||
/**
|
||||
* @brief Closes the LEN sequence
|
||||
* This method will jump to the end of the sequence and continue reading
|
||||
* messages from the previous block or file.
|
||||
*/
|
||||
void close ();
|
||||
|
||||
/**
|
||||
* @brief Returns true if at the end of the file or end of a block
|
||||
*/
|
||||
bool at_end () const;
|
||||
|
||||
private:
|
||||
tl::InputStream m_stream;
|
||||
PBWireType m_type;
|
||||
size_t m_pos;
|
||||
std::vector<size_t> m_block_end;
|
||||
|
||||
pb_varint read_varint ();
|
||||
bool has_bytes (size_t n);
|
||||
void skip_bytes (size_t n);
|
||||
void error (const std::string &msg);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The Protocol buffer writer
|
||||
*
|
||||
* Scalar types are easy to write: just use the "write" methods.
|
||||
* This includes strings.
|
||||
*
|
||||
* Submessages and packed sequences are special as byte counting is
|
||||
* required. The writer uses a two-pass approach. This means:
|
||||
*
|
||||
* 1. On writing a submessage or packed repetition, call "begin_seq"
|
||||
* with the message tag and "counting" set to true.
|
||||
* 2. Write the elements using "write" or the submessage writing
|
||||
* scheme recursively.
|
||||
* 3. At the end of the sequence, call "end_seq".
|
||||
* 4. if "is_counting()" is false, repeat steps 1 to 3 with
|
||||
* "counting" set to false on "begin_seq".
|
||||
*/
|
||||
class TL_PUBLIC ProtocolBufferWriter
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Creates a writer for the given stream
|
||||
*/
|
||||
ProtocolBufferWriter (tl::OutputStream &stream);
|
||||
|
||||
/**
|
||||
* @brief Writes a scalar tag with the given value
|
||||
*/
|
||||
void write (int tag, float v);
|
||||
void write (int tag, double v);
|
||||
void write (int tag, uint32_t v, bool fixed = false);
|
||||
void write (int tag, int32_t v, bool fixed = false);
|
||||
void write (int tag, uint64_t v, bool fixed = false);
|
||||
void write (int tag, int64_t v, bool fixed = false);
|
||||
void write (int tag, bool b);
|
||||
void write (int tag, const std::string &s);
|
||||
|
||||
/**
|
||||
* @brief Returns true if the writer is in counting mode
|
||||
*/
|
||||
bool is_counting () const;
|
||||
|
||||
/**
|
||||
* @brief Initiates a new sequence. See class documentation for details.
|
||||
*/
|
||||
void begin_seq (int tag, bool counting);
|
||||
|
||||
/**
|
||||
* @brief Ends a sequence. See class documentation for details.
|
||||
*/
|
||||
void end_seq ();
|
||||
|
||||
private:
|
||||
size_t count_bytes_for (pb_varint v);
|
||||
void write_varint (pb_varint v);
|
||||
|
||||
tl::OutputStream m_stream;
|
||||
size_t m_bytes_counted;
|
||||
std::vector<size_t> m_byte_counter_stack;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
Loading…
Reference in New Issue