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)>";
54 MorkParser::MorkParser( int DefaultScope
) :
62 nextAddValueId_(0x7fffffff),
63 defaultScope_(DefaultScope
),
64 defaultListScope_(0x81),
70 bool MorkParser::open( const std::string
&path
)
74 std::ifstream
infile(path
.c_str(), std::ios_base::in
);
77 error_
= FailedToOpen
;
81 while (getline(infile
, line
, '\n'))
83 morkData_
.append(line
);
84 morkData_
.append("\n");
91 inline MorkErrors
MorkParser::error()
96 void MorkParser::initVars()
100 nowParsing_
= NPValues
;
102 nextAddValueId_
= 0x7fffffff;
105 bool MorkParser::parse()
109 // Run over mork chars and parse each term
110 char cur
= nextChar();
114 while ( Result
&& cur
)
116 if ( !isWhiteSpace( cur
) )
119 // Figure out what a term
124 Result
= parseDict();
128 Result
= parseComment();
131 Result
= parseTable();
135 Result
= parseRow( 0, 0 );
139 Result
= parseGroup();
143 error_
= DefectedFormat
;
156 bool MorkParser::isWhiteSpace( char c
)
171 inline char MorkParser::nextChar()
176 if ( morkPos_
< morkData_
.length() )
178 cur
= morkData_
[ morkPos_
];
190 bool MorkParser::parseDict()
192 char cur
= nextChar();
194 nowParsing_
= NPValues
;
196 while ( Result
&& cur
!= '>' && cur
)
198 if ( !isWhiteSpace( cur
) )
205 if ( morkData_
.substr( morkPos_
- 1, strlen( MorkDictColumnMeta
) ) == MorkDictColumnMeta
)
207 nowParsing_
= NPColumns
;
208 morkPos_
+= strlen( MorkDictColumnMeta
) - 1;
215 Result
= parseCell();
218 Result
= parseComment();
230 inline bool MorkParser::parseComment()
232 char cur
= nextChar();
233 if ( '/' != cur
) return false;
235 while ( cur
!= '\r' && cur
!= '\n' && cur
)
243 bool MorkParser::parseCell()
246 bool bValueOid
= false;
256 char cur
= nextChar();
258 // Process cell start with column (bColumn == true)
259 while ( Result
&& cur
!= ')' && cur
)
269 else if ( 2 == Corners
)
281 // From column to value
293 // Get next two chars
294 char NextChar
= nextChar();
295 if ( '\r' != NextChar
&& '\n' != NextChar
)
304 // Get next two chars
306 HexChar
+= nextChar();
307 HexChar
+= nextChar();
308 Text
+= (char)strtoul(HexChar
.c_str(), 0, 16);
327 // Apply column and text
328 int ColumnId
= strtoul(Column
.c_str(), 0, 16);
330 if ( NPRows
!= nowParsing_
)
335 if ( nowParsing_
== NPColumns
)
337 columns_
[ ColumnId
] = Text
;
341 values_
[ ColumnId
] = Text
;
350 //int ValueId = string( Text.c_str() ).toInt( 0, 16 );
351 int ValueId
= strtoul(Text
.c_str(), 0, 16);
355 ( *currentCells_
)[ ColumnId
] = ValueId
;
360 values_
[ nextAddValueId_
] = Text
;
361 ( *currentCells_
)[ ColumnId
] = nextAddValueId_
;
369 bool MorkParser::parseTable()
373 int Id
= 0, Scope
= 0;
375 char cur
= nextChar();
378 while ( cur
!= '{' && cur
!= '[' && cur
!= '}' && cur
)
380 if ( !isWhiteSpace( cur
) )
388 parseScopeId( TextId
, &Id
, &Scope
);
391 while ( Result
&& cur
!= '}' && cur
)
393 if ( !isWhiteSpace( cur
) )
398 Result
= parseMeta( '}' );
401 Result
= parseRow( Id
, Scope
);
409 while ( !isWhiteSpace( cur
) && cur
)
420 int JustIdNum
= 0, JustScopeNum
= 0;
421 parseScopeId( JustId
, &JustIdNum
, &JustScopeNum
);
423 setCurrentRow( Scope
, Id
, JustScopeNum
, JustIdNum
);
435 void MorkParser::parseScopeId( const std::string
&TextId
, int *Id
, int *Scope
)
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 ] )
450 *Id
= strtoul(tId
.c_str(), 0, 16);
452 *Scope
= strtoul(tSc
.c_str(), 0, 16);
456 *Id
= strtoul(TextId
.c_str(), 0, 16);
460 inline void MorkParser::setCurrentRow( int TableScope
, int TableId
, int RowScope
, int RowId
)
464 RowScope
= defaultScope_
;
469 TableScope
= defaultScope_
;
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)
478 defaultTableId_
= TableId
;
483 TableId
= defaultTableId_
;
486 currentCells_
= &( mork_
[ abs( TableScope
) ][ abs( TableId
) ][ abs( RowScope
) ][ abs( RowId
) ] );
489 bool MorkParser::parseRow( int TableId
, int TableScope
)
493 int Id
= 0, Scope
= 0;
494 nowParsing_
= NPRows
;
496 char cur
= nextChar();
499 while ( cur
!= '(' && cur
!= ']' && cur
!= '[' && cur
)
501 if ( !isWhiteSpace( cur
) )
509 parseScopeId( TextId
, &Id
, &Scope
);
510 setCurrentRow( TableScope
, TableId
, Scope
, Id
);
513 while ( Result
&& cur
!= ']' && cur
)
515 if ( !isWhiteSpace( cur
) )
520 Result
= parseCell();
523 Result
= parseMeta( ']' );
537 bool MorkParser::parseGroup()
539 return parseMeta( '@' );
542 bool MorkParser::parseMeta( char c
)
544 char cur
= nextChar();
546 while ( cur
!= c
&& cur
)
554 MorkTableMap
*MorkParser::getTables( int TableScope
)
556 TableScopeMap::iterator iter
;
557 iter
= mork_
.find( TableScope
);
559 if ( iter
== mork_
.end() )
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() )
577 return &iter
->second
;
580 std::string
&MorkParser::getValue( int oid
)
582 MorkDict::iterator foundIter
= values_
.find( oid
);
584 if ( values_
.end() == foundIter
)
589 return foundIter
->second
;
592 std::string
&MorkParser::getColumn( int oid
)
594 MorkDict::iterator foundIter
= columns_
.find( oid
);
596 if ( columns_
.end() == foundIter
)
601 return foundIter
->second
;
604 void MorkParser::retrieveLists(std::set
<std::string
>& lists
)
607 boost::io::ios_all_saver
ias(std::cout
);
608 std::cout
<< std::hex
<< std::uppercase
;
611 MorkTableMap
* tables
= getTables(defaultScope_
);
613 for (MorkTableMap::iterator TableIter
= tables
->begin();
614 TableIter
!= tables
->end(); ++TableIter
)
617 std::cout
<< "\t Table:"
618 << ( ( int ) TableIter
->first
< 0 ? "-" : " " )
619 << TableIter
->first
<< std::endl
;
621 MorkRowMap
* rows
= getRows( defaultListScope_
, &TableIter
->second
);
623 for ( MorkRowMap::iterator RowIter
= rows
->begin();
624 RowIter
!= rows
->end(); ++RowIter
)
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";
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
));
646 void MorkParser::getRecordKeysForListTable(std::string
& listName
, std::set
<int>& records
)
649 boost::io::ios_all_saver
ias(std::cout
);
650 std::cout
<< std::hex
<< std::uppercase
;
653 MorkTableMap
* tables
= getTables(defaultScope_
);
655 for (MorkTableMap::iterator TableIter
= tables
->begin();
656 TableIter
!= tables
->end(); ++TableIter
)
659 std::cout
<< "\t Table:"
660 << ( ( int ) TableIter
->first
< 0 ? "-" : " " )
661 << TableIter
->first
<< std::endl
;
663 MorkRowMap
* rows
= getRows( 0x81, &TableIter
->second
);
665 for ( MorkRowMap::iterator RowIter
= rows
->begin();
666 RowIter
!= rows
->end(); ++RowIter
)
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";
675 bool listFound
= false;
676 for ( MorkCells::iterator cellsIter
= RowIter
->second
.begin();
677 cellsIter
!= RowIter
->second
.end(); ++cellsIter
)
681 if (cellsIter
->first
>= 0xC7)
683 std::string value
= getValue(cellsIter
->second
);
684 int id
= strtoul(value
.c_str(), 0, 16);
688 else if ((cellsIter
->first
== 0xC1) &&
689 listName
== getValue( cellsIter
->second
))
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";
708 for ( MorkDict::iterator iter
= columns_
.begin();
709 iter
!= columns_
.end(); ++iter
)
711 std::cout
<< iter
->first
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_
) {
728 std::cout
<< iter
->first
734 std::cout
<< std::endl
<< "Data:" << std::endl
;
735 std::cout
<< "============================================="
736 << std::endl
<< std::endl
;
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
)
769 std::cout
<< "\t\t\t\t\t"
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()
781 << FoundIter
->second
.c_str()
791 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */