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