Major Update:

- Update printing: Do not use '\n' if indent = 0
- Implement refilling of buffer (from fd) while parsing
  - No longer use LineMark, but keep track of char position with CharNo
  - Use Mark to reference point for shifting buffer on refill
- SkipWhiteSpace no longer inline method
  - Refill buffer if required, change Mark & CharNo on line break
- CreateBuffer(), RefillBuffer() & FreeBuffer() now public methods
- Make Loading and Saving more flexible:
  - Refactor from LoadFromFile():
    ReadFromFile(), ReadFromHandle(), ReadFromBuffer()
  - Refactor from SaveToFile() & PrintToScreen:
    WriteToFile(), WriteToScreen, WriteToHandle()
This commit is contained in:
Charl Wentzel
2017-04-02 19:44:44 +02:00
parent 8f39adb0f3
commit 2e2ba113f1
3 changed files with 268 additions and 141 deletions

View File

@@ -27,12 +27,13 @@ CJSONparse::CJSONparse( CDataTree * pDataTree )
OutputHandle = -1;
Buffer = NULL;
BufEnd = NULL;
// Parsing operation
BufPos = NULL;
LineMark = NULL;
Mark = NULL;
LineNo = 0;
CharNo = 0;
RefillBuffer = false;
// Printing operation
Spacer[0] = 0;
@@ -53,53 +54,31 @@ CJSONparse::~CJSONparse()
}
//---------------------------------------------------------------------------
bool CJSONparse::PrintToScreen( const char * RootPath, const int Indent )
bool CJSONparse::WriteToScreen( const char * RootPath, const int Indent )
{
TDataMember * RootObject;
// Validate
if (!DataTree) {
return false;
}
// Set to StdOut
OutputHandle = 1;
// Get Root object
if (!RootPath || !*RootPath) {
RootObject = DataTree->GetRootMember();
}
else if (!(RootObject = DataTree->GetMember( NULL, RootPath ))) {
Error = true;
sprintf( ErrorText, "Invalid root object path" );
return false;
}
// Print key name
if (RootObject->Name) {
write( OutputHandle, "\"", 1 );
write( OutputHandle, RootObject->Name, strlen(RootObject->Name) );
write( OutputHandle, "\" : ", 4 );
}
// Print to screen
PrintObject( RootObject, Indent );
WriteToHandle( RootPath, 1, Indent );
// Close file
close( OutputHandle );
OutputHandle = -1;
return true;
}
//---------------------------------------------------------------------------
bool CJSONparse::SaveToFile( const char * RootPath, const char * FilePath, const int Indent )
bool CJSONparse::WriteToFile( const char * RootPath, const char * Path, const char * FileName, const int Indent )
{
TDataMember * RootObject;
char FilePath[250] = "";
// Validate
if (!DataTree) {
return false;
}
// Build file name
strcpy( FilePath, Path );
strcat( FilePath, FileName );
// Read file
return WriteToFile( RootPath, FilePath, Indent );
}
//---------------------------------------------------------------------------
bool CJSONparse::WriteToFile( const char * RootPath, const char * FilePath, const int Indent )
{
int Handle = -1;
// Clear Error
Error = false;
@@ -112,12 +91,38 @@ bool CJSONparse::SaveToFile( const char * RootPath, const char * FilePath, const
}
// Open file
if (!(OutputHandle = open( FilePath, O_CREAT|O_WRONLY|O_TRUNC ))) {
if ((Handle = open( FilePath, O_CREAT|O_WRONLY|O_TRUNC )) < 0) {
Error = true;
sprintf( ErrorText, "Could not open file" );
return false;
}
// Save to file
WriteToHandle( RootPath, Handle, Indent );
// Close file
close( Handle );
return true;
}
//---------------------------------------------------------------------------
bool CJSONparse::WriteToHandle( const char * RootPath, const int Handle, const int Indent )
{
TDataMember * RootObject;
// 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 (!RootPath || !*RootPath) {
RootObject = DataTree->GetRootMember();
@@ -130,17 +135,29 @@ bool CJSONparse::SaveToFile( const char * RootPath, const char * FilePath, const
// Print to file
PrintObject( RootObject, Indent );
write( OutputHandle, "\n", 1 );
// Close file
close( OutputHandle );
OutputHandle = -1;
return true;
}
//---------------------------------------------------------------------------
bool CJSONparse::LoadFromFile( const char * RootPath, const char * FilePath, int pBufLen )
bool CJSONparse::ReadFromFile( const char * RootPath, const char * Path, const char * FileName )
{
TDataMember * RootObject = NULL;
char FilePath[250] = "";
// Build file name
strcpy( FilePath, Path );
strcat( FilePath, FileName );
// Read file
return ReadFromFile( RootPath, FilePath );
}
//---------------------------------------------------------------------------
bool CJSONparse::ReadFromFile( const char * RootPath, const char * FilePath )
{
int Handle = -1;
// Validate
if (!DataTree) {
@@ -158,14 +175,36 @@ bool CJSONparse::LoadFromFile( const char * RootPath, const char * FilePath, int
}
// Open file
if (!(InputHandle = open( FilePath, O_RDONLY ))) {
if ((Handle = open( FilePath, O_RDONLY )) < 0) {
Error = true;
sprintf( ErrorText, "Could not open file" );
return false;
}
// Continuously refill buffer while loading
ReadFromHandle( RootPath, Handle, true );
// Close File
close( Handle );
return true;
}
//---------------------------------------------------------------------------
bool CJSONparse::ReadFromHandle( const char * RootPath, int Handle, bool pRefillBuffer )
{
// Clear Error
Error = false;
// Validate
if (Handle < 0) {
Error = true;
sprintf( ErrorText, "Cannot read from invalid handle" );
return false;
}
InputHandle = Handle;
// Load Buffer
CreateBuffer( pBufLen );
CreateBuffer( 50 );
if (!FillBuffer()) {
Error = true;
sprintf( ErrorText, "Could not read from file" );
@@ -173,6 +212,31 @@ bool CJSONparse::LoadFromFile( const char * RootPath, const char * FilePath, int
return false;
}
// Continuously refill buffer while loading
RefillBuffer = pRefillBuffer;
ReadFromBuffer( RootPath );
RefillBuffer = false;
// Destroy buffer
FreeBuffer();
InputHandle = -1;
return true;
}
//---------------------------------------------------------------------------
bool CJSONparse::ReadFromBuffer( const char * RootPath )
{
TDataMember * RootObject = NULL;
// Validate
if (!DataTree || !Buffer) {
return false;
}
// Clear Error
Error = false;
// Get/Create Root object
if (!RootPath || !*RootPath) {
RootObject = DataTree->GetRootMember();
@@ -183,16 +247,20 @@ bool CJSONparse::LoadFromFile( const char * RootPath, const char * FilePath, int
return false;
}
// Reset values
LineNo = 1;
// Delete existing object contents
DataTree->Delete( RootObject, NULL );
// Position Counters
LineNo = 1;
CharNo = 0;
// Parse Root Object
SkipWhiteSpace();
if (!ParseObject( RootObject )) {
if (!Error) {
Error = true;
sprintf( ErrorText, "First entry in file must be an Object on line %d:%ld", LineNo, BufPos-LineMark );
CharNo += BufPos-Mark;
sprintf( ErrorText, "First entry in file must be an Object on line %d:%d", LineNo, CharNo );
}
FreeBuffer();
return false;
@@ -202,15 +270,13 @@ bool CJSONparse::LoadFromFile( const char * RootPath, const char * FilePath, int
SkipWhiteSpace();
if (*BufPos != 0) {
Error = true;
sprintf( ErrorText, "No content expected after Root object on line %d:%ld", LineNo, BufPos-LineMark );
CharNo += BufPos-Mark;
sprintf( ErrorText, "No content expected after Root object on line %d:%d", LineNo, CharNo );
FreeBuffer();
return false;
}
// Success
close( InputHandle );
InputHandle = -1;
FreeBuffer();
return true;
}
//---------------------------------------------------------------------------
@@ -226,8 +292,7 @@ bool CJSONparse::CreateBuffer( int pBufLen )
// Reset markers
Buffer->PeekDirect( &BufPos, 0 );
BufEnd = BufPos;
LineMark = BufPos;
Mark = BufPos;
return true;
}
@@ -235,13 +300,19 @@ bool CJSONparse::CreateBuffer( int pBufLen )
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 );
// Update Markers
Buffer->PeekDirect( &BufEnd, Buffer->Len() );
Buffer->PeekDirect( &BufPos, 0 );
LineMark = BufPos;
// Reset Mark to start of buffer
Mark = BufStart;
BufPos = Mark + PosShift;
return true;
}
@@ -255,18 +326,40 @@ void CJSONparse::FreeBuffer()
Buffer = NULL;
// Update Markers
BufEnd = NULL;
BufPos = NULL;
LineMark = NULL;
Mark = NULL;
}
}
//---------------------------------------------------------------------------
bool CJSONparse::ParseString( char ** Value, int &pLen )
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 * Mark;
char * EndMark;
int Len;
// Check for opening quote
if (*BufPos != '"') {
@@ -278,12 +371,19 @@ bool CJSONparse::ParseString( char ** Value, int &pLen )
Len = 0;
// Mark start of quote
Mark = BufPos;
BufPos++;
// Check for closing quote
while ((BufPos = strpbrk( BufPos, "\"/\\\n\t\b\f\n\r" )))
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++;
@@ -291,15 +391,25 @@ bool CJSONparse::ParseString( char ** Value, int &pLen )
}
else if (!*BufPos) {
Error = true;
sprintf( ErrorText, "Expect closing '\"' for string on line %d:%ld", LineNo, Mark-LineMark );
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 (!*BufPos && RefillBuffer) {
FillBuffer();
continue;
}
if (!isxdigit( *EndMark )) {
Error = true;
sprintf( ErrorText, "Expect 4-digit hex value for escape value on line %d:%ld", LineNo, Mark-LineMark );
CharNo += BufPos-EndMark;
sprintf( ErrorText, "Expect 4-digit hex value for escape value on line %d:%d", LineNo, CharNo );
return false;
}
}
@@ -310,18 +420,20 @@ bool CJSONparse::ParseString( char ** Value, int &pLen )
}
else {
Error = true;
sprintf( ErrorText, "Invalid escape sequence on line %d:%ld", LineNo, Mark-LineMark );
CharNo += BufPos-Mark+1;
sprintf( ErrorText, "Invalid escape sequence on line %d:%d", LineNo, CharNo );
return false;
}
}
else {
Error = true;
sprintf( ErrorText, "Un-escaped special character in string on line %d:%ld", LineNo, BufPos-LineMark );
CharNo += BufPos-Mark+1;
sprintf( ErrorText, "Un-escaped special character in string on line %d:%d", LineNo, CharNo );
return false;
}
}
// Validate size of name
// Get size of name
Len = BufPos-Mark-2;
// Create Return value pointer
@@ -329,9 +441,6 @@ bool CJSONparse::ParseString( char ** Value, int &pLen )
memcpy( *Value, Mark+1, Len );
(*Value)[Len] = 0;
// Set other parameters
pLen = Len;
// Success
return true;
}
@@ -354,21 +463,22 @@ bool CJSONparse::ParseObject( TDataMember * Object )
while (true)
{
// Look for Member Name
// 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:%ld", LineNo, BufPos-LineMark );
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:%ld", LineNo, BufPos-LineMark );
sprintf( ErrorText, "Empty parameter name on line %d:%d", LineNo, CharNo );
return false;
}
@@ -379,7 +489,7 @@ bool CJSONparse::ParseObject( TDataMember * Object )
SkipWhiteSpace();
if (*BufPos != ':') {
Error = true;
sprintf( ErrorText, "Expected ':' delimiter on line %d:%ld", LineNo, BufPos-LineMark );
sprintf( ErrorText, "Expected ':' delimiter on line %d:%d", LineNo, CharNo );
return false;
}
BufPos++;
@@ -394,6 +504,7 @@ bool CJSONparse::ParseObject( TDataMember * Object )
!Error &&
!ParsePrimitive( Member ))
{
// Destroy member
DataTree->Delete( Object, MemberName );
return false;
}
@@ -413,7 +524,7 @@ bool CJSONparse::ParseObject( TDataMember * Object )
// Expect end of object
if (*BufPos != '}') {
Error = true;
sprintf( ErrorText, "Closing brace for object '}' expected on line %d:%ld", LineNo, BufPos-LineMark );
sprintf( ErrorText, "Closing brace for object '}' expected on line %d:%d", LineNo, CharNo );
return false;
}
BufPos++;
@@ -476,7 +587,7 @@ bool CJSONparse::ParseArray( TDataMember * Array )
// Expect end of object
if (*BufPos != ']') {
Error = true;
sprintf( ErrorText, "Closing brace for array ']' expected on line %d:%ld", LineNo, BufPos-LineMark );
sprintf( ErrorText, "Closing brace for array ']' expected on line %d:%d", LineNo, CharNo );
return false;
}
BufPos++;
@@ -507,14 +618,14 @@ bool CJSONparse::ParsePrimitive( TDataMember * Member )
{
char * Value = NULL;
int Len = 0;
char * Mark;
char * EndMark;
// Mark start of value
Mark = BufPos;
// Get end of value
while ((*BufPos != 0) && !isspace(*BufPos) && (*BufPos != ',')) {
while (true) {
if (!*BufPos && RefillBuffer)
FillBuffer();
if (!*BufPos || isspace(*BufPos) || (*BufPos == ',') || (*BufPos == '}') || (*BufPos == ']'))
break;
BufPos++;
}
@@ -522,7 +633,7 @@ bool CJSONparse::ParsePrimitive( TDataMember * Member )
Len = BufPos - Mark;
if (!Len) {
Error = true;
sprintf( ErrorText, "Missing param value on line %d:%ld", LineNo, Mark-LineMark );
sprintf( ErrorText, "Missing param value on line %d:%d", LineNo, CharNo );
return false;
}
@@ -556,7 +667,7 @@ bool CJSONparse::ParsePrimitive( TDataMember * Member )
}
else {
Error = true;
sprintf( ErrorText, "Invalid primitive param value on line %d:%ld", LineNo, Mark-LineMark );
sprintf( ErrorText, "Invalid primitive param value on line %d:%d", LineNo, CharNo );
return false;
}
}
@@ -578,32 +689,40 @@ bool CJSONparse::PrintObject( TDataMember * Object, const int Indent )
write( OutputHandle, "{", 1 );
// Extend spacer
memset( &Spacer[SpacerLen], ' ', 2 );
SpacerLen += 2;
Spacer[SpacerLen] = 0;
if (Indent) {
memset( &Spacer[SpacerLen], ' ', 2 );
SpacerLen += 2;
Spacer[SpacerLen] = 0;
}
// Save parameters
for (Member = Object->FirstChild; Member != NULL; (Member = Member->Next))
{
// Write parameter name
if (First) {
First = false;
if (Object->Name) {
write( OutputHandle, "\n", 1 );
write( OutputHandle, Spacer, SpacerLen );
// Whitespace around first bracket
if (Indent) {
if (First) {
First = false;
if (Object->Name) {
write( OutputHandle, "\n", 1 );
write( OutputHandle, Spacer, SpacerLen );
}
else {
write( OutputHandle, " ", 1 );
}
}
else {
write( OutputHandle, " ", 1 );
write( OutputHandle, Spacer, SpacerLen );
}
}
else {
write( OutputHandle, Spacer, SpacerLen );
}
// Print key name
write( OutputHandle, "\"", 1 );
write( OutputHandle, Member->Name, strlen(Member->Name) );
write( OutputHandle, "\" : ", 4 );
if (Indent) {
write( OutputHandle,"\" : ", 4 );
} else {
write( OutputHandle, "\":", 2 );
}
// Print value
Last = (++Count >= Object->Len);
@@ -633,15 +752,17 @@ bool CJSONparse::PrintObject( TDataMember * Object, const int Indent )
PrintObject( Member, Indent );
break;
}
if (!Last) {
if (!Last)
write( OutputHandle, ",", 1 );
}
write( OutputHandle, "\n", 1 );
if (Indent)
write( OutputHandle, "\n", 1 );
}
// Shorten spacer
SpacerLen -= 2;
Spacer[SpacerLen] = 0;
if (Indent) {
SpacerLen -= 2;
Spacer[SpacerLen] = 0;
}
// Closing brace
if (Object->Len) {
@@ -663,19 +784,23 @@ bool CJSONparse::PrintArray( TDataMember * Array, const int Indent )
write( OutputHandle, "[", 1 );
// Extend spacer
memset( &Spacer[SpacerLen], ' ', 2 );
SpacerLen += 2;
Spacer[SpacerLen] = 0;
if (Indent) {
memset( &Spacer[SpacerLen], ' ', 2 );
SpacerLen += 2;
Spacer[SpacerLen] = 0;
}
// Save parameters
for (Member = Array->FirstChild; Member != NULL; (Member = Member->Next))
{
// Write parameter name
if (First) {
First = false;
write( OutputHandle, "\n", 1 );
// Whitespace around brace
if (Indent) {
if (First) {
First = false;
write( OutputHandle, "\n", 1 );
}
write( OutputHandle, Spacer, SpacerLen );
}
write( OutputHandle, Spacer, SpacerLen );
Last = (++Count >= Array->Len);
switch (Member->Type)
@@ -704,15 +829,17 @@ bool CJSONparse::PrintArray( TDataMember * Array, const int Indent )
PrintObject( Member, Indent );
break;
}
if (!Last) {
if (!Last)
write( OutputHandle, ",", 1 );
}
write( OutputHandle, "\n", 1 );
if (Indent)
write( OutputHandle, "\n", 1 );
}
// Shorten spacer
SpacerLen -= 2;
Spacer[SpacerLen] = 0;
if (Indent) {
SpacerLen -= 2;
Spacer[SpacerLen] = 0;
}
// Closing brace
if (Array->Len) {