/src/gdal/frmts/miramon/miramon_band.cpp
Line | Count | Source |
1 | | /****************************************************************************** |
2 | | * |
3 | | * Project: MiraMonRaster driver |
4 | | * Purpose: Implements MMRBand class: This class manages the metadata of each |
5 | | * band to be processed. It is useful for maintaining a list of bands |
6 | | * and for determining the number of subdatasets that need to be |
7 | | * generated. |
8 | | * Author: Abel Pau |
9 | | * |
10 | | ****************************************************************************** |
11 | | * Copyright (c) 2025, Xavier Pons |
12 | | * |
13 | | * SPDX-License-Identifier: MIT |
14 | | ****************************************************************************/ |
15 | | #include <algorithm> |
16 | | #include <limits> |
17 | | #include "gdal_rat.h" |
18 | | |
19 | | #include "miramon_rel.h" |
20 | | #include "miramon_band.h" |
21 | | |
22 | | #include "../miramon_common/mm_gdal_functions.h" // For MM_CreateDBFHeader |
23 | | |
24 | | /************************************************************************/ |
25 | | /* MMRBand() */ |
26 | | /************************************************************************/ |
27 | | MMRBand::MMRBand(MMRRel &fRel, const CPLString &osBandSectionIn) |
28 | 6.51k | : m_pfRel(&fRel), m_nWidth(0), m_nHeight(0), |
29 | 6.51k | m_osBandSection(osBandSectionIn) |
30 | 6.51k | { |
31 | | // Getting band and band file name from metadata. |
32 | 6.51k | CPLString osNomFitxer; |
33 | 6.51k | osNomFitxer = SECTION_ATTRIBUTE_DATA; |
34 | 6.51k | osNomFitxer.append(":"); |
35 | 6.51k | osNomFitxer.append(osBandSectionIn); |
36 | 6.51k | if (!m_pfRel->GetMetadataValue(osNomFitxer, KEY_NomFitxer, |
37 | 6.51k | m_osRawBandFileName) || |
38 | 4.32k | m_osRawBandFileName.empty()) |
39 | 2.19k | { |
40 | | // A band name may be empty only if it is the only band present |
41 | | // in the REL file. Otherwise, inferring the band name from the |
42 | | // REL filename is considered an error. |
43 | | // Consequently, for a REL file containing exactly one band, if |
44 | | // the band name is empty, it shall be inferred from the REL |
45 | | // filename. |
46 | | // Example: REL: testI.rel --> IMG: test.img |
47 | 2.19k | if (m_pfRel->GetNBands() >= 1) |
48 | 43 | m_osBandFileName = ""; |
49 | 2.15k | else |
50 | 2.15k | { |
51 | 2.15k | m_osBandFileName = m_pfRel->MMRGetFileNameFromRelName( |
52 | 2.15k | m_pfRel->GetRELName(), pszExtRaster); |
53 | 2.15k | } |
54 | | |
55 | 2.19k | if (m_osBandFileName.empty()) |
56 | 43 | { |
57 | 43 | m_nWidth = 0; |
58 | 43 | m_nHeight = 0; |
59 | 43 | CPLError(CE_Failure, CPLE_AssertionFailed, |
60 | 43 | "The REL file '%s' contains a documented \ |
61 | 43 | band with no explicit or wrong name. Section [%s] or [%s:%s].", |
62 | 43 | m_pfRel->GetRELNameChar(), SECTION_ATTRIBUTE_DATA, |
63 | 43 | SECTION_ATTRIBUTE_DATA, m_osBandSection.c_str()); |
64 | 43 | return; |
65 | 43 | } |
66 | 2.15k | m_osBandName = CPLGetBasenameSafe(m_osBandFileName); |
67 | 2.15k | m_osRawBandFileName = m_osBandName; |
68 | 2.15k | } |
69 | 4.32k | else |
70 | 4.32k | { |
71 | 4.32k | m_osBandName = CPLGetBasenameSafe(m_osRawBandFileName); |
72 | 4.32k | CPLString osAux = CPLGetPathSafe(m_pfRel->GetRELNameChar()); |
73 | 4.32k | m_osBandFileName = |
74 | 4.32k | CPLFormFilenameSafe(osAux.c_str(), m_osRawBandFileName.c_str(), ""); |
75 | | |
76 | 4.32k | CPLString osExtension = |
77 | 4.32k | CPLString(CPLGetExtensionSafe(m_osBandFileName).c_str()); |
78 | 4.32k | if (!EQUAL(osExtension, pszExtRaster + 1)) |
79 | 120 | return; |
80 | 4.32k | } |
81 | | |
82 | | // There is a band file documented? |
83 | 6.35k | if (m_osBandName.empty()) |
84 | 0 | { |
85 | 0 | m_nWidth = 0; |
86 | 0 | m_nHeight = 0; |
87 | 0 | CPLError(CE_Failure, CPLE_AssertionFailed, |
88 | 0 | "The REL file '%s' contains a documented \ |
89 | 0 | band with no explicit name. Section [%s] or [%s:%s].", |
90 | 0 | m_pfRel->GetRELNameChar(), SECTION_ATTRIBUTE_DATA, |
91 | 0 | SECTION_ATTRIBUTE_DATA, m_osBandSection.c_str()); |
92 | 0 | return; |
93 | 0 | } |
94 | | |
95 | | // Getting essential metadata documented at |
96 | | // https://www.miramon.cat/new_note/eng/notes/MiraMon_raster_file_format.pdf |
97 | | |
98 | | // Getting number of columns and rows |
99 | 6.35k | if (!UpdateColumnsNumberFromREL(m_osBandSection)) |
100 | 40 | { |
101 | 40 | m_nWidth = 0; |
102 | 40 | m_nHeight = 0; |
103 | 40 | return; |
104 | 40 | } |
105 | | |
106 | 6.31k | if (!UpdateRowsNumberFromREL(m_osBandSection)) |
107 | 12 | { |
108 | 12 | m_nWidth = 0; |
109 | 12 | m_nHeight = 0; |
110 | 12 | return; |
111 | 12 | } |
112 | | |
113 | 6.30k | if (m_nWidth <= 0 || m_nHeight <= 0) |
114 | 11 | { |
115 | 11 | m_nWidth = 0; |
116 | 11 | m_nHeight = 0; |
117 | 11 | CPLError(CE_Failure, CPLE_AppDefined, |
118 | 11 | "MMRBand::MMRBand : (nWidth <= 0 || nHeight <= 0)"); |
119 | 11 | return; |
120 | 11 | } |
121 | | |
122 | | // Getting data type and compression. |
123 | | // If error, message given inside. |
124 | 6.28k | if (!UpdateDataTypeFromREL(m_osBandSection)) |
125 | 204 | return; |
126 | | |
127 | | // Let's see if there is RLE compression |
128 | 6.08k | m_bIsCompressed = |
129 | 6.08k | (((m_eMMDataType >= MMDataType::DATATYPE_AND_COMPR_BYTE_RLE) && |
130 | 5.66k | (m_eMMDataType <= MMDataType::DATATYPE_AND_COMPR_DOUBLE_RLE)) || |
131 | 424 | m_eMMDataType == MMDataType::DATATYPE_AND_COMPR_BIT); |
132 | | |
133 | | // Getting min and max values |
134 | 6.08k | UpdateMinMaxValuesFromREL(m_osBandSection); |
135 | | |
136 | | // Getting unit type |
137 | 6.08k | UpdateUnitTypeValueFromREL(m_osBandSection); |
138 | | |
139 | | // Getting min and max values for simbolization |
140 | 6.08k | UpdateMinMaxVisuValuesFromREL(m_osBandSection); |
141 | 6.08k | if (!m_bMinVisuSet) |
142 | 6.08k | { |
143 | 6.08k | if (m_bMinSet) |
144 | 1.49k | { |
145 | 1.49k | m_dfVisuMin = m_dfMin; |
146 | 1.49k | m_bMinVisuSet = true; |
147 | 1.49k | } |
148 | 6.08k | } |
149 | 6.08k | if (!m_bMaxVisuSet) |
150 | 6.08k | { |
151 | 6.08k | if (m_bMaxSet) |
152 | 221 | { |
153 | 221 | m_dfVisuMax = m_dfMax; |
154 | 221 | m_bMaxVisuSet = true; |
155 | 221 | } |
156 | 6.08k | } |
157 | | |
158 | | // Getting the friendly description of the band |
159 | 6.08k | UpdateFriendlyDescriptionFromREL(m_osBandSection); |
160 | | |
161 | | // Getting NoData value and definition |
162 | 6.08k | UpdateNoDataValue(m_osBandSection); |
163 | | |
164 | | // Getting reference system and coordinates of the geographic bounding box |
165 | 6.08k | UpdateReferenceSystemFromREL(); |
166 | | |
167 | | // Getting the bounding box: coordinates in the terrain |
168 | 6.08k | UpdateBoundingBoxFromREL(m_osBandSection); |
169 | | |
170 | | // Getting all information about simbolization |
171 | 6.08k | UpdateSimbolizationInfo(m_osBandSection); |
172 | | |
173 | | // Getting all information about RAT |
174 | 6.08k | UpdateRATInfo(m_osBandSection); |
175 | | |
176 | | // MiraMon IMG files are efficient in going to an specified row. |
177 | | // So le'ts configurate the blocks as line blocks. |
178 | 6.08k | m_nBlockXSize = m_nWidth; |
179 | 6.08k | m_nBlockYSize = 1; |
180 | 6.08k | m_nNRowsPerBlock = 1; |
181 | | |
182 | | // Can the binary file that contains all data for this band be opened? |
183 | 6.08k | m_pfIMG = VSIFOpenL(m_osBandFileName, "rb"); |
184 | 6.08k | if (!m_pfIMG) |
185 | 2.57k | { |
186 | 2.57k | m_nWidth = 0; |
187 | 2.57k | m_nHeight = 0; |
188 | 2.57k | CPLError(CE_Failure, CPLE_OpenFailed, |
189 | 2.57k | "Failed to open MiraMon band file `%s' with access 'rb'.", |
190 | 2.57k | m_osBandFileName.c_str()); |
191 | 2.57k | return; |
192 | 2.57k | } |
193 | | |
194 | | // We have a valid MMRBand. |
195 | 3.50k | m_bIsValid = true; |
196 | 3.50k | } |
197 | | |
198 | | /************************************************************************/ |
199 | | /* ~MMRBand() */ |
200 | | /************************************************************************/ |
201 | | MMRBand::~MMRBand() |
202 | 6.51k | { |
203 | 6.51k | if (m_pfIMG == nullptr) |
204 | 3.00k | return; |
205 | | |
206 | 3.50k | CPL_IGNORE_RET_VAL(VSIFCloseL(m_pfIMG)); |
207 | 3.50k | m_pfIMG = nullptr; |
208 | 3.50k | } |
209 | | |
210 | | const CPLString MMRBand::GetRELFileName() const |
211 | 137 | { |
212 | 137 | if (!m_pfRel) |
213 | 0 | return ""; |
214 | 137 | return m_pfRel->GetRELName(); |
215 | 137 | } |
216 | | |
217 | | /************************************************************************/ |
218 | | /* GetRasterBlock() */ |
219 | | /************************************************************************/ |
220 | | CPLErr MMRBand::GetRasterBlock(int /*nXBlock*/, int nYBlock, void *pData, |
221 | | int nDataSize) |
222 | | |
223 | 38.5k | { |
224 | 38.5k | if (nYBlock > INT_MAX / (std::max(1, m_nNRowsPerBlock))) |
225 | 0 | { |
226 | 0 | CPLError(CE_Failure, CPLE_OutOfMemory, "Error in GetRasterBlock"); |
227 | 0 | return CE_Failure; |
228 | 0 | } |
229 | 38.5k | const int iBlock = nYBlock * m_nNRowsPerBlock; |
230 | | |
231 | 38.5k | if (m_nBlockXSize > INT_MAX / (std::max(1, m_nDataTypeSizeBytes))) |
232 | 0 | { |
233 | 0 | CPLError(CE_Failure, CPLE_OutOfMemory, "Error in GetRasterBlock"); |
234 | 0 | return CE_Failure; |
235 | 0 | } |
236 | | |
237 | 38.5k | if (m_nBlockYSize > |
238 | 38.5k | INT_MAX / (std::max(1, m_nDataTypeSizeBytes * m_nBlockXSize))) |
239 | 0 | { |
240 | 0 | CPLError(CE_Failure, CPLE_OutOfMemory, "Error in GetRasterBlock"); |
241 | 0 | return CE_Failure; |
242 | 0 | } |
243 | | |
244 | 38.5k | const int nGDALBlockSize = |
245 | 38.5k | m_nDataTypeSizeBytes * m_nBlockXSize * m_nBlockYSize; |
246 | | |
247 | | // Calculate block offset in case we have spill file. Use predefined |
248 | | // block map otherwise. |
249 | | |
250 | 38.5k | if (nDataSize != -1 && nGDALBlockSize > nDataSize) |
251 | 0 | { |
252 | 0 | CPLError(CE_Failure, CPLE_AppDefined, "Invalid block size: %d", |
253 | 0 | nGDALBlockSize); |
254 | 0 | return CE_Failure; |
255 | 0 | } |
256 | | |
257 | | // Getting the row offsets to optimize access. |
258 | 38.5k | if (FillRowOffsets() == false || m_aFileOffsets.empty()) |
259 | 66 | { |
260 | 66 | CPLError(CE_Failure, CPLE_AppDefined, |
261 | 66 | "Some error in offsets calculation"); |
262 | 66 | return CE_Failure; |
263 | 66 | } |
264 | | |
265 | | // Read the block in the documented or deduced offset |
266 | 38.5k | if (VSIFSeekL(m_pfIMG, m_aFileOffsets[iBlock], SEEK_SET)) |
267 | 1 | { |
268 | 1 | CPLError(CE_Failure, CPLE_AppDefined, |
269 | 1 | "Read from invalid offset for grid block."); |
270 | 1 | return CE_Failure; |
271 | 1 | } |
272 | | |
273 | 38.5k | size_t nCompressedRawSize; |
274 | 38.5k | if (iBlock == m_nHeight - 1) |
275 | 818 | nCompressedRawSize = SIZE_MAX; // We don't know it |
276 | 37.6k | else |
277 | 37.6k | nCompressedRawSize = static_cast<size_t>(m_aFileOffsets[iBlock + 1] - |
278 | 37.6k | m_aFileOffsets[iBlock]); |
279 | | |
280 | 38.5k | return GetBlockData(pData, nCompressedRawSize); |
281 | 38.5k | } |
282 | | |
283 | | void MMRBand::UpdateGeoTransform() |
284 | 3.27k | { |
285 | 3.27k | m_gt.xorig = GetBoundingBoxMinX(); |
286 | 3.27k | m_gt.xscale = (GetBoundingBoxMaxX() - m_gt.xorig) / GetWidth(); |
287 | 3.27k | m_gt.xrot = 0.0; // No rotation in MiraMon rasters |
288 | 3.27k | m_gt.yorig = GetBoundingBoxMaxY(); |
289 | 3.27k | m_gt.yrot = 0.0; |
290 | 3.27k | m_gt.yscale = (GetBoundingBoxMinY() - m_gt.yorig) / GetHeight(); |
291 | 3.27k | } |
292 | | |
293 | | /************************************************************************/ |
294 | | /* Other functions */ |
295 | | /************************************************************************/ |
296 | | |
297 | | // [ATTRIBUTE_DATA:xxxx] or [OVERVIEW:ASPECTES_TECNICS] |
298 | | bool MMRBand::Get_ATTRIBUTE_DATA_or_OVERVIEW_ASPECTES_TECNICS_int( |
299 | | const CPLString &osSection, const char *pszKey, int *nValue, |
300 | | const char *pszErrorMessage) |
301 | 12.6k | { |
302 | 12.6k | if (osSection.empty() || !pszKey || !nValue) |
303 | 0 | return false; |
304 | | |
305 | 12.6k | CPLString osValue; |
306 | 12.6k | if (!m_pfRel->GetMetadataValue(SECTION_ATTRIBUTE_DATA, osSection, pszKey, |
307 | 12.6k | osValue) || |
308 | 6.45k | osValue.empty()) |
309 | 6.27k | { |
310 | 6.27k | if (m_pfRel->GetMetadataValue(SECTION_OVERVIEW, |
311 | 6.27k | SECTION_ASPECTES_TECNICS, pszKey, |
312 | 6.27k | osValue) == false || |
313 | 6.23k | osValue.empty()) |
314 | 45 | { |
315 | 45 | if (pszErrorMessage) |
316 | 45 | CPLError(CE_Failure, CPLE_AppDefined, "%s", pszErrorMessage); |
317 | 45 | return false; |
318 | 45 | } |
319 | 6.27k | } |
320 | | |
321 | 12.6k | if (1 != sscanf(osValue, "%d", nValue)) |
322 | 7 | { |
323 | 7 | if (pszErrorMessage) |
324 | 7 | CPLError(CE_Failure, CPLE_AppDefined, "%s", pszErrorMessage); |
325 | 7 | return false; |
326 | 7 | } |
327 | 12.6k | return true; |
328 | 12.6k | } |
329 | | |
330 | | bool MMRBand::GetDataTypeAndBytesPerPixel(const char *pszCompType, |
331 | | MMDataType *nCompressionType, |
332 | | MMBytesPerPixel *nBytesPerPixel) |
333 | 6.27k | { |
334 | 6.27k | if (!nCompressionType || !nBytesPerPixel || !pszCompType) |
335 | 0 | return false; |
336 | | |
337 | 6.27k | if (EQUAL(pszCompType, "bit")) |
338 | 58 | { |
339 | 58 | *nCompressionType = MMDataType::DATATYPE_AND_COMPR_BIT; |
340 | 58 | *nBytesPerPixel = MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_BYTE_I_RLE; |
341 | 58 | return true; |
342 | 58 | } |
343 | 6.21k | if (EQUAL(pszCompType, "byte")) |
344 | 203 | { |
345 | 203 | *nCompressionType = MMDataType::DATATYPE_AND_COMPR_BYTE; |
346 | 203 | *nBytesPerPixel = MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_BYTE_I_RLE; |
347 | 203 | return true; |
348 | 203 | } |
349 | 6.01k | if (EQUAL(pszCompType, "byte-RLE")) |
350 | 3.77k | { |
351 | 3.77k | *nCompressionType = MMDataType::DATATYPE_AND_COMPR_BYTE_RLE; |
352 | 3.77k | *nBytesPerPixel = MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_BYTE_I_RLE; |
353 | 3.77k | return true; |
354 | 3.77k | } |
355 | 2.24k | if (EQUAL(pszCompType, "integer")) |
356 | 26 | { |
357 | 26 | *nCompressionType = MMDataType::DATATYPE_AND_COMPR_INTEGER; |
358 | 26 | *nBytesPerPixel = MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_INTEGER_I_RLE; |
359 | 26 | return true; |
360 | 26 | } |
361 | 2.21k | if (EQUAL(pszCompType, "integer-RLE")) |
362 | 357 | { |
363 | 357 | *nCompressionType = MMDataType::DATATYPE_AND_COMPR_INTEGER_RLE; |
364 | 357 | *nBytesPerPixel = MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_INTEGER_I_RLE; |
365 | 357 | return true; |
366 | 357 | } |
367 | 1.85k | if (EQUAL(pszCompType, "uinteger")) |
368 | 9 | { |
369 | 9 | *nCompressionType = MMDataType::DATATYPE_AND_COMPR_UINTEGER; |
370 | 9 | *nBytesPerPixel = MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_INTEGER_I_RLE; |
371 | 9 | return true; |
372 | 9 | } |
373 | 1.84k | if (EQUAL(pszCompType, "uinteger-RLE")) |
374 | 380 | { |
375 | 380 | *nCompressionType = MMDataType::DATATYPE_AND_COMPR_UINTEGER_RLE; |
376 | 380 | *nBytesPerPixel = MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_INTEGER_I_RLE; |
377 | 380 | return true; |
378 | 380 | } |
379 | 1.46k | if (EQUAL(pszCompType, "long")) |
380 | 14 | { |
381 | 14 | *nCompressionType = MMDataType::DATATYPE_AND_COMPR_LONG; |
382 | 14 | *nBytesPerPixel = MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_LONG_REAL_I_RLE; |
383 | 14 | return true; |
384 | 14 | } |
385 | 1.45k | if (EQUAL(pszCompType, "long-RLE")) |
386 | 296 | { |
387 | 296 | *nCompressionType = MMDataType::DATATYPE_AND_COMPR_LONG_RLE; |
388 | 296 | *nBytesPerPixel = MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_LONG_REAL_I_RLE; |
389 | 296 | return true; |
390 | 296 | } |
391 | 1.15k | if (EQUAL(pszCompType, "real")) |
392 | 63 | { |
393 | 63 | *nCompressionType = MMDataType::DATATYPE_AND_COMPR_REAL; |
394 | 63 | *nBytesPerPixel = MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_LONG_REAL_I_RLE; |
395 | 63 | return true; |
396 | 63 | } |
397 | 1.09k | if (EQUAL(pszCompType, "real-RLE")) |
398 | 296 | { |
399 | 296 | *nCompressionType = MMDataType::DATATYPE_AND_COMPR_REAL_RLE; |
400 | 296 | *nBytesPerPixel = MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_LONG_REAL_I_RLE; |
401 | 296 | return true; |
402 | 296 | } |
403 | 799 | if (EQUAL(pszCompType, "double")) |
404 | 51 | { |
405 | 51 | *nCompressionType = MMDataType::DATATYPE_AND_COMPR_DOUBLE; |
406 | 51 | *nBytesPerPixel = MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_DOUBLE_I_RLE; |
407 | 51 | return true; |
408 | 51 | } |
409 | 748 | if (EQUAL(pszCompType, "double-RLE")) |
410 | 557 | { |
411 | 557 | *nCompressionType = MMDataType::DATATYPE_AND_COMPR_DOUBLE_RLE; |
412 | 557 | *nBytesPerPixel = MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_DOUBLE_I_RLE; |
413 | 557 | return true; |
414 | 557 | } |
415 | | |
416 | 191 | return false; |
417 | 748 | } |
418 | | |
419 | | // Getting data type from metadata |
420 | | bool MMRBand::UpdateDataTypeFromREL(const CPLString osSection) |
421 | 6.28k | { |
422 | 6.28k | m_eMMDataType = MMDataType::DATATYPE_AND_COMPR_UNDEFINED; |
423 | 6.28k | m_eMMBytesPerPixel = MMBytesPerPixel::TYPE_BYTES_PER_PIXEL_UNDEFINED; |
424 | | |
425 | 6.28k | CPLString osValue; |
426 | 6.28k | if (!m_pfRel->GetMetadataValue(SECTION_ATTRIBUTE_DATA, osSection, |
427 | 6.28k | "TipusCompressio", osValue) || |
428 | 6.27k | osValue.empty()) |
429 | 13 | { |
430 | 13 | m_nWidth = 0; |
431 | 13 | m_nHeight = 0; |
432 | 13 | CPLError(CE_Failure, CPLE_AppDefined, |
433 | 13 | "MiraMonRaster: no nDataType documented"); |
434 | 13 | return false; |
435 | 13 | } |
436 | | |
437 | 6.27k | if (!GetDataTypeAndBytesPerPixel(osValue.c_str(), &m_eMMDataType, |
438 | 6.27k | &m_eMMBytesPerPixel)) |
439 | 191 | { |
440 | 191 | m_nWidth = 0; |
441 | 191 | m_nHeight = 0; |
442 | 191 | CPLError(CE_Failure, CPLE_AppDefined, |
443 | 191 | "MiraMonRaster: data type unhandled"); |
444 | 191 | return false; |
445 | 191 | } |
446 | | |
447 | 6.08k | m_nDataTypeSizeBytes = std::max(1, static_cast<int>(m_eMMBytesPerPixel)); |
448 | 6.08k | return true; |
449 | 6.27k | } |
450 | | |
451 | | // Getting number of columns from metadata |
452 | | bool MMRBand::UpdateColumnsNumberFromREL(const CPLString &osSection) |
453 | 6.35k | { |
454 | 6.35k | return Get_ATTRIBUTE_DATA_or_OVERVIEW_ASPECTES_TECNICS_int( |
455 | 6.35k | osSection, "columns", &m_nWidth, |
456 | 6.35k | "MMRBand::MMRBand : No number of columns documented"); |
457 | 6.35k | } |
458 | | |
459 | | bool MMRBand::UpdateRowsNumberFromREL(const CPLString &osSection) |
460 | 6.31k | { |
461 | 6.31k | return Get_ATTRIBUTE_DATA_or_OVERVIEW_ASPECTES_TECNICS_int( |
462 | 6.31k | osSection, "rows", &m_nHeight, |
463 | 6.31k | "MMRBand::MMRBand : No number of rows documented"); |
464 | 6.31k | } |
465 | | |
466 | | // Getting nodata value from metadata |
467 | | void MMRBand::UpdateNoDataValue(const CPLString &osSection) |
468 | 6.08k | { |
469 | 6.08k | CPLString osValue; |
470 | 6.08k | if (!m_pfRel->GetMetadataValue(SECTION_ATTRIBUTE_DATA, osSection, "NODATA", |
471 | 6.08k | osValue) || |
472 | 368 | osValue.empty()) |
473 | 5.90k | { |
474 | 5.90k | m_dfNoData = 0; // No a valid value. |
475 | 5.90k | m_bNoDataSet = false; |
476 | 5.90k | } |
477 | 179 | else |
478 | 179 | { |
479 | 179 | m_dfNoData = CPLAtof(osValue); |
480 | 179 | m_bNoDataSet = true; |
481 | 179 | } |
482 | 6.08k | } |
483 | | |
484 | | void MMRBand::UpdateMinMaxValuesFromREL(const CPLString &osSection) |
485 | 6.08k | { |
486 | 6.08k | m_bMinSet = false; |
487 | | |
488 | 6.08k | CPLString osValue; |
489 | | |
490 | 6.08k | CPLString osAuxSection = SECTION_ATTRIBUTE_DATA; |
491 | 6.08k | osAuxSection.append(":"); |
492 | 6.08k | osAuxSection.append(osSection); |
493 | 6.08k | if (m_pfRel->GetMetadataValue(osAuxSection, "min", osValue) && |
494 | 1.60k | !osValue.empty()) |
495 | 1.56k | { |
496 | 1.56k | if (1 == CPLsscanf(osValue, "%lf", &m_dfMin)) |
497 | 1.53k | m_bMinSet = true; |
498 | 1.56k | } |
499 | | |
500 | 6.08k | m_bMaxSet = false; |
501 | 6.08k | if (m_pfRel->GetMetadataValue(osAuxSection, "max", osValue) && |
502 | 427 | !osValue.empty()) |
503 | 421 | { |
504 | 421 | if (1 == CPLsscanf(osValue, "%lf", &m_dfMax)) |
505 | 255 | m_bMaxSet = true; |
506 | 421 | } |
507 | | |
508 | | // Special case: dfMin > dfMax |
509 | 6.08k | if (m_bMinSet && m_bMaxSet && m_dfMin > m_dfMax) |
510 | 34 | { |
511 | 34 | m_bMinSet = false; |
512 | 34 | m_bMaxSet = false; |
513 | 34 | } |
514 | 6.08k | } |
515 | | |
516 | | void MMRBand::UpdateUnitTypeValueFromREL(const CPLString &osSection) |
517 | 6.08k | { |
518 | 6.08k | CPLString osValue; |
519 | | |
520 | 6.08k | CPLString osAuxSection = SECTION_ATTRIBUTE_DATA; |
521 | 6.08k | osAuxSection.append(":"); |
522 | 6.08k | osAuxSection.append(osSection); |
523 | 6.08k | if (m_pfRel->GetMetadataValue(osAuxSection, "unitats", osValue) && |
524 | 0 | !osValue.empty()) |
525 | 0 | { |
526 | 0 | m_osBandUnitType = osValue; |
527 | 0 | } |
528 | 6.08k | } |
529 | | |
530 | | void MMRBand::UpdateMinMaxVisuValuesFromREL(const CPLString &osSection) |
531 | 6.08k | { |
532 | 6.08k | m_bMinVisuSet = false; |
533 | 6.08k | m_dfVisuMin = 1; |
534 | | |
535 | 6.08k | CPLString osValue; |
536 | 6.08k | if (m_pfRel->GetMetadataValue(SECTION_COLOR_TEXT, osSection, |
537 | 6.08k | "Color_ValorColor_0", osValue) && |
538 | 0 | !osValue.empty()) |
539 | 0 | { |
540 | 0 | if (1 == CPLsscanf(osValue, "%lf", &m_dfVisuMin)) |
541 | 0 | m_bMinVisuSet = true; |
542 | 0 | } |
543 | | |
544 | 6.08k | m_bMaxVisuSet = false; |
545 | 6.08k | m_dfVisuMax = 1; |
546 | | |
547 | 6.08k | if (m_pfRel->GetMetadataValue(SECTION_COLOR_TEXT, osSection, |
548 | 6.08k | "Color_ValorColor_n_1", osValue) && |
549 | 0 | !osValue.empty()) |
550 | 0 | { |
551 | 0 | if (1 == CPLsscanf(osValue, "%lf", &m_dfVisuMax)) |
552 | 0 | m_bMaxVisuSet = true; |
553 | 0 | } |
554 | 6.08k | } |
555 | | |
556 | | void MMRBand::UpdateFriendlyDescriptionFromREL(const CPLString &osSection) |
557 | 6.08k | { |
558 | | // This "if" is due to CID 1620830 in Coverity Scan |
559 | 6.08k | if (!m_pfRel->GetMetadataValue(SECTION_ATTRIBUTE_DATA, osSection, |
560 | 6.08k | KEY_descriptor, m_osFriendlyDescription)) |
561 | 4.86k | m_osFriendlyDescription = ""; |
562 | 6.08k | } |
563 | | |
564 | | void MMRBand::UpdateReferenceSystemFromREL() |
565 | 6.08k | { |
566 | | // This "if" is due to CID 1620842 in Coverity Scan |
567 | 6.08k | if (!m_pfRel->GetMetadataValue("SPATIAL_REFERENCE_SYSTEM:HORIZONTAL", |
568 | 6.08k | "HorizontalSystemIdentifier", m_osRefSystem)) |
569 | 6.02k | m_osRefSystem = ""; |
570 | 6.08k | } |
571 | | |
572 | | void MMRBand::UpdateBoundingBoxFromREL(const CPLString &osSection) |
573 | 6.08k | { |
574 | | // Bounding box of the band |
575 | | // [ATTRIBUTE_DATA:xxxx:EXTENT] or [EXTENT] |
576 | 6.08k | CPLString osValue; |
577 | 6.08k | if (!m_pfRel->GetMetadataValue(SECTION_ATTRIBUTE_DATA, osSection, |
578 | 6.08k | SECTION_EXTENT, "MinX", osValue) || |
579 | 1.72k | osValue.empty()) |
580 | 4.38k | { |
581 | 4.38k | m_dfBBMinX = 0; |
582 | 4.38k | } |
583 | 1.70k | else |
584 | 1.70k | { |
585 | 1.70k | if (1 != CPLsscanf(osValue, "%lf", &m_dfBBMinX)) |
586 | 738 | m_dfBBMinX = 0; |
587 | 1.70k | } |
588 | | |
589 | 6.08k | if (!m_pfRel->GetMetadataValue(SECTION_ATTRIBUTE_DATA, osSection, |
590 | 6.08k | SECTION_EXTENT, "MaxX", osValue) || |
591 | 672 | osValue.empty()) |
592 | 5.43k | { |
593 | 5.43k | m_dfBBMaxX = m_nWidth; |
594 | 5.43k | } |
595 | 652 | else |
596 | 652 | { |
597 | 652 | if (1 != CPLsscanf(osValue, "%lf", &m_dfBBMaxX)) |
598 | 63 | { |
599 | | // If the value is something that cannot be scanned, |
600 | | // we silently continue as it was undefined. |
601 | 63 | m_dfBBMaxX = m_nWidth; |
602 | 63 | } |
603 | 652 | } |
604 | | |
605 | 6.08k | if (!m_pfRel->GetMetadataValue(SECTION_ATTRIBUTE_DATA, osSection, |
606 | 6.08k | SECTION_EXTENT, "MinY", osValue) || |
607 | 1.31k | osValue.empty()) |
608 | 4.77k | { |
609 | 4.77k | m_dfBBMinY = 0; |
610 | 4.77k | } |
611 | 1.31k | else |
612 | 1.31k | { |
613 | 1.31k | if (1 != CPLsscanf(osValue, "%lf", &m_dfBBMinY)) |
614 | 46 | m_dfBBMinY = 0; |
615 | 1.31k | } |
616 | | |
617 | 6.08k | if (!m_pfRel->GetMetadataValue(SECTION_ATTRIBUTE_DATA, osSection, |
618 | 6.08k | SECTION_EXTENT, "MaxY", osValue) || |
619 | 874 | osValue.empty()) |
620 | 5.22k | { |
621 | 5.22k | m_dfBBMaxY = m_nHeight; |
622 | 5.22k | } |
623 | 863 | else |
624 | 863 | { |
625 | 863 | if (1 != CPLsscanf(osValue, "%lf", &m_dfBBMaxY)) |
626 | 94 | { |
627 | | // If the value is something that cannot be scanned, |
628 | | // we silently continue as it was undefined. |
629 | 94 | m_dfBBMaxY = m_nHeight; |
630 | 94 | } |
631 | 863 | } |
632 | 6.08k | } |
633 | | |
634 | | void MMRBand::UpdateSimbolizationInfo(const CPLString &osSection) |
635 | 6.08k | { |
636 | 6.08k | m_pfRel->GetMetadataValue(SECTION_COLOR_TEXT, osSection, "Color_Const", |
637 | 6.08k | m_osColor_Const); |
638 | | |
639 | 6.08k | if (EQUAL(m_osColor_Const, "1")) |
640 | 9 | { |
641 | 9 | if (CE_None == m_pfRel->UpdateGDALColorEntryFromBand( |
642 | 9 | osSection, m_sConstantColorRGB)) |
643 | 9 | m_osValidColorConst = true; |
644 | 9 | } |
645 | | |
646 | 6.08k | m_pfRel->GetMetadataValue(SECTION_COLOR_TEXT, osSection, "Color_Paleta", |
647 | 6.08k | m_osColor_Paleta); |
648 | | |
649 | | // Treatment of the color variable |
650 | 6.08k | m_pfRel->GetMetadataValue(SECTION_COLOR_TEXT, osSection, |
651 | 6.08k | "Color_TractamentVariable", |
652 | 6.08k | m_osColor_TractamentVariable); |
653 | | |
654 | 6.08k | m_pfRel->GetMetadataValue(SECTION_ATTRIBUTE_DATA, osSection, |
655 | 6.08k | KEY_TractamentVariable, m_osTractamentVariable); |
656 | | |
657 | | // Is categorical? |
658 | 6.08k | if (m_osTractamentVariable.empty()) |
659 | 5.15k | { |
660 | 5.15k | m_bIsCategorical = false; |
661 | 5.15k | } |
662 | 926 | else |
663 | 926 | { |
664 | 926 | if (EQUAL(m_osTractamentVariable, "Categoric")) |
665 | 310 | m_bIsCategorical = true; |
666 | 616 | else |
667 | 616 | m_bIsCategorical = false; |
668 | 926 | } |
669 | | |
670 | 6.08k | m_pfRel->GetMetadataValue(SECTION_COLOR_TEXT, osSection, |
671 | 6.08k | "Color_EscalatColor", m_osColor_EscalatColor); |
672 | | |
673 | 6.08k | m_pfRel->GetMetadataValue(SECTION_COLOR_TEXT, osSection, |
674 | 6.08k | "Color_N_SimbolsALaTaula", |
675 | 6.08k | m_osColor_N_SimbolsALaTaula); |
676 | 6.08k | } |
677 | | |
678 | | void MMRBand::UpdateRATInfo(const CPLString &osSection) |
679 | 6.08k | { |
680 | 6.08k | CPLString os_IndexJoin; |
681 | | |
682 | 6.08k | if (!m_pfRel->GetMetadataValue(SECTION_ATTRIBUTE_DATA, osSection, |
683 | 6.08k | "IndexsJoinTaula", os_IndexJoin) || |
684 | 94 | os_IndexJoin.empty()) |
685 | 5.99k | { |
686 | 5.99k | return; |
687 | 5.99k | } |
688 | | |
689 | | // Let's see if there is any table that can ve converted to RAT |
690 | 94 | const CPLStringList aosTokens(CSLTokenizeString2(os_IndexJoin, ",", 0)); |
691 | 94 | const int nTokens = CSLCount(aosTokens); |
692 | 94 | if (nTokens < 1) |
693 | 0 | return; |
694 | | |
695 | 94 | CPLString os_Join = "JoinTaula"; |
696 | 94 | os_Join.append("_"); |
697 | 94 | os_Join.append(aosTokens[0]); |
698 | | |
699 | 94 | CPLString osTableNameSection_value; |
700 | 94 | if (!m_pfRel->GetMetadataValue(SECTION_ATTRIBUTE_DATA, osSection, os_Join, |
701 | 94 | osTableNameSection_value) || |
702 | 18 | osTableNameSection_value.empty()) |
703 | 76 | return; |
704 | | |
705 | 18 | CPLString osTableNameSection = "TAULA_"; |
706 | 18 | osTableNameSection.append(osTableNameSection_value); |
707 | | |
708 | 18 | if (!m_pfRel->GetMetadataValue(osTableNameSection, KEY_NomFitxer, |
709 | 18 | m_osShortRATName) || |
710 | 8 | m_osShortRATName.empty()) |
711 | 10 | { |
712 | 10 | m_osAssociateREL = ""; |
713 | 10 | return; |
714 | 10 | } |
715 | | |
716 | 8 | m_pfRel->GetMetadataValue(osTableNameSection, "AssociatRel", |
717 | 8 | m_osAssociateREL); |
718 | 8 | } |
719 | | |
720 | | /************************************************************************/ |
721 | | /* Functions that read bytes from IMG file band */ |
722 | | /************************************************************************/ |
723 | | template <typename TYPE> |
724 | | CPLErr MMRBand::UncompressRow(void *rowBuffer, size_t nCompressedRawSize) |
725 | 40.3M | { |
726 | 40.3M | int nAccumulated = 0L, nIAccumulated = 0L; |
727 | 40.3M | unsigned char cCounter; |
728 | 40.3M | size_t nCompressedIndex = 0; |
729 | | |
730 | 40.3M | TYPE RLEValue; |
731 | 40.3M | TYPE *pDst; |
732 | 40.3M | size_t sizeof_TYPE = sizeof(TYPE); |
733 | | |
734 | 40.3M | std::vector<unsigned char> aCompressedRow; |
735 | | |
736 | 40.3M | if (nCompressedRawSize != SIZE_MAX) |
737 | 5.48k | { |
738 | 5.48k | if (nCompressedRawSize > 1000 * 1000 && |
739 | 479 | GetFileSize() < nCompressedRawSize) |
740 | 427 | { |
741 | 427 | CPLError(CE_Failure, CPLE_AppDefined, "Too small file"); |
742 | 427 | return CE_Failure; |
743 | 427 | } |
744 | 5.06k | try |
745 | 5.06k | { |
746 | 5.06k | aCompressedRow.resize(nCompressedRawSize); |
747 | 5.06k | } |
748 | 5.06k | catch (const std::exception &) |
749 | 5.06k | { |
750 | 0 | CPLError(CE_Failure, CPLE_OutOfMemory, |
751 | 0 | "Out of memory allocating working buffer"); |
752 | 0 | return CE_Failure; |
753 | 0 | } |
754 | 5.06k | if (VSIFReadL(aCompressedRow.data(), nCompressedRawSize, 1, m_pfIMG) != |
755 | 5.06k | 1) |
756 | 25 | return CE_Failure; |
757 | 5.06k | } |
758 | | |
759 | 189M | while (nAccumulated < m_nWidth) |
760 | 189M | { |
761 | 189M | if (nCompressedRawSize == SIZE_MAX) |
762 | 116M | { |
763 | 116M | if (VSIFReadL(&cCounter, 1, 1, m_pfIMG) != 1) |
764 | 40.1M | return CE_Failure; |
765 | 116M | } |
766 | 73.3M | else |
767 | 73.3M | { |
768 | 73.3M | if (nCompressedIndex >= aCompressedRow.size()) |
769 | 204 | { |
770 | 204 | CPLError(CE_Failure, CPLE_AppDefined, |
771 | 204 | "Invalid nCompressedIndex"); |
772 | 204 | return CE_Failure; |
773 | 204 | } |
774 | 73.3M | cCounter = aCompressedRow[nCompressedIndex]; |
775 | 73.3M | nCompressedIndex++; |
776 | 73.3M | } |
777 | | |
778 | 149M | if (cCounter == 0) /* Not compressed part */ |
779 | 145M | { |
780 | | /* The following counter read does not indicate |
781 | | "how many repeated values follow" but rather |
782 | | "how many are decompressed in standard raster format" */ |
783 | 145M | if (nCompressedRawSize == SIZE_MAX) |
784 | 73.8M | { |
785 | 73.8M | if (VSIFReadL(&cCounter, 1, 1, m_pfIMG) != 1) |
786 | 220 | return CE_Failure; |
787 | 73.8M | } |
788 | 71.2M | else |
789 | 71.2M | { |
790 | 71.2M | if (nCompressedIndex >= aCompressedRow.size()) |
791 | 131 | { |
792 | 131 | CPLError(CE_Failure, CPLE_AppDefined, |
793 | 131 | "Invalid nCompressedIndex"); |
794 | 131 | return CE_Failure; |
795 | 131 | } |
796 | 71.2M | cCounter = aCompressedRow[nCompressedIndex]; |
797 | 71.2M | nCompressedIndex++; |
798 | 71.2M | } |
799 | | |
800 | 145M | nAccumulated += cCounter; |
801 | | |
802 | 145M | if (nAccumulated > m_nWidth) /* This should not happen if the file |
803 | | is RLE and does not share counters across rows */ |
804 | 2.57k | return CE_Failure; |
805 | | |
806 | 151M | for (; nIAccumulated < nAccumulated; nIAccumulated++) |
807 | 6.08M | { |
808 | 6.08M | if (nCompressedRawSize == SIZE_MAX) |
809 | 3.23M | { |
810 | 3.23M | VSIFReadL(&RLEValue, sizeof_TYPE, 1, m_pfIMG); |
811 | 3.23M | memcpy((static_cast<TYPE *>(rowBuffer)) + nIAccumulated, |
812 | 3.23M | &RLEValue, sizeof_TYPE); |
813 | 3.23M | } |
814 | 2.84M | else |
815 | 2.84M | { |
816 | 2.84M | if (nCompressedIndex + sizeof_TYPE > aCompressedRow.size()) |
817 | 285 | { |
818 | 285 | CPLError(CE_Failure, CPLE_AppDefined, |
819 | 285 | "Invalid nCompressedIndex"); |
820 | 285 | return CE_Failure; |
821 | 285 | } |
822 | 2.84M | memcpy((static_cast<TYPE *>(rowBuffer)) + nIAccumulated, |
823 | 2.84M | &aCompressedRow[nCompressedIndex], sizeof_TYPE); |
824 | 2.84M | nCompressedIndex += sizeof_TYPE; |
825 | 2.84M | } |
826 | 6.08M | } |
827 | 145M | } |
828 | 4.60M | else |
829 | 4.60M | { |
830 | 4.60M | nAccumulated += cCounter; |
831 | 4.60M | if (nAccumulated > m_nWidth) /* This should not happen if the file |
832 | | is RLE and does not share counters across rows */ |
833 | 223k | return CE_Failure; |
834 | | |
835 | 4.37M | if (nCompressedRawSize == SIZE_MAX) |
836 | 2.30M | { |
837 | 2.30M | if (VSIFReadL(&RLEValue, sizeof_TYPE, 1, m_pfIMG) != 1) |
838 | 268 | return CE_Failure; |
839 | 2.30M | } |
840 | 2.07M | else |
841 | 2.07M | { |
842 | 2.07M | if (nCompressedIndex + sizeof(TYPE) > aCompressedRow.size()) |
843 | 162 | { |
844 | 162 | CPLError(CE_Failure, CPLE_AppDefined, |
845 | 162 | "Invalid nCompressedIndex"); |
846 | 162 | return CE_Failure; |
847 | 162 | } |
848 | 2.07M | memcpy(&RLEValue, &aCompressedRow[nCompressedIndex], |
849 | 2.07M | sizeof(TYPE)); |
850 | 2.07M | nCompressedIndex += sizeof(TYPE); |
851 | 2.07M | } |
852 | | |
853 | 4.37M | const int nCount = nAccumulated - nIAccumulated; |
854 | 4.37M | pDst = static_cast<TYPE *>(rowBuffer) + nIAccumulated; |
855 | | |
856 | 4.37M | std::fill(pDst, pDst + nCount, RLEValue); |
857 | | |
858 | 4.37M | nIAccumulated = nAccumulated; |
859 | 4.37M | } |
860 | 149M | } |
861 | | |
862 | 9.87k | return CE_None; |
863 | 40.3M | } CPLErr MMRBand::UncompressRow<unsigned char>(void*, unsigned long) Line | Count | Source | 725 | 16.2M | { | 726 | 16.2M | int nAccumulated = 0L, nIAccumulated = 0L; | 727 | 16.2M | unsigned char cCounter; | 728 | 16.2M | size_t nCompressedIndex = 0; | 729 | | | 730 | 16.2M | TYPE RLEValue; | 731 | 16.2M | TYPE *pDst; | 732 | 16.2M | size_t sizeof_TYPE = sizeof(TYPE); | 733 | | | 734 | 16.2M | std::vector<unsigned char> aCompressedRow; | 735 | | | 736 | 16.2M | if (nCompressedRawSize != SIZE_MAX) | 737 | 2.19k | { | 738 | 2.19k | if (nCompressedRawSize > 1000 * 1000 && | 739 | 100 | GetFileSize() < nCompressedRawSize) | 740 | 87 | { | 741 | 87 | CPLError(CE_Failure, CPLE_AppDefined, "Too small file"); | 742 | 87 | return CE_Failure; | 743 | 87 | } | 744 | 2.11k | try | 745 | 2.11k | { | 746 | 2.11k | aCompressedRow.resize(nCompressedRawSize); | 747 | 2.11k | } | 748 | 2.11k | catch (const std::exception &) | 749 | 2.11k | { | 750 | 0 | CPLError(CE_Failure, CPLE_OutOfMemory, | 751 | 0 | "Out of memory allocating working buffer"); | 752 | 0 | return CE_Failure; | 753 | 0 | } | 754 | 2.11k | if (VSIFReadL(aCompressedRow.data(), nCompressedRawSize, 1, m_pfIMG) != | 755 | 2.11k | 1) | 756 | 9 | return CE_Failure; | 757 | 2.11k | } | 758 | | | 759 | 50.6M | while (nAccumulated < m_nWidth) | 760 | 50.6M | { | 761 | 50.6M | if (nCompressedRawSize == SIZE_MAX) | 762 | 33.4M | { | 763 | 33.4M | if (VSIFReadL(&cCounter, 1, 1, m_pfIMG) != 1) | 764 | 16.1M | return CE_Failure; | 765 | 33.4M | } | 766 | 17.2M | else | 767 | 17.2M | { | 768 | 17.2M | if (nCompressedIndex >= aCompressedRow.size()) | 769 | 44 | { | 770 | 44 | CPLError(CE_Failure, CPLE_AppDefined, | 771 | 44 | "Invalid nCompressedIndex"); | 772 | 44 | return CE_Failure; | 773 | 44 | } | 774 | 17.2M | cCounter = aCompressedRow[nCompressedIndex]; | 775 | 17.2M | nCompressedIndex++; | 776 | 17.2M | } | 777 | | | 778 | 34.5M | if (cCounter == 0) /* Not compressed part */ | 779 | 33.1M | { | 780 | | /* The following counter read does not indicate | 781 | | "how many repeated values follow" but rather | 782 | | "how many are decompressed in standard raster format" */ | 783 | 33.1M | if (nCompressedRawSize == SIZE_MAX) | 784 | 16.5M | { | 785 | 16.5M | if (VSIFReadL(&cCounter, 1, 1, m_pfIMG) != 1) | 786 | 58 | return CE_Failure; | 787 | 16.5M | } | 788 | 16.5M | else | 789 | 16.5M | { | 790 | 16.5M | if (nCompressedIndex >= aCompressedRow.size()) | 791 | 29 | { | 792 | 29 | CPLError(CE_Failure, CPLE_AppDefined, | 793 | 29 | "Invalid nCompressedIndex"); | 794 | 29 | return CE_Failure; | 795 | 29 | } | 796 | 16.5M | cCounter = aCompressedRow[nCompressedIndex]; | 797 | 16.5M | nCompressedIndex++; | 798 | 16.5M | } | 799 | | | 800 | 33.1M | nAccumulated += cCounter; | 801 | | | 802 | 33.1M | if (nAccumulated > m_nWidth) /* This should not happen if the file | 803 | | is RLE and does not share counters across rows */ | 804 | 489 | return CE_Failure; | 805 | | | 806 | 34.1M | for (; nIAccumulated < nAccumulated; nIAccumulated++) | 807 | 998k | { | 808 | 998k | if (nCompressedRawSize == SIZE_MAX) | 809 | 512k | { | 810 | 512k | VSIFReadL(&RLEValue, sizeof_TYPE, 1, m_pfIMG); | 811 | 512k | memcpy((static_cast<TYPE *>(rowBuffer)) + nIAccumulated, | 812 | 512k | &RLEValue, sizeof_TYPE); | 813 | 512k | } | 814 | 486k | else | 815 | 486k | { | 816 | 486k | if (nCompressedIndex + sizeof_TYPE > aCompressedRow.size()) | 817 | 46 | { | 818 | 46 | CPLError(CE_Failure, CPLE_AppDefined, | 819 | 46 | "Invalid nCompressedIndex"); | 820 | 46 | return CE_Failure; | 821 | 46 | } | 822 | 486k | memcpy((static_cast<TYPE *>(rowBuffer)) + nIAccumulated, | 823 | 486k | &aCompressedRow[nCompressedIndex], sizeof_TYPE); | 824 | 486k | nCompressedIndex += sizeof_TYPE; | 825 | 486k | } | 826 | 998k | } | 827 | 33.1M | } | 828 | 1.34M | else | 829 | 1.34M | { | 830 | 1.34M | nAccumulated += cCounter; | 831 | 1.34M | if (nAccumulated > m_nWidth) /* This should not happen if the file | 832 | | is RLE and does not share counters across rows */ | 833 | 48.1k | return CE_Failure; | 834 | | | 835 | 1.29M | if (nCompressedRawSize == SIZE_MAX) | 836 | 665k | { | 837 | 665k | if (VSIFReadL(&RLEValue, sizeof_TYPE, 1, m_pfIMG) != 1) | 838 | 42 | return CE_Failure; | 839 | 665k | } | 840 | 628k | else | 841 | 628k | { | 842 | 628k | if (nCompressedIndex + sizeof(TYPE) > aCompressedRow.size()) | 843 | 31 | { | 844 | 31 | CPLError(CE_Failure, CPLE_AppDefined, | 845 | 31 | "Invalid nCompressedIndex"); | 846 | 31 | return CE_Failure; | 847 | 31 | } | 848 | 628k | memcpy(&RLEValue, &aCompressedRow[nCompressedIndex], | 849 | 628k | sizeof(TYPE)); | 850 | 628k | nCompressedIndex += sizeof(TYPE); | 851 | 628k | } | 852 | | | 853 | 1.29M | const int nCount = nAccumulated - nIAccumulated; | 854 | 1.29M | pDst = static_cast<TYPE *>(rowBuffer) + nIAccumulated; | 855 | | | 856 | 1.29M | std::fill(pDst, pDst + nCount, RLEValue); | 857 | | | 858 | 1.29M | nIAccumulated = nAccumulated; | 859 | 1.29M | } | 860 | 34.5M | } | 861 | | | 862 | 4.60k | return CE_None; | 863 | 16.2M | } |
CPLErr MMRBand::UncompressRow<short>(void*, unsigned long) Line | Count | Source | 725 | 4.57M | { | 726 | 4.57M | int nAccumulated = 0L, nIAccumulated = 0L; | 727 | 4.57M | unsigned char cCounter; | 728 | 4.57M | size_t nCompressedIndex = 0; | 729 | | | 730 | 4.57M | TYPE RLEValue; | 731 | 4.57M | TYPE *pDst; | 732 | 4.57M | size_t sizeof_TYPE = sizeof(TYPE); | 733 | | | 734 | 4.57M | std::vector<unsigned char> aCompressedRow; | 735 | | | 736 | 4.57M | if (nCompressedRawSize != SIZE_MAX) | 737 | 546 | { | 738 | 546 | if (nCompressedRawSize > 1000 * 1000 && | 739 | 72 | GetFileSize() < nCompressedRawSize) | 740 | 64 | { | 741 | 64 | CPLError(CE_Failure, CPLE_AppDefined, "Too small file"); | 742 | 64 | return CE_Failure; | 743 | 64 | } | 744 | 482 | try | 745 | 482 | { | 746 | 482 | aCompressedRow.resize(nCompressedRawSize); | 747 | 482 | } | 748 | 482 | catch (const std::exception &) | 749 | 482 | { | 750 | 0 | CPLError(CE_Failure, CPLE_OutOfMemory, | 751 | 0 | "Out of memory allocating working buffer"); | 752 | 0 | return CE_Failure; | 753 | 0 | } | 754 | 482 | if (VSIFReadL(aCompressedRow.data(), nCompressedRawSize, 1, m_pfIMG) != | 755 | 482 | 1) | 756 | 7 | return CE_Failure; | 757 | 482 | } | 758 | | | 759 | 20.3M | while (nAccumulated < m_nWidth) | 760 | 20.3M | { | 761 | 20.3M | if (nCompressedRawSize == SIZE_MAX) | 762 | 12.4M | { | 763 | 12.4M | if (VSIFReadL(&cCounter, 1, 1, m_pfIMG) != 1) | 764 | 4.52M | return CE_Failure; | 765 | 12.4M | } | 766 | 7.89M | else | 767 | 7.89M | { | 768 | 7.89M | if (nCompressedIndex >= aCompressedRow.size()) | 769 | 26 | { | 770 | 26 | CPLError(CE_Failure, CPLE_AppDefined, | 771 | 26 | "Invalid nCompressedIndex"); | 772 | 26 | return CE_Failure; | 773 | 26 | } | 774 | 7.89M | cCounter = aCompressedRow[nCompressedIndex]; | 775 | 7.89M | nCompressedIndex++; | 776 | 7.89M | } | 777 | | | 778 | 15.8M | if (cCounter == 0) /* Not compressed part */ | 779 | 15.0M | { | 780 | | /* The following counter read does not indicate | 781 | | "how many repeated values follow" but rather | 782 | | "how many are decompressed in standard raster format" */ | 783 | 15.0M | if (nCompressedRawSize == SIZE_MAX) | 784 | 7.51M | { | 785 | 7.51M | if (VSIFReadL(&cCounter, 1, 1, m_pfIMG) != 1) | 786 | 17 | return CE_Failure; | 787 | 7.51M | } | 788 | 7.50M | else | 789 | 7.50M | { | 790 | 7.50M | if (nCompressedIndex >= aCompressedRow.size()) | 791 | 16 | { | 792 | 16 | CPLError(CE_Failure, CPLE_AppDefined, | 793 | 16 | "Invalid nCompressedIndex"); | 794 | 16 | return CE_Failure; | 795 | 16 | } | 796 | 7.50M | cCounter = aCompressedRow[nCompressedIndex]; | 797 | 7.50M | nCompressedIndex++; | 798 | 7.50M | } | 799 | | | 800 | 15.0M | nAccumulated += cCounter; | 801 | | | 802 | 15.0M | if (nAccumulated > m_nWidth) /* This should not happen if the file | 803 | | is RLE and does not share counters across rows */ | 804 | 739 | return CE_Failure; | 805 | | | 806 | 15.9M | for (; nIAccumulated < nAccumulated; nIAccumulated++) | 807 | 919k | { | 808 | 919k | if (nCompressedRawSize == SIZE_MAX) | 809 | 473k | { | 810 | 473k | VSIFReadL(&RLEValue, sizeof_TYPE, 1, m_pfIMG); | 811 | 473k | memcpy((static_cast<TYPE *>(rowBuffer)) + nIAccumulated, | 812 | 473k | &RLEValue, sizeof_TYPE); | 813 | 473k | } | 814 | 446k | else | 815 | 446k | { | 816 | 446k | if (nCompressedIndex + sizeof_TYPE > aCompressedRow.size()) | 817 | 73 | { | 818 | 73 | CPLError(CE_Failure, CPLE_AppDefined, | 819 | 73 | "Invalid nCompressedIndex"); | 820 | 73 | return CE_Failure; | 821 | 73 | } | 822 | 446k | memcpy((static_cast<TYPE *>(rowBuffer)) + nIAccumulated, | 823 | 446k | &aCompressedRow[nCompressedIndex], sizeof_TYPE); | 824 | 446k | nCompressedIndex += sizeof_TYPE; | 825 | 446k | } | 826 | 919k | } | 827 | 15.0M | } | 828 | 837k | else | 829 | 837k | { | 830 | 837k | nAccumulated += cCounter; | 831 | 837k | if (nAccumulated > m_nWidth) /* This should not happen if the file | 832 | | is RLE and does not share counters across rows */ | 833 | 51.3k | return CE_Failure; | 834 | | | 835 | 786k | if (nCompressedRawSize == SIZE_MAX) | 836 | 402k | { | 837 | 402k | if (VSIFReadL(&RLEValue, sizeof_TYPE, 1, m_pfIMG) != 1) | 838 | 28 | return CE_Failure; | 839 | 402k | } | 840 | 384k | else | 841 | 384k | { | 842 | 384k | if (nCompressedIndex + sizeof(TYPE) > aCompressedRow.size()) | 843 | 20 | { | 844 | 20 | CPLError(CE_Failure, CPLE_AppDefined, | 845 | 20 | "Invalid nCompressedIndex"); | 846 | 20 | return CE_Failure; | 847 | 20 | } | 848 | 384k | memcpy(&RLEValue, &aCompressedRow[nCompressedIndex], | 849 | 384k | sizeof(TYPE)); | 850 | 384k | nCompressedIndex += sizeof(TYPE); | 851 | 384k | } | 852 | | | 853 | 786k | const int nCount = nAccumulated - nIAccumulated; | 854 | 786k | pDst = static_cast<TYPE *>(rowBuffer) + nIAccumulated; | 855 | | | 856 | 786k | std::fill(pDst, pDst + nCount, RLEValue); | 857 | | | 858 | 786k | nIAccumulated = nAccumulated; | 859 | 786k | } | 860 | 15.8M | } | 861 | | | 862 | 1.09k | return CE_None; | 863 | 4.57M | } |
CPLErr MMRBand::UncompressRow<unsigned short>(void*, unsigned long) Line | Count | Source | 725 | 1.96M | { | 726 | 1.96M | int nAccumulated = 0L, nIAccumulated = 0L; | 727 | 1.96M | unsigned char cCounter; | 728 | 1.96M | size_t nCompressedIndex = 0; | 729 | | | 730 | 1.96M | TYPE RLEValue; | 731 | 1.96M | TYPE *pDst; | 732 | 1.96M | size_t sizeof_TYPE = sizeof(TYPE); | 733 | | | 734 | 1.96M | std::vector<unsigned char> aCompressedRow; | 735 | | | 736 | 1.96M | if (nCompressedRawSize != SIZE_MAX) | 737 | 652 | { | 738 | 652 | if (nCompressedRawSize > 1000 * 1000 && | 739 | 89 | GetFileSize() < nCompressedRawSize) | 740 | 72 | { | 741 | 72 | CPLError(CE_Failure, CPLE_AppDefined, "Too small file"); | 742 | 72 | return CE_Failure; | 743 | 72 | } | 744 | 580 | try | 745 | 580 | { | 746 | 580 | aCompressedRow.resize(nCompressedRawSize); | 747 | 580 | } | 748 | 580 | catch (const std::exception &) | 749 | 580 | { | 750 | 0 | CPLError(CE_Failure, CPLE_OutOfMemory, | 751 | 0 | "Out of memory allocating working buffer"); | 752 | 0 | return CE_Failure; | 753 | 0 | } | 754 | 580 | if (VSIFReadL(aCompressedRow.data(), nCompressedRawSize, 1, m_pfIMG) != | 755 | 580 | 1) | 756 | 3 | return CE_Failure; | 757 | 580 | } | 758 | | | 759 | 50.0M | while (nAccumulated < m_nWidth) | 760 | 50.0M | { | 761 | 50.0M | if (nCompressedRawSize == SIZE_MAX) | 762 | 26.3M | { | 763 | 26.3M | if (VSIFReadL(&cCounter, 1, 1, m_pfIMG) != 1) | 764 | 1.93M | return CE_Failure; | 765 | 26.3M | } | 766 | 23.6M | else | 767 | 23.6M | { | 768 | 23.6M | if (nCompressedIndex >= aCompressedRow.size()) | 769 | 53 | { | 770 | 53 | CPLError(CE_Failure, CPLE_AppDefined, | 771 | 53 | "Invalid nCompressedIndex"); | 772 | 53 | return CE_Failure; | 773 | 53 | } | 774 | 23.6M | cCounter = aCompressedRow[nCompressedIndex]; | 775 | 23.6M | nCompressedIndex++; | 776 | 23.6M | } | 777 | | | 778 | 48.1M | if (cCounter == 0) /* Not compressed part */ | 779 | 46.8M | { | 780 | | /* The following counter read does not indicate | 781 | | "how many repeated values follow" but rather | 782 | | "how many are decompressed in standard raster format" */ | 783 | 46.8M | if (nCompressedRawSize == SIZE_MAX) | 784 | 23.7M | { | 785 | 23.7M | if (VSIFReadL(&cCounter, 1, 1, m_pfIMG) != 1) | 786 | 28 | return CE_Failure; | 787 | 23.7M | } | 788 | 23.0M | else | 789 | 23.0M | { | 790 | 23.0M | if (nCompressedIndex >= aCompressedRow.size()) | 791 | 21 | { | 792 | 21 | CPLError(CE_Failure, CPLE_AppDefined, | 793 | 21 | "Invalid nCompressedIndex"); | 794 | 21 | return CE_Failure; | 795 | 21 | } | 796 | 23.0M | cCounter = aCompressedRow[nCompressedIndex]; | 797 | 23.0M | nCompressedIndex++; | 798 | 23.0M | } | 799 | | | 800 | 46.8M | nAccumulated += cCounter; | 801 | | | 802 | 46.8M | if (nAccumulated > m_nWidth) /* This should not happen if the file | 803 | | is RLE and does not share counters across rows */ | 804 | 420 | return CE_Failure; | 805 | | | 806 | 48.9M | for (; nIAccumulated < nAccumulated; nIAccumulated++) | 807 | 2.10M | { | 808 | 2.10M | if (nCompressedRawSize == SIZE_MAX) | 809 | 1.06M | { | 810 | 1.06M | VSIFReadL(&RLEValue, sizeof_TYPE, 1, m_pfIMG); | 811 | 1.06M | memcpy((static_cast<TYPE *>(rowBuffer)) + nIAccumulated, | 812 | 1.06M | &RLEValue, sizeof_TYPE); | 813 | 1.06M | } | 814 | 1.03M | else | 815 | 1.03M | { | 816 | 1.03M | if (nCompressedIndex + sizeof_TYPE > aCompressedRow.size()) | 817 | 43 | { | 818 | 43 | CPLError(CE_Failure, CPLE_AppDefined, | 819 | 43 | "Invalid nCompressedIndex"); | 820 | 43 | return CE_Failure; | 821 | 43 | } | 822 | 1.03M | memcpy((static_cast<TYPE *>(rowBuffer)) + nIAccumulated, | 823 | 1.03M | &aCompressedRow[nCompressedIndex], sizeof_TYPE); | 824 | 1.03M | nCompressedIndex += sizeof_TYPE; | 825 | 1.03M | } | 826 | 2.10M | } | 827 | 46.8M | } | 828 | 1.25M | else | 829 | 1.25M | { | 830 | 1.25M | nAccumulated += cCounter; | 831 | 1.25M | if (nAccumulated > m_nWidth) /* This should not happen if the file | 832 | | is RLE and does not share counters across rows */ | 833 | 29.3k | return CE_Failure; | 834 | | | 835 | 1.22M | if (nCompressedRawSize == SIZE_MAX) | 836 | 624k | { | 837 | 624k | if (VSIFReadL(&RLEValue, sizeof_TYPE, 1, m_pfIMG) != 1) | 838 | 48 | return CE_Failure; | 839 | 624k | } | 840 | 599k | else | 841 | 599k | { | 842 | 599k | if (nCompressedIndex + sizeof(TYPE) > aCompressedRow.size()) | 843 | 26 | { | 844 | 26 | CPLError(CE_Failure, CPLE_AppDefined, | 845 | 26 | "Invalid nCompressedIndex"); | 846 | 26 | return CE_Failure; | 847 | 26 | } | 848 | 599k | memcpy(&RLEValue, &aCompressedRow[nCompressedIndex], | 849 | 599k | sizeof(TYPE)); | 850 | 599k | nCompressedIndex += sizeof(TYPE); | 851 | 599k | } | 852 | | | 853 | 1.22M | const int nCount = nAccumulated - nIAccumulated; | 854 | 1.22M | pDst = static_cast<TYPE *>(rowBuffer) + nIAccumulated; | 855 | | | 856 | 1.22M | std::fill(pDst, pDst + nCount, RLEValue); | 857 | | | 858 | 1.22M | nIAccumulated = nAccumulated; | 859 | 1.22M | } | 860 | 48.1M | } | 861 | | | 862 | 917 | return CE_None; | 863 | 1.96M | } |
CPLErr MMRBand::UncompressRow<int>(void*, unsigned long) Line | Count | Source | 725 | 5.64M | { | 726 | 5.64M | int nAccumulated = 0L, nIAccumulated = 0L; | 727 | 5.64M | unsigned char cCounter; | 728 | 5.64M | size_t nCompressedIndex = 0; | 729 | | | 730 | 5.64M | TYPE RLEValue; | 731 | 5.64M | TYPE *pDst; | 732 | 5.64M | size_t sizeof_TYPE = sizeof(TYPE); | 733 | | | 734 | 5.64M | std::vector<unsigned char> aCompressedRow; | 735 | | | 736 | 5.64M | if (nCompressedRawSize != SIZE_MAX) | 737 | 715 | { | 738 | 715 | if (nCompressedRawSize > 1000 * 1000 && | 739 | 82 | GetFileSize() < nCompressedRawSize) | 740 | 79 | { | 741 | 79 | CPLError(CE_Failure, CPLE_AppDefined, "Too small file"); | 742 | 79 | return CE_Failure; | 743 | 79 | } | 744 | 636 | try | 745 | 636 | { | 746 | 636 | aCompressedRow.resize(nCompressedRawSize); | 747 | 636 | } | 748 | 636 | catch (const std::exception &) | 749 | 636 | { | 750 | 0 | CPLError(CE_Failure, CPLE_OutOfMemory, | 751 | 0 | "Out of memory allocating working buffer"); | 752 | 0 | return CE_Failure; | 753 | 0 | } | 754 | 636 | if (VSIFReadL(aCompressedRow.data(), nCompressedRawSize, 1, m_pfIMG) != | 755 | 636 | 1) | 756 | 4 | return CE_Failure; | 757 | 636 | } | 758 | | | 759 | 20.4M | while (nAccumulated < m_nWidth) | 760 | 20.3M | { | 761 | 20.3M | if (nCompressedRawSize == SIZE_MAX) | 762 | 13.0M | { | 763 | 13.0M | if (VSIFReadL(&cCounter, 1, 1, m_pfIMG) != 1) | 764 | 5.61M | return CE_Failure; | 765 | 13.0M | } | 766 | 7.33M | else | 767 | 7.33M | { | 768 | 7.33M | if (nCompressedIndex >= aCompressedRow.size()) | 769 | 20 | { | 770 | 20 | CPLError(CE_Failure, CPLE_AppDefined, | 771 | 20 | "Invalid nCompressedIndex"); | 772 | 20 | return CE_Failure; | 773 | 20 | } | 774 | 7.33M | cCounter = aCompressedRow[nCompressedIndex]; | 775 | 7.33M | nCompressedIndex++; | 776 | 7.33M | } | 777 | | | 778 | 14.7M | if (cCounter == 0) /* Not compressed part */ | 779 | 14.2M | { | 780 | | /* The following counter read does not indicate | 781 | | "how many repeated values follow" but rather | 782 | | "how many are decompressed in standard raster format" */ | 783 | 14.2M | if (nCompressedRawSize == SIZE_MAX) | 784 | 7.16M | { | 785 | 7.16M | if (VSIFReadL(&cCounter, 1, 1, m_pfIMG) != 1) | 786 | 29 | return CE_Failure; | 787 | 7.16M | } | 788 | 7.10M | else | 789 | 7.10M | { | 790 | 7.10M | if (nCompressedIndex >= aCompressedRow.size()) | 791 | 24 | { | 792 | 24 | CPLError(CE_Failure, CPLE_AppDefined, | 793 | 24 | "Invalid nCompressedIndex"); | 794 | 24 | return CE_Failure; | 795 | 24 | } | 796 | 7.10M | cCounter = aCompressedRow[nCompressedIndex]; | 797 | 7.10M | nCompressedIndex++; | 798 | 7.10M | } | 799 | | | 800 | 14.2M | nAccumulated += cCounter; | 801 | | | 802 | 14.2M | if (nAccumulated > m_nWidth) /* This should not happen if the file | 803 | | is RLE and does not share counters across rows */ | 804 | 292 | return CE_Failure; | 805 | | | 806 | 14.8M | for (; nIAccumulated < nAccumulated; nIAccumulated++) | 807 | 619k | { | 808 | 619k | if (nCompressedRawSize == SIZE_MAX) | 809 | 319k | { | 810 | 319k | VSIFReadL(&RLEValue, sizeof_TYPE, 1, m_pfIMG); | 811 | 319k | memcpy((static_cast<TYPE *>(rowBuffer)) + nIAccumulated, | 812 | 319k | &RLEValue, sizeof_TYPE); | 813 | 319k | } | 814 | 300k | else | 815 | 300k | { | 816 | 300k | if (nCompressedIndex + sizeof_TYPE > aCompressedRow.size()) | 817 | 37 | { | 818 | 37 | CPLError(CE_Failure, CPLE_AppDefined, | 819 | 37 | "Invalid nCompressedIndex"); | 820 | 37 | return CE_Failure; | 821 | 37 | } | 822 | 300k | memcpy((static_cast<TYPE *>(rowBuffer)) + nIAccumulated, | 823 | 300k | &aCompressedRow[nCompressedIndex], sizeof_TYPE); | 824 | 300k | nCompressedIndex += sizeof_TYPE; | 825 | 300k | } | 826 | 619k | } | 827 | 14.2M | } | 828 | 515k | else | 829 | 515k | { | 830 | 515k | nAccumulated += cCounter; | 831 | 515k | if (nAccumulated > m_nWidth) /* This should not happen if the file | 832 | | is RLE and does not share counters across rows */ | 833 | 32.8k | return CE_Failure; | 834 | | | 835 | 482k | if (nCompressedRawSize == SIZE_MAX) | 836 | 248k | { | 837 | 248k | if (VSIFReadL(&RLEValue, sizeof_TYPE, 1, m_pfIMG) != 1) | 838 | 34 | return CE_Failure; | 839 | 248k | } | 840 | 234k | else | 841 | 234k | { | 842 | 234k | if (nCompressedIndex + sizeof(TYPE) > aCompressedRow.size()) | 843 | 23 | { | 844 | 23 | CPLError(CE_Failure, CPLE_AppDefined, | 845 | 23 | "Invalid nCompressedIndex"); | 846 | 23 | return CE_Failure; | 847 | 23 | } | 848 | 234k | memcpy(&RLEValue, &aCompressedRow[nCompressedIndex], | 849 | 234k | sizeof(TYPE)); | 850 | 234k | nCompressedIndex += sizeof(TYPE); | 851 | 234k | } | 852 | | | 853 | 482k | const int nCount = nAccumulated - nIAccumulated; | 854 | 482k | pDst = static_cast<TYPE *>(rowBuffer) + nIAccumulated; | 855 | | | 856 | 482k | std::fill(pDst, pDst + nCount, RLEValue); | 857 | | | 858 | 482k | nIAccumulated = nAccumulated; | 859 | 482k | } | 860 | 14.7M | } | 861 | | | 862 | 1.21k | return CE_None; | 863 | 5.64M | } |
CPLErr MMRBand::UncompressRow<float>(void*, unsigned long) Line | Count | Source | 725 | 792k | { | 726 | 792k | int nAccumulated = 0L, nIAccumulated = 0L; | 727 | 792k | unsigned char cCounter; | 728 | 792k | size_t nCompressedIndex = 0; | 729 | | | 730 | 792k | TYPE RLEValue; | 731 | 792k | TYPE *pDst; | 732 | 792k | size_t sizeof_TYPE = sizeof(TYPE); | 733 | | | 734 | 792k | std::vector<unsigned char> aCompressedRow; | 735 | | | 736 | 792k | if (nCompressedRawSize != SIZE_MAX) | 737 | 405 | { | 738 | 405 | if (nCompressedRawSize > 1000 * 1000 && | 739 | 66 | GetFileSize() < nCompressedRawSize) | 740 | 61 | { | 741 | 61 | CPLError(CE_Failure, CPLE_AppDefined, "Too small file"); | 742 | 61 | return CE_Failure; | 743 | 61 | } | 744 | 344 | try | 745 | 344 | { | 746 | 344 | aCompressedRow.resize(nCompressedRawSize); | 747 | 344 | } | 748 | 344 | catch (const std::exception &) | 749 | 344 | { | 750 | 0 | CPLError(CE_Failure, CPLE_OutOfMemory, | 751 | 0 | "Out of memory allocating working buffer"); | 752 | 0 | return CE_Failure; | 753 | 0 | } | 754 | 344 | if (VSIFReadL(aCompressedRow.data(), nCompressedRawSize, 1, m_pfIMG) != | 755 | 344 | 1) | 756 | 1 | return CE_Failure; | 757 | 344 | } | 758 | | | 759 | 15.2M | while (nAccumulated < m_nWidth) | 760 | 15.2M | { | 761 | 15.2M | if (nCompressedRawSize == SIZE_MAX) | 762 | 8.06M | { | 763 | 8.06M | if (VSIFReadL(&cCounter, 1, 1, m_pfIMG) != 1) | 764 | 769k | return CE_Failure; | 765 | 8.06M | } | 766 | 7.22M | else | 767 | 7.22M | { | 768 | 7.22M | if (nCompressedIndex >= aCompressedRow.size()) | 769 | 21 | { | 770 | 21 | CPLError(CE_Failure, CPLE_AppDefined, | 771 | 21 | "Invalid nCompressedIndex"); | 772 | 21 | return CE_Failure; | 773 | 21 | } | 774 | 7.22M | cCounter = aCompressedRow[nCompressedIndex]; | 775 | 7.22M | nCompressedIndex++; | 776 | 7.22M | } | 777 | | | 778 | 14.5M | if (cCounter == 0) /* Not compressed part */ | 779 | 14.1M | { | 780 | | /* The following counter read does not indicate | 781 | | "how many repeated values follow" but rather | 782 | | "how many are decompressed in standard raster format" */ | 783 | 14.1M | if (nCompressedRawSize == SIZE_MAX) | 784 | 7.07M | { | 785 | 7.07M | if (VSIFReadL(&cCounter, 1, 1, m_pfIMG) != 1) | 786 | 27 | return CE_Failure; | 787 | 7.07M | } | 788 | 7.04M | else | 789 | 7.04M | { | 790 | 7.04M | if (nCompressedIndex >= aCompressedRow.size()) | 791 | 12 | { | 792 | 12 | CPLError(CE_Failure, CPLE_AppDefined, | 793 | 12 | "Invalid nCompressedIndex"); | 794 | 12 | return CE_Failure; | 795 | 12 | } | 796 | 7.04M | cCounter = aCompressedRow[nCompressedIndex]; | 797 | 7.04M | nCompressedIndex++; | 798 | 7.04M | } | 799 | | | 800 | 14.1M | nAccumulated += cCounter; | 801 | | | 802 | 14.1M | if (nAccumulated > m_nWidth) /* This should not happen if the file | 803 | | is RLE and does not share counters across rows */ | 804 | 299 | return CE_Failure; | 805 | | | 806 | 14.8M | for (; nIAccumulated < nAccumulated; nIAccumulated++) | 807 | 702k | { | 808 | 702k | if (nCompressedRawSize == SIZE_MAX) | 809 | 356k | { | 810 | 356k | VSIFReadL(&RLEValue, sizeof_TYPE, 1, m_pfIMG); | 811 | 356k | memcpy((static_cast<TYPE *>(rowBuffer)) + nIAccumulated, | 812 | 356k | &RLEValue, sizeof_TYPE); | 813 | 356k | } | 814 | 345k | else | 815 | 345k | { | 816 | 345k | if (nCompressedIndex + sizeof_TYPE > aCompressedRow.size()) | 817 | 34 | { | 818 | 34 | CPLError(CE_Failure, CPLE_AppDefined, | 819 | 34 | "Invalid nCompressedIndex"); | 820 | 34 | return CE_Failure; | 821 | 34 | } | 822 | 345k | memcpy((static_cast<TYPE *>(rowBuffer)) + nIAccumulated, | 823 | 345k | &aCompressedRow[nCompressedIndex], sizeof_TYPE); | 824 | 345k | nCompressedIndex += sizeof_TYPE; | 825 | 345k | } | 826 | 702k | } | 827 | 14.1M | } | 828 | 399k | else | 829 | 399k | { | 830 | 399k | nAccumulated += cCounter; | 831 | 399k | if (nAccumulated > m_nWidth) /* This should not happen if the file | 832 | | is RLE and does not share counters across rows */ | 833 | 22.0k | return CE_Failure; | 834 | | | 835 | 377k | if (nCompressedRawSize == SIZE_MAX) | 836 | 191k | { | 837 | 191k | if (VSIFReadL(&RLEValue, sizeof_TYPE, 1, m_pfIMG) != 1) | 838 | 63 | return CE_Failure; | 839 | 191k | } | 840 | 186k | else | 841 | 186k | { | 842 | 186k | if (nCompressedIndex + sizeof(TYPE) > aCompressedRow.size()) | 843 | 34 | { | 844 | 34 | CPLError(CE_Failure, CPLE_AppDefined, | 845 | 34 | "Invalid nCompressedIndex"); | 846 | 34 | return CE_Failure; | 847 | 34 | } | 848 | 186k | memcpy(&RLEValue, &aCompressedRow[nCompressedIndex], | 849 | 186k | sizeof(TYPE)); | 850 | 186k | nCompressedIndex += sizeof(TYPE); | 851 | 186k | } | 852 | | | 853 | 377k | const int nCount = nAccumulated - nIAccumulated; | 854 | 377k | pDst = static_cast<TYPE *>(rowBuffer) + nIAccumulated; | 855 | | | 856 | 377k | std::fill(pDst, pDst + nCount, RLEValue); | 857 | | | 858 | 377k | nIAccumulated = nAccumulated; | 859 | 377k | } | 860 | 14.5M | } | 861 | | | 862 | 602 | return CE_None; | 863 | 792k | } |
CPLErr MMRBand::UncompressRow<double>(void*, unsigned long) Line | Count | Source | 725 | 11.1M | { | 726 | 11.1M | int nAccumulated = 0L, nIAccumulated = 0L; | 727 | 11.1M | unsigned char cCounter; | 728 | 11.1M | size_t nCompressedIndex = 0; | 729 | | | 730 | 11.1M | TYPE RLEValue; | 731 | 11.1M | TYPE *pDst; | 732 | 11.1M | size_t sizeof_TYPE = sizeof(TYPE); | 733 | | | 734 | 11.1M | std::vector<unsigned char> aCompressedRow; | 735 | | | 736 | 11.1M | if (nCompressedRawSize != SIZE_MAX) | 737 | 971 | { | 738 | 971 | if (nCompressedRawSize > 1000 * 1000 && | 739 | 70 | GetFileSize() < nCompressedRawSize) | 740 | 64 | { | 741 | 64 | CPLError(CE_Failure, CPLE_AppDefined, "Too small file"); | 742 | 64 | return CE_Failure; | 743 | 64 | } | 744 | 907 | try | 745 | 907 | { | 746 | 907 | aCompressedRow.resize(nCompressedRawSize); | 747 | 907 | } | 748 | 907 | catch (const std::exception &) | 749 | 907 | { | 750 | 0 | CPLError(CE_Failure, CPLE_OutOfMemory, | 751 | 0 | "Out of memory allocating working buffer"); | 752 | 0 | return CE_Failure; | 753 | 0 | } | 754 | 907 | if (VSIFReadL(aCompressedRow.data(), nCompressedRawSize, 1, m_pfIMG) != | 755 | 907 | 1) | 756 | 1 | return CE_Failure; | 757 | 907 | } | 758 | | | 759 | 33.0M | while (nAccumulated < m_nWidth) | 760 | 33.0M | { | 761 | 33.0M | if (nCompressedRawSize == SIZE_MAX) | 762 | 23.0M | { | 763 | 23.0M | if (VSIFReadL(&cCounter, 1, 1, m_pfIMG) != 1) | 764 | 11.1M | return CE_Failure; | 765 | 23.0M | } | 766 | 9.99M | else | 767 | 9.99M | { | 768 | 9.99M | if (nCompressedIndex >= aCompressedRow.size()) | 769 | 40 | { | 770 | 40 | CPLError(CE_Failure, CPLE_AppDefined, | 771 | 40 | "Invalid nCompressedIndex"); | 772 | 40 | return CE_Failure; | 773 | 40 | } | 774 | 9.99M | cCounter = aCompressedRow[nCompressedIndex]; | 775 | 9.99M | nCompressedIndex++; | 776 | 9.99M | } | 777 | | | 778 | 21.9M | if (cCounter == 0) /* Not compressed part */ | 779 | 21.6M | { | 780 | | /* The following counter read does not indicate | 781 | | "how many repeated values follow" but rather | 782 | | "how many are decompressed in standard raster format" */ | 783 | 21.6M | if (nCompressedRawSize == SIZE_MAX) | 784 | 11.7M | { | 785 | 11.7M | if (VSIFReadL(&cCounter, 1, 1, m_pfIMG) != 1) | 786 | 61 | return CE_Failure; | 787 | 11.7M | } | 788 | 9.95M | else | 789 | 9.95M | { | 790 | 9.95M | if (nCompressedIndex >= aCompressedRow.size()) | 791 | 29 | { | 792 | 29 | CPLError(CE_Failure, CPLE_AppDefined, | 793 | 29 | "Invalid nCompressedIndex"); | 794 | 29 | return CE_Failure; | 795 | 29 | } | 796 | 9.95M | cCounter = aCompressedRow[nCompressedIndex]; | 797 | 9.95M | nCompressedIndex++; | 798 | 9.95M | } | 799 | | | 800 | 21.6M | nAccumulated += cCounter; | 801 | | | 802 | 21.6M | if (nAccumulated > m_nWidth) /* This should not happen if the file | 803 | | is RLE and does not share counters across rows */ | 804 | 340 | return CE_Failure; | 805 | | | 806 | 22.4M | for (; nIAccumulated < nAccumulated; nIAccumulated++) | 807 | 743k | { | 808 | 743k | if (nCompressedRawSize == SIZE_MAX) | 809 | 509k | { | 810 | 509k | VSIFReadL(&RLEValue, sizeof_TYPE, 1, m_pfIMG); | 811 | 509k | memcpy((static_cast<TYPE *>(rowBuffer)) + nIAccumulated, | 812 | 509k | &RLEValue, sizeof_TYPE); | 813 | 509k | } | 814 | 233k | else | 815 | 233k | { | 816 | 233k | if (nCompressedIndex + sizeof_TYPE > aCompressedRow.size()) | 817 | 52 | { | 818 | 52 | CPLError(CE_Failure, CPLE_AppDefined, | 819 | 52 | "Invalid nCompressedIndex"); | 820 | 52 | return CE_Failure; | 821 | 52 | } | 822 | 233k | memcpy((static_cast<TYPE *>(rowBuffer)) + nIAccumulated, | 823 | 233k | &aCompressedRow[nCompressedIndex], sizeof_TYPE); | 824 | 233k | nCompressedIndex += sizeof_TYPE; | 825 | 233k | } | 826 | 743k | } | 827 | 21.6M | } | 828 | 252k | else | 829 | 252k | { | 830 | 252k | nAccumulated += cCounter; | 831 | 252k | if (nAccumulated > m_nWidth) /* This should not happen if the file | 832 | | is RLE and does not share counters across rows */ | 833 | 39.9k | return CE_Failure; | 834 | | | 835 | 212k | if (nCompressedRawSize == SIZE_MAX) | 836 | 171k | { | 837 | 171k | if (VSIFReadL(&RLEValue, sizeof_TYPE, 1, m_pfIMG) != 1) | 838 | 53 | return CE_Failure; | 839 | 171k | } | 840 | 40.5k | else | 841 | 40.5k | { | 842 | 40.5k | if (nCompressedIndex + sizeof(TYPE) > aCompressedRow.size()) | 843 | 28 | { | 844 | 28 | CPLError(CE_Failure, CPLE_AppDefined, | 845 | 28 | "Invalid nCompressedIndex"); | 846 | 28 | return CE_Failure; | 847 | 28 | } | 848 | 40.4k | memcpy(&RLEValue, &aCompressedRow[nCompressedIndex], | 849 | 40.4k | sizeof(TYPE)); | 850 | 40.4k | nCompressedIndex += sizeof(TYPE); | 851 | 40.4k | } | 852 | | | 853 | 212k | const int nCount = nAccumulated - nIAccumulated; | 854 | 212k | pDst = static_cast<TYPE *>(rowBuffer) + nIAccumulated; | 855 | | | 856 | 212k | std::fill(pDst, pDst + nCount, RLEValue); | 857 | | | 858 | 212k | nIAccumulated = nAccumulated; | 859 | 212k | } | 860 | 21.9M | } | 861 | | | 862 | 1.44k | return CE_None; | 863 | 11.1M | } |
|
864 | | |
865 | | CPLErr MMRBand::GetBlockData(void *rowBuffer, size_t nCompressedRawSize) |
866 | 40.4M | { |
867 | 40.4M | if (m_eMMDataType == MMDataType::DATATYPE_AND_COMPR_BIT) |
868 | 3.16k | { |
869 | 3.16k | const int nGDALBlockSize = DIV_ROUND_UP(m_nBlockXSize, 8); |
870 | | |
871 | 3.16k | if (VSIFReadL(rowBuffer, nGDALBlockSize, 1, m_pfIMG) != 1) |
872 | 28 | { |
873 | 28 | CPLError(CE_Failure, CPLE_AppDefined, "Error while reading band"); |
874 | 28 | return CE_Failure; |
875 | 28 | } |
876 | 3.13k | return CE_None; |
877 | 3.16k | } |
878 | | |
879 | 40.4M | if (m_eMMDataType == MMDataType::DATATYPE_AND_COMPR_BYTE || |
880 | 40.3M | m_eMMDataType == MMDataType::DATATYPE_AND_COMPR_INTEGER || |
881 | 40.3M | m_eMMDataType == MMDataType::DATATYPE_AND_COMPR_UINTEGER || |
882 | 40.3M | m_eMMDataType == MMDataType::DATATYPE_AND_COMPR_LONG || |
883 | 40.3M | m_eMMDataType == MMDataType::DATATYPE_AND_COMPR_REAL || |
884 | 40.3M | m_eMMDataType == MMDataType::DATATYPE_AND_COMPR_DOUBLE) |
885 | 29.2k | { |
886 | 29.2k | if (VSIFReadL(rowBuffer, m_nDataTypeSizeBytes, m_nWidth, m_pfIMG) != |
887 | 29.2k | static_cast<size_t>(m_nWidth)) |
888 | 156 | { |
889 | 156 | CPLError(CE_Failure, CPLE_AppDefined, "Error while reading band"); |
890 | 156 | return CE_Failure; |
891 | 156 | } |
892 | 29.0k | return CE_None; |
893 | 29.2k | } |
894 | | |
895 | 40.3M | CPLErr eErr; |
896 | 40.3M | switch (m_eMMDataType) |
897 | 40.3M | { |
898 | 16.2M | case MMDataType::DATATYPE_AND_COMPR_BYTE_RLE: |
899 | 16.2M | eErr = UncompressRow<GByte>(rowBuffer, nCompressedRawSize); |
900 | 16.2M | break; |
901 | 4.57M | case MMDataType::DATATYPE_AND_COMPR_INTEGER_RLE: |
902 | 4.57M | eErr = UncompressRow<GInt16>(rowBuffer, nCompressedRawSize); |
903 | 4.57M | break; |
904 | 1.96M | case MMDataType::DATATYPE_AND_COMPR_UINTEGER_RLE: |
905 | 1.96M | eErr = UncompressRow<GUInt16>(rowBuffer, nCompressedRawSize); |
906 | 1.96M | break; |
907 | 5.64M | case MMDataType::DATATYPE_AND_COMPR_LONG_RLE: |
908 | 5.64M | eErr = UncompressRow<GInt32>(rowBuffer, nCompressedRawSize); |
909 | 5.64M | break; |
910 | 792k | case MMDataType::DATATYPE_AND_COMPR_REAL_RLE: |
911 | 792k | eErr = UncompressRow<float>(rowBuffer, nCompressedRawSize); |
912 | 792k | break; |
913 | 11.1M | case MMDataType::DATATYPE_AND_COMPR_DOUBLE_RLE: |
914 | 11.1M | eErr = UncompressRow<double>(rowBuffer, nCompressedRawSize); |
915 | 11.1M | break; |
916 | | |
917 | 0 | default: |
918 | 0 | CPLError(CE_Failure, CPLE_AppDefined, "Error in datatype"); |
919 | 0 | eErr = CE_Failure; |
920 | 40.3M | } |
921 | | |
922 | 40.3M | return eErr; |
923 | 40.3M | } // End of GetBlockData() |
924 | | |
925 | | int MMRBand::PositionAtStartOfRowOffsetsInFile() |
926 | 2.86k | { |
927 | 2.86k | vsi_l_offset nFileSize, nHeaderOffset; |
928 | 2.86k | char szChain[16]; |
929 | 2.86k | GInt16 nVersion, nSubVersion; |
930 | 2.86k | int nOffsetSize, nOffsetsSectionType; |
931 | | |
932 | 2.86k | if (VSIFSeekL(m_pfIMG, 0, SEEK_END)) |
933 | 0 | return 0; |
934 | | |
935 | 2.86k | nFileSize = VSIFTellL(m_pfIMG); |
936 | | |
937 | 2.86k | if (nFileSize < 32) // Minimum required size |
938 | 70 | return 0; |
939 | | |
940 | 2.79k | if (m_nHeight) |
941 | 2.79k | { |
942 | 2.79k | if (nFileSize < static_cast<vsi_l_offset>(32) + m_nHeight + 32) |
943 | 309 | return 0; |
944 | 2.79k | } |
945 | | |
946 | 2.48k | vsi_l_offset nHeadOffset = nFileSize - 32; |
947 | | |
948 | 2.48k | if (VSIFSeekL(m_pfIMG, nHeadOffset, SEEK_SET)) // Reading final header. |
949 | 0 | return 0; |
950 | 2.48k | if (VSIFReadL(szChain, 16, 1, m_pfIMG) != 1) |
951 | 0 | return 0; |
952 | 22.7k | for (int nIndex = 0; nIndex < 16; nIndex++) |
953 | 21.6k | { |
954 | 21.6k | if (szChain[nIndex] != '\0') |
955 | 1.35k | return 0; // Supposed 0's are not 0. |
956 | 21.6k | } |
957 | | |
958 | 1.13k | if (VSIFReadL(szChain, 8, 1, m_pfIMG) != 1) |
959 | 0 | return 0; |
960 | | |
961 | 1.13k | if (strncmp(szChain, "IMG ", 4) || szChain[5] != '.') |
962 | 206 | return 0; |
963 | | |
964 | | // Some version checks |
965 | 927 | szChain[7] = 0; |
966 | 927 | if (sscanf(szChain + 6, "%hd", &nSubVersion) != 1 || nSubVersion < 0) |
967 | 10 | return 0; |
968 | | |
969 | 917 | szChain[5] = 0; |
970 | 917 | if (sscanf(szChain + 4, "%hd", &nVersion) != 1 || nVersion != 1) |
971 | 22 | return 0; |
972 | | |
973 | | // Next header to be read |
974 | 895 | if (VSIFReadL(&nHeaderOffset, sizeof(vsi_l_offset), 1, m_pfIMG) != 1) |
975 | 0 | return 0; |
976 | | |
977 | 895 | std::set<vsi_l_offset> alreadyVisitedOffsets; |
978 | 895 | bool bRepeat; |
979 | 895 | do |
980 | 1.09k | { |
981 | 1.09k | bRepeat = FALSE; |
982 | | |
983 | 1.09k | if (VSIFSeekL(m_pfIMG, nHeaderOffset, SEEK_SET)) |
984 | 10 | return 0; |
985 | | |
986 | 1.08k | if (VSIFReadL(szChain, 8, 1, m_pfIMG) != 1) |
987 | 178 | return 0; |
988 | | |
989 | 909 | if (strncmp(szChain, "IMG ", 4) || szChain[5] != '.') |
990 | 70 | return 0; |
991 | | |
992 | 839 | if (VSIFReadL(&nOffsetsSectionType, 4, 1, m_pfIMG) != 1) |
993 | 0 | return 0; |
994 | | |
995 | 839 | if (nOffsetsSectionType != 2) // 2 = row offsets section |
996 | 229 | { |
997 | | // This is not the section I am looking for |
998 | 229 | if (VSIFSeekL(m_pfIMG, 8 + 4, SEEK_CUR)) |
999 | 0 | return 0; |
1000 | | |
1001 | 229 | if (VSIFReadL(&nHeaderOffset, sizeof(vsi_l_offset), 1, m_pfIMG) != |
1002 | 229 | 1) |
1003 | 3 | return 0; |
1004 | | |
1005 | 226 | if (nHeaderOffset == 0) |
1006 | 12 | return 0; |
1007 | | |
1008 | 214 | if (cpl::contains(alreadyVisitedOffsets, nHeaderOffset)) |
1009 | 12 | { |
1010 | 12 | CPLError(CE_Failure, CPLE_AssertionFailed, |
1011 | 12 | "Error reading offsets. They will be ignored."); |
1012 | 12 | return 0; |
1013 | 12 | } |
1014 | | |
1015 | 202 | alreadyVisitedOffsets.insert(nHeaderOffset); |
1016 | | |
1017 | 202 | bRepeat = TRUE; |
1018 | 202 | } |
1019 | | |
1020 | 839 | } while (bRepeat); |
1021 | | |
1022 | 610 | szChain[7] = 0; |
1023 | 610 | if (sscanf(szChain + 6, "%hd", &nSubVersion) != 1 || nSubVersion < 0) |
1024 | 5 | return 0; |
1025 | 605 | szChain[5] = 0; |
1026 | 605 | if (sscanf(szChain + 4, "%hd", &nVersion) != 1 || nVersion != 1) |
1027 | 29 | return 0; |
1028 | | |
1029 | | /* |
1030 | | Now I'm in the correct section |
1031 | | ------------------------------- |
1032 | | Info about this section: |
1033 | | RasterRLE: minimum size: nHeight*2 |
1034 | | Offsets: minimum size: 32+nHeight*4 |
1035 | | Final: size: 32 |
1036 | | */ |
1037 | | |
1038 | 576 | if (m_nHeight) |
1039 | 576 | { |
1040 | 576 | if (nHeaderOffset < static_cast<vsi_l_offset>(m_nHeight) * |
1041 | 576 | 2 || // Minimum size of an RLE |
1042 | 560 | nFileSize - nHeaderOffset < |
1043 | 560 | static_cast<vsi_l_offset>(32) + m_nHeight + |
1044 | 560 | 32) // Minimum size of the section in version 1.0 |
1045 | 19 | return 0; |
1046 | 576 | } |
1047 | | |
1048 | 557 | if (VSIFReadL(&nOffsetSize, 4, 1, m_pfIMG) != 1 || |
1049 | 557 | (nOffsetSize != 8 && nOffsetSize != 4 && nOffsetSize != 2 && |
1050 | 66 | nOffsetSize != 1)) |
1051 | 40 | return 0; |
1052 | | |
1053 | 517 | if (m_nHeight) |
1054 | 517 | { |
1055 | 517 | if (nFileSize - nHeaderOffset < |
1056 | 517 | 32 + static_cast<vsi_l_offset>(nOffsetSize) * m_nHeight + |
1057 | 517 | 32) // No space for this section in this file |
1058 | 16 | return 0; |
1059 | | |
1060 | | // I leave the file prepared to read offsets |
1061 | 501 | if (VSIFSeekL(m_pfIMG, 16, SEEK_CUR)) |
1062 | 0 | return 0; |
1063 | 501 | } |
1064 | 0 | else |
1065 | 0 | { |
1066 | 0 | if (VSIFSeekL(m_pfIMG, 4, SEEK_CUR)) |
1067 | 0 | return 0; |
1068 | | |
1069 | 0 | if (VSIFSeekL(m_pfIMG, 4, SEEK_CUR)) |
1070 | 0 | return 0; |
1071 | | |
1072 | | // I leave the file prepared to read offsets |
1073 | 0 | if (VSIFSeekL(m_pfIMG, 8, SEEK_CUR)) |
1074 | 0 | return 0; |
1075 | 0 | } |
1076 | | |
1077 | | // There are offsets! |
1078 | 501 | return nOffsetSize; |
1079 | 517 | } // Fi de PositionAtStartOfRowOffsetsInFile() |
1080 | | |
1081 | | /************************************************************************/ |
1082 | | /* GetFileSize() */ |
1083 | | /************************************************************************/ |
1084 | | |
1085 | | vsi_l_offset MMRBand::GetFileSize() |
1086 | 517 | { |
1087 | 517 | if (m_nFileSize == 0) |
1088 | 517 | { |
1089 | 517 | const auto nCurPos = VSIFTellL(m_pfIMG); |
1090 | 517 | VSIFSeekL(m_pfIMG, 0, SEEK_END); |
1091 | 517 | m_nFileSize = VSIFTellL(m_pfIMG); |
1092 | 517 | VSIFSeekL(m_pfIMG, nCurPos, SEEK_SET); |
1093 | 517 | } |
1094 | 517 | return m_nFileSize; |
1095 | 517 | } |
1096 | | |
1097 | | /************************************************************************/ |
1098 | | /* FillRowOffsets() */ |
1099 | | /************************************************************************/ |
1100 | | |
1101 | | bool MMRBand::FillRowOffsets() |
1102 | 38.5k | { |
1103 | 38.5k | vsi_l_offset nStartOffset; |
1104 | 38.5k | int nIRow; |
1105 | 38.5k | vsi_l_offset nBytesPerPixelPerNCol; |
1106 | 38.5k | int nSizeToRead; // nSizeToRead is not an offset, but the size of the offsets being read |
1107 | | // directly from the IMG file (can be 1, 2, 4, or 8). |
1108 | 38.5k | vsi_l_offset nFileByte; |
1109 | 38.5k | size_t nMaxBytesPerCompressedRow; |
1110 | 38.5k | const int nGDALBlockSize = DIV_ROUND_UP(m_nBlockXSize, 8); |
1111 | | |
1112 | | // If it's filled, there is no need to fill it again |
1113 | 38.5k | if (!m_aFileOffsets.empty()) |
1114 | 35.3k | return true; |
1115 | | |
1116 | | // Sanity check to avoid attempting huge memory allocation |
1117 | 3.24k | if (m_nHeight > 1000 * 1000) |
1118 | 38 | { |
1119 | 38 | if (GetFileSize() < static_cast<vsi_l_offset>(m_nHeight)) |
1120 | 38 | { |
1121 | 38 | CPLError(CE_Failure, CPLE_AppDefined, "Too small file"); |
1122 | 38 | return false; |
1123 | 38 | } |
1124 | 38 | } |
1125 | | |
1126 | 3.20k | try |
1127 | 3.20k | { |
1128 | 3.20k | m_aFileOffsets.resize(static_cast<size_t>(m_nHeight) + 1); |
1129 | 3.20k | } |
1130 | 3.20k | catch (const std::bad_alloc &e) |
1131 | 3.20k | { |
1132 | 0 | CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what()); |
1133 | 0 | return false; |
1134 | 0 | } |
1135 | | |
1136 | 3.20k | switch (m_eMMDataType) |
1137 | 3.20k | { |
1138 | 57 | case MMDataType::DATATYPE_AND_COMPR_BIT: |
1139 | | |
1140 | | // "<=" it's ok. There is space and it's to make easier the programming |
1141 | 2.69M | for (nIRow = 0; nIRow <= m_nHeight; nIRow++) |
1142 | 2.69M | m_aFileOffsets[nIRow] = |
1143 | 2.69M | static_cast<vsi_l_offset>(nIRow) * nGDALBlockSize; |
1144 | 57 | break; |
1145 | | |
1146 | 162 | case MMDataType::DATATYPE_AND_COMPR_BYTE: |
1147 | 185 | case MMDataType::DATATYPE_AND_COMPR_INTEGER: |
1148 | 194 | case MMDataType::DATATYPE_AND_COMPR_UINTEGER: |
1149 | 207 | case MMDataType::DATATYPE_AND_COMPR_LONG: |
1150 | 255 | case MMDataType::DATATYPE_AND_COMPR_REAL: |
1151 | 280 | case MMDataType::DATATYPE_AND_COMPR_DOUBLE: |
1152 | 280 | nBytesPerPixelPerNCol = |
1153 | 280 | m_nDataTypeSizeBytes * static_cast<vsi_l_offset>(m_nWidth); |
1154 | | // "<=" it's ok. There is space and it's to make easier the programming |
1155 | 67.5M | for (nIRow = 0; nIRow <= m_nHeight; nIRow++) |
1156 | 67.5M | m_aFileOffsets[nIRow] = |
1157 | 67.5M | static_cast<vsi_l_offset>(nIRow) * nBytesPerPixelPerNCol; |
1158 | 280 | break; |
1159 | | |
1160 | 1.22k | case MMDataType::DATATYPE_AND_COMPR_BYTE_RLE: |
1161 | 1.52k | case MMDataType::DATATYPE_AND_COMPR_INTEGER_RLE: |
1162 | 1.84k | case MMDataType::DATATYPE_AND_COMPR_UINTEGER_RLE: |
1163 | 2.12k | case MMDataType::DATATYPE_AND_COMPR_LONG_RLE: |
1164 | 2.39k | case MMDataType::DATATYPE_AND_COMPR_REAL_RLE: |
1165 | 2.86k | case MMDataType::DATATYPE_AND_COMPR_DOUBLE_RLE: |
1166 | | |
1167 | 2.86k | nStartOffset = VSIFTellL(m_pfIMG); |
1168 | | |
1169 | | // Let's determine if are there offsets in the file |
1170 | 2.86k | if (0 < (nSizeToRead = PositionAtStartOfRowOffsetsInFile())) |
1171 | 501 | { |
1172 | | // I have offsets!! |
1173 | 501 | nFileByte = 0L; // all bits to 0 |
1174 | 1.90k | for (nIRow = 0; nIRow < m_nHeight; nIRow++) |
1175 | 1.42k | { |
1176 | 1.42k | if (VSIFReadL(&nFileByte, nSizeToRead, 1, m_pfIMG) != 1) |
1177 | 0 | return false; |
1178 | | |
1179 | 1.42k | m_aFileOffsets[nIRow] = nFileByte; |
1180 | | |
1181 | | // Let's check that the difference between two offsets is in a int range |
1182 | 1.42k | if (nIRow > 0) |
1183 | 928 | { |
1184 | 928 | if (m_aFileOffsets[nIRow] <= |
1185 | 928 | m_aFileOffsets[static_cast<size_t>(nIRow) - 1]) |
1186 | 22 | return false; |
1187 | | |
1188 | 906 | if (m_aFileOffsets[nIRow] - |
1189 | 906 | m_aFileOffsets[static_cast<size_t>(nIRow) - |
1190 | 906 | 1] >= |
1191 | 906 | static_cast<vsi_l_offset>(SIZE_MAX)) |
1192 | 6 | return false; |
1193 | 906 | } |
1194 | 1.42k | } |
1195 | 473 | m_aFileOffsets[nIRow] = 0; // Not reliable |
1196 | 473 | VSIFSeekL(m_pfIMG, nStartOffset, SEEK_SET); |
1197 | 473 | break; |
1198 | 501 | } |
1199 | | |
1200 | | // Not indexed RLE. We create a dynamic indexation |
1201 | 2.36k | if (m_nWidth > |
1202 | 2.36k | INT_MAX / |
1203 | 2.36k | (std::max(1, static_cast<int>(m_eMMBytesPerPixel)) + 1)) |
1204 | 0 | { |
1205 | 0 | CPLError(CE_Failure, CPLE_AppDefined, "Too large row: %d", |
1206 | 0 | m_nWidth); |
1207 | 0 | VSIFSeekL(m_pfIMG, nStartOffset, SEEK_SET); |
1208 | 0 | return false; |
1209 | 0 | } |
1210 | | |
1211 | 2.36k | nMaxBytesPerCompressedRow = |
1212 | 2.36k | static_cast<int>(m_eMMBytesPerPixel) |
1213 | 2.36k | ? (m_nWidth * (static_cast<int>(m_eMMBytesPerPixel) + 1)) |
1214 | 2.36k | : (m_nWidth * (1 + 1)); |
1215 | 2.36k | unsigned char *pBuffer; |
1216 | | |
1217 | 2.36k | if (nullptr == (pBuffer = static_cast<unsigned char *>( |
1218 | 2.36k | VSI_MALLOC_VERBOSE(nMaxBytesPerCompressedRow)))) |
1219 | 0 | { |
1220 | 0 | VSIFSeekL(m_pfIMG, nStartOffset, SEEK_SET); |
1221 | 0 | return false; |
1222 | 0 | } |
1223 | | |
1224 | 2.36k | VSIFSeekL(m_pfIMG, 0, SEEK_SET); |
1225 | 2.36k | m_aFileOffsets[0] = 0; |
1226 | 40.3M | for (nIRow = 0; nIRow < m_nHeight; nIRow++) |
1227 | 40.3M | { |
1228 | 40.3M | GetBlockData(pBuffer, SIZE_MAX); |
1229 | 40.3M | m_aFileOffsets[static_cast<size_t>(nIRow) + 1] = |
1230 | 40.3M | VSIFTellL(m_pfIMG); |
1231 | 40.3M | } |
1232 | 2.36k | VSIFree(pBuffer); |
1233 | 2.36k | VSIFSeekL(m_pfIMG, nStartOffset, SEEK_SET); |
1234 | 2.36k | break; |
1235 | | |
1236 | 0 | default: |
1237 | 0 | return false; |
1238 | 3.20k | } // End of switch (eMMDataType) |
1239 | 3.17k | return true; |
1240 | | |
1241 | 3.20k | } // End of FillRowOffsets() |