Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: R Format Driver
4 : * Purpose: CreateCopy() implementation for R stats package object format.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2009, Frank Warmerdam <warmerdam@pobox.com>
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #include "cpl_port.h"
14 : #include "rdataset.h"
15 :
16 : #include <cstdio>
17 : #include <cstring>
18 : #include <string>
19 :
20 : #include "cpl_conv.h"
21 : #include "cpl_error.h"
22 : #include "cpl_progress.h"
23 : #include "cpl_string.h"
24 : #include "cpl_vsi.h"
25 : #include "gdal.h"
26 : #include "gdal_pam.h"
27 : #include "gdal_priv.h"
28 :
29 : GDALDataset *RCreateCopy(const char *pszFilename, GDALDataset *poSrcDS,
30 : int bStrict, char **papszOptions,
31 : GDALProgressFunc pfnProgress, void *pProgressData);
32 :
33 : /************************************************************************/
34 : /* ==================================================================== */
35 : /* Writer Implementation */
36 : /* ==================================================================== */
37 : /************************************************************************/
38 :
39 : /************************************************************************/
40 : /* RWriteInteger() */
41 : /************************************************************************/
42 :
43 360 : static void RWriteInteger(VSILFILE *fp, int bASCII, int nValue)
44 :
45 : {
46 360 : if (bASCII)
47 : {
48 20 : char szOutput[50] = {'\0'};
49 20 : snprintf(szOutput, sizeof(szOutput), "%d\n", nValue);
50 20 : VSIFWriteL(szOutput, 1, strlen(szOutput), fp);
51 : }
52 : else
53 : {
54 340 : CPL_MSBPTR32(&nValue);
55 340 : VSIFWriteL(&nValue, 4, 1, fp);
56 : }
57 360 : }
58 :
59 : /************************************************************************/
60 : /* RWriteString() */
61 : /************************************************************************/
62 :
63 36 : static void RWriteString(VSILFILE *fp, int bASCII, const char *pszValue)
64 :
65 : {
66 36 : RWriteInteger(fp, bASCII, 4105);
67 36 : RWriteInteger(fp, bASCII, static_cast<int>(strlen(pszValue)));
68 :
69 36 : if (bASCII)
70 : {
71 2 : VSIFWriteL(pszValue, 1, strlen(pszValue), fp);
72 2 : VSIFWriteL("\n", 1, 1, fp);
73 : }
74 : else
75 : {
76 34 : VSIFWriteL(pszValue, 1, static_cast<int>(strlen(pszValue)), fp);
77 : }
78 36 : }
79 :
80 : /************************************************************************/
81 : /* RCreateCopy() */
82 : /************************************************************************/
83 :
84 20 : GDALDataset *RCreateCopy(const char *pszFilename, GDALDataset *poSrcDS,
85 : CPL_UNUSED int bStrict, char **papszOptions,
86 : GDALProgressFunc pfnProgress, void *pProgressData)
87 : {
88 20 : const int nBands = poSrcDS->GetRasterCount();
89 20 : const int nXSize = poSrcDS->GetRasterXSize();
90 20 : const int nYSize = poSrcDS->GetRasterYSize();
91 20 : const bool bASCII = CPLFetchBool(papszOptions, "ASCII", false);
92 20 : const bool bCompressed = CPLFetchBool(papszOptions, "COMPRESS", !bASCII);
93 :
94 20 : vsi_l_offset nSize = static_cast<vsi_l_offset>(nBands) * nXSize * nYSize;
95 20 : if (nSize > static_cast<vsi_l_offset>(INT_MAX))
96 : {
97 0 : CPLError(CE_Failure, CPLE_NotSupported, "Too big raster");
98 0 : return nullptr;
99 : }
100 :
101 : // Some some rudimentary checks.
102 :
103 : // Setup the filename to actually use. We prefix with
104 : // /vsigzip/ if we want compressed output.
105 : const CPLString osAdjustedFilename =
106 60 : std::string(bCompressed ? "/vsigzip/" : "") + pszFilename;
107 :
108 : // Create the file.
109 20 : VSILFILE *fp = VSIFOpenL(osAdjustedFilename, "wb");
110 20 : if (fp == nullptr)
111 : {
112 2 : CPLError(CE_Failure, CPLE_OpenFailed, "Unable to create file %s.",
113 : pszFilename);
114 2 : return nullptr;
115 : }
116 :
117 : // Write header with version, etc.
118 18 : if (bASCII)
119 : {
120 1 : const char *pszHeader = "RDA2\nA\n";
121 1 : VSIFWriteL(pszHeader, 1, strlen(pszHeader), fp);
122 : }
123 : else
124 : {
125 17 : const char *pszHeader = "RDX2\nX\n";
126 17 : VSIFWriteL(pszHeader, 1, strlen(pszHeader), fp);
127 : }
128 :
129 18 : RWriteInteger(fp, bASCII, 2);
130 18 : RWriteInteger(fp, bASCII, 133377);
131 18 : RWriteInteger(fp, bASCII, 131840);
132 :
133 : // Establish the primary pairlist with one component object.
134 18 : RWriteInteger(fp, bASCII, 1026);
135 18 : RWriteInteger(fp, bASCII, 1);
136 :
137 : // Write the object name. Eventually we should derive this
138 : // from the filename, possible with override by a creation option.
139 18 : RWriteString(fp, bASCII, "gg");
140 :
141 : // For now we write the raster as a numeric array with attributes (526).
142 18 : RWriteInteger(fp, bASCII, 526);
143 18 : RWriteInteger(fp, bASCII, nXSize * nYSize * nBands);
144 :
145 : // Write the raster data.
146 18 : CPLErr eErr = CE_None;
147 :
148 : double *padfScanline =
149 18 : static_cast<double *>(CPLMalloc(nXSize * sizeof(double)));
150 :
151 45 : for (int iBand = 0; iBand < nBands; iBand++)
152 : {
153 27 : GDALRasterBand *poBand = poSrcDS->GetRasterBand(iBand + 1);
154 :
155 317 : for (int iLine = 0; iLine < nYSize && eErr == CE_None; iLine++)
156 : {
157 290 : eErr = poBand->RasterIO(GF_Read, 0, iLine, nXSize, 1, padfScanline,
158 : nXSize, 1, GDT_Float64, sizeof(double), 0,
159 : nullptr);
160 :
161 290 : if (bASCII)
162 : {
163 420 : for (int iValue = 0; iValue < nXSize; iValue++)
164 : {
165 400 : char szValue[128] = {'\0'};
166 400 : CPLsnprintf(szValue, sizeof(szValue), "%.16g\n",
167 400 : padfScanline[iValue]);
168 400 : VSIFWriteL(szValue, 1, strlen(szValue), fp);
169 : }
170 : }
171 : else
172 : {
173 3170 : for (int iValue = 0; iValue < nXSize; iValue++)
174 2900 : CPL_MSBPTR64(padfScanline + iValue);
175 :
176 270 : VSIFWriteL(padfScanline, 8, nXSize, fp);
177 : }
178 :
179 580 : if (eErr == CE_None &&
180 290 : !pfnProgress((iLine + 1) / static_cast<double>(nYSize), nullptr,
181 : pProgressData))
182 : {
183 0 : eErr = CE_Failure;
184 0 : CPLError(CE_Failure, CPLE_UserInterrupt,
185 : "User terminated CreateCopy()");
186 : }
187 : }
188 : }
189 :
190 18 : CPLFree(padfScanline);
191 :
192 : // Write out the dims attribute.
193 18 : RWriteInteger(fp, bASCII, 1026);
194 18 : RWriteInteger(fp, bASCII, 1);
195 :
196 18 : RWriteString(fp, bASCII, "dim");
197 :
198 18 : RWriteInteger(fp, bASCII, 13);
199 18 : RWriteInteger(fp, bASCII, 3);
200 18 : RWriteInteger(fp, bASCII, nXSize);
201 18 : RWriteInteger(fp, bASCII, nYSize);
202 18 : RWriteInteger(fp, bASCII, nBands);
203 :
204 18 : RWriteInteger(fp, bASCII, 254);
205 :
206 : // Terminate overall pairlist.
207 18 : RWriteInteger(fp, bASCII, 254);
208 :
209 : // Cleanup.
210 18 : VSIFCloseL(fp);
211 :
212 18 : if (eErr != CE_None)
213 0 : return nullptr;
214 :
215 : // Re-open dataset, and copy any auxiliary pam information.
216 : GDALPamDataset *poDS =
217 18 : static_cast<GDALPamDataset *>(GDALOpen(pszFilename, GA_ReadOnly));
218 :
219 18 : if (poDS)
220 2 : poDS->CloneInfo(poSrcDS, GCIF_PAM_DEFAULT);
221 :
222 18 : return poDS;
223 : }
|