Coverage Report

Created: 2025-12-03 08:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/frmts/pcidsk/sdk/segment/cpcidsk_array.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Purpose:  Implementation of the CPCIDSK_TEX class.
4
 *
5
 ******************************************************************************
6
 * Copyright (c) 2010
7
 * PCI Geomatics, 90 Allstate Parkway, Markham, Ontario, Canada.
8
 *
9
 * SPDX-License-Identifier: MIT
10
 ****************************************************************************/
11
12
#include "pcidsk_exception.h"
13
#include "segment/cpcidsk_array.h"
14
#include "core/cpcidskfile.h"
15
#include <cstring>
16
#include <sstream>
17
#include <cassert>
18
#include "core/pcidsk_utils.h"
19
20
using namespace PCIDSK;
21
22
0
PCIDSK_ARRAY::~PCIDSK_ARRAY() = default;
23
24
/************************************************************************/
25
/*                            CPCIDSK_ARRAY()                           */
26
/************************************************************************/
27
28
CPCIDSK_ARRAY::CPCIDSK_ARRAY( PCIDSKFile *fileIn, int segmentIn,
29
                              const char *segment_pointer )
30
0
        : CPCIDSKSegment( fileIn, segmentIn, segment_pointer ),
31
0
        loaded_(false),mbModified(false)
32
0
{
33
0
    MAX_DIMENSIONS = 8;
34
0
    Load();
35
0
}
Unexecuted instantiation: PCIDSK::CPCIDSK_ARRAY::CPCIDSK_ARRAY(PCIDSK::PCIDSKFile*, int, char const*)
Unexecuted instantiation: PCIDSK::CPCIDSK_ARRAY::CPCIDSK_ARRAY(PCIDSK::PCIDSKFile*, int, char const*)
36
37
/************************************************************************/
38
/*                            ~CPCIDSK_ARRAY                            */
39
/************************************************************************/
40
41
CPCIDSK_ARRAY::~CPCIDSK_ARRAY()
42
43
0
{
44
0
}
45
46
/**
47
 * Load the contents of the segment
48
 */
49
void CPCIDSK_ARRAY::Load()
50
0
{
51
    // Check if we've already loaded the segment into memory
52
0
    if (loaded_) {
53
0
        return;
54
0
    }
55
56
0
    PCIDSKBuffer& seg_header = this->GetHeader();
57
0
    seg_data.SetSize(!IsContentSizeValid() ? -1 : // will throw exception
58
0
                     static_cast<int>(GetContentSize()));
59
0
    ReadFromFile(seg_data.buffer, 0, seg_data.buffer_size);
60
61
0
    if(!STARTS_WITH(seg_header.buffer+160, "64R     "))
62
0
    {
63
0
        seg_header.Put("64R     ",160,8);
64
0
        loaded_ = true;
65
0
        return ;
66
0
    }
67
68
0
    int nDimension = seg_header.GetInt(160+8,8);
69
0
    if(nDimension < 1 || nDimension > MAX_DIMENSIONS)
70
0
    {
71
0
        std::stringstream oStream;
72
0
        oStream << "Invalid array dimension " << nDimension;
73
0
        oStream << " stored in the segment.";
74
0
        std::string oMsg = oStream.str();
75
0
        return ThrowPCIDSKException("%s", oMsg.c_str());
76
0
    }
77
0
    mnDimension = static_cast<unsigned char>(nDimension);
78
79
0
    moSizes.clear();
80
0
    for( int i = 0; i < mnDimension; i++ )
81
0
    {
82
0
        int nSize = seg_header.GetInt(160+24 + i*8,8);
83
0
        if(nSize < 1)
84
0
        {
85
0
            std::stringstream oStream;
86
0
            oStream << "Invalid size " << nSize << " for dimension " << i+1;
87
0
            std::string oMsg = oStream.str();
88
0
            return ThrowPCIDSKException("%s", oMsg.c_str());
89
0
        }
90
0
        moSizes.push_back( nSize );
91
0
    }
92
93
    //calculate the total number of elements in the array.
94
0
    unsigned int nElements = 1;
95
0
    for(unsigned int i=0 ; i < moSizes.size() ; i++)
96
0
    {
97
0
        nElements *= moSizes[i];
98
0
    }
99
100
0
    moArray.resize(nElements);
101
0
    for( unsigned int i = 0; i < nElements; i++ )
102
0
    {
103
0
        const double* pdValue = (const double*)seg_data.Get(i*8,8);
104
0
        char uValue[8];
105
0
        std::memcpy(uValue,pdValue,8);
106
0
        SwapData(uValue,8,1);
107
0
        memcpy(&moArray[i], uValue, 8);
108
0
    }
109
110
    //PCIDSK doesn't have support for headers.
111
112
    // We've now loaded the structure up with data. Mark it as being loaded
113
    // properly.
114
0
    loaded_ = true;
115
116
0
}
117
118
/**
119
 * Write the segment on disk
120
 */
