mirror of
https://bitbucket.org/smil3y/kde-playground.git
synced 2025-02-24 02:42:51 +00:00
608 lines
16 KiB
C++
608 lines
16 KiB
C++
////////////////////////////////////////////////////////////////////
|
|
///
|
|
/// MorkParser.cpp - Mozilla Mork Format Parser/Reader implementation
|
|
///
|
|
/// Copyright (C) 2007 ScalingWeb.com
|
|
/// All rights reserved.
|
|
///
|
|
/// Authors: Yuriy Soroka <ysoroka@scalingweb.com>
|
|
/// Anton Fedoruk <afedoruk@scalingweb.com>
|
|
///
|
|
///
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
|
|
#include "MorkParser.h"
|
|
#include <QtCore>
|
|
|
|
// =============================================================
|
|
// MorkParser::MorkParser
|
|
|
|
MorkParser::MorkParser( int DefaultScope )
|
|
{
|
|
initVars();
|
|
mDefaultScope = DefaultScope;
|
|
}
|
|
|
|
// =============================================================
|
|
// MorkParser::open
|
|
|
|
bool MorkParser::open( const QString &path )
|
|
{
|
|
initVars();
|
|
|
|
QFile MorkFile( path );
|
|
|
|
// Open file
|
|
if ( !MorkFile.exists() ||
|
|
!MorkFile.open( QIODevice::ReadOnly ) )
|
|
{
|
|
mError = FailedToOpen;
|
|
return false;
|
|
}
|
|
|
|
// Check magic header
|
|
QByteArray MagicHeader = MorkFile.readLine();
|
|
|
|
if ( !MagicHeader.contains( MorkMagicHeader ) )
|
|
{
|
|
mError = UnsupportedVersion;
|
|
return false;
|
|
}
|
|
|
|
mMorkData = MorkFile.readAll();
|
|
MorkFile.close();
|
|
|
|
// Parse mork
|
|
return parse();
|
|
}
|
|
|
|
// =============================================================
|
|
// MorkParser::error
|
|
|
|
MorkErrors MorkParser::error() const
|
|
{
|
|
return mError;
|
|
}
|
|
|
|
// =============================================================
|
|
// MorkParser::initVars
|
|
|
|
void MorkParser::initVars()
|
|
{
|
|
mError = NoError;
|
|
mMorkPos = 0;
|
|
nowParsing_ = NPValues;
|
|
mCurrentCells = 0;
|
|
mNextAddValueId = 0x7fffffff;
|
|
}
|
|
|
|
// =============================================================
|
|
// MorkParser::parse
|
|
|
|
bool MorkParser::parse()
|
|
{
|
|
bool Result = true;
|
|
char cur = 0;
|
|
|
|
// Run over mork chars and parse each term
|
|
cur = nextChar();
|
|
|
|
int i = 0;
|
|
|
|
while ( Result && cur )
|
|
{
|
|
if ( !isWhiteSpace( cur ) )
|
|
{
|
|
++i;
|
|
// Figure out what a term
|
|
switch ( cur )
|
|
{
|
|
case '<':
|
|
// Dict
|
|
Result = parseDict();
|
|
break;
|
|
case '/':
|
|
// Comment
|
|
Result = parseComment();
|
|
break;
|
|
case '{':
|
|
Result = parseTable();
|
|
// Table
|
|
break;
|
|
case '[':
|
|
Result = parseRow( 0, 0 );
|
|
// Row
|
|
break;
|
|
case '@':
|
|
Result = parseGroup();
|
|
// Group
|
|
break;
|
|
default:
|
|
mError = DefectedFormat;
|
|
Result = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Get next char
|
|
cur = nextChar();
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
// =============================================================
|
|
// MorkParser::isWhiteSpace
|
|
|
|
bool MorkParser::isWhiteSpace( char c )
|
|
{
|
|
switch ( c )
|
|
{
|
|
case ' ':
|
|
case '\t':
|
|
case '\r':
|
|
case '\n':
|
|
case '\f':
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// =============================================================
|
|
// MorkParser::nextChar
|
|
|
|
char MorkParser::nextChar()
|
|
{
|
|
char cur = 0;
|
|
|
|
if ( mMorkPos < mMorkData.length() )
|
|
{
|
|
cur = mMorkData[ mMorkPos ];
|
|
mMorkPos++;
|
|
}
|
|
|
|
if ( !cur )
|
|
{
|
|
cur = 0;
|
|
}
|
|
|
|
return cur;
|
|
}
|
|
|
|
// =============================================================
|
|
// MorkParser::parseDict
|
|
|
|
bool MorkParser::parseDict()
|
|
{
|
|
char cur = nextChar();
|
|
bool Result = true;
|
|
nowParsing_ = NPValues;
|
|
|
|
while ( Result && cur != '>' && cur )
|
|
{
|
|
if ( !isWhiteSpace( cur ) )
|
|
{
|
|
switch ( cur )
|
|
{
|
|
case '<':
|
|
if ( mMorkData.mid( mMorkPos - 1, strlen( MorkDictColumnMeta ) )
|
|
== MorkDictColumnMeta )
|
|
{
|
|
nowParsing_ = NPColumns;
|
|
mMorkPos += strlen( MorkDictColumnMeta ) - 1;
|
|
}
|
|
break;
|
|
case '(':
|
|
Result = parseCell();
|
|
break;
|
|
case '/':
|
|
Result = parseComment();
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
cur = nextChar();
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
// =============================================================
|
|
// MorkParser::parseComment
|
|
|
|
bool MorkParser::parseComment()
|
|
{
|
|
char cur = nextChar();
|
|
if ( '/' != cur )
|
|
return false;
|
|
|
|
while ( cur != '\r' && cur != '\n' && cur ) {
|
|
cur = nextChar();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// =============================================================
|
|
// MorkParser::parseCell
|
|
|
|
bool MorkParser::parseCell()
|
|
{
|
|
bool Result = true;
|
|
bool bColumnOid = false;
|
|
bool bValueOid = false;
|
|
bool bColumn = true;
|
|
int Corners = 0;
|
|
|
|
// Column = Value
|
|
QString Column;
|
|
QString Text;
|
|
|
|
char cur = nextChar();
|
|
|
|
// Process cell start with column (bColumn == true)
|
|
while ( Result && cur != ')' && cur )
|
|
{
|
|
switch ( cur )
|
|
{
|
|
case '^':
|
|
// Oids
|
|
Corners++;
|
|
if ( Corners == 1 )
|
|
{
|
|
bColumnOid = true;
|
|
}
|
|
else if ( Corners == 2 )
|
|
{
|
|
bColumn = false;
|
|
bValueOid = true;
|
|
}
|
|
else
|
|
{
|
|
Text += cur;
|
|
}
|
|
|
|
break;
|
|
case '=':
|
|
// From column to value
|
|
if ( bColumn )
|
|
{
|
|
bColumn = false;
|
|
}
|
|
else
|
|
{
|
|
Text += cur;
|
|
}
|
|
break;
|
|
case '\\':
|
|
{
|
|
// Get next two chars
|
|
char NextChar= nextChar();
|
|
if ( '\r' != NextChar && '\n' != NextChar )
|
|
{
|
|
Text += NextChar;
|
|
}
|
|
else nextChar();
|
|
}
|
|
break;
|
|
case '$':
|
|
{
|
|
// Get next two chars
|
|
QString HexChar;
|
|
HexChar += nextChar();
|
|
HexChar += nextChar();
|
|
Text += ( char ) HexChar.toInt( 0, 16 );
|
|
}
|
|
break;
|
|
default:
|
|
// Just a char
|
|
if ( bColumn )
|
|
{
|
|
Column += cur;
|
|
}
|
|
else
|
|
{
|
|
Text += cur;
|
|
}
|
|
break;
|
|
}
|
|
|
|
cur = nextChar();
|
|
}
|
|
Q_UNUSED( bColumnOid );
|
|
// Apply column and text
|
|
int ColumnId = Column.toInt( 0, 16 );
|
|
|
|
if ( NPRows != nowParsing_ )
|
|
{
|
|
// Dicts
|
|
if ( !Text.isEmpty() )
|
|
{
|
|
if ( nowParsing_ == NPColumns )
|
|
{
|
|
mColumns[ ColumnId ] = Text;
|
|
//qDebug()<<" column :"<<ColumnId<<" Text "<<Text;
|
|
}
|
|
else
|
|
{
|
|
mValues[ ColumnId ] = Text;
|
|
//qDebug()<<" ColumnId "<<ColumnId<<" Value : "<<Text;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( !Text.isEmpty() )
|
|
{
|
|
// Rows
|
|
int ValueId = Text.toInt( 0, 16 );
|
|
|
|
if ( bValueOid )
|
|
{
|
|
( *mCurrentCells )[ ColumnId ] = ValueId;
|
|
}
|
|
else
|
|
{
|
|
mNextAddValueId--;
|
|
mValues[ mNextAddValueId ] = Text;
|
|
( *mCurrentCells )[ ColumnId ] = mNextAddValueId;
|
|
}
|
|
}
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
// =============================================================
|
|
// MorkParser::parseTable
|
|
|
|
bool MorkParser::parseTable()
|
|
{
|
|
bool Result = true;
|
|
QString TextId;
|
|
int Id = 0, Scope = 0;
|
|
|
|
char cur = nextChar();
|
|
|
|
// Get id
|
|
while ( cur != '{' && cur != '[' && cur != '}' && cur )
|
|
{
|
|
if ( !isWhiteSpace( cur ) )
|
|
{
|
|
TextId += cur;
|
|
}
|
|
|
|
cur = nextChar();
|
|
}
|
|
|
|
parseScopeId( TextId, Id, Scope );
|
|
|
|
// Parse the table
|
|
while ( Result && cur != '}' && cur )
|
|
{
|
|
if ( !isWhiteSpace( cur ) )
|
|
{
|
|
switch ( cur )
|
|
{
|
|
case '{':
|
|
Result = parseMeta( '}' );
|
|
break;
|
|
case '[':
|
|
Result = parseRow( Id, Scope );
|
|
break;
|
|
case '-':
|
|
case '+':
|
|
break;
|
|
default:
|
|
{
|
|
QString JustId;
|
|
while ( !isWhiteSpace( cur ) && cur )
|
|
{
|
|
JustId += cur;
|
|
cur = nextChar();
|
|
|
|
if ( cur == '}' )
|
|
{
|
|
return Result;
|
|
}
|
|
}
|
|
|
|
int JustIdNum = 0, JustScopeNum = 0;
|
|
parseScopeId( JustId, JustIdNum, JustScopeNum );
|
|
|
|
setCurrentRow( Scope, Id, JustScopeNum, JustIdNum );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
cur = nextChar();
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
// =============================================================
|
|
// MorkParser::parseScopeId
|
|
|
|
void MorkParser::parseScopeId( const QString &textId, int &Id, int &Scope )
|
|
{
|
|
int Pos = 0;
|
|
|
|
if ( ( Pos = textId.indexOf( QLatin1Char(':') ) ) >= 0 )
|
|
{
|
|
QString tId = textId.mid( 0, Pos );
|
|
QString tSc = textId.mid( Pos + 1, textId.length() - Pos );
|
|
|
|
if ( tSc.length() > 1 && tSc[ 0 ] == '^' )
|
|
{
|
|
// Delete '^'
|
|
tSc.remove( 0, 1 );
|
|
}
|
|
|
|
Id = tId.toInt( 0, 16 );
|
|
Scope = tSc.toInt( 0, 16 );
|
|
}
|
|
else
|
|
{
|
|
Id = textId.toInt( 0, 16 );
|
|
}
|
|
}
|
|
|
|
// =============================================================
|
|
// MorkParser::setCurrentRow
|
|
|
|
void MorkParser::setCurrentRow( int TableScope, int TableId, int RowScope, int RowId )
|
|
{
|
|
if ( !RowScope )
|
|
{
|
|
RowScope = mDefaultScope;
|
|
}
|
|
|
|
if ( !TableScope )
|
|
{
|
|
TableScope = mDefaultScope;
|
|
}
|
|
|
|
mCurrentCells = &( mMork[ abs( TableScope ) ][ abs( TableId ) ][ abs( RowScope ) ][ abs( RowId ) ] );
|
|
}
|
|
|
|
// =============================================================
|
|
// MorkParser::parseRow
|
|
|
|
bool MorkParser::parseRow( int TableId, int TableScope )
|
|
{
|
|
bool Result = true;
|
|
QString TextId;
|
|
int Id = 0, Scope = 0;
|
|
nowParsing_ = NPRows;
|
|
|
|
char cur = nextChar();
|
|
|
|
// Get id
|
|
while ( cur != '(' && cur != ']' && cur != '[' && cur )
|
|
{
|
|
if ( !isWhiteSpace( cur ) )
|
|
{
|
|
TextId += cur;
|
|
}
|
|
|
|
cur = nextChar();
|
|
}
|
|
|
|
parseScopeId( TextId, Id, Scope );
|
|
setCurrentRow( TableScope, TableId, Scope, Id );
|
|
|
|
// Parse the row
|
|
while ( Result && cur != ']' && cur )
|
|
{
|
|
if ( !isWhiteSpace( cur ) )
|
|
{
|
|
switch ( cur )
|
|
{
|
|
case '(':
|
|
Result = parseCell();
|
|
break;
|
|
case '[':
|
|
Result = parseMeta( ']' );
|
|
break;
|
|
default:
|
|
Result = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
cur = nextChar();
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
// =============================================================
|
|
// MorkParser::parseGroup
|
|
|
|
bool MorkParser::parseGroup()
|
|
{
|
|
return parseMeta( '@' );
|
|
}
|
|
|
|
// =============================================================
|
|
// MorkParser::parseMeta
|
|
|
|
bool MorkParser::parseMeta( char c )
|
|
{
|
|
char cur = nextChar();
|
|
|
|
while ( cur != c && cur )
|
|
{
|
|
cur = nextChar();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// =============================================================
|
|
// MorkParser::getTables
|
|
|
|
MorkTableMap *MorkParser::getTables( int TableScope )
|
|
{
|
|
TableScopeMap::iterator iter;
|
|
iter = mMork.find( TableScope );
|
|
|
|
if ( iter == mMork.end() )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return &iter.value();
|
|
}
|
|
|
|
// =============================================================
|
|
// MorkParser::getRows
|
|
|
|
MorkRowMap *MorkParser::getRows( int RowScope, RowScopeMap *table )
|
|
{
|
|
RowScopeMap::iterator iter;
|
|
iter = table->find( RowScope );
|
|
|
|
if ( iter == table->end() )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return &iter.value();
|
|
}
|
|
|
|
// =============================================================
|
|
// MorkParser::getValue
|
|
|
|
QString MorkParser::getValue( int oid )
|
|
{
|
|
MorkDict::ConstIterator foundIter = mValues.constFind( oid );
|
|
|
|
if ( foundIter == mValues.constEnd() )
|
|
{
|
|
return QString();
|
|
}
|
|
|
|
return *foundIter;
|
|
}
|
|
|
|
// =============================================================
|
|
// MorkParser::getColumn
|
|
|
|
QString MorkParser::getColumn( int oid )
|
|
{
|
|
MorkDict::ConstIterator foundIter = mColumns.constFind( oid );
|
|
|
|
if ( foundIter == mColumns.constEnd() )
|
|
{
|
|
return QString();
|
|
}
|
|
|
|
return *foundIter;
|
|
}
|
|
|
|
|