1 /*
2  * Copyright (C) 2017  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 @e CodecNative, which is used as base class by native codecs.
22  */
23 
24 #ifndef CODEC_NATIVE_H
25 #define CODEC_NATIVE_H
26 
27 #include "bytebuf.h"
28 #include "codec.h"
29 #include "game.h"
30 #include "index.h"
31 #include "namebase.h"
32 
33 /**
34  * This class stores the pointers to the @e Index and @e NameBase objects used
35  * by a native codec. It also implements the addGame() and saveGame() functions
36  * of the ICodecDatabase interface, splitting them into 2 function calls to a
37  * derived class (CRTP technique):
38  * - dyn_addName() should return the ID corresponding to a name, eventually
39  *   adding the name to the @e nb_ if necessary;
40  * - dyn_addGameData() should stores the data of the game, encoded in native
41  *   format, and returns the offset that can be used to retrieve the data.
42  */
43 template <typename Derived> class CodecNative : public ICodecDatabase {
44 protected:
45 	Index* idx_;
46 	NameBase* nb_;
47 	ByteBuffer bbuf_;
48 
49 protected:
CodecNative()50 	CodecNative() : idx_(0), nb_(0), bbuf_(BBUF_SIZE) {}
51 
52 public: // ICodecDatabase interface
addGame(const IndexEntry * srcIe,const NameBase * srcNb,const byte * srcData,size_t dataLen)53 	errorT addGame(const IndexEntry* srcIe, const NameBase* srcNb,
54 	               const byte* srcData, size_t dataLen) override {
55 		IndexEntry ie = *srcIe;
56 		errorT err = addGameHelper(
57 		    &ie, srcData, dataLen,
58 		    srcNb->GetName(NAME_PLAYER, srcIe->GetWhite()),
59 		    srcNb->GetName(NAME_PLAYER, srcIe->GetBlack()),
60 		    srcNb->GetName(NAME_EVENT, srcIe->GetEvent()),
61 		    srcNb->GetName(NAME_SITE, srcIe->GetSite()),
62 		    srcNb->GetName(NAME_ROUND, srcIe->GetRound()));
63 		if (err != OK)
64 			return err;
65 
66 		return derived()->dyn_addIndexEntry(ie);
67 	}
68 
addGame(Game * game)69 	errorT addGame(Game* game) override {
70 		std::pair<errorT, IndexEntry> ie = addGameHelper(game);
71 		if (ie.first != OK)
72 			return ie.first;
73 
74 		return derived()->dyn_addIndexEntry(ie.second);
75 	}
76 
saveGame(Game * game,gamenumT replaced)77 	errorT saveGame(Game* game, gamenumT replaced) override {
78 		if (replaced >= idx_->GetNumGames())
79 			return ERROR_BadArg;
80 
81 		std::pair<errorT, IndexEntry> ie = addGameHelper(game);
82 		if (ie.first != OK)
83 			return ie.first;
84 
85 		return derived()->dyn_saveIndexEntry(ie.second, replaced);
86 	}
87 
saveIndexEntry(const IndexEntry & ie,gamenumT replaced)88 	errorT saveIndexEntry(const IndexEntry& ie, gamenumT replaced) override {
89 		return derived()->dyn_saveIndexEntry(ie, replaced);
90 	}
91 
addName(nameT nt,const char * name)92 	std::pair<errorT, idNumberT> addName(nameT nt, const char* name) override {
93 		return derived()->dyn_addName(nt, name);
94 	}
95 
96 private:
addGameHelper(Game * game)97 	std::pair<errorT, IndexEntry> addGameHelper(Game* game) {
98 		std::pair<errorT, IndexEntry> res;
99 		res.second.Init();
100 		res.first = game->Encode(&bbuf_, &res.second);
101 		if (res.first == OK) {
102 			res.first = addGameHelper(&res.second, bbuf_.getData(),
103 			                          bbuf_.GetByteCount(), game->GetWhiteStr(),
104 			                          game->GetBlackStr(), game->GetEventStr(),
105 			                          game->GetSiteStr(), game->GetRoundStr());
106 		}
107 		return res;
108 	}
109 
addGameHelper(IndexEntry * ie,const byte * srcData,size_t dataLen,const char * white,const char * black,const char * event,const char * site,const char * round)110 	errorT addGameHelper(IndexEntry* ie, const byte* srcData, size_t dataLen,
111 	                     const char* white, const char* black,
112 	                     const char* event, const char* site,
113 	                     const char* round) {
114 		auto id = derived()->dyn_addName(NAME_PLAYER, white);
115 		if (id.first != OK)
116 			return id.first;
117 		ie->SetWhite(id.second);
118 		nb_->AddElo(id.second, ie->GetWhiteElo());
119 
120 		id = derived()->dyn_addName(NAME_PLAYER, black);
121 		if (id.first != OK)
122 			return id.first;
123 		ie->SetBlack(id.second);
124 		nb_->AddElo(id.second, ie->GetBlackElo());
125 
126 		id = derived()->dyn_addName(NAME_EVENT, event);
127 		if (id.first != OK)
128 			return id.first;
129 		ie->SetEvent(id.second);
130 
131 		id = derived()->dyn_addName(NAME_SITE, site);
132 		if (id.first != OK)
133 			return id.first;
134 		ie->SetSite(id.second);
135 
136 		id = derived()->dyn_addName(NAME_ROUND, round);
137 		if (id.first != OK)
138 			return id.first;
139 		ie->SetRound(id.second);
140 
141 		auto offset = derived()->dyn_addGameData(srcData, dataLen);
142 		if (offset.first == OK) {
143 			ie->SetOffset(offset.second);
144 			ie->SetLength(dataLen);
145 		}
146 		return offset.first;
147 	}
148 
derived()149 	Derived* derived() { return static_cast<Derived*>(this); }
150 };
151 
152 #endif
153