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() override
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 : const int nFlags = (osAccess == "r") ? GDAL_OF_READONLY : GDAL_OF_UPDATE;
76 2 : poDS = GDALDataset::Open(osFilename.c_str(),
77 2 : nFlags | GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR);
78 2 : if (poDS == nullptr)
79 2 : ThrowPCIDSKException("%s", CPLGetLastErrorMsg());
80 :
81 0 : return new GDAL_EDBFile(poDS);
82 : }
83 :
84 : /************************************************************************/
85 : /* Close() */
86 : /************************************************************************/
87 :
88 0 : int GDAL_EDBFile::Close() const
89 :
90 : {
91 0 : if (poDS != nullptr)
92 : {
93 0 : delete poDS;
94 0 : const_cast<GDAL_EDBFile *>(this)->poDS = nullptr;
95 : }
96 :
97 0 : return 1;
98 : }
99 :
100 : /************************************************************************/
101 : /* GetWidth() */
102 : /************************************************************************/
103 :
104 0 : int GDAL_EDBFile::GetWidth() const
105 :
106 : {
107 0 : return poDS->GetRasterXSize();
108 : }
109 :
110 : /************************************************************************/
111 : /* GetHeight() */
112 : /************************************************************************/
113 :
114 0 : int GDAL_EDBFile::GetHeight() const
115 :
116 : {
117 0 : return poDS->GetRasterYSize();
118 : }
119 :
120 : /************************************************************************/
121 : /* GetChannels() */
122 : /************************************************************************/
123 :
124 0 : int GDAL_EDBFile::GetChannels() const
125 :
126 : {
127 0 : return poDS->GetRasterCount();
128 : }
129 :
130 : /************************************************************************/
131 : /* GetBlockWidth() */
132 : /************************************************************************/
133 :
134 0 : int GDAL_EDBFile::GetBlockWidth(int nChannel) const
135 :
136 : {
137 : int nWidth, nHeight;
138 :
139 0 : poDS->GetRasterBand(nChannel)->GetBlockSize(&nWidth, &nHeight);
140 :
141 0 : return nWidth;
142 : }
143 :
144 : /************************************************************************/
145 : /* GetBlockHeight() */
146 : /************************************************************************/
147 :
148 0 : int GDAL_EDBFile::GetBlockHeight(int nChannel) const
149 :
150 : {
151 : int nWidth, nHeight;
152 :
153 0 : poDS->GetRasterBand(nChannel)->GetBlockSize(&nWidth, &nHeight);
154 :
155 0 : return nHeight;
156 : }
157 :
158 : /************************************************************************/
159 : /* GetType() */
160 : /************************************************************************/
161 :
162 0 : eChanType GDAL_EDBFile::GetType(int nChannel) const
163 : {
164 0 : switch (poDS->GetRasterBand(nChannel)->GetRasterDataType())
165 : {
166 0 : case GDT_UInt8:
167 0 : return CHN_8U;
168 :
169 0 : case GDT_Int16:
170 0 : return CHN_16S;
171 :
172 0 : case GDT_UInt16:
173 0 : return CHN_16U;
174 :
175 0 : case GDT_Float32:
176 0 : return CHN_32R;
177 :
178 0 : case GDT_CInt16:
179 0 : return CHN_C16S;
180 :
181 0 : default:
182 0 : return CHN_UNKNOWN;
183 : }
184 : }
185 :
186 : /************************************************************************/
187 : /* ReadBlock() */
188 : /************************************************************************/
189 :
190 0 : int GDAL_EDBFile::ReadBlock(int channel, int block_index, void *buffer,
191 : int win_xoff, int win_yoff, int win_xsize,
192 : int win_ysize)
193 :
194 : {
195 0 : GDALRasterBand *poBand = poDS->GetRasterBand(channel);
196 :
197 0 : if (GetType(channel) == CHN_UNKNOWN)
198 : {
199 0 : ThrowPCIDSKException("%s channel type not supported for PCIDSK access.",
200 : GDALGetDataTypeName(poBand->GetRasterDataType()));
201 : }
202 :
203 : int nBlockXSize, nBlockYSize;
204 0 : poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
205 :
206 0 : const int nWidthInBlocks = DIV_ROUND_UP(poBand->GetXSize(), nBlockXSize);
207 :
208 0 : const int nBlockX = block_index % nWidthInBlocks;
209 0 : const int nBlockY = block_index / nWidthInBlocks;
210 :
211 : const int nPixelOffset =
212 0 : GDALGetDataTypeSizeBytes(poBand->GetRasterDataType());
213 0 : const int nLineOffset = win_xsize * nPixelOffset;
214 :
215 : /* -------------------------------------------------------------------- */
216 : /* Are we reading a partial block at the edge of the database? */
217 : /* If so, ensure we don't read off the database. */
218 : /* -------------------------------------------------------------------- */
219 0 : if (nBlockX * nBlockXSize + win_xoff + win_xsize > poBand->GetXSize())
220 0 : win_xsize = poBand->GetXSize() - nBlockX * nBlockXSize - win_xoff;
221 :
222 0 : if (nBlockY * nBlockYSize + win_yoff + win_ysize > poBand->GetYSize())
223 0 : win_ysize = poBand->GetYSize() - nBlockY * nBlockYSize - win_yoff;
224 :
225 0 : const CPLErr eErr = poBand->RasterIO(
226 0 : GF_Read, nBlockX * nBlockXSize + win_xoff,
227 0 : nBlockY * nBlockYSize + win_yoff, win_xsize, win_ysize, buffer,
228 : win_xsize, win_ysize, poBand->GetRasterDataType(), nPixelOffset,
229 : nLineOffset, nullptr);
230 :
231 0 : if (eErr != CE_None)
232 : {
233 0 : ThrowPCIDSKException("%s", CPLGetLastErrorMsg());
234 : }
235 :
236 0 : return 1;
237 : }
238 :
239 : /************************************************************************/
240 : /* WriteBlock() */
241 : /************************************************************************/
242 :
243 0 : int GDAL_EDBFile::WriteBlock(int channel, int block_index, void *buffer)
244 :
245 : {
246 0 : GDALRasterBand *poBand = poDS->GetRasterBand(channel);
247 :
248 0 : if (GetType(channel) == CHN_UNKNOWN)
249 : {
250 0 : ThrowPCIDSKException("%s channel type not supported for PCIDSK access.",
251 : GDALGetDataTypeName(poBand->GetRasterDataType()));
252 : }
253 :
254 : int nBlockXSize, nBlockYSize;
255 0 : poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
256 :
257 0 : const int nWidthInBlocks = DIV_ROUND_UP(poBand->GetXSize(), nBlockXSize);
258 :
259 0 : const int nBlockX = block_index % nWidthInBlocks;
260 0 : const int nBlockY = block_index / nWidthInBlocks;
261 :
262 : /* -------------------------------------------------------------------- */
263 : /* Are we reading a partial block at the edge of the database? */
264 : /* If so, ensure we don't read off the database. */
265 : /* -------------------------------------------------------------------- */
266 : int nWinXSize, nWinYSize;
267 :
268 0 : if (nBlockX * nBlockXSize + nBlockXSize > poBand->GetXSize())
269 0 : nWinXSize = poBand->GetXSize() - nBlockX * nBlockXSize;
270 : else
271 0 : nWinXSize = nBlockXSize;
272 :
273 0 : if (nBlockY * nBlockYSize + nBlockYSize > poBand->GetYSize())
274 0 : nWinYSize = poBand->GetYSize() - nBlockY * nBlockYSize;
275 : else
276 0 : nWinYSize = nBlockYSize;
277 :
278 : const CPLErr eErr =
279 0 : poBand->RasterIO(GF_Write, nBlockX * nBlockXSize, nBlockY * nBlockYSize,
280 : nWinXSize, nWinYSize, buffer, nWinXSize, nWinYSize,
281 : poBand->GetRasterDataType(), 0, 0, nullptr);
282 :
283 0 : if (eErr != CE_None)
284 : {
285 0 : ThrowPCIDSKException("%s", CPLGetLastErrorMsg());
286 : }
287 :
288 0 : return 1;
289 : }
|