Line data Source code
1 : /*
2 : * Software License Agreement (BSD License)
3 : *
4 : * Copyright (c) 2006, ScalingWeb.com
5 : * All rights reserved.
6 : *
7 : * Redistribution and use of this software in source and binary forms, with or without modification, are
8 : * permitted provided that the following conditions are met:
9 : *
10 : * * Redistributions of source code must retain the above
11 : * copyright notice, this list of conditions and the
12 : * following disclaimer.
13 : *
14 : * * Redistributions in binary form must reproduce the above
15 : * copyright notice, this list of conditions and the
16 : * following disclaimer in the documentation and/or other
17 : * materials provided with the distribution.
18 : *
19 : * * Neither the name of ScalingWeb.com nor the names of its
20 : * contributors may be used to endorse or promote products
21 : * derived from this software without specific prior
22 : * written permission of ScalingWeb.com.
23 :
24 : * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
25 : * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
26 : * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
27 : * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28 : * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 : * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
30 : * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31 : * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 : */
33 :
34 : #include "MorkParser.hxx"
35 : #include <boost/io/ios_state.hpp>
36 : #include <stdlib.h>
37 : #include <sstream>
38 : #include <string>
39 : #include <string.h>
40 : #include <stdexcept>
41 : #include <fstream>
42 : #include <iostream>
43 : #include <algorithm>
44 :
45 0 : std::string g_Empty = "";
46 :
47 : // Mork header of supported format version
48 : const char *MorkMagicHeader = "// <!-- <mdb:mork:z v=\"1.4\"/> -->";
49 :
50 : const char *MorkDictColumnMeta = "<(a=c)>";
51 :
52 :
53 0 : MorkParser::MorkParser( int DefaultScope ) :
54 : columns_(),
55 : values_(),
56 : mork_(),
57 : currentCells_(0),
58 : error_(NoError),
59 : morkData_(),
60 : morkPos_(0),
61 : nextAddValueId_(0x7fffffff),
62 : defaultScope_(DefaultScope),
63 : defaultListScope_(0x81),
64 : defaultTableId_(1),
65 0 : nowParsing_(NPValues)
66 : {
67 0 : }
68 :
69 0 : bool MorkParser::open( const std::string &path )
70 : {
71 0 : initVars();
72 0 : std::string line;
73 0 : std::ifstream infile(path.c_str(), std::ios_base::in);
74 0 : if(!infile.is_open())
75 : {
76 0 : error_ = FailedToOpen;
77 0 : return false;
78 : }
79 :
80 0 : while (getline(infile, line, '\n'))
81 : {
82 0 : morkData_.append(line);
83 0 : morkData_.append("\n");
84 : }
85 :
86 : // Parse mork
87 0 : return parse();
88 : }
89 :
90 : inline MorkErrors MorkParser::error()
91 : {
92 : return error_;
93 : }
94 :
95 0 : void MorkParser::initVars()
96 : {
97 0 : error_ = NoError;
98 0 : morkPos_ = 0;
99 0 : nowParsing_ = NPValues;
100 0 : currentCells_ = 0;
101 0 : nextAddValueId_ = 0x7fffffff;
102 0 : }
103 :
104 0 : bool MorkParser::parse()
105 : {
106 0 : bool Result = true;
107 :
108 : // Run over mork chars and parse each term
109 0 : char cur = nextChar();
110 :
111 0 : int i = 0;
112 :
113 0 : while ( Result && cur )
114 : {
115 0 : if ( !isWhiteSpace( cur ) )
116 : {
117 0 : i++;
118 : // Figure out what a term
119 0 : switch ( cur )
120 : {
121 : case '<':
122 : // Dict
123 0 : Result = parseDict();
124 0 : break;
125 : case '/':
126 : // Comment
127 0 : Result = parseComment();
128 0 : break;
129 : case '{':
130 0 : Result = parseTable();
131 : // Table
132 0 : break;
133 : case '[':
134 0 : Result = parseRow( 0, 0 );
135 : // Row
136 0 : break;
137 : case '@':
138 0 : Result = parseGroup();
139 : // Group
140 0 : break;
141 : default:
142 0 : error_ = DefectedFormat;
143 0 : Result = false;
144 0 : break;
145 : }
146 : }
147 :
148 : // Get next char
149 0 : cur = nextChar();
150 : }
151 :
152 0 : return Result;
153 : }
154 :
155 0 : bool MorkParser::isWhiteSpace( char c )
156 : {
157 0 : switch ( c )
158 : {
159 : case ' ':
160 : case '\t':
161 : case '\r':
162 : case '\n':
163 : case '\f':
164 0 : return true;
165 : default:
166 0 : return false;
167 : }
168 : }
169 :
170 0 : inline char MorkParser::nextChar()
171 : {
172 0 : char cur = 0;
173 :
174 :
175 0 : if ( morkPos_ < morkData_.length() )
176 : {
177 0 : cur = morkData_[ morkPos_ ];
178 0 : morkPos_++;
179 : }
180 :
181 0 : if ( !cur )
182 : {
183 0 : cur = 0;
184 : }
185 :
186 0 : return cur;
187 : }
188 :
189 0 : bool MorkParser::parseDict()
190 : {
191 0 : char cur = nextChar();
192 0 : bool Result = true;
193 0 : nowParsing_ = NPValues;
194 :
195 0 : while ( Result && cur != '>' && cur )
196 : {
197 0 : if ( !isWhiteSpace( cur ) )
198 : {
199 0 : switch ( cur )
200 : {
201 : case '<':
202 : {
203 :
204 0 : if ( morkData_.substr( morkPos_ - 1, strlen( MorkDictColumnMeta ) ) == MorkDictColumnMeta )
205 : {
206 0 : nowParsing_ = NPColumns;
207 0 : morkPos_ += strlen( MorkDictColumnMeta ) - 1;
208 : }
209 :
210 :
211 0 : break;
212 : }
213 : case '(':
214 0 : Result = parseCell();
215 0 : break;
216 : case '/':
217 0 : Result = parseComment();
218 0 : break;
219 :
220 : }
221 : }
222 :
223 0 : cur = nextChar();
224 : }
225 :
226 0 : return Result;
227 : }
228 :
229 0 : inline bool MorkParser::parseComment()
230 : {
231 0 : char cur = nextChar();
232 0 : if ( '/' != cur ) return false;
233 :
234 0 : while ( cur != '\r' && cur != '\n' && cur )
235 : {
236 0 : cur = nextChar();
237 : }
238 :
239 0 : return true;
240 : }
241 :
242 0 : bool MorkParser::parseCell()
243 : {
244 0 : bool Result = true;
245 0 : bool bValueOid = false;
246 0 : bool bColumn = true;
247 0 : int Corners = 0;
248 :
249 : // Column = Value
250 0 : std::string Column;
251 0 : std::string Text;
252 0 : Column.reserve( 4 );
253 0 : Text.reserve( 32 );
254 :
255 0 : char cur = nextChar();
256 :
257 : // Process cell start with column (bColumn == true)
258 0 : while ( Result && cur != ')' && cur )
259 : {
260 0 : switch ( cur )
261 : {
262 : case '^':
263 : // Oids
264 0 : Corners++;
265 0 : if ( 1 == Corners )
266 : {
267 : }
268 0 : else if ( 2 == Corners )
269 : {
270 0 : bColumn = false;
271 0 : bValueOid = true;
272 : }
273 : else
274 : {
275 0 : Text += cur;
276 : }
277 :
278 0 : break;
279 : case '=':
280 : // From column to value
281 0 : if ( bColumn )
282 : {
283 0 : bColumn = false;
284 : }
285 : else
286 : {
287 0 : Text += cur;
288 : }
289 0 : break;
290 : case '\\':
291 : {
292 : // Get next two chars
293 0 : char NextChar= nextChar();
294 0 : if ( '\r' != NextChar && '\n' != NextChar )
295 : {
296 0 : Text += NextChar;
297 : }
298 0 : else nextChar();
299 : }
300 0 : break;
301 : case '$':
302 : {
303 : // Get next two chars
304 0 : std::string HexChar;
305 0 : HexChar += nextChar();
306 0 : HexChar += nextChar();
307 0 : Text += (char)strtoul(HexChar.c_str(), 0, 16);
308 : }
309 0 : break;
310 : default:
311 : // Just a char
312 0 : if ( bColumn )
313 : {
314 0 : Column += cur;
315 : }
316 : else
317 : {
318 0 : Text += cur;
319 : }
320 0 : break;
321 : }
322 :
323 0 : cur = nextChar();
324 : }
325 :
326 : // Apply column and text
327 0 : int ColumnId = strtoul(Column.c_str(), 0, 16);
328 :
329 0 : if ( NPRows != nowParsing_ )
330 : {
331 : // Dicts
332 0 : if ( "" != Text )
333 : {
334 0 : if ( nowParsing_ == NPColumns )
335 : {
336 0 : columns_[ ColumnId ] = Text;
337 : }
338 : else
339 : {
340 0 : values_[ ColumnId ] = Text;
341 : }
342 : }
343 : }
344 : else
345 : {
346 0 : if ( "" != Text )
347 : {
348 : // Rows
349 : //int ValueId = string( Text.c_str() ).toInt( 0, 16 );
350 0 : int ValueId = strtoul(Text.c_str(), 0, 16);
351 :
352 0 : if ( bValueOid )
353 : {
354 0 : ( *currentCells_ )[ ColumnId ] = ValueId;
355 : }
356 : else
357 : {
358 0 : nextAddValueId_--;
359 0 : values_[ nextAddValueId_ ] = Text;
360 0 : ( *currentCells_ )[ ColumnId ] = nextAddValueId_;
361 : }
362 : }
363 : }
364 :
365 0 : return Result;
366 : }
367 :
368 0 : bool MorkParser::parseTable()
369 : {
370 0 : bool Result = true;
371 0 : std::string TextId;
372 0 : int Id = 0, Scope = 0;
373 :
374 0 : char cur = nextChar();
375 :
376 : // Get id
377 0 : while ( cur != '{' && cur != '[' && cur != '}' && cur )
378 : {
379 0 : if ( !isWhiteSpace( cur ) )
380 : {
381 0 : TextId += cur;
382 : }
383 :
384 0 : cur = nextChar();
385 : }
386 :
387 0 : parseScopeId( TextId, &Id, &Scope );
388 :
389 : // Parse the table
390 0 : while ( Result && cur != '}' && cur )
391 : {
392 0 : if ( !isWhiteSpace( cur ) )
393 : {
394 0 : switch ( cur )
395 : {
396 : case '{':
397 0 : Result = parseMeta( '}' );
398 0 : break;
399 : case '[':
400 0 : Result = parseRow( Id, Scope );
401 0 : break;
402 : case '-':
403 : case '+':
404 0 : break;
405 : default:
406 : {
407 0 : std::string JustId;
408 0 : while ( !isWhiteSpace( cur ) && cur )
409 : {
410 0 : JustId += cur;
411 0 : cur = nextChar();
412 :
413 0 : if ( cur == '}' )
414 : {
415 0 : return Result;
416 : }
417 : }
418 :
419 0 : int JustIdNum = 0, JustScopeNum = 0;
420 0 : parseScopeId( JustId, &JustIdNum, &JustScopeNum );
421 :
422 0 : setCurrentRow( Scope, Id, JustScopeNum, JustIdNum );
423 : }
424 0 : break;
425 : }
426 : }
427 :
428 0 : cur = nextChar();
429 : }
430 :
431 0 : return Result;
432 : }
433 :
434 0 : void MorkParser::parseScopeId( const std::string &TextId, int *Id, int *Scope )
435 : {
436 0 : int Pos = 0;
437 :
438 0 : if ( ( Pos = TextId.find( ':' ) ) >= 0 )
439 : {
440 0 : std::string tId = TextId.substr( 0, Pos );
441 0 : std::string tSc = TextId.substr( Pos + 1, TextId.length() - Pos );
442 :
443 0 : if ( tSc.length() > 1 && '^' == tSc[ 0 ] )
444 : {
445 : // Delete '^'
446 0 : tSc.erase( 0, 1 );
447 : }
448 :
449 0 : *Id = strtoul(tId.c_str(), 0, 16);
450 :
451 0 : *Scope = strtoul(tSc.c_str(), 0, 16);
452 : }
453 : else
454 : {
455 0 : *Id = strtoul(TextId.c_str(), 0, 16);
456 : }
457 0 : }
458 :
459 0 : inline void MorkParser::setCurrentRow( int TableScope, int TableId, int RowScope, int RowId )
460 : {
461 0 : if ( !RowScope )
462 : {
463 0 : RowScope = defaultScope_;
464 : }
465 :
466 0 : if ( !TableScope )
467 : {
468 0 : TableScope = defaultScope_;
469 : }
470 :
471 : // 01.08.2012 davido
472 : // TableId 0 is wrong here.
473 : // Straying rows (rows that defined outside the table) belong to the default scope and table is the last was seen: 1:^80
474 : // (at least i read so the specification)
475 0 : if (TableId)
476 : {
477 0 : defaultTableId_ = TableId;
478 : }
479 :
480 0 : if (!TableId)
481 : {
482 0 : TableId = defaultTableId_;
483 : }
484 :
485 0 : currentCells_ = &( mork_[ abs( TableScope ) ][ abs( TableId ) ][ abs( RowScope ) ][ abs( RowId ) ] );
486 0 : }
487 :
488 0 : bool MorkParser::parseRow( int TableId, int TableScope )
489 : {
490 0 : bool Result = true;
491 0 : std::string TextId;
492 0 : int Id = 0, Scope = 0;
493 0 : nowParsing_ = NPRows;
494 :
495 0 : char cur = nextChar();
496 :
497 : // Get id
498 0 : while ( cur != '(' && cur != ']' && cur != '[' && cur )
499 : {
500 0 : if ( !isWhiteSpace( cur ) )
501 : {
502 0 : TextId += cur;
503 : }
504 :
505 0 : cur = nextChar();
506 : }
507 :
508 0 : parseScopeId( TextId, &Id, &Scope );
509 0 : setCurrentRow( TableScope, TableId, Scope, Id );
510 :
511 : // Parse the row
512 0 : while ( Result && cur != ']' && cur )
513 : {
514 0 : if ( !isWhiteSpace( cur ) )
515 : {
516 0 : switch ( cur )
517 : {
518 : case '(':
519 0 : Result = parseCell();
520 0 : break;
521 : case '[':
522 0 : Result = parseMeta( ']' );
523 0 : break;
524 : default:
525 0 : Result = false;
526 0 : break;
527 : }
528 : }
529 :
530 0 : cur = nextChar();
531 : }
532 :
533 0 : return Result;
534 : }
535 :
536 0 : bool MorkParser::parseGroup()
537 : {
538 0 : return parseMeta( '@' );
539 : }
540 :
541 0 : bool MorkParser::parseMeta( char c )
542 : {
543 0 : char cur = nextChar();
544 :
545 0 : while ( cur != c && cur )
546 : {
547 0 : cur = nextChar();
548 : }
549 :
550 0 : return true;
551 : }
552 :
553 0 : MorkTableMap *MorkParser::getTables( int TableScope )
554 : {
555 0 : TableScopeMap::iterator iter;
556 0 : iter = mork_.find( TableScope );
557 :
558 0 : if ( iter == mork_.end() )
559 : {
560 0 : return 0;
561 : }
562 :
563 0 : return &iter->second;
564 : }
565 :
566 0 : MorkRowMap *MorkParser::getRows( int RowScope, RowScopeMap *table )
567 : {
568 0 : RowScopeMap::iterator iter;
569 0 : iter = table->find( RowScope );
570 :
571 0 : if ( iter == table->end() )
572 : {
573 0 : return 0;
574 : }
575 :
576 0 : return &iter->second;
577 : }
578 :
579 0 : std::string &MorkParser::getValue( int oid )
580 : {
581 0 : MorkDict::iterator foundIter = values_.find( oid );
582 :
583 0 : if ( values_.end() == foundIter )
584 : {
585 0 : return g_Empty;
586 : }
587 :
588 0 : return foundIter->second;
589 : }
590 :
591 0 : std::string &MorkParser::getColumn( int oid )
592 : {
593 0 : MorkDict::iterator foundIter = columns_.find( oid );
594 :
595 0 : if ( columns_.end() == foundIter )
596 : {
597 0 : return g_Empty;
598 : }
599 :
600 0 : return foundIter->second;
601 : }
602 :
603 0 : void MorkParser::retrieveLists(std::set<std::string>& lists)
604 : {
605 : #ifdef VERBOSE
606 : boost::io::ios_all_saver ias(std::cout);
607 : std::cout << std::hex << std::uppercase;
608 : #endif
609 :
610 0 : MorkTableMap* tables = getTables(defaultScope_);
611 0 : if (!tables) return;
612 0 : for (MorkTableMap::iterator TableIter = tables->begin();
613 0 : TableIter != tables->end(); ++TableIter )
614 : {
615 : #ifdef VERBOSE
616 : std::cout << "\t Table:"
617 : << ( ( int ) TableIter->first < 0 ? "-" : " " )
618 : << TableIter->first << std::endl;
619 : #endif
620 0 : MorkRowMap* rows = getRows( defaultListScope_, &TableIter->second );
621 0 : if (!rows) return;
622 0 : for ( MorkRowMap::iterator RowIter = rows->begin();
623 0 : RowIter != rows->end(); ++RowIter )
624 : {
625 : #ifdef VERBOSE
626 : std::cout << "\t\t\t Row Id:"
627 : << ( ( int ) RowIter->first < 0 ? "-" : " ")
628 : << RowIter->first << std::endl;
629 : std::cout << "\t\t\t\t Cells:\r\n";
630 : #endif
631 : // Get cells
632 0 : for ( MorkCells::iterator cellsIter = RowIter->second.begin();
633 0 : cellsIter != RowIter->second.end(); ++cellsIter )
634 : {
635 0 : if (cellsIter->first == 0xC1)
636 : {
637 0 : lists.insert(getValue( cellsIter->second ));
638 0 : break;
639 : }
640 : }
641 : }
642 : }
643 : }
644 :
645 0 : void MorkParser::getRecordKeysForListTable(std::string& listName, std::set<int>& records)
646 : {
647 : #ifdef VERBOSE
648 : boost::io::ios_all_saver ias(std::cout);
649 : std::cout << std::hex << std::uppercase;
650 : #endif
651 :
652 0 : MorkTableMap* tables = getTables(defaultScope_);
653 0 : if (!tables) return;
654 0 : for (MorkTableMap::iterator TableIter = tables->begin();
655 0 : TableIter != tables->end(); ++TableIter )
656 : {
657 : #ifdef VERBOSE
658 : std::cout << "\t Table:"
659 : << ( ( int ) TableIter->first < 0 ? "-" : " " )
660 : << TableIter->first << std::endl;
661 : #endif
662 0 : MorkRowMap* rows = getRows( 0x81, &TableIter->second );
663 0 : if (!rows) return;
664 0 : for ( MorkRowMap::iterator RowIter = rows->begin();
665 0 : RowIter != rows->end(); ++RowIter )
666 : {
667 : #ifdef VERBOSE
668 : std::cout << "\t\t\t Row Id:"
669 : << ( ( int ) RowIter->first < 0 ? "-" : " ")
670 : << RowIter->first << std::endl;
671 : std::cout << "\t\t\t\t Cells:\r\n";
672 : #endif
673 : // Get cells
674 0 : bool listFound = false;
675 0 : for ( MorkCells::iterator cellsIter = RowIter->second.begin();
676 0 : cellsIter != RowIter->second.end(); ++cellsIter )
677 : {
678 0 : if (listFound)
679 : {
680 0 : if (cellsIter->first >= 0xC7)
681 : {
682 0 : std::string value = getValue(cellsIter->second);
683 0 : int id = strtoul(value.c_str(), 0, 16);
684 0 : records.insert(id);
685 : }
686 : }
687 0 : else if ((cellsIter->first == 0xC1) &&
688 0 : listName == getValue( cellsIter->second ))
689 : {
690 0 : listFound = true;
691 : }
692 : }
693 :
694 : }
695 : }
696 : }
697 :
698 0 : void MorkParser::dump()
699 : {
700 0 : boost::io::ios_all_saver ias(std::cout);
701 0 : std::cout << std::hex << std::uppercase;
702 :
703 0 : std::cout << "Column Dict:\r\n";
704 0 : std::cout << "=============================================\r\n\r\n";
705 :
706 : //// columns dict
707 0 : for ( MorkDict::iterator iter = columns_.begin();
708 0 : iter != columns_.end(); ++iter )
709 : {
710 0 : std::cout << iter->first
711 0 : << " : "
712 0 : << iter->second
713 0 : << std::endl;
714 : }
715 :
716 : //// values dict
717 0 : std::cout << "\r\nValues Dict:\r\n";
718 0 : std::cout << "=============================================\r\n\r\n";
719 :
720 0 : for ( MorkDict::iterator iter = values_.begin();
721 0 : iter != values_.end(); ++iter )
722 : {
723 0 : if (iter->first >= nextAddValueId_) {
724 0 : continue;
725 : }
726 :
727 0 : std::cout << iter->first
728 0 : << " : "
729 0 : << iter->second
730 0 : << "\r\n";
731 : }
732 :
733 0 : std::cout << std::endl << "Data:" << std::endl;
734 0 : std::cout << "============================================="
735 0 : << std::endl << std::endl;
736 :
737 : //// Mork data
738 0 : for ( TableScopeMap::iterator iter = mork_.begin();
739 0 : iter != mork_.end(); ++iter )
740 : {
741 0 : std::cout << "\r\n Scope:" << iter->first << std::endl;
742 :
743 0 : for ( MorkTableMap::iterator TableIter = iter->second.begin();
744 0 : TableIter != iter->second.end(); ++TableIter )
745 : {
746 0 : std::cout << "\t Table:"
747 0 : << ( ( int ) TableIter->first < 0 ? "-" : " " )
748 0 : << TableIter->first << std::endl;
749 :
750 0 : for (RowScopeMap::iterator RowScopeIter = TableIter->second.begin();
751 0 : RowScopeIter != TableIter->second.end(); ++RowScopeIter )
752 : {
753 0 : std::cout << "\t\t RowScope:"
754 0 : << RowScopeIter->first << std::endl;
755 :
756 0 : for (MorkRowMap::iterator RowIter = RowScopeIter->second.begin();
757 0 : RowIter != RowScopeIter->second.end(); ++RowIter )
758 : {
759 0 : std::cout << "\t\t\t Row Id:"
760 0 : << ((int) RowIter->first < 0 ? "-" : " ")
761 0 : << RowIter->first << std::endl;
762 0 : std::cout << "\t\t\t\t Cells:" << std::endl;
763 :
764 0 : for (MorkCells::iterator CellsIter = RowIter->second.begin();
765 0 : CellsIter != RowIter->second.end(); ++CellsIter )
766 : {
767 : // Write ids
768 0 : std::cout << "\t\t\t\t\t"
769 0 : << CellsIter->first
770 0 : << " : "
771 0 : << CellsIter->second
772 0 : << " => ";
773 :
774 0 : MorkDict::iterator FoundIter = values_.find( CellsIter->second );
775 0 : if ( FoundIter != values_.end() )
776 : {
777 : // Write string values
778 0 : std::cout << columns_[ CellsIter->first ].c_str()
779 0 : << " : "
780 0 : << FoundIter->second.c_str()
781 0 : << std::endl;
782 : }
783 : }
784 : }
785 : }
786 : }
787 0 : }
788 0 : }
|