Line data Source code
1 : /******************************************************************************
2 : *
3 : * Purpose: Block directory API.
4 : *
5 : ******************************************************************************
6 : * Copyright (c) 2011
7 : * PCI Geomatics, 90 Allstate Parkway, Markham, Ontario, Canada.
8 : *
9 : * SPDX-License-Identifier: MIT
10 : ****************************************************************************/
11 :
12 : #include "blockdir/asciitilelayer.h"
13 : #include "blockdir/blockfile.h"
14 : #include "core/pcidsk_scanint.h"
15 : #include "pcidsk_exception.h"
16 : #include "pcidsk_buffer.h"
17 : #include <cstdlib>
18 : #include <cstring>
19 : #include <cstdio>
20 : #include <algorithm>
21 : #include <limits>
22 :
23 : using namespace PCIDSK;
24 :
25 : /************************************************************************/
26 : /* AsciiTileLayer() */
27 : /************************************************************************/
28 :
29 : /**
30 : * Constructor.
31 : *
32 : * @param poBlockDir The associated block directory.
33 : * @param nLayer The index of the block layer.
34 : * @param psBlockLayer The block layer info.
35 : * @param psTileLayer The tile layer info.
36 : */
37 22 : AsciiTileLayer::AsciiTileLayer(BlockDir * poBlockDir, uint32 nLayer,
38 : BlockLayerInfo * psBlockLayer,
39 22 : TileLayerInfo * psTileLayer)
40 22 : : BlockTileLayer(poBlockDir, nLayer, psBlockLayer, psTileLayer)
41 : {
42 22 : }
43 :
44 : /************************************************************************/
45 : /* ReadHeader() */
46 : /************************************************************************/
47 :
48 : /**
49 : * Reads the tile layer header from disk.
50 : */
51 5 : void AsciiTileLayer::ReadHeader(void)
52 : {
53 : uint8 abyHeader[128];
54 :
55 5 : uint8 * pabyHeaderIter = abyHeader;
56 :
57 5 : ReadFromLayer(abyHeader, 0, 128);
58 :
59 5 : mpsTileLayer->nXSize = ScanInt8(pabyHeaderIter);
60 5 : pabyHeaderIter += 8;
61 :
62 5 : mpsTileLayer->nYSize = ScanInt8(pabyHeaderIter);
63 5 : pabyHeaderIter += 8;
64 :
65 5 : mpsTileLayer->nTileXSize = ScanInt8(pabyHeaderIter);
66 5 : pabyHeaderIter += 8;
67 :
68 5 : mpsTileLayer->nTileYSize = ScanInt8(pabyHeaderIter);
69 5 : pabyHeaderIter += 8;
70 :
71 5 : memcpy(mpsTileLayer->szDataType, pabyHeaderIter, 4);
72 5 : pabyHeaderIter += 4;
73 : /*
74 : std::string oNoDataValue((char *) pabyHeaderIter,
75 : (char *) pabyHeaderIter + 18);
76 : */
77 5 : mpsTileLayer->bNoDataValid = false;
78 5 : mpsTileLayer->dfNoDataValue = 0.0;
79 5 : pabyHeaderIter += 18;
80 :
81 5 : memcpy(mpsTileLayer->szCompress, pabyHeaderIter, 8);
82 5 : }
83 :
84 : /************************************************************************/
85 : /* WriteTileList() */
86 : /************************************************************************/
87 :
88 : /**
89 : * Writes the tile list to disk.
90 : */
91 4 : void AsciiTileLayer::WriteTileList(void)
92 : {
93 4 : uint32 nTileCount = GetTileCount();
94 :
95 4 : size_t nSize = 128 + nTileCount * 20;
96 :
97 4 : char * pabyTileLayer = (char *) malloc(nSize + 1); // +1 for '\0'.
98 :
99 4 : if (!pabyTileLayer)
100 0 : return ThrowPCIDSKException("Out of memory in AsciiTileLayer::WriteTileList().");
101 :
102 8 : PCIDSKBuffer oTileLayerAutoPtr;
103 4 : oTileLayerAutoPtr.buffer = pabyTileLayer;
104 :
105 : // Write the tile layer header to disk.
106 4 : char * pabyHeaderIter = pabyTileLayer;
107 :
108 4 : memset(pabyTileLayer, ' ', 128);
109 :
110 4 : snprintf(pabyHeaderIter, 9, "%8d", mpsTileLayer->nXSize);
111 4 : pabyHeaderIter += 8;
112 :
113 4 : snprintf(pabyHeaderIter, 9, "%8d", mpsTileLayer->nYSize);
114 4 : pabyHeaderIter += 8;
115 :
116 4 : snprintf(pabyHeaderIter, 9, "%8d", mpsTileLayer->nTileXSize);
117 4 : pabyHeaderIter += 8;
118 :
119 4 : snprintf(pabyHeaderIter, 9, "%8d", mpsTileLayer->nTileYSize);
120 4 : pabyHeaderIter += 8;
121 :
122 4 : memcpy(pabyHeaderIter, mpsTileLayer->szDataType, 4);
123 4 : pabyHeaderIter += 4;
124 :
125 4 : if (mpsTileLayer->bNoDataValid)
126 0 : snprintf(pabyHeaderIter, 19, "%18.10E", mpsTileLayer->dfNoDataValue);
127 4 : pabyHeaderIter += 18;
128 :
129 4 : memcpy(pabyHeaderIter, mpsTileLayer->szCompress, 8);
130 :
131 : // Write the tile list to disk.
132 4 : char * pabyTileListIter = pabyTileLayer + 128;
133 :
134 8 : for (uint32 iTile = 0; iTile < nTileCount; iTile++)
135 : {
136 4 : BlockTileInfo * psTile = &moTileList[iTile];
137 :
138 4 : snprintf(pabyTileListIter, 13, "%12" PCIDSK_FRMT_64_WITHOUT_PREFIX "d", psTile->nOffset);
139 4 : pabyTileListIter += 12;
140 : }
141 :
142 : // We cannot write the offset and the size at the same time because
143 : // snprintf() inserts a '\0' in the first character of the first size.
144 8 : for (uint32 iTile = 0; iTile < nTileCount; iTile++)
145 : {
146 4 : BlockTileInfo * psTile = &moTileList[iTile];
147 :
148 4 : snprintf(pabyTileListIter, 9, "%8d", psTile->nSize);
149 4 : pabyTileListIter += 8;
150 : }
151 :
152 4 : WriteToLayer(pabyTileLayer, 0, nSize);
153 : }
154 :
155 : /************************************************************************/
156 : /* ReadTileList() */
157 : /************************************************************************/
158 :
159 : /**
160 : * Reads the tile list from disk.
161 : */
162 5 : void AsciiTileLayer::ReadTileList(void)
163 : {
164 5 : uint32 nTileCount = GetTileCount();
165 :
166 5 : uint64 nSize = static_cast<uint64>(nTileCount) * 20;
167 :
168 5 : if (128 + nSize > GetLayerSize() || !GetFile()->IsValidFileOffset(128 + nSize))
169 0 : return ThrowPCIDSKException("The tile layer is corrupted.");
170 :
171 : #if SIZEOF_VOIDP < 8
172 : if (nSize > std::numeric_limits<size_t>::max())
173 : return ThrowPCIDSKException("Unable to open extremely large tile layer on 32-bit system.");
174 : #endif
175 :
176 5 : uint8 * pabyTileList = (uint8 *) malloc(static_cast<size_t>(nSize));
177 :
178 5 : if (!pabyTileList)
179 0 : return ThrowPCIDSKException("Out of memory in AsciiTileLayer::ReadTileList().");
180 :
181 5 : PCIDSKBuffer oTileListAutoPtr;
182 5 : oTileListAutoPtr.buffer = (char *) pabyTileList;
183 :
184 5 : ReadFromLayer(pabyTileList, 128, nSize);
185 :
186 5 : uint8 * pabyTileOffsetIter = pabyTileList;
187 5 : uint8 * pabyTileSizeIter = pabyTileList + nTileCount * 12;
188 :
189 : try
190 : {
191 5 : moTileList.resize(nTileCount);
192 : }
193 0 : catch (const std::exception & ex)
194 : {
195 0 : return ThrowPCIDSKException("Out of memory in AsciiTileLayer::ReadTileList(): %s", ex.what());
196 : }
197 :
198 18 : for (uint32 iTile = 0; iTile < nTileCount; iTile++)
199 : {
200 13 : BlockTileInfo * psTile = &moTileList[iTile];
201 :
202 13 : psTile->nOffset = ScanInt12(pabyTileOffsetIter);
203 13 : pabyTileOffsetIter += 12;
204 :
205 13 : psTile->nSize = ScanInt8(pabyTileSizeIter);
206 13 : pabyTileSizeIter += 8;
207 : }
208 : }
|