Line data Source code
1 : /*
2 : * Copyright (c) 1999-2002 Shane Hudson
3 : * Copyright (c) 2006-2009 Pascal Georges
4 : * Copyright (C) 2014-2016 Fulvio Benini
5 :
6 : * This file is part of Scid (Shane's Chess Information Database).
7 : *
8 : * Scid is free software: you can redistribute it and/or modify
9 : * it under the terms of the GNU General Public License as published by
10 : * the Free Software Foundation.
11 : *
12 : * Scid is distributed in the hope that it will be useful,
13 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : * GNU General Public License for more details.
16 : *
17 : * You should have received a copy of the GNU General Public License
18 : * along with Scid. If not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include "index.h"
22 : #include "namebase.h"
23 : #include <cstring>
24 :
25 : static constexpr char INDEX_MAGIC[8] = "Scid.si";
26 :
27 128 : void Index::Init ()
28 : {
29 128 : Header.numGames = 0;
30 128 : Header.version = SCID_VERSION;
31 128 : Header.baseType = 0;
32 128 : Header.autoLoad = 1;
33 128 : Header.description[0] = 0;
34 128 : std::memset(Header.customFlagDesc, 0, sizeof(Header.customFlagDesc));
35 128 : Header.dirty_ = false;
36 128 : FilePtr = NULL;
37 128 : fileMode_ = FMODE_Memory;
38 128 : nInvalidNameId_ = 0;
39 128 : seqWrite_ = 0;
40 128 : entries_.resize(0);
41 128 : }
42 :
43 78 : errorT Index::Clear ()
44 : {
45 78 : errorT res = flush();
46 78 : delete FilePtr;
47 78 : Init();
48 78 : return res;
49 : }
50 :
51 : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
52 : // Index::CreateIndexFile():
53 : // Creates and opens a new empty index file.
54 : //
55 : errorT
56 6 : Index::Create(const char* filename)
57 : {
58 6 : ASSERT(filename != 0);
59 :
60 6 : Clear();
61 6 : FilePtr = new Filebuf;
62 12 : std::string fname = filename;
63 6 : fname += INDEX_SUFFIX;
64 : //Check that the file does not exists and then create it
65 12 : if (FilePtr->Open(fname.c_str(), FMODE_ReadOnly) == OK ||
66 6 : FilePtr->Open(fname.c_str(), FMODE_Create) != OK) {
67 0 : delete FilePtr;
68 0 : FilePtr = NULL;
69 0 : return ERROR_FileOpen;
70 : }
71 6 : fileMode_ = FMODE_Both;
72 6 : return WriteHeader();
73 : }
74 :
75 : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
76 : // Index::Open():
77 : // Open an index file and read the header.
78 : //
79 : errorT
80 8 : Index::Open (const char* filename, fileModeT fmode)
81 : {
82 8 : ASSERT(filename != 0);
83 :
84 8 : Clear();
85 8 : if (fmode == FMODE_WriteOnly) return ERROR_FileMode;
86 7 : FilePtr = new Filebuf;
87 14 : std::string fname = filename;
88 7 : fname += INDEX_SUFFIX;
89 :
90 7 : if (FilePtr->Open (fname.c_str(), fmode) != OK) {
91 0 : delete FilePtr;
92 0 : FilePtr = NULL;
93 0 : return ERROR_FileOpen;
94 : }
95 :
96 : char magic[8];
97 7 : FilePtr->sgetn(magic, 8);
98 7 : if (!std::equal(std::begin(magic), std::end(magic), std::begin(INDEX_MAGIC),
99 : std::end(INDEX_MAGIC))) {
100 0 : delete FilePtr;
101 0 : FilePtr = NULL;
102 0 : return ERROR_BadMagic;
103 : }
104 :
105 7 : Header.version = FilePtr->ReadTwoBytes ();
106 7 : if (Header.version < SCID_OLDEST_VERSION || Header.version > SCID_VERSION) {
107 0 : delete FilePtr;
108 0 : FilePtr = NULL;
109 0 : return ERROR_FileVersion;
110 : }
111 7 : if (Header.version != SCID_VERSION && fmode != FMODE_ReadOnly) {
112 : //Old versions must be opened readonly
113 0 : delete FilePtr;
114 0 : FilePtr = NULL;
115 0 : return ERROR_FileMode;
116 : }
117 :
118 7 : Header.baseType = FilePtr->ReadFourBytes ();
119 7 : Header.numGames = FilePtr->ReadThreeBytes ();
120 7 : Header.autoLoad = FilePtr->ReadThreeBytes ();
121 7 : FilePtr->sgetn(Header.description, SCID_DESC_LENGTH + 1);
122 7 : Header.description[SCID_DESC_LENGTH] = 0;
123 7 : if (Header.version >= 400) {
124 49 : for (uint i = 0 ; i < CUSTOM_FLAG_MAX ; i++ ) {
125 42 : FilePtr->sgetn(Header.customFlagDesc[i], CUSTOM_FLAG_DESC_LENGTH + 1);
126 42 : Header.customFlagDesc[i][CUSTOM_FLAG_DESC_LENGTH] = 0;
127 : }
128 : }
129 :
130 7 : fileMode_ = fmode;
131 7 : return OK;
132 : }
133 :
134 : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
135 : // Index::WriteHeader():
136 : // Write the header to the open index file.
137 : //
138 : errorT
139 9 : Index::WriteHeader ()
140 : {
141 9 : ASSERT(FilePtr != NULL);
142 9 : if (FilePtr->pubseekpos(0) != std::streampos(0)) return ERROR_FileWrite;
143 :
144 9 : seqWrite_ = 0;
145 9 : std::streamsize n = 0;
146 9 : n += FilePtr->sputn(INDEX_MAGIC, 8);
147 9 : n += FilePtr->WriteTwoBytes (Header.version);
148 9 : n += FilePtr->WriteFourBytes (Header.baseType);
149 9 : n += FilePtr->WriteThreeBytes (Header.numGames);
150 9 : n += FilePtr->WriteThreeBytes (Header.autoLoad);
151 9 : n += FilePtr->sputn(Header.description, SCID_DESC_LENGTH + 1);
152 63 : for (size_t i = 0 ; i < CUSTOM_FLAG_MAX ; i++ ) {
153 54 : n += FilePtr->sputn(Header.customFlagDesc[i], CUSTOM_FLAG_DESC_LENGTH + 1);
154 : }
155 9 : if (n != INDEX_HEADER_SIZE || FilePtr->pubsync() == -1) return ERROR_FileWrite;
156 9 : Header.dirty_ = false;
157 9 : return OK;
158 : }
159 :
160 12018 : errorT Index::WriteEntry(const IndexEntry* ie, gamenumT idx)
161 : {
162 12018 : if (idx > Header.numGames) return ERROR_BadArg;
163 12018 : if (fileMode_ == FMODE_ReadOnly) { return ERROR_FileMode; }
164 :
165 12018 : if (idx == Header.numGames) {
166 10017 : entries_.push_back(*ie);
167 10017 : Header.numGames++;
168 10017 : Header.dirty_ = true;
169 : } else {
170 2001 : IndexEntry* copyToMemory = &(entries_[idx]);
171 2001 : *copyToMemory = *ie;
172 : }
173 12018 : if (FilePtr == NULL) return OK;
174 :
175 4000 : if ((seqWrite_ == 0) || (idx != seqWrite_ + 1)) {
176 1004 : std::streampos pos = INDEX_ENTRY_SIZE * idx + INDEX_HEADER_SIZE;
177 1004 : if (FilePtr->pubseekpos(pos) != pos) {
178 0 : seqWrite_ = 0;
179 0 : return ERROR_FileWrite;
180 : }
181 : }
182 4000 : errorT res = ie->Write (FilePtr, Header.version);
183 4000 : seqWrite_ = (res == OK) ? idx : 0;
184 4000 : return res;
185 : }
186 :
187 : //////////////////////////////////////////////////////////////////////
188 : // EOF: index.cpp
189 : //////////////////////////////////////////////////////////////////////
190 :
|