Implementation of JSON Streaming Parser
This change will introduce a streaming parser capability to Haiku. The existing functionality of writing the JSON data to a BMessage in-memory model is retained. The new parser implements a SAX-style listener based interface where the listener accepts parse events. Unit tests have been supplied for the JSON parser as well.
This commit is contained in:
parent
c72855f6c0
commit
1f6b57a5d2
@ -39,6 +39,11 @@ for architectureObject in [ MultiArchSubDirSetup ] {
|
||||
HashString.cpp
|
||||
IconButton.cpp
|
||||
IconView.cpp
|
||||
JsonWriter.cpp
|
||||
JsonEventListener.cpp
|
||||
JsonMessageWriter.cpp
|
||||
JsonTextWriter.cpp
|
||||
JsonEvent.cpp
|
||||
Json.cpp
|
||||
Keymap.cpp
|
||||
LongAndDragTrackingFilter.cpp
|
||||
|
File diff suppressed because it is too large
Load Diff
127
src/kits/shared/JsonEvent.cpp
Normal file
127
src/kits/shared/JsonEvent.cpp
Normal file
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright 2017, Andrew Lindesay <apl@lindesay.co.nz>
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#include "JsonEvent.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <String.h>
|
||||
|
||||
|
||||
BJsonEvent::BJsonEvent(json_event_type eventType, const char* content)
|
||||
:
|
||||
fEventType(eventType),
|
||||
fContent(content),
|
||||
fOwnedContent(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
BJsonEvent::BJsonEvent(const char* content)
|
||||
:
|
||||
fEventType(B_JSON_STRING),
|
||||
fContent(content),
|
||||
fOwnedContent(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
BJsonEvent::BJsonEvent(double content) {
|
||||
fEventType = B_JSON_NUMBER;
|
||||
fContent = NULL;
|
||||
|
||||
int actualLength = snprintf(0, 0, "%f", content) + 1;
|
||||
char* buffer = (char*) malloc(sizeof(char) * actualLength);
|
||||
|
||||
if (buffer == NULL) {
|
||||
fprintf(stderr, "memory exhaustion\n");
|
||||
// given the risk, this is the only sensible thing to do here.
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
sprintf(buffer, "%f", content);
|
||||
fOwnedContent = buffer;
|
||||
}
|
||||
|
||||
|
||||
BJsonEvent::BJsonEvent(int64 content) {
|
||||
fEventType = B_JSON_NUMBER;
|
||||
fContent = NULL;
|
||||
fOwnedContent = NULL;
|
||||
|
||||
static const char* zeroValue = "0";
|
||||
static const char* oneValue = "1";
|
||||
|
||||
switch (content) {
|
||||
case 0:
|
||||
fContent = zeroValue;
|
||||
break;
|
||||
case 1:
|
||||
fContent = oneValue;
|
||||
break;
|
||||
default:
|
||||
{
|
||||
int actualLength = snprintf(0, 0, "%" B_PRId64, content) + 1;
|
||||
char* buffer = (char*) malloc(sizeof(char) * actualLength);
|
||||
|
||||
if (buffer == NULL) {
|
||||
fprintf(stderr, "memory exhaustion\n");
|
||||
// given the risk, this is the only sensible thing to do
|
||||
// here.
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
sprintf(buffer, "%" B_PRId64, content);
|
||||
fOwnedContent = buffer;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BJsonEvent::BJsonEvent(json_event_type eventType)
|
||||
:
|
||||
fEventType(eventType),
|
||||
fContent(NULL),
|
||||
fOwnedContent(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
BJsonEvent::~BJsonEvent()
|
||||
{
|
||||
if (NULL != fOwnedContent)
|
||||
free(fOwnedContent);
|
||||
}
|
||||
|
||||
|
||||
json_event_type
|
||||
BJsonEvent::EventType() const
|
||||
{
|
||||
return fEventType;
|
||||
}
|
||||
|
||||
|
||||
const char*
|
||||
BJsonEvent::Content() const
|
||||
{
|
||||
if (NULL != fOwnedContent)
|
||||
return fOwnedContent;
|
||||
return fContent;
|
||||
}
|
||||
|
||||
|
||||
double
|
||||
BJsonEvent::ContentDouble() const
|
||||
{
|
||||
return strtod(Content(), NULL);
|
||||
}
|
||||
|
||||
|
||||
int64
|
||||
BJsonEvent::ContentInteger() const
|
||||
{
|
||||
return strtoll(Content(), NULL, 10);
|
||||
}
|
16
src/kits/shared/JsonEventListener.cpp
Normal file
16
src/kits/shared/JsonEventListener.cpp
Normal file
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright 2017, Andrew Lindesay <apl@lindesay.co.nz>
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include "JsonEventListener.h"
|
||||
|
||||
|
||||
BJsonEventListener::BJsonEventListener()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
BJsonEventListener::~BJsonEventListener()
|
||||
{
|
||||
}
|
520
src/kits/shared/JsonMessageWriter.cpp
Normal file
520
src/kits/shared/JsonMessageWriter.cpp
Normal file
@ -0,0 +1,520 @@
|
||||
/*
|
||||
* Copyright 2017, Andrew Lindesay <apl@lindesay.co.nz>
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include "JsonMessageWriter.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
namespace BPrivate {
|
||||
|
||||
/*! The class and sub-classes of it are used as a stack internal to the
|
||||
BJsonMessageWriter class. As the JSON is parsed, the stack of these
|
||||
internal listeners follows the stack of the JSON parsing in terms of
|
||||
containers; arrays and objects.
|
||||
*/
|
||||
|
||||
class BStackedMessageEventListener : public BJsonEventListener {
|
||||
public:
|
||||
BStackedMessageEventListener(
|
||||
BJsonMessageWriter* writer,
|
||||
BStackedMessageEventListener* parent,
|
||||
uint32 messageWhat);
|
||||
BStackedMessageEventListener(
|
||||
BJsonMessageWriter* writer,
|
||||
BStackedMessageEventListener* parent,
|
||||
BMessage* message);
|
||||
~BStackedMessageEventListener();
|
||||
|
||||
bool Handle(const BJsonEvent& event);
|
||||
void HandleError(status_t status, int32 line,
|
||||
const char* message);
|
||||
void Complete();
|
||||
|
||||
void AddMessage(BMessage* value);
|
||||
|
||||
status_t ErrorStatus();
|
||||
virtual const char* NextItemName() = 0;
|
||||
|
||||
BStackedMessageEventListener*
|
||||
Parent();
|
||||
|
||||
protected:
|
||||
void AddBool(bool value);
|
||||
void AddNull();
|
||||
void AddDouble(double value);
|
||||
void AddString(const char* value);
|
||||
|
||||
virtual bool WillAdd();
|
||||
virtual void DidAdd();
|
||||
|
||||
void SetStackedListenerOnWriter(
|
||||
BStackedMessageEventListener*
|
||||
stackedListener);
|
||||
|
||||
BJsonMessageWriter* fWriter;
|
||||
bool fOwnsMessage;
|
||||
BStackedMessageEventListener
|
||||
*fParent;
|
||||
BMessage* fMessage;
|
||||
};
|
||||
|
||||
|
||||
class BStackedArrayMessageEventListener : public BStackedMessageEventListener {
|
||||
public:
|
||||
BStackedArrayMessageEventListener(
|
||||
BJsonMessageWriter* writer,
|
||||
BStackedMessageEventListener* parent);
|
||||
BStackedArrayMessageEventListener(
|
||||
BJsonMessageWriter* writer,
|
||||
BStackedMessageEventListener* parent,
|
||||
BMessage* message);
|
||||
~BStackedArrayMessageEventListener();
|
||||
|
||||
bool Handle(const BJsonEvent& event);
|
||||
|
||||
const char* NextItemName();
|
||||
|
||||
protected:
|
||||
void DidAdd();
|
||||
|
||||
private:
|
||||
uint32 fCount;
|
||||
BString fNextItemName;
|
||||
|
||||
};
|
||||
|
||||
|
||||
class BStackedObjectMessageEventListener : public BStackedMessageEventListener {
|
||||
public:
|
||||
BStackedObjectMessageEventListener(
|
||||
BJsonMessageWriter* writer,
|
||||
BStackedMessageEventListener* parent);
|
||||
BStackedObjectMessageEventListener(
|
||||
BJsonMessageWriter* writer,
|
||||
BStackedMessageEventListener* parent,
|
||||
BMessage* message);
|
||||
~BStackedObjectMessageEventListener();
|
||||
|
||||
bool Handle(const BJsonEvent& event);
|
||||
|
||||
const char* NextItemName();
|
||||
|
||||
protected:
|
||||
bool WillAdd();
|
||||
void DidAdd();
|
||||
private:
|
||||
BString fNextItemName;
|
||||
};
|
||||
|
||||
} // namespace BPrivate
|
||||
|
||||
using BPrivate::BStackedMessageEventListener;
|
||||
using BPrivate::BStackedArrayMessageEventListener;
|
||||
using BPrivate::BStackedObjectMessageEventListener;
|
||||
|
||||
|
||||
// #pragma mark - BStackedMessageEventListener
|
||||
|
||||
|
||||
BStackedMessageEventListener::BStackedMessageEventListener(
|
||||
BJsonMessageWriter* writer,
|
||||
BStackedMessageEventListener* parent,
|
||||
uint32 messageWhat)
|
||||
{
|
||||
fWriter = writer;
|
||||
fParent = parent;
|
||||
fOwnsMessage = true;
|
||||
fMessage = new BMessage(messageWhat);
|
||||
}
|
||||
|
||||
|
||||
BStackedMessageEventListener::BStackedMessageEventListener(
|
||||
BJsonMessageWriter* writer,
|
||||
BStackedMessageEventListener* parent,
|
||||
BMessage* message)
|
||||
{
|
||||
fWriter = writer;
|
||||
fParent = parent;
|
||||
fOwnsMessage = false;
|
||||
fMessage = message;
|
||||
}
|
||||
|
||||
|
||||
BStackedMessageEventListener::~BStackedMessageEventListener()
|
||||
{
|
||||
if (fOwnsMessage)
|
||||
delete fMessage;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
BStackedMessageEventListener::Handle(const BJsonEvent& event)
|
||||
{
|
||||
if (fWriter->ErrorStatus() != B_OK)
|
||||
return false;
|
||||
|
||||
switch (event.EventType()) {
|
||||
|
||||
case B_JSON_NUMBER:
|
||||
AddDouble(event.ContentDouble());
|
||||
break;
|
||||
|
||||
case B_JSON_STRING:
|
||||
AddString(event.Content());
|
||||
break;
|
||||
|
||||
case B_JSON_TRUE:
|
||||
AddBool(true);
|
||||
break;
|
||||
|
||||
case B_JSON_FALSE:
|
||||
AddBool(false);
|
||||
break;
|
||||
|
||||
case B_JSON_NULL:
|
||||
AddNull();
|
||||
break;
|
||||
|
||||
case B_JSON_OBJECT_START:
|
||||
SetStackedListenerOnWriter(new BStackedObjectMessageEventListener(
|
||||
fWriter, this));
|
||||
break;
|
||||
|
||||
case B_JSON_ARRAY_START:
|
||||
SetStackedListenerOnWriter(new BStackedArrayMessageEventListener(
|
||||
fWriter, this));
|
||||
break;
|
||||
|
||||
default:
|
||||
HandleError(B_NOT_ALLOWED, JSON_EVENT_LISTENER_ANY_LINE,
|
||||
"unexpected type of json item to add to container");
|
||||
return false;
|
||||
}
|
||||
|
||||
return ErrorStatus() == B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BStackedMessageEventListener::HandleError(status_t status, int32 line,
|
||||
const char* message)
|
||||
{
|
||||
fWriter->HandleError(status, line, message);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BStackedMessageEventListener::Complete()
|
||||
{
|
||||
// illegal state.
|
||||
HandleError(JSON_EVENT_LISTENER_ANY_LINE, B_NOT_ALLOWED,
|
||||
"Complete() called on stacked message listener");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BStackedMessageEventListener::AddMessage(BMessage* message)
|
||||
{
|
||||
if (WillAdd()) {
|
||||
fMessage->AddMessage(NextItemName(), message);
|
||||
DidAdd();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BStackedMessageEventListener::ErrorStatus()
|
||||
{
|
||||
return fWriter->ErrorStatus();
|
||||
}
|
||||
|
||||
|
||||
BStackedMessageEventListener*
|
||||
BStackedMessageEventListener::Parent()
|
||||
{
|
||||
return fParent;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BStackedMessageEventListener::AddBool(bool value)
|
||||
{
|
||||
if (WillAdd()) {
|
||||
fMessage->AddBool(NextItemName(), value);
|
||||
DidAdd();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BStackedMessageEventListener::AddNull()
|
||||
{
|
||||
if (WillAdd()) {
|
||||
fMessage->AddPointer(NextItemName(), (void*)NULL);
|
||||
DidAdd();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BStackedMessageEventListener::AddDouble(double value)
|
||||
{
|
||||
if (WillAdd()) {
|
||||
fMessage->AddDouble(NextItemName(), value);
|
||||
DidAdd();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BStackedMessageEventListener::AddString(const char* value)
|
||||
{
|
||||
if (WillAdd()) {
|
||||
fMessage->AddString(NextItemName(), value);
|
||||
DidAdd();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
BStackedMessageEventListener::WillAdd()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BStackedMessageEventListener::DidAdd()
|
||||
{
|
||||
// noop - present for overriding
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BStackedMessageEventListener::SetStackedListenerOnWriter(
|
||||
BStackedMessageEventListener* stackedListener)
|
||||
{
|
||||
fWriter->SetStackedListener(stackedListener);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - BStackedArrayMessageEventListener
|
||||
|
||||
|
||||
BStackedArrayMessageEventListener::BStackedArrayMessageEventListener(
|
||||
BJsonMessageWriter* writer,
|
||||
BStackedMessageEventListener* parent)
|
||||
: BStackedMessageEventListener(writer, parent, B_JSON_MESSAGE_WHAT_ARRAY)
|
||||
{
|
||||
fCount = 0;
|
||||
}
|
||||
|
||||
|
||||
BStackedArrayMessageEventListener::BStackedArrayMessageEventListener(
|
||||
BJsonMessageWriter* writer,
|
||||
BStackedMessageEventListener* parent,
|
||||
BMessage* message)
|
||||
: BStackedMessageEventListener(writer, parent, message)
|
||||
{
|
||||
message->what = B_JSON_MESSAGE_WHAT_ARRAY;
|
||||
fCount = 0;
|
||||
}
|
||||
|
||||
|
||||
BStackedArrayMessageEventListener::~BStackedArrayMessageEventListener()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
BStackedArrayMessageEventListener::Handle(const BJsonEvent& event)
|
||||
{
|
||||
if (fWriter->ErrorStatus() != B_OK)
|
||||
return false;
|
||||
|
||||
switch (event.EventType()) {
|
||||
case B_JSON_ARRAY_END:
|
||||
if (fParent != NULL)
|
||||
fParent->AddMessage(fMessage);
|
||||
SetStackedListenerOnWriter(fParent);
|
||||
delete this;
|
||||
break;
|
||||
|
||||
default:
|
||||
return BStackedMessageEventListener::Handle(event);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
const char*
|
||||
BStackedArrayMessageEventListener::NextItemName()
|
||||
{
|
||||
fNextItemName.SetToFormat("%" B_PRIu32, fCount);
|
||||
return fNextItemName.String();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BStackedArrayMessageEventListener::DidAdd()
|
||||
{
|
||||
BStackedMessageEventListener::DidAdd();
|
||||
fCount++;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - BStackedObjectMessageEventListener
|
||||
|
||||
|
||||
BStackedObjectMessageEventListener::BStackedObjectMessageEventListener(
|
||||
BJsonMessageWriter* writer,
|
||||
BStackedMessageEventListener* parent)
|
||||
: BStackedMessageEventListener(writer, parent, B_JSON_MESSAGE_WHAT_OBJECT)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
BStackedObjectMessageEventListener::BStackedObjectMessageEventListener(
|
||||
BJsonMessageWriter* writer,
|
||||
BStackedMessageEventListener* parent,
|
||||
BMessage* message)
|
||||
: BStackedMessageEventListener(writer, parent, message)
|
||||
{
|
||||
message->what = B_JSON_MESSAGE_WHAT_OBJECT;
|
||||
}
|
||||
|
||||
|
||||
BStackedObjectMessageEventListener::~BStackedObjectMessageEventListener()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
BStackedObjectMessageEventListener::Handle(const BJsonEvent& event)
|
||||
{
|
||||
if (fWriter->ErrorStatus() != B_OK)
|
||||
return false;
|
||||
|
||||
switch (event.EventType()) {
|
||||
case B_JSON_OBJECT_END:
|
||||
if (fParent != NULL)
|
||||
fParent->AddMessage(fMessage);
|
||||
SetStackedListenerOnWriter(fParent);
|
||||
delete this;
|
||||
break;
|
||||
|
||||
case B_JSON_OBJECT_NAME:
|
||||
fNextItemName.SetTo(event.Content());
|
||||
break;
|
||||
|
||||
default:
|
||||
return BStackedMessageEventListener::Handle(event);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
const char*
|
||||
BStackedObjectMessageEventListener::NextItemName()
|
||||
{
|
||||
return fNextItemName.String();
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
BStackedObjectMessageEventListener::WillAdd()
|
||||
{
|
||||
if (0 == fNextItemName.Length()) {
|
||||
HandleError(B_NOT_ALLOWED, JSON_EVENT_LISTENER_ANY_LINE,
|
||||
"missing name for adding value into an object");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BStackedObjectMessageEventListener::DidAdd()
|
||||
{
|
||||
BStackedMessageEventListener::DidAdd();
|
||||
fNextItemName.SetTo("", 0);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - BJsonMessageWriter
|
||||
|
||||
|
||||
BJsonMessageWriter::BJsonMessageWriter(BMessage& message)
|
||||
{
|
||||
fTopLevelMessage = &message;
|
||||
fStackedListener = NULL;
|
||||
}
|
||||
|
||||
|
||||
BJsonMessageWriter::~BJsonMessageWriter()
|
||||
{
|
||||
BStackedMessageEventListener* listener = fStackedListener;
|
||||
|
||||
while (listener != NULL) {
|
||||
BStackedMessageEventListener* nextListener = listener->Parent();
|
||||
delete listener;
|
||||
listener = nextListener;
|
||||
}
|
||||
|
||||
fStackedListener = NULL;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
BJsonMessageWriter::Handle(const BJsonEvent& event)
|
||||
{
|
||||
if (fErrorStatus != B_OK)
|
||||
return false;
|
||||
|
||||
if (fStackedListener != NULL)
|
||||
return fStackedListener->Handle(event);
|
||||
else {
|
||||
switch(event.EventType()) {
|
||||
case B_JSON_OBJECT_START:
|
||||
SetStackedListener(new BStackedObjectMessageEventListener(
|
||||
this, NULL, fTopLevelMessage));
|
||||
break;
|
||||
|
||||
case B_JSON_ARRAY_START:
|
||||
fTopLevelMessage->what = B_JSON_MESSAGE_WHAT_ARRAY;
|
||||
SetStackedListener(new BStackedArrayMessageEventListener(
|
||||
this, NULL, fTopLevelMessage));
|
||||
break;
|
||||
|
||||
default:
|
||||
HandleError(B_NOT_ALLOWED, JSON_EVENT_LISTENER_ANY_LINE,
|
||||
"a message object can only handle an object or an array"
|
||||
"at the top level");
|
||||
return false;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return true; // keep going
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BJsonMessageWriter::Complete()
|
||||
{
|
||||
if (fStackedListener != NULL) {
|
||||
HandleError(B_BAD_DATA, JSON_EVENT_LISTENER_ANY_LINE,
|
||||
"unexpected end of input data processing structure");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BJsonMessageWriter::SetStackedListener(
|
||||
BStackedMessageEventListener* listener)
|
||||
{
|
||||
fStackedListener = listener;
|
||||
}
|
697
src/kits/shared/JsonTextWriter.cpp
Normal file
697
src/kits/shared/JsonTextWriter.cpp
Normal file
@ -0,0 +1,697 @@
|
||||
/*
|
||||
* Copyright 2017, Andrew Lindesay <apl@lindesay.co.nz>
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include "JsonTextWriter.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <UnicodeChar.h>
|
||||
|
||||
|
||||
namespace BPrivate {
|
||||
|
||||
|
||||
static bool
|
||||
b_json_is_7bit_clean(uint8 c)
|
||||
{
|
||||
return c >= 0x20 && c < 0x7f;
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
b_json_is_illegal(uint8 c) {
|
||||
return c < 0x20 || c == 0x7f;
|
||||
}
|
||||
|
||||
|
||||
static const char*
|
||||
b_json_simple_esc_sequence(char c)
|
||||
{
|
||||
switch (c) {
|
||||
case '"':
|
||||
return "\\\"";
|
||||
case '\\':
|
||||
return "\\\\";
|
||||
case '/':
|
||||
return "\\/";
|
||||
case '\b':
|
||||
return "\\b";
|
||||
case '\f':
|
||||
return "\\f";
|
||||
case '\n':
|
||||
return "\\n";
|
||||
case '\r':
|
||||
return "\\r";
|
||||
case '\t':
|
||||
return "\\t";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*! The class and sub-classes of it are used as a stack internal to the
|
||||
BJsonTextWriter class. As the JSON is parsed, the stack of these
|
||||
internal listeners follows the stack of the JSON parsing in terms of
|
||||
containers; arrays and objects.
|
||||
*/
|
||||
|
||||
class BJsonTextWriterStackedEventListener : public BJsonEventListener {
|
||||
public:
|
||||
BJsonTextWriterStackedEventListener(
|
||||
BJsonTextWriter* writer,
|
||||
BJsonTextWriterStackedEventListener* parent);
|
||||
~BJsonTextWriterStackedEventListener();
|
||||
|
||||
bool Handle(const BJsonEvent& event);
|
||||
void HandleError(status_t status, int32 line,
|
||||
const char* message);
|
||||
void Complete();
|
||||
|
||||
status_t ErrorStatus();
|
||||
|
||||
BJsonTextWriterStackedEventListener*
|
||||
Parent();
|
||||
|
||||
protected:
|
||||
|
||||
status_t StreamNumberNode(const BJsonEvent& event);
|
||||
|
||||
status_t StreamStringVerbatim(const char* string);
|
||||
status_t StreamStringVerbatim(const char* string,
|
||||
off_t offset, size_t length);
|
||||
|
||||
status_t StreamStringEncoded(const char* string);
|
||||
status_t StreamStringEncoded(const char* string,
|
||||
off_t offset, size_t length);
|
||||
|
||||
status_t StreamQuotedEncodedString(const char* string);
|
||||
status_t StreamQuotedEncodedString(const char* string,
|
||||
off_t offset, size_t length);
|
||||
|
||||
status_t StreamChar(char c);
|
||||
|
||||
virtual bool WillAdd();
|
||||
virtual void DidAdd();
|
||||
|
||||
void SetStackedListenerOnWriter(
|
||||
BJsonTextWriterStackedEventListener*
|
||||
stackedListener);
|
||||
|
||||
BJsonTextWriter*
|
||||
fWriter;
|
||||
BJsonTextWriterStackedEventListener*
|
||||
fParent;
|
||||
uint32 fCount;
|
||||
|
||||
};
|
||||
|
||||
|
||||
class BJsonTextWriterArrayStackedEventListener
|
||||
: public BJsonTextWriterStackedEventListener {
|
||||
public:
|
||||
BJsonTextWriterArrayStackedEventListener(
|
||||
BJsonTextWriter* writer,
|
||||
BJsonTextWriterStackedEventListener* parent);
|
||||
~BJsonTextWriterArrayStackedEventListener();
|
||||
|
||||
bool Handle(const BJsonEvent& event);
|
||||
|
||||
protected:
|
||||
bool WillAdd();
|
||||
};
|
||||
|
||||
|
||||
class BJsonTextWriterObjectStackedEventListener
|
||||
: public BJsonTextWriterStackedEventListener {
|
||||
public:
|
||||
BJsonTextWriterObjectStackedEventListener(
|
||||
BJsonTextWriter* writer,
|
||||
BJsonTextWriterStackedEventListener* parent);
|
||||
~BJsonTextWriterObjectStackedEventListener();
|
||||
|
||||
bool Handle(const BJsonEvent& event);
|
||||
};
|
||||
|
||||
} // namespace BPrivate
|
||||
|
||||
|
||||
using BPrivate::BJsonTextWriterStackedEventListener;
|
||||
using BPrivate::BJsonTextWriterArrayStackedEventListener;
|
||||
using BPrivate::BJsonTextWriterObjectStackedEventListener;
|
||||
|
||||
|
||||
// #pragma mark - BJsonTextWriterStackedEventListener
|
||||
|
||||
|
||||
BJsonTextWriterStackedEventListener::BJsonTextWriterStackedEventListener(
|
||||
BJsonTextWriter* writer,
|
||||
BJsonTextWriterStackedEventListener* parent)
|
||||
{
|
||||
fWriter = writer;
|
||||
fParent = parent;
|
||||
fCount = 0;
|
||||
}
|
||||
|
||||
|
||||
BJsonTextWriterStackedEventListener::~BJsonTextWriterStackedEventListener()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
BJsonTextWriterStackedEventListener::Handle(const BJsonEvent& event)
|
||||
{
|
||||
status_t writeResult = B_OK;
|
||||
|
||||
if (fWriter->ErrorStatus() != B_OK)
|
||||
return false;
|
||||
|
||||
switch (event.EventType()) {
|
||||
|
||||
case B_JSON_NUMBER:
|
||||
case B_JSON_STRING:
|
||||
case B_JSON_TRUE:
|
||||
case B_JSON_FALSE:
|
||||
case B_JSON_NULL:
|
||||
case B_JSON_OBJECT_START:
|
||||
case B_JSON_ARRAY_START:
|
||||
if (!WillAdd())
|
||||
return false;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (event.EventType()) {
|
||||
|
||||
case B_JSON_NUMBER:
|
||||
writeResult = StreamNumberNode(event);
|
||||
break;
|
||||
|
||||
case B_JSON_STRING:
|
||||
writeResult = StreamQuotedEncodedString(event.Content());
|
||||
break;
|
||||
|
||||
case B_JSON_TRUE:
|
||||
writeResult = StreamStringVerbatim("true", 0, 4);
|
||||
break;
|
||||
|
||||
case B_JSON_FALSE:
|
||||
writeResult = StreamStringVerbatim("false", 0, 5);
|
||||
break;
|
||||
|
||||
case B_JSON_NULL:
|
||||
writeResult = StreamStringVerbatim("null", 0, 4);
|
||||
break;
|
||||
|
||||
case B_JSON_OBJECT_START:
|
||||
writeResult = StreamChar('{');
|
||||
|
||||
if (writeResult == B_OK) {
|
||||
SetStackedListenerOnWriter(
|
||||
new BJsonTextWriterObjectStackedEventListener(fWriter, this));
|
||||
}
|
||||
break;
|
||||
|
||||
case B_JSON_ARRAY_START:
|
||||
writeResult = StreamChar('[');
|
||||
|
||||
if (writeResult == B_OK) {
|
||||
SetStackedListenerOnWriter(
|
||||
new BJsonTextWriterArrayStackedEventListener(fWriter, this));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
HandleError(B_NOT_ALLOWED, JSON_EVENT_LISTENER_ANY_LINE,
|
||||
"unexpected type of json item to add to container");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (writeResult == B_OK)
|
||||
DidAdd();
|
||||
else {
|
||||
HandleError(writeResult, JSON_EVENT_LISTENER_ANY_LINE,
|
||||
"error writing output");
|
||||
}
|
||||
|
||||
return ErrorStatus() == B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BJsonTextWriterStackedEventListener::HandleError(status_t status, int32 line,
|
||||
const char* message)
|
||||
{
|
||||
fWriter->HandleError(status, line, message);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BJsonTextWriterStackedEventListener::Complete()
|
||||
{
|
||||
// illegal state.
|
||||
HandleError(JSON_EVENT_LISTENER_ANY_LINE, B_NOT_ALLOWED,
|
||||
"Complete() called on stacked message listener");
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BJsonTextWriterStackedEventListener::ErrorStatus()
|
||||
{
|
||||
return fWriter->ErrorStatus();
|
||||
}
|
||||
|
||||
|
||||
BJsonTextWriterStackedEventListener*
|
||||
BJsonTextWriterStackedEventListener::Parent()
|
||||
{
|
||||
return fParent;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BJsonTextWriterStackedEventListener::StreamNumberNode(const BJsonEvent& event)
|
||||
{
|
||||
return fWriter->StreamNumberNode(event);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BJsonTextWriterStackedEventListener::StreamStringVerbatim(const char* string)
|
||||
{
|
||||
return fWriter->StreamStringVerbatim(string);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BJsonTextWriterStackedEventListener::StreamStringVerbatim(const char* string,
|
||||
off_t offset, size_t length)
|
||||
{
|
||||
return fWriter->StreamStringVerbatim(string, offset, length);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BJsonTextWriterStackedEventListener::StreamStringEncoded(const char* string)
|
||||
{
|
||||
return fWriter->StreamStringEncoded(string);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BJsonTextWriterStackedEventListener::StreamStringEncoded(const char* string,
|
||||
off_t offset, size_t length)
|
||||
{
|
||||
return fWriter->StreamStringEncoded(string, offset, length);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BJsonTextWriterStackedEventListener::StreamQuotedEncodedString(const char* string)
|
||||
{
|
||||
return fWriter->StreamQuotedEncodedString(string);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BJsonTextWriterStackedEventListener::StreamQuotedEncodedString(const char* string,
|
||||
off_t offset, size_t length)
|
||||
{
|
||||
return fWriter->StreamQuotedEncodedString(string, offset, length);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BJsonTextWriterStackedEventListener::StreamChar(char c)
|
||||
{
|
||||
return fWriter->StreamChar(c);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
BJsonTextWriterStackedEventListener::WillAdd()
|
||||
{
|
||||
return true; // carry on
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BJsonTextWriterStackedEventListener::DidAdd()
|
||||
{
|
||||
fCount++;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BJsonTextWriterStackedEventListener::SetStackedListenerOnWriter(
|
||||
BJsonTextWriterStackedEventListener* stackedListener)
|
||||
{
|
||||
fWriter->SetStackedListener(stackedListener);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - BJsonTextWriterArrayStackedEventListener
|
||||
|
||||
|
||||
BJsonTextWriterArrayStackedEventListener::BJsonTextWriterArrayStackedEventListener(
|
||||
BJsonTextWriter* writer,
|
||||
BJsonTextWriterStackedEventListener* parent)
|
||||
: BJsonTextWriterStackedEventListener(writer, parent)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
BJsonTextWriterArrayStackedEventListener
|
||||
::~BJsonTextWriterArrayStackedEventListener()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
BJsonTextWriterArrayStackedEventListener::Handle(const BJsonEvent& event)
|
||||
{
|
||||
status_t writeResult = B_OK;
|
||||
|
||||
if (fWriter->ErrorStatus() != B_OK)
|
||||
return false;
|
||||
|
||||
switch (event.EventType()) {
|
||||
case B_JSON_ARRAY_END:
|
||||
{
|
||||
writeResult = StreamChar(']');
|
||||
|
||||
if (writeResult == B_OK) {
|
||||
SetStackedListenerOnWriter(fParent);
|
||||
delete this;
|
||||
return true; // must exit immediately after delete this.
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return BJsonTextWriterStackedEventListener::Handle(event);
|
||||
}
|
||||
|
||||
if(writeResult != B_OK) {
|
||||
HandleError(writeResult, JSON_EVENT_LISTENER_ANY_LINE,
|
||||
"error writing output");
|
||||
}
|
||||
|
||||
return ErrorStatus() == B_OK;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
BJsonTextWriterArrayStackedEventListener::WillAdd()
|
||||
{
|
||||
status_t writeResult = B_OK;
|
||||
|
||||
if (writeResult == B_OK && fCount > 0)
|
||||
writeResult = StreamChar(',');
|
||||
|
||||
if (writeResult != B_OK) {
|
||||
HandleError(B_IO_ERROR, JSON_EVENT_LISTENER_ANY_LINE,
|
||||
"error writing data");
|
||||
return false;
|
||||
}
|
||||
|
||||
return BJsonTextWriterStackedEventListener::WillAdd();
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - BJsonTextWriterObjectStackedEventListener
|
||||
|
||||
|
||||
BJsonTextWriterObjectStackedEventListener::BJsonTextWriterObjectStackedEventListener(
|
||||
BJsonTextWriter* writer,
|
||||
BJsonTextWriterStackedEventListener* parent)
|
||||
: BJsonTextWriterStackedEventListener(writer, parent)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
BJsonTextWriterObjectStackedEventListener
|
||||
::~BJsonTextWriterObjectStackedEventListener()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
BJsonTextWriterObjectStackedEventListener::Handle(const BJsonEvent& event)
|
||||
{
|
||||
status_t writeResult = B_OK;
|
||||
|
||||
if (fWriter->ErrorStatus() != B_OK)
|
||||
return false;
|
||||
|
||||
switch (event.EventType()) {
|
||||
case B_JSON_OBJECT_END:
|
||||
{
|
||||
writeResult = StreamChar('}');
|
||||
|
||||
if (writeResult == B_OK) {
|
||||
SetStackedListenerOnWriter(fParent);
|
||||
delete this;
|
||||
return true; // just exit after delete this.
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case B_JSON_OBJECT_NAME:
|
||||
{
|
||||
if (writeResult == B_OK && fCount > 0)
|
||||
writeResult = StreamChar(',');
|
||||
|
||||
if (writeResult == B_OK)
|
||||
writeResult = StreamQuotedEncodedString(event.Content());
|
||||
|
||||
if (writeResult == B_OK)
|
||||
writeResult = StreamChar(':');
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return BJsonTextWriterStackedEventListener::Handle(event);
|
||||
}
|
||||
|
||||
if (writeResult != B_OK) {
|
||||
HandleError(writeResult, JSON_EVENT_LISTENER_ANY_LINE,
|
||||
"error writing data");
|
||||
}
|
||||
|
||||
return ErrorStatus() == B_OK;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - BJsonTextWriter
|
||||
|
||||
|
||||
BJsonTextWriter::BJsonTextWriter(
|
||||
BDataIO* dataIO)
|
||||
:
|
||||
fDataIO(dataIO)
|
||||
{
|
||||
|
||||
// this is a preparation for this buffer to easily be used later
|
||||
// to efficiently output encoded unicode characters.
|
||||
|
||||
fUnicodeAssemblyBuffer[0] = '\\';
|
||||
fUnicodeAssemblyBuffer[1] = 'u';
|
||||
|
||||
fStackedListener = new BJsonTextWriterStackedEventListener(this, NULL);
|
||||
}
|
||||
|
||||
|
||||
BJsonTextWriter::~BJsonTextWriter()
|
||||
{
|
||||
BJsonTextWriterStackedEventListener* listener = fStackedListener;
|
||||
|
||||
while (listener != NULL) {
|
||||
BJsonTextWriterStackedEventListener* nextListener = listener->Parent();
|
||||
delete listener;
|
||||
listener = nextListener;
|
||||
}
|
||||
|
||||
fStackedListener = NULL;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
BJsonTextWriter::Handle(const BJsonEvent& event)
|
||||
{
|
||||
return fStackedListener->Handle(event);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BJsonTextWriter::Complete()
|
||||
{
|
||||
// upon construction, this object will add one listener to the
|
||||
// stack. On complete, this listener should still be there;
|
||||
// otherwise this implies an unterminated structure such as array
|
||||
// / object.
|
||||
|
||||
if (fStackedListener->Parent() != NULL) {
|
||||
HandleError(B_BAD_DATA, JSON_EVENT_LISTENER_ANY_LINE,
|
||||
"unexpected end of input data");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BJsonTextWriter::SetStackedListener(
|
||||
BJsonTextWriterStackedEventListener* stackedListener)
|
||||
{
|
||||
fStackedListener = stackedListener;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BJsonTextWriter::StreamNumberNode(const BJsonEvent& event)
|
||||
{
|
||||
return StreamStringVerbatim(event.Content());
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BJsonTextWriter::StreamStringVerbatim(const char* string)
|
||||
{
|
||||
return StreamStringVerbatim(string, 0, strlen(string));
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BJsonTextWriter::StreamStringVerbatim(const char* string,
|
||||
off_t offset, size_t length)
|
||||
{
|
||||
return fDataIO->WriteExactly(&string[offset], length);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BJsonTextWriter::StreamStringEncoded(const char* string)
|
||||
{
|
||||
return StreamStringEncoded(string, 0, strlen(string));
|
||||
}
|
||||
|
||||
|
||||
/*! Note that this method will expect a UTF-8 encoded string. */
|
||||
|
||||
status_t
|
||||
BJsonTextWriter::StreamStringEncoded(const char* string,
|
||||
off_t offset, size_t length)
|
||||
{
|
||||
status_t writeResult = B_OK;
|
||||
uint8* string8bit = (uint8*)string;
|
||||
|
||||
while (writeResult == B_OK && 0 != length) {
|
||||
uint8 c = string8bit[offset];
|
||||
const char* simpleEsc = b_json_simple_esc_sequence(c);
|
||||
|
||||
// simple escape sequence involving the backslash + one character.
|
||||
|
||||
if (simpleEsc != NULL) {
|
||||
writeResult = StreamStringVerbatim(simpleEsc, 0, 2);
|
||||
|
||||
if (writeResult == B_OK) {
|
||||
offset++;
|
||||
length--;
|
||||
}
|
||||
} else {
|
||||
|
||||
if (b_json_is_7bit_clean(c)) {
|
||||
|
||||
// roll forward while the characters are simple and then
|
||||
// output them at as a block verbatim.
|
||||
|
||||
uint32 count7BitClean = 1;
|
||||
|
||||
while (count7BitClean < length
|
||||
&& b_json_is_7bit_clean(
|
||||
string8bit[offset + count7BitClean])) {
|
||||
count7BitClean++;
|
||||
}
|
||||
|
||||
writeResult = StreamStringVerbatim(&string[offset], 0,
|
||||
count7BitClean);
|
||||
|
||||
if (writeResult == B_OK) {
|
||||
offset += count7BitClean;
|
||||
length -= count7BitClean;
|
||||
}
|
||||
} else {
|
||||
if (b_json_is_illegal(c)) {
|
||||
fprintf(stderr, "! string encoding error - illegal "
|
||||
"character [%" B_PRIu32 "]\n", static_cast<uint32>(c));
|
||||
offset++;
|
||||
length--;
|
||||
} else {
|
||||
|
||||
// if the character is < 128 then it can be rendered
|
||||
// verbatim - check how many are like this and then
|
||||
// render those verbatim.
|
||||
|
||||
const char* stringInitial = &string[offset];
|
||||
uint32 unicodeCharacter = BUnicodeChar::FromUTF8(
|
||||
&stringInitial);
|
||||
|
||||
sprintf(&fUnicodeAssemblyBuffer[2], "%04" B_PRIx32,
|
||||
unicodeCharacter);
|
||||
writeResult = StreamStringVerbatim(fUnicodeAssemblyBuffer,
|
||||
0, 6);
|
||||
|
||||
if (writeResult == B_OK) {
|
||||
uint32 sequence_length
|
||||
= (uint32)(stringInitial - &string[offset]);
|
||||
offset += sequence_length;
|
||||
length -= sequence_length;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return writeResult;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BJsonTextWriter::StreamQuotedEncodedString(const char* string)
|
||||
{
|
||||
return StreamQuotedEncodedString(string, 0, strlen(string));
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BJsonTextWriter::StreamQuotedEncodedString(const char* string,
|
||||
off_t offset, size_t length)
|
||||
{
|
||||
status_t write_result = B_OK;
|
||||
|
||||
if (write_result == B_OK)
|
||||
write_result = StreamChar('\"');
|
||||
|
||||
if (write_result == B_OK)
|
||||
write_result = StreamStringEncoded(string, offset, length);
|
||||
|
||||
if (write_result == B_OK)
|
||||
write_result = StreamChar('\"');
|
||||
|
||||
return write_result;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BJsonTextWriter::StreamChar(char c)
|
||||
{
|
||||
return fDataIO->WriteExactly(&c, 1);
|
||||
}
|
||||
|
||||
|
144
src/kits/shared/JsonWriter.cpp
Normal file
144
src/kits/shared/JsonWriter.cpp
Normal file
@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright 2017, Andrew Lindesay <apl@lindesay.co.nz>
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include "JsonWriter.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <UnicodeChar.h>
|
||||
|
||||
|
||||
BJsonWriter::BJsonWriter()
|
||||
:
|
||||
fErrorStatus(B_OK)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
BJsonWriter::~BJsonWriter()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BJsonWriter::HandleError(status_t status, int32 line,
|
||||
const char* message)
|
||||
{
|
||||
if(fErrorStatus == B_OK) {
|
||||
if (message == NULL)
|
||||
message = "?";
|
||||
|
||||
fErrorStatus = status;
|
||||
fprintf(stderr, "! json err @line %" B_PRIi32 " - %s : %s\n", line,
|
||||
strerror(status), message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BJsonWriter::ErrorStatus()
|
||||
{
|
||||
return fErrorStatus;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BJsonWriter::WriteBoolean(bool value)
|
||||
{
|
||||
if (value)
|
||||
return WriteTrue();
|
||||
|
||||
return WriteFalse();
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BJsonWriter::WriteTrue()
|
||||
{
|
||||
Handle(BJsonEvent(B_JSON_TRUE));
|
||||
return fErrorStatus;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BJsonWriter::WriteFalse()
|
||||
{
|
||||
Handle(BJsonEvent(B_JSON_FALSE));
|
||||
return fErrorStatus;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BJsonWriter::WriteNull()
|
||||
{
|
||||
Handle(BJsonEvent(B_JSON_NULL));
|
||||
return fErrorStatus;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BJsonWriter::WriteInteger(int64 value)
|
||||
{
|
||||
Handle(BJsonEvent(value));
|
||||
return fErrorStatus;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BJsonWriter::WriteDouble(double value)
|
||||
{
|
||||
Handle(BJsonEvent(value));
|
||||
return fErrorStatus;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BJsonWriter::WriteString(const char* value)
|
||||
{
|
||||
Handle(BJsonEvent(value));
|
||||
return fErrorStatus;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BJsonWriter::WriteObjectStart()
|
||||
{
|
||||
Handle(BJsonEvent(B_JSON_OBJECT_START));
|
||||
return fErrorStatus;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BJsonWriter::WriteObjectName(const char* value)
|
||||
{
|
||||
Handle(BJsonEvent(B_JSON_OBJECT_NAME, value));
|
||||
return fErrorStatus;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BJsonWriter::WriteObjectEnd()
|
||||
{
|
||||
Handle(BJsonEvent(B_JSON_OBJECT_END));
|
||||
return fErrorStatus;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BJsonWriter::WriteArrayStart()
|
||||
{
|
||||
Handle(BJsonEvent(B_JSON_ARRAY_START));
|
||||
return fErrorStatus;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BJsonWriter::WriteArrayEnd()
|
||||
{
|
||||
Handle(BJsonEvent(B_JSON_ARRAY_END));
|
||||
return fErrorStatus;
|
||||
}
|
||||
|
@ -10,6 +10,10 @@ UnitTestLib libsharedtest.so :
|
||||
|
||||
CalendarViewTest.cpp
|
||||
DriverSettingsMessageAdapterTest.cpp
|
||||
JsonEndToEndTest.cpp
|
||||
JsonErrorHandlingTest.cpp
|
||||
JsonTextWriterTest.cpp
|
||||
JsonToMessageTest.cpp
|
||||
GeolocationTest.cpp
|
||||
NaturalCompareTest.cpp
|
||||
|
||||
|
215
src/tests/kits/shared/JsonEndToEndTest.cpp
Normal file
215
src/tests/kits/shared/JsonEndToEndTest.cpp
Normal file
@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Copyright 2017, Andrew Lindesay <apl@lindesay.co.nz>
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#include "JsonEndToEndTest.h"
|
||||
|
||||
#include <AutoDeleter.h>
|
||||
|
||||
#include <Json.h>
|
||||
#include <JsonTextWriter.h>
|
||||
|
||||
#include <cppunit/TestCaller.h>
|
||||
#include <cppunit/TestSuite.h>
|
||||
|
||||
#include "JsonSamples.h"
|
||||
|
||||
|
||||
using namespace BPrivate;
|
||||
|
||||
|
||||
JsonEndToEndTest::JsonEndToEndTest()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
JsonEndToEndTest::~JsonEndToEndTest()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JsonEndToEndTest::TestParseAndWrite(char* input, char* expectedOutput)
|
||||
{
|
||||
BDataIO* inputData = new BMemoryIO(input, strlen(input));
|
||||
ObjectDeleter<BDataIO> inputDataDeleter(inputData);
|
||||
BMallocIO* outputData = new BMallocIO();
|
||||
ObjectDeleter<BMallocIO> outputDataDeleter(outputData);
|
||||
BPrivate::BJsonTextWriter* listener
|
||||
= new BJsonTextWriter(outputData);
|
||||
ObjectDeleter<BPrivate::BJsonTextWriter> listenerDeleter(listener);
|
||||
|
||||
// ----------------------
|
||||
BPrivate::BJson::Parse(inputData, listener);
|
||||
// ----------------------
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK, listener->ErrorStatus());
|
||||
fprintf(stderr, "in >%s<\n", input);
|
||||
fprintf(stderr, "expected out >%s<\n", expectedOutput);
|
||||
fprintf(stderr, "actual out >%s<\n", (char*)outputData->Buffer());
|
||||
CPPUNIT_ASSERT_MESSAGE("expected did no equal actual output",
|
||||
0 == strncmp(expectedOutput, (char*)outputData->Buffer(),
|
||||
strlen(expectedOutput)));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JsonEndToEndTest::TestNullA()
|
||||
{
|
||||
TestParseAndWrite(JSON_SAMPLE_NULL_A_IN,
|
||||
JSON_SAMPLE_NULL_A_EXPECTED_OUT);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JsonEndToEndTest::TestTrueA()
|
||||
{
|
||||
TestParseAndWrite(JSON_SAMPLE_TRUE_A_IN,
|
||||
JSON_SAMPLE_TRUE_A_EXPECTED_OUT);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JsonEndToEndTest::TestFalseA()
|
||||
{
|
||||
TestParseAndWrite(JSON_SAMPLE_FALSE_A_IN,
|
||||
JSON_SAMPLE_FALSE_A_EXPECTED_OUT);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JsonEndToEndTest::TestNumberA()
|
||||
{
|
||||
TestParseAndWrite(JSON_SAMPLE_NUMBER_A_IN,
|
||||
JSON_SAMPLE_NUMBER_A_EXPECTED_OUT);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JsonEndToEndTest::TestStringA()
|
||||
{
|
||||
TestParseAndWrite(JSON_SAMPLE_STRING_A_IN,
|
||||
JSON_SAMPLE_STRING_A_EXPECTED_OUT);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JsonEndToEndTest::TestStringB()
|
||||
{
|
||||
TestParseAndWrite(JSON_SAMPLE_STRING_B_IN,
|
||||
JSON_SAMPLE_STRING_B_EXPECTED_OUT);
|
||||
}
|
||||
|
||||
|
||||
/* In this test, there are some UTF-8 characters. */
|
||||
|
||||
void
|
||||
JsonEndToEndTest::TestStringA2()
|
||||
{
|
||||
TestParseAndWrite(JSON_SAMPLE_STRING_A2_IN,
|
||||
JSON_SAMPLE_STRING_A_EXPECTED_OUT);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JsonEndToEndTest::TestArrayA()
|
||||
{
|
||||
TestParseAndWrite(JSON_SAMPLE_ARRAY_A_IN, JSON_SAMPLE_ARRAY_A_EXPECTED_OUT);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JsonEndToEndTest::TestArrayB()
|
||||
{
|
||||
TestParseAndWrite(JSON_SAMPLE_ARRAY_B_IN, JSON_SAMPLE_ARRAY_B_EXPECTED_OUT);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JsonEndToEndTest::TestObjectA()
|
||||
{
|
||||
TestParseAndWrite(JSON_SAMPLE_OBJECT_A_IN,
|
||||
JSON_SAMPLE_OBJECT_A_EXPECTED_OUT);
|
||||
}
|
||||
|
||||
|
||||
/*! This method will test an element being unterminated; such an object that
|
||||
is missing the terminating "}" symbol or a string that has no closing
|
||||
quote. This is tested here because the writer
|
||||
*/
|
||||
|
||||
void
|
||||
JsonEndToEndTest::TestUnterminated(const char *input)
|
||||
{
|
||||
BDataIO* inputData = new BMemoryIO(input, strlen(input));
|
||||
ObjectDeleter<BDataIO> inputDataDeleter(inputData);
|
||||
BMallocIO* outputData = new BMallocIO();
|
||||
ObjectDeleter<BMallocIO> outputDataDeleter(outputData);
|
||||
BPrivate::BJsonTextWriter* listener
|
||||
= new BJsonTextWriter(outputData);
|
||||
ObjectDeleter<BPrivate::BJsonTextWriter> listenerDeleter(listener);
|
||||
|
||||
// ----------------------
|
||||
BPrivate::BJson::Parse(inputData, listener);
|
||||
// ----------------------
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(B_BAD_DATA, listener->ErrorStatus());
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JsonEndToEndTest::TestStringUnterminated()
|
||||
{
|
||||
TestUnterminated(JSON_SAMPLE_BROKEN_UNTERMINATED_STRING);
|
||||
}
|
||||
|
||||
void
|
||||
JsonEndToEndTest::TestArrayUnterminated()
|
||||
{
|
||||
TestUnterminated(JSON_SAMPLE_BROKEN_UNTERMINATED_ARRAY);
|
||||
}
|
||||
|
||||
void
|
||||
JsonEndToEndTest::TestObjectUnterminated()
|
||||
{
|
||||
TestUnterminated(JSON_SAMPLE_BROKEN_UNTERMINATED_OBJECT);
|
||||
}
|
||||
|
||||
|
||||
/*static*/ void
|
||||
JsonEndToEndTest::AddTests(BTestSuite& parent)
|
||||
{
|
||||
CppUnit::TestSuite& suite = *new CppUnit::TestSuite("JsonEndToEndTest");
|
||||
|
||||
suite.addTest(new CppUnit::TestCaller<JsonEndToEndTest>(
|
||||
"JsonEndToEndTest::TestNullA", &JsonEndToEndTest::TestNullA));
|
||||
suite.addTest(new CppUnit::TestCaller<JsonEndToEndTest>(
|
||||
"JsonEndToEndTest::TestTrueA", &JsonEndToEndTest::TestTrueA));
|
||||
suite.addTest(new CppUnit::TestCaller<JsonEndToEndTest>(
|
||||
"JsonEndToEndTest::TestFalseA", &JsonEndToEndTest::TestFalseA));
|
||||
suite.addTest(new CppUnit::TestCaller<JsonEndToEndTest>(
|
||||
"JsonEndToEndTest::TestNumberA", &JsonEndToEndTest::TestNumberA));
|
||||
suite.addTest(new CppUnit::TestCaller<JsonEndToEndTest>(
|
||||
"JsonEndToEndTest::TestStringA", &JsonEndToEndTest::TestStringA));
|
||||
suite.addTest(new CppUnit::TestCaller<JsonEndToEndTest>(
|
||||
"JsonEndToEndTest::TestStringA2", &JsonEndToEndTest::TestStringA2));
|
||||
suite.addTest(new CppUnit::TestCaller<JsonEndToEndTest>(
|
||||
"JsonEndToEndTest::TestStringB", &JsonEndToEndTest::TestStringB));
|
||||
suite.addTest(new CppUnit::TestCaller<JsonEndToEndTest>(
|
||||
"JsonEndToEndTest::TestArrayA", &JsonEndToEndTest::TestArrayA));
|
||||
suite.addTest(new CppUnit::TestCaller<JsonEndToEndTest>(
|
||||
"JsonEndToEndTest::TestArrayB", &JsonEndToEndTest::TestArrayB));
|
||||
suite.addTest(new CppUnit::TestCaller<JsonEndToEndTest>(
|
||||
"JsonEndToEndTest::TestObjectA", &JsonEndToEndTest::TestObjectA));
|
||||
suite.addTest(new CppUnit::TestCaller<JsonEndToEndTest>(
|
||||
"JsonEndToEndTest::TestStringUnterminated",
|
||||
&JsonEndToEndTest::TestStringUnterminated));
|
||||
suite.addTest(new CppUnit::TestCaller<JsonEndToEndTest>(
|
||||
"JsonEndToEndTest::TestArrayUnterminated",
|
||||
&JsonEndToEndTest::TestArrayUnterminated));
|
||||
suite.addTest(new CppUnit::TestCaller<JsonEndToEndTest>(
|
||||
"JsonEndToEndTest::TestObjectUnterminated",
|
||||
&JsonEndToEndTest::TestObjectUnterminated));
|
||||
|
||||
parent.addTest("JsonEndToEndTest", &suite);
|
||||
}
|
45
src/tests/kits/shared/JsonEndToEndTest.h
Normal file
45
src/tests/kits/shared/JsonEndToEndTest.h
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2017, Andrew Lindesay <apl@lindesay.co.nz>
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef JSON_END_TO_END_TEST_H
|
||||
#define JSON_END_TO_END_TEST_H
|
||||
|
||||
|
||||
#include <TestCase.h>
|
||||
#include <TestSuite.h>
|
||||
|
||||
|
||||
class Sample;
|
||||
|
||||
|
||||
class JsonEndToEndTest : public CppUnit::TestCase {
|
||||
public:
|
||||
JsonEndToEndTest();
|
||||
virtual ~JsonEndToEndTest();
|
||||
|
||||
void TestNullA();
|
||||
void TestTrueA();
|
||||
void TestFalseA();
|
||||
void TestNumberA();
|
||||
void TestStringA();
|
||||
void TestStringA2();
|
||||
void TestStringB();
|
||||
void TestArrayA();
|
||||
void TestArrayB();
|
||||
void TestObjectA();
|
||||
|
||||
void TestStringUnterminated();
|
||||
void TestArrayUnterminated();
|
||||
void TestObjectUnterminated();
|
||||
|
||||
static void AddTests(BTestSuite& suite);
|
||||
private:
|
||||
void TestUnterminated(const char* input);
|
||||
|
||||
void TestParseAndWrite(char* input,
|
||||
char* expectedOutput);
|
||||
};
|
||||
|
||||
|
||||
#endif // JSON_END_TO_END_TEST_H
|
354
src/tests/kits/shared/JsonErrorHandlingTest.cpp
Normal file
354
src/tests/kits/shared/JsonErrorHandlingTest.cpp
Normal file
@ -0,0 +1,354 @@
|
||||
/*
|
||||
* Copyright 2017, Andrew Lindesay <apl@lindesay.co.nz>
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#include "JsonErrorHandlingTest.h"
|
||||
|
||||
#include <AutoDeleter.h>
|
||||
|
||||
#include <Json.h>
|
||||
#include <JsonEventListener.h>
|
||||
|
||||
#include <cppunit/TestCaller.h>
|
||||
#include <cppunit/TestSuite.h>
|
||||
|
||||
#include "JsonSamples.h"
|
||||
|
||||
|
||||
using namespace BPrivate;
|
||||
|
||||
class ErrorCapturingListener : public BJsonEventListener {
|
||||
public:
|
||||
ErrorCapturingListener();
|
||||
virtual ~ErrorCapturingListener();
|
||||
|
||||
bool Handle(const BJsonEvent& event);
|
||||
void HandleError(status_t status, int32 line,
|
||||
const char* message);
|
||||
void Complete() {};
|
||||
|
||||
status_t ErrorStatus();
|
||||
int32 GetErrorLine();
|
||||
BString GetErrorMessage();
|
||||
bool HasEventsAfterError();
|
||||
json_event_type FirstEventTypeAfterError();
|
||||
private:
|
||||
status_t fErrorStatus;
|
||||
int32 fErrorLine;
|
||||
BString fErrorMessage;
|
||||
json_event_type fFirstEventTypeAfterError;
|
||||
int32 fEventCountAfterError;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/*! This DataIO concrete implementation is designed to open and then to fail
|
||||
in order to simulate what might happen if there were an IO problem when
|
||||
parsing some JSON.
|
||||
*/
|
||||
|
||||
class FailingDataIO : public BDataIO {
|
||||
public:
|
||||
FailingDataIO();
|
||||
virtual ~FailingDataIO();
|
||||
|
||||
ssize_t Read(void* buffer, size_t size);
|
||||
ssize_t Write(const void* buffer, size_t size);
|
||||
|
||||
status_t Flush();
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark - FailingDataIO
|
||||
|
||||
|
||||
FailingDataIO::FailingDataIO()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
FailingDataIO::~FailingDataIO()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
FailingDataIO::Read(void* buffer, size_t size)
|
||||
{
|
||||
return B_IO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
FailingDataIO::Write(const void* buffer, size_t size)
|
||||
{
|
||||
fprintf(stdout, "attempt to write");
|
||||
return B_IO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
FailingDataIO::Flush()
|
||||
{
|
||||
return B_IO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - ErrorCapturingListener
|
||||
|
||||
|
||||
ErrorCapturingListener::ErrorCapturingListener()
|
||||
{
|
||||
fErrorStatus = B_OK;
|
||||
fFirstEventTypeAfterError = B_JSON_NULL; // least likely
|
||||
fEventCountAfterError = 0;
|
||||
}
|
||||
|
||||
|
||||
ErrorCapturingListener::~ErrorCapturingListener()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ErrorCapturingListener::Handle(const BJsonEvent& event)
|
||||
{
|
||||
if (fErrorStatus != B_OK) {
|
||||
if (fEventCountAfterError == 0)
|
||||
fFirstEventTypeAfterError = event.EventType();
|
||||
|
||||
fEventCountAfterError++;
|
||||
}
|
||||
return true; // keep going.
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ErrorCapturingListener::HandleError(status_t status, int32 line,
|
||||
const char *message)
|
||||
{
|
||||
fErrorStatus = status;
|
||||
fErrorLine = line;
|
||||
|
||||
if (message != NULL)
|
||||
fErrorMessage = BString(message);
|
||||
else
|
||||
fErrorMessage = BString();
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ErrorCapturingListener::ErrorStatus()
|
||||
{
|
||||
return fErrorStatus;
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
ErrorCapturingListener::GetErrorLine()
|
||||
{
|
||||
return fErrorLine;
|
||||
}
|
||||
|
||||
|
||||
BString
|
||||
ErrorCapturingListener::GetErrorMessage()
|
||||
{
|
||||
return fErrorMessage;
|
||||
}
|
||||
|
||||
|
||||
json_event_type
|
||||
ErrorCapturingListener::FirstEventTypeAfterError()
|
||||
{
|
||||
return fFirstEventTypeAfterError;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ErrorCapturingListener::HasEventsAfterError()
|
||||
{
|
||||
return fEventCountAfterError > 0;
|
||||
}
|
||||
|
||||
|
||||
JsonErrorHandlingTest::JsonErrorHandlingTest()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
JsonErrorHandlingTest::~JsonErrorHandlingTest()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JsonErrorHandlingTest::TestParseWithBadStringEscape(const char* input,
|
||||
int32 line, status_t expectedStatus, char expectedBadEscapeChar)
|
||||
{
|
||||
BString expectedMessage;
|
||||
expectedMessage.SetToFormat("unexpected escaped character [%c] "
|
||||
"in string parsing", expectedBadEscapeChar);
|
||||
|
||||
TestParseWithErrorMessage(input, line, expectedStatus,
|
||||
expectedMessage.String());
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JsonErrorHandlingTest::TestParseWithUnterminatedElement(const char* input,
|
||||
int32 line, status_t expectedStatus)
|
||||
{
|
||||
BString expectedMessage;
|
||||
expectedMessage.SetToFormat("unterminated element");
|
||||
|
||||
TestParseWithErrorMessage(input, line, expectedStatus,
|
||||
expectedMessage.String());
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JsonErrorHandlingTest::TestParseWithUnexpectedCharacter(const char* input,
|
||||
int32 line, status_t expectedStatus, char expectedChar)
|
||||
{
|
||||
BString expectedMessage;
|
||||
expectedMessage.SetToFormat("unexpected character [%" B_PRIu8
|
||||
"] (%c) when parsing element", static_cast<uint8>(expectedChar),
|
||||
expectedChar);
|
||||
|
||||
TestParseWithErrorMessage(input, line, expectedStatus,
|
||||
expectedMessage.String());
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JsonErrorHandlingTest::TestParseWithErrorMessage(const char* input, int32 line,
|
||||
status_t expectedStatus, const char* expectedMessage)
|
||||
{
|
||||
fprintf(stderr, "in >%s<\n", input);
|
||||
BDataIO *inputData = new BMemoryIO(input, strlen(input));
|
||||
ObjectDeleter<BDataIO> inputDataDeleter(inputData);
|
||||
TestParseWithErrorMessage(inputData, line, expectedStatus, expectedMessage);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JsonErrorHandlingTest::TestParseWithErrorMessage(BDataIO* inputData, int32 line,
|
||||
status_t expectedStatus, const char* expectedMessage)
|
||||
{
|
||||
ErrorCapturingListener* listener = new ErrorCapturingListener();
|
||||
ObjectDeleter<ErrorCapturingListener> listenerDeleter(listener);
|
||||
|
||||
// ----------------------
|
||||
BPrivate::BJson::Parse(inputData, listener);
|
||||
// ----------------------
|
||||
|
||||
fprintf(stderr, "expected error at line %" B_PRIi32 " - %s : %s\n",
|
||||
line,
|
||||
strerror(expectedStatus),
|
||||
expectedMessage);
|
||||
|
||||
fprintf(stderr, "actual error at line %" B_PRIi32 " - %s : %s\n",
|
||||
listener->GetErrorLine(),
|
||||
strerror(listener->ErrorStatus()),
|
||||
listener->GetErrorMessage().String());
|
||||
|
||||
if (listener->HasEventsAfterError()) {
|
||||
fprintf(stderr, "first event after error [%d]\n",
|
||||
listener->FirstEventTypeAfterError());
|
||||
}
|
||||
|
||||
CPPUNIT_ASSERT(!listener->HasEventsAfterError());
|
||||
CPPUNIT_ASSERT_EQUAL(expectedStatus, listener->ErrorStatus());
|
||||
CPPUNIT_ASSERT_EQUAL(line, listener->GetErrorLine());
|
||||
CPPUNIT_ASSERT(0 == strcmp(expectedMessage,
|
||||
listener->GetErrorMessage().String()));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JsonErrorHandlingTest::TestCompletelyUnknown()
|
||||
{
|
||||
TestParseWithUnexpectedCharacter(
|
||||
JSON_SAMPLE_BROKEN_COMPLETELY_UNKNOWN, 1, B_BAD_DATA, 'z');
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JsonErrorHandlingTest::TestObjectWithPrematureSeparator()
|
||||
{
|
||||
TestParseWithErrorMessage(JSON_SAMPLE_BROKEN_OBJECT_PREMATURE_SEPARATOR, 1,
|
||||
B_BAD_DATA, "unexpected item separator when parsing start of object");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JsonErrorHandlingTest::TestStringUnterminated()
|
||||
{
|
||||
TestParseWithErrorMessage(JSON_SAMPLE_BROKEN_UNTERMINATED_STRING, 1,
|
||||
B_BAD_DATA, "unexpected end of input");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JsonErrorHandlingTest::TestBadStringEscape()
|
||||
{
|
||||
TestParseWithBadStringEscape(
|
||||
JSON_SAMPLE_BROKEN_BAD_STRING_ESCAPE, 1, B_BAD_DATA, 'v');
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JsonErrorHandlingTest::TestBadNumber()
|
||||
{
|
||||
BString expectedMessage;
|
||||
expectedMessage.SetToFormat("malformed number",
|
||||
JSON_SAMPLE_BROKEN_NUMBER);
|
||||
|
||||
TestParseWithErrorMessage(JSON_SAMPLE_BROKEN_NUMBER, 1, B_BAD_DATA,
|
||||
expectedMessage.String());
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JsonErrorHandlingTest::TestIOIssue()
|
||||
{
|
||||
BDataIO *inputData = new FailingDataIO();
|
||||
ObjectDeleter<BDataIO> inputDataDeleter(inputData);
|
||||
TestParseWithErrorMessage(inputData, -1, B_IO_ERROR,
|
||||
"io related read error");
|
||||
}
|
||||
|
||||
|
||||
/*static*/ void
|
||||
JsonErrorHandlingTest::AddTests(BTestSuite& parent)
|
||||
{
|
||||
CppUnit::TestSuite& suite = *new CppUnit::TestSuite(
|
||||
"JsonErrorHandlingTest");
|
||||
|
||||
suite.addTest(new CppUnit::TestCaller<JsonErrorHandlingTest>(
|
||||
"JsonErrorHandlingTest::TestCompletelyUnknown",
|
||||
&JsonErrorHandlingTest::TestCompletelyUnknown));
|
||||
|
||||
suite.addTest(new CppUnit::TestCaller<JsonErrorHandlingTest>(
|
||||
"JsonErrorHandlingTest::TestObjectWithPrematureSeparator",
|
||||
&JsonErrorHandlingTest::TestObjectWithPrematureSeparator));
|
||||
|
||||
suite.addTest(new CppUnit::TestCaller<JsonErrorHandlingTest>(
|
||||
"JsonErrorHandlingTest::TestStringUnterminated",
|
||||
&JsonErrorHandlingTest::TestStringUnterminated));
|
||||
|
||||
suite.addTest(new CppUnit::TestCaller<JsonErrorHandlingTest>(
|
||||
"JsonErrorHandlingTest::TestBadStringEscape",
|
||||
&JsonErrorHandlingTest::TestBadStringEscape));
|
||||
|
||||
suite.addTest(new CppUnit::TestCaller<JsonErrorHandlingTest>(
|
||||
"JsonErrorHandlingTest::TestBadNumber",
|
||||
&JsonErrorHandlingTest::TestBadNumber));
|
||||
|
||||
suite.addTest(new CppUnit::TestCaller<JsonErrorHandlingTest>(
|
||||
"JsonErrorHandlingTest::TestIOIssue",
|
||||
&JsonErrorHandlingTest::TestIOIssue));
|
||||
|
||||
parent.addTest("JsonErrorHandlingTest", &suite);
|
||||
}
|
61
src/tests/kits/shared/JsonErrorHandlingTest.h
Normal file
61
src/tests/kits/shared/JsonErrorHandlingTest.h
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2017, Andrew Lindesay <apl@lindesay.co.nz>
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef JSON_ERROR_HANDLING_TEST_H
|
||||
#define JSON_ERROR_HANDLING_TEST_H
|
||||
|
||||
|
||||
#include <TestCase.h>
|
||||
#include <TestSuite.h>
|
||||
|
||||
#include <DataIO.h>
|
||||
|
||||
class Sample;
|
||||
|
||||
|
||||
class JsonErrorHandlingTest : public CppUnit::TestCase {
|
||||
public:
|
||||
JsonErrorHandlingTest();
|
||||
virtual ~JsonErrorHandlingTest();
|
||||
|
||||
void TestCompletelyUnknown();
|
||||
void TestObjectWithPrematureSeparator();
|
||||
|
||||
void TestStringUnterminated();
|
||||
|
||||
void TestBadStringEscape();
|
||||
|
||||
void TestBadNumber();
|
||||
|
||||
void TestIOIssue();
|
||||
|
||||
static void AddTests(BTestSuite& suite);
|
||||
private:
|
||||
void TestParseWithUnexpectedCharacter(
|
||||
const char* input, int32 line,
|
||||
status_t expectedStatus, char expectedChar);
|
||||
|
||||
void TestParseWithUnterminatedElement(
|
||||
const char* input, int32 line,
|
||||
status_t expectedStatus);
|
||||
|
||||
void TestParseWithBadStringEscape(
|
||||
const char* input,
|
||||
int32 line, status_t expectedStatus,
|
||||
char expectedBadEscapeChar);
|
||||
|
||||
void TestParseWithErrorMessage(
|
||||
const char* input, int32 line,
|
||||
status_t expectedStatus,
|
||||
const char* expectedMessage);
|
||||
|
||||
void TestParseWithErrorMessage(
|
||||
BDataIO* data, int32 line,
|
||||
status_t expectedStatus,
|
||||
const char* expectedMessage);
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // JSON_ERROR_HANDLING_TEST_H
|
707
src/tests/kits/shared/JsonSamples.h
Normal file
707
src/tests/kits/shared/JsonSamples.h
Normal file
@ -0,0 +1,707 @@
|
||||
/*
|
||||
* Copyright 2017, Andrew Lindesay <apl@lindesay.co.nz>
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef JSON_SAMPLES_H
|
||||
#define JSON_SAMPLES_H
|
||||
|
||||
|
||||
#define JSON_SAMPLE_FALSE_A_IN "false"
|
||||
#define JSON_SAMPLE_FALSE_A_EXPECTED_OUT JSON_SAMPLE_FALSE_A_IN
|
||||
|
||||
#define JSON_SAMPLE_TRUE_A_IN "true"
|
||||
#define JSON_SAMPLE_TRUE_A_EXPECTED_OUT JSON_SAMPLE_TRUE_A_IN
|
||||
|
||||
#define JSON_SAMPLE_NULL_A_IN "null"
|
||||
#define JSON_SAMPLE_NULL_A_EXPECTED_OUT JSON_SAMPLE_NULL_A_IN
|
||||
|
||||
#define JSON_SAMPLE_NUMBER_A_LITERAL 3.142857142857143
|
||||
#define JSON_SAMPLE_NUMBER_A_IN "3.142857142857143"
|
||||
#define JSON_SAMPLE_NUMBER_A_EXPECTED_OUT JSON_SAMPLE_NUMBER_A_IN
|
||||
|
||||
#define JSON_SAMPLE_NUMBER_B_LITERAL 1122334455
|
||||
#define JSON_SAMPLE_NUMBER_B_IN "1122334455"
|
||||
#define JSON_SAMPLE_NUMBER_B_EXPECTED_OUT JSON_SAMPLE_NUMBER_B_IN
|
||||
|
||||
/*! This sample is a string that contains a newline in the middle as well as a
|
||||
unicode character escaped with an "\x..." sequence. The second version 'A2'
|
||||
has the same unicode character (non US-ASCII) represented as UTF-8 directly.
|
||||
*/
|
||||
|
||||
#define JSON_SAMPLE_STRING_A_IN "\"Lake\\nTaup\\u014d\""
|
||||
#define JSON_SAMPLE_STRING_A2_IN "\"Lake\\nTaup\xc5\x8d\""
|
||||
#define JSON_SAMPLE_STRING_A_EXPECTED_OUT JSON_SAMPLE_STRING_A_IN
|
||||
|
||||
#define JSON_SAMPLE_STRING_B_IN "\"\\u21c8\""
|
||||
#define JSON_SAMPLE_STRING_B_EXPECTED_OUT JSON_SAMPLE_STRING_B_IN
|
||||
|
||||
/*! This sample is an array containing other elements. */
|
||||
|
||||
#define JSON_SAMPLE_ARRAY_A_IN "[\"1234\", 4567 , \n" \
|
||||
" [ \"A\" ,\"b\", \"C\\u00e9zanne\"] ]"
|
||||
#define JSON_SAMPLE_ARRAY_A_EXPECTED_OUT "[\"1234\",4567," \
|
||||
"[\"A\",\"b\",\"C\\u00e9zanne\"]]"
|
||||
|
||||
#define JSON_SAMPLE_ARRAY_B_IN "[\"Whirinaki\", \"Wellington\" , \n" \
|
||||
" { \"key\" : [ \"value\" ] }\n" \
|
||||
"]"
|
||||
#define JSON_SAMPLE_ARRAY_B_EXPECTED_OUT "[\"Whirinaki\",\"Wellington\"," \
|
||||
"{\"key\":[\"value\"]}]"
|
||||
|
||||
/*! This sample is an object type containing other elements. */
|
||||
|
||||
#define JSON_SAMPLE_OBJECT_A_IN "{\"weather\":\"raining\", \"humidity\" : " \
|
||||
"\"too-high\", \"daysOfWeek\": [\"MON\", \"TUE\", \"WED\", \"THR\"," \
|
||||
"\"FRI\"]}"
|
||||
#define JSON_SAMPLE_OBJECT_A_EXPECTED_OUT "{\"weather\":\"raining\"," \
|
||||
"\"humidity\":\"too-high\",\"daysOfWeek\":[\"MON\",\"TUE\",\"WED\",\"THR\"," \
|
||||
"\"FRI\"]}"
|
||||
|
||||
/*! This sample contains some other types of JSON nodes such as true, false
|
||||
and null.
|
||||
*/
|
||||
|
||||
#define JSON_SAMPLE_OBJECT_B_IN "{\"testTrue\":true, \"testFalse\" : " \
|
||||
"false, \"testNull\": null }"
|
||||
|
||||
/*! A very simple object that can be used to test basic functionality. */
|
||||
|
||||
#define JSON_SAMPLE_OBJECT_C_IN "{\"key\":\"value\"}"
|
||||
|
||||
/*! This sample has a key-value separator as the first character after
|
||||
opening the object.
|
||||
*/
|
||||
|
||||
#define JSON_SAMPLE_BROKEN_OBJECT_PREMATURE_SEPARATOR "{,\"key\":\"value\"}"
|
||||
|
||||
#define JSON_SAMPLE_BROKEN_COMPLETELY_UNKNOWN "zzz"
|
||||
|
||||
#define JSON_SAMPLE_BROKEN_UNTERMINATED_OBJECT "[ 123, {\"key\":\"value\""
|
||||
|
||||
#define JSON_SAMPLE_BROKEN_UNTERMINATED_ARRAY "{\"key\":\"value\",\n" \
|
||||
"\"key2\":\n" \
|
||||
"["
|
||||
|
||||
#define JSON_SAMPLE_BROKEN_UNTERMINATED_STRING "\"without end"
|
||||
|
||||
#define JSON_SAMPLE_BROKEN_BAD_STRING_ESCAPE "\"a dastardly \\v escape sequence\""
|
||||
|
||||
#define JSON_SAMPLE_BROKEN_NUMBER "-123e123E456e"
|
||||
|
||||
/*! This is a larger example and comes from the request-response
|
||||
cycle of a JSON-RPC request from the HaikuDepot desktop application
|
||||
into the HaikuDepotServer system.
|
||||
*/
|
||||
|
||||
#define JSON_SAMPLE_HDS_FETCH_BATCH_PKGS { \
|
||||
0x7b, 0x22, 0x6a, 0x73, 0x6f, 0x6e, 0x72, 0x70, 0x63, 0x22, 0x3a, 0x22, \
|
||||
0x32, 0x2e, 0x30, 0x22, 0x2c, 0x22, 0x69, 0x64, 0x22, 0x3a, 0x36, 0x2c, \
|
||||
0x22, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x3a, 0x7b, 0x22, 0x70, \
|
||||
0x6b, 0x67, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x6e, 0x61, 0x6d, 0x65, \
|
||||
0x22, 0x3a, 0x22, 0x62, 0x65, 0x73, 0x68, 0x61, 0x72, 0x65, 0x5f, 0x73, \
|
||||
0x65, 0x72, 0x76, 0x65, 0x72, 0x22, 0x2c, 0x22, 0x6d, 0x6f, 0x64, 0x69, \
|
||||
0x66, 0x79, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, \
|
||||
0x3a, 0x31, 0x34, 0x37, 0x36, 0x31, 0x39, 0x39, 0x33, 0x36, 0x34, 0x30, \
|
||||
0x37, 0x30, 0x2c, 0x22, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, \
|
||||
0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x22, 0x3a, \
|
||||
0x22, 0x32, 0x22, 0x2c, 0x22, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x22, 0x3a, \
|
||||
0x22, 0x34, 0x32, 0x22, 0x2c, 0x22, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x22, \
|
||||
0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, 0x22, 0x70, 0x72, 0x65, 0x52, 0x65, \
|
||||
0x6c, 0x65, 0x61, 0x73, 0x65, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, \
|
||||
0x22, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x33, \
|
||||
0x2c, 0x22, 0x61, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, \
|
||||
0x72, 0x65, 0x43, 0x6f, 0x64, 0x65, 0x22, 0x3a, 0x22, 0x78, 0x38, 0x36, \
|
||||
0x5f, 0x67, 0x63, 0x63, 0x32, 0x22, 0x2c, 0x22, 0x74, 0x69, 0x74, 0x6c, \
|
||||
0x65, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, 0x22, 0x72, 0x65, 0x70, \
|
||||
0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x53, 0x6f, 0x75, 0x72, 0x63, \
|
||||
0x65, 0x43, 0x6f, 0x64, 0x65, 0x22, 0x3a, 0x22, 0x66, 0x61, 0x74, 0x65, \
|
||||
0x6c, 0x6b, 0x5f, 0x78, 0x38, 0x36, 0x5f, 0x67, 0x63, 0x63, 0x32, 0x22, \
|
||||
0x2c, 0x22, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, \
|
||||
0x43, 0x6f, 0x64, 0x65, 0x22, 0x3a, 0x22, 0x66, 0x61, 0x74, 0x65, 0x6c, \
|
||||
0x6b, 0x22, 0x2c, 0x22, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x22, \
|
||||
0x3a, 0x22, 0x42, 0x65, 0x53, 0x68, 0x61, 0x72, 0x65, 0x20, 0x53, 0x65, \
|
||||
0x72, 0x76, 0x65, 0x72, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x41, 0x74, 0x72, \
|
||||
0x75, 0x73, 0x20, 0x43, 0x68, 0x61, 0x74, 0x62, 0x6f, 0x74, 0x22, 0x2c, \
|
||||
0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, \
|
||||
0x22, 0x3a, 0x22, 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x61, 0x63, 0x6b, \
|
||||
0x61, 0x67, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, \
|
||||
0x20, 0x74, 0x68, 0x65, 0x20, 0x5c, 0x22, 0x6d, 0x75, 0x73, 0x63, 0x6c, \
|
||||
0x65, 0x64, 0x5c, 0x22, 0x20, 0x28, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x20, \
|
||||
0x55, 0x73, 0x65, 0x72, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, \
|
||||
0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x4c, 0x69, 0x6e, 0x6b, 0x69, \
|
||||
0x6e, 0x67, 0x20, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, \
|
||||
0x6e, 0x74, 0x20, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x29, 0x20, 0x73, \
|
||||
0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x28, 0x76, 0x65, 0x72, 0x73, 0x69, \
|
||||
0x6f, 0x6e, 0x20, 0x33, 0x2e, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x72, 0x74, \
|
||||
0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x48, 0x61, 0x69, 0x6b, 0x75, 0x20, \
|
||||
0x47, 0x43, 0x43, 0x32, 0x20, 0x62, 0x79, 0x20, 0x41, 0x47, 0x4d, 0x53, \
|
||||
0x20, 0x69, 0x6e, 0x20, 0x32, 0x30, 0x31, 0x36, 0x29, 0x20, 0x61, 0x6e, \
|
||||
0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x41, 0x74, 0x72, 0x75, 0x73, 0x20, \
|
||||
0x63, 0x68, 0x61, 0x74, 0x20, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x20, 0x32, \
|
||||
0x2e, 0x34, 0x32, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x6d, 0x6f, \
|
||||
0x6e, 0x69, 0x74, 0x6f, 0x72, 0x73, 0x20, 0x74, 0x65, 0x78, 0x74, 0x20, \
|
||||
0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, \
|
||||
0x73, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x72, \
|
||||
0x76, 0x65, 0x72, 0x2e, 0x20, 0x20, 0x54, 0x68, 0x61, 0x74, 0x20, 0x70, \
|
||||
0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x73, 0x20, 0x65, 0x76, 0x65, 0x72, \
|
||||
0x79, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6e, \
|
||||
0x65, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x73, 0x65, 0x74, 0x20, 0x75, \
|
||||
0x70, 0x20, 0x79, 0x6f, 0x75, 0x72, 0x20, 0x6f, 0x77, 0x6e, 0x20, 0x42, \
|
||||
0x65, 0x53, 0x68, 0x61, 0x72, 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, \
|
||||
0x72, 0x2e, 0x5c, 0x6e, 0x5c, 0x6e, 0x41, 0x66, 0x74, 0x65, 0x72, 0x20, \
|
||||
0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x2c, 0x20, \
|
||||
0x79, 0x6f, 0x75, 0x20, 0x6e, 0x65, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, \
|
||||
0x64, 0x6f, 0x20, 0x61, 0x20, 0x66, 0x65, 0x77, 0x20, 0x74, 0x68, 0x69, \
|
||||
0x6e, 0x67, 0x73, 0x3a, 0x5c, 0x6e, 0x5c, 0x6e, 0x31, 0x29, 0x20, 0x53, \
|
||||
0x65, 0x65, 0x20, 0x69, 0x66, 0x20, 0x69, 0x74, 0x20, 0x69, 0x6e, 0x73, \
|
||||
0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x2e, 0x20, 0x20, 0x49, 0x74, 0x20, \
|
||||
0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, \
|
||||
0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, \
|
||||
0x61, 0x66, 0x74, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, \
|
||||
0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, \
|
||||
0x61, 0x75, 0x74, 0x6f, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x6c, \
|
||||
0x79, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x20, 0x75, 0x70, 0x20, 0x61, \
|
||||
0x66, 0x74, 0x65, 0x72, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x72, 0x65, 0x62, \
|
||||
0x6f, 0x6f, 0x74, 0x2e, 0x20, 0x20, 0x49, 0x6e, 0x20, 0x50, 0x72, 0x6f, \
|
||||
0x63, 0x65, 0x73, 0x73, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, \
|
||||
0x6c, 0x65, 0x72, 0x20, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x20, 0x74, 0x68, \
|
||||
0x65, 0x20, 0x5c, 0x22, 0x54, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x20, \
|
||||
0x61, 0x6e, 0x64, 0x20, 0x43, 0x50, 0x55, 0x20, 0x75, 0x73, 0x61, 0x67, \
|
||||
0x65, 0x5c, 0x22, 0x20, 0x6d, 0x65, 0x6e, 0x75, 0x20, 0x79, 0x6f, 0x75, \
|
||||
0x20, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x73, 0x65, 0x65, 0x20, \
|
||||
0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x20, 0x66, 0x6f, 0x72, 0x20, \
|
||||
0x5c, 0x22, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x6d, 0x75, 0x73, 0x63, 0x6c, \
|
||||
0x65, 0x64, 0x5c, 0x22, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x5c, 0x22, 0x2f, \
|
||||
0x62, 0x69, 0x6e, 0x41, 0x74, 0x72, 0x75, 0x73, 0x5c, 0x22, 0x2e, 0x5c, \
|
||||
0x6e, 0x5c, 0x6e, 0x32, 0x29, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x69, \
|
||||
0x74, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x42, 0x65, 0x53, 0x68, 0x61, \
|
||||
0x72, 0x65, 0x2e, 0x20, 0x20, 0x55, 0x73, 0x65, 0x20, 0x79, 0x6f, 0x75, \
|
||||
0x72, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x27, 0x73, \
|
||||
0x20, 0x49, 0x50, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x20, \
|
||||
0x6f, 0x72, 0x20, 0x6c, 0x65, 0x73, 0x73, 0x20, 0x72, 0x65, 0x6c, 0x69, \
|
||||
0x61, 0x62, 0x6c, 0x79, 0x20, 0x5c, 0x22, 0x6c, 0x6f, 0x63, 0x61, 0x6c, \
|
||||
0x68, 0x6f, 0x73, 0x74, 0x5c, 0x22, 0x20, 0x61, 0x73, 0x20, 0x74, 0x68, \
|
||||
0x65, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, \
|
||||
0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x74, 0x6f, 0x20, \
|
||||
0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x20, 0x74, 0x6f, 0x2e, 0x5c, \
|
||||
0x6e, 0x5c, 0x6e, 0x33, 0x29, 0x20, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, \
|
||||
0x64, 0x20, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x32, 0x39, 0x36, 0x30, 0x20, \
|
||||
0x66, 0x72, 0x6f, 0x6d, 0x20, 0x79, 0x6f, 0x75, 0x72, 0x20, 0x72, 0x6f, \
|
||||
0x75, 0x74, 0x65, 0x72, 0x20, 0x74, 0x6f, 0x20, 0x79, 0x6f, 0x75, 0x72, \
|
||||
0x20, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x20, 0x28, 0x6f, \
|
||||
0x74, 0x68, 0x65, 0x72, 0x77, 0x69, 0x73, 0x65, 0x20, 0x6e, 0x6f, 0x62, \
|
||||
0x6f, 0x64, 0x79, 0x20, 0x6f, 0x75, 0x74, 0x73, 0x69, 0x64, 0x65, 0x20, \
|
||||
0x63, 0x61, 0x6e, 0x20, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x20, 0x79, \
|
||||
0x6f, 0x75, 0x72, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x29, 0x2e, \
|
||||
0x5c, 0x6e, 0x5c, 0x6e, 0x34, 0x29, 0x20, 0x55, 0x70, 0x6f, 0x6e, 0x20, \
|
||||
0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, \
|
||||
0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6f, 0x6f, 0x74, 0x20, 0x73, 0x63, \
|
||||
0x72, 0x69, 0x70, 0x74, 0x20, 0x69, 0x73, 0x20, 0x63, 0x6f, 0x70, 0x69, \
|
||||
0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x2f, 0x62, 0x6f, 0x6f, 0x74, 0x2f, \
|
||||
0x68, 0x6f, 0x6d, 0x65, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f, \
|
||||
0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2f, 0x62, 0x6f, 0x6f, \
|
||||
0x74, 0x2f, 0x6c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x2f, 0x62, 0x65, 0x73, \
|
||||
0x68, 0x61, 0x72, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, \
|
||||
0x73, 0x68, 0x20, 0x77, 0x68, 0x65, 0x72, 0x65, 0x20, 0x79, 0x6f, 0x75, \
|
||||
0x20, 0x63, 0x61, 0x6e, 0x20, 0x65, 0x64, 0x69, 0x74, 0x20, 0x74, 0x68, \
|
||||
0x65, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x20, 0x6f, 0x70, \
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2c, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, \
|
||||
0x64, 0x69, 0x6e, 0x67, 0x20, 0x79, 0x6f, 0x75, 0x72, 0x20, 0x27, 0x62, \
|
||||
0x6f, 0x74, 0x73, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x61, 0x6e, 0x64, \
|
||||
0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, \
|
||||
0x6c, 0x20, 0x49, 0x50, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, \
|
||||
0x20, 0x66, 0x6f, 0x72, 0x20, 0x4d, 0x75, 0x73, 0x63, 0x6c, 0x65, 0x20, \
|
||||
0x74, 0x6f, 0x20, 0x75, 0x73, 0x65, 0x20, 0x28, 0x6f, 0x74, 0x68, 0x65, \
|
||||
0x72, 0x77, 0x69, 0x73, 0x65, 0x20, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, \
|
||||
0x61, 0x6c, 0x20, 0x75, 0x73, 0x65, 0x72, 0x73, 0x20, 0x77, 0x69, 0x6c, \
|
||||
0x6c, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x74, 0x72, 0x6f, 0x75, 0x62, \
|
||||
0x6c, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6e, \
|
||||
0x67, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x64, 0x6f, 0x69, 0x6e, 0x67, 0x20, \
|
||||
0x66, 0x69, 0x6c, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, \
|
||||
0x72, 0x73, 0x29, 0x2e, 0x20, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6c, 0x6f, \
|
||||
0x67, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, \
|
||||
0x61, 0x6c, 0x73, 0x6f, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, \
|
||||
0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, 0x2c, 0x20, 0x72, 0x65, \
|
||||
0x6d, 0x6f, 0x76, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6d, 0x20, 0x69, 0x66, \
|
||||
0x20, 0x79, 0x6f, 0x75, 0x27, 0x72, 0x65, 0x20, 0x75, 0x73, 0x69, 0x6e, \
|
||||
0x67, 0x20, 0x61, 0x20, 0x72, 0x65, 0x61, 0x64, 0x2d, 0x6f, 0x6e, 0x6c, \
|
||||
0x79, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x73, 0x79, 0x73, 0x74, 0x65, \
|
||||
0x6d, 0x2e, 0x5c, 0x6e, 0x5c, 0x6e, 0x35, 0x29, 0x20, 0x45, 0x64, 0x69, \
|
||||
0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x42, 0x6f, 0x74, 0x44, 0x61, 0x74, \
|
||||
0x61, 0x20, 0x74, 0x65, 0x78, 0x74, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x73, \
|
||||
0x20, 0x69, 0x6e, 0x20, 0x2f, 0x62, 0x6f, 0x6f, 0x74, 0x2f, 0x68, 0x6f, \
|
||||
0x6d, 0x65, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f, 0x73, 0x65, \
|
||||
0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2f, 0x42, 0x6f, 0x74, 0x44, 0x61, \
|
||||
0x74, 0x61, 0x20, 0x74, 0x6f, 0x20, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, \
|
||||
0x69, 0x7a, 0x65, 0x20, 0x79, 0x6f, 0x75, 0x72, 0x20, 0x63, 0x68, 0x61, \
|
||||
0x74, 0x62, 0x6f, 0x74, 0x27, 0x73, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2e, \
|
||||
0x5c, 0x6e, 0x5c, 0x6e, 0x48, 0x61, 0x70, 0x70, 0x79, 0x20, 0x42, 0x65, \
|
||||
0x73, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x21, 0x22, 0x2c, 0x22, 0x70, \
|
||||
0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, \
|
||||
0x22, 0x3a, 0x34, 0x30, 0x33, 0x36, 0x33, 0x37, 0x33, 0x7d, 0x5d, 0x2c, \
|
||||
0x22, 0x70, 0x6b, 0x67, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, \
|
||||
0x43, 0x6f, 0x64, 0x65, 0x73, 0x22, 0x3a, 0x5b, 0x22, 0x69, 0x6e, 0x74, \
|
||||
0x65, 0x72, 0x6e, 0x65, 0x74, 0x61, 0x6e, 0x64, 0x6e, 0x65, 0x74, 0x77, \
|
||||
0x6f, 0x72, 0x6b, 0x22, 0x5d, 0x2c, 0x22, 0x70, 0x6b, 0x67, 0x53, 0x63, \
|
||||
0x72, 0x65, 0x65, 0x6e, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x22, 0x3a, 0x5b, \
|
||||
0x5d, 0x2c, 0x22, 0x70, 0x6b, 0x67, 0x49, 0x63, 0x6f, 0x6e, 0x73, 0x22, \
|
||||
0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, 0x22, 0x64, 0x65, 0x72, 0x69, 0x76, \
|
||||
0x65, 0x64, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x22, 0x3a, 0x6e, 0x75, \
|
||||
0x6c, 0x6c, 0x2c, 0x22, 0x70, 0x72, 0x6f, 0x6d, 0x69, 0x6e, 0x65, 0x6e, \
|
||||
0x63, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x3a, \
|
||||
0x31, 0x30, 0x30, 0x30, 0x2c, 0x22, 0x70, 0x6b, 0x67, 0x43, 0x68, 0x61, \
|
||||
0x6e, 0x67, 0x65, 0x6c, 0x6f, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, \
|
||||
0x74, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x7d, 0x2c, 0x7b, 0x22, 0x6e, \
|
||||
0x61, 0x6d, 0x65, 0x22, 0x3a, 0x22, 0x62, 0x6f, 0x6f, 0x6b, 0x6d, 0x61, \
|
||||
0x72, 0x6b, 0x65, 0x72, 0x22, 0x2c, 0x22, 0x6d, 0x6f, 0x64, 0x69, 0x66, \
|
||||
0x79, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x3a, \
|
||||
0x31, 0x34, 0x38, 0x38, 0x37, 0x38, 0x35, 0x33, 0x33, 0x31, 0x36, 0x33, \
|
||||
0x31, 0x2c, 0x22, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, \
|
||||
0x3a, 0x5b, 0x7b, 0x22, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x22, 0x3a, 0x22, \
|
||||
0x31, 0x22, 0x2c, 0x22, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x22, 0x3a, 0x22, \
|
||||
0x33, 0x22, 0x2c, 0x22, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x22, 0x3a, 0x6e, \
|
||||
0x75, 0x6c, 0x6c, 0x2c, 0x22, 0x70, 0x72, 0x65, 0x52, 0x65, 0x6c, 0x65, \
|
||||
0x61, 0x73, 0x65, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, 0x22, 0x72, \
|
||||
0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x32, 0x2c, 0x22, \
|
||||
0x61, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, \
|
||||
0x43, 0x6f, 0x64, 0x65, 0x22, 0x3a, 0x22, 0x78, 0x38, 0x36, 0x5f, 0x67, \
|
||||
0x63, 0x63, 0x32, 0x22, 0x2c, 0x22, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x22, \
|
||||
0x3a, 0x22, 0x42, 0x6f, 0x6f, 0x6b, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x72, \
|
||||
0x22, 0x2c, 0x22, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, \
|
||||
0x79, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x6f, 0x64, 0x65, 0x22, \
|
||||
0x3a, 0x22, 0x66, 0x61, 0x74, 0x65, 0x6c, 0x6b, 0x5f, 0x78, 0x38, 0x36, \
|
||||
0x5f, 0x67, 0x63, 0x63, 0x32, 0x22, 0x2c, 0x22, 0x72, 0x65, 0x70, 0x6f, \
|
||||
0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x22, 0x3a, \
|
||||
0x22, 0x66, 0x61, 0x74, 0x65, 0x6c, 0x6b, 0x22, 0x2c, 0x22, 0x73, 0x75, \
|
||||
0x6d, 0x6d, 0x61, 0x72, 0x79, 0x22, 0x3a, 0x22, 0x42, 0x6f, 0x6f, 0x6b, \
|
||||
0x6d, 0x61, 0x72, 0x6b, 0x20, 0x6d, 0x61, 0x6b, 0x65, 0x72, 0x22, 0x2c, \
|
||||
0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, \
|
||||
0x22, 0x3a, 0x22, 0x42, 0x6f, 0x6f, 0x6b, 0x6d, 0x61, 0x72, 0x6b, 0x65, \
|
||||
0x72, 0x20, 0x6d, 0x61, 0x6b, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, \
|
||||
0x73, 0x74, 0x6f, 0x72, 0x65, 0x73, 0x20, 0x62, 0x6f, 0x6f, 0x6b, 0x6d, \
|
||||
0x61, 0x72, 0x6b, 0x73, 0x20, 0x28, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, \
|
||||
0x20, 0x77, 0x69, 0x64, 0x65, 0x20, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x20, \
|
||||
0x74, 0x6f, 0x20, 0x77, 0x65, 0x62, 0x20, 0x73, 0x69, 0x74, 0x65, 0x73, \
|
||||
0x29, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x48, 0x61, \
|
||||
0x69, 0x6b, 0x75, 0x20, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6e, \
|
||||
0x67, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x20, 0x49, 0x74, \
|
||||
0x61, 0x6c, 0x73, 0x6f, 0x20, 0x61, 0x64, 0x64, 0x73, 0x20, 0x74, 0x68, \
|
||||
0x65, 0x20, 0x62, 0x6f, 0x6f, 0x6b, 0x6d, 0x61, 0x72, 0x6b, 0x73, 0x20, \
|
||||
0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x44, 0x65, 0x73, 0x6b, 0x62, \
|
||||
0x61, 0x72, 0x20, 0x6d, 0x65, 0x6e, 0x75, 0x2e, 0x22, 0x2c, 0x22, 0x70, \
|
||||
0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, \
|
||||
0x22, 0x3a, 0x36, 0x34, 0x34, 0x31, 0x35, 0x7d, 0x5d, 0x2c, 0x22, 0x70, \
|
||||
0x6b, 0x67, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x43, 0x6f, \
|
||||
0x64, 0x65, 0x73, 0x22, 0x3a, 0x5b, 0x22, 0x70, 0x72, 0x6f, 0x64, 0x75, \
|
||||
0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x22, 0x2c, 0x22, 0x73, 0x79, \
|
||||
0x73, 0x74, 0x65, 0x6d, 0x61, 0x6e, 0x64, 0x75, 0x74, 0x69, 0x6c, 0x69, \
|
||||
0x74, 0x69, 0x65, 0x73, 0x22, 0x2c, 0x22, 0x69, 0x6e, 0x74, 0x65, 0x72, \
|
||||
0x6e, 0x65, 0x74, 0x61, 0x6e, 0x64, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, \
|
||||
0x6b, 0x22, 0x5d, 0x2c, 0x22, 0x70, 0x6b, 0x67, 0x53, 0x63, 0x72, 0x65, \
|
||||
0x65, 0x6e, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, \
|
||||
0x63, 0x6f, 0x64, 0x65, 0x22, 0x3a, 0x22, 0x37, 0x36, 0x35, 0x30, 0x39, \
|
||||
0x64, 0x64, 0x36, 0x2d, 0x32, 0x35, 0x39, 0x36, 0x2d, 0x34, 0x32, 0x34, \
|
||||
0x37, 0x2d, 0x61, 0x38, 0x65, 0x34, 0x2d, 0x34, 0x37, 0x36, 0x39, 0x65, \
|
||||
0x34, 0x35, 0x61, 0x36, 0x66, 0x37, 0x35, 0x22, 0x2c, 0x22, 0x6c, 0x65, \
|
||||
0x6e, 0x67, 0x74, 0x68, 0x22, 0x3a, 0x32, 0x32, 0x31, 0x32, 0x35, 0x2c, \
|
||||
0x22, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x22, 0x3a, 0x34, 0x33, 0x32, \
|
||||
0x2c, 0x22, 0x77, 0x69, 0x64, 0x74, 0x68, 0x22, 0x3a, 0x35, 0x31, 0x31, \
|
||||
0x7d, 0x2c, 0x7b, 0x22, 0x63, 0x6f, 0x64, 0x65, 0x22, 0x3a, 0x22, 0x33, \
|
||||
0x32, 0x32, 0x61, 0x62, 0x39, 0x66, 0x33, 0x2d, 0x65, 0x35, 0x36, 0x66, \
|
||||
0x2d, 0x34, 0x64, 0x31, 0x61, 0x2d, 0x39, 0x37, 0x34, 0x33, 0x2d, 0x35, \
|
||||
0x63, 0x65, 0x66, 0x65, 0x39, 0x39, 0x32, 0x38, 0x32, 0x37, 0x66, 0x22, \
|
||||
0x2c, 0x22, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x22, 0x3a, 0x35, 0x34, \
|
||||
0x31, 0x30, 0x34, 0x2c, 0x22, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x22, \
|
||||
0x3a, 0x33, 0x30, 0x39, 0x2c, 0x22, 0x77, 0x69, 0x64, 0x74, 0x68, 0x22, \
|
||||
0x3a, 0x33, 0x32, 0x36, 0x7d, 0x5d, 0x2c, 0x22, 0x70, 0x6b, 0x67, 0x49, \
|
||||
0x63, 0x6f, 0x6e, 0x73, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, 0x22, \
|
||||
0x64, 0x65, 0x72, 0x69, 0x76, 0x65, 0x64, 0x52, 0x61, 0x74, 0x69, 0x6e, \
|
||||
0x67, 0x22, 0x3a, 0x32, 0x2e, 0x30, 0x2c, 0x22, 0x70, 0x72, 0x6f, 0x6d, \
|
||||
0x69, 0x6e, 0x65, 0x6e, 0x63, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x69, \
|
||||
0x6e, 0x67, 0x22, 0x3a, 0x31, 0x30, 0x30, 0x30, 0x2c, 0x22, 0x70, 0x6b, \
|
||||
0x67, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x6c, 0x6f, 0x67, 0x43, 0x6f, \
|
||||
0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x7d, \
|
||||
0x2c, 0x7b, 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x3a, 0x22, 0x66, 0x61, \
|
||||
0x6c, 0x6c, 0x6c, 0x65, 0x61, 0x76, 0x65, 0x73, 0x22, 0x2c, 0x22, 0x6d, \
|
||||
0x6f, 0x64, 0x69, 0x66, 0x79, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, \
|
||||
0x6d, 0x70, 0x22, 0x3a, 0x31, 0x34, 0x36, 0x33, 0x36, 0x38, 0x34, 0x36, \
|
||||
0x35, 0x38, 0x33, 0x39, 0x38, 0x2c, 0x22, 0x76, 0x65, 0x72, 0x73, 0x69, \
|
||||
0x6f, 0x6e, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x6d, 0x61, 0x6a, 0x6f, \
|
||||
0x72, 0x22, 0x3a, 0x22, 0x31, 0x22, 0x2c, 0x22, 0x6d, 0x69, 0x6e, 0x6f, \
|
||||
0x72, 0x22, 0x3a, 0x22, 0x32, 0x22, 0x2c, 0x22, 0x6d, 0x69, 0x63, 0x72, \
|
||||
0x6f, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, 0x22, 0x70, 0x72, 0x65, \
|
||||
0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x22, 0x3a, 0x6e, 0x75, 0x6c, \
|
||||
0x6c, 0x2c, 0x22, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x22, \
|
||||
0x3a, 0x31, 0x2c, 0x22, 0x61, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, \
|
||||
0x74, 0x75, 0x72, 0x65, 0x43, 0x6f, 0x64, 0x65, 0x22, 0x3a, 0x22, 0x78, \
|
||||
0x38, 0x36, 0x5f, 0x67, 0x63, 0x63, 0x32, 0x22, 0x2c, 0x22, 0x74, 0x69, \
|
||||
0x74, 0x6c, 0x65, 0x22, 0x3a, 0x22, 0x46, 0x61, 0x6c, 0x6c, 0x20, 0x4c, \
|
||||
0x65, 0x61, 0x76, 0x65, 0x73, 0x22, 0x2c, 0x22, 0x72, 0x65, 0x70, 0x6f, \
|
||||
0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, \
|
||||
0x43, 0x6f, 0x64, 0x65, 0x22, 0x3a, 0x22, 0x66, 0x61, 0x74, 0x65, 0x6c, \
|
||||
0x6b, 0x5f, 0x78, 0x38, 0x36, 0x5f, 0x67, 0x63, 0x63, 0x32, 0x22, 0x2c, \
|
||||
0x22, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x43, \
|
||||
0x6f, 0x64, 0x65, 0x22, 0x3a, 0x22, 0x66, 0x61, 0x74, 0x65, 0x6c, 0x6b, \
|
||||
0x22, 0x2c, 0x22, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x22, 0x3a, \
|
||||
0x22, 0x46, 0x61, 0x6c, 0x6c, 0x20, 0x4c, 0x65, 0x61, 0x76, 0x65, 0x73, \
|
||||
0x20, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x73, 0x61, 0x76, 0x65, 0x72, \
|
||||
0x22, 0x2c, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, \
|
||||
0x6f, 0x6e, 0x22, 0x3a, 0x22, 0x41, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x6c, \
|
||||
0x79, 0x20, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x73, 0x61, 0x76, 0x65, \
|
||||
0x72, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x66, 0x61, 0x6c, 0x6c, 0x69, \
|
||||
0x6e, 0x67, 0x20, 0x48, 0x61, 0x69, 0x6b, 0x75, 0x20, 0x6c, 0x65, 0x61, \
|
||||
0x76, 0x65, 0x73, 0x2e, 0x22, 0x2c, 0x22, 0x70, 0x61, 0x79, 0x6c, 0x6f, \
|
||||
0x61, 0x64, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x22, 0x3a, 0x31, 0x32, \
|
||||
0x34, 0x31, 0x32, 0x7d, 0x5d, 0x2c, 0x22, 0x70, 0x6b, 0x67, 0x43, 0x61, \
|
||||
0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x73, 0x22, \
|
||||
0x3a, 0x5b, 0x22, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x61, 0x6e, 0x64, \
|
||||
0x75, 0x74, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x22, 0x5d, 0x2c, \
|
||||
0x22, 0x70, 0x6b, 0x67, 0x53, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x73, 0x68, \
|
||||
0x6f, 0x74, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x63, 0x6f, 0x64, 0x65, \
|
||||
0x22, 0x3a, 0x22, 0x64, 0x64, 0x62, 0x37, 0x62, 0x63, 0x66, 0x63, 0x2d, \
|
||||
0x64, 0x35, 0x32, 0x31, 0x2d, 0x34, 0x61, 0x66, 0x36, 0x2d, 0x38, 0x32, \
|
||||
0x38, 0x33, 0x2d, 0x34, 0x62, 0x30, 0x31, 0x66, 0x39, 0x36, 0x63, 0x63, \
|
||||
0x31, 0x34, 0x39, 0x22, 0x2c, 0x22, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, \
|
||||
0x22, 0x3a, 0x32, 0x36, 0x31, 0x33, 0x36, 0x35, 0x2c, 0x22, 0x68, 0x65, \
|
||||
0x69, 0x67, 0x68, 0x74, 0x22, 0x3a, 0x31, 0x30, 0x32, 0x34, 0x2c, 0x22, \
|
||||
0x77, 0x69, 0x64, 0x74, 0x68, 0x22, 0x3a, 0x31, 0x32, 0x38, 0x30, 0x7d, \
|
||||
0x5d, 0x2c, 0x22, 0x70, 0x6b, 0x67, 0x49, 0x63, 0x6f, 0x6e, 0x73, 0x22, \
|
||||
0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, 0x22, 0x64, 0x65, 0x72, 0x69, 0x76, \
|
||||
0x65, 0x64, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x22, 0x3a, 0x6e, 0x75, \
|
||||
0x6c, 0x6c, 0x2c, 0x22, 0x70, 0x72, 0x6f, 0x6d, 0x69, 0x6e, 0x65, 0x6e, \
|
||||
0x63, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x3a, \
|
||||
0x31, 0x30, 0x30, 0x30, 0x2c, 0x22, 0x70, 0x6b, 0x67, 0x43, 0x68, 0x61, \
|
||||
0x6e, 0x67, 0x65, 0x6c, 0x6f, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, \
|
||||
0x74, 0x22, 0x3a, 0x22, 0x31, 0x2e, 0x32, 0x20, 0x63, 0x68, 0x61, 0x6e, \
|
||||
0x67, 0x65, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x20, \
|
||||
0x62, 0x79, 0x20, 0x68, 0x72, 0x65, 0x76, 0x35, 0x30, 0x32, 0x32, 0x36, \
|
||||
0x20, 0x20, 0x74, 0x6f, 0x20, 0x75, 0x73, 0x65, 0x20, 0x42, 0x75, 0x69, \
|
||||
0x6c, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x53, 0x65, 0x74, \
|
||||
0x74, 0x69, 0x6e, 0x67, 0x73, 0x56, 0x69, 0x65, 0x77, 0x5c, 0x6e, 0x5c, \
|
||||
0x6e, 0x31, 0x2e, 0x31, 0x20, 0x6d, 0x61, 0x6b, 0x65, 0x20, 0x73, 0x6f, \
|
||||
0x6d, 0x65, 0x20, 0x6c, 0x65, 0x76, 0x65, 0x73, 0x20, 0x63, 0x68, 0x61, \
|
||||
0x6e, 0x67, 0x65, 0x20, 0x6f, 0x72, 0x69, 0x65, 0x6e, 0x74, 0x61, 0x74, \
|
||||
0x69, 0x6f, 0x6e, 0x5c, 0x6e, 0x5c, 0x6e, 0x31, 0x2e, 0x30, 0x20, 0x6f, \
|
||||
0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x6c, 0x65, \
|
||||
0x61, 0x73, 0x65, 0x22, 0x7d, 0x2c, 0x7b, 0x22, 0x6e, 0x61, 0x6d, 0x65, \
|
||||
0x22, 0x3a, 0x22, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x62, 0x75, \
|
||||
0x69, 0x6c, 0x64, 0x65, 0x72, 0x22, 0x2c, 0x22, 0x6d, 0x6f, 0x64, 0x69, \
|
||||
0x66, 0x79, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, \
|
||||
0x3a, 0x31, 0x34, 0x38, 0x38, 0x38, 0x30, 0x34, 0x37, 0x30, 0x30, 0x36, \
|
||||
0x33, 0x30, 0x2c, 0x22, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, \
|
||||
0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x22, 0x3a, \
|
||||
0x22, 0x34, 0x22, 0x2c, 0x22, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x22, 0x3a, \
|
||||
0x22, 0x35, 0x22, 0x2c, 0x22, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x22, 0x3a, \
|
||||
0x6e, 0x75, 0x6c, 0x6c, 0x2c, 0x22, 0x70, 0x72, 0x65, 0x52, 0x65, 0x6c, \
|
||||
0x65, 0x61, 0x73, 0x65, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, 0x22, \
|
||||
0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x31, 0x2c, \
|
||||
0x22, 0x61, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, \
|
||||
0x65, 0x43, 0x6f, 0x64, 0x65, 0x22, 0x3a, 0x22, 0x78, 0x38, 0x36, 0x5f, \
|
||||
0x67, 0x63, 0x63, 0x32, 0x22, 0x2c, 0x22, 0x74, 0x69, 0x74, 0x6c, 0x65, \
|
||||
0x22, 0x3a, 0x22, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x42, 0x75, \
|
||||
0x69, 0x6c, 0x64, 0x65, 0x72, 0x22, 0x2c, 0x22, 0x72, 0x65, 0x70, 0x6f, \
|
||||
0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, \
|
||||
0x43, 0x6f, 0x64, 0x65, 0x22, 0x3a, 0x22, 0x66, 0x61, 0x74, 0x65, 0x6c, \
|
||||
0x6b, 0x5f, 0x78, 0x38, 0x36, 0x5f, 0x67, 0x63, 0x63, 0x32, 0x22, 0x2c, \
|
||||
0x22, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x43, \
|
||||
0x6f, 0x64, 0x65, 0x22, 0x3a, 0x22, 0x66, 0x61, 0x74, 0x65, 0x6c, 0x6b, \
|
||||
0x22, 0x2c, 0x22, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x22, 0x3a, \
|
||||
0x22, 0x55, 0x74, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x20, 0x74, 0x6f, 0x20, \
|
||||
0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6f, \
|
||||
0x70, 0x65, 0x6e, 0x20, 0x2e, 0x70, 0x6b, 0x67, 0x20, 0x66, 0x69, 0x6c, \
|
||||
0x65, 0x73, 0x22, 0x2c, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, \
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x22, 0x54, 0x68, 0x69, 0x73, 0x20, \
|
||||
0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, \
|
||||
0x77, 0x61, 0x73, 0x20, 0x42, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x27, \
|
||||
0x73, 0x20, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x20, 0x6f, 0x66, 0x20, \
|
||||
0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x2e, 0x70, 0x6b, \
|
||||
0x67, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, \
|
||||
0x6f, 0x6e, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x20, 0x49, 0x74, \
|
||||
0x20, 0x77, 0x61, 0x73, 0x20, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, \
|
||||
0x64, 0x20, 0x73, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x6c, 0x79, \
|
||||
0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x42, 0x65, 0x4f, 0x53, 0x20, 0x61, \
|
||||
0x73, 0x20, 0x70, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, \
|
||||
0x65, 0x20, 0x64, 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x72, 0x20, \
|
||||
0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x20, 0x49, 0x74, 0x20, 0x69, 0x73, \
|
||||
0x20, 0x75, 0x6e, 0x6c, 0x69, 0x6b, 0x65, 0x6c, 0x79, 0x20, 0x74, 0x68, \
|
||||
0x61, 0x74, 0x20, 0x61, 0x6e, 0x79, 0x6f, 0x6e, 0x65, 0x20, 0x77, 0x69, \
|
||||
0x6c, 0x6c, 0x20, 0x73, 0x74, 0x69, 0x6c, 0x6c, 0x20, 0x77, 0x61, 0x6e, \
|
||||
0x74, 0x20, 0x74, 0x6f, 0x20, 0x6d, 0x61, 0x6b, 0x65, 0x20, 0x74, 0x68, \
|
||||
0x65, 0x73, 0x65, 0x20, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, \
|
||||
0x20, 0x6e, 0x6f, 0x77, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x77, 0x65, \
|
||||
0x20, 0x61, 0x72, 0x65, 0x20, 0x6d, 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x20, \
|
||||
0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x27, 0x68, 0x70, 0x6b, 0x67, \
|
||||
0x20, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x20, 0x42, 0x75, 0x74, \
|
||||
0x20, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x42, 0x75, 0x69, 0x6c, \
|
||||
0x64, 0x65, 0x72, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6f, \
|
||||
0x6e, 0x6c, 0x79, 0x20, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x20, 0x77, 0x61, \
|
||||
0x79, 0x20, 0x74, 0x6f, 0x20, 0x72, 0x69, 0x70, 0x20, 0x61, 0x20, 0x2e, \
|
||||
0x70, 0x6b, 0x67, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x61, 0x70, 0x61, \
|
||||
0x72, 0x74, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x67, 0x65, 0x74, 0x20, 0x61, \
|
||||
0x74, 0x20, 0x69, 0x74, 0x73, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, \
|
||||
0x74, 0x73, 0x2e, 0x20, 0x49, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, \
|
||||
0x65, 0x72, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x20, 0x73, 0x74, 0x69, 0x6c, \
|
||||
0x6c, 0x20, 0x6f, 0x66, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x65, 0x73, \
|
||||
0x74, 0x20, 0x74, 0x6f, 0x20, 0x64, 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, \
|
||||
0x65, 0x72, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x70, 0x6f, 0x72, 0x74, \
|
||||
0x65, 0x72, 0x73, 0x2e, 0x22, 0x2c, 0x22, 0x70, 0x61, 0x79, 0x6c, 0x6f, \
|
||||
0x61, 0x64, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x22, 0x3a, 0x34, 0x39, \
|
||||
0x38, 0x38, 0x38, 0x36, 0x7d, 0x5d, 0x2c, 0x22, 0x70, 0x6b, 0x67, 0x43, \
|
||||
0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x73, \
|
||||
0x22, 0x3a, 0x5b, 0x22, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x61, 0x6e, \
|
||||
0x64, 0x75, 0x74, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x22, 0x2c, \
|
||||
0x22, 0x64, 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x6d, 0x65, 0x6e, 0x74, \
|
||||
0x22, 0x5d, 0x2c, 0x22, 0x70, 0x6b, 0x67, 0x53, 0x63, 0x72, 0x65, 0x65, \
|
||||
0x6e, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x63, \
|
||||
0x6f, 0x64, 0x65, 0x22, 0x3a, 0x22, 0x65, 0x66, 0x62, 0x34, 0x32, 0x32, \
|
||||
0x31, 0x34, 0x2d, 0x30, 0x31, 0x66, 0x36, 0x2d, 0x34, 0x38, 0x37, 0x63, \
|
||||
0x2d, 0x61, 0x33, 0x39, 0x33, 0x2d, 0x36, 0x32, 0x61, 0x33, 0x61, 0x31, \
|
||||
0x34, 0x64, 0x31, 0x36, 0x30, 0x31, 0x22, 0x2c, 0x22, 0x6c, 0x65, 0x6e, \
|
||||
0x67, 0x74, 0x68, 0x22, 0x3a, 0x35, 0x34, 0x32, 0x31, 0x33, 0x2c, 0x22, \
|
||||
0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x22, 0x3a, 0x33, 0x36, 0x30, 0x2c, \
|
||||
0x22, 0x77, 0x69, 0x64, 0x74, 0x68, 0x22, 0x3a, 0x33, 0x32, 0x37, 0x7d, \
|
||||
0x5d, 0x2c, 0x22, 0x70, 0x6b, 0x67, 0x49, 0x63, 0x6f, 0x6e, 0x73, 0x22, \
|
||||
0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, 0x22, 0x64, 0x65, 0x72, 0x69, 0x76, \
|
||||
0x65, 0x64, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x22, 0x3a, 0x34, 0x2e, \
|
||||
0x30, 0x2c, 0x22, 0x70, 0x72, 0x6f, 0x6d, 0x69, 0x6e, 0x65, 0x6e, 0x63, \
|
||||
0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x3a, 0x31, \
|
||||
0x30, 0x30, 0x2c, 0x22, 0x70, 0x6b, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x67, \
|
||||
0x65, 0x6c, 0x6f, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, \
|
||||
0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x7d, 0x2c, 0x7b, 0x22, 0x6e, 0x61, 0x6d, \
|
||||
0x65, 0x22, 0x3a, 0x22, 0x72, 0x61, 0x77, 0x61, 0x65, 0x73, 0x22, 0x2c, \
|
||||
0x22, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x54, 0x69, 0x6d, 0x65, 0x73, \
|
||||
0x74, 0x61, 0x6d, 0x70, 0x22, 0x3a, 0x31, 0x34, 0x39, 0x31, 0x36, 0x35, \
|
||||
0x32, 0x30, 0x33, 0x39, 0x30, 0x38, 0x39, 0x2c, 0x22, 0x76, 0x65, 0x72, \
|
||||
0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x6d, 0x61, \
|
||||
0x6a, 0x6f, 0x72, 0x22, 0x3a, 0x22, 0x31, 0x22, 0x2c, 0x22, 0x6d, 0x69, \
|
||||
0x6e, 0x6f, 0x72, 0x22, 0x3a, 0x22, 0x31, 0x22, 0x2c, 0x22, 0x6d, 0x69, \
|
||||
0x63, 0x72, 0x6f, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, 0x22, 0x70, \
|
||||
0x72, 0x65, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x22, 0x3a, 0x6e, \
|
||||
0x75, 0x6c, 0x6c, 0x2c, 0x22, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, \
|
||||
0x6e, 0x22, 0x3a, 0x31, 0x2c, 0x22, 0x61, 0x72, 0x63, 0x68, 0x69, 0x74, \
|
||||
0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x43, 0x6f, 0x64, 0x65, 0x22, 0x3a, \
|
||||
0x22, 0x78, 0x38, 0x36, 0x5f, 0x67, 0x63, 0x63, 0x32, 0x22, 0x2c, 0x22, \
|
||||
0x74, 0x69, 0x74, 0x6c, 0x65, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, \
|
||||
0x22, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x53, \
|
||||
0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x6f, 0x64, 0x65, 0x22, 0x3a, 0x22, \
|
||||
0x66, 0x61, 0x74, 0x65, 0x6c, 0x6b, 0x5f, 0x78, 0x38, 0x36, 0x5f, 0x67, \
|
||||
0x63, 0x63, 0x32, 0x22, 0x2c, 0x22, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, \
|
||||
0x74, 0x6f, 0x72, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x22, 0x3a, 0x22, 0x66, \
|
||||
0x61, 0x74, 0x65, 0x6c, 0x6b, 0x22, 0x2c, 0x22, 0x73, 0x75, 0x6d, 0x6d, \
|
||||
0x61, 0x72, 0x79, 0x22, 0x3a, 0x22, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, \
|
||||
0x64, 0x2d, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x65, 0x6e, 0x63, 0x72, 0x79, \
|
||||
0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x75, 0x74, 0x69, 0x6c, 0x69, 0x74, \
|
||||
0x79, 0x22, 0x2c, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, \
|
||||
0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x22, 0x52, 0x61, 0x77, 0x61, 0x65, 0x73, \
|
||||
0x20, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x73, 0x20, 0x61, 0x20, \
|
||||
0x66, 0x69, 0x6c, 0x65, 0x20, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x74, \
|
||||
0x68, 0x65, 0x20, 0x41, 0x64, 0x76, 0x61, 0x6e, 0x64, 0x63, 0x65, 0x64, \
|
||||
0x20, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, \
|
||||
0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x28, 0x41, 0x45, \
|
||||
0x53, 0x29, 0x2e, 0x20, 0x20, 0x41, 0x45, 0x53, 0x20, 0x75, 0x73, 0x65, \
|
||||
0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x52, 0x69, 0x6a, 0x6e, 0x64, 0x61, \
|
||||
0x65, 0x6c, 0x20, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, \
|
||||
0x2c, 0x20, 0x61, 0x20, 0x31, 0x32, 0x38, 0x2d, 0x62, 0x69, 0x74, 0x20, \
|
||||
0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x20, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, \
|
||||
0x2c, 0x20, 0x74, 0x6f, 0x20, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, \
|
||||
0x2e, 0x20, 0x20, 0x53, 0x69, 0x6e, 0x63, 0x65, 0x20, 0x74, 0x68, 0x65, \
|
||||
0x20, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, \
|
||||
0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x20, 0x31, 0x36, 0x2d, \
|
||||
0x62, 0x79, 0x74, 0x65, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x2c, \
|
||||
0x20, 0x72, 0x61, 0x77, 0x61, 0x65, 0x73, 0x20, 0x77, 0x69, 0x6c, 0x6c, \
|
||||
0x20, 0x70, 0x61, 0x64, 0x20, 0x61, 0x6e, 0x79, 0x20, 0x75, 0x6e, 0x65, \
|
||||
0x76, 0x65, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x20, 0x77, \
|
||||
0x69, 0x74, 0x68, 0x20, 0x30, 0x73, 0x2c, 0x20, 0x70, 0x6f, 0x73, 0x73, \
|
||||
0x69, 0x62, 0x6c, 0x79, 0x20, 0x69, 0x6e, 0x63, 0x72, 0x65, 0x61, 0x73, \
|
||||
0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x69, 0x7a, 0x65, \
|
||||
0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x6c, 0x65, \
|
||||
0x20, 0x75, 0x70, 0x20, 0x74, 0x6f, 0x20, 0x31, 0x35, 0x20, 0x62, 0x79, \
|
||||
0x74, 0x65, 0x73, 0x2e, 0x22, 0x2c, 0x22, 0x70, 0x61, 0x79, 0x6c, 0x6f, \
|
||||
0x61, 0x64, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x22, 0x3a, 0x36, 0x32, \
|
||||
0x37, 0x39, 0x33, 0x7d, 0x5d, 0x2c, 0x22, 0x70, 0x6b, 0x67, 0x43, 0x61, \
|
||||
0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x73, 0x22, \
|
||||
0x3a, 0x5b, 0x22, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x61, 0x6e, 0x64, \
|
||||
0x75, 0x74, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x22, 0x2c, 0x22, \
|
||||
0x73, 0x63, 0x69, 0x65, 0x6e, 0x63, 0x65, 0x61, 0x6e, 0x64, 0x6d, 0x61, \
|
||||
0x74, 0x68, 0x65, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x73, 0x22, 0x5d, 0x2c, \
|
||||
0x22, 0x70, 0x6b, 0x67, 0x53, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x73, 0x68, \
|
||||
0x6f, 0x74, 0x73, 0x22, 0x3a, 0x5b, 0x5d, 0x2c, 0x22, 0x70, 0x6b, 0x67, \
|
||||
0x49, 0x63, 0x6f, 0x6e, 0x73, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, \
|
||||
0x22, 0x64, 0x65, 0x72, 0x69, 0x76, 0x65, 0x64, 0x52, 0x61, 0x74, 0x69, \
|
||||
0x6e, 0x67, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, 0x22, 0x70, 0x72, \
|
||||
0x6f, 0x6d, 0x69, 0x6e, 0x65, 0x6e, 0x63, 0x65, 0x4f, 0x72, 0x64, 0x65, \
|
||||
0x72, 0x69, 0x6e, 0x67, 0x22, 0x3a, 0x31, 0x30, 0x30, 0x30, 0x2c, 0x22, \
|
||||
0x70, 0x6b, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x6c, 0x6f, 0x67, \
|
||||
0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x3a, 0x6e, 0x75, 0x6c, \
|
||||
0x6c, 0x7d, 0x2c, 0x7b, 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x3a, 0x22, \
|
||||
0x74, 0x65, 0x78, 0x74, 0x73, 0x61, 0x76, 0x65, 0x72, 0x22, 0x2c, 0x22, \
|
||||
0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, \
|
||||
0x61, 0x6d, 0x70, 0x22, 0x3a, 0x31, 0x34, 0x39, 0x31, 0x36, 0x35, 0x32, \
|
||||
0x30, 0x33, 0x39, 0x38, 0x30, 0x39, 0x2c, 0x22, 0x76, 0x65, 0x72, 0x73, \
|
||||
0x69, 0x6f, 0x6e, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x6d, 0x61, 0x6a, \
|
||||
0x6f, 0x72, 0x22, 0x3a, 0x22, 0x31, 0x22, 0x2c, 0x22, 0x6d, 0x69, 0x6e, \
|
||||
0x6f, 0x72, 0x22, 0x3a, 0x22, 0x30, 0x22, 0x2c, 0x22, 0x6d, 0x69, 0x63, \
|
||||
0x72, 0x6f, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, 0x22, 0x70, 0x72, \
|
||||
0x65, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x22, 0x3a, 0x6e, 0x75, \
|
||||
0x6c, 0x6c, 0x2c, 0x22, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, \
|
||||
0x22, 0x3a, 0x31, 0x2c, 0x22, 0x61, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, \
|
||||
0x63, 0x74, 0x75, 0x72, 0x65, 0x43, 0x6f, 0x64, 0x65, 0x22, 0x3a, 0x22, \
|
||||
0x78, 0x38, 0x36, 0x5f, 0x67, 0x63, 0x63, 0x32, 0x22, 0x2c, 0x22, 0x74, \
|
||||
0x69, 0x74, 0x6c, 0x65, 0x22, 0x3a, 0x22, 0x54, 0x65, 0x78, 0x74, 0x53, \
|
||||
0x61, 0x76, 0x65, 0x72, 0x22, 0x2c, 0x22, 0x72, 0x65, 0x70, 0x6f, 0x73, \
|
||||
0x69, 0x74, 0x6f, 0x72, 0x79, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, \
|
||||
0x6f, 0x64, 0x65, 0x22, 0x3a, 0x22, 0x66, 0x61, 0x74, 0x65, 0x6c, 0x6b, \
|
||||
0x5f, 0x78, 0x38, 0x36, 0x5f, 0x67, 0x63, 0x63, 0x32, 0x22, 0x2c, 0x22, \
|
||||
0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x43, 0x6f, \
|
||||
0x64, 0x65, 0x22, 0x3a, 0x22, 0x66, 0x61, 0x74, 0x65, 0x6c, 0x6b, 0x22, \
|
||||
0x2c, 0x22, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x22, 0x3a, 0x22, \
|
||||
0x54, 0x65, 0x78, 0x74, 0x53, 0x61, 0x76, 0x65, 0x72, 0x20, 0x73, 0x63, \
|
||||
0x72, 0x65, 0x65, 0x6e, 0x73, 0x61, 0x76, 0x65, 0x72, 0x22, 0x2c, 0x22, \
|
||||
0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, \
|
||||
0x3a, 0x22, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x73, 0x20, 0x79, \
|
||||
0x6f, 0x75, 0x72, 0x20, 0x74, 0x65, 0x78, 0x74, 0x20, 0x61, 0x74, 0x20, \
|
||||
0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x74, \
|
||||
0x69, 0x6f, 0x6e, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x72, 0x61, 0x6e, 0x64, \
|
||||
0x6f, 0x6d, 0x20, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x73, 0x2e, 0x22, 0x2c, \
|
||||
0x22, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x4c, 0x65, 0x6e, 0x67, \
|
||||
0x74, 0x68, 0x22, 0x3a, 0x31, 0x32, 0x31, 0x36, 0x38, 0x7d, 0x5d, 0x2c, \
|
||||
0x22, 0x70, 0x6b, 0x67, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, \
|
||||
0x43, 0x6f, 0x64, 0x65, 0x73, 0x22, 0x3a, 0x5b, 0x22, 0x73, 0x79, 0x73, \
|
||||
0x74, 0x65, 0x6d, 0x61, 0x6e, 0x64, 0x75, 0x74, 0x69, 0x6c, 0x69, 0x74, \
|
||||
0x69, 0x65, 0x73, 0x22, 0x5d, 0x2c, 0x22, 0x70, 0x6b, 0x67, 0x53, 0x63, \
|
||||
0x72, 0x65, 0x65, 0x6e, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x22, 0x3a, 0x5b, \
|
||||
0x5d, 0x2c, 0x22, 0x70, 0x6b, 0x67, 0x49, 0x63, 0x6f, 0x6e, 0x73, 0x22, \
|
||||
0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, 0x22, 0x64, 0x65, 0x72, 0x69, 0x76, \
|
||||
0x65, 0x64, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x22, 0x3a, 0x6e, 0x75, \
|
||||
0x6c, 0x6c, 0x2c, 0x22, 0x70, 0x72, 0x6f, 0x6d, 0x69, 0x6e, 0x65, 0x6e, \
|
||||
0x63, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x3a, \
|
||||
0x31, 0x30, 0x30, 0x30, 0x2c, 0x22, 0x70, 0x6b, 0x67, 0x43, 0x68, 0x61, \
|
||||
0x6e, 0x67, 0x65, 0x6c, 0x6f, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, \
|
||||
0x74, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x7d, 0x2c, 0x7b, 0x22, 0x6e, \
|
||||
0x61, 0x6d, 0x65, 0x22, 0x3a, 0x22, 0x76, 0x6e, 0x63, 0x73, 0x65, 0x72, \
|
||||
0x76, 0x65, 0x72, 0x22, 0x2c, 0x22, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, \
|
||||
0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x3a, 0x31, \
|
||||
0x34, 0x39, 0x31, 0x36, 0x35, 0x32, 0x30, 0x34, 0x30, 0x32, 0x34, 0x34, \
|
||||
0x2c, 0x22, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x3a, \
|
||||
0x5b, 0x7b, 0x22, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x22, 0x3a, 0x22, 0x76, \
|
||||
0x6e, 0x63, 0x34, 0x5f, 0x30, 0x22, 0x2c, 0x22, 0x6d, 0x69, 0x6e, 0x6f, \
|
||||
0x72, 0x22, 0x3a, 0x22, 0x61, 0x67, 0x6d, 0x73, 0x5f, 0x31, 0x22, 0x2c, \
|
||||
0x22, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x22, 0x3a, 0x22, 0x32, 0x37, 0x22, \
|
||||
0x2c, 0x22, 0x70, 0x72, 0x65, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, \
|
||||
0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, 0x22, 0x72, 0x65, 0x76, 0x69, \
|
||||
0x73, 0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x32, 0x2c, 0x22, 0x61, 0x72, 0x63, \
|
||||
0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x43, 0x6f, 0x64, \
|
||||
0x65, 0x22, 0x3a, 0x22, 0x78, 0x38, 0x36, 0x5f, 0x67, 0x63, 0x63, 0x32, \
|
||||
0x22, 0x2c, 0x22, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x22, 0x3a, 0x22, 0x56, \
|
||||
0x4e, 0x43, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x22, 0x2c, 0x22, 0x72, \
|
||||
0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x53, 0x6f, 0x75, \
|
||||
0x72, 0x63, 0x65, 0x43, 0x6f, 0x64, 0x65, 0x22, 0x3a, 0x22, 0x66, 0x61, \
|
||||
0x74, 0x65, 0x6c, 0x6b, 0x5f, 0x78, 0x38, 0x36, 0x5f, 0x67, 0x63, 0x63, \
|
||||
0x32, 0x22, 0x2c, 0x22, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, \
|
||||
0x72, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x22, 0x3a, 0x22, 0x66, 0x61, 0x74, \
|
||||
0x65, 0x6c, 0x6b, 0x22, 0x2c, 0x22, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, \
|
||||
0x79, 0x22, 0x3a, 0x22, 0x56, 0x4e, 0x43, 0x53, 0x65, 0x72, 0x76, 0x65, \
|
||||
0x72, 0x20, 0x6c, 0x65, 0x74, 0x73, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x75, \
|
||||
0x73, 0x65, 0x20, 0x79, 0x6f, 0x75, 0x72, 0x20, 0x42, 0x65, 0x4f, 0x53, \
|
||||
0x20, 0x2f, 0x20, 0x48, 0x61, 0x69, 0x6b, 0x75, 0x20, 0x63, 0x6f, 0x6d, \
|
||||
0x70, 0x75, 0x74, 0x65, 0x72, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x61, \
|
||||
0x6e, 0x79, 0x77, 0x68, 0x65, 0x72, 0x65, 0x20, 0x74, 0x68, 0x65, 0x72, \
|
||||
0x65, 0x20, 0x69, 0x73, 0x20, 0x61, 0x6e, 0x20, 0x49, 0x6e, 0x74, 0x65, \
|
||||
0x72, 0x6e, 0x65, 0x74, 0x20, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, \
|
||||
0x69, 0x6f, 0x6e, 0x2e, 0x20, 0x20, 0x59, 0x6f, 0x75, 0x20, 0x63, 0x61, \
|
||||
0x6e, 0x20, 0x74, 0x68, 0x69, 0x6e, 0x6b, 0x20, 0x6f, 0x66, 0x20, 0x69, \
|
||||
0x74, 0x20, 0x61, 0x73, 0x20, 0x61, 0x20, 0x72, 0x65, 0x61, 0x6c, 0x6c, \
|
||||
0x79, 0x20, 0x6c, 0x6f, 0x6e, 0x67, 0x20, 0x6b, 0x65, 0x79, 0x62, 0x6f, \
|
||||
0x61, 0x72, 0x64, 0x2c, 0x20, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x20, 0x61, \
|
||||
0x6e, 0x64, 0x20, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x20, 0x63, 0x61, 0x62, \
|
||||
0x6c, 0x65, 0x2e, 0x22, 0x2c, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, \
|
||||
0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x22, 0x41, 0x20, 0x56, 0x4e, \
|
||||
0x43, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x28, 0x61, 0x76, \
|
||||
0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x65, 0x6c, 0x73, 0x65, \
|
||||
0x77, 0x68, 0x65, 0x72, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x57, 0x69, \
|
||||
0x6e, 0x64, 0x6f, 0x77, 0x73, 0x2c, 0x20, 0x4d, 0x61, 0x63, 0x2c, 0x20, \
|
||||
0x4c, 0x69, 0x6e, 0x75, 0x78, 0x2c, 0x20, 0x6f, 0x74, 0x68, 0x65, 0x72, \
|
||||
0x73, 0x29, 0x20, 0x73, 0x68, 0x6f, 0x77, 0x73, 0x20, 0x79, 0x6f, 0x75, \
|
||||
0x20, 0x77, 0x68, 0x61, 0x74, 0x27, 0x73, 0x20, 0x6f, 0x6e, 0x20, 0x74, \
|
||||
0x68, 0x65, 0x20, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x20, 0x42, 0x65, \
|
||||
0x4f, 0x53, 0x20, 0x2f, 0x20, 0x48, 0x61, 0x69, 0x6b, 0x75, 0x20, 0x63, \
|
||||
0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x27, 0x73, 0x20, 0x73, 0x63, \
|
||||
0x72, 0x65, 0x65, 0x6e, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x73, 0x65, 0x6e, \
|
||||
0x64, 0x73, 0x20, 0x6b, 0x65, 0x79, 0x73, 0x74, 0x72, 0x6f, 0x6b, 0x65, \
|
||||
0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x20, \
|
||||
0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x6f, 0x76, 0x65, 0x72, \
|
||||
0x20, 0x74, 0x68, 0x65, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, \
|
||||
0x74, 0x2e, 0x20, 0x20, 0x54, 0x68, 0x65, 0x20, 0x56, 0x4e, 0x43, 0x53, \
|
||||
0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, \
|
||||
0x72, 0x65, 0x20, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x6f, \
|
||||
0x6e, 0x20, 0x42, 0x65, 0x4f, 0x53, 0x20, 0x6f, 0x72, 0x20, 0x48, 0x61, \
|
||||
0x69, 0x6b, 0x75, 0x20, 0x75, 0x73, 0x65, 0x73, 0x20, 0x74, 0x68, 0x61, \
|
||||
0x74, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x64, 0x61, 0x74, \
|
||||
0x61, 0x20, 0x74, 0x6f, 0x20, 0x73, 0x69, 0x6d, 0x75, 0x6c, 0x61, 0x74, \
|
||||
0x65, 0x20, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x20, 0x70, 0x72, 0x65, \
|
||||
0x73, 0x73, 0x65, 0x73, 0x20, 0x6f, 0x6e, 0x20, 0x61, 0x20, 0x66, 0x61, \
|
||||
0x6b, 0x65, 0x20, 0x6b, 0x65, 0x79, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x20, \
|
||||
0x61, 0x6e, 0x64, 0x20, 0x6d, 0x6f, 0x76, 0x65, 0x6d, 0x65, 0x6e, 0x74, \
|
||||
0x73, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x6e, 0x20, 0x69, 0x6d, 0x61, 0x67, \
|
||||
0x69, 0x6e, 0x61, 0x72, 0x79, 0x20, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x2e, \
|
||||
0x20, 0x20, 0x49, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6f, 0x70, 0x70, \
|
||||
0x6f, 0x73, 0x69, 0x74, 0x65, 0x20, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, \
|
||||
0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x56, 0x4e, 0x43, 0x53, 0x65, 0x72, 0x76, \
|
||||
0x65, 0x72, 0x20, 0x73, 0x63, 0x61, 0x6e, 0x73, 0x20, 0x79, 0x6f, 0x75, \
|
||||
0x72, 0x20, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x66, 0x6f, 0x72, \
|
||||
0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x2c, 0x20, 0x63, 0x6f, \
|
||||
0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, \
|
||||
0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x67, \
|
||||
0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x20, 0x64, 0x61, 0x74, 0x61, \
|
||||
0x20, 0x61, 0x6e, 0x64, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x6d, 0x69, \
|
||||
0x74, 0x73, 0x20, 0x69, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, \
|
||||
0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x5c, 0x6e, 0x5c, 0x6e, \
|
||||
0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x70, 0x6f, \
|
||||
0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x56, 0x4e, 0x43, 0x20, 0x75, 0x73, \
|
||||
0x69, 0x6e, 0x67, 0x20, 0x52, 0x65, 0x61, 0x6c, 0x56, 0x4e, 0x43, 0x27, \
|
||||
0x73, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x34, 0x2e, \
|
||||
0x30, 0x20, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x20, 0x73, 0x6f, 0x75, 0x72, \
|
||||
0x63, 0x65, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x28, 0x77, 0x68, 0x69, \
|
||||
0x63, 0x68, 0x20, 0x68, 0x61, 0x73, 0x20, 0x61, 0x6e, 0x20, 0x65, 0x78, \
|
||||
0x74, 0x72, 0x65, 0x6d, 0x65, 0x6c, 0x79, 0x20, 0x77, 0x65, 0x6c, 0x6c, \
|
||||
0x20, 0x64, 0x65, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x63, 0x6c, \
|
||||
0x61, 0x73, 0x73, 0x20, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, \
|
||||
0x65, 0x2c, 0x20, 0x6d, 0x61, 0x6b, 0x69, 0x6e, 0x67, 0x20, 0x69, 0x74, \
|
||||
0x20, 0x65, 0x61, 0x73, 0x79, 0x20, 0x74, 0x6f, 0x20, 0x64, 0x6f, 0x20, \
|
||||
0x74, 0x68, 0x69, 0x73, 0x20, 0x70, 0x6f, 0x72, 0x74, 0x29, 0x2e, 0x20, \
|
||||
0x20, 0x54, 0x68, 0x65, 0x72, 0x65, 0x20, 0x61, 0x72, 0x65, 0x20, 0x6c, \
|
||||
0x6f, 0x74, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x56, 0x4e, 0x43, 0x20, 0x63, \
|
||||
0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x6f, 0x75, 0x74, 0x20, 0x74, \
|
||||
0x68, 0x65, 0x72, 0x65, 0x2c, 0x20, 0x62, 0x75, 0x74, 0x20, 0x49, 0x20, \
|
||||
0x63, 0x61, 0x6e, 0x20, 0x72, 0x65, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, \
|
||||
0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x52, 0x65, 0x61, 0x6c, 0x56, 0x4e, \
|
||||
0x43, 0x20, 0x6f, 0x6e, 0x65, 0x73, 0x20, 0x61, 0x73, 0x20, 0x77, 0x6f, \
|
||||
0x72, 0x6b, 0x69, 0x6e, 0x67, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x77, \
|
||||
0x65, 0x6c, 0x6c, 0x20, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x20, 0x57, 0x69, \
|
||||
0x6e, 0x64, 0x6f, 0x77, 0x73, 0x2e, 0x20, 0x20, 0x59, 0x6f, 0x75, 0x20, \
|
||||
0x63, 0x61, 0x6e, 0x20, 0x67, 0x65, 0x74, 0x20, 0x74, 0x68, 0x65, 0x69, \
|
||||
0x72, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x2c, 0x20, 0x73, \
|
||||
0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x73, \
|
||||
0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x61, \
|
||||
0x74, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, \
|
||||
0x2e, 0x72, 0x65, 0x61, 0x6c, 0x76, 0x6e, 0x63, 0x2e, 0x63, 0x6f, 0x6d, \
|
||||
0x2f, 0x22, 0x2c, 0x22, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x4c, \
|
||||
0x65, 0x6e, 0x67, 0x74, 0x68, 0x22, 0x3a, 0x32, 0x32, 0x34, 0x35, 0x37, \
|
||||
0x32, 0x7d, 0x5d, 0x2c, 0x22, 0x70, 0x6b, 0x67, 0x43, 0x61, 0x74, 0x65, \
|
||||
0x67, 0x6f, 0x72, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x73, 0x22, 0x3a, 0x5b, \
|
||||
0x22, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x61, 0x6e, 0x64, \
|
||||
0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x22, 0x5d, 0x2c, 0x22, 0x70, \
|
||||
0x6b, 0x67, 0x53, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x73, 0x68, 0x6f, 0x74, \
|
||||
0x73, 0x22, 0x3a, 0x5b, 0x5d, 0x2c, 0x22, 0x70, 0x6b, 0x67, 0x49, 0x63, \
|
||||
0x6f, 0x6e, 0x73, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, 0x22, 0x64, \
|
||||
0x65, 0x72, 0x69, 0x76, 0x65, 0x64, 0x52, 0x61, 0x74, 0x69, 0x6e, 0x67, \
|
||||
0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x2c, 0x22, 0x70, 0x72, 0x6f, 0x6d, \
|
||||
0x69, 0x6e, 0x65, 0x6e, 0x63, 0x65, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x69, \
|
||||
0x6e, 0x67, 0x22, 0x3a, 0x31, 0x30, 0x30, 0x30, 0x2c, 0x22, 0x70, 0x6b, \
|
||||
0x67, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x6c, 0x6f, 0x67, 0x43, 0x6f, \
|
||||
0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c, 0x7d, \
|
||||
0x5d, 0x7d, 0x7d, 0x0a, 0x00 \
|
||||
}
|
||||
|
||||
|
||||
#endif // JSON_SAMPLES_H
|
207
src/tests/kits/shared/JsonTextWriterTest.cpp
Normal file
207
src/tests/kits/shared/JsonTextWriterTest.cpp
Normal file
@ -0,0 +1,207 @@
|
||||
/*
|
||||
* Copyright 2017, Andrew Lindesay <apl@lindesay.co.nz>
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#include "JsonTextWriterTest.h"
|
||||
|
||||
#include <AutoDeleter.h>
|
||||
|
||||
#include <Json.h>
|
||||
#include <JsonTextWriter.h>
|
||||
|
||||
#include <cppunit/TestCaller.h>
|
||||
#include <cppunit/TestSuite.h>
|
||||
|
||||
#include "JsonSamples.h"
|
||||
|
||||
|
||||
#define LOOPS_TEST_OBJECT_A_FOR_PERFORMANCE 100000
|
||||
|
||||
|
||||
using namespace BPrivate;
|
||||
|
||||
|
||||
JsonTextWriterTest::JsonTextWriterTest()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
JsonTextWriterTest::~JsonTextWriterTest()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JsonTextWriterTest::TestArrayA()
|
||||
{
|
||||
BMallocIO* outputData = new BMallocIO();
|
||||
ObjectDeleter<BMallocIO> outputDataDeleter(outputData);
|
||||
BJsonTextWriter writer(outputData);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK, writer.WriteArrayStart());
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK, writer.WriteString("1234"));
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK, writer.WriteInteger(4567));
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK, writer.WriteArrayStart());
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK, writer.WriteString("A"));
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK, writer.WriteString("b"));
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK, writer.WriteString("C\xc3\xa9zanne"));
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK, writer.WriteArrayEnd());
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK, writer.WriteArrayEnd());
|
||||
writer.Complete();
|
||||
|
||||
BString outputString((char*)outputData->Buffer(),
|
||||
outputData->BufferLength());
|
||||
fprintf(stderr, "expected out >%s<\n", JSON_SAMPLE_ARRAY_A_EXPECTED_OUT);
|
||||
fprintf(stderr, "actual out >%s< (%" B_PRIuSIZE ")\n", outputString.String(),
|
||||
outputData->BufferLength());
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(BString(JSON_SAMPLE_ARRAY_A_EXPECTED_OUT),
|
||||
outputString);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JsonTextWriterTest::TestObjectA()
|
||||
{
|
||||
BMallocIO* outputData = new BMallocIO();
|
||||
ObjectDeleter<BMallocIO> outputDataDeleter(outputData);
|
||||
BJsonTextWriter writer(outputData);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK, writer.WriteObjectStart());
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK, writer.WriteObjectName("weather"));
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK, writer.WriteString("raining"));
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK, writer.WriteObjectName("humidity"));
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK, writer.WriteString("too-high"));
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK, writer.WriteObjectName("daysOfWeek"));
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK, writer.WriteArrayStart());
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK, writer.WriteString("MON"));
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK, writer.WriteString("TUE"));
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK, writer.WriteString("WED"));
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK, writer.WriteString("THR"));
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK, writer.WriteString("FRI"));
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK, writer.WriteArrayEnd());
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK, writer.WriteObjectEnd());
|
||||
writer.Complete();
|
||||
|
||||
BString outputString((char*)outputData->Buffer(),
|
||||
outputData->BufferLength());
|
||||
fprintf(stderr, "expected out >%s<\n", JSON_SAMPLE_OBJECT_A_EXPECTED_OUT);
|
||||
fprintf(stderr, "actual out >%s< (%" B_PRIuSIZE ")\n", outputString.String(),
|
||||
outputData->BufferLength());
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(BString(JSON_SAMPLE_OBJECT_A_EXPECTED_OUT),
|
||||
outputString);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JsonTextWriterTest::TestObjectAForPerformance()
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < LOOPS_TEST_OBJECT_A_FOR_PERFORMANCE; i++) {
|
||||
TestObjectA();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JsonTextWriterTest::TestInteger()
|
||||
{
|
||||
BMallocIO* outputData = new BMallocIO();
|
||||
ObjectDeleter<BMallocIO> outputDataDeleter(outputData);
|
||||
BJsonTextWriter writer(outputData);
|
||||
static char* expectedOut = JSON_SAMPLE_NUMBER_B_EXPECTED_OUT;
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK,
|
||||
writer.WriteInteger(JSON_SAMPLE_NUMBER_B_LITERAL));
|
||||
writer.Complete();
|
||||
|
||||
BString outputString((char *)outputData->Buffer(),
|
||||
outputData->BufferLength());
|
||||
fprintf(stderr, "expected out >%s<\n", expectedOut);
|
||||
fprintf(stderr, "actual out >%s< (%" B_PRIuSIZE ")\n", outputString.String(),
|
||||
outputData->BufferLength());
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(BString(expectedOut),
|
||||
outputString);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JsonTextWriterTest::TestDouble()
|
||||
{
|
||||
BMallocIO* outputData = new BMallocIO();
|
||||
ObjectDeleter<BMallocIO> outputDataDeleter(outputData);
|
||||
BJsonTextWriter writer(outputData);
|
||||
static char* expectedOut = "3.142857";
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK,
|
||||
writer.WriteDouble(JSON_SAMPLE_NUMBER_A_LITERAL));
|
||||
writer.Complete();
|
||||
|
||||
BString outputString((char *)outputData->Buffer(),
|
||||
outputData->BufferLength());
|
||||
fprintf(stderr, "expected out >%s<\n", expectedOut);
|
||||
fprintf(stderr, "actual out >%s< (%" B_PRIuSIZE ")\n", outputString.String(),
|
||||
outputData->BufferLength());
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(BString(expectedOut),
|
||||
outputString);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JsonTextWriterTest::TestFalse()
|
||||
{
|
||||
BMallocIO* outputData = new BMallocIO();
|
||||
ObjectDeleter<BMallocIO> outputDataDeleter(outputData);
|
||||
BJsonTextWriter writer(outputData);
|
||||
static char* expectedOut = "false";
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK, writer.WriteFalse());
|
||||
writer.Complete();
|
||||
|
||||
BString outputString((char*)outputData->Buffer(),
|
||||
outputData->BufferLength());
|
||||
fprintf(stderr, "expected out >%s<\n", expectedOut);
|
||||
fprintf(stderr, "actual out >%s< (%" B_PRIuSIZE ")\n",
|
||||
outputString.String(), outputData->BufferLength());
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(BString(expectedOut),
|
||||
outputString);
|
||||
}
|
||||
|
||||
|
||||
/*static*/ void
|
||||
JsonTextWriterTest::AddTests(BTestSuite& parent)
|
||||
{
|
||||
CppUnit::TestSuite& suite = *new CppUnit::TestSuite(
|
||||
"JsonTextWriterTest");
|
||||
|
||||
suite.addTest(new CppUnit::TestCaller<JsonTextWriterTest>(
|
||||
"JsonTextWriterTest::TestDouble",
|
||||
&JsonTextWriterTest::TestDouble));
|
||||
|
||||
suite.addTest(new CppUnit::TestCaller<JsonTextWriterTest>(
|
||||
"JsonTextWriterTest::TestInteger",
|
||||
&JsonTextWriterTest::TestInteger));
|
||||
|
||||
suite.addTest(new CppUnit::TestCaller<JsonTextWriterTest>(
|
||||
"JsonTextWriterTest::TestFalse",
|
||||
&JsonTextWriterTest::TestFalse));
|
||||
|
||||
suite.addTest(new CppUnit::TestCaller<JsonTextWriterTest>(
|
||||
"JsonTextWriterTest::TestArrayA",
|
||||
&JsonTextWriterTest::TestArrayA));
|
||||
|
||||
suite.addTest(new CppUnit::TestCaller<JsonTextWriterTest>(
|
||||
"JsonTextWriterTest::TestObjectA",
|
||||
&JsonTextWriterTest::TestObjectA));
|
||||
|
||||
// suite.addTest(new CppUnit::TestCaller<JsonTextWriterTest>(
|
||||
// "JsonTextWriterTest::TestObjectAForPerformance",
|
||||
// &JsonTextWriterTest::TestObjectAForPerformance));
|
||||
|
||||
parent.addTest("JsonTextWriterTest", &suite);
|
||||
}
|
35
src/tests/kits/shared/JsonTextWriterTest.h
Normal file
35
src/tests/kits/shared/JsonTextWriterTest.h
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2017, Andrew Lindesay <apl@lindesay.co.nz>
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef JSON_WRITER_TEST_H
|
||||
#define JSON_WRITER_TEST_H
|
||||
|
||||
|
||||
#include <TestCase.h>
|
||||
#include <TestSuite.h>
|
||||
|
||||
#include <DataIO.h>
|
||||
|
||||
class Sample;
|
||||
|
||||
|
||||
class JsonTextWriterTest : public CppUnit::TestCase {
|
||||
public:
|
||||
JsonTextWriterTest();
|
||||
virtual ~JsonTextWriterTest();
|
||||
|
||||
void TestArrayA();
|
||||
void TestObjectA();
|
||||
void TestObjectAForPerformance();
|
||||
void TestDouble();
|
||||
void TestInteger();
|
||||
void TestFalse();
|
||||
|
||||
static void AddTests(BTestSuite& suite);
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // JSON_WRITER_TEST_H
|
292
src/tests/kits/shared/JsonToMessageTest.cpp
Normal file
292
src/tests/kits/shared/JsonToMessageTest.cpp
Normal file
@ -0,0 +1,292 @@
|
||||
/*
|
||||
* Copyright 2017, Andrew Lindesay <apl@lindesay.co.nz>
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#include "JsonToMessageTest.h"
|
||||
|
||||
#include <Json.h>
|
||||
|
||||
#include <cppunit/TestCaller.h>
|
||||
#include <cppunit/TestSuite.h>
|
||||
|
||||
#include "JsonSamples.h"
|
||||
|
||||
|
||||
#define LOOPS_TEST_OBJECT_A_FOR_PERFORMANCE 100000
|
||||
|
||||
using namespace BPrivate;
|
||||
|
||||
|
||||
JsonToMessageTest::JsonToMessageTest()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
JsonToMessageTest::~JsonToMessageTest()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JsonToMessageTest::TestArrayA()
|
||||
{
|
||||
BMessage message;
|
||||
BMessage subMessage;
|
||||
BString stringValue;
|
||||
double doubleValue;
|
||||
|
||||
// ----------------------
|
||||
BJson::Parse(JSON_SAMPLE_ARRAY_A_IN, message);
|
||||
// ----------------------
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("!find [0]", B_OK,
|
||||
message.FindString("0", &stringValue));
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("!eq [0]", BString("1234"), stringValue);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("!find [1]", B_OK,
|
||||
message.FindDouble("1", &doubleValue));
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("!eq [1]", 4567, doubleValue);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("!find [2]", B_OK,
|
||||
message.FindMessage("2", &subMessage));
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("!find [2.0]", B_OK,
|
||||
subMessage.FindString("0", &stringValue));
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("!eq [2.0]", BString("A"), stringValue);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("!find [2.1]", B_OK,
|
||||
subMessage.FindString("1", &stringValue));
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("!eq [2.1]", BString("b"), stringValue);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("!find [2.2]", B_OK,
|
||||
subMessage.FindString("2", &stringValue));
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("!eq [2.2]", BString("C\xc3\xa9zanne"),
|
||||
stringValue);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JsonToMessageTest::TestArrayB()
|
||||
{
|
||||
BMessage message;
|
||||
BMessage subMessage;
|
||||
BMessage subSubMessage;
|
||||
BString stringValue;
|
||||
|
||||
// ----------------------
|
||||
BJson::Parse(JSON_SAMPLE_ARRAY_B_IN, message);
|
||||
// ----------------------
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("!find [0]", B_OK,
|
||||
message.FindString("0", &stringValue));
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("!eq [0]", BString("Whirinaki"), stringValue);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("!find [1]", B_OK,
|
||||
message.FindString("1", &stringValue));
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("!eq [1]", BString("Wellington"), stringValue);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("!find [2]", B_OK,
|
||||
message.FindMessage("2", &subMessage));
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("!find [2.0]", B_OK,
|
||||
subMessage.FindMessage("key", &subSubMessage));
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("!find [2.0.0]", B_OK,
|
||||
subSubMessage.FindString("0", &stringValue));
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("!eq [2.0.0]", BString("value"), stringValue);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JsonToMessageTest::TestObjectA()
|
||||
{
|
||||
BMessage message;
|
||||
BMessage subMessage;
|
||||
BString stringValue;
|
||||
|
||||
// ----------------------
|
||||
BJson::Parse(JSON_SAMPLE_OBJECT_A_IN, message);
|
||||
// ----------------------
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK, message.FindString("weather", &stringValue));
|
||||
CPPUNIT_ASSERT_EQUAL(BString("raining"), stringValue);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK, message.FindString("humidity", &stringValue));
|
||||
CPPUNIT_ASSERT_EQUAL(BString("too-high"), stringValue);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK, message.FindMessage("daysOfWeek", &subMessage));
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK, subMessage.FindString("0", &stringValue));
|
||||
CPPUNIT_ASSERT_EQUAL(BString("MON"), stringValue);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK, subMessage.FindString("1", &stringValue));
|
||||
CPPUNIT_ASSERT_EQUAL(BString("TUE"), stringValue);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK, subMessage.FindString("2", &stringValue));
|
||||
CPPUNIT_ASSERT_EQUAL(BString("WED"), stringValue);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK, subMessage.FindString("3", &stringValue));
|
||||
CPPUNIT_ASSERT_EQUAL(BString("THR"), stringValue);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK, subMessage.FindString("4", &stringValue));
|
||||
CPPUNIT_ASSERT_EQUAL(BString("FRI"), stringValue);
|
||||
}
|
||||
|
||||
|
||||
/*! This is not a real test, but is a convenient point at which to implement a
|
||||
performance test.
|
||||
*/
|
||||
|
||||
void
|
||||
JsonToMessageTest::TestObjectAForPerformance()
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i < LOOPS_TEST_OBJECT_A_FOR_PERFORMANCE; i++)
|
||||
TestObjectA();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JsonToMessageTest::TestObjectB()
|
||||
{
|
||||
BMessage message;
|
||||
bool boolValue;
|
||||
void *ptrValue; // this is how NULL is represented.
|
||||
|
||||
// ----------------------
|
||||
BJson::Parse(JSON_SAMPLE_OBJECT_B_IN, message);
|
||||
// ----------------------
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK, message.FindBool("testTrue", &boolValue));
|
||||
CPPUNIT_ASSERT_EQUAL(true, boolValue);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK, message.FindBool("testFalse", &boolValue));
|
||||
CPPUNIT_ASSERT_EQUAL(false, boolValue);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK, message.FindPointer("testNull", &ptrValue));
|
||||
CPPUNIT_ASSERT_EQUAL(0, (uint32) ptrValue);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JsonToMessageTest::TestObjectC()
|
||||
{
|
||||
BMessage message;
|
||||
BMessage subMessage;
|
||||
BString stringValue;
|
||||
|
||||
// ----------------------
|
||||
BJson::Parse(JSON_SAMPLE_OBJECT_C_IN, message);
|
||||
// ----------------------
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK, message.FindString("key", &stringValue));
|
||||
CPPUNIT_ASSERT_EQUAL(BString("value"), stringValue);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JsonToMessageTest::TestUnterminatedObject()
|
||||
{
|
||||
BMessage message;
|
||||
|
||||
// ----------------------
|
||||
status_t result = BJson::Parse(JSON_SAMPLE_BROKEN_UNTERMINATED_OBJECT,
|
||||
message);
|
||||
// ----------------------
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(B_BAD_DATA, result);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JsonToMessageTest::TestUnterminatedArray()
|
||||
{
|
||||
BMessage message;
|
||||
|
||||
// ----------------------
|
||||
status_t result = BJson::Parse(JSON_SAMPLE_BROKEN_UNTERMINATED_ARRAY,
|
||||
message);
|
||||
// ----------------------
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(B_BAD_DATA, result);
|
||||
}
|
||||
|
||||
|
||||
void JsonToMessageTest::TestHaikuDepotFetchBatch()
|
||||
{
|
||||
const unsigned char input[] = JSON_SAMPLE_HDS_FETCH_BATCH_PKGS;
|
||||
BMessage message;
|
||||
BMessage resultMessage;
|
||||
BMessage pkgsMessage;
|
||||
BMessage pkgMessage1;
|
||||
double modifyTimestampDouble;
|
||||
double expectedModifyTimestampDouble = 1488785331631.0;
|
||||
|
||||
// ----------------------
|
||||
status_t result = BJson::Parse((char*)input,
|
||||
message);
|
||||
// ----------------------
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK, result);
|
||||
|
||||
// this is quite a large test input so a random sample "thing to
|
||||
// check" is chosen to indicate that the parse was successful.
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("result", B_OK,
|
||||
message.FindMessage("result", &resultMessage));
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("pkgs", B_OK,
|
||||
resultMessage.FindMessage("pkgs", &pkgsMessage));
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("1", B_OK,
|
||||
pkgsMessage.FindMessage("1", &pkgMessage1));
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("modifyTimestamp", B_OK,
|
||||
pkgMessage1.FindDouble("modifyTimestamp", &modifyTimestampDouble));
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(expectedModifyTimestampDouble, modifyTimestampDouble);
|
||||
}
|
||||
|
||||
|
||||
/*static*/ void
|
||||
JsonToMessageTest::AddTests(BTestSuite& parent)
|
||||
{
|
||||
CppUnit::TestSuite& suite = *new CppUnit::TestSuite(
|
||||
"JsonToMessageTest");
|
||||
|
||||
suite.addTest(new CppUnit::TestCaller<JsonToMessageTest>(
|
||||
"JsonToMessageTest::TestArrayA",
|
||||
&JsonToMessageTest::TestArrayA));
|
||||
|
||||
suite.addTest(new CppUnit::TestCaller<JsonToMessageTest>(
|
||||
"JsonToMessageTest::TestArrayB",
|
||||
&JsonToMessageTest::TestArrayB));
|
||||
|
||||
suite.addTest(new CppUnit::TestCaller<JsonToMessageTest>(
|
||||
"JsonToMessageTest::TestObjectA",
|
||||
&JsonToMessageTest::TestObjectA));
|
||||
|
||||
suite.addTest(new CppUnit::TestCaller<JsonToMessageTest>(
|
||||
"JsonToMessageTest::TestObjectB",
|
||||
&JsonToMessageTest::TestObjectB));
|
||||
|
||||
suite.addTest(new CppUnit::TestCaller<JsonToMessageTest>(
|
||||
"JsonToMessageTest::TestObjectC",
|
||||
&JsonToMessageTest::TestObjectC));
|
||||
|
||||
suite.addTest(new CppUnit::TestCaller<JsonToMessageTest>(
|
||||
"JsonToMessageTest::TestUnterminatedObject",
|
||||
&JsonToMessageTest::TestUnterminatedObject));
|
||||
|
||||
suite.addTest(new CppUnit::TestCaller<JsonToMessageTest>(
|
||||
"JsonToMessageTest::TestUnterminatedArray",
|
||||
&JsonToMessageTest::TestUnterminatedArray));
|
||||
|
||||
suite.addTest(new CppUnit::TestCaller<JsonToMessageTest>(
|
||||
"JsonToMessageTest::TestHaikuDepotFetchBatch",
|
||||
&JsonToMessageTest::TestHaikuDepotFetchBatch));
|
||||
|
||||
// suite.addTest(new CppUnit::TestCaller<JsonToMessageTest>(
|
||||
// "JsonToMessageTest::TestObjectAForPerformance",
|
||||
// &JsonToMessageTest::TestObjectAForPerformance));
|
||||
|
||||
parent.addTest("JsonToMessageTest", &suite);
|
||||
}
|
38
src/tests/kits/shared/JsonToMessageTest.h
Normal file
38
src/tests/kits/shared/JsonToMessageTest.h
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2017, Andrew Lindesay <apl@lindesay.co.nz>
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef JSON_TO_MESSAGE_TEST_H
|
||||
#define JSON_TO_MESSAGE_TEST_H
|
||||
|
||||
|
||||
#include <TestCase.h>
|
||||
#include <TestSuite.h>
|
||||
|
||||
#include <DataIO.h>
|
||||
|
||||
class Sample;
|
||||
|
||||
|
||||
class JsonToMessageTest : public CppUnit::TestCase {
|
||||
public:
|
||||
JsonToMessageTest();
|
||||
virtual ~JsonToMessageTest();
|
||||
|
||||
void TestArrayA();
|
||||
void TestArrayB();
|
||||
void TestObjectAForPerformance();
|
||||
void TestObjectA();
|
||||
void TestObjectB();
|
||||
void TestObjectC();
|
||||
void TestUnterminatedObject();
|
||||
void TestUnterminatedArray();
|
||||
void TestHaikuDepotFetchBatch();
|
||||
|
||||
static void AddTests(BTestSuite& suite);
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // JSON_TO_MESSAGE_TEST_H
|
@ -1,4 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017, Andrew Lindesay, apl@lindesay.co.nz
|
||||
* Copyright 2012-2015, Axel Dörfler, axeld@pinc-software.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
@ -11,6 +12,10 @@
|
||||
#include "DriverSettingsMessageAdapterTest.h"
|
||||
#include "GeolocationTest.h"
|
||||
#include "NaturalCompareTest.h"
|
||||
#include "JsonEndToEndTest.h"
|
||||
#include "JsonErrorHandlingTest.h"
|
||||
#include "JsonTextWriterTest.h"
|
||||
#include "JsonToMessageTest.h"
|
||||
|
||||
|
||||
BTestSuite*
|
||||
@ -22,6 +27,10 @@ getTestSuite()
|
||||
DriverSettingsMessageAdapterTest::AddTests(*suite);
|
||||
GeolocationTest::AddTests(*suite);
|
||||
NaturalCompareTest::AddTests(*suite);
|
||||
JsonEndToEndTest::AddTests(*suite);
|
||||
JsonErrorHandlingTest::AddTests(*suite);
|
||||
JsonTextWriterTest::AddTests(*suite);
|
||||
JsonToMessageTest::AddTests(*suite);
|
||||
|
||||
return suite;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user