LCOV - code coverage report
Current view: top level - src - codec_scid4.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 31 57 54.4 %
Date: 2019-01-29 11:06:41 Functions: 10 11 90.9 %

          Line data    Source code
       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 CodecSCID4 class that manages databases encoded in SCID
      22             :  * format v4.
      23             :  */
      24             : 
      25             : #ifndef CODEC_SCID4_H
      26             : #define CODEC_SCID4_H
      27             : 
      28             : #include "codec_native.h"
      29             : #include "filebuf.h"
      30             : #include <limits>
      31             : 
      32             : /**
      33             :  * This class manages databases encoded in SCID format v4.
      34             :  */
      35          48 : class CodecSCID4 : public CodecNative<CodecSCID4> {
      36             :         std::vector<std::string> filenames_;
      37             :         FilebufAppend gfile_;
      38             :         char gamecache_[1ULL << 17];
      39             : 
      40             :         enum : uint64_t {
      41             :                 LIMIT_GAMEOFFSET = 1ULL << 32,
      42             :                 LIMIT_GAMELEN = 1ULL << 17,
      43             :                 LIMIT_NUMGAMES = 16777214ULL, // Three bytes -1 because GetAutoLoad uses
      44             :                                               // 0 to mean "no autoload"
      45             :                 LIMIT_NAMELEN = 255
      46             :         };
      47             : 
      48             : public: // ICodecDatabase interface
      49           3 :         Codec getType() const final { return ICodecDatabase::SCID4; }
      50             : 
      51             :         /**
      52             :          * Returns the full path of the three files (index, namebase and gamefile)
      53             :          * used by the database.
      54             :          */
      55           9 :         std::vector<std::string> getFilenames() const final { return filenames_; };
      56             : 
      57             :         std::vector<std::pair<const char*, std::string>>
      58           0 :         getExtraInfo() const final {
      59           0 :                 std::vector<std::pair<const char*, std::string>> res;
      60           0 :                 res.emplace_back("type", std::to_string(idx_->GetType()));
      61           0 :                 res.emplace_back("description", idx_->GetDescription());
      62           0 :                 res.emplace_back("autoload", std::to_string(idx_->GetAutoLoad()));
      63           0 :                 res.emplace_back("flag1",
      64           0 :                                  idx_->GetCustomFlagDesc(IndexEntry::IDX_FLAG_CUSTOM1));
      65           0 :                 res.emplace_back("flag2",
      66           0 :                                  idx_->GetCustomFlagDesc(IndexEntry::IDX_FLAG_CUSTOM2));
      67           0 :                 res.emplace_back("flag3",
      68           0 :                                  idx_->GetCustomFlagDesc(IndexEntry::IDX_FLAG_CUSTOM3));
      69           0 :                 res.emplace_back("flag4",
      70           0 :                                  idx_->GetCustomFlagDesc(IndexEntry::IDX_FLAG_CUSTOM4));
      71           0 :                 res.emplace_back("flag5",
      72           0 :                                  idx_->GetCustomFlagDesc(IndexEntry::IDX_FLAG_CUSTOM5));
      73           0 :                 res.emplace_back("flag6",
      74           0 :                                  idx_->GetCustomFlagDesc(IndexEntry::IDX_FLAG_CUSTOM6));
      75           0 :                 return res;
      76             :         }
      77             : 
      78        6000 :         const byte* getGameData(uint64_t offset, uint32_t length) final {
      79        6000 :                 if (offset >= gfile_.size())
      80           0 :                         return NULL;
      81        6000 :                 if (length >= LIMIT_GAMELEN)
      82           0 :                         return NULL;
      83             : 
      84        6000 :                 if (gfile_.pubseekpos(offset) == -1)
      85           0 :                         return NULL;
      86        6000 :                 if (gfile_.sgetn(gamecache_, length) != std::streamsize(length))
      87           0 :                         return NULL;
      88             : 
      89        6000 :                 return reinterpret_cast<const byte*>(gamecache_);
      90             :         }
      91             : 
      92             :         errorT flush() final;
      93             : 
      94             :         errorT dyn_open(fileModeT, const char*, const Progress&, Index*,
      95             :                         NameBase*) final;
      96             : 
      97             : public: // CodecNative interface
      98             :         /**
      99             :          * Stores the data into the .sg4 file.
     100             :          * @param src:    valid pointer to a buffer that contains the game data
     101             :          *                (encoded in native format).
     102             :          * @param length: the length of the buffer @e src (in bytes).
     103             :          * @returns
     104             :          * - on success, a @e std::pair containing OK and the offset of the stored
     105             :          *   data (needed for retrieving the data with getGameData()).
     106             :          * - on failure, a @e std::pair containing an error code and 0.
     107             :          */
     108        4000 :         std::pair<errorT, uint64_t> dyn_addGameData(const byte* src,
     109             :                                                     size_t length) {
     110        4000 :                 ASSERT(src != 0);
     111        4000 :                 const char* data = reinterpret_cast<const char*>(src);
     112             : 
     113        4000 :                 if (length >= LIMIT_GAMELEN)
     114           0 :                         return std::make_pair(ERROR_GameLengthLimit, 0);
     115             : 
     116             :                 // The SCID4 format uses 32-bits to store games' offset.
     117        4000 :                 uint64_t offset = gfile_.size();
     118        4000 :                 if (offset >= LIMIT_GAMEOFFSET - length)
     119           0 :                         return std::make_pair(ERROR_OffsetLimit, 0);
     120             : 
     121             :                 // The SCID4 format stores games into blocks of 128KB.
     122             :                 // If the current block does not have enough space, we fill it with
     123             :                 // random data and use the next one.
     124        4000 :                 uint64_t blockSpace = LIMIT_GAMELEN - (offset % LIMIT_GAMELEN);
     125        4000 :                 if (blockSpace < length) {
     126         795 :                         errorT err = gfile_.append(data, blockSpace);
     127         795 :                         if (err != OK)
     128           0 :                                 return std::make_pair(err, 0);
     129         795 :                         offset += blockSpace;
     130             :                 }
     131             : 
     132        4000 :                 errorT err = gfile_.append(data, length);
     133        4000 :                 return std::make_pair(err, offset);
     134             :         }
     135             : 
     136             :         /**
     137             :          * Given a name (string), retrieve the corresponding ID.
     138             :          * The name is added to @e nb_ if do not already exists in the NameBase.
     139             :          * @param nt:   nameT type of the name to retrieve.
     140             :          * @param name: the name to retrieve.
     141             :          * @returns
     142             :          * - on success, a @e std::pair containing OK and the ID.
     143             :          * - on failure, a @e std::pair containing an error code and 0.
     144             :          */
     145       20000 :         std::pair<errorT, idNumberT> dyn_addName(nameT nt, const char* name) {
     146       20000 :                 const idNumberT MAX_ID[] = {
     147             :                     1048575, /* Player names: Maximum of 2^20 -1 = 1,048,575 */
     148             :                     524287,  /* Event names:  Maximum of 2^19 -1 =   524,287 */
     149             :                     524287,  /* Site names:   Maximum of 2^19 -1 =   524,287 */
     150             :                     262143   /* Round names:  Maximum of 2^18 -1 =   262,143 */
     151             :                 };
     152       20000 :                 return nb_->addName(nt, name, LIMIT_NAMELEN, MAX_ID[nt]);
     153             :         }
     154             : 
     155             :         /**
     156             :          * Add an IndexEntry to @e idx_.
     157             :          * @param ie: the IndexEntry object to add.
     158             :          * @returns OK if successful or an error code.
     159             :          */
     160        3000 :         errorT dyn_addIndexEntry(const IndexEntry& ie) {
     161        3000 :                 auto nGames = idx_->GetNumGames();
     162        3000 :                 if (nGames >= LIMIT_NUMGAMES)
     163           0 :                         return ERROR_NumGamesLimit;
     164             : 
     165        3000 :                 return idx_->WriteEntry(&ie, nGames);
     166             :         }
     167             : 
     168             :         /**
     169             :          * Replace an IndexEntry.
     170             :          * @param ie:       the IndexEntry with the new data.
     171             :          * @param replaced: valid gamenumT of the game to be replaced.
     172             :          * @returns OK if successful or an error code.
     173             :          */
     174        1000 :         errorT dyn_saveIndexEntry(const IndexEntry& ie, gamenumT replaced) {
     175        1000 :                 return idx_->WriteEntry(&ie, replaced);
     176             :         }
     177             : 
     178             : private:
     179             :         errorT readIndex(const Progress& progress);
     180             : };
     181             : 
     182             : #endif

Generated by: LCOV version 1.13