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.fail();
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 void SgGameReader::HandleProperties(SgNode* node,
00059                                     const RawProperties& properties,
00060                                     int& boardSize, SgPropPointFmt& fmt)
00061 {
00062     int value;
00063     if (GetIntProp(properties, "SZ", value))
00064     {
00065        if (value < SG_MIN_SIZE || value > SG_MAX_SIZE)
00066            m_warnings.set(INVALID_BOARDSIZE);
00067        else
00068            boardSize = value;
00069     }
00070     if (GetIntProp(properties, "GM", value))
00071         fmt = SgPropUtil::GetPointFmt(value);
00072     for (RawProperties::const_iterator it = properties.begin();
00073          it != properties.end(); ++it)
00074     {
00075         const string& label = it->first;
00076         const vector<string>& values = it->second;
00077         if (values.size() == 0)
00078             m_warnings.set(PROPERTY_WITHOUT_VALUE);
00079         SgProp* prop;
00080         SgPropID id = SgProp::GetIDOfLabel(label);
00081         if (id != SG_PROP_NONE)
00082             prop = SgProp::CreateProperty(id);
00083         else
00084             prop =
00085                 new SgPropUnknown(SG_PROP_UNKNOWN, label, vector<string>());
00086         if (prop->FromString(values, boardSize, fmt))
00087             node->Add(prop);
00088     }
00089 }
00090 
00091 void SgGameReader::PrintWarnings(ostream& out) const
00092 {
00093     Warnings warnings = m_warnings;
00094     // Print more severe warnings first, less severe warnings later
00095     PrintWarning(out, warnings, INVALID_BOARDSIZE, "Invalid board size");
00096     PrintWarning(out, warnings, PROPERTY_WITHOUT_VALUE,
00097                  "Property withour value");
00098     SG_ASSERT(warnings.none());
00099 }
00100 
00101 SgNode* SgGameReader::ReadGame(bool resetWarnings)
00102 {
00103     if (resetWarnings)
00104         m_warnings.reset();
00105     SgNode* root = 0;
00106     int c;
00107     while ((c = m_in.get()) != EOF)
00108     {
00109         while (c != '(' && c != EOF)
00110             c = m_in.get();
00111         if (c == EOF)
00112             break;
00113         root = ReadSubtree(0, m_defaultSize, SG_PROPPOINTFMT_GO);
00114         if (root)
00115             root = root->Root();
00116         if (root)
00117             break;
00118     }
00119     return root;
00120 }
00121 
00122 void SgGameReader::ReadGames(SgVectorOf<SgNode>* rootList)
00123 {
00124     m_warnings.reset();
00125     SG_ASSERT(rootList);
00126     rootList->Clear();
00127     while (true)
00128     {
00129         SgNode* root = ReadGame(false);
00130         if (root)
00131             rootList->PushBack(root);
00132         else
00133             break;
00134     }
00135 }
00136 
00137 string SgGameReader::ReadLabel(int c)
00138 {
00139     // Precondition: Character 'c' is in range 'A'..'Z', to be interpreted
00140     // as the first letter of a property label. Second letter can be capital
00141     // letter or digit, lower case letters are ignored.
00142     string label;
00143     label += static_cast<char>(c);
00144     while ((c = m_in.get()) != EOF
00145            && (('A' <= c && c <= 'Z')
00146                || ('a' <= c && c <= 'z')
00147                || ('0' <= c && c <= '9')))
00148         label += static_cast<char>(c);
00149     if (c != EOF)
00150         m_in.unget();
00151     return label;
00152 }
00153 
00154 SgNode* SgGameReader::ReadSubtree(SgNode* node, int boardSize,
00155                                   SgPropPointFmt fmt)
00156 {
00157     RawProperties properties;
00158     int c;
00159     while ((c = m_in.get()) != EOF && c != ')')
00160     {
00161         if ('A' <= c && c <= 'Z')
00162         {
00163             string label = ReadLabel(c);
00164             m_in >> ws;
00165             string value;
00166             while (ReadValue(value))
00167                 properties[label].push_back(value);
00168         }
00169         else if (c == ';')
00170         {
00171             if (node)
00172             {
00173                 HandleProperties(node, properties, boardSize, fmt);
00174                 properties.clear();
00175                 node = node->NewRightMostSon();
00176             }
00177             else
00178                 node = new SgNode(); // first node
00179         }
00180         else if (c == '(')
00181         {
00182             HandleProperties(node, properties, boardSize, fmt);
00183             properties.clear();
00184             ReadSubtree(node, boardSize, fmt);
00185         }
00186     }
00187     HandleProperties(node, properties, boardSize, fmt);
00188     return node;
00189 }
00190 
00191 bool SgGameReader::ReadValue(string& value)
00192 {
00193     m_in >> ws;
00194     value = "";
00195     int c;
00196     if ((c = m_in.get()) == EOF)
00197         return false;
00198     if (c != '[')
00199     {
00200         m_in.unget();
00201         return false;
00202     }
00203     bool inEscape = false;
00204     while ((c = m_in.get()) != EOF && (c != ']' || inEscape))
00205     {
00206         if (c != '\n')
00207             value += static_cast<char>(c);
00208         if (inEscape)
00209             inEscape = false;
00210         else if (c == '\\')
00211             inEscape = true;
00212     }
00213     return true;
00214 }
00215 
00216 //----------------------------------------------------------------------------


Sun Mar 13 2011 Doxygen 1.7.1