121
void CPCIDSK_ARRAY::Write(void)
122
0
{
123
    //We are not writing if nothing was loaded.
124
0
    if (!loaded_) {
125
0
        return;
126
0
    }
127
128
0
    PCIDSKBuffer& seg_header = this->GetHeader();
129
0
    int nBlocks = (static_cast<int>(moArray.size())*8 + 511)/512 ;
130
0
    unsigned int nSizeBuffer = (nBlocks)*512 ;
131
    //64 values can be put into 512 bytes.
132
0
    unsigned int nRest = nBlocks*64 - static_cast<unsigned int>(moArray.size());
133
134
0
    seg_data.SetSize(nSizeBuffer);
135
136
0
    seg_header.Put("64R     ",160,8);
137
0
    seg_header.Put((int)mnDimension,160+8,8);
138
139
0
    for( int i = 0; i < mnDimension; i++ )
140
0
    {
141
0
        int nSize = static_cast<int>(moSizes[i]);
142
0
        seg_header.Put(nSize,160+24 + i*8,8);
143
0
    }
144
145
0
    for( unsigned int i = 0; i < moArray.size(); i++ )
146
0
    {
147
0
        double dValue = moArray[i];
148
0
        SwapData(&dValue,8,1);
149
0
        seg_data.PutBin(dValue,i*8);
150
0
    }
151
152
    //set the end of the buffer to 0.
153
0
    for( unsigned int i=0 ; i < nRest ; i++)
154
0
    {
155
0
        seg_data.Put(0.0,(static_cast<int>(moArray.size())+i)*8,8,"%22.14f");
156
0
    }
157
158
0
    WriteToFile(seg_data.buffer,0,seg_data.buffer_size);
159
160
0
    mbModified = false;
161
0
}
162
163
/**
164
 * Synchronize the segment, if it was modified then
165
 * write it into disk.
166
 */
167
void CPCIDSK_ARRAY::Synchronize()
168
0
{
169
0
    if(mbModified)
170
0
    {
171
0
        this->Write();
172
        //write the modified header
173
0
        file->WriteToFile( header.buffer, data_offset, 1024 );
174
0
    }
175
0
}
176
177
/**
178
 * This function returns the number of dimension in the array.
179
 * an array segment can have minimum 1 dimension and maximum
180
 * 8 dimension.
181
 *
182
 * @return the dimension of the array in [1,8]
183
 */
184
unsigned char CPCIDSK_ARRAY::GetDimensionCount() const
185
0
{
186
0
    return mnDimension;
187
0
}
188
189
/**
190
 * This function set the dimension of the array. the dimension
191
 * must be in [1,8] or a pci::Exception is thrown.
192
 *
193
 * @param nDim number of dimension, should be in [1,8]
194
 */
195
void CPCIDSK_ARRAY::SetDimensionCount(unsigned char nDim)
196
0
{
197
0
    if( !file->GetUpdatable() )
198
0
        return ThrowPCIDSKException("File not open for update.");
199
0
    if(nDim < 1 || nDim > 8)
200
0
    {
201
0
        return ThrowPCIDSKException("An array cannot have a "
202
0
            "dimension bigger than 8 or smaller than 1.");
203
0
    }
204
0
    mnDimension = nDim;
205
0
    mbModified = true;
206
0
}
207
208
/**
209
 * Get the number of element that can be put in each of the dimension
210
 * of the array. the size of the return vector is GetDimensionCount().
211
 *
212
 * @return the size of each dimension.
213
 */
214
const std::vector<unsigned int>& CPCIDSK_ARRAY::GetSizes() const
215
0
{
216
0
    return moSizes;
217
0
}
218
219
/**
220
 * Set the size of each dimension. If the size of the array is bigger
221
 * or smaller than GetDimensionCount(), then a pci::Exception is thrown
222
 * if one of the sizes is 0, then a pci::Exception is thrown.
223
 *
224
 * @param oSizes the size of each dimension
225
 */
226
void CPCIDSK_ARRAY::SetSizes(const std::vector<unsigned int>& oSizes)
227
0
{
228
0
    if(oSizes.size() != GetDimensionCount())
229
0
    {
230
0
        return ThrowPCIDSKException("You need to specify the sizes"
231
0
            " for each dimension of the array");
232
0
    }
233
234
0
    for( unsigned int i=0 ; i < oSizes.size() ; i++)
235
0
    {
236
0
        if(oSizes[i] == 0)
237
0
        {
238
0
            return ThrowPCIDSKException("You cannot define the size of a dimension to 0.");
239
0
        }
240
0
    }
241
0
    moSizes = oSizes;
242
0
    mbModified = true;
243
0
}
244
245
/**
246
 * Get the array in a vector. the size of this vector is
247
 * GetSize()[0]*GetSize()[2]*...*GetSize()[GetDimensionCount()-1].
248
 * value are stored in the following order inside this vector:
249
 * ViDj = Value i of Dimension j
250
 * n = size of dimension 1
251
 * p = size of dimension 2
252
 * h = size of dimension k
253
 *
254
 * V1D1 ... VnD1 V1D2 ... VpD2 ... V1Dk ... VhDk
255
 *
256
 * @return the array.
257
 */
258
const std::vector<double>& CPCIDSK_ARRAY::GetArray() const
259
0
{
260
0
    return moArray;
261
0
}
262
263
/**
264
 * Set the array in the segment. the size of this vector is
265
 * GetSize()[0]*GetSize()[2]*...*GetSize()[GetDimensionCount()-1].
266
 * value are stored in the following order inside this vector:
267
 * ViDj = Value i of Dimension j
268
 * n = size of dimension 1
269
 * p = size of dimension 2
270
 * h = size of dimension k
271
 *
272
 * V1D1 ... VnD1 V1D2 ... VpD2 ... V1Dk ... VhDk
273
 *
274
 * If the size of oArray doesn't match the sizes and dimensions
275
 * then a pci::Exception is thrown.
276
 *
277
 * @param oArray the array.
278
 */
279
void CPCIDSK_ARRAY::SetArray(const std::vector<double>& oArray)
280
0
{
281
0
    if( !file->GetUpdatable() )
282
0
        return ThrowPCIDSKException("File not open for update.");
283
0
    unsigned int nLength = 1;
284
0
    for( unsigned int i=0 ; i < moSizes.size() ; i++)
285
0
    {
286
0
        nLength *= moSizes[i];
287
0
    }
288
289
0
    if(nLength != oArray.size())
290
0
    {
291
0
        return ThrowPCIDSKException("the size of this array doesn't match "
292
0
            "the size specified in GetSizes(). See documentation for"
293
0
            " more information.");
294
0
    }
295
0
    moArray = oArray;
296
0
    mbModified = true;
297
0
}
298
299
/**
300
 * Get the headers of this array. If no headers has be specified, then
301
 * this function return an empty vector.
302
 * the size of this vector should be equal to the size of the first dimension
303
 * returned by GetSize()[0]
304
 *
305
 * @return the headers.
306
 */
307
const std::vector<std::string>&  CPCIDSK_ARRAY::GetHeaders() const
308
0
{
309
0
    return moHeaders;
310
0
}
311
312
/**
313
 * Set the headers of this array. An empty vector can be specified to clear
314
 * the headers in the segment.
315
 * the size of this vector should be equal to the size of the first dimension
316
 * returned by GetSize()[0]. If it is not the case, a pci::Exception is thrown.
317
 *
318
 * @param oHeaders the headers.
319
 */
320
void CPCIDSK_ARRAY::SetHeaders(const std::vector<std::string>& oHeaders)
321
0
{
322
0
    moHeaders = oHeaders;
323
0
    mbModified = true;
324
0
}