build fix
[LibreOffice.git] / connectivity / source / drivers / mork / MorkParser.cxx
blob9a4b89526c0076e9b87fe54539d7dbc32b85f384
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * Software License Agreement (BSD License)
5 * Copyright (c) 2006, ScalingWeb.com
6 * All rights reserved.
8 * Redistribution and use of this software in source and binary forms, with or without modification, are
9 * permitted provided that the following conditions are met:
11 * * Redistributions of source code must retain the above
12 * copyright notice, this list of conditions and the
13 * following disclaimer.
15 * * Redistributions in binary form must reproduce the above
16 * copyright notice, this list of conditions and the
17 * following disclaimer in the documentation and/or other
18 * materials provided with the distribution.
20 * * Neither the name of ScalingWeb.com nor the names of its
21 * contributors may be used to endorse or promote products
22 * derived from this software without specific prior
23 * written permission of ScalingWeb.com.
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
26 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
27 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
28 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
31 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 #include "MorkParser.hxx"
36 #include <boost/io/ios_state.hpp>
37 #include <stdlib.h>
38 #include <sstream>
39 #include <string>
40 #include <string.h>
41 #include <stdexcept>
42 #include <fstream>
43 #include <iostream>
44 #include <algorithm>
46 std::string g_Empty = "";
48 // Mork header of supported format version
49 const char *MorkMagicHeader = "// <!-- <mdb:mork:z v=\"1.4\"/> -->";
51 const char *MorkDictColumnMeta = "<(a=c)>";
53 static const int defaultScope_ = 0x80;
55 MorkParser::MorkParser() :
56 columns_(),
57 values_(),
58 mork_(),
59 currentCells_(nullptr),
60 error_(NoError),
61 morkData_(),
62 morkPos_(0),
63 nextAddValueId_(0x7fffffff),
64 defaultTableId_(1),
65 nowParsing_(NPValues)
69 bool MorkParser::open( const std::string &path )
71 initVars();
72 std::string line;
73 std::ifstream infile(path.c_str(), std::ios_base::in);
74 if(!infile.is_open())
76 error_ = FailedToOpen;
77 return false;
80 while (getline(infile, line, '\n'))
82 morkData_.append(line);
83 morkData_.append("\n");
86 // Parse mork
87 return parse();
90 void MorkParser::initVars()
92 error_ = NoError;
93 morkPos_ = 0;
94 nowParsing_ = NPValues;
95 currentCells_ = nullptr;
96 nextAddValueId_ = 0x7fffffff;
99 bool MorkParser::parse()
101 bool Result = true;
103 // Run over mork chars and parse each term
104 char cur = nextChar();
106 int i = 0;
108 while ( Result && cur )
110 if ( !isWhiteSpace( cur ) )
112 i++;
113 // Figure out what a term
114 switch ( cur )
116 case '<':
117 // Dict
118 Result = parseDict();
119 break;
120 case '/':
121 // Comment
122 Result = parseComment();
123 break;
124 case '{':
125 Result = parseTable();
126 // Table
127 break;
128 case '[':
129 Result = parseRow( 0, 0 );
130 // Row
131 break;
132 case '@':
133 Result = parseGroup();
134 // Group
135 break;
136 default:
137 error_ = DefectedFormat;
138 Result = false;
139 break;
143 // Get next char
144 cur = nextChar();
147 return Result;
150 bool MorkParser::isWhiteSpace( char c )
152 switch ( c )
154 case ' ':
155 case '\t':
156 case '\r':
157 case '\n':
158 case '\f':
159 return true;
160 default:
161 return false;
165 inline char MorkParser::nextChar()
167 char cur = 0;
170 if ( morkPos_ < morkData_.length() )
172 cur = morkData_[ morkPos_ ];
173 morkPos_++;
176 if ( !cur )
178 cur = 0;
181 return cur;
184 bool MorkParser::parseDict()
186 char cur = nextChar();
187 bool Result = true;
188 nowParsing_ = NPValues;
190 while ( Result && cur != '>' && cur )
192 if ( !isWhiteSpace( cur ) )
194 switch ( cur )
196 case '<':
199 if ( morkData_.substr( morkPos_ - 1, strlen( MorkDictColumnMeta ) ) == MorkDictColumnMeta )
201 nowParsing_ = NPColumns;
202 morkPos_ += strlen( MorkDictColumnMeta ) - 1;
206 break;
208 case '(':
209 Result = parseCell();
210 break;
211 case '/':
212 Result = parseComment();
213 break;
218 cur = nextChar();
221 return Result;
224 inline bool MorkParser::parseComment()
226 char cur = nextChar();
227 if ( '/' != cur ) return false;
229 while ( cur != '\r' && cur != '\n' && cur )
231 cur = nextChar();
234 return true;
237 bool MorkParser::parseCell()
239 bool Result = true;
240 bool bValueOid = false;
241 bool bColumn = true;
242 int Corners = 0;
244 // Column = Value
245 std::string Column;
246 std::string Text;
247 Column.reserve( 4 );
248 Text.reserve( 32 );
250 char cur = nextChar();
252 // Process cell start with column (bColumn == true)
253 while ( Result && cur != ')' && cur )
255 switch ( cur )
257 case '^':
258 // Oids
259 Corners++;
260 if ( 1 == Corners )
263 else if ( 2 == Corners )
265 bColumn = false;
266 bValueOid = true;
268 else
270 Text += cur;
273 break;
274 case '=':
275 // From column to value
276 if ( bColumn )
278 bColumn = false;
280 else
282 Text += cur;
284 break;
285 case '\\':
287 // Get next two chars
288 char NextChar= nextChar();
289 if ( '\r' != NextChar && '\n' != NextChar )
291 Text += NextChar;
293 else
295 (void)nextChar();
298 break;
299 case '$':
301 // Get next two chars
302 std::string HexChar;
303 HexChar += nextChar();
304 HexChar += nextChar();
305 Text += (char)strtoul(HexChar.c_str(), nullptr, 16);
307 break;
308 default:
309 // Just a char
310 if ( bColumn )
312 Column += cur;
314 else
316 Text += cur;
318 break;
321 cur = nextChar();
324 // Apply column and text
325 int ColumnId = strtoul(Column.c_str(), nullptr, 16);
327 if ( NPRows != nowParsing_ )
329 // Dicts
330 if ( "" != Text )
332 if ( nowParsing_ == NPColumns )
334 columns_[ ColumnId ] = Text;
336 else
338 values_[ ColumnId ] = Text;
342 else
344 if ( "" != Text )
346 // Rows
347 //int ValueId = string( Text.c_str() ).toInt( 0, 16 );
348 int ValueId = strtoul(Text.c_str(), nullptr, 16);
350 if ( bValueOid )
352 ( *currentCells_ )[ ColumnId ] = ValueId;
354 else
356 nextAddValueId_--;
357 values_[ nextAddValueId_ ] = Text;
358 ( *currentCells_ )[ ColumnId ] = nextAddValueId_;
363 return Result;
366 bool MorkParser::parseTable()
368 bool Result = true;
369 std::string TextId;
370 int Id = 0, Scope = 0;
372 char cur = nextChar();
374 // Get id
375 while ( cur != '{' && cur != '[' && cur != '}' && cur )
377 if ( !isWhiteSpace( cur ) )
379 TextId += cur;
382 cur = nextChar();
385 parseScopeId( TextId, &Id, &Scope );
387 // Parse the table
388 while ( Result && cur != '}' && cur )
390 if ( !isWhiteSpace( cur ) )
392 switch ( cur )
394 case '{':
395 Result = parseMeta( '}' );
396 break;
397 case '[':
398 Result = parseRow( Id, Scope );
399 break;
400 case '-':
401 case '+':
402 break;
403 default:
405 std::string JustId;
406 while ( !isWhiteSpace( cur ) && cur )
408 JustId += cur;
409 cur = nextChar();
411 if ( cur == '}' )
413 return Result;
417 int JustIdNum = 0, JustScopeNum = 0;
418 parseScopeId( JustId, &JustIdNum, &JustScopeNum );
420 setCurrentRow( Scope, Id, JustScopeNum, JustIdNum );
422 break;
426 cur = nextChar();
429 return Result;
432 void MorkParser::parseScopeId( const std::string &TextId, int *Id, int *Scope )
434 int Pos = 0;
436 if ( ( Pos = TextId.find( ':' ) ) >= 0 )
438 std::string tId = TextId.substr( 0, Pos );
439 std::string tSc = TextId.substr( Pos + 1, TextId.length() - Pos );
441 if ( tSc.length() > 1 && '^' == tSc[ 0 ] )
443 // Delete '^'
444 tSc.erase( 0, 1 );
447 *Id = strtoul(tId.c_str(), nullptr, 16);
449 *Scope = strtoul(tSc.c_str(), nullptr, 16);
451 else
453 *Id = strtoul(TextId.c_str(), nullptr, 16);
457 inline void MorkParser::setCurrentRow( int TableScope, int TableId, int RowScope, int RowId )
459 if ( !RowScope )
461 RowScope = defaultScope_;
464 if ( !TableScope )
466 TableScope = defaultScope_;
469 // 01.08.2012 davido
470 // TableId 0 is wrong here.
471 // Straying rows (rows that defined outside the table) belong to the default scope and table is the last was seen: 1:^80
472 // (at least i read so the specification)
473 if (TableId)
475 defaultTableId_ = TableId;
478 if (!TableId)
480 TableId = defaultTableId_;
483 currentCells_ = &( mork_.map[ abs( TableScope ) ].map[ abs( TableId ) ].map[ abs( RowScope ) ].map[ abs( RowId ) ] );
486 bool MorkParser::parseRow( int TableId, int TableScope )
488 bool Result = true;
489 std::string TextId;
490 int Id = 0, Scope = 0;
491 nowParsing_ = NPRows;
493 char cur = nextChar();
495 // Get id
496 while ( cur != '(' && cur != ']' && cur != '[' && cur )
498 if ( !isWhiteSpace( cur ) )
500 TextId += cur;
503 cur = nextChar();
506 parseScopeId( TextId, &Id, &Scope );
507 setCurrentRow( TableScope, TableId, Scope, Id );
509 // Parse the row
510 while ( Result && cur != ']' && cur )
512 if ( !isWhiteSpace( cur ) )
514 switch ( cur )
516 case '(':
517 Result = parseCell();
518 break;
519 case '[':
520 Result = parseMeta( ']' );
521 break;
522 default:
523 Result = false;
524 break;
528 cur = nextChar();
531 return Result;
534 bool MorkParser::parseGroup()
536 return parseMeta( '@' );
539 bool MorkParser::parseMeta( char c )
541 char cur = nextChar();
543 while ( cur != c && cur )
545 cur = nextChar();
548 return true;
551 MorkTableMap *MorkParser::getTables( int TableScope )
553 TableScopeMap::Map::iterator iter;
554 iter = mork_.map.find( TableScope );
556 if ( iter == mork_.map.end() )
558 return nullptr;
561 return &iter->second;
564 MorkRowMap *MorkParser::getRows( int RowScope, RowScopeMap *table )
566 RowScopeMap::Map::iterator iter;
567 iter = table->map.find( RowScope );
569 if ( iter == table->map.end() )
571 return nullptr;
574 return &iter->second;
577 std::string &MorkParser::getValue( int oid )
579 MorkDict::iterator foundIter = values_.find( oid );
581 if ( values_.end() == foundIter )
583 return g_Empty;
586 return foundIter->second;
589 std::string &MorkParser::getColumn( int oid )
591 MorkDict::iterator foundIter = columns_.find( oid );
593 if ( columns_.end() == foundIter )
595 return g_Empty;
598 return foundIter->second;
601 void MorkParser::retrieveLists(std::set<std::string>& lists)
603 #ifdef VERBOSE
604 boost::io::ios_all_saver ias(std::cout);
605 std::cout << std::hex << std::uppercase;
606 #endif
608 MorkTableMap* tables = getTables(defaultScope_);
609 if (!tables) return;
610 for (MorkTableMap::Map::iterator TableIter = tables->map.begin();
611 TableIter != tables->map.end(); ++TableIter )
613 #ifdef VERBOSE
614 std::cout << "\t Table:"
615 << ( ( int ) TableIter->first < 0 ? "-" : " " )
616 << TableIter->first << std::endl;
617 #endif
618 MorkRowMap* rows = getRows( 0x81/*defaultListScope*/, &TableIter->second );
619 if (!rows) return;
620 for ( MorkRowMap::Map::const_iterator RowIter = rows->map.begin();
621 RowIter != rows->map.end(); ++RowIter )
623 #ifdef VERBOSE
624 std::cout << "\t\t\t Row Id:"
625 << ( ( int ) RowIter->first < 0 ? "-" : " ")
626 << RowIter->first << std::endl;
627 std::cout << "\t\t\t\t Cells:\r\n";
628 #endif
629 // Get cells
630 for ( MorkCells::const_iterator cellsIter = RowIter->second.begin();
631 cellsIter != RowIter->second.end(); ++cellsIter )
633 if (cellsIter->first == 0xC1)
635 lists.insert(getValue( cellsIter->second ));
636 break;
643 void MorkParser::getRecordKeysForListTable(std::string& listName, std::set<int>& records)
645 #ifdef VERBOSE
646 boost::io::ios_all_saver ias(std::cout);
647 std::cout << std::hex << std::uppercase;
648 #endif
650 MorkTableMap* tables = getTables(defaultScope_);
651 if (!tables) return;
652 for (MorkTableMap::Map::iterator TableIter = tables->map.begin();
653 TableIter != tables->map.end(); ++TableIter )
655 #ifdef VERBOSE
656 std::cout << "\t Table:"
657 << ( ( int ) TableIter->first < 0 ? "-" : " " )
658 << TableIter->first << std::endl;
659 #endif
660 MorkRowMap* rows = getRows( 0x81, &TableIter->second );
661 if (!rows) return;
662 for ( MorkRowMap::Map::const_iterator RowIter = rows->map.begin();
663 RowIter != rows->map.end(); ++RowIter )
665 #ifdef VERBOSE
666 std::cout << "\t\t\t Row Id:"
667 << ( ( int ) RowIter->first < 0 ? "-" : " ")
668 << RowIter->first << std::endl;
669 std::cout << "\t\t\t\t Cells:\r\n";
670 #endif
671 // Get cells
672 bool isListFound = false;
673 for ( MorkCells::const_iterator cellsIter = RowIter->second.begin();
674 cellsIter != RowIter->second.end(); ++cellsIter )
676 if (isListFound)
678 if (cellsIter->first >= 0xC7)
680 std::string value = getValue(cellsIter->second);
681 int id = strtoul(value.c_str(), nullptr, 16);
682 records.insert(id);
685 else if ((cellsIter->first == 0xC1) &&
686 listName == getValue( cellsIter->second ))
688 isListFound = true;
696 void MorkParser::dump()
698 boost::io::ios_all_saver ias(std::cout);
699 std::cout << std::hex << std::uppercase;
701 std::cout << "Column Dict:\r\n";
702 std::cout << "=============================================\r\n\r\n";
704 //// columns dict
705 for ( MorkDict::const_iterator iter = columns_.begin();
706 iter != columns_.end(); ++iter )
708 std::cout << iter->first
709 << " : "
710 << iter->second
711 << std::endl;
714 //// values dict
715 std::cout << "\r\nValues Dict:\r\n";
716 std::cout << "=============================================\r\n\r\n";
718 for ( MorkDict::const_iterator iter = values_.begin();
719 iter != values_.end(); ++iter )
721 if (iter->first >= nextAddValueId_) {
722 continue;
725 std::cout << iter->first
726 << " : "
727 << iter->second
728 << "\r\n";
731 std::cout << std::endl << "Data:" << std::endl;
732 std::cout << "============================================="
733 << std::endl << std::endl;
735 //// Mork data
736 for ( TableScopeMap::Map::const_iterator iter = mork_.map.begin();
737 iter != mork_.map.end(); ++iter )
739 std::cout << "\r\n Scope:" << iter->first << std::endl;
741 for ( MorkTableMap::Map::const_iterator TableIter = iter->second.map.begin();
742 TableIter != iter->second.map.end(); ++TableIter )
744 std::cout << "\t Table:"
745 << ( ( int ) TableIter->first < 0 ? "-" : " " )
746 << TableIter->first << std::endl;
748 for (RowScopeMap::Map::const_iterator RowScopeIter = TableIter->second.map.begin();
749 RowScopeIter != TableIter->second.map.end(); ++RowScopeIter )
751 std::cout << "\t\t RowScope:"
752 << RowScopeIter->first << std::endl;
754 for (MorkRowMap::Map::const_iterator RowIter = RowScopeIter->second.map.begin();
755 RowIter != RowScopeIter->second.map.end(); ++RowIter )
757 std::cout << "\t\t\t Row Id:"
758 << ((int) RowIter->first < 0 ? "-" : " ")
759 << RowIter->first << std::endl;
760 std::cout << "\t\t\t\t Cells:" << std::endl;
762 for (MorkCells::const_iterator CellsIter = RowIter->second.begin();
763 CellsIter != RowIter->second.end(); ++CellsIter )
765 // Write ids
766 std::cout << "\t\t\t\t\t"
767 << CellsIter->first
768 << " : "
769 << CellsIter->second
770 << " => ";
772 MorkDict::const_iterator FoundIter = values_.find( CellsIter->second );
773 if ( FoundIter != values_.end() )
775 // Write string values
776 std::cout << columns_[ CellsIter->first ].c_str()
777 << " : "
778 << FoundIter->second.c_str()
779 << std::endl;
788 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */