summaryrefslogtreecommitdiffstats
path: root/connectivity/source/drivers/mork/MorkParser.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'connectivity/source/drivers/mork/MorkParser.cxx')
-rw-r--r--connectivity/source/drivers/mork/MorkParser.cxx757
1 files changed, 757 insertions, 0 deletions
diff --git a/connectivity/source/drivers/mork/MorkParser.cxx b/connectivity/source/drivers/mork/MorkParser.cxx
new file mode 100644
index 000000000..188f8e6fb
--- /dev/null
+++ b/connectivity/source/drivers/mork/MorkParser.cxx
@@ -0,0 +1,757 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * Software License Agreement (BSD License)
+ *
+ * Copyright (c) 2006, ScalingWeb.com
+ * All rights reserved.
+ *
+ * Redistribution and use of this software in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * * Neither the name of ScalingWeb.com nor the names of its
+ * contributors may be used to endorse or promote products
+ * derived from this software without specific prior
+ * written permission of ScalingWeb.com.
+
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "MorkParser.hxx"
+#include <boost/io/ios_state.hpp>
+#include <stdlib.h>
+#include <string>
+#include <string.h>
+#include <fstream>
+#include <iostream>
+
+std::string const g_Empty = "";
+
+const char * const MorkDictColumnMeta = "<(a=c)>";
+
+static const int defaultScope_ = 0x80;
+
+MorkParser::MorkParser() :
+ columns_(),
+ values_(),
+ mork_(),
+ currentCells_(nullptr),
+ error_(NoError),
+ morkData_(),
+ morkPos_(0),
+ nextAddValueId_(0x7fffffff),
+ defaultTableId_(1),
+ nowParsing_(NP::Values)
+{
+}
+
+bool MorkParser::open( const std::string &path )
+{
+ initVars();
+ std::string line;
+ std::ifstream infile(path.c_str(), std::ios_base::in);
+ if(!infile.is_open())
+ {
+ error_ = FailedToOpen;
+ return false;
+ }
+
+ while (getline(infile, line, '\n'))
+ {
+ morkData_.append(line);
+ morkData_.append("\n");
+ }
+
+ // Parse mork
+ return parse();
+}
+
+void MorkParser::initVars()
+{
+ error_ = NoError;
+ morkPos_ = 0;
+ nowParsing_ = NP::Values;
+ currentCells_ = nullptr;
+ nextAddValueId_ = 0x7fffffff;
+}
+
+bool MorkParser::parse()
+{
+ bool Result = true;
+
+ // Run over mork chars and parse each term
+ char cur = nextChar();
+
+ while ( Result && cur )
+ {
+ if ( !isWhiteSpace( cur ) )
+ {
+ // 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 '@':
+ parseGroup();
+ // Group
+ break;
+ default:
+ error_ = DefectedFormat;
+ Result = false;
+ break;
+ }
+ }
+
+ // Get next char
+ cur = nextChar();
+ }
+
+ return Result;
+}
+
+bool MorkParser::isWhiteSpace( char c )
+{
+ switch ( c )
+ {
+ case ' ':
+ case '\t':
+ case '\r':
+ case '\n':
+ case '\f':
+ return true;
+ default:
+ return false;
+ }
+}
+
+inline char MorkParser::nextChar()
+{
+ char cur = 0;
+
+
+ if ( morkPos_ < morkData_.length() )
+ {
+ cur = morkData_[ morkPos_ ];
+ morkPos_++;
+ }
+
+ if ( !cur )
+ {
+ cur = 0;
+ }
+
+ return cur;
+}
+
+bool MorkParser::parseDict()
+{
+ char cur = nextChar();
+ bool Result = true;
+ nowParsing_ = NP::Values;
+
+ while ( Result && cur != '>' && cur )
+ {
+ if ( !isWhiteSpace( cur ) )
+ {
+ switch ( cur )
+ {
+ case '<':
+ {
+
+ if ( morkData_.substr( morkPos_ - 1, strlen( MorkDictColumnMeta ) ) == MorkDictColumnMeta )
+ {
+ nowParsing_ = NP::Columns;
+ morkPos_ += strlen( MorkDictColumnMeta ) - 1;
+ }
+
+
+ break;
+ }
+ case '(':
+ Result = parseCell();
+ break;
+ case '/':
+ Result = parseComment();
+ break;
+
+ }
+ }
+
+ cur = nextChar();
+ }
+
+ return Result;
+}
+
+inline bool MorkParser::parseComment()
+{
+ char cur = nextChar();
+ if ( '/' != cur ) return false;
+
+ while ( cur != '\r' && cur != '\n' && cur )
+ {
+ cur = nextChar();
+ }
+
+ return true;
+}
+
+bool MorkParser::parseCell()
+{
+ bool Result = true;
+ bool bValueOid = false;
+ bool bColumn = true;
+ int Corners = 0;
+
+ // Column = Value
+ std::string Column;
+ std::string Text;
+ Column.reserve( 4 );
+ Text.reserve( 32 );
+
+ char cur = nextChar();
+
+ // Process cell start with column (bColumn == true)
+ while ( Result && cur != ')' && cur )
+ {
+ switch ( cur )
+ {
+ case '^':
+ // Oids
+ Corners++;
+ if ( 1 == Corners )
+ {
+ }
+ else if ( 2 == Corners )
+ {
+ 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
+ {
+ (void)nextChar();
+ }
+ }
+ break;
+ case '$':
+ {
+ // Get next two chars
+ std::string HexChar;
+ HexChar += nextChar();
+ HexChar += nextChar();
+ Text += static_cast<char>(strtoul(HexChar.c_str(), nullptr, 16));
+ }
+ break;
+ default:
+ // Just a char
+ if ( bColumn )
+ {
+ Column += cur;
+ }
+ else
+ {
+ Text += cur;
+ }
+ break;
+ }
+
+ cur = nextChar();
+ }
+
+ // Apply column and text
+ int ColumnId = strtoul(Column.c_str(), nullptr, 16);
+
+ if ( NP::Rows != nowParsing_ )
+ {
+ // Dicts
+ if ( !Text.empty() )
+ {
+ if ( nowParsing_ == NP::Columns )
+ {
+ columns_[ ColumnId ] = Text;
+ }
+ else
+ {
+ values_[ ColumnId ] = Text;
+ }
+ }
+ }
+ else
+ {
+ if ( !Text.empty() )
+ {
+ // Rows
+ //int ValueId = string( Text.c_str() ).toInt( 0, 16 );
+ int ValueId = strtoul(Text.c_str(), nullptr, 16);
+
+ if ( bValueOid )
+ {
+ ( *currentCells_ )[ ColumnId ] = ValueId;
+ }
+ else
+ {
+ nextAddValueId_--;
+ values_[ nextAddValueId_ ] = Text;
+ ( *currentCells_ )[ ColumnId ] = nextAddValueId_;
+ }
+ }
+ }
+
+ return Result;
+}
+
+bool MorkParser::parseTable()
+{
+ bool Result = true;
+ std::string 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 '{':
+ parseMeta( '}' );
+ break;
+ case '[':
+ Result = parseRow( Id, Scope );
+ break;
+ case '-':
+ case '+':
+ break;
+ default:
+ {
+ std::string 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;
+}
+
+void MorkParser::parseScopeId( const std::string &TextId, int *Id, int *Scope )
+{
+ int Pos = 0;
+
+ if ( ( Pos = TextId.find( ':' ) ) >= 0 )
+ {
+ std::string tId = TextId.substr( 0, Pos );
+ std::string tSc = TextId.substr( Pos + 1, TextId.length() - Pos );
+
+ if ( tSc.length() > 1 && '^' == tSc[ 0 ] )
+ {
+ // Delete '^'
+ tSc.erase( 0, 1 );
+ }
+
+ *Id = strtoul(tId.c_str(), nullptr, 16);
+
+ *Scope = strtoul(tSc.c_str(), nullptr, 16);
+ }
+ else
+ {
+ *Id = strtoul(TextId.c_str(), nullptr, 16);
+ }
+}
+
+inline void MorkParser::setCurrentRow( int TableScope, int TableId, int RowScope, int RowId )
+{
+ if ( !RowScope )
+ {
+ RowScope = defaultScope_;
+ }
+
+ if ( !TableScope )
+ {
+ TableScope = defaultScope_;
+ }
+
+ // 01.08.2012 davido
+ // TableId 0 is wrong here.
+ // Straying rows (rows that defined outside the table) belong to the default scope and table is the last was seen: 1:^80
+ // (at least i read so the specification)
+ if (TableId)
+ {
+ defaultTableId_ = TableId;
+ }
+
+ if (!TableId)
+ {
+ TableId = defaultTableId_;
+ }
+
+ currentCells_ = &( mork_.map[ abs( TableScope ) ].map[ abs( TableId ) ].map[ abs( RowScope ) ].map[ abs( RowId ) ] );
+}
+
+bool MorkParser::parseRow( int TableId, int TableScope )
+{
+ bool Result = true;
+ std::string TextId;
+ int Id = 0, Scope = 0;
+ nowParsing_ = NP::Rows;
+
+ 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 '[':
+ parseMeta( ']' );
+ break;
+ default:
+ Result = false;
+ break;
+ }
+ }
+
+ cur = nextChar();
+ }
+
+ return Result;
+}
+
+void MorkParser::parseGroup()
+{
+ parseMeta( '@' );
+}
+
+void MorkParser::parseMeta( char c )
+{
+ char cur = nextChar();
+
+ while ( cur != c && cur )
+ {
+ cur = nextChar();
+ }
+}
+
+MorkTableMap *MorkParser::getTables( int TableScope )
+{
+ TableScopeMap::Map::iterator iter = mork_.map.find( TableScope );
+
+ if ( iter == mork_.map.end() )
+ {
+ return nullptr;
+ }
+
+ return &iter->second;
+}
+
+MorkRowMap *MorkParser::getRows( int RowScope, RowScopeMap *table )
+{
+ RowScopeMap::Map::iterator iter = table->map.find( RowScope );
+
+ if ( iter == table->map.end() )
+ {
+ return nullptr;
+ }
+
+ return &iter->second;
+}
+
+std::string const &MorkParser::getValue( int oid )
+{
+ MorkDict::iterator foundIter = values_.find( oid );
+
+ if ( values_.end() == foundIter )
+ {
+ return g_Empty;
+ }
+
+ return foundIter->second;
+}
+
+std::string const &MorkParser::getColumn( int oid )
+{
+ MorkDict::iterator foundIter = columns_.find( oid );
+
+ if ( columns_.end() == foundIter )
+ {
+ return g_Empty;
+ }
+
+ return foundIter->second;
+}
+
+void MorkParser::retrieveLists(std::set<std::string>& lists)
+{
+#ifdef VERBOSE
+ boost::io::ios_all_saver ias(std::cout);
+ std::cout << std::hex << std::uppercase;
+#endif
+
+ MorkTableMap* tables = getTables(defaultScope_);
+ if (!tables) return;
+ for (auto& rTable : tables->map)
+ {
+#ifdef VERBOSE
+ std::cout << "\t Table:"
+ << ( ( int ) rTable.first < 0 ? "-" : " " )
+ << rTable.first << std::endl;
+#endif
+ MorkRowMap* rows = getRows( 0x81/*defaultListScope*/, &rTable.second );
+ if (!rows) return;
+ for ( const auto& rRow : rows->map )
+ {
+#ifdef VERBOSE
+ std::cout << "\t\t\t Row Id:"
+ << ( ( int ) rRow.first < 0 ? "-" : " ")
+ << rRow.first << std::endl;
+ std::cout << "\t\t\t\t Cells:\r\n";
+#endif
+ // Get cells
+ MorkCells::const_iterator cellsIter = rRow.second.find(0xC1);
+ if (cellsIter != rRow.second.end())
+ lists.insert(getValue( cellsIter->second ));
+ }
+ }
+}
+
+void MorkParser::getRecordKeysForListTable(std::string const & listName, std::set<int>& records)
+{
+#ifdef VERBOSE
+ boost::io::ios_all_saver ias(std::cout);
+ std::cout << std::hex << std::uppercase;
+#endif
+
+ MorkTableMap* tables = getTables(defaultScope_);
+ if (!tables) return;
+ for (auto& rTable : tables->map)
+ {
+#ifdef VERBOSE
+ std::cout << "\t Table:"
+ << ( ( int ) rTable.first < 0 ? "-" : " " )
+ << rTable.first << std::endl;
+#endif
+ MorkRowMap* rows = getRows( 0x81, &rTable.second );
+ if (!rows) return;
+ for ( const auto& rRow : rows->map )
+ {
+#ifdef VERBOSE
+ std::cout << "\t\t\t Row Id:"
+ << ( ( int ) rRow.first < 0 ? "-" : " ")
+ << rRow.first << std::endl;
+ std::cout << "\t\t\t\t Cells:\r\n";
+#endif
+ // Get cells
+ bool isListFound = false;
+ for ( const auto& [rColumnId, rValueId] : rRow.second )
+ {
+ if (isListFound)
+ {
+ if (rColumnId >= 0xC7)
+ {
+ std::string value = getValue(rValueId);
+ int id = strtoul(value.c_str(), nullptr, 16);
+ records.insert(id);
+ }
+ }
+ else if ((rColumnId == 0xC1) &&
+ listName == getValue( rValueId ))
+ {
+ isListFound = true;
+ }
+ }
+
+ }
+ }
+}
+
+void MorkParser::dump()
+{
+ boost::io::ios_all_saver ias(std::cout);
+ std::cout << std::hex << std::uppercase;
+
+ std::cout << "Column Dict:\r\n";
+ std::cout << "=============================================\r\n\r\n";
+
+ //// columns dict
+ for ( const auto& [rColumnId, rText] : columns_ )
+ {
+ std::cout << rColumnId
+ << " : "
+ << rText
+ << std::endl;
+ }
+
+ //// values dict
+ std::cout << "\r\nValues Dict:\r\n";
+ std::cout << "=============================================\r\n\r\n";
+
+ for ( const auto& [rValueId, rText] : values_ )
+ {
+ if (rValueId >= nextAddValueId_) {
+ continue;
+ }
+
+ std::cout << rValueId
+ << " : "
+ << rText
+ << "\r\n";
+ }
+
+ std::cout << std::endl << "Data:" << std::endl;
+ std::cout << "============================================="
+ << std::endl << std::endl;
+
+ //// Mork data
+ for ( const auto& [rTableScopeId, rTableScope] : mork_.map )
+ {
+ std::cout << "\r\n Scope:" << rTableScopeId << std::endl;
+
+ for ( const auto& [rTableId, rTable] : rTableScope.map )
+ {
+ std::cout << "\t Table:"
+ << ( rTableId < 0 ? "-" : " " )
+ << rTableId << std::endl;
+
+ for (const auto& [rRowScopeId, rRowScope] : rTable.map)
+ {
+ std::cout << "\t\t RowScope:"
+ << rRowScopeId << std::endl;
+
+ for (const auto& [rRowId, rRow] : rRowScope.map)
+ {
+ std::cout << "\t\t\t Row Id:"
+ << (rRowId < 0 ? "-" : " ")
+ << rRowId << std::endl;
+ std::cout << "\t\t\t\t Cells:" << std::endl;
+
+ for (const auto& [rColumnId, rValueId] : rRow)
+ {
+ // Write ids
+ std::cout << "\t\t\t\t\t"
+ << rColumnId
+ << " : "
+ << rValueId
+ << " => ";
+
+ MorkDict::const_iterator FoundIter = values_.find( rValueId );
+ if ( FoundIter != values_.end() )
+ {
+ // Write string values
+ std::cout << columns_[ rColumnId ].c_str()
+ << " : "
+ << FoundIter->second.c_str()
+ << std::endl;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */