- DataTreeCore: - Re-arrange method declaration order - Renamed methods Delete() to DeleteCh() - Added GetChName(), GetChType(), GetChLen() & ClearCh(Path) methods - ApplicationCore: - Add WriteToScreen() method (Hide access to JSONparser)
1027 lines
26 KiB
C++
1027 lines
26 KiB
C++
/*
|
|
* JSONparseCore.cpp
|
|
*
|
|
* Created on: 5 Mar 2017
|
|
* Author: wentzelc
|
|
*/
|
|
|
|
// Standard C/C++ Libraries
|
|
#include <stdio.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
|
|
// redA Libraries
|
|
#include "JSONparseCore.h"
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
CJSONparse::CJSONparse( CDataMember * pDataTree )
|
|
{
|
|
// Object tree
|
|
DataTree = pDataTree;
|
|
|
|
// File Operation
|
|
InputHandle = -1;
|
|
OutputHandle = -1;
|
|
|
|
Buffer = NULL;
|
|
|
|
// Parsing operation
|
|
BufPos = NULL;
|
|
Mark = NULL;
|
|
LineNo = 0;
|
|
CharNo = 0;
|
|
RefillBuffer = false;
|
|
|
|
// Printing operation
|
|
Spacer[0] = 0;
|
|
SpacerLen = 0;
|
|
|
|
// Error reporting
|
|
Error = false;
|
|
ErrorText[0] = 0;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
CJSONparse::~CJSONparse()
|
|
{
|
|
// Destroy buffer
|
|
if (Buffer) {
|
|
delete Buffer;
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CJSONparse::WriteToScreen( const char * BasePath, const int Indent )
|
|
{
|
|
// Print to screen
|
|
WriteToHandle( BasePath, 1, Indent );
|
|
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CJSONparse::WriteToFile( const char * BasePath, const char * Path, const char * FileName, const int Indent )
|
|
{
|
|
char FilePath[250] = "";
|
|
int PathLen = 0;
|
|
|
|
// Validate
|
|
if (!FileName) {
|
|
Error = true;
|
|
sprintf( ErrorText, "No File name specified" );
|
|
return false;
|
|
}
|
|
|
|
// Build file name
|
|
if (Path && *Path) {
|
|
strcpy( FilePath, Path );
|
|
PathLen = strlen( FilePath );
|
|
if (FilePath[PathLen] != '/') {
|
|
FilePath[PathLen++] = '/';
|
|
}
|
|
}
|
|
strcpy( &FilePath[PathLen], FileName );
|
|
|
|
// Read file
|
|
return WriteToFile( BasePath, FilePath, Indent );
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CJSONparse::WriteToFile( const char * BasePath, const char * FilePath, const int Indent )
|
|
{
|
|
int Handle = -1;
|
|
|
|
// Clear Error
|
|
Error = false;
|
|
|
|
// Validate
|
|
if (!FilePath || !FilePath[0]) {
|
|
Error = true;
|
|
sprintf( ErrorText, "No File path specified" );
|
|
return false;
|
|
}
|
|
|
|
// Open file
|
|
if ((Handle = open( FilePath, O_CREAT|O_WRONLY|O_TRUNC, 660 )) < 0) {
|
|
Error = true;
|
|
sprintf( ErrorText, "Could not open file" );
|
|
return false;
|
|
}
|
|
|
|
// Save to file
|
|
WriteToHandle( BasePath, Handle, Indent );
|
|
|
|
// Close file
|
|
close( Handle );
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CJSONparse::WriteToHandle( const char * BasePath, const int Handle, const int Indent )
|
|
{
|
|
CDataMember * Member;
|
|
|
|
// Validate
|
|
if (!DataTree) {
|
|
return false;
|
|
}
|
|
|
|
// Open file
|
|
if (Handle < 0) {
|
|
Error = true;
|
|
sprintf( ErrorText, "Could not write to invalid handle" );
|
|
return false;
|
|
}
|
|
OutputHandle = Handle;
|
|
|
|
// Get Root object
|
|
if (!(Member = DataTree->GetChild( BasePath ))) {
|
|
Error = true;
|
|
sprintf( ErrorText, "Invalid root object path" );
|
|
OutputHandle = -1;
|
|
return false;
|
|
}
|
|
|
|
// Print to file
|
|
if (!PrintObject( Member, Indent ) ||
|
|
(write( OutputHandle, "\n", 1 ) < 0)) {
|
|
OutputHandle = -1;
|
|
return false;
|
|
}
|
|
|
|
OutputHandle = -1;
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CJSONparse::ReadFromFile( const char * BasePath, const char * Path, const char * FileName )
|
|
{
|
|
char FilePath[250] = "";
|
|
int PathLen = 0;
|
|
|
|
// Validate
|
|
if (!FileName) {
|
|
Error = true;
|
|
sprintf( ErrorText, "No File name specified" );
|
|
return false;
|
|
}
|
|
|
|
// Build file name
|
|
if (Path && *Path) {
|
|
strcpy( FilePath, Path );
|
|
PathLen = strlen( FilePath );
|
|
if (FilePath[PathLen] != '/') {
|
|
FilePath[PathLen++] = '/';
|
|
}
|
|
}
|
|
strcpy( &FilePath[PathLen], FileName );
|
|
|
|
// Read file
|
|
return ReadFromFile( BasePath, FilePath );
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CJSONparse::ReadFromFile( const char * BasePath, const char * FilePath )
|
|
{
|
|
int Handle = -1;
|
|
bool result = false;
|
|
|
|
// Validate
|
|
if (!DataTree) {
|
|
return false;
|
|
}
|
|
|
|
// Clear Error
|
|
Error = false;
|
|
|
|
// Validate
|
|
if (!FilePath || !FilePath[0]) {
|
|
Error = true;
|
|
sprintf( ErrorText, "No File path specified" );
|
|
return false;
|
|
}
|
|
|
|
// Open file
|
|
if ((Handle = open( FilePath, O_RDONLY )) < 0) {
|
|
Error = true;
|
|
sprintf( ErrorText, "Could not open file" );
|
|
return false;
|
|
}
|
|
|
|
// Continuously refill buffer while loading
|
|
result = ReadFromHandle( BasePath, Handle, true );
|
|
|
|
// Close File
|
|
close( Handle );
|
|
return result;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CJSONparse::ReadFromHandle( const char * BasePath, int Handle, bool pRefillBuffer )
|
|
{
|
|
bool result = false;
|
|
|
|
// Clear Error
|
|
Error = false;
|
|
|
|
// Validate
|
|
if (Handle < 0) {
|
|
Error = true;
|
|
sprintf( ErrorText, "Cannot read from invalid handle" );
|
|
return false;
|
|
}
|
|
InputHandle = Handle;
|
|
|
|
// Load Buffer
|
|
CreateBuffer( 50 );
|
|
if (!FillBuffer()) {
|
|
Error = true;
|
|
sprintf( ErrorText, "Could not read from file" );
|
|
FreeBuffer();
|
|
return false;
|
|
}
|
|
|
|
// Continuously refill buffer while loading
|
|
RefillBuffer = pRefillBuffer;
|
|
result = ReadFromBuffer( BasePath );
|
|
RefillBuffer = false;
|
|
|
|
// Destroy buffer
|
|
FreeBuffer();
|
|
|
|
InputHandle = -1;
|
|
return result;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CJSONparse::ReadFromString( const char * BasePath, const char * InString, const int Len )
|
|
{
|
|
bool result = false;
|
|
|
|
// Clear Error
|
|
Error = false;
|
|
|
|
// Load Buffer
|
|
CreateBuffer( Len );
|
|
Buffer->Push( true, InString, Len );
|
|
|
|
// Continuously refill buffer while loading
|
|
result = ReadFromBuffer( BasePath );
|
|
RefillBuffer = false;
|
|
|
|
// Destroy buffer
|
|
FreeBuffer();
|
|
|
|
InputHandle = -1;
|
|
return result;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CJSONparse::ReadFromBuffer( const char * BasePath )
|
|
{
|
|
CDataMember * BaseMember = NULL;
|
|
|
|
// Validate
|
|
if (!DataTree || !Buffer) {
|
|
return false;
|
|
}
|
|
|
|
// Clear Error
|
|
Error = false;
|
|
|
|
// Get/Create Root object
|
|
if (!(BaseMember = DataTree->GetChild( BasePath, true ))) {
|
|
Error = true;
|
|
sprintf( ErrorText, "Invalid root object path" );
|
|
return false;
|
|
}
|
|
|
|
// Delete existing object contents
|
|
BaseMember->Clear();
|
|
|
|
// Position Counters
|
|
LineNo = 1;
|
|
CharNo = 0;
|
|
|
|
// Parse Root Object
|
|
SkipWhiteSpace();
|
|
if (!ParseObject( BaseMember )) {
|
|
if (!Error) {
|
|
Error = true;
|
|
CharNo += BufPos-Mark;
|
|
sprintf( ErrorText, "First entry in file must be an Object on line %d:%d", LineNo, CharNo );
|
|
}
|
|
FreeBuffer();
|
|
return false;
|
|
}
|
|
|
|
// Ensure remainder of file is empty
|
|
SkipWhiteSpace();
|
|
if (*BufPos != 0) {
|
|
Error = true;
|
|
CharNo += BufPos-Mark;
|
|
sprintf( ErrorText, "No content expected after Root object on line %d:%d", LineNo, CharNo );
|
|
FreeBuffer();
|
|
return false;
|
|
}
|
|
|
|
// Success
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CJSONparse::CreateBuffer( int pBufLen )
|
|
{
|
|
// Validate
|
|
if (!pBufLen)
|
|
return false;
|
|
|
|
// Create buffer
|
|
Buffer = new CShiftBuffer( pBufLen );
|
|
|
|
// Reset markers
|
|
Buffer->PeekDirect( &BufPos, 0 );
|
|
Mark = BufPos;
|
|
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CJSONparse::FillBuffer()
|
|
{
|
|
char * BufStart;
|
|
int PosShift = BufPos - Mark;
|
|
|
|
// Remove all bytes up to Mark
|
|
Buffer->PeekDirect( &BufStart, 0 );
|
|
Buffer->Clear( Mark-BufStart );
|
|
|
|
// Read from file
|
|
Buffer->ReadFromFD( InputHandle );
|
|
|
|
// Reset Mark to start of buffer
|
|
Mark = BufStart;
|
|
BufPos = Mark + PosShift;
|
|
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
void CJSONparse::FreeBuffer()
|
|
{
|
|
// Destroy buffer
|
|
if (Buffer) {
|
|
delete Buffer;
|
|
Buffer = NULL;
|
|
|
|
// Update Markers
|
|
BufPos = NULL;
|
|
Mark = NULL;
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
void CJSONparse::SkipWhiteSpace()
|
|
{
|
|
while (true)
|
|
{
|
|
// Append buffer if required
|
|
if (!*BufPos && RefillBuffer)
|
|
FillBuffer();
|
|
|
|
// Skip whitespace
|
|
if (!isspace(*BufPos)) {
|
|
CharNo += BufPos-Mark;
|
|
Mark = BufPos;
|
|
break;
|
|
}
|
|
|
|
if (*BufPos == '\n') {
|
|
Mark = BufPos;
|
|
LineNo++;
|
|
CharNo = 0;
|
|
}
|
|
BufPos++;
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CJSONparse::ParseString( char ** Value, int &Len )
|
|
{
|
|
char * EndMark;
|
|
char * ValuePos = NULL;
|
|
char HexVal[5] = "";
|
|
|
|
// Check for opening quote
|
|
if (*BufPos != '"') {
|
|
return false;
|
|
}
|
|
|
|
// Clear values
|
|
*Value = NULL;
|
|
Len = 0;
|
|
|
|
// Mark start of quote
|
|
BufPos++;
|
|
|
|
// Check for closing quote
|
|
while (true)
|
|
{
|
|
// Check for special characters
|
|
if ((EndMark = strpbrk( BufPos, "\"/\\\n\t\b\f\n\r" ))) {
|
|
BufPos = EndMark;
|
|
} else if (RefillBuffer) {
|
|
FillBuffer();
|
|
continue;
|
|
}
|
|
|
|
if (*BufPos == '"') {
|
|
// End of string found
|
|
BufPos++;
|
|
break;
|
|
}
|
|
else if (!*BufPos) {
|
|
Error = true;
|
|
sprintf( ErrorText, "Expect closing '\"' for string on line %d:%d", LineNo, CharNo+1 );
|
|
return false;
|
|
}
|
|
else if (*BufPos == '\\') {
|
|
if (!*(BufPos+1) && RefillBuffer) {
|
|
if (FillBuffer()) {
|
|
continue;
|
|
}
|
|
}
|
|
if (*(BufPos+1) == 'u') {
|
|
for (EndMark = BufPos+2; EndMark < BufPos+6; EndMark++) {
|
|
if (!*EndMark && RefillBuffer) {
|
|
FillBuffer();
|
|
continue;
|
|
}
|
|
if (!isxdigit( *EndMark )) {
|
|
Error = true;
|
|
CharNo += BufPos-EndMark;
|
|
sprintf( ErrorText, "Expect 4-digit hex value for escape value on line %d:%d", LineNo, CharNo );
|
|
return false;
|
|
}
|
|
}
|
|
BufPos += 6;
|
|
Len -= 5;
|
|
}
|
|
else if (strchr( "bfnrt/\\\"", *(BufPos+1) )) {
|
|
BufPos += 2;
|
|
Len -= 1;
|
|
}
|
|
else {
|
|
Error = true;
|
|
CharNo += BufPos-Mark;
|
|
sprintf( ErrorText, "Invalid escape sequence on line %d:%d", LineNo, CharNo );
|
|
return false;
|
|
}
|
|
}
|
|
else {
|
|
Error = true;
|
|
CharNo += BufPos-Mark;
|
|
sprintf( ErrorText, "Un-escaped special character in string on line %d:%d", LineNo, CharNo );
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Create Return value pointer
|
|
Len += BufPos-Mark-2;
|
|
*Value = (char*)malloc( Len+1 );
|
|
ValuePos = *Value;
|
|
|
|
// Convert value
|
|
BufPos = Mark+1;
|
|
while ((EndMark = strpbrk( BufPos, "\"\\" )))
|
|
{
|
|
// Copy portion
|
|
memcpy( ValuePos, BufPos, (EndMark-BufPos) );
|
|
ValuePos += (EndMark-BufPos);
|
|
BufPos = EndMark;
|
|
|
|
if (*BufPos == '"') {
|
|
break;
|
|
}
|
|
else if (*BufPos== '\\') {
|
|
if (*(BufPos+1) == 'u') {
|
|
strncpy( HexVal, BufPos+2, 4 );
|
|
*ValuePos = (char)strtol( HexVal, NULL, 16 );
|
|
ValuePos++;
|
|
BufPos += 6;
|
|
}
|
|
else {
|
|
switch (*(BufPos+1)) {
|
|
case 'b': *ValuePos = '\b'; break;
|
|
case 'f': *ValuePos = '\f'; break;
|
|
case 'n': *ValuePos = '\n'; break;
|
|
case 'r': *ValuePos = '\r'; break;
|
|
case 't': *ValuePos = '\t'; break;
|
|
case '/': *ValuePos = '/'; break;
|
|
case '\\': *ValuePos = '\\'; break;
|
|
case '"': *ValuePos = '"'; break;
|
|
}
|
|
ValuePos++;
|
|
BufPos +=2;
|
|
}
|
|
}
|
|
}
|
|
*ValuePos = 0;
|
|
BufPos++;
|
|
|
|
// Success
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CJSONparse::ParseObject( CDataMember * Object )
|
|
{
|
|
CDataMember * Member = NULL;
|
|
char * MemberName = NULL;
|
|
int Len = 0;
|
|
|
|
// Check for start of Object
|
|
if (*BufPos != '{') {
|
|
return false;
|
|
}
|
|
BufPos++;
|
|
|
|
// Set Type
|
|
Object->SetValue( jtObject );
|
|
|
|
while (true)
|
|
{
|
|
// Evaluate key name
|
|
SkipWhiteSpace();
|
|
if (*BufPos == '}') {
|
|
// End of Object
|
|
break;
|
|
}
|
|
else if (!ParseString( &MemberName, Len )) {
|
|
if (!Error) {
|
|
Error = true;
|
|
sprintf( ErrorText, "Expect quoted key name on line %d:%d", LineNo, CharNo );
|
|
}
|
|
return false;
|
|
}
|
|
else if (!Len) {
|
|
Error = true;
|
|
sprintf( ErrorText, "Empty parameter name on line %d:%d", LineNo, CharNo );
|
|
return false;
|
|
}
|
|
|
|
// Check if Member exists
|
|
Member = Object->GetChild( MemberName, true );
|
|
|
|
// Check for delimiter
|
|
SkipWhiteSpace();
|
|
if (*BufPos != ':') {
|
|
Error = true;
|
|
sprintf( ErrorText, "Expected ':' delimiter on line %d:%d", LineNo, CharNo );
|
|
return false;
|
|
}
|
|
BufPos++;
|
|
|
|
// Get Value
|
|
SkipWhiteSpace();
|
|
if (!ParseObject( Member ) && !Error && !ParseArray( Member ) && !Error && !ParseString( Member ) && !Error && !ParsePrimitive( Member ) ) {}
|
|
if (Error) {
|
|
// Destroy member
|
|
Object->DeleteCh( MemberName );
|
|
return false;
|
|
}
|
|
|
|
// Free Name
|
|
free( MemberName );
|
|
|
|
// Check if more parameters to follow
|
|
SkipWhiteSpace();
|
|
if (*BufPos != ',') {
|
|
// No more parameters
|
|
break;
|
|
}
|
|
BufPos++;
|
|
}
|
|
|
|
// Expect end of object
|
|
if (*BufPos != '}') {
|
|
Error = true;
|
|
sprintf( ErrorText, "Closing brace for object '}' expected on line %d:%d", LineNo, CharNo );
|
|
return false;
|
|
}
|
|
BufPos++;
|
|
|
|
// success
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CJSONparse::ParseArray( CDataMember * Array )
|
|
{
|
|
CDataMember ** Member;
|
|
|
|
// Check for start of Object
|
|
if (*BufPos != '[') {
|
|
return false;
|
|
}
|
|
BufPos++;
|
|
|
|
// Set Type
|
|
Array->SetValue( jtArray );
|
|
Member = &(Array->FirstChild);
|
|
while (true)
|
|
{
|
|
// Look for Member Name
|
|
SkipWhiteSpace();
|
|
if (*BufPos == ']') {
|
|
break;
|
|
}
|
|
|
|
// Add new element
|
|
*Member = new CDataMember( Array );
|
|
|
|
// Get Value
|
|
SkipWhiteSpace();
|
|
if (!ParseObject( *Member ) && !Error && !ParseArray( *Member ) && !Error && !ParseString( *Member ) && !Error && !ParsePrimitive( *Member ) ) {}
|
|
if (Error) {
|
|
delete Member;
|
|
return false;
|
|
}
|
|
else {
|
|
Member = &((*Member)->NextPeer);
|
|
}
|
|
|
|
// Check if more parameters to follow
|
|
SkipWhiteSpace();
|
|
if (*BufPos != ',') {
|
|
// No more parameters
|
|
break;
|
|
}
|
|
BufPos++;
|
|
}
|
|
|
|
// Expect end of object
|
|
if (*BufPos != ']') {
|
|
Error = true;
|
|
sprintf( ErrorText, "Closing brace for array ']' expected on line %d:%d", LineNo, CharNo );
|
|
return false;
|
|
}
|
|
BufPos++;
|
|
|
|
// success
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CJSONparse::ParseString( CDataMember * Member )
|
|
{
|
|
char * Value = NULL;
|
|
int Len = 0;
|
|
|
|
// Try to parse
|
|
if (!ParseString( &Value, Len )) {
|
|
return false;
|
|
}
|
|
|
|
// Set string
|
|
Member->SetValuePtr( jtString, Value, Len );
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
bool CJSONparse::ParsePrimitive( CDataMember * Member )
|
|
{
|
|
char * Value = NULL;
|
|
int Len = 0;
|
|
char * EndMark;
|
|
|
|
// Get end of value
|
|
while (true) {
|
|
if (!*BufPos && RefillBuffer)
|
|
FillBuffer();
|
|
if (!*BufPos || isspace(*BufPos) || (*BufPos == ',') || (*BufPos == '}') || (*BufPos == ']'))
|
|
break;
|
|
BufPos++;
|
|
}
|
|
|
|
// Check length of value
|
|
Len = BufPos - Mark;
|
|
if (!Len) {
|
|
Error = true;
|
|
sprintf( ErrorText, "Missing param value on line %d:%d", LineNo, CharNo );
|
|
return false;
|
|
}
|
|
|
|
// Check for primitive values
|
|
if ((Len == 4) && !strncasecmp( Mark, "null", 4 )) {
|
|
Member->SetValue( jtNull );
|
|
}
|
|
else if ((Len == 4) && !strncasecmp( Mark, "true", 4 )) {
|
|
Member->SetValue( jtBool, "1" );
|
|
}
|
|
else if ((Len == 5) && !strncasecmp( Mark, "false", 5 )) {
|
|
Member->SetValue( jtBool, "0" );
|
|
}
|
|
else {
|
|
// Try conversion to int
|
|
strtol( Mark, &EndMark, 10 );
|
|
if (EndMark == BufPos) {
|
|
Value = (char*)malloc( Len+1 );
|
|
memcpy( Value, Mark, Len );
|
|
Value[Len] = 0;
|
|
Member->SetValuePtr( jtInt, Value, Len );
|
|
}
|
|
else {
|
|
// Try conversion to float
|
|
strtod( Mark, &EndMark );
|
|
if (EndMark == BufPos) {
|
|
Value = (char*)malloc( Len+1 );
|
|
memcpy( Value, Mark, Len );
|
|
Value[Len] = 0;
|
|
Member->SetValuePtr( jtFloat, Value, Len );
|
|
}
|
|
else {
|
|
Error = true;
|
|
sprintf( ErrorText, "Invalid primitive param value on line %d:%d", LineNo, CharNo );
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Success
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CJSONparse::PrintString( char * String, int Len )
|
|
{
|
|
int BytesWritten = 0;
|
|
|
|
// Start quote
|
|
if (write( OutputHandle, "\"", 1 ) < 0)
|
|
return false;
|
|
|
|
// Content
|
|
BufPos = String;
|
|
while (true)
|
|
{
|
|
// Scan for special chars
|
|
Mark = BufPos;
|
|
while ((*BufPos >= 32) && (*BufPos <= 126) && (*BufPos != '\\') && (*BufPos != '/') && (*BufPos != '"'))
|
|
BufPos++;
|
|
|
|
// Print Portion
|
|
if (write( OutputHandle, Mark, (BufPos-Mark) ) < 0)
|
|
return false;
|
|
|
|
// Handle special chars
|
|
if (BufPos-String >= Len) {
|
|
break;
|
|
}
|
|
else {
|
|
switch (*BufPos) {
|
|
case '\b': BytesWritten = write( OutputHandle, "\\b", 2 ); break;
|
|
case '\f': BytesWritten = write( OutputHandle, "\\f", 2 ); break;
|
|
case '\n': BytesWritten = write( OutputHandle, "\\n", 2 ); break;
|
|
case '\r': BytesWritten = write( OutputHandle, "\\r", 2 ); break;
|
|
case '\t': BytesWritten = write( OutputHandle, "\\t", 2 ); break;
|
|
case '/': BytesWritten = write( OutputHandle, "\\/", 2 ); break;
|
|
case '\\': BytesWritten = write( OutputHandle, "\\\\", 2 ); break;
|
|
case '"': BytesWritten = write( OutputHandle, "\\\"", 2 ); break;
|
|
default:
|
|
BytesWritten = dprintf( OutputHandle, "\\u%04X", (unsigned char)*BufPos );
|
|
break;
|
|
}
|
|
if (BytesWritten < 0)
|
|
return false;
|
|
BufPos++;
|
|
}
|
|
}
|
|
|
|
// End Quote
|
|
if (write( OutputHandle, "\"", 1 ) < 0)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CJSONparse::PrintObject( CDataMember * Object, const int Indent )
|
|
{
|
|
CDataMember * Member;
|
|
bool First = true;
|
|
bool Last = false;
|
|
int Count = 0;
|
|
|
|
// Opening brace
|
|
if (write( OutputHandle, "{", 1 ) < 0)
|
|
return false;
|
|
|
|
// Check if empty
|
|
if (Object->Len == 0) {
|
|
if (write( OutputHandle, "}", 1 ) < 0)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
// Extend spacer
|
|
if (Indent) {
|
|
memset( &Spacer[SpacerLen], ' ', 2 );
|
|
SpacerLen += 2;
|
|
Spacer[SpacerLen] = 0;
|
|
}
|
|
|
|
// Save parameters
|
|
for (Member = Object->FirstChild; Member != NULL; (Member = Member->NextPeer))
|
|
{
|
|
// Whitespace around first bracket
|
|
if (Indent) {
|
|
if (First) {
|
|
First = false;
|
|
if (write( OutputHandle, "\n", 1 ) < 0)
|
|
return false;
|
|
}
|
|
if (write( OutputHandle, Spacer, SpacerLen ) < 0)
|
|
return false;
|
|
}
|
|
|
|
// Print key name
|
|
if (!PrintString( Member->Name, strlen(Member->Name) ))
|
|
return false;
|
|
if (Indent) {
|
|
if (write( OutputHandle," : ", 3 ) < 0)
|
|
return false;
|
|
} else {
|
|
if (write( OutputHandle, ":", 1 ) < 0)
|
|
return false;
|
|
}
|
|
|
|
// Print value
|
|
Last = (++Count >= Object->Len);
|
|
switch (Member->Type)
|
|
{
|
|
case jtNull :
|
|
if (write( OutputHandle, "null", 4 ) < 0)
|
|
return false;
|
|
break;
|
|
|
|
case jtBool :
|
|
if (!strcmp( Member->Value, "0" )) {
|
|
if (write( OutputHandle, "false", 5 ) < 0)
|
|
return false;
|
|
}
|
|
else {
|
|
if (write( OutputHandle, "true", 4 ) < 0)
|
|
return false;
|
|
}
|
|
break;
|
|
|
|
case jtInt :
|
|
case jtFloat :
|
|
if (write( OutputHandle, Member->Value, Member->Len ) < 0)
|
|
return false;
|
|
break;
|
|
|
|
case jtString :
|
|
if (!PrintString( Member->Value, Member->Len ))
|
|
return false;
|
|
break;
|
|
|
|
case jtArray :
|
|
if (!PrintArray( Member, Indent ))
|
|
return false;
|
|
break;
|
|
|
|
case jtObject :
|
|
if (!PrintObject( Member, Indent ))
|
|
return false;
|
|
break;
|
|
}
|
|
if (!Last) {
|
|
if (write( OutputHandle, ",", 1 ) < 0)
|
|
return false;
|
|
}
|
|
if (Indent) {
|
|
if (write( OutputHandle, "\n", 1 ) < 0)
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Shorten spacer
|
|
if (Indent) {
|
|
SpacerLen -= 2;
|
|
Spacer[SpacerLen] = 0;
|
|
}
|
|
|
|
// Closing brace
|
|
if (Indent) {
|
|
if (write( OutputHandle, Spacer, SpacerLen ) < 0)
|
|
return false;
|
|
}
|
|
if (write( OutputHandle, "}", 1 ) < 0)
|
|
return false;
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CJSONparse::PrintArray( CDataMember * Array, const int Indent )
|
|
{
|
|
CDataMember * Member;
|
|
bool First = true;
|
|
bool Last = false;
|
|
int Count = 0;
|
|
|
|
// Opening brace
|
|
if (write( OutputHandle, "[", 1 ) < 0)
|
|
return false;
|
|
|
|
// Check if empty
|
|
if (Array->Len == 0) {
|
|
if (write( OutputHandle, "]", 1 ) < 0)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
// Extend spacer
|
|
if (Indent) {
|
|
memset( &Spacer[SpacerLen], ' ', 2 );
|
|
SpacerLen += 2;
|
|
Spacer[SpacerLen] = 0;
|
|
}
|
|
|
|
// Save parameters
|
|
for (Member = Array->FirstChild; Member != NULL; (Member = Member->NextPeer))
|
|
{
|
|
// Whitespace around brace
|
|
if (Indent) {
|
|
if (First) {
|
|
First = false;
|
|
if (write( OutputHandle, "\n", 1 ) < 0)
|
|
return false;
|
|
}
|
|
if (write( OutputHandle, Spacer, SpacerLen ) < 0)
|
|
return false;
|
|
}
|
|
|
|
Last = (++Count >= Array->Len);
|
|
switch (Member->Type)
|
|
{
|
|
case jtNull :
|
|
if (write( OutputHandle, "null", 4 ) < 0)
|
|
return false;
|
|
break;
|
|
|
|
case jtBool :
|
|
case jtInt :
|
|
case jtFloat :
|
|
if (write( OutputHandle, Member->Value, Member->Len ) < 0)
|
|
return false;
|
|
break;
|
|
|
|
case jtString :
|
|
if ((write( OutputHandle, "\"", 1 ) < 0) ||
|
|
(write( OutputHandle, Member->Value, Member->Len ) < 0) ||
|
|
(write( OutputHandle, "\"", 1 ) < 0))
|
|
return false;
|
|
break;
|
|
|
|
case jtArray :
|
|
if (!PrintArray( Member, Indent ))
|
|
return false;
|
|
break;
|
|
|
|
case jtObject :
|
|
if (!PrintObject( Member, Indent ))
|
|
return false;
|
|
break;
|
|
}
|
|
if (!Last) {
|
|
if (write( OutputHandle, ",", 1 ) < 0)
|
|
return false;
|
|
}
|
|
if (Indent) {
|
|
if (write( OutputHandle, "\n", 1 ) < 0)
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Shorten spacer
|
|
if (Indent) {
|
|
SpacerLen -= 2;
|
|
Spacer[SpacerLen] = 0;
|
|
}
|
|
|
|
// Closing brace
|
|
if (Indent) {
|
|
if (write( OutputHandle, Spacer, SpacerLen ) < 0)
|
|
return false;
|
|
}
|
|
if (write( OutputHandle, "]", 1 ) < 0)
|
|
return false;
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|