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 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 : const int nPixelOffset =
215 0 : GDALGetDataTypeSizeBytes(poBand->GetRasterDataType());
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 : win_xsize, win_ysize, poBand->GetRasterDataType(), nPixelOffset,
232 : nLineOffset, nullptr);
233 :
234 0 : if (eErr != CE_None)
235 : {
236 0 : ThrowPCIDSKException("%s", CPLGetLastErrorMsg());
237 : }
238 :
239 0 : return 1;
240 : }
241 :
242 : /************************************************************************/
243 : /* WriteBlock() */
244 : /************************************************************************/
245 :
246 0 : int GDAL_EDBFile::WriteBlock(int channel, int block_index, void *buffer)
247 :
248 : {
249 0 : GDALRasterBand *poBand = poDS->GetRasterBand(channel);
250 :
251 0 : if (GetType(channel) == CHN_UNKNOWN)
252 : {
253 0 : ThrowPCIDSKException("%s channel type not supported for PCIDSK access.",
254 : GDALGetDataTypeName(poBand->GetRasterDataType()));
255 : }
256 :
257 : 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 : int nWinXSize, nWinYSize;
270 :
271 0 : if (nBlockX * nBlockXSize + nBlockXSize > poBand->GetXSize())
272 0 : nWinXSize = poBand->GetXSize() - nBlockX * nBlockXSize;
273 : else
274 0 : nWinXSize = nBlockXSize;
275 :
276 0 : if (nBlockY * nBlockYSize + nBlockYSize > poBand->GetYSize())
277 0 : nWinYSize = poBand->GetYSize() - nBlockY * nBlockYSize;
278 : else
279 0 : nWinYSize = nBlockYSize;
280 :
281 : const CPLErr eErr =
282 0 : poBand->RasterIO(GF_Write, nBlockX * nBlockXSize, nBlockY * nBlockYSize,
283 : nWinXSize, nWinYSize, buffer, nWinXSize, nWinYSize,
284 : poBand->GetRasterDataType(), 0, 0, nullptr);
285 :
286 0 : if (eErr != CE_None)
287 : {
288 0 : ThrowPCIDSKException("%s", CPLGetLastErrorMsg());
289 : }
290 :
291 0 : return 1;
292 : }
|