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