Line data Source code
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 0 : explicit GDAL_EDBFile(GDALDataset *poDSIn)
43 0 : {
44 0 : poDS = poDSIn;
45 0 : }
46 :
47 0 : ~GDAL_EDBFile()
48 0 : {
49 0 : if (poDS)
50 0 : GDAL_EDBFile::Close();
51 0 : }
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 2 : EDBFile *GDAL_EDBOpen(const std::string &osFilename,
70 : const std::string &osAccess)
71 :
72 : {
73 2 : GDALDataset *poDS = nullptr;
74 :
75 2 : if (osAccess == "r")
76 : poDS =
77 2 : GDALDataset::FromHandle(GDALOpen(osFilename.c_str(), GA_ReadOnly));
78 : else
79 0 : poDS = GDALDataset::FromHandle(GDALOpen(osFilename.c_str(), GA_Update));
80 :
81 2 : if (poDS == nullptr)
82 2 : ThrowPCIDSKException("%s", CPLGetLastErrorMsg());
83 :
84 0 : return new GDAL_EDBFile(poDS);
85 : }
86 :
87 : /************************************************************************/
88 : /* Close() */
89 : /************************************************************************/
90 :
91 0 : int GDAL_EDBFile::Close() const
92 :
93 : {
94 0 : if (poDS != nullptr)
95 : {
96 0 : delete poDS;
97 0 : const_cast<GDAL_EDBFile *>(this)->poDS = nullptr;
98 : }
99 :
100 0 : return 1;
101 : }
102 :
103 : /************************************************************************/
104 : /* GetWidth() */
105 : /************************************************************************/
106 :
107 0 : int GDAL_EDBFile::GetWidth() const
108 :
109 : {
110 0 : return poDS->GetRasterXSize();
111 : }
112 :
113 : /************************************************************************/
114 : /* GetHeight() */
115 : /************************************************************************/
116 :
117 0 : int GDAL_EDBFile::GetHeight() const
118 :
119 : {
120 0 : return poDS->GetRasterYSize();
121 : }
122 :
123 : /************************************************************************/
124 : /* GetChannels() */
125 : /************************************************************************/
126 :
127 0 : int GDAL_EDBFile::GetChannels() const
128 :
129 : {
130 0 : return poDS->GetRasterCount();
131 : }
132 :
133 : /************************************************************************/
134 : /* GetBlockWidth() */
135 : /************************************************************************/
136 :
137 0 : int GDAL_EDBFile::GetBlockWidth(int nChannel) const
138 :
139 : {
140 : int nWidth, nHeight;
141 :
142 0 : poDS->GetRasterBand(nChannel)->GetBlockSize(&nWidth, &nHeight);
143 :
144 0 : return nWidth;
145 : }
146 :
147 : /************************************************************************/
148 : /* GetBlockHeight() */
149 : /************************************************************************/
150 :
151 0 : int GDAL_EDBFile::GetBlockHeight(int nChannel) const
152 :
153 : {
154 : int nWidth, nHeight;
155 :
156 0 : poDS->GetRasterBand(nChannel)->GetBlockSize(&nWidth, &nHeight);
157 :
158 0 : return nHeight;
159 : }
160 :
161 : /************************************************************************/
162 : /* GetType() */
163 : /************************************************************************/
164 :
165 0 : eChanType GDAL_EDBFile::GetType(int nChannel) const
166 : {
167 0 : switch (poDS->GetRasterBand(nChannel)->GetRasterDataType())
168 : {
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 : }
187 : }
188 :
189 : /************************************************************************/
190 : /* ReadBlock() */
191 : /************************************************************************/
192 :
193 0 : 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 : {
198 0 : GDALRasterBand *poBand = poDS->GetRasterBand(channel);
199 :
200 0 : if (GetType(channel) == CHN_UNKNOWN)
201 : {
202 0 : ThrowPCIDSKException("%s channel type not supported for PCIDSK access.",
203 : GDALGetDataTypeName(poBand->GetRasterDataType()));
204 : }
205 :
206 : int nBlockXSize, nBlockYSize;
207 0 : poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
208 :
209 : const int nWidthInBlocks =
210 0 : (poBand->GetXSize() + nBlockXSize - 1) / nBlockXSize;
211 :
212 0 : const int nBlockX = block_index % nWidthInBlocks;
213 0 : const int nBlockY = block_index / nWidthInBlocks;
214 :
215 : const int nPixelOffset =
216 0 : GDALGetDataTypeSize(poBand->GetRasterDataType()) / 8;
217 0 : const int nLineOffset = win_xsize * nPixelOffset;
218 :
219 : /* -------------------------------------------------------------------- */
220 : /* Are we reading a partial block at the edge of the database? */
221 : /* If so, ensure we don't read off the database. */
222 : /* -------------------------------------------------------------------- */
223 0 : if (nBlockX * nBlockXSize + win_xoff + win_xsize > poBand->GetXSize())
224 0 : win_xsize = poBand->GetXSize() - nBlockX * nBlockXSize - win_xoff;
225 :
226 0 : if (nBlockY * nBlockYSize + win_yoff + win_ysize > poBand->GetYSize())
227 0 : win_ysize = poBand->GetYSize() - nBlockY * nBlockYSize - win_yoff;
228 :
229 0 : const CPLErr eErr = poBand->RasterIO(
230 0 : GF_Read, nBlockX * nBlockXSize + win_xoff,
231 0 : nBlockY * nBlockYSize + win_yoff, win_xsize, win_ysize, buffer,
232 : win_xsize, win_ysize, poBand->GetRasterDataType(), nPixelOffset,
233 : nLineOffset, nullptr);
234 :
235 0 : if (eErr != CE_None)
236 : {
237 0 : ThrowPCIDSKException("%s", CPLGetLastErrorMsg());
238 : }
239 :
240 0 : return 1;
241 : }
242 :
243 : /************************************************************************/
244 : /* WriteBlock() */
245 : /************************************************************************/
246 :
247 0 : int GDAL_EDBFile::WriteBlock(int channel, int block_index, void *buffer)
248 :
249 : {
250 0 : GDALRasterBand *poBand = poDS->GetRasterBand(channel);
251 :
252 0 : if (GetType(channel) == CHN_UNKNOWN)
253 : {
254 0 : ThrowPCIDSKException("%s channel type not supported for PCIDSK access.",
255 : GDALGetDataTypeName(poBand->GetRasterDataType()));
256 : }
257 :
258 : int nBlockXSize, nBlockYSize;
259 0 : poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
260 :
261 : const int nWidthInBlocks =
262 0 : (poBand->GetXSize() + nBlockXSize - 1) / nBlockXSize;
263 :
264 0 : const int nBlockX = block_index % nWidthInBlocks;
265 0 : const int nBlockY = block_index / nWidthInBlocks;
266 :
267 : /* -------------------------------------------------------------------- */
268 : /* Are we reading a partial block at the edge of the database? */
269 : /* If so, ensure we don't read off the database. */
270 : /* -------------------------------------------------------------------- */
271 : int nWinXSize, nWinYSize;
272 :
273 0 : if (nBlockX * nBlockXSize + nBlockXSize > poBand->GetXSize())
274 0 : nWinXSize = poBand->GetXSize() - nBlockX * nBlockXSize;
275 : else
276 0 : nWinXSize = nBlockXSize;
277 :
278 0 : if (nBlockY * nBlockYSize + nBlockYSize > poBand->GetYSize())
279 0 : nWinYSize = poBand->GetYSize() - nBlockY * nBlockYSize;
280 : else
281 0 : nWinYSize = nBlockYSize;
282 :
283 : const CPLErr eErr =
284 0 : poBand->RasterIO(GF_Write, nBlockX * nBlockXSize, nBlockY * nBlockYSize,
285 : nWinXSize, nWinYSize, buffer, nWinXSize, nWinYSize,
286 : poBand->GetRasterDataType(), 0, 0, nullptr);
287 :
288 0 : if (eErr != CE_None)
289 : {
290 0 : ThrowPCIDSKException("%s", CPLGetLastErrorMsg());
291 : }
292 :
293 0 : return 1;
294 : }
|