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 1 : 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 3 : 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 3 : nowParsing_(NPValues)
65 : {
66 3 : }
67 :
68 3 : bool MorkParser::open( const std::string &path )
69 : {
70 3 : initVars();
71 3 : std::string line;
72 3 : std::ifstream infile(path.c_str(), std::ios_base::in);
73 3 : if(!infile.is_open())
74 : {
75 0 : error_ = FailedToOpen;
76 0 : return false;
77 : }
78 :
79 483 : while (getline(infile, line, '\n'))
80 : {
81 477 : morkData_.append(line);
82 477 : morkData_.append("\n");
83 : }
84 :
85 : // Parse mork
86 3 : return parse();
87 : }
88 :
89 : inline MorkErrors MorkParser::error()
90 : {
91 : return error_;
92 : }
93 :
94 3 : void MorkParser::initVars()
95 : {
96 3 : error_ = NoError;
97 3 : morkPos_ = 0;
98 3 : nowParsing_ = NPValues;
99 3 : currentCells_ = 0;
100 3 : nextAddValueId_ = 0x7fffffff;
101 3 : }
102 :
103 3 : bool MorkParser::parse()
104 : {
105 3 : bool Result = true;
106 :
107 : // Run over mork chars and parse each term
108 3 : char cur = nextChar();
109 :
110 3 : int i = 0;
111 :
112 306 : while ( Result && cur )
113 : {
114 300 : if ( !isWhiteSpace( cur ) )
115 : {
116 132 : i++;
117 : // Figure out what a term
118 132 : switch ( cur )
119 : {
120 : case '<':
121 : // Dict
122 24 : Result = parseDict();
123 24 : break;
124 : case '/':
125 : // Comment
126 3 : Result = parseComment();
127 3 : break;
128 : case '{':
129 6 : Result = parseTable();
130 : // Table
131 6 : break;
132 : case '[':
133 33 : Result = parseRow( 0, 0 );
134 : // Row
135 33 : break;
136 : case '@':
137 66 : Result = parseGroup();
138 : // Group
139 66 : break;
140 : default:
141 0 : error_ = DefectedFormat;
142 0 : Result = false;
143 0 : break;
144 : }
145 : }
146 :
147 : // Get next char
148 300 : cur = nextChar();
149 : }
150 :
151 3 : return Result;
152 : }
153 :
154 4368 : bool MorkParser::isWhiteSpace( char c )
155 : {
156 4368 : switch ( c )
157 : {
158 : case ' ':
159 : case '\t':
160 : case '\r':
161 : case '\n':
162 : case '\f':
163 1425 : return true;
164 : default:
165 2943 : return false;
166 : }
167 : }
168 :
169 21927 : inline char MorkParser::nextChar()
170 : {
171 21927 : char cur = 0;
172 :
173 :
174 21927 : if ( morkPos_ < morkData_.length() )
175 : {
176 21924 : cur = morkData_[ morkPos_ ];
177 21924 : morkPos_++;
178 : }
179 :
180 21927 : if ( !cur )
181 : {
182 3 : cur = 0;
183 : }
184 :
185 21927 : return cur;
186 : }
187 :
188 24 : bool MorkParser::parseDict()
189 : {
190 24 : char cur = nextChar();
191 24 : bool Result = true;
192 24 : nowParsing_ = NPValues;
193 :
194 813 : while ( Result && cur != '>' && cur )
195 : {
196 765 : if ( !isWhiteSpace( cur ) )
197 : {
198 441 : switch ( cur )
199 : {
200 : case '<':
201 : {
202 :
203 18 : if ( morkData_.substr( morkPos_ - 1, strlen( MorkDictColumnMeta ) ) == MorkDictColumnMeta )
204 : {
205 18 : nowParsing_ = NPColumns;
206 18 : morkPos_ += strlen( MorkDictColumnMeta ) - 1;
207 : }
208 :
209 :
210 18 : break;
211 : }
212 : case '(':
213 405 : Result = parseCell();
214 405 : break;
215 : case '/':
216 18 : Result = parseComment();
217 18 : break;
218 :
219 : }
220 : }
221 :
222 765 : cur = nextChar();
223 : }
224 :
225 24 : return Result;
226 : }
227 :
228 21 : inline bool MorkParser::parseComment()
229 : {
230 21 : char cur = nextChar();
231 21 : if ( '/' != cur ) return false;
232 :
233 426 : while ( cur != '\r' && cur != '\n' && cur )
234 : {
235 384 : cur = nextChar();
236 : }
237 :
238 21 : return true;
239 : }
240 :
241 2427 : bool MorkParser::parseCell()
242 : {
243 2427 : bool Result = true;
244 2427 : bool bValueOid = false;
245 2427 : bool bColumn = true;
246 2427 : int Corners = 0;
247 :
248 : // Column = Value
249 2427 : std::string Column;
250 2427 : std::string Text;
251 2427 : Column.reserve( 4 );
252 2427 : Text.reserve( 32 );
253 :
254 2427 : char cur = nextChar();
255 :
256 : // Process cell start with column (bColumn == true)
257 18972 : while ( Result && cur != ')' && cur )
258 : {
259 14118 : switch ( cur )
260 : {
261 : case '^':
262 : // Oids
263 2274 : Corners++;
264 2274 : if ( 1 == Corners )
265 : {
266 : }
267 252 : else if ( 2 == Corners )
268 : {
269 252 : bColumn = false;
270 252 : bValueOid = true;
271 : }
272 : else
273 : {
274 0 : Text += cur;
275 : }
276 :
277 2274 : break;
278 : case '=':
279 : // From column to value
280 2175 : if ( bColumn )
281 : {
282 2175 : bColumn = false;
283 : }
284 : else
285 : {
286 0 : Text += cur;
287 : }
288 2175 : 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 9669 : if ( bColumn )
312 : {
313 4869 : Column += cur;
314 : }
315 : else
316 : {
317 4800 : Text += cur;
318 : }
319 9669 : break;
320 : }
321 :
322 14118 : cur = nextChar();
323 : }
324 :
325 : // Apply column and text
326 2427 : int ColumnId = strtoul(Column.c_str(), 0, 16);
327 :
328 2427 : if ( NPRows != nowParsing_ )
329 : {
330 : // Dicts
331 405 : if ( "" != Text )
332 : {
333 402 : if ( nowParsing_ == NPColumns )
334 : {
335 252 : columns_[ ColumnId ] = Text;
336 : }
337 : else
338 : {
339 150 : values_[ ColumnId ] = Text;
340 : }
341 : }
342 : }
343 : else
344 : {
345 2022 : if ( "" != Text )
346 : {
347 : // Rows
348 : //int ValueId = string( Text.c_str() ).toInt( 0, 16 );
349 630 : int ValueId = strtoul(Text.c_str(), 0, 16);
350 :
351 630 : if ( bValueOid )
352 : {
353 252 : ( *currentCells_ )[ ColumnId ] = ValueId;
354 : }
355 : else
356 : {
357 378 : nextAddValueId_--;
358 378 : values_[ nextAddValueId_ ] = Text;
359 378 : ( *currentCells_ )[ ColumnId ] = nextAddValueId_;
360 : }
361 : }
362 : }
363 :
364 2427 : return Result;
365 : }
366 :
367 6 : bool MorkParser::parseTable()
368 : {
369 6 : bool Result = true;
370 6 : std::string TextId;
371 6 : int Id = 0, Scope = 0;
372 :
373 6 : char cur = nextChar();
374 :
375 : // Get id
376 48 : while ( cur != '{' && cur != '[' && cur != '}' && cur )
377 : {
378 36 : if ( !isWhiteSpace( cur ) )
379 : {
380 30 : TextId += cur;
381 : }
382 :
383 36 : cur = nextChar();
384 : }
385 :
386 6 : parseScopeId( TextId, &Id, &Scope );
387 :
388 : // Parse the table
389 174 : while ( Result && cur != '}' && cur )
390 : {
391 162 : if ( !isWhiteSpace( cur ) )
392 : {
393 45 : switch ( cur )
394 : {
395 : case '{':
396 6 : Result = parseMeta( '}' );
397 6 : break;
398 : case '[':
399 39 : Result = parseRow( Id, Scope );
400 39 : 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 162 : cur = nextChar();
428 : }
429 :
430 6 : return Result;
431 : }
432 :
433 78 : void MorkParser::parseScopeId( const std::string &TextId, int *Id, int *Scope )
434 : {
435 78 : int Pos = 0;
436 :
437 78 : if ( ( Pos = TextId.find( ':' ) ) >= 0 )
438 : {
439 48 : std::string tId = TextId.substr( 0, Pos );
440 48 : std::string tSc = TextId.substr( Pos + 1, TextId.length() - Pos );
441 :
442 48 : if ( tSc.length() > 1 && '^' == tSc[ 0 ] )
443 : {
444 : // Delete '^'
445 48 : tSc.erase( 0, 1 );
446 : }
447 :
448 48 : *Id = strtoul(tId.c_str(), 0, 16);
449 :
450 48 : *Scope = strtoul(tSc.c_str(), 0, 16);
451 : }
452 : else
453 : {
454 30 : *Id = strtoul(TextId.c_str(), 0, 16);
455 : }
456 78 : }
457 :
458 72 : inline void MorkParser::setCurrentRow( int TableScope, int TableId, int RowScope, int RowId )
459 : {
460 72 : if ( !RowScope )
461 : {
462 30 : RowScope = defaultScope_;
463 : }
464 :
465 72 : if ( !TableScope )
466 : {
467 33 : 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 72 : if (TableId)
475 : {
476 39 : defaultTableId_ = TableId;
477 : }
478 :
479 72 : if (!TableId)
480 : {
481 33 : TableId = defaultTableId_;
482 : }
483 :
484 72 : currentCells_ = &( mork_[ abs( TableScope ) ][ abs( TableId ) ][ abs( RowScope ) ][ abs( RowId ) ] );
485 72 : }
486 :
487 72 : bool MorkParser::parseRow( int TableId, int TableScope )
488 : {
489 72 : bool Result = true;
490 72 : std::string TextId;
491 72 : int Id = 0, Scope = 0;
492 72 : nowParsing_ = NPRows;
493 :
494 72 : char cur = nextChar();
495 :
496 : // Get id
497 417 : while ( cur != '(' && cur != ']' && cur != '[' && cur )
498 : {
499 273 : if ( !isWhiteSpace( cur ) )
500 : {
501 273 : TextId += cur;
502 : }
503 :
504 273 : cur = nextChar();
505 : }
506 :
507 72 : parseScopeId( TextId, &Id, &Scope );
508 72 : setCurrentRow( TableScope, TableId, Scope, Id );
509 :
510 : // Parse the row
511 2976 : while ( Result && cur != ']' && cur )
512 : {
513 2832 : if ( !isWhiteSpace( cur ) )
514 : {
515 2022 : switch ( cur )
516 : {
517 : case '(':
518 2022 : Result = parseCell();
519 2022 : break;
520 : case '[':
521 0 : Result = parseMeta( ']' );
522 0 : break;
523 : default:
524 0 : Result = false;
525 0 : break;
526 : }
527 : }
528 :
529 2832 : cur = nextChar();
530 : }
531 :
532 72 : return Result;
533 : }
534 :
535 66 : bool MorkParser::parseGroup()
536 : {
537 66 : return parseMeta( '@' );
538 : }
539 :
540 72 : bool MorkParser::parseMeta( char c )
541 : {
542 72 : char cur = nextChar();
543 :
544 576 : while ( cur != c && cur )
545 : {
546 432 : cur = nextChar();
547 : }
548 :
549 72 : return true;
550 : }
551 :
552 87 : MorkTableMap *MorkParser::getTables( int TableScope )
553 : {
554 87 : TableScopeMap::iterator iter;
555 87 : iter = mork_.find( TableScope );
556 :
557 87 : if ( iter == mork_.end() )
558 : {
559 0 : return 0;
560 : }
561 :
562 87 : return &iter->second;
563 : }
564 :
565 84 : MorkRowMap *MorkParser::getRows( int RowScope, RowScopeMap *table )
566 : {
567 84 : RowScopeMap::iterator iter;
568 84 : iter = table->find( RowScope );
569 :
570 84 : if ( iter == table->end() )
571 : {
572 0 : return 0;
573 : }
574 :
575 84 : return &iter->second;
576 : }
577 :
578 364 : std::string &MorkParser::getValue( int oid )
579 : {
580 364 : MorkDict::iterator foundIter = values_.find( oid );
581 :
582 364 : if ( values_.end() == foundIter )
583 : {
584 0 : return g_Empty;
585 : }
586 :
587 364 : return foundIter->second;
588 : }
589 :
590 195 : std::string &MorkParser::getColumn( int oid )
591 : {
592 195 : MorkDict::iterator foundIter = columns_.find( oid );
593 :
594 195 : if ( columns_.end() == foundIter )
595 : {
596 0 : return g_Empty;
597 : }
598 :
599 195 : return foundIter->second;
600 : }
601 :
602 81 : void MorkParser::retrieveLists(std::set<std::string>& lists)
603 : {
604 81 : MorkTableMap* tables = getTables(defaultScope_);
605 81 : if (!tables) return;
606 486 : for (MorkTableMap::iterator TableIter = tables->begin();
607 324 : 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 81 : MorkRowMap* rows = getRows( defaultListScope_, &TableIter->second );
615 81 : if (!rows) return;
616 729 : for ( MorkRowMap::iterator RowIter = rows->begin();
617 486 : 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 1944 : for ( MorkCells::iterator cellsIter = RowIter->second.begin();
627 1296 : cellsIter != RowIter->second.end(); ++cellsIter )
628 : {
629 648 : if (cellsIter->first == 0xC1)
630 : {
631 162 : lists.insert(getValue( cellsIter->second ));
632 162 : break;
633 : }
634 : }
635 : }
636 : }
637 : }
638 :
639 1 : void MorkParser::getRecordKeysForListTable(std::string& listName, std::set<int>& records)
640 : {
641 1 : MorkTableMap* tables = getTables(defaultScope_);
642 1 : if (!tables) return;
643 6 : for (MorkTableMap::iterator TableIter = tables->begin();
644 4 : 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 1 : MorkRowMap* rows = getRows( 0x81, &TableIter->second );
652 1 : if (!rows) return;
653 9 : for ( MorkRowMap::iterator RowIter = rows->begin();
654 6 : 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 2 : bool listFound = false;
664 60 : for ( MorkCells::iterator cellsIter = RowIter->second.begin();
665 40 : cellsIter != RowIter->second.end(); ++cellsIter )
666 : {
667 18 : if (listFound)
668 : {
669 5 : if (cellsIter->first >= 0xC7)
670 : {
671 5 : std::string value = getValue(cellsIter->second);
672 5 : int id = strtoul(value.c_str(), 0, 16);
673 5 : records.insert(id);
674 : }
675 : }
676 15 : else if ((cellsIter->first == 0xC1) &&
677 2 : listName == getValue( cellsIter->second ))
678 : {
679 1 : 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 3 : }
|