/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. |