NOTICK: Add BlobWriter and Schema Dumper

The Blob Writer is a small kotlin app that allows arbitrary things to be serialized and then those bytes written to a file, quite useful for working on non JVM parsing of such things.

Along a similar vein, add a schema dumper alongside the blob-inspector to highlight the contents of the header
This commit is contained in:
Katelyn Baker 2019-08-26 20:59:56 +01:00 committed by GitHub
parent dbce25b575
commit 7b308eb45f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
46 changed files with 1290 additions and 458 deletions

View File

@ -0,0 +1,27 @@
apply plugin : 'kotlin'
apply plugin : 'application'
mainClassName = "net.corda.blobwriter.BlobWriter.kt"
dependencies {
compile project(':tools:cliutils')
compile project(":common-logging")
compile project(':serialization')
compile "org.slf4j:jul-to-slf4j:$slf4j_version"
compile "org.apache.logging.log4j:log4j-slf4j-impl:$log4j_version"
}
jar {
from (configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }) {
exclude "META-INF/*.SF"
exclude "META-INF/*.DSA"
exclude "META-INF/*.RSA"
}
baseName = "blobwriter"
manifest {
attributes(
'Main-Class': 'net.corda.blobwriter.BlobWriterKt'
)
}
}

View File

@ -0,0 +1,61 @@
package net.corda.blobwriter
import net.corda.core.serialization.SerializationContext
import net.corda.core.serialization.SerializationDefaults
import net.corda.core.serialization.internal.SerializationEnvironment
import net.corda.core.serialization.internal._contextSerializationEnv
import net.corda.core.serialization.serialize
import net.corda.serialization.internal.*
import net.corda.serialization.internal.amqp.AbstractAMQPSerializationScheme
import net.corda.serialization.internal.amqp.amqpMagic
import java.io.File
object AMQPInspectorSerializationScheme : AbstractAMQPSerializationScheme(emptyList()) {
override fun canDeserializeVersion (
magic: CordaSerializationMagic,
target: SerializationContext.UseCase
): Boolean {
return magic == amqpMagic
}
override fun rpcClientSerializerFactory(context: SerializationContext) = throw UnsupportedOperationException()
override fun rpcServerSerializerFactory(context: SerializationContext) = throw UnsupportedOperationException()
}
val BLOB_WRITER_CONTEXT = SerializationContextImpl(
amqpMagic,
SerializationDefaults.javaClass.classLoader,
AllWhitelist,
emptyMap(),
true,
SerializationContext.UseCase.P2P,
null
)
fun initialiseSerialization() {
_contextSerializationEnv.set (
SerializationEnvironment.with (
SerializationFactoryImpl().apply {
registerScheme (AMQPInspectorSerializationScheme)
},
p2pContext = BLOB_WRITER_CONTEXT
)
)
}
data class _i_ (val a: Int)
data class _is_ (val a: Int, val b: String)
data class _i_is__ (val a: Int, val b: _is_)
data class _Li_ (val a: List<Int>)
data class _Mis_ (val a: Map<Int, String>)
fun main (args: Array<String>) {
initialiseSerialization()
File("../cpp-serializer/bin/blob-inspector/test/_i_is__").writeBytes(_i_is__(1, _is_ (2, "three")).serialize().bytes)
File("../cpp-serializer/bin/blob-inspector/test/_Li_").writeBytes(_Li_(listOf (1, 2, 3, 4, 5, 6)).serialize().bytes)
File("../cpp-serializer/bin/blob-inspector/test/_Mis_").writeBytes(_Mis_(
mapOf (1 to "two", 3 to "four", 5 to "six")).serialize().bytes)
}

View File

@ -1,9 +1,2 @@
include_directories (${BLOB-INSPECTOR_SOURCE_DIR}/src)
include_directories (${BLOB-INSPECTOR_SOURCE_DIR}/src/amqp)
link_directories (${BLOB-INSPECTOR_BINARY_DIR}/src/amqp)
link_directories (${BLOB-INSPECTOR_BINARY_DIR}/src/proton)
add_executable (blob-inspector main)
target_link_libraries (blob-inspector amqp proton qpid-proton)
ADD_SUBDIRECTORY (blob-inspector)
ADD_SUBDIRECTORY (schema-dumper)

View File

@ -0,0 +1,9 @@
include_directories (${BLOB-INSPECTOR_SOURCE_DIR}/src)
include_directories (${BLOB-INSPECTOR_SOURCE_DIR}/src/amqp)
link_directories (${BLOB-INSPECTOR_BINARY_DIR}/src/amqp)
link_directories (${BLOB-INSPECTOR_BINARY_DIR}/src/proton)
add_executable (blob-inspector main)
target_link_libraries (blob-inspector amqp proton qpid-proton)

View File

