Version 4.3.0.0.beta1, tag libreoffice-4.3.0.0.beta1
[LibreOffice.git] / connectivity / source / drivers / mork / MorkParser.cxx
blob8057b0987c49190fb0cd543c0eb95dc143b82a8e
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)>";
54 MorkParser::MorkParser( int DefaultScope ) :
55 columns_(),
56 values_(),
57 mork_(),
58 currentCells_(0),
59 error_(NoError),
60 morkData_(),
61 morkPos_(0),
62 nextAddValueId_(0x7fffffff),
63 defaultScope_(DefaultScope),
64 defaultListScope_(0x81),
65 defaultTableId_(1),
66 nowParsing_(NPValues)
70 bool MorkParser::open( const std::string &path )
72 initVars();
73 std::string line;
74 std::ifstream infile(path.c_str(), std::ios_base::in);
75 if(!infile.is_open())
77 error_ = FailedToOpen;
78 return false;
81 while (getline(infile, line, '\n'))
83 morkData_.append(line);
84 morkData_.append("\n");
87 // Parse mork
88 return parse();
91 inline MorkErrors MorkParser::error()
93 return error_;
96 void MorkParser::initVars()
98 error_ = NoError;
99 morkPos_ = 0;
100 nowParsing_ = NPValues;
101 currentCells_ = 0;
102 nextAddValueId_ = 0x7fffffff;
105 bool MorkParser::parse()
107 bool Result = true;
109 // Run over mork chars and parse each term
110 char cur = nextChar();
112 int i = 0;
114 while ( Result && cur )
116 if ( !isWhiteSpace( cur ) )
118 i++;
119 // Figure out what a term
120 switch ( cur )
122 case '<':
123 // Dict
124 Result = parseDict();
125 break;
126 case '/':
127 // Comment
128 Result = parseComment();
129 break;
130 case '{':
131 Result = parseTable();
132 // Table
133 break;
134 case '[':
135 Result = parseRow( 0, 0 );
136 // Row
137 break;
138 case '@':
139 Result = parseGroup();
140 // Group
141 break;
142 default:
143 error_ = DefectedFormat;
144 Result = false;
145 break;
149 // Get next char
150 cur = nextChar();
153 return Result;
156 bool MorkParser::isWhiteSpace( char c )
158 switch ( c )
160 case ' ':
161 case '\t':
162 case '\r':
163 case '\n':
164 case '\f':
165 return true;
166 default:
167 return false;
171 inline char MorkParser::nextChar()
173 char cur = 0;
176 if ( morkPos_ < morkData_.length() )
178 cur = morkData_[ morkPos_ ];
179 morkPos_++;
182 if ( !cur )
184 cur = 0;
187 return cur;
190 bool MorkParser::parseDict()
192 char cur = nextChar();
193 bool Result = true;
194 nowParsing_ = NPValues;
196 while ( Result && cur != '>' && cur )
198 if ( !isWhiteSpace( cur ) )
200 switch ( cur )
202 case '<':
205 if ( morkData_.substr( morkPos_ - 1, strlen( MorkDictColumnMeta ) ) == MorkDictColumnMeta )
207 nowParsing_ = NPColumns;
208 morkPos_ += strlen( MorkDictColumnMeta ) - 1;
212 break;
214 case '(':
215 Result = parseCell();
216 break;
217 case '/':
218 Result = parseComment();
219 break;
224 cur = nextChar();
227 return Result;
230 inline bool MorkParser::parseComment()
232 char cur = nextChar();
233 if ( '/' != cur ) return false;
235 while ( cur != '\r' && cur != '\n' && cur )
237 cur = nextChar();
240 return true;
243 bool MorkParser::parseCell()
245 bool Result = true;
246 bool bValueOid = false;
247 bool bColumn = true;
248 int Corners = 0;
250 // Column = Value
251 std::string Column;
252 std::string Text;
253 Column.reserve( 4 );
254 Text.reserve( 32 );
256 char cur = nextChar();
258 // Process cell start with column (bColumn == true)
259 while ( Result && cur != ')' && cur )
261 switch ( cur )
263 case '^':
264 // Oids
265 Corners++;
266 if ( 1 == Corners )
269 else if ( 2 == Corners )
271 bColumn = false;
272 bValueOid = true;
274 else
276 Text += cur;
279 break;
280 case '=':
281 // From column to value
282 if ( bColumn )
284 bColumn = false;
286 else
288 Text += cur;
290 break;
291 case '\\':
293 // Get next two chars
294 char NextChar= nextChar();
295 if ( '\r' != NextChar && '\n' != NextChar )
297 Text += NextChar;
299 else nextChar();
301 break;
302 case '$':
304 // Get next two chars
305 std::string HexChar;
306 HexChar += nextChar();
307 HexChar += nextChar();
308 Text += (char)strtoul(HexChar.c_str(), 0, 16);
310 break;
311 default:
312 // Just a char
313 if ( bColumn )
315 Column += cur;
317 else
319 Text += cur;
321 break;
324 cur = nextChar();
327 // Apply column and text
328 int ColumnId = strtoul(Column.c_str(), 0, 16);
330 if ( NPRows != nowParsing_ )
332 // Dicts
333 if ( "" != Text )
335 if ( nowParsing_ == NPColumns )
337 columns_[ ColumnId ] = Text;
339 else
341 values_[ ColumnId ] = Text;
345 else
347 if ( "" != Text )
349 // Rows
350 //int ValueId = string( Text.c_str() ).toInt( 0, 16 );
351 int ValueId = strtoul(Text.c_str(), 0, 16);
353 if ( bValueOid )
355 ( *currentCells_ )[ ColumnId ] = ValueId;
357 else
359 nextAddValueId_--;
360 values_[ nextAddValueId_ ] = Text;
361 ( *currentCells_ )[ ColumnId ] = nextAddValueId_;
366 return Result;
369 bool MorkParser::parseTable()
371 bool Result = true;
372 std::string TextId;
373 int Id = 0, Scope = 0;
375 char cur = nextChar();
377 // Get id
378 while ( cur != '{' && cur != '[' && cur != '}' && cur )
380 if ( !isWhiteSpace( cur ) )
382 TextId += cur;
385 cur = nextChar();
388 parseScopeId( TextId, &Id, &Scope );
390 // Parse the table
391 while ( Result && cur != '}' && cur )
393 if ( !isWhiteSpace( cur ) )
395 switch ( cur )
397 case '{':
398 Result = parseMeta( '}' );
399 break;
400 case '[':
401 Result = parseRow( Id, Scope );
402 break;
403 case '-':
404 case '+':
405 break;
406 default:
408 std::string JustId;
409 while ( !isWhiteSpace( cur ) && cur )
411 JustId += cur;
412 cur = nextChar();
414 if ( cur == '}' )
416 return Result;
420 int JustIdNum = 0, JustScopeNum = 0;
421 parseScopeId( JustId, &JustIdNum, &JustScopeNum );
423 setCurrentRow( Scope, Id, JustScopeNum, JustIdNum );
425 break;
429 cur = nextChar();
432 return Result;
435 void MorkParser::parseScopeId( const std::string &TextId, int *Id, int *Scope )
437 int Pos = 0;
439 if ( ( Pos = TextId.find( ':' ) ) >= 0 )
441 std::string tId = TextId.substr( 0, Pos );
442 std::string tSc = TextId.substr( Pos + 1, TextId.length() - Pos );
444 if ( tSc.length() > 1 && '^' == tSc[ 0 ] )
446 // Delete '^'
447 tSc.erase( 0, 1 );
450 *Id = strtoul(tId.c_str(), 0, 16);
452 *Scope = strtoul(tSc.c_str(), 0, 16);
454 else
456 *Id = strtoul(TextId.c_str(), 0, 16);
460 inline void MorkParser::setCurrentRow( int TableScope, int TableId, int RowScope, int RowId )
462 if ( !RowScope )
464 RowScope = defaultScope_;
467 if ( !TableScope )
469 TableScope = defaultScope_;
472 // 01.08.2012 davido
473 // TableId 0 is wrong here.
474 // Straying rows (rows that defined outside the table) belong to the default scope and table is the last was seen: 1:^80
475 // (at least i read so the specification)
476 if (TableId)
478 defaultTableId_ = TableId;
481 if (!TableId)
483 TableId = defaultTableId_;
486 currentCells_ = &( mork_[ abs( TableScope ) ][ abs( TableId ) ][ abs( RowScope ) ][ abs( RowId ) ] );
489 bool MorkParser::parseRow( int TableId, int TableScope )
491 bool Result = true;
492 std::string TextId;
493 int Id = 0, Scope = 0;
494 nowParsing_ = NPRows;
496 char cur = nextChar();
498 // Get id
499 while ( cur != '(' && cur != ']' && cur != '[' && cur )
501 if ( !isWhiteSpace( cur ) )
503 TextId += cur;
506 cur = nextChar();
509 parseScopeId( TextId, &Id, &Scope );
510 setCurrentRow( TableScope, TableId, Scope, Id );
512 // Parse the row
513 while ( Result && cur != ']' && cur )
515 if ( !isWhiteSpace( cur ) )
517 switch ( cur )
519 case '(':
520 Result = parseCell();
521 break;
522 case '[':
523 Result = parseMeta( ']' );
524 break;
525 default:
526 Result = false;
527 break;
531 cur = nextChar();
534 return Result;
537 bool MorkParser::parseGroup()
539 return parseMeta( '@' );
542 bool MorkParser::parseMeta( char c )
544 char cur = nextChar();
546 while ( cur != c && cur )
548 cur = nextChar();
551 return true;
554 MorkTableMap *MorkParser::getTables( int TableScope )
556 TableScopeMap::iterator iter;
557 iter = mork_.find( TableScope );
559 if ( iter == mork_.end() )
561 return 0;
564 return &iter->second;
567 MorkRowMap *MorkParser::getRows( int RowScope, RowScopeMap *table )
569 RowScopeMap::iterator iter;
570 iter = table->find( RowScope );
572 if ( iter == table->end() )
574 return 0;
577 return &iter->second;
580 std::string &MorkParser::getValue( int oid )
582 MorkDict::iterator foundIter = values_.find( oid );
584 if ( values_.end() == foundIter )
586 return g_Empty;
589 return foundIter->second;
592 std::string &MorkParser::getColumn( int oid )
594 MorkDict::iterator foundIter = columns_.find( oid );
596 if ( columns_.end() == foundIter )
598 return g_Empty;
601 return foundIter->second;
604 void MorkParser::retrieveLists(std::set<std::string>& lists)
606 #ifdef VERBOSE
607 boost::io::ios_all_saver ias(std::cout);
608 std::cout << std::hex << std::uppercase;
609 #endif
611 MorkTableMap* tables = getTables(defaultScope_);
612 if (!tables) return;
613 for (MorkTableMap::iterator TableIter = tables->begin();
614 TableIter != tables->end(); ++TableIter )
616 #ifdef VERBOSE
617 std::cout << "\t Table:"
618 << ( ( int ) TableIter->first < 0 ? "-" : " " )
619 << TableIter->first << std::endl;
620 #endif
621 MorkRowMap* rows = getRows( defaultListScope_, &TableIter->second );
622 if (!rows) return;
623 for ( MorkRowMap::iterator RowIter = rows->begin();
624 RowIter != rows->end(); ++RowIter )
626 #ifdef VERBOSE
627 std::cout << "\t\t\t Row Id:"
628 << ( ( int ) RowIter->first < 0 ? "-" : " ")
629 << RowIter->first << std::endl;
630 std::cout << "\t\t\t\t Cells:\r\n";
631 #endif
632 // Get cells
633 for ( MorkCells::iterator cellsIter = RowIter->second.begin();
634 cellsIter != RowIter->second.end(); ++cellsIter )
636 if (cellsIter->first == 0xC1)
638 lists.insert(getValue( cellsIter->second ));
639 break;
646 void MorkParser::getRecordKeysForListTable(std::string& listName, std::set<int>& records)
648 #ifdef VERBOSE
649 boost::io::ios_all_saver ias(std::cout);
650 std::cout << std::hex << std::uppercase;
651 #endif
653 MorkTableMap* tables = getTables(defaultScope_);
654 if (!tables) return;
655 for (MorkTableMap::iterator TableIter = tables->begin();
656 TableIter != tables->end(); ++TableIter )
658 #ifdef VERBOSE
659 std::cout << "\t Table:"
660 << ( ( int ) TableIter->first < 0 ? "-" : " " )
661 << TableIter->first << std::endl;
662 #endif
663 MorkRowMap* rows = getRows( 0x81, &TableIter->second );
664 if (!rows) return;
665 for ( MorkRowMap::iterator RowIter = rows->begin();
666 RowIter != rows->end(); ++RowIter )
668 #ifdef VERBOSE
669 std::cout << "\t\t\t Row Id:"
670 << ( ( int ) RowIter->first < 0 ? "-" : " ")
671 << RowIter->first << std::endl;
672 std::cout << "\t\t\t\t Cells:\r\n";
673 #endif
674 // Get cells
675 bool listFound = false;
676 for ( MorkCells::iterator cellsIter = RowIter->second.begin();
677 cellsIter != RowIter->second.end(); ++cellsIter )
679 if (listFound)
681 if (cellsIter->first >= 0xC7)
683 std::string value = getValue(cellsIter->second);
684 int id = strtoul(value.c_str(), 0, 16);
685 records.insert(id);
688 else if ((cellsIter->first == 0xC1) &&
689 listName == getValue( cellsIter->second ))
691 listFound = true;
699 void MorkParser::dump()
701 boost::io::ios_all_saver ias(std::cout);
702 std::cout << std::hex << std::uppercase;
704 std::cout << "Column Dict:\r\n";
705 std::cout << "=============================================\r\n\r\n";
707 //// columns dict
708 for ( MorkDict::iterator iter = columns_.begin();
709 iter != columns_.end(); ++iter )
711 std::cout << iter->first
712 << " : "
713 << iter->second
714 << std::endl;
717 //// values dict
718 std::cout << "\r\nValues Dict:\r\n";
719 std::cout << "=============================================\r\n\r\n";
721 for ( MorkDict::iterator iter = values_.begin();
722 iter != values_.end(); ++iter )
724 if (iter->first >= nextAddValueId_) {
725 continue;
728 std::cout << iter->first
729 << " : "
730 << iter->second
731 << "\r\n";
734 std::cout << std::endl << "Data:" << std::endl;
735 std::cout << "============================================="
736 << std::endl << std::endl;
738 //// Mork data
739 for ( TableScopeMap::iterator iter = mork_.begin();
740 iter != mork_.end(); ++iter )
742 std::cout << "\r\n Scope:" << iter->first << std::endl;
744 for ( MorkTableMap::iterator TableIter = iter->second.begin();
745 TableIter != iter->second.end(); ++TableIter )
747 std::cout << "\t Table:"
748 << ( ( int ) TableIter->first < 0 ? "-" : " " )
749 << TableIter->first << std::endl;
751 for (RowScopeMap::iterator RowScopeIter = TableIter->second.begin();
752 RowScopeIter != TableIter->second.end(); ++RowScopeIter )
754 std::cout << "\t\t RowScope:"
755 << RowScopeIter->first << std::endl;
757 for (MorkRowMap::iterator RowIter = RowScopeIter->second.begin();
758 RowIter != RowScopeIter->second.end(); ++RowIter )
760 std::cout << "\t\t\t Row Id:"
761 << ((int) RowIter->first < 0 ? "-" : " ")
762 << RowIter->first << std::endl;
763 std::cout << "\t\t\t\t Cells:" << std::endl;
765 for (MorkCells::iterator CellsIter = RowIter->second.begin();
766 CellsIter != RowIter->second.end(); ++CellsIter )
768 // Write ids
769 std::cout << "\t\t\t\t\t"
770 << CellsIter->first
771 << " : "
772 << CellsIter->second
773 << " => ";
775 MorkDict::iterator FoundIter = values_.find( CellsIter->second );
776 if ( FoundIter != values_.end() )
778 // Write string values
779 std::cout << columns_[ CellsIter->first ].c_str()
780 << " : "
781 << FoundIter->second.c_str()
782 << std::endl;
791 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */