Coverage Report

Created: 2026-10-28 06:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tesseract/src/ccutil/serialis.cpp
Line
Count
Source
1
/**********************************************************************
2
 * File:        serialis.cpp  (Formerly serialmac.h)
3
 * Description: Inline routines and macros for serialisation functions
4
 * Author:      Phil Cheatle
5
 *
6
 * (C) Copyright 1990, Hewlett-Packard Ltd.
7
 ** Licensed under the Apache License, Version 2.0 (the "License");
8
 ** you may not use this file except in compliance with the License.
9
 ** You may obtain a copy of the License at
10
 ** http://www.apache.org/licenses/LICENSE-2.0
11
 ** Unless required by applicable law or agreed to in writing, software
12
 ** distributed under the License is distributed on an "AS IS" BASIS,
13
 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 ** See the License for the specific language governing permissions and
15
 ** limitations under the License.
16
 *
17
 **********************************************************************/
18
19
#include "serialis.h"
20
21
#include "errcode.h"
22
23
#include "helpers.h" // for ReverseN
24
25
#include <climits> // for INT_MAX
26
#include <cstdio>
27
28
namespace tesseract {
29
30
// The default FileReader loads the whole file into the vector of char,
31
// returning false on error.
32
4
bool LoadDataFromFile(const char *filename, std::vector<char> *data) {
33
4
  bool result = false;
34
4
  FILE *fp = fopen(filename, "rb");
35
4
  if (fp != nullptr) {
36
4
    fseek(fp, 0, SEEK_END);
37
4
    auto size = std::ftell(fp);
38
4
    fseek(fp, 0, SEEK_SET);
39
    // Trying to open a directory on Linux sets size to LONG_MAX. Catch it here.
40
4
    if (size > 0 && size < LONG_MAX) {
41
      // reserve an extra byte in case caller wants to append a '\0' character
42
4
      data->reserve(size + 1);
43
4
      data->resize(size); // TODO: optimize no init
44
4
      result = static_cast<long>(fread(&(*data)[0], 1, size, fp)) == size;
45
4
    }
46
4
    fclose(fp);
47
4
  }
48
4
  return result;
49
4
}
50
51
// The default FileWriter writes the vector of char to the filename file,
52
// returning false on error.
53
0
bool SaveDataToFile(const std::vector<char> &data, const char *filename) {
54
0
  FILE *fp = fopen(filename, "wb");
55
0
  if (fp == nullptr) {
56
0
    return false;
57
0
  }
58
0
  bool result = fwrite(&data[0], 1, data.size(), fp) == data.size();
59
0
  fclose(fp);
60
0
  return result;
61
0
}
62
63
60
TFile::TFile() {
64
60
}
65
66
60
TFile::~TFile() {
67
60
  if (data_is_owned_) {
68
56
    delete data_;
69
56
  }
70
60
}
71
72
0
bool TFile::DeSerializeSize(int32_t *pSize) {
73
0
  uint32_t size;
74
0
  if (FReadEndian(&size, sizeof(size), 1) != 1) {
75
0
    return false;
76
0
  }
77
0
  if (size > data_->size() / 4) {
78
    // Reverse endianness.
79
0
    swap_ = !swap_;
80
0
    ReverseN(&size, 4);
81
0
  }
82
0
  *pSize = size;
83
0
  return true;
84
0
}
85
86
0
bool TFile::DeSerializeSkip(size_t size) {
87
0
  uint32_t len;
88
0
  if (!DeSerialize(&len)) {
89
0
    return false;
90
0
  }
91
  // Check for overflow: len * size must not overflow size_t.
92
0
  if (size != 0 && len > SIZE_MAX / size) {
93
0
    return false;
94
0
  }
95
0
  return Skip(len * size);
96
0
}
97
98
108
bool TFile::DeSerialize(std::string &data) {
99
108
  uint32_t size;
100
108
  if (!DeSerialize(&size)) {
101
0
    return false;
102
108
  } else if (size > 50000000) {
103
    // Arbitrarily limit the size to protect against bad data.
104
0
    return false;
105
108
  } else if (size > 0) {
106
    // TODO: optimize.
107
108
    data.resize(size);
108
108
    return DeSerialize(&data[0], size);
109
108
  }
110
0
  data.clear();
111
0
  return true;
112
108
}
113
114
0
bool TFile::Serialize(const std::string &data) {
115
0
  uint32_t size = data.size();
116
0
  return Serialize(&size) && Serialize(data.c_str(), size);
117
0
}
118
119
0
bool TFile::DeSerialize(std::vector<char> &data) {
120
0
  uint32_t size;
121
0
  if (!DeSerialize(&size)) {
122
0
    return false;
123
0
  } else if (size > 50000000) {
124
    // Arbitrarily limit the size to protect against bad data.
125
0
    return false;
126
0
  } else if (size > 0) {
127
    // TODO: optimize.
128
0
    data.resize(size);
129
0
    return DeSerialize(&data[0], data.size());
130
0
  }
131
0
  data.clear();
132
0
  return true;
133
0
}
134
135
0
bool TFile::Serialize(const std::vector<char> &data) {
136
0
  uint32_t size = data.size();
137
0
  if (!Serialize(&size)) {
138
0
    return false;
139
0
  } else if (size > 0) {
140
0
    return Serialize(&data[0], size);
141
0
  }
142
0
  return true;
143
0
}
144
145
0
bool TFile::Skip(size_t count) {
146
0
  if (data_ != nullptr) {
147
0
    size_t data_size = data_->size();
148
    // Subtraction-based check to avoid overflow in offset_ + count.
149
0
    if (offset_ >= data_size || count > data_size - offset_) {
150
0
      offset_ = data_size > UINT_MAX ? UINT_MAX : static_cast<unsigned>(data_size);
151
0
      return false;
152
0
    }
153
0
  }
154
0
  offset_ += count;
155
0
  return true;
156
0
}
157
158
0
bool TFile::Open(const char *filename, FileReader reader) {
159
0
  if (!data_is_owned_) {
160
0
    data_ = new std::vector<char>;
161
0
    data_is_owned_ = true;
162
0
  }
163
0
  offset_ = 0;
164
0
  is_writing_ = false;
165
0
  swap_ = false;
166
0
  if (reader == nullptr) {
167
0
    return LoadDataFromFile(filename, data_);
168
0
  } else {
169
0
    return (*reader)(filename, data_);
170
0
  }
171
0
}
172
173
76
bool TFile::Open(const char *data, size_t size) {
174
76
  offset_ = 0;
175
76
  if (!data_is_owned_) {
176
56
    data_ = new std::vector<char>;
177
56
    data_is_owned_ = true;
178
56
  }
179
76
  is_writing_ = false;
180
76
  swap_ = false;
181
76
  data_->resize(size); // TODO: optimize no init
182
76
  memcpy(&(*data_)[0], data, size);
183
76
  return true;
184
76
}
185
186
0
bool TFile::Open(FILE *fp, int64_t end_offset) {
187
0
  offset_ = 0;
188
0
  auto current_pos = std::ftell(fp);
189
0
  if (current_pos < 0) {
190
    // ftell failed.
191
0
    return false;
192
0
  }
193
0
  if (end_offset < 0) {
194
0
    if (fseek(fp, 0, SEEK_END)) {
195
0
      return false;
196
0
    }
197
0
    end_offset = ftell(fp);
198
0
    if (fseek(fp, current_pos, SEEK_SET)) {
199
0
      return false;
200
0
    }
201
0
  }
202
0
  size_t size = end_offset - current_pos;
203
0
  is_writing_ = false;
204
0
  swap_ = false;
205
0
  if (!data_is_owned_) {
206
0
    data_ = new std::vector<char>;
207
0
    data_is_owned_ = true;
208
0
  }
209
0
  data_->resize(size); // TODO: optimize no init
210
0
  return fread(&(*data_)[0], 1, size, fp) == size;
211
0
}
212
213
79.9k
char *TFile::FGets(char *buffer, int buffer_size) {
214
79.9k
  ASSERT_HOST(!is_writing_);
215
79.9k
  int size = 0;
216
799k
  while (size + 1 < buffer_size && offset_ < data_->size()) {
217
799k
    buffer[size++] = (*data_)[offset_++];
218
799k
    if ((*data_)[offset_ - 1] == '\n') {
219
79.9k
      break;
220
79.9k
    }
221
799k
  }
222
79.9k
  if (size < buffer_size) {
223
79.9k
    buffer[size] = '\0';
224
79.9k
  }
225
79.9k
  return size > 0 ? buffer : nullptr;
226
79.9k
}
227
228
204k
size_t TFile::FReadEndian(void *buffer, size_t size, size_t count) {
229
204k
  auto num_read = FRead(buffer, size, count);
230
204k
  if (swap_ && size != 1) {
231
0
    char *char_buffer = static_cast<char *>(buffer);
232
0
    for (size_t i = 0; i < num_read; ++i, char_buffer += size) {
233
0
      ReverseN(char_buffer, size);
234
0
    }
235
0
  }
236
204k
  return num_read;
237
204k
}
238
239
409k
size_t TFile::FRead(void *buffer, size_t size, size_t count) {
240
409k
  ASSERT_HOST(!is_writing_);
241
409k
  ASSERT_HOST(size > 0);
242
409k
  size_t required_size;
243
409k
  if (SIZE_MAX / size <= count) {
244
    // Avoid integer overflow.
245
0
    required_size = data_->size() - offset_;
246
409k
  } else {
247
409k
    required_size = size * count;
248
409k
    if (data_->size() - offset_ < required_size) {
249
0
      required_size = data_->size() - offset_;
250
0
    }
251
409k
  }
252
409k
  if (required_size > 0 && buffer != nullptr) {
253
409k
    memcpy(buffer, &(*data_)[offset_], required_size);
254
409k
  }
255
409k
  offset_ += required_size;
256
409k
  return required_size / size;
257
409k
}
258
259
0
void TFile::Rewind() {
260
0
  ASSERT_HOST(!is_writing_);
261
0
  offset_ = 0;
262
0
}
263
264
0
void TFile::OpenWrite(std::vector<char> *data) {
265
0
  offset_ = 0;
266
0
  if (data != nullptr) {
267
0
    if (data_is_owned_) {
268
0
      delete data_;
269
0
    }
270
0
    data_ = data;
271
0
    data_is_owned_ = false;
272
0
  } else if (!data_is_owned_) {
273
0
    data_ = new std::vector<char>;
274
0
    data_is_owned_ = true;
275
0
  }
276
0
  is_writing_ = true;
277
0
  swap_ = false;
278
0
  data_->clear();
279
0
}
280
281
0
bool TFile::CloseWrite(const char *filename, FileWriter writer) {
282
0
  ASSERT_HOST(is_writing_);
283
0
  if (writer == nullptr) {
284
0
    return SaveDataToFile(*data_, filename);
285
0
  } else {
286
0
    return (*writer)(*data_, filename);
287
0
  }
288
0
}
289
290
0
size_t TFile::FWrite(const void *buffer, size_t size, size_t count) {
291
0
  ASSERT_HOST(is_writing_);
292
0
  ASSERT_HOST(size > 0);
293
0
  ASSERT_HOST(SIZE_MAX / size > count);
294
0
  size_t total = size * count;
295
0
  const char *buf = static_cast<const char *>(buffer);
296
  // This isn't very efficient, but memory is so fast compared to disk
297
  // that it is relatively unimportant, and very simple.
298
0
  for (size_t i = 0; i < total; ++i) {
299
0
    data_->push_back(buf[i]);
300
0
  }
301
0
  return count;
302
0
}
303
304
} // namespace tesseract.