1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * Software License Agreement (BSD License)
5 * Copyright (c) 2006, ScalingWeb.com
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>
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() :
59 currentCells_(nullptr),
63 nextAddValueId_(0x7fffffff),
69 bool MorkParser::open( const std::string
&path
)
73 std::ifstream
infile(path
.c_str(), std::ios_base::in
);
76 error_
= FailedToOpen
;
80 while (getline(infile
, line
, '\n'))
82 morkData_
.append(line
);
83 morkData_
.append("\n");
90 void MorkParser::initVars()
94 nowParsing_
= NPValues
;
95 currentCells_
= nullptr;
96 nextAddValueId_
= 0x7fffffff;
99 bool MorkParser::parse()
103 // Run over mork chars and parse each term
104 char cur
= nextChar();
108 while ( Result
&& cur
)
110 if ( !isWhiteSpace( cur
) )
113 // Figure out what a term
118 Result
= parseDict();
122 Result
= parseComment();
125 Result
= parseTable();
129 Result
= parseRow( 0, 0 );
133 Result
= parseGroup();
137 error_
= DefectedFormat
;
150 bool MorkParser::isWhiteSpace( char c
)
165 inline char MorkParser::nextChar()
170 if ( morkPos_
< morkData_
.length() )
172 cur
= morkData_
[ morkPos_
];
184 bool MorkParser::parseDict()
186 char cur
= nextChar();
188 nowParsing_
= NPValues
;
190 while ( Result
&& cur
!= '>' && cur
)
192 if ( !isWhiteSpace( cur
) )
199 if ( morkData_
.substr( morkPos_
- 1, strlen( MorkDictColumnMeta
) ) == MorkDictColumnMeta
)
201 nowParsing_
= NPColumns
;
202 morkPos_
+= strlen( MorkDictColumnMeta
) - 1;
209 Result
= parseCell();
212 Result
= parseComment();
224 inline bool MorkParser::parseComment()
226 char cur
= nextChar();
227 if ( '/' != cur
) return false;
229 while ( cur
!= '\r' && cur
!= '\n' && cur
)
237 bool MorkParser::parseCell()
240 bool bValueOid
= false;
250 char cur
= nextChar();
252 // Process cell start with column (bColumn == true)
253 while ( Result
&& cur
!= ')' && cur
)
263 else if ( 2 == Corners
)
275 // From column to value
287 // Get next two chars
288 char NextChar
= nextChar();
289 if ( '\r' != NextChar
&& '\n' != NextChar
)
301 // Get next two chars
303 HexChar
+= nextChar();
304 HexChar
+= nextChar();
305 Text
+= (char)strtoul(HexChar
.c_str(), nullptr, 16);
324 // Apply column and text
325 int ColumnId
= strtoul(Column
.c_str(), nullptr, 16);
327 if ( NPRows
!= nowParsing_
)
332 if ( nowParsing_
== NPColumns
)
334 columns_
[ ColumnId
] = Text
;
338 values_
[ ColumnId
] = Text
;
347 //int ValueId = string( Text.c_str() ).toInt( 0, 16 );
348 int ValueId
= strtoul(Text
.c_str(), nullptr, 16);
352 ( *currentCells_
)[ ColumnId
] = ValueId
;
357 values_
[ nextAddValueId_
] = Text
;
358 ( *currentCells_
)[ ColumnId
] = nextAddValueId_
;
366 bool MorkParser::parseTable()
370 int Id
= 0, Scope
= 0;
372 char cur
= nextChar();
375 while ( cur
!= '{' && cur
!= '[' && cur
!= '}' && cur
)
377 if ( !isWhiteSpace( cur
) )
385 parseScopeId( TextId
, &Id
, &Scope
);
388 while ( Result
&& cur
!= '}' && cur
)
390 if ( !isWhiteSpace( cur
) )
395 Result
= parseMeta( '}' );
398 Result
= parseRow( Id
, Scope
);
406 while ( !isWhiteSpace( cur
) && cur
)
417 int JustIdNum
= 0, JustScopeNum
= 0;
418 parseScopeId( JustId
, &JustIdNum
, &JustScopeNum
);
420 setCurrentRow( Scope
, Id
, JustScopeNum
, JustIdNum
);
432 void MorkParser::parseScopeId( const std::string
&TextId
, int *Id
, int *Scope
)
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 ] )
447 *Id
= strtoul(tId
.c_str(), nullptr, 16);
449 *Scope
= strtoul(tSc
.c_str(), nullptr, 16);
453 *Id
= strtoul(TextId
.c_str(), nullptr, 16);
457 inline void MorkParser::setCurrentRow( int TableScope
, int TableId
, int RowScope
, int RowId
)
461 RowScope
= defaultScope_
;
466 TableScope
= defaultScope_
;
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)
475 defaultTableId_
= 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
)
490 int Id
= 0, Scope
= 0;
491 nowParsing_
= NPRows
;
493 char cur
= nextChar();
496 while ( cur
!= '(' && cur
!= ']' && cur
!= '[' && cur
)
498 if ( !isWhiteSpace( cur
) )
506 parseScopeId( TextId
, &Id
, &Scope
);
507 setCurrentRow( TableScope
, TableId
, Scope
, Id
);
510 while ( Result
&& cur
!= ']' && cur
)
512 if ( !isWhiteSpace( cur
) )
517 Result
= parseCell();
520 Result
= parseMeta( ']' );
534 bool MorkParser::parseGroup()
536 return parseMeta( '@' );
539 bool MorkParser::parseMeta( char c
)
541 char cur
= nextChar();
543 while ( cur
!= c
&& cur
)
551 MorkTableMap
*MorkParser::getTables( int TableScope
)
553 TableScopeMap::Map::iterator iter
;
554 iter
= mork_
.map
.find( TableScope
);
556 if ( iter
== mork_
.map
.end() )
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() )
574 return &iter
->second
;
577 std::string
&MorkParser::getValue( int oid
)
579 MorkDict::iterator foundIter
= values_
.find( oid
);
581 if ( values_
.end() == foundIter
)
586 return foundIter
->second
;
589 std::string
&MorkParser::getColumn( int oid
)
591 MorkDict::iterator foundIter
= columns_
.find( oid
);
593 if ( columns_
.end() == foundIter
)
598 return foundIter
->second
;
601 void MorkParser::retrieveLists(std::set
<std::string
>& lists
)
604 boost::io::ios_all_saver
ias(std::cout
);
605 std::cout
<< std::hex
<< std::uppercase
;
608 MorkTableMap
* tables
= getTables(defaultScope_
);
610 for (MorkTableMap::Map::iterator TableIter
= tables
->map
.begin();
611 TableIter
!= tables
->map
.end(); ++TableIter
)
614 std::cout
<< "\t Table:"
615 << ( ( int ) TableIter
->first
< 0 ? "-" : " " )
616 << TableIter
->first
<< std::endl
;
618 MorkRowMap
* rows
= getRows( 0x81/*defaultListScope*/, &TableIter
->second
);
620 for ( MorkRowMap::Map::const_iterator RowIter
= rows
->map
.begin();
621 RowIter
!= rows
->map
.end(); ++RowIter
)
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";
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
));
643 void MorkParser::getRecordKeysForListTable(std::string
& listName
, std::set
<int>& records
)
646 boost::io::ios_all_saver
ias(std::cout
);
647 std::cout
<< std::hex
<< std::uppercase
;
650 MorkTableMap
* tables
= getTables(defaultScope_
);
652 for (MorkTableMap::Map::iterator TableIter
= tables
->map
.begin();
653 TableIter
!= tables
->map
.end(); ++TableIter
)
656 std::cout
<< "\t Table:"
657 << ( ( int ) TableIter
->first
< 0 ? "-" : " " )
658 << TableIter
->first
<< std::endl
;
660 MorkRowMap
* rows
= getRows( 0x81, &TableIter
->second
);
662 for ( MorkRowMap::Map::const_iterator RowIter
= rows
->map
.begin();
663 RowIter
!= rows
->map
.end(); ++RowIter
)
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";
672 bool isListFound
= false;
673 for ( MorkCells::const_iterator cellsIter
= RowIter
->second
.begin();
674 cellsIter
!= RowIter
->second
.end(); ++cellsIter
)
678 if (cellsIter
->first
>= 0xC7)
680 std::string value
= getValue(cellsIter
->second
);
681 int id
= strtoul(value
.c_str(), nullptr, 16);
685 else if ((cellsIter
->first
== 0xC1) &&
686 listName
== getValue( cellsIter
->second
))
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";
705 for ( MorkDict::const_iterator iter
= columns_
.begin();
706 iter
!= columns_
.end(); ++iter
)
708 std::cout
<< iter
->first
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_
) {
725 std::cout
<< iter
->first
731 std::cout
<< std::endl
<< "Data:" << std::endl
;
732 std::cout
<< "============================================="
733 << std::endl
<< std::endl
;
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
)
766 std::cout
<< "\t\t\t\t\t"
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()
778 << FoundIter
->second
.c_str()
788 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */