Scid  4.7.0
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
codec_pgn.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2016-2018 Fulvio Benini
3 
4  * This file is part of Scid (Shane's Chess Information Database).
5  *
6  * Scid is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation.
9  *
10  * Scid is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with Scid. If not, see <http://www.gnu.org/licenses/>.
17  *
18  */
19 
20 /** @file
21  * Implements the CodecPgn class, which manages the databases encoded in PGN
22  * format.
23  */
24 
25 #ifndef CODEC_PGN_H
26 #define CODEC_PGN_H
27 
28 #include "codec_proxy.h"
29 #include "common.h"
30 #include "filebuf.h"
31 #include "pgnparse.h"
32 #include <algorithm>
33 #include <cstring>
34 #include <vector>
35 
36 class CodecPgn : public CodecProxy<CodecPgn> {
37  Filebuf file_;
38  std::streamsize fileSize_ = 0;
39  std::string filename_;
40  std::vector<char> buf_;
41  size_t nParsed_ = 0;
42  size_t nRead_ = 0;
43  PgnParseLog parseLog_;
44 
45 public:
46  Codec getType() const final { return ICodecDatabase::PGN; }
47 
48  std::vector<std::string> getFilenames() const final {
49  return std::vector<std::string>(1, filename_);
50  };
51 
52  errorT flush() final {
53  errorT errFile = (file_.pubsync() == 0) ? OK : ERROR_FileWrite;
55  return (errFile != OK) ? errFile : errProxy;
56  }
57 
58  /**
59  * Opens/creates a PGN database.
60  * After successfully opening/creating the file, the object is ready for
61  * parseNext() calls.
62  * @param filename: full path of the pgn file to be opened.
63  * @param fmode: valid file access mode.
64  * @returns OK in case of success, an @e errorT code otherwise.
65  */
66  errorT open(const char* filename, fileModeT fmode) {
67  ASSERT(filename && !file_.is_open());
68  filename_ = filename;
69  if (filename_.empty())
70  return ERROR_FileOpen;
71 
72  errorT err_open = file_.Open(filename, fmode);
73  if (err_open != OK)
74  return err_open;
75 
76  buf_.resize(128 * 1024);
77  nRead_ = nParsed_ = buf_.size();
78  file_.pubsetbuf(nullptr, nRead_); // Optimization
79 
80  fileSize_ = file_.pubseekoff(0, std::ios::end);
81  file_.pubseekpos(0);
82  if (fileSize_ < 0)
83  return ERROR_FileSeek;
84 
85  return OK;
86  }
87 
88  /**
89  * Reads the next game.
90  * @param game: the Game object where the data will be stored.
91  * @returns
92  * - ERROR_NotFound if there are no more games to be read.
93  * - OK otherwise.
94  */
96  const auto verge = 3 * (nRead_ / 4);
97  if (nParsed_ > verge && nRead_ == buf_.size()) {
98  nParsed_ -= verge;
99  nRead_ -= verge;
100  std::copy_n(buf_.data() + verge, nRead_, buf_.data());
101  nRead_ += file_.sgetn(buf_.data() + nRead_, verge);
102  }
103 
104  game.Clear();
105  PgnVisitor visitor(game);
106  auto parse = pgn::parse_game(
107  {buf_.data() + nParsed_, buf_.data() + nRead_}, visitor);
108 
109  bool eof = (nRead_ - nParsed_ == parse.first);
110  if (eof && nRead_ == buf_.size()) {
111  // Reached the end of input, but the file contains more bytes.
112  if (nRead_ <= 128 * 1024 * 1024) {
113  // Double the buffer size and retry.
114  buf_.resize(nRead_ * 2);
115  nRead_ += file_.sgetn(buf_.data() + nRead_, nRead_);
116  return parseNext(game);
117  }
118  // Abort
119  nRead_ = nParsed_ = 0;
120  parseLog_.log.append("PGN parsing aborted.\n");
121  return ERROR_NotFound;
122  }
123 
124  nParsed_ += parse.first;
125  parseLog_.logGame(parse.first, visitor);
126  if (eof && !parse.second && *game.GetMoveComment() == '\0')
127  return ERROR_NotFound;
128 
129  return OK;
130  }
131 
132  /**
133  * Returns info about the parsing progress.
134  * @returns a pair<size_t, size_t> where first element is the quantity of
135  * data parsed and second one is the total amount of data of the database.
136  */
137  std::pair<size_t, size_t> parseProgress() {
138  return std::make_pair(parseLog_.n_bytes / 1024, fileSize_ / 1024);
139  }
140 
141  /**
142  * Returns the list of errors produced by parseNext() calls.
143  */
144  const char* parseErrors() { return parseLog_.log.c_str(); }
145 
146  /**
147  * Add a game into the database.
148  * The @e game is encoded in pgn format and appended at the end of @e file_.
149  * @param game: valid pointer to a Game object with the new data.
150  * @returns OK in case of success, an @e errorT code otherwise.
151  */
153  // buf_.clear();
154  // auto moves_begin = encode(*game, buf_);
155  // Split the range (moves_begin, buf_.size()) into lines
156  // auto sz = static_cast<std::streamsize>(buf_.size());
157 
158  auto old_language = language;
159  language = 0;
163  std::pair<const char*, unsigned> pgn = game->WriteToPGN(75, true);
164  language = old_language;
165 
166  file_.pubseekpos(fileSize_);
167  if (file_.sputn(pgn.first, pgn.second) == pgn.second) {
168  fileSize_ += pgn.second;
169  return OK;
170  }
171  return ERROR_FileWrite;
172  }
173 
174  /**
175  * Encode a game into PGN format.
176  * @param game: the Game object to encode.
177  * @param dest: the container where the PGN Game will be appended.
178  * @returns the size of the tag pairs section.
179  */
180  template <typename TCont> static size_t encode(Game& game, TCont& dest) {
181  size_t tags_size = encodeTags(game, dest);
182  dest.push_back('\n');
183 
184  game.MoveToStart();
185  do {
186  // TODO: comment, variations, etc..
187  const char* next_move = game.GetNextSAN();
188  dest.insert(dest.end(), next_move,
189  next_move + std::strlen(next_move));
190  dest.push_back(' ');
191  } while (game.MoveForwardInPGN() == OK);
192 
193  return tags_size;
194  }
195 
196  template <typename TCont>
197  static size_t encodeTags(Game& game, TCont& dest) {
198  auto format_tag = [&dest](const char* tag, const char* value) {
199  dest.push_back('[');
200  dest.insert(dest.end(), tag, tag + std::strlen(tag));
201  dest.push_back(' ');
202 
203  dest.push_back('"');
204  auto value_begin = dest.size();
205  dest.insert(dest.end(), value, value + std::strlen(value));
206  pgn::escape_string(dest, value_begin);
207  dest.push_back('"');
208 
209  dest.push_back(']');
210  dest.push_back('\n');
211  };
212  auto format_tag_question_mark = [&format_tag](const char* tag,
213  const char* value) {
214  format_tag(tag, (*value) ? value : "?");
215  };
216 
217  size_t tags_size = dest.size();
218  gamevisit::tags_STR(game, format_tag_question_mark);
219  gamevisit::tags_extra(game, format_tag);
220  return dest.size() - tags_size;
221  }
222 };
223 
224 #endif
errorT flush() final
Writes all pending output to the files.
Definition: codec_pgn.h:52
#define PGN_STYLE_COMMENTS
Definition: game.h:145
std::pair< std::size_t, bool > parse_game(pgn_impl::InputMemory input, TVisitor &&parser)
Read a PGN game from memory, grouping characters in tokens and dispatching them to a PGN parser...
Definition: pgn_lexer.h:371
void tags_extra(const Game &game, TFunc visitor)
Definition: game.h:486
const errorT OK
Definition: error.h:23
Format and store errors.
Definition: pgnparse.h:332
const char * GetNextSAN()
Definition: game.cpp:1676
std::vector< std::string > getFilenames() const final
Returns the full path of the files used by the database.
Definition: codec_pgn.h:48
errorT gameAdd(Game *game)
Add a game into the database.
Definition: codec_pgn.h:152
const errorT ERROR_FileWrite
Definition: error.h:32
#define ASSERT(f)
Definition: common.h:59
This class implements a PGN "visitor" that invokes the appropriate member functions of the associated...
Definition: pgnparse.h:39
const char * GetMoveComment() const
Definition: game.h:357
bool logGame(size_t nBytes, const PgnVisitor &visitor)
Format and store errors occurred while parsing a Game.
Definition: pgnparse.h:343
#define PGN_STYLE_VARS
Definition: game.h:146
Codec getType() const final
Returns the Codec type.
Definition: codec_pgn.h:46
errorT MoveForwardInPGN()
Definition: game.cpp:829
void MoveToStart()
Definition: game.cpp:815
std::pair< size_t, size_t > parseProgress()
Returns info about the parsing progress.
Definition: codec_pgn.h:137
std::pair< const char *, unsigned > WriteToPGN(uint lineWidth=0, bool NewLineAtEnd=false, bool newLineToSpaces=true)
Definition: game.cpp:2563
errorT Open(const char *filename, fileModeT fmode)
Opens a file.
Definition: filebuf.h:43
#define PGN_STYLE_SCIDFLAGS
Definition: game.h:153
Implements a parser that converts PGN text into SCID&#39;s Game objects.
Implements the CodecProxy class, which serves as base class for non-native databases.
static size_t encode(Game &game, TCont &dest)
Encode a game into PGN format.
Definition: codec_pgn.h:180
unsigned long long n_bytes
Definition: pgnparse.h:334
void SetPgnFormat(gameFormatT gf)
Definition: game.h:433
unsigned short errorT
Definition: error.h:20
int language
Definition: game.cpp:28
static size_t encodeTags(Game &game, TCont &dest)
Definition: codec_pgn.h:197
Base class for non-native databases.
Definition: codec_proxy.h:48
Definition: game.h:167
errorT parseNext(Game &game)
Reads the next game.
Definition: codec_pgn.h:95
const errorT ERROR_FileSeek
Definition: error.h:34
errorT flush() override
Writes all pending output to the files.
Definition: codec_memory.h:66
Adds some helper functions to std::filebuf:
Definition: filebuf.h:35
void tags_STR(const Game &game, TFunc visitor)
Definition: game.h:474
void Clear()
Definition: game.cpp:541
errorT open(const char *filename, fileModeT fmode)
Opens/creates a PGN database.
Definition: codec_pgn.h:66
Extends the std:filebuf class with performance improvements.
void escape_string(TString &str, std::size_t pos)
Escape quote and backslash chars according to the PGN standard: "A quote inside a string is represent...
Definition: pgn_lexer.h:453
fileModeT
Definition: common.h:136
const errorT ERROR_NotFound
Definition: error.h:50
Definition: pgn_lexer.h:359
const errorT ERROR_FileOpen
Definition: error.h:31
const char * parseErrors()
Returns the list of errors produced by parseNext() calls.
Definition: codec_pgn.h:144
#define PGN_STYLE_TAGS
Definition: game.h:144
std::string log
Definition: pgnparse.h:333
void ResetPgnStyle(void)
Definition: game.h:423