ultimatepp/bazaar/plugin/gdal/frmts/ers/ershdrnode.cpp
cxl 23ff1e7e82 .gdal moved to bazaar
git-svn-id: svn://ultimatepp.org/upp/trunk@9273 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2015-12-07 13:36:24 +00:00

471 lines
16 KiB
C++

/******************************************************************************
* $Id: ershdrnode.cpp 21814 2011-02-23 22:55:14Z warmerdam $
*
* Project: ERMapper .ers Driver
* Purpose: Implementation of ERSHdrNode class for parsing/accessing .ers hdr.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 2007, Frank Warmerdam <warmerdam@pobox.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
****************************************************************************/
#include "cpl_conv.h"
#include "cpl_string.h"
#include "ershdrnode.h"
CPL_CVSID("$Id: ershdrnode.cpp 21814 2011-02-23 22:55:14Z warmerdam $");
/************************************************************************/
/* ERSHdrNode() */
/************************************************************************/
ERSHdrNode::ERSHdrNode()
{
nItemMax = 0;
nItemCount = 0;
papszItemName = NULL;
papszItemValue = NULL;
papoItemChild = NULL;
}
/************************************************************************/
/* ~ERSHdrNode() */
/************************************************************************/
ERSHdrNode::~ERSHdrNode()
{
int i;
for( i = 0; i < nItemCount; i++ )
{
if( papoItemChild[i] != NULL )
delete papoItemChild[i];
if( papszItemValue[i] != NULL )
CPLFree( papszItemValue[i] );
CPLFree( papszItemName[i] );
}
CPLFree( papszItemName );
CPLFree( papszItemValue );
CPLFree( papoItemChild );
}
/************************************************************************/
/* MakeSpace() */
/* */
/* Ensure we have room for at least one more entry in our item */
/* lists. */
/************************************************************************/
void ERSHdrNode::MakeSpace()
{
if( nItemCount == nItemMax )
{
nItemMax = (int) (nItemMax * 1.3) + 10;
papszItemName = (char **)
CPLRealloc(papszItemName,sizeof(char *) * nItemMax);
papszItemValue = (char **)
CPLRealloc(papszItemValue,sizeof(char *) * nItemMax);
papoItemChild = (ERSHdrNode **)
CPLRealloc(papoItemChild,sizeof(void *) * nItemMax);
}
}
/************************************************************************/
/* ReadLine() */
/* */
/* Read one virtual line from the input source. Multiple lines */
/* will be appended for objects enclosed in {}. */
/************************************************************************/
int ERSHdrNode::ReadLine( VSILFILE * fp, CPLString &osLine )
{
int nBracketLevel;
osLine = "";
do
{
const char *pszNewLine = CPLReadLineL( fp );
if( pszNewLine == NULL )
return FALSE;
osLine += pszNewLine;
int bInQuote = FALSE;
size_t i;
nBracketLevel = 0;
for( i = 0; i < osLine.length(); i++ )
{
if( osLine[i] == '"' )
bInQuote = !bInQuote;
else if( osLine[i] == '{' && !bInQuote )
nBracketLevel++;
else if( osLine[i] == '}' && !bInQuote )
nBracketLevel--;
// We have to ignore escaped quotes and backslashes in strings.
else if( osLine[i] == '\\' && osLine[i+1] == '"' && bInQuote )
i++;
else if( osLine[i] == '\\' && osLine[i+1] == '\\' && bInQuote )
i++;
}
} while( nBracketLevel > 0 );
return TRUE;
}
/************************************************************************/
/* ParseChildren() */
/* */
/* We receive the FILE * positioned after the "Object Begin" */
/* line for this object, and are responsible for reading all */
/* children. We should return after consuming the */
/* corresponding End line for this object. Really the first */
/* unmatched End since we don't know what object we are. */
/* */
/* This function is used recursively to read sub-objects. */
/************************************************************************/
int ERSHdrNode::ParseChildren( VSILFILE * fp )
{
while( TRUE )
{
size_t iOff;
CPLString osLine;
/* -------------------------------------------------------------------- */
/* Read the next line (or multi-line for bracketed value). */
/* -------------------------------------------------------------------- */
if( !ReadLine( fp, osLine ) )
return FALSE;
/* -------------------------------------------------------------------- */
/* Got a Name=Value. */
/* -------------------------------------------------------------------- */
if( (iOff = osLine.find_first_of( '=' )) != std::string::npos )
{
CPLString osName = osLine.substr(0,iOff-1);
osName.Trim();
CPLString osValue = osLine.c_str() + iOff + 1;
osValue.Trim();
MakeSpace();
papszItemName[nItemCount] = CPLStrdup(osName);
papszItemValue[nItemCount] = CPLStrdup(osValue);
papoItemChild[nItemCount] = NULL;
nItemCount++;
}
/* -------------------------------------------------------------------- */
/* Got a Begin for an object. */
/* -------------------------------------------------------------------- */
else if( (iOff = osLine.ifind( " Begin" )) != std::string::npos )
{
CPLString osName = osLine.substr(0,iOff);
osName.Trim();
MakeSpace();
papszItemName[nItemCount] = CPLStrdup(osName);
papszItemValue[nItemCount] = NULL;
papoItemChild[nItemCount] = new ERSHdrNode();
nItemCount++;
if( !papoItemChild[nItemCount-1]->ParseChildren( fp ) )
return FALSE;
}
/* -------------------------------------------------------------------- */
/* Got an End for our object. Well, at least we *assume* it */
/* must be for our object. */
/* -------------------------------------------------------------------- */
else if( osLine.ifind( " End" ) != std::string::npos )
{
return TRUE;
}
/* -------------------------------------------------------------------- */
/* Error? */
/* -------------------------------------------------------------------- */
else if( osLine.Trim().length() > 0 )
{
CPLError( CE_Failure, CPLE_AppDefined,
"Unexpected line parsing .ecw:\n%s",
osLine.c_str() );
return FALSE;
}
}
}
/************************************************************************/
/* WriteSelf() */
/* */
/* Recursively write self and children to file. */
/************************************************************************/
int ERSHdrNode::WriteSelf( VSILFILE * fp, int nIndent )
{
CPLString oIndent;
int i;
oIndent.assign( nIndent, '\t' );
for( i = 0; i < nItemCount; i++ )
{
if( papszItemValue[i] != NULL )
{
if( VSIFPrintfL( fp, "%s%s\t= %s\n",
oIndent.c_str(),
papszItemName[i],
papszItemValue[i] ) < 1 )
return FALSE;
}
else
{
VSIFPrintfL( fp, "%s%s Begin\n",
oIndent.c_str(), papszItemName[i] );
if( !papoItemChild[i]->WriteSelf( fp, nIndent+1 ) )
return FALSE;
if( VSIFPrintfL( fp, "%s%s End\n",
oIndent.c_str(), papszItemName[i] ) < 1 )
return FALSE;
}
}
return TRUE;
}
/************************************************************************/
/* Find() */
/* */
/* Find the desired entry value. The input is a path with */
/* components seperated by dots, relative to the current node. */
/************************************************************************/
const char *ERSHdrNode::Find( const char *pszPath, const char *pszDefault )
{
int i;
/* -------------------------------------------------------------------- */
/* If this is the final component of the path, search for a */
/* matching child and return the value. */
/* -------------------------------------------------------------------- */
if( strchr(pszPath,'.') == NULL )
{
for( i = 0; i < nItemCount; i++ )
{
if( EQUAL(pszPath,papszItemName[i]) )
{
if( papszItemValue[i] != NULL )
{
if( papszItemValue[i][0] == '"' )
{
// strip off quotes.
osTempReturn = papszItemValue[i];
osTempReturn =
osTempReturn.substr( 1, osTempReturn.length()-2 );
return osTempReturn;
}
else
return papszItemValue[i];
}
else
return pszDefault;
}
}
return pszDefault;
}
/* -------------------------------------------------------------------- */
/* This is a dot path - extract the first element, find a match */
/* and recurse. */
/* -------------------------------------------------------------------- */
CPLString osPathFirst, osPathRest, osPath = pszPath;
int iDot;
iDot = osPath.find_first_of('.');
osPathFirst = osPath.substr(0,iDot);
osPathRest = osPath.substr(iDot+1);
for( i = 0; i < nItemCount; i++ )
{
if( EQUAL(osPathFirst,papszItemName[i]) )
{
if( papoItemChild[i] != NULL )
return papoItemChild[i]->Find( osPathRest, pszDefault );
else
return pszDefault;
}
}
return pszDefault;
}
/************************************************************************/
/* FindElem() */
/* */
/* Find a particular element from an array valued item. */
/************************************************************************/
const char *ERSHdrNode::FindElem( const char *pszPath, int iElem,
const char *pszDefault )
{
const char *pszArray = Find( pszPath, NULL );
char **papszTokens;
int bDefault = TRUE;
if( pszArray == NULL )
return pszDefault;
papszTokens = CSLTokenizeStringComplex( pszArray, "{ \t}", TRUE, FALSE );
if( iElem >= 0 && iElem < CSLCount(papszTokens) )
{
osTempReturn = papszTokens[iElem];
bDefault = FALSE;
}
CSLDestroy( papszTokens );
if( bDefault )
return pszDefault;
else
return osTempReturn;
}
/************************************************************************/
/* FindNode() */
/* */
/* Find the desired node. */
/************************************************************************/
ERSHdrNode *ERSHdrNode::FindNode( const char *pszPath )
{
int i;
CPLString osPathFirst, osPathRest, osPath = pszPath;
int iDot;
iDot = osPath.find_first_of('.');
if( iDot == -1 )
{
osPathFirst = osPath;
}
else
{
osPathFirst = osPath.substr(0,iDot);
osPathRest = osPath.substr(iDot+1);
}
for( i = 0; i < nItemCount; i++ )
{
if( EQUAL(osPathFirst,papszItemName[i]) )
{
if( papoItemChild[i] != NULL )
{
if( osPathRest.length() > 0 )
return papoItemChild[i]->FindNode( osPathRest );
else
return papoItemChild[i];
}
else
return NULL;
}
}
return NULL;
}
/************************************************************************/
/* Set() */
/* */
/* Set a value item. */
/************************************************************************/
void ERSHdrNode::Set( const char *pszPath, const char *pszValue )
{
CPLString osPath = pszPath;
int iDot;
iDot = osPath.find_first_of('.');
/* -------------------------------------------------------------------- */
/* We have an intermediate node, find or create it and */
/* recurse. */
/* -------------------------------------------------------------------- */
if( iDot != -1 )
{
CPLString osPathFirst = osPath.substr(0,iDot);
CPLString osPathRest = osPath.substr(iDot+1);
ERSHdrNode *poFirst = FindNode( osPathFirst );
if( poFirst == NULL )
{
poFirst = new ERSHdrNode();
MakeSpace();
papszItemName[nItemCount] = CPLStrdup(osPathFirst);
papszItemValue[nItemCount] = NULL;
papoItemChild[nItemCount] = poFirst;
nItemCount++;
}
poFirst->Set( osPathRest, pszValue );
return;
}
/* -------------------------------------------------------------------- */
/* This is the final item name. Find or create it. */
/* -------------------------------------------------------------------- */
int i;
for( i = 0; i < nItemCount; i++ )
{
if( EQUAL(osPath,papszItemName[i])
&& papszItemValue[i] != NULL )
{
CPLFree( papszItemValue[i] );
papszItemValue[i] = CPLStrdup( pszValue );
return;
}
}
MakeSpace();
papszItemName[nItemCount] = CPLStrdup(osPath);
papszItemValue[nItemCount] = CPLStrdup(pszValue);
papoItemChild[nItemCount] = NULL;
nItemCount++;
}