@ -75,7 +75,6 @@ data_and_stop(std::ifstream & f_, ssize_t sz) {
<< reader->dump ("{ Parsed", d, envelope->schema())->dump()
<< " }" << std::endl;
}
}
}
@ -104,7 +103,9 @@ main (int argc, char **argv) {
if (encoding == amqp::DATA_AND_STOP) {
data_and_stop(f, results.st_size - 8);
} else {
std::cerr << "BAD ENCODING " << encoding << " != " << amqp::DATA_AND_STOP << std::endl;
std::cerr << "BAD ENCODING " << encoding << " != "
<< amqp::DATA_AND_STOP << std::endl;
return EXIT_FAILURE;
}

View File

@ -0,0 +1 @@
schema-dumper

View File

@ -0,0 +1,9 @@
include_directories (${BLOB-INSPECTOR_SOURCE_DIR}/src)
include_directories (${BLOB-INSPECTOR_SOURCE_DIR}/src/amqp)
link_directories (${BLOB-INSPECTOR_BINARY_DIR}/src/amqp)
link_directories (${BLOB-INSPECTOR_BINARY_DIR}/src/proton)
add_executable (schema-dumper main)
target_link_libraries (schema-dumper proton amqp qpid-proton)

View File

@ -0,0 +1,92 @@
#include <iostream>
#include <iomanip>
#include <fstream>
#include <cstddef>
#include <assert.h>
#include <string.h>
#include <proton/types.h>
#include <proton/codec.h>
#include <sys/stat.h>
#include <sstream>
#import "debug.h"
#include "proton/proton_wrapper.h"
#include "amqp/AMQPHeader.h"
#include "amqp/AMQPSectionId.h"
#include "amqp/descriptors/AMQPDescriptorRegistory.h"
#include "amqp/schema/Envelope.h"
#include "amqp/CompositeFactory.h"
/******************************************************************************/
void
printNode (pn_data_t * d_) {
std::stringstream ss;
if (pn_data_is_described (d_)) {
amqp::AMQPDescriptorRegistory[22UL]->read (d_, ss);
}
std::cout << ss.str() << std::endl;
}
/******************************************************************************/
void
data_and_stop(std::ifstream & f_, ssize_t sz) {
char * blob = new char[sz];
memset (blob, 0, sz);
f_.read(blob, sz);
pn_data_t * d = pn_data(sz);
// returns how many bytes we processed which right now we don't care
// about but I assume there is a case where it doesn't process the
// entire file
auto rtn = pn_data_decode (d, blob, sz);
assert (rtn == sz);
printNode (d);
}
/******************************************************************************/
int
main (int argc, char **argv) {
struct stat results { };
if (stat(argv[1], &results) != 0) {
return EXIT_FAILURE;
}
std::ifstream f (argv[1], std::ios::in | std::ios::binary);
std::array<char, 7> header { };
f.read(header.data(), 7);
if (header != amqp::AMQP_HEADER) {
std::cerr << "Bad Header in blob" << std::endl;
return EXIT_FAILURE;
}
amqp::amqp_section_id_t encoding;
f.read((char *)&encoding, 1);
if (encoding == amqp::DATA_AND_STOP) {
data_and_stop(f, results.st_size - 8);
} else {
std::cerr << "BAD ENCODING " << encoding << " != "
<< amqp::DATA_AND_STOP << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
/******************************************************************************/

View File

@ -12,7 +12,7 @@ namespace amqp {
* The 8th byte is used to store weather the stream is compressed or
* not
*/
std::array<char, 7> AMQP_HEADER = { { 'c', 'o', 'r', 'd', 'a', 1, 0 } };
std::array<char, 7> AMQP_HEADER { { 'c', 'o', 'r', 'd', 'a', 1, 0 } };
}

View File

@ -5,8 +5,15 @@ include_directories (.)
set (amqp_sources
CompositeFactory.cxx
descriptors/AMQPDescriptor.cxx
descriptors/AMQPDescriptors.cxx
descriptors/AMQPDescriptorRegistory.cxx
descriptors/corda-descriptors/FieldDescriptor.cxx
descriptors/corda-descriptors/SchemaDescriptor.cxx
descriptors/corda-descriptors/ObjectDescriptor.cxx
descriptors/corda-descriptors/EnvelopeDescriptor.cxx
descriptors/corda-descriptors/CompositeDescriptor.cxx
descriptors/corda-descriptors/RestrictedDescriptor.cxx
schema/Schema.cxx
schema/Field.cxx
schema/Envelope.cxx
@ -16,14 +23,14 @@ set (amqp_sources
schema/restricted-types/List.cxx
schema/AMQPTypeNotation.cxx
reader/Reader.cxx
reader/RestrictedReader.cxx
reader/CompositeReader.cxx
reader/PropertyReader.cxx
reader/property-readers/StringPropertyReader.cxx
reader/CompositeReader.cxx
reader/RestrictedReader.cxx
reader/property-readers/IntPropertyReader.cxx
reader/property-readers/DoublePropertyReader.cxx
reader/property-readers/LongPropertyReader.cxx
reader/property-readers/BoolPropertyReader.cxx
reader/property-readers/DoublePropertyReader.cxx
reader/property-readers/StringPropertyReader.cxx
reader/restricted-readers/ListReader.cxx
)

View File

@ -0,0 +1,102 @@
#include "AMQPDescriptor.h"
#include <sstream>
#include <amqp/descriptors/corda-descriptors/EnvelopeDescriptor.h>
#include "proton/proton_wrapper.h"
#include "AMQPDescriptorRegistory.h"
/******************************************************************************/
namespace amqp::internal {
std::ostream &
operator<<(std::ostream &stream_, const amqp::internal::AutoIndent &ai_) {
stream_ << ai_.indent;
return stream_;
}
}
/******************************************************************************/
const std::string &
amqp::internal::
AMQPDescriptor::symbol() const {
return m_symbol;
}
/******************************************************************************/
std::unique_ptr<amqp::AMQPDescribed>
amqp::internal::
AMQPDescriptor::build (pn_data_t *) const {
throw std::runtime_error ("Should never be called");
}
/******************************************************************************/
inline void
amqp::internal::
AMQPDescriptor::read (
pn_data_t * data_,
std::stringstream & ss_
) const {
return read (data_, ss_, AutoIndent());
}
/******************************************************************************/
void
amqp::internal::
AMQPDescriptor::read (
pn_data_t * data_,
std::stringstream & ss_,
const AutoIndent & ai_
) const {
switch (pn_data_type (data_)) {
case PN_DESCRIBED : {
ss_ << ai_ << "DESCRIBED: " << std::endl;
{
AutoIndent ai { ai_ } ; // NOLINT
proton::auto_enter p (data_);
switch (pn_data_type (data_)) {
case PN_ULONG : {
auto key = proton::readAndNext<u_long>(data_);
ss_ << ai << "key : "
<< key << " :: " << amqp::stripCorda(key)
<< " -> "
<< amqp::describedToString ((uint64_t )key)
<< std::endl;
proton::is_list (data_);
ss_ << ai << "list : entries: "
<< pn_data_get_list(data_)
<< std::endl;
AMQPDescriptorRegistory[key]->read (data_, ss_, ai);
break;
}
case PN_SYMBOL : {
ss_ << ai << "blob: bytes: "
<< pn_data_get_symbol(data_).size
<< std::endl;
break;
}
default : {
throw std::runtime_error (
"Described type should only contain long or blob");
}
}
}
break;
}
default : {
throw std::runtime_error ("Can only dispatch described objects");
}
}
}
/******************************************************************************/

View File

@ -16,6 +16,30 @@
struct pn_data_t;
/******************************************************************************
*
* amqp::internal::AMQPDescribed
*
******************************************************************************/
namespace amqp::internal {
class AutoIndent {
private :
std::string indent;
public :
AutoIndent() : indent { "" } { }
AutoIndent (const AutoIndent & ai_)
: indent { ai_.indent + " "}
{ }
friend std::ostream &
operator << (std::ostream & stream_, const AutoIndent & ai_);
};
}
/******************************************************************************
*
* amqp::internal::AMQPDescriptor
@ -35,18 +59,27 @@ namespace amqp::internal {
, m_val (-1)
{ }
AMQPDescriptor(std::string symbol_, int val_)
AMQPDescriptor (std::string symbol_, int val_)
: m_symbol (std::move (symbol_))
, m_val (val_)
{ }
virtual ~AMQPDescriptor() = default;
const std::string & symbol() const { return m_symbol; }
const std::string & symbol() const;
void validateAndNext (pn_data_t *) const;
virtual std::unique_ptr<AMQPDescribed> build (pn_data_t * data_) const = 0;
virtual std::unique_ptr<AMQPDescribed> build (pn_data_t * data_) const;
virtual void read (
pn_data_t *,
std::stringstream &) const;
virtual void read (
pn_data_t *,
std::stringstream &,
const AutoIndent &) const;
};
}

View File

@ -1,6 +1,13 @@
#include "AMQPDescriptorRegistory.h"
#include "AMQPDescriptors.h"
#include "corda-descriptors/FieldDescriptor.h"
#include "corda-descriptors/SchemaDescriptor.h"
#include "corda-descriptors/ObjectDescriptor.h"
#include "corda-descriptors/EnvelopeDescriptor.h"
#include "corda-descriptors/CompositeDescriptor.h"
#include "corda-descriptors/RestrictedDescriptor.h"
#include <limits>
#include <climits>
@ -8,8 +15,7 @@
namespace amqp::internal {
const uint64_t DESCRIPTOR_TOP_32BITS = 0xc562L << (32 + 16);
constexpr uint64_t DESCRIPTOR_TOP_32BITS = 0xc562UL << (unsigned int)(32 + 16);
}
@ -41,77 +47,83 @@ namespace amqp {
std::map<uint64_t, std::shared_ptr<internal::AMQPDescriptor>>
AMQPDescriptorRegistory = {
{
1L | internal::DESCRIPTOR_TOP_32BITS,
22UL,
std::make_shared<internal::AMQPDescriptor> (
"DESCRIBED",
-1)
},
{
1UL | internal::DESCRIPTOR_TOP_32BITS,
std::make_shared<internal::EnvelopeDescriptor> (
internal::EnvelopeDescriptor (
"ENVELOPE",
internal::ENVELOPE))
},
{
2L | internal::DESCRIPTOR_TOP_32BITS,
2UL | internal::DESCRIPTOR_TOP_32BITS,
std::make_shared<internal::SchemaDescriptor> (
internal::SchemaDescriptor (
"SCHEMA",
internal::SCHEMA))
},
{
3L | internal::DESCRIPTOR_TOP_32BITS,
3UL | internal::DESCRIPTOR_TOP_32BITS,
std::make_shared<internal::ObjectDescriptor> (
internal::ObjectDescriptor (
"OBJECT_DESCRIPTOR",
internal::OBJECT))
},
{
4L | internal::DESCRIPTOR_TOP_32BITS,
4UL | internal::DESCRIPTOR_TOP_32BITS,
std::make_shared<internal::FieldDescriptor> (
internal::FieldDescriptor (
"FIELD",
internal::FIELD))
},
{
5L | internal::DESCRIPTOR_TOP_32BITS,
5UL | internal::DESCRIPTOR_TOP_32BITS,
std::make_shared<internal::CompositeDescriptor> (
internal::CompositeDescriptor (
"COMPOSITE_TYPE",
internal::COMPOSITE_TYPE))
},
{
6L | internal::DESCRIPTOR_TOP_32BITS,
6UL | internal::DESCRIPTOR_TOP_32BITS,
std::make_shared<internal::RestrictedDescriptor> (
internal::RestrictedDescriptor (
"RESTRICTED_TYPE",
internal::RESTRICTED_TYPE))
},
{
7L | internal::DESCRIPTOR_TOP_32BITS,
7UL | internal::DESCRIPTOR_TOP_32BITS,
std::make_shared<internal::ChoiceDescriptor> (
internal::ChoiceDescriptor (
"CHOICE",
internal::CHOICE))
},
{
8L | internal::DESCRIPTOR_TOP_32BITS,
8UL | internal::DESCRIPTOR_TOP_32BITS,
std::make_shared<internal::ReferencedObjectDescriptor> (
internal::ReferencedObjectDescriptor (
"REFERENCED_OBJECT",
internal::REFERENCED_OBJECT))
},
{
9L | internal::DESCRIPTOR_TOP_32BITS,
9UL | internal::DESCRIPTOR_TOP_32BITS,
std::make_shared<internal::TransformSchemaDescriptor> (
internal::TransformSchemaDescriptor (
"TRANSFORM_SCHEMA",
internal::TRANSFORM_SCHEMA))
},
{
10L | internal::DESCRIPTOR_TOP_32BITS,
10UL | internal::DESCRIPTOR_TOP_32BITS,
std::make_shared<internal::TransformElementDescriptor> (
internal::TransformElementDescriptor (
"TRANSFORM_ELEMENT",
internal::TRANSFORM_ELEMENT))
},
{
11L | internal::DESCRIPTOR_TOP_32BITS,
11UL | internal::DESCRIPTOR_TOP_32BITS,
std::make_shared<internal::TransformElementKeyDescriptor> (
internal::TransformElementKeyDescriptor (
"TRANSFORM_ELEMENT_KEY",
@ -132,19 +144,19 @@ amqp::stripCorda (uint64_t id) {
std::string
amqp::describedToString (uint64_t val_) {
switch (val_) {
case (1L | internal::DESCRIPTOR_TOP_32BITS) : return "ENVELOPE";
case (2L | internal::DESCRIPTOR_TOP_32BITS) : return "SCHEMA";
case (3L | internal::DESCRIPTOR_TOP_32BITS) : return "OBJECT_DESCRIPTOR";
case (4L | internal::DESCRIPTOR_TOP_32BITS) : return "FIELD";
case (5L | internal::DESCRIPTOR_TOP_32BITS) : return "COMPOSITE_TYPE";
case (6L | internal::DESCRIPTOR_TOP_32BITS) : return "RESTRICTED_TYPE";
case (7L | internal::DESCRIPTOR_TOP_32BITS) : return "CHOICE";
case (8L | internal::DESCRIPTOR_TOP_32BITS) : return "REFERENCED_OBJECT";
case (9L | internal::DESCRIPTOR_TOP_32BITS) : return "TRANSFORM_SCHEMA";
case (10L | internal::DESCRIPTOR_TOP_32BITS) : return "TRANSFORM_ELEMENT";
case (11L | internal::DESCRIPTOR_TOP_32BITS) : return "TRANSFORM_ELEMENT_KEY";
case (1UL | internal::DESCRIPTOR_TOP_32BITS) : return "ENVELOPE";
case (2UL | internal::DESCRIPTOR_TOP_32BITS) : return "SCHEMA";
case (3UL | internal::DESCRIPTOR_TOP_32BITS) : return "OBJECT_DESCRIPTOR";
case (4UL | internal::DESCRIPTOR_TOP_32BITS) : return "FIELD";
case (5UL | internal::DESCRIPTOR_TOP_32BITS) : return "COMPOSITE_TYPE";
case (6UL | internal::DESCRIPTOR_TOP_32BITS) : return "RESTRICTED_TYPE";
case (7UL | internal::DESCRIPTOR_TOP_32BITS) : return "CHOICE";
case (8UL | internal::DESCRIPTOR_TOP_32BITS) : return "REFERENCED_OBJECT";
case (9UL | internal::DESCRIPTOR_TOP_32BITS) : return "TRANSFORM_SCHEMA";
case (10UL | internal::DESCRIPTOR_TOP_32BITS) : return "TRANSFORM_ELEMENT";
case (11UL | internal::DESCRIPTOR_TOP_32BITS) : return "TRANSFORM_ELEMENT_KEY";
default : return "UNKNOWN";
};
}
}
/******************************************************************************/

View File

@ -7,7 +7,7 @@
/******************************************************************************/
#include "amqp/AMQPDescriptor.h"
#include "AMQPDescriptor.h"
/******************************************************************************/

View File

@ -25,31 +25,6 @@
*
******************************************************************************/
namespace {
/**
* Look up a described type by its ID in the AMQPDescriptorRegistry and
* return the corresponding schema type. Specialised below to avoid
* the cast and re-owning of the unigue pointer when we're happy
* with a simple uPtr<AMQPDescribed>
*/
template<class T>
uPtr<T>
dispatchDescribed (pn_data_t * data_) {
proton::is_described(data_);
proton::auto_enter p (data_);
proton::is_ulong(data_);
auto id = pn_data_get_ulong(data_);
return uPtr<T> (
static_cast<T *>(amqp::AMQPDescriptorRegistory[id]->build(data_).release()));
}
}
/******************************************************************************/
void
amqp::internal::
AMQPDescriptor::validateAndNext (pn_data_t * const data_) const {
@ -63,272 +38,7 @@ AMQPDescriptor::validateAndNext (pn_data_t * const data_) const {
throw std::runtime_error ("Invalid Type");
}
pn_data_next(data_);
}
/******************************************************************************/
namespace {
const std::string
consumeBlob (pn_data_t * data_) {
proton::is_described (data_);
proton::auto_enter p (data_);
return proton::get_symbol<std::string> (data_);
}
}
/******************************************************************************
*
* amqp::internal::EnvelopeDescriptor
*
******************************************************************************/
uPtr<amqp::AMQPDescribed>
amqp::internal::
EnvelopeDescriptor::build(pn_data_t * data_) const {
DBG ("ENVELOPE" << std::endl); // NOLINT
validateAndNext(data_);
proton::auto_enter p (data_);
/*
* The actual blob... if this was java we would use the type symbols
* in the blob to look up serialisers in the cache... but we don't
* have any so we are actually going to need to use the schema
* which we parse *after* this to be able to read any data!
*/
std::string outerType = consumeBlob(data_);
pn_data_next (data_);
/*
* The schema
*/
auto schema = dispatchDescribed<schema::Schema> (data_);
pn_data_next(data_);
/*
* The transforms schema
*/
// Skip for now
// dispatchDescribed (data_);
return std::make_unique<schema::Envelope> (schema::Envelope (schema, outerType));
}
/******************************************************************************/
uPtr<amqp::AMQPDescribed>
amqp::internal::
SchemaDescriptor::build(pn_data_t * data_) const {
DBG ("SCHEMA" << std::endl); // NOLINT
validateAndNext(data_);
schema::OrderedTypeNotations<schema::AMQPTypeNotation> schemas;
/*
* The Schema is stored as a list of lists of described objects
*/
{
proton::auto_list_enter ale (data_);
for (int i { 1 } ; pn_data_next(data_) ; ++i) {
DBG (" " << i << "/" << ale.elements() << std::endl); // NOLINT
proton::auto_list_enter ale2 (data_);
while (pn_data_next(data_)) {
schemas.insert (dispatchDescribed<schema::AMQPTypeNotation>(data_));
}
}
}
return std::make_unique<schema::Schema> (std::move (schemas));
}
/******************************************************************************
*
* amqp::internal::ObjectDescriptor
*
******************************************************************************/
/**
*
*/
uPtr<amqp::AMQPDescribed>
amqp::internal::
ObjectDescriptor::build(pn_data_t * data_) const {
DBG ("DESCRIPTOR" << std::endl); // NOLINT
validateAndNext(data_);
proton::auto_enter p (data_);
auto symbol = proton::get_symbol<std::string> (data_);
return std::make_unique<schema::Descriptor> (symbol);
}
/******************************************************************************
*
* amqp::internal::FieldDescriptor
*
******************************************************************************/
uPtr<amqp::AMQPDescribed>
amqp::internal::
FieldDescriptor::build(pn_data_t * data_) const {
DBG ("FIELD" << std::endl); // NOLINT
validateAndNext(data_);
proton::auto_enter ae (data_);
/* name: String */
auto name = proton::get_string (data_);
pn_data_next(data_);
/* type: String */
auto type = proton::get_string (data_);
pn_data_next(data_);
/* requires: List<String> */
std::list<std::string> requires;
{
proton::auto_list_enter ale (data_);
while (pn_data_next(data_)) {
requires.push_back (proton::get_string(data_));
}
}
pn_data_next(data_);
/* default: String? */
auto def = proton::get_string (data_, true);
pn_data_next(data_);
/* label: String? */
auto label = proton::get_string (data_, true);
pn_data_next(data_);
/* mandatory: Boolean - copes with the Kotlin concept of nullability.
If something is mandatory then it cannot be null */
auto mandatory = proton::get_boolean (data_);
pn_data_next(data_);
/* multiple: Boolean */
auto multiple = proton::get_boolean(data_);
return std::make_unique<schema::Field> (name, type, requires, def, label,
mandatory, multiple);
}
/******************************************************************************
*
* amqp::internal::CompositeDescriptor
*
******************************************************************************/
uPtr<amqp::AMQPDescribed>
amqp::internal::
CompositeDescriptor::build (pn_data_t * data_) const {
DBG ("COMPOSITE" << std::endl); // NOLINT
validateAndNext(data_);
proton::auto_enter p (data_);
/* Class Name - String */
auto name = proton::get_string(data_);
pn_data_next(data_);
/* Label Name - Nullable String */
auto label = proton::get_string (data_, true);
pn_data_next(data_);
/* provides: List<String> */
std::list<std::string> provides;
{
proton::auto_list_enter p2 (data_);
while (pn_data_next(data_)) {
provides.push_back (proton::get_string (data_));
}
}
pn_data_next(data_);
/* descriptor: Descriptor */
auto descriptor = dispatchDescribed<schema::Descriptor>(data_);
pn_data_next(data_);
/* fields: List<Described>*/
std::vector<uPtr<schema::Field>> fields;
fields.reserve (pn_data_get_list (data_));
{
proton::auto_list_enter p2 (data_);
while (pn_data_next (data_)) {
fields.emplace_back (dispatchDescribed<schema::Field>(data_));
}
}
return std::make_unique<schema::Composite> (
schema::Composite (name, label, provides, descriptor, fields));
}
/******************************************************************************
*
* Restricted types represent lists and maps
*
* NOTE: The Corda serialization scheme doesn't support all container classes
* as it has the requiremnt that iteration order be deterministic for purposes
* of signing over data.
*
* name : String
* label : String?
* provides : List<String>
* source : String
* descriptor : Descriptor
* choices : List<Choice>
*
******************************************************************************/
uPtr<amqp::AMQPDescribed>
amqp::internal::
RestrictedDescriptor::build (pn_data_t * data_) const {
DBG ("RESTRICTED" << std::endl); // NOLINT
validateAndNext(data_);
proton::auto_enter ae (data_);
auto name = proton::readAndNext<std::string>(data_);
auto label = proton::readAndNext<std::string>(data_, true);
std::vector<std::string> provides;
{
proton::auto_list_enter ae2 (data_);
while (pn_data_next(data_)) {
provides.push_back (proton::get_string (data_));
}
}
pn_data_next (data_);
auto source = proton::readAndNext<std::string> (data_);
auto descriptor = dispatchDescribed<schema::Descriptor> (data_);
// SKIP the choices section **FOR NOW**
return schema::Restricted::make (descriptor, name,
label, provides, source);
}
/******************************************************************************
@ -396,3 +106,4 @@ TransformElementKeyDescriptor::build (pn_data_t * data_) const {
}
/******************************************************************************/

View File

@ -8,9 +8,12 @@
#include <memory>
#include <iostream>
#include "types.h"
#include "amqp/AMQPDescribed.h"
#include "amqp/AMQPDescriptor.h"
#include "AMQPDescriptor.h"
#include "amqp/schema/Descriptor.h"
#include "proton/proton_wrapper.h"
#include "AMQPDescriptorRegistory.h"
/******************************************************************************/
@ -18,116 +21,26 @@ struct pn_data_t;
/******************************************************************************/
namespace amqp::internal {
namespace amqp::internal::descriptors {
class EnvelopeDescriptor : public AMQPDescriptor {
public :
EnvelopeDescriptor() : AMQPDescriptor() { }
/**
* Look up a described type by its ID in the AMQPDescriptorRegistry and
* return the corresponding schema type. Specialised below to avoid
* the cast and re-owning of the unigue pointer when we're happy
* with a simple uPtr<AMQPDescribed>
*/
template<class T>
uPtr <T>
dispatchDescribed(pn_data_t *data_) {
proton::is_described(data_);
proton::auto_enter p(data_);
proton::is_ulong(data_);
EnvelopeDescriptor(const std::string & symbol_, int val_)
: AMQPDescriptor(symbol_, val_)
{ }
~EnvelopeDescriptor() final = default;
std::unique_ptr<AMQPDescribed> build (pn_data_t *) const override;
};
}
/******************************************************************************/
namespace amqp::internal {
class SchemaDescriptor : public AMQPDescriptor {
public :
SchemaDescriptor() : AMQPDescriptor() { }
SchemaDescriptor(const std::string & symbol_, int val_)
: AMQPDescriptor(symbol_, val_)
{ }
~SchemaDescriptor() final = default;
std::unique_ptr<AMQPDescribed> build (pn_data_t *) const override;
};
}
/******************************************************************************/
namespace amqp::internal {
class ObjectDescriptor : public AMQPDescriptor {
public :
ObjectDescriptor() : AMQPDescriptor() { }
ObjectDescriptor(const std::string & symbol_, int val_)
: AMQPDescriptor(symbol_, val_)
{ }
~ObjectDescriptor() final = default;
std::unique_ptr<AMQPDescribed> build (pn_data_t *) const override;
};
}
/******************************************************************************/
namespace amqp::internal {
class FieldDescriptor : public AMQPDescriptor {
public :
FieldDescriptor() : AMQPDescriptor() { }
FieldDescriptor(const std::string & symbol_, int val_)
: AMQPDescriptor(symbol_, val_)
{ }
~FieldDescriptor() final = default;
std::unique_ptr<AMQPDescribed> build (pn_data_t *) const override;
};
}
/******************************************************************************/
namespace amqp::internal {
class CompositeDescriptor : public AMQPDescriptor {
public :
CompositeDescriptor() : AMQPDescriptor() { }
CompositeDescriptor(const std::string & symbol_, int val_)
: AMQPDescriptor(symbol_, val_)
{ }
~CompositeDescriptor() final = default;
std::unique_ptr<AMQPDescribed> build (pn_data_t *) const override;
};
}
/******************************************************************************/
namespace amqp::internal {
class RestrictedDescriptor : public AMQPDescriptor {
public :
RestrictedDescriptor() : AMQPDescriptor() { }
RestrictedDescriptor(const std::string & symbol_, int val_)
: AMQPDescriptor(symbol_, val_)
{ }
~RestrictedDescriptor() final = default;
std::unique_ptr<AMQPDescribed> build (pn_data_t *) const override;
};
auto id = pn_data_get_ulong(data_);
return uPtr<T>(
static_cast<T *>(amqp::AMQPDescriptorRegistory[id]->build(data_).release()));
}
}
/******************************************************************************/

View File

@ -0,0 +1,146 @@
#include "CompositeDescriptor.h"
#include <string>
#include <sstream>
#include <iostream>
#include "types.h"
#include "debug.h"
#include "proton/proton_wrapper.h"
#include "amqp/descriptors/AMQPDescriptors.h"
#include "amqp/schema/Field.h"
#include "amqp/schema/Composite.h"
#include "amqp/schema/Descriptor.h"
/******************************************************************************
*
* amqp::internal::CompositeDescriptor
*
******************************************************************************/
amqp::internal::
CompositeDescriptor::CompositeDescriptor (
const std::string & symbol_,
int val_
) : AMQPDescriptor (symbol_, val_) {
}
/******************************************************************************/
uPtr<amqp::AMQPDescribed>
amqp::internal::
CompositeDescriptor::build (pn_data_t * data_) const {
DBG ("COMPOSITE" << std::endl); // NOLINT
validateAndNext(data_);
proton::auto_enter p (data_);
/* Class Name - String */
auto name = proton::get_string(data_);
pn_data_next(data_);
/* Label Name - Nullable String */
auto label = proton::get_string (data_, true);
pn_data_next(data_);
/* provides: List<String> */
std::list<std::string> provides;
{
proton::auto_list_enter p2 (data_);
while (pn_data_next(data_)) {
provides.push_back (proton::get_string (data_));
}
}
pn_data_next (data_);
/* descriptor: Descriptor */
auto descriptor = descriptors::dispatchDescribed<schema::Descriptor>(data_);
pn_data_next (data_);
/* fields: List<Described>*/
std::vector<uPtr<schema::Field>> fields;
fields.reserve (pn_data_get_list (data_));
{
proton::auto_list_enter p2 (data_);
while (pn_data_next (data_)) {
fields.emplace_back (descriptors::dispatchDescribed<schema::Field>(data_));
}
}
return std::make_unique<schema::Composite> (
schema::Composite (name, label, provides, descriptor, fields));
}
/******************************************************************************/
void
amqp::internal::
CompositeDescriptor::read (
pn_data_t * data_,
std::stringstream & ss_,
const AutoIndent & ai_
) const {
proton::is_list(data_);
{
AutoIndent ai { ai_ };
proton::auto_enter p (data_);
proton::is_string (data_);
ss_ << ai
<< "1] String: ClassName: "
<< proton::readAndNext<std::string>(data_)
<< std::endl;
proton::is_string (data_);
ss_ << ai
<< "2] String: Label: \""
<< proton::readAndNext<std::string>(data_, true)
<< "\"" << std::endl;
proton::is_list (data_);
ss_ << ai << "3] List: Provides: [ ";
{
proton::auto_list_enter ale (data_);
while (pn_data_next(data_)) {
ss_ << ai << (proton::get_string (data_)) << " ";
}
}
ss_ << "]" << std::endl;
pn_data_next (data_);
proton::is_described (data_);
ss_ << ai << "4] Descriptor:" << std::endl;
AMQPDescriptorRegistory[pn_data_type(data_)]->read (
(pn_data_t *)proton::auto_next(data_), ss_, AutoIndent { ai });
ss_ << ai << "5] List: Fields: " << std::endl;
{
AutoIndent ai2 { ai };
proton::auto_list_enter ale (data_);
for (int i { 1 } ; pn_data_next (data_) ; ++i) {
ss_ << ai2 << i << "/"
<< ale.elements() << "]"
<< std::endl;
AMQPDescriptorRegistory[pn_data_type(data_)]->read (
data_, ss_, AutoIndent { ai2 });
}
}
}
}
/******************************************************************************/

View File

@ -0,0 +1,26 @@
#pragma once
#include "amqp/descriptors/AMQPDescriptor.h"
/******************************************************************************/
namespace amqp::internal {
class CompositeDescriptor : public AMQPDescriptor {
public :
CompositeDescriptor() : AMQPDescriptor() { }
CompositeDescriptor (const std::string &, int);
~CompositeDescriptor() final = default;
std::unique_ptr<AMQPDescribed> build (pn_data_t *) const override;
void read (
pn_data_t *,
std::stringstream &,
const AutoIndent &) const override;
};
}
/******************************************************************************/

View File

@ -0,0 +1,114 @@
#include "EnvelopeDescriptor.h"
#include "amqp/schema/Schema.h"
#include "amqp/schema/Envelope.h"
#include "proton/proton_wrapper.h"
#include "types.h"
#include "debug.h"
#include <sstream>
/******************************************************************************/
namespace {
const std::string
consumeBlob (pn_data_t * data_) {
proton::is_described (data_);
proton::auto_enter p (data_);
return proton::get_symbol<std::string> (data_);
}
}
/******************************************************************************
*
* amqp::internal::EnvelopeDescriptor
*
******************************************************************************/
/*
* Described types are a pair of a key and a list of elements. Having
* parsed this as such a type we should be in the stack at the point
* where we found the list and don't expect to have entered it before
* calling this
*/
void
amqp::internal::
EnvelopeDescriptor::read (
pn_data_t * data_, std::stringstream & ss_, const AutoIndent & ai_
) const {
// lets just make sure we haven't entered this already
proton::is_list (data_);
{
AutoIndent ai { ai_ };
proton::auto_enter p (data_);
ss_ << ai << "1]" << std::endl;
AMQPDescriptorRegistory[pn_data_type(data_)]->read (
(pn_data_t *)proton::auto_next (data_), ss_, AutoIndent { ai });
ss_ << ai << "2]" << std::endl;
AMQPDescriptorRegistory[pn_data_type(data_)]->read (
(pn_data_t *)proton::auto_next(data_), ss_, AutoIndent { ai });
}
}
/******************************************************************************/
amqp::internal::
EnvelopeDescriptor::EnvelopeDescriptor() : AMQPDescriptor() { }
/******************************************************************************/
amqp::internal::
EnvelopeDescriptor::EnvelopeDescriptor (
const std::string & symbol_,
int val_
) : AMQPDescriptor (symbol_, val_) {
}
/******************************************************************************/
uPtr<amqp::AMQPDescribed>
amqp::internal::
EnvelopeDescriptor::build (pn_data_t * data_) const {
DBG ("ENVELOPE" << std::endl); // NOLINT
validateAndNext(data_);
proton::auto_enter p (data_);
/*
* The actual blob... if this was java we would use the type symbols
* in the blob to look up serialisers in the cache... but we don't
* have any so we are actually going to need to use the schema
* which we parse *after* this to be able to read any data!
*/
std::string outerType = consumeBlob(data_);
pn_data_next (data_);
/*
* The schema
*/
auto schema = descriptors::dispatchDescribed<schema::Schema> (data_);
pn_data_next(data_);
/*
* The transforms schema
*/
// Skip for now
// dispatchDescribed (data_);
return std::make_unique<schema::Envelope> (schema::Envelope (schema, outerType));
}
/******************************************************************************/

View File

@ -0,0 +1,41 @@
#pragma once
#include <string>
#include "AMQPDescriptors.h"
/******************************************************************************
*
* Forward Class Declarations
*
******************************************************************************/
struct pn_data_t;
/******************************************************************************
*
* class amqp::internal::EnvelopeDescriptor
*
******************************************************************************/
namespace amqp::internal {
class EnvelopeDescriptor : public AMQPDescriptor {
public :
EnvelopeDescriptor();
EnvelopeDescriptor (const std::string &, int);
~EnvelopeDescriptor() final = default;
std::unique_ptr<AMQPDescribed> build (pn_data_t *) const override;
void read (
pn_data_t *,
std::stringstream &,
const AutoIndent &) const override;
};
}
/******************************************************************************/

View File

@ -0,0 +1,138 @@
#include "FieldDescriptor.h"
#include "debug.h"
#include "types.h"
#include "proton/proton_wrapper.h"
#include "amqp/schema/Field.h"
#include <sstream>
/******************************************************************************
*
* amqp::internal::FieldDescriptor
*
******************************************************************************/
amqp::internal::
FieldDescriptor::FieldDescriptor() : AMQPDescriptor() { }
/******************************************************************************/
amqp::internal::
FieldDescriptor::FieldDescriptor (
const std::string & symbol_,
int val_
) : AMQPDescriptor(symbol_, val_) {
}
/******************************************************************************/
uPtr<amqp::AMQPDescribed>
amqp::internal::
FieldDescriptor::build(pn_data_t * data_) const {
DBG ("FIELD" << std::endl); // NOLINT
validateAndNext(data_);
proton::auto_enter ae (data_);
/* name: String */
auto name = proton::get_string (data_);
pn_data_next (data_);
/* type: String */
auto type = proton::get_string (data_);
pn_data_next (data_);
/* requires: List<String> */
std::list<std::string> requires;
{
proton::auto_list_enter ale (data_);
while (pn_data_next(data_)) {
requires.push_back (proton::get_string(data_));
}
}
pn_data_next (data_);
/* default: String? */
auto def = proton::get_string (data_, true);
pn_data_next (data_);
/* label: String? */
auto label = proton::get_string (data_, true);
pn_data_next (data_);
/* mandatory: Boolean - copes with the Kotlin concept of nullability.
If something is mandatory then it cannot be null */
auto mandatory = proton::get_boolean (data_);
pn_data_next (data_);
/* multiple: Boolean */
auto multiple = proton::get_boolean(data_);
return std::make_unique<schema::Field> (
name, type, requires, def, label, mandatory, multiple);
}
/******************************************************************************/
void
amqp::internal::
FieldDescriptor::read (
pn_data_t * data_,
std::stringstream & ss_,
const AutoIndent & ai_
) const {
proton::is_list (data_);
proton::auto_list_enter ale (data_, true);
AutoIndent ai { ai_ };
ss_ << ai << "1/7] String: Name: "
<< proton::get_string ((pn_data_t *)proton::auto_next (data_))
<< std::endl;
ss_ << ai << "2/7] String: Type: "
<< proton::get_string ((pn_data_t *)proton::auto_next (data_))
<< std::endl;
{
proton::auto_list_enter ale2 (data_);
ss_ << ai << "3/7] List: Requires: elements " << ale2.elements()
<< std::endl;
AutoIndent ai2 { ai };
while (pn_data_next(data_)) {
ss_ << ai2 << proton::get_string (data_) << std::endl;
}
}
pn_data_next (data_);
proton::is_string (data_, true);
ss_ << ai << "4/7] String: Default: "
<< proton::get_string ((pn_data_t *)proton::auto_next (data_), true)
<< std::endl;
ss_ << ai << "5/7] String: Label: "
<< proton::get_string ((pn_data_t *)proton::auto_next (data_), true)
<< std::endl;
ss_ << ai << "6/7] Boolean: Mandatory: "
<< proton::get_boolean ((pn_data_t *)proton::auto_next (data_))
<< std::endl;
ss_ << ai << "7/7] Boolean: Multiple: "
<< proton::get_boolean ((pn_data_t *)proton::auto_next (data_))
<< std::endl;
}
/******************************************************************************/

View File

@ -0,0 +1,30 @@
#pragma once
/******************************************************************************/
#include "proton/codec.h"
#include "amqp/AMQPDescribed.h"
#include "amqp/descriptors/AMQPDescriptor.h"
/******************************************************************************/
namespace amqp::internal {
class FieldDescriptor : public AMQPDescriptor {
public :
FieldDescriptor();
FieldDescriptor (const std::string &, int);
~FieldDescriptor() final = default;
std::unique_ptr<AMQPDescribed> build (pn_data_t *) const override;
void read (
pn_data_t *,
std::stringstream &,
const AutoIndent &) const override;
};
}
/******************************************************************************/

View File

@ -0,0 +1,59 @@
#include "ObjectDescriptor.h"
#include "types.h"
#include "debug.h"
#include "proton/proton_wrapper.h"
#include "amqp/schema/Descriptor.h"
#include <sstream>
/******************************************************************************
*
* amqp::internal::ObjectDescriptor
*
******************************************************************************/
/**
*
*/
uPtr<amqp::AMQPDescribed>
amqp::internal::
ObjectDescriptor::build(pn_data_t * data_) const {
DBG ("DESCRIPTOR" << std::endl); // NOLINT
validateAndNext (data_);
proton::auto_enter p (data_);
auto symbol = proton::get_symbol<std::string> (data_);
return std::make_unique<schema::Descriptor> (symbol);
}
/******************************************************************************/
void
amqp::internal::
ObjectDescriptor::read (
pn_data_t * data_,
std::stringstream & ss_,
const AutoIndent & ai_
) const {
proton::is_list (data_);
{
AutoIndent ai { ai_ };
proton::auto_list_enter ale (data_);
pn_data_next(data_);
ss_ << ai << "1/2] "
<< proton::get_symbol<std::string>(
(pn_data_t *)proton::auto_next (data_))
<< std::endl;
ss_ << ai << "2/2] " << data_ << std::endl;
}
}
/******************************************************************************/

View File

@ -0,0 +1,35 @@
#pragma once
/******************************************************************************/
#include "amqp/descriptors/AMQPDescriptor.h"
/******************************************************************************/
struct pn_data_t;
/******************************************************************************/
namespace amqp::internal {
class ObjectDescriptor : public AMQPDescriptor {
public :
ObjectDescriptor() : AMQPDescriptor() { }
ObjectDescriptor(const std::string & symbol_, int val_)
: AMQPDescriptor(symbol_, val_)
{ }
~ObjectDescriptor() final = default;
std::unique_ptr<AMQPDescribed> build (pn_data_t *) const override;
void read (
pn_data_t *,
std::stringstream &,
const AutoIndent &) const override;
};
}
/******************************************************************************/

View File

@ -0,0 +1,98 @@
#include "RestrictedDescriptor.h"
#include "types.h"
#include "debug.h"
#include "amqp/schema/restricted-types/Restricted.h"
#include "amqp/descriptors/AMQPDescriptors.h"
#include <sstream>
/******************************************************************************
*
* Restricted types represent lists and maps
*
* NOTE: The Corda serialization scheme doesn't support all container classes
* as it has the requiremnt that iteration order be deterministic for purposes
* of signing over data.
*
* name : String
* label : String?
* provides : List<String>
* source : String
* descriptor : Descriptor
* choices : List<Choice>
*
******************************************************************************/
uPtr<amqp::AMQPDescribed>
amqp::internal::
RestrictedDescriptor::build (pn_data_t * data_) const {
DBG ("RESTRICTED" << std::endl); // NOLINT
validateAndNext(data_);
proton::auto_enter ae (data_);
auto name = proton::readAndNext<std::string>(data_);
auto label = proton::readAndNext<std::string>(data_, true);
std::vector<std::string> provides;
{
proton::auto_list_enter ae2 (data_);
while (pn_data_next(data_)) {
provides.push_back (proton::get_string (data_));
}
}
pn_data_next (data_);
auto source = proton::readAndNext<std::string> (data_);
auto descriptor = descriptors::dispatchDescribed<schema::Descriptor> (data_);
// SKIP the choices section **FOR NOW**
return schema::Restricted::make (descriptor, name,
label, provides, source);
}
/******************************************************************************/
void
amqp::internal::
RestrictedDescriptor::read (
pn_data_t * data_,
std::stringstream & ss_,
const AutoIndent & ai_
) const {
proton::is_list (data_);
proton::auto_enter ae (data_);
AutoIndent ai { ai_ };
ss_ << ai << "1] String: Name: "
<< proton::readAndNext<std::string> (data_)
<< std::endl;
ss_ << ai << "2] String: Label: "
<< proton::readAndNext<std::string> (data_, true)
<< std::endl;
ss_ << ai << "3] List: Provides: [ ";
{
proton::auto_list_enter ae2 (data_);
while (pn_data_next(data_)) {
ss_ << proton::get_string (data_) << " ";
}
ss_ << "]" << std::endl;
}
pn_data_next (data_);
ss_ << ai << "4] String: Source: "
<< proton::readAndNext<std::string> (data_)
<< std::endl;
ss_ << ai << "5] Descriptor:" << std::endl;
AMQPDescriptorRegistory[pn_data_type(data_)]->read (
(pn_data_t *)proton::auto_next(data_), ss_, AutoIndent { ai });
}
/******************************************************************************/

View File

@ -0,0 +1,34 @@
#pragma once
/******************************************************************************/
#include <string>
#include "amqp/descriptors/AMQPDescriptor.h"
/******************************************************************************/
namespace amqp::internal {
class RestrictedDescriptor : public AMQPDescriptor {
public :
RestrictedDescriptor() : AMQPDescriptor() { }
RestrictedDescriptor(const std::string & symbol_, int val_)
: AMQPDescriptor(symbol_, val_)
{ }
~RestrictedDescriptor() final = default;
std::unique_ptr<AMQPDescribed> build (pn_data_t *) const override;
void read (
pn_data_t *,
std::stringstream &,
const AutoIndent &) const override;
};
}
/******************************************************************************/

View File

@ -0,0 +1,93 @@
#include "SchemaDescriptor.h"
#include "types.h"
#include "debug.h"
#include "AMQPDescriptor.h"
#include "proton/codec.h"
#include "proton/proton_wrapper.h"
#include "amqp/AMQPDescribed.h"
#include "amqp/descriptors/AMQPDescriptors.h"
#include "amqp/schema/Schema.h"
#include "amqp/schema/OrderedTypeNotations.h"
#include "amqp/schema/AMQPTypeNotation.h"
#include <sstream>
/******************************************************************************/
amqp::internal::
SchemaDescriptor::SchemaDescriptor (
const std::string & symbol_,
int val_
) : AMQPDescriptor(symbol_, val_) {
}
/******************************************************************************/
uPtr<amqp::AMQPDescribed>
amqp::internal::
SchemaDescriptor::build (pn_data_t * data_) const {
DBG ("SCHEMA" << std::endl); // NOLINT
validateAndNext(data_);
schema::OrderedTypeNotations<schema::AMQPTypeNotation> schemas;
/*
* The Schema is stored as a list of lists of described objects
*/
{
proton::auto_list_enter ale (data_);
for (int i { 1 } ; pn_data_next(data_) ; ++i) {
DBG (" " << i << "/" << ale.elements() << std::endl); // NOLINT
proton::auto_list_enter ale2 (data_);
while (pn_data_next(data_)) {
schemas.insert (
descriptors::dispatchDescribed<schema::AMQPTypeNotation>(data_));
}
}
}
return std::make_unique<schema::Schema> (std::move (schemas));
}
/******************************************************************************/
void
amqp::internal::
SchemaDescriptor::read (
pn_data_t * data_,
std::stringstream & ss_,
const AutoIndent & ai_
) const {
proton::is_list (data_);
{
AutoIndent ai { ai_ };
proton::auto_list_enter ale (data_);
for (int i { 1 } ; pn_data_next (data_) ; ++i) {
proton::is_list (data_);
ss_ << ai << i << "/" << ale.elements() <<"]";
AutoIndent ai2 { ai };
proton::auto_list_enter ale2 (data_);
ss_ << " list: entries: " << ale2.elements() << std::endl;
for (int j { 1 } ; pn_data_next (data_) ; ++j) {
ss_ << ai2 << i << ":" << j << "/" << ale2.elements()
<< "] " << std::endl;
AMQPDescriptorRegistory[pn_data_type(data_)]->read (
data_, ss_,
AutoIndent { ai2 });
}
}
}
}
/******************************************************************************/

View File

@ -0,0 +1,29 @@
#pragma once
#include "amqp/descriptors/AMQPDescriptor.h"
/******************************************************************************/
struct pn_data_t;
/******************************************************************************/
namespace amqp::internal {
class SchemaDescriptor : public AMQPDescriptor {
public :
SchemaDescriptor() = default;
SchemaDescriptor (const std::string &, int);
~SchemaDescriptor() final = default;
std::unique_ptr<AMQPDescribed> build (pn_data_t *) const override;
void read (
pn_data_t *,
std::stringstream &,
const AutoIndent &) const override;
};
}
/******************************************************************************/

View File

@ -31,7 +31,7 @@ namespace amqp::internal::reader {
std::any read (pn_data_t *) const override;
std::string readString(pn_data_t *) const override;
std::string readString (pn_data_t *) const override;
std::unique_ptr<amqp::reader::IValue> dump(
const std::string &,

View File

@ -11,7 +11,7 @@
std::ostream&
operator << (std::ostream& stream, pn_data_t * data_) {
auto type = pn_data_type(data_);
auto type = pn_data_type (data_);
stream << std::setw (2) << type << " " << pn_type_name (type);
switch (type) {
@ -89,14 +89,14 @@ proton::is_ulong (pn_data_t * data_) {
auto t = pn_data_type(data_);
if (t != PN_ULONG) {
std::stringstream ss;
ss << "Expected an unsigned long but recieved " << pn_type_name (t);
ss << "Expected an unsigned long but received " << pn_type_name (t);
throw std::runtime_error (ss.str());
}
}
/******************************************************************************/
inline void
void
proton::is_symbol (pn_data_t * data_) {
if (pn_data_type(data_) != PN_SYMBOL) {
throw std::runtime_error ("Expected an unsigned long");
@ -114,7 +114,7 @@ proton::is_list (pn_data_t * data_) {
/******************************************************************************/
inline void
void
proton::is_string (pn_data_t * data_, bool allowNull) {
if (pn_data_type(data_) != PN_STRING) {
if (allowNull && pn_data_type(data_) != PN_NULL) {
@ -141,9 +141,9 @@ proton::get_string (pn_data_t * data_, bool allowNull) {
template<>
std::string
proton::get_symbol<std::string> (pn_data_t * data_) {
is_symbol (data_);
auto symbol = pn_data_get_symbol(data_);
return std::string (symbol.start, symbol.size);
is_symbol (data_);
auto symbol = pn_data_get_symbol(data_);
return std::string (symbol.start, symbol.size);
}
template<>
@ -173,8 +173,8 @@ proton::
auto_enter::auto_enter (pn_data_t * data_, bool next_)
: m_data (data_)
{
proton::pn_data_enter(m_data);
if (next_) pn_data_next(m_data);
proton::pn_data_enter (m_data);
if (next_) pn_data_next (m_data);
}
/******************************************************************************/
@ -224,7 +224,7 @@ auto_list_enter::auto_list_enter (pn_data_t * data_, bool next_)
proton::
auto_list_enter::~auto_list_enter() {
pn_data_exit(m_data);
pn_data_exit (m_data);
}
/******************************************************************************/
@ -321,3 +321,16 @@ readAndNext<long> (
/******************************************************************************/
template<>
u_long
proton::
readAndNext<u_long > (
pn_data_t * data_,
bool tolerateDeviance_
) {
long rtn = pn_data_get_ulong (data_);
pn_data_next(data_);
return rtn;
}
/******************************************************************************/

View File

@ -46,7 +46,7 @@ namespace proton {
pn_data_t * m_data;
public :
auto_enter (pn_data_t *, bool next_ = false);
explicit auto_enter (pn_data_t *, bool next_ = false);
~auto_enter();
};
@ -55,9 +55,13 @@ namespace proton {
pn_data_t * m_data;
public :
auto_next (pn_data_t *);
explicit auto_next (pn_data_t *);
auto_next (const auto_next &) = delete;
explicit operator pn_data_t *() {
return m_data;
}
~auto_next();
};
@ -67,7 +71,7 @@ namespace proton {
pn_data_t * m_data;
public :
auto_list_enter (pn_data_t *, bool next_ = false);
explicit auto_list_enter (pn_data_t *, bool next_ = false);
~auto_list_enter();
size_t elements() const;
@ -81,7 +85,7 @@ namespace proton {
template<typename T>
T
readAndNext (pn_data_t * data_, bool tolerateDeviance_ = false) {
readAndNext (pn_data_t *, bool tolerateDeviance_ = false) {
return T{};
}

View File

@ -29,6 +29,7 @@ include 'webserver'
include 'webserver:webcapsule'
include 'experimental'
include 'experimental:avalanche'
include 'experimental:blobwriter'
include 'experimental:quasar-hook'
include 'experimental:corda-utils'
include 'experimental:nodeinfo'