/src/gdal/frmts/pcidsk/gdal_edb.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /****************************************************************************** |
2 | | * |
3 | | * Project: PCIDSK Database File |
4 | | * Purpose: External Database access interface implementation (EDBFile). |
5 | | * Author: Frank Warmerdam, warmerdam@pobox.com |
6 | | * |
7 | | ****************************************************************************** |
8 | | * Copyright (c) 2010, Frank Warmerdam <warmerdam@pobox.com> |
9 | | * |
10 | | * SPDX-License-Identifier: MIT |
11 | | ****************************************************************************/ |
12 | | |
13 | | #include "cpl_conv.h" |
14 | | #include "cpl_multiproc.h" |
15 | | #include "gdal_priv.h" |
16 | | #include "pcidsk.h" |
17 | | |
18 | | using PCIDSK::CHN_16S; |
19 | | using PCIDSK::CHN_16U; |
20 | | using PCIDSK::CHN_32R; |
21 | | using PCIDSK::CHN_8U; |
22 | | using PCIDSK::CHN_C16S; |
23 | | using PCIDSK::CHN_UNKNOWN; |
24 | | using PCIDSK::eChanType; |
25 | | using PCIDSK::EDBFile; |
26 | | using PCIDSK::ThrowPCIDSKException; |
27 | | |
28 | | EDBFile *GDAL_EDBOpen(const std::string &osFilename, |
29 | | const std::string &osAccess); |
30 | | |
31 | | /************************************************************************/ |
32 | | /* ==================================================================== */ |
33 | | /* GDAL_EDBFile */ |
34 | | /* ==================================================================== */ |
35 | | /************************************************************************/ |
36 | | |
37 | | class GDAL_EDBFile final : public EDBFile |
38 | | { |
39 | | GDALDataset *poDS; |
40 | | |
41 | | public: |
42 | | explicit GDAL_EDBFile(GDALDataset *poDSIn) |
43 | 15.2k | { |
44 | 15.2k | poDS = poDSIn; |
45 | 15.2k | } |
46 | | |
47 | | ~GDAL_EDBFile() |
48 | 15.2k | { |
49 | 15.2k | if (poDS) |
50 | 15.2k | GDAL_EDBFile::Close(); |
51 | 15.2k | } |
52 | | |
53 | | int Close() const override; |
54 | | int GetWidth() const override; |
55 | | int GetHeight() const override; |
56 | | int GetChannels() const override; |
57 | | int GetBlockWidth(int channel) const override; |
58 | | int GetBlockHeight(int channel) const override; |
59 | | eChanType GetType(int channel) const override; |
60 | | int ReadBlock(int channel, int block_index, void *buffer, int win_xoff, |
61 | | int win_yoff, int win_xsize, int win_ysize) override; |
62 | | int WriteBlock(int channel, int block_index, void *buffer) override; |
63 | | }; |
64 | | |
65 | | /************************************************************************/ |
66 | | /* GDAL_EDBOpen() */ |
67 | | /************************************************************************/ |
68 | | |
69 | | EDBFile *GDAL_EDBOpen(const std::string &osFilename, |
70 | | const std::string &osAccess) |
71 | | |
72 | 492k | { |
73 | 492k | GDALDataset *poDS = nullptr; |
74 | | |
75 | 492k | if (osAccess == "r") |
76 | 492k | poDS = |
77 | 492k | GDALDataset::FromHandle(GDALOpen(osFilename.c_str(), GA_ReadOnly)); |
78 | 0 | else |
79 | 0 | poDS = GDALDataset::FromHandle(GDALOpen(osFilename.c_str(), GA_Update)); |
80 | | |
81 | 492k | if (poDS == nullptr) |
82 | 477k | ThrowPCIDSKException("%s", CPLGetLastErrorMsg()); |
83 | | |
84 | 492k | return new GDAL_EDBFile(poDS); |
85 | 492k | } |
86 | | |
87 | | /************************************************************************/ |
88 | | /* Close() */ |
89 | | /************************************************************************/ |
90 | | |
91 | | int GDAL_EDBFile::Close() const |
92 | | |
93 | 15.2k | { |
94 | 15.2k | if (poDS != nullptr) |
95 | 15.2k | { |
96 | 15.2k | delete poDS; |
97 | 15.2k | const_cast<GDAL_EDBFile *>(this)->poDS = nullptr; |
98 | 15.2k | } |
99 | | |
100 | 15.2k | return 1; |
101 | 15.2k | } |
102 | | |
103 | | /************************************************************************/ |
104 | | /* GetWidth() */ |
105 | | /************************************************************************/ |
106 | | |
107 | | int GDAL_EDBFile::GetWidth() const |
108 | | |
109 | 0 | { |
110 | 0 | return poDS->GetRasterXSize(); |
111 | 0 | } |
112 | | |
113 | | /************************************************************************/ |
114 | | /* GetHeight() */ |
115 | | /************************************************************************/ |
116 | | |
117 | | int GDAL_EDBFile::GetHeight() const |
118 | | |
119 | 0 | { |
120 | 0 | return poDS->GetRasterYSize(); |
121 | 0 | } |
122 | | |
123 | | /************************************************************************/ |
124 | | /* GetChannels() */ |
125 | | /************************************************************************/ |
126 | | |
127 | | int GDAL_EDBFile::GetChannels() const |
128 | | |
129 | 0 | { |
130 | 0 | return poDS->GetRasterCount(); |
131 | 0 | } |
132 | | |
133 | | /************************************************************************/ |
134 | | /* GetBlockWidth() */ |
135 | | /************************************************************************/ |
136 | | |
137 | | int GDAL_EDBFile::GetBlockWidth(int nChannel) const |
138 | | |
139 | 0 | { |
140 | 0 | int nWidth, nHeight; |
141 | |
|
142 | 0 | poDS->GetRasterBand(nChannel)->GetBlockSize(&nWidth, &nHeight); |
143 | |
|
144 | 0 | return nWidth; |
145 | 0 | } |
146 | | |
147 | | /************************************************************************/ |
148 | | /* GetBlockHeight() */ |
149 | | /************************************************************************/ |
150 | | |
151 | | int GDAL_EDBFile::GetBlockHeight(int nChannel) const |
152 | | |
153 | 0 | { |
154 | 0 | int nWidth, nHeight; |
155 | |
|
156 | 0 | poDS->GetRasterBand(nChannel)->GetBlockSize(&nWidth, &nHeight); |
157 | |
|
158 | 0 | return nHeight; |
159 | 0 | } |
160 | | |
161 | | /************************************************************************/ |
162 | | /* GetType() */ |
163 | | /************************************************************************/ |
164 | | |
165 | | eChanType GDAL_EDBFile::GetType(int nChannel) const |
166 | 0 | { |
167 | 0 | switch (poDS->GetRasterBand(nChannel)->GetRasterDataType()) |
168 | 0 | { |
169 | 0 | case GDT_Byte: |
170 | 0 | return CHN_8U; |
171 | | |
172 | 0 | case GDT_Int16: |
173 | 0 | return CHN_16S; |
174 | | |
175 | 0 | case GDT_UInt16: |
176 | 0 | return CHN_16U; |
177 | | |
178 | 0 | case GDT_Float32: |
179 | 0 | return CHN_32R; |
180 | | |
181 | 0 | case GDT_CInt16: |
182 | 0 | return CHN_C16S; |
183 | | |
184 | 0 | default: |
185 | 0 | return CHN_UNKNOWN; |
186 | 0 | } |
187 | 0 | } |
188 | | |
189 | | /************************************************************************/ |
190 | | /* ReadBlock() */ |
191 | | /************************************************************************/ |
192 | | |
193 | | int GDAL_EDBFile::ReadBlock(int channel, int block_index, void *buffer, |
194 | | int win_xoff, int win_yoff, int win_xsize, |
195 | | int win_ysize) |
196 | | |
197 | 0 | { |
198 | 0 | GDALRasterBand *poBand = poDS->GetRasterBand(channel); |
199 | |
|
200 | 0 | if (GetType(channel) == CHN_UNKNOWN) |
201 | 0 | { |
202 | 0 | ThrowPCIDSKException("%s channel type not supported for PCIDSK access.", |
203 | 0 | GDALGetDataTypeName(poBand->GetRasterDataType())); |
204 | 0 | } |
205 | |
|
206 | 0 | int nBlockXSize, nBlockYSize; |
207 | 0 | poBand->GetBlockSize(&nBlockXSize, &nBlockYSize); |
208 | |
|
209 | 0 | const int nWidthInBlocks = DIV_ROUND_UP(poBand->GetXSize(), nBlockXSize); |
210 | |
|
211 | 0 | const int nBlockX = block_index % nWidthInBlocks; |
212 | 0 | const int nBlockY = block_index / nWidthInBlocks; |
213 | |
|
214 | 0 | const int nPixelOffset = |
215 | 0 | GDALGetDataTypeSize(poBand->GetRasterDataType()) / 8; |
216 | 0 | const int nLineOffset = win_xsize * nPixelOffset; |
217 | | |
218 | | /* -------------------------------------------------------------------- */ |
219 | | /* Are we reading a partial block at the edge of the database? */ |
220 | | /* If so, ensure we don't read off the database. */ |
221 | | /* -------------------------------------------------------------------- */ |
222 | 0 | if (nBlockX * nBlockXSize + win_xoff + win_xsize > poBand->GetXSize()) |
223 | 0 | win_xsize = poBand->GetXSize() - nBlockX * nBlockXSize - win_xoff; |
224 | |
|
225 | 0 | if (nBlockY * nBlockYSize + win_yoff + win_ysize > poBand->GetYSize()) |
226 | 0 | win_ysize = poBand->GetYSize() - nBlockY * nBlockYSize - win_yoff; |
227 | |
|
228 | 0 | const CPLErr eErr = poBand->RasterIO( |
229 | 0 | GF_Read, nBlockX * nBlockXSize + win_xoff, |
230 | 0 | nBlockY * nBlockYSize + win_yoff, win_xsize, win_ysize, buffer, |
231 | 0 | win_xsize, win_ysize, poBand->GetRasterDataType(), nPixelOffset, |
232 | 0 | nLineOffset, nullptr); |
233 | |
|
234 | 0 | if (eErr != CE_None) |
235 | 0 | { |
236 | 0 | ThrowPCIDSKException("%s", CPLGetLastErrorMsg()); |
237 | 0 | } |
238 | |
|
239 | 0 | return 1; |
240 | 0 | } |
241 | | |
242 | | /************************************************************************/ |
243 | | /* WriteBlock() */ |
244 | | /************************************************************************/ |
245 | | |
246 | | int GDAL_EDBFile::WriteBlock(int channel, int block_index, void *buffer) |
247 | | |
248 | 0 | { |
249 | 0 | GDALRasterBand *poBand = poDS->GetRasterBand(channel); |
250 | |
|
251 | 0 | if (GetType(channel) == CHN_UNKNOWN) |
252 | 0 | { |
253 | 0 | ThrowPCIDSKException("%s channel type not supported for PCIDSK access.", |
254 | 0 | GDALGetDataTypeName(poBand->GetRasterDataType())); |
255 | 0 | } |
256 | |
|
257 | 0 | int nBlockXSize, nBlockYSize; |
258 | 0 | poBand->GetBlockSize(&nBlockXSize, &nBlockYSize); |
259 | |
|
260 | 0 | const int nWidthInBlocks = DIV_ROUND_UP(poBand->GetXSize(), nBlockXSize); |
261 | |
|
262 | 0 | const int nBlockX = block_index % nWidthInBlocks; |
263 | 0 | const int nBlockY = block_index / nWidthInBlocks; |
264 | | |
265 | | /* -------------------------------------------------------------------- */ |
266 | | /* Are we reading a partial block at the edge of the database? */ |
267 | | /* If so, ensure we don't read off the database. */ |
268 | | /* -------------------------------------------------------------------- */ |
269 | 0 | int nWinXSize, nWinYSize; |
270 | |
|
271 | 0 | if (nBlockX * nBlockXSize + nBlockXSize > poBand->GetXSize()) |
272 | 0 | nWinXSize = poBand->GetXSize() - nBlockX * nBlockXSize; |
273 | 0 | else |
274 | 0 | nWinXSize = nBlockXSize; |
275 | |
|
276 | 0 | if (nBlockY * nBlockYSize + nBlockYSize > poBand->GetYSize()) |
277 | 0 | nWinYSize = poBand->GetYSize() - nBlockY * nBlockYSize; |
278 | 0 | else |
279 | 0 | nWinYSize = nBlockYSize; |
280 | |
|
281 | 0 | const CPLErr eErr = |
282 | 0 | poBand->RasterIO(GF_Write, nBlockX * nBlockXSize, nBlockY * nBlockYSize, |
283 | 0 | nWinXSize, nWinYSize, buffer, nWinXSize, nWinYSize, |
284 | 0 | poBand->GetRasterDataType(), 0, 0, nullptr); |
285 | |
|
286 | 0 | if (eErr != CE_None) |
287 | 0 | { |
288 | 0 | ThrowPCIDSKException("%s", CPLGetLastErrorMsg()); |
289 | 0 | } |
290 | |
|
291 | 0 | return 1; |
292 | 0 | } |