Index   Main   Namespaces   Classes   Hierarchy   Annotated   Files   Compound   Global   Pages  

SgGameReader.cpp

Go to the documentation of this file.
00001 //----------------------------------------------------------------------------
00002 /** @file SgGameReader.cpp */
00003 //----------------------------------------------------------------------------
00004 
00005 #include "SgSystem.h"
00006 #include "SgGameReader.h"
00007 
00008 #include <cstdio> // Defines EOF
00009 #include <iostream>
00010 #include <map>
00011 #include <vector>
00012 #include "SgDebug.h"
00013 #include "SgException.h"
00014 #include "SgNode.h"
00015 
00016 using namespace std;
00017 
00018 //----------------------------------------------------------------------------
00019 
00020 namespace {
00021 
00022 /** Print warning and reset flag in temporary copy of m_warnings. */
00023 void PrintWarning(ostream& out, SgGameReader::Warnings& warnings, int index,
00024                   const char* text)
00025 {
00026     if (! warnings.test(index))
00027         return;
00028     out << text << '\n';
00029     warnings.reset(index);
00030 }
00031 
00032 } // namespace
00033 
00034 //----------------------------------------------------------------------------
00035 
00036 SgGameReader::SgGameReader(istream& in, int defaultSize)
00037     : m_in(in),
00038       m_defaultSize(defaultSize),
00039       m_fileFormat(4)
00040 {
00041 }
00042 
00043 bool SgGameReader::GetIntProp(const SgGameReader::RawProperties& properties,
00044                               const string& label, int& value)
00045 {
00046     RawProperties::const_iterator it = properties.find(label);
00047     if (it == properties.end() || it->second.size() == 0)
00048         return false;
00049     istringstream in(it->second[0]);
00050     in >> value;
00051     return in;
00052 }
00053 
00054 /** Create SgProp instances and add them to node.
00055     The only properties that are interpreted by the reader are SZ (board size)
00056     and GM (point format, because they must be handled before all other root
00057     node properties to parse points correctly.
00058 */
00059 void SgGameReader::HandleProperties(SgNode* node,
00060                                     const RawProperties& properties,
00061                                     int& boardSize, SgPropPointFmt& fmt)
00062 {
00063     int value;
00064     if (GetIntProp(properties, "SZ", value))
00065     {
00066        if (value < SG_MIN_SIZE || value > SG_MAX_SIZE)
00067            m_warnings.set(INVALID_BOARDSIZE);
00068        else
00069            boardSize = value;
00070     }
00071     if (GetIntProp(properties, "GM", value))
00072         fmt = SgPropUtil::GetPointFmt(value);
00073     for (RawProperties::const_iterator it = properties.begin();
00074          it != properties.end(); ++it)
00075     {
00076         const string& label = it->first;
00077         const vector<string>& values = it->second;
00078         if (values.size() == 0)
00079             m_warnings.set(PROPERTY_WITHOUT_VALUE);
00080         SgProp* prop;
00081         SgPropID id = SgProp::GetIDOfLabel(label);
00082         if (id != SG_PROP_NONE)
00083             prop = SgProp::CreateProperty(id);
00084         else
00085             prop =
00086                 new SgPropUnknown(SG_PROP_UNKNOWN, label, vector<string>());
00087         if (prop->FromString(values, boardSize, fmt))
00088             node->Add(prop);
00089     }
00090 }
00091 
00092 void SgGameReader::PrintWarnings(ostream& out) const
00093 {
00094     Warnings warnings = m_warnings;
00095     // Print more severe warnings first, less severe warnings later
00096     PrintWarning(out, warnings, INVALID_BOARDSIZE, "Invalid board size");
00097     PrintWarning(out, warnings, PROPERTY_WITHOUT_VALUE,
00098                  "Property withour value");
00099     SG_ASSERT(warnings.none());
00100 }
00101 
00102 SgNode* SgGameReader::ReadGame(bool resetWarnings)
00103 {
00104     if (resetWarnings)
00105         m_warnings.reset();
00106     SgNode* root = 0;
00107     int c;
00108     while ((c = m_in.get()) != EOF)
00109     {
00110         while (c != '(' && c != EOF)
00111             c = m_in.get();
00112         if (c == EOF)
00113             break;
00114         root = ReadSubtree(0, m_defaultSize, SG_PROPPOINTFMT_GO);
00115         if (root)
00116             root = root->Root();
00117         if (root)
00118             break;
00119     }
00120     return root;
00121 }
00122 
00123 void SgGameReader::ReadGames(SgVectorOf<SgNode>* rootList)
00124 {
00125     m_warnings.reset();
00126     SG_ASSERT(rootList);
00127     rootList->Clear();
00128     while (true)
00129     {
00130         SgNode* root = ReadGame(false);
00131         if (root)
00132             rootList->PushBack(root);
00133         else
00134             break;
00135     }
00136 }
00137 
00138 string SgGameReader::ReadLabel(int c)
00139 {
00140     // Precondition: Character 'c' is in range 'A'..'Z', to be interpreted
00141     // as the first letter of a property label. Second letter can be capital
00142     // letter or digit, lower case letters are ignored.
00143     string label;
00144     label += static_cast<char>(c);
00145     while ((c = m_in.get()) != EOF
00146            && (('A' <= c && c <= 'Z')
00147                || ('a' <= c && c <= 'z')
00148                || ('0' <= c && c <= '9')))
00149         label += static_cast<char>(c);
00150     if (c != EOF)
00151         m_in.unget();
00152     return label;
00153 }
00154 
00155 SgNode* SgGameReader::ReadSubtree(SgNode* node, int boardSize,
00156                                   SgPropPointFmt fmt)
00157 {
00158     RawProperties properties;
00159     int c;
00160     while ((c = m_in.get()) != EOF && c != ')')
00161     {
00162         if ('A' <= c && c <= 'Z')
00163         {
00164             string label = ReadLabel(c);
00165             m_in >> ws;
00166             string value;
00167             while (ReadValue(value))
00168                 properties[label].push_back(value);
00169         }
00170         else if (c == ';')
00171         {
00172             if (node)
00173             {
00174                 HandleProperties(node, properties, boardSize, fmt);
00175                 properties.clear();
00176                 node = node->NewRightMostSon();
00177             }
00178             else
00179                 node = new SgNode(); // first node
00180         }
00181         else if (c == '(')
00182         {
00183             HandleProperties(node, properties, boardSize, fmt);
00184             properties.clear();
00185             ReadSubtree(node, boardSize, fmt);
00186         }
00187     }
00188     HandleProperties(node, properties, boardSize, fmt);
00189     return node;
00190 }
00191 
00192 bool SgGameReader::ReadValue(string& value)
00193 {
00194     m_in >> ws;
00195     value = "";
00196     int c;
00197     if ((c = m_in.get()) == EOF)
00198         return false;
00199     if (c != '[')
00200     {
00201         m_in.unget();
00202         return false;
00203     }
00204     bool inEscape = false;
00205     while ((c = m_in.get()) != EOF && (c != ']' || inEscape))
00206     {
00207         if (c != '\n')
00208             value += static_cast<char>(c);
00209         if (inEscape)
00210             inEscape = false;
00211         else if (c == '\\')
00212             inEscape = true;
00213     }
00214     return true;
00215 }
00216 
00217 //----------------------------------------------------------------------------


17 Jun 2010 Doxygen 1.4.7