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 : * Permission is hereby granted, free of charge, to any person obtaining a
10 : * copy of this software and associated documentation files (the "Software"),
11 : * to deal in the Software without restriction, including without limitation
12 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 : * and/or sell copies of the Software, and to permit persons to whom the
14 : * Software is furnished to do so, subject to the following conditions:
15 : *
16 : * The above copyright notice and this permission notice shall be included
17 : * in all copies or substantial portions of the Software.
18 : *
19 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 : * DEALINGS IN THE SOFTWARE.
26 : ****************************************************************************/
27 :
28 : #include "core/cpcidskblockfile.h"
29 : #include "core/cpcidskfile.h"
30 : #include "segment/systiledir.h"
31 : #include "blockdir/asciitiledir.h"
32 : #include "blockdir/binarytiledir.h"
33 : #include "pcidsk_channel.h"
34 : #include <cassert>
35 : #include <algorithm>
36 :
37 : using namespace PCIDSK;
38 :
39 76 : CPCIDSKBlockFile::CPCIDSKBlockFile(PCIDSKFile * poFile)
40 76 : : mpoFile(dynamic_cast<CPCIDSKFile *>(poFile)),
41 76 : mnGrowingSegment(0)
42 : {
43 76 : assert(mpoFile);
44 76 : }
45 :
46 37 : SysTileDir * CPCIDSKBlockFile::GetTileDir(void)
47 : {
48 16 : SysTileDir * poTileDir = dynamic_cast<SysTileDir *>
49 53 : (mpoFile->GetSegment(SEG_SYS, "TileDir"));
50 :
51 37 : if (!poTileDir)
52 : {
53 1 : poTileDir = dynamic_cast<SysTileDir *>
54 17 : (mpoFile->GetSegment(SEG_SYS, "SysBMDir"));
55 : }
56 :
57 37 : return poTileDir;
58 : }
59 :
60 8 : SysTileDir * CPCIDSKBlockFile::CreateTileDir(void)
61 : {
62 8 : SysTileDir * poTileDir = nullptr;
63 :
64 8 : std::string oFileOptions = GetFileOptions();
65 :
66 100 : for (char & chIter : oFileOptions)
67 92 : chIter = (char) toupper(static_cast<unsigned char>(chIter));
68 :
69 : // Check if we should create a TILEV1 or TILEV2 block directory.
70 8 : bool bTileV1 = oFileOptions.find("TILEV1") != std::string::npos;
71 8 : bool bTileV2 = oFileOptions.find("TILEV2") != std::string::npos;
72 :
73 : // The TILEV1 block directory has a limit of 762GB, so default
74 : // to TILEV2 if the image file size exceed 512GB.
75 12 : if (!bTileV2 && !bTileV1 &&
76 4 : GetImageFileSize() > (uint64) 549755813888ULL)
77 : {
78 0 : bTileV2 = true;
79 : }
80 :
81 : // We now use TILEV2 by default.
82 8 : if (bTileV2 || !bTileV1)
83 : {
84 6 : const char * pszDesc = "Block Tile Directory - Do not modify.";
85 :
86 6 : size_t nSegmentSize = BinaryTileDir::GetOptimizedDirSize(this);
87 :
88 : int nSegment =
89 6 : mpoFile->CreateSegment("TileDir", pszDesc, SEG_SYS,
90 6 : (int) ((nSegmentSize + 511) / 512));
91 :
92 6 : poTileDir = dynamic_cast<SysTileDir *>(mpoFile->GetSegment(nSegment));
93 : }
94 : else
95 : {
96 2 : const char * pszDesc =
97 : "System Block Map Directory - Do not modify.";
98 :
99 2 : size_t nSegmentSize = AsciiTileDir::GetOptimizedDirSize(this);
100 :
101 : int nSegment =
102 2 : mpoFile->CreateSegment("SysBMDir", pszDesc, SEG_SYS,
103 2 : (int) ((nSegmentSize + 511) / 512));
104 :
105 2 : poTileDir = dynamic_cast<SysTileDir *>(mpoFile->GetSegment(nSegment));
106 : }
107 :
108 8 : assert(poTileDir);
109 :
110 8 : poTileDir->CreateTileDir();
111 :
112 16 : return poTileDir;
113 : }
114 :
115 0 : std::string CPCIDSKBlockFile::GetFilename(void) const
116 : {
117 0 : return mpoFile->GetFilename();
118 : }
119 :
120 16 : bool CPCIDSKBlockFile::GetUpdatable(void) const
121 : {
122 16 : return mpoFile->GetUpdatable();
123 : }
124 :
125 0 : uint32 CPCIDSKBlockFile::GetWidth(void) const
126 : {
127 0 : return mpoFile->GetWidth();
128 : }
129 :
130 0 : uint32 CPCIDSKBlockFile::GetHeight(void) const
131 : {
132 0 : return mpoFile->GetHeight();
133 : }
134 :
135 8 : uint32 CPCIDSKBlockFile::GetChannels(void) const
136 : {
137 8 : return mpoFile->GetChannels();
138 : }
139 :
140 28 : std::string CPCIDSKBlockFile::GetFileOptions(void) const
141 : {
142 28 : return mpoFile->GetMetadataValue("_DBLayout");
143 : }
144 :
145 20 : uint64 CPCIDSKBlockFile::GetImageFileSize(void) const
146 : {
147 20 : uint64 nImageSize = 0;
148 :
149 20 : int nChanCount = mpoFile->GetChannels();
150 :
151 40 : for (int iChan = 1; iChan <= nChanCount; iChan++)
152 : {
153 20 : PCIDSKChannel * poChannel = mpoFile->GetChannel(iChan);
154 :
155 20 : nImageSize += DataTypeSize(poChannel->GetType());
156 : }
157 :
158 20 : return nImageSize * mpoFile->GetWidth() * mpoFile->GetHeight();
159 : }
160 :
161 58 : bool CPCIDSKBlockFile::IsValidFileOffset(uint64 nOffset) const
162 : {
163 58 : return nOffset <= mpoFile->GetFileSize() * 512;
164 : }
165 :
166 46 : bool CPCIDSKBlockFile::IsCorruptedSegment(uint16 nSegment, uint64 nOffset, uint64 nSize) const
167 : {
168 46 : PCIDSKSegment * poSegment = mpoFile->GetSegment(nSegment);
169 :
170 46 : return (!poSegment ||
171 92 : nOffset + nSize > poSegment->GetContentSize() ||
172 92 : !IsValidFileOffset(nOffset + nSize + poSegment->GetContentOffset()));
173 : }
174 :
175 8 : uint16 CPCIDSKBlockFile::ExtendSegment(const std::string & oName,
176 : const std::string & oDesc,
177 : uint64 nExtendSize)
178 : {
179 : // Check to see if the cached growing segment is still valid.
180 8 : if (mnGrowingSegment > 0)
181 : {
182 0 : PCIDSKSegment * poSegment = mpoFile->GetSegment(mnGrowingSegment);
183 :
184 0 : if (!poSegment->IsAtEOF() || !poSegment->CanExtend(nExtendSize))
185 0 : mnGrowingSegment = 0;
186 : }
187 : else
188 : {
189 8 : mnGrowingSegment = 0;
190 : }
191 :
192 : // Try to find an extendable segment.
193 8 : if (mnGrowingSegment < 1)
194 : {
195 8 : int nSegment = 0;
196 :
197 : PCIDSKSegment * poSegment;
198 :
199 0 : while ((poSegment =
200 8 : mpoFile->GetSegment(SEG_SYS, oName, nSegment)) != nullptr)
201 : {
202 0 : nSegment = poSegment->GetSegmentNumber();
203 :
204 0 : if (poSegment->IsAtEOF() && poSegment->CanExtend(nExtendSize))
205 : {
206 0 : mnGrowingSegment = (uint16) nSegment;
207 0 : break;
208 : }
209 : }
210 : }
211 :
212 : // Create a new segment if we could not found an extendable segment.
213 8 : if (mnGrowingSegment < 1)
214 : {
215 8 : mnGrowingSegment =
216 8 : (uint16) mpoFile->CreateSegment(oName, oDesc, SEG_SYS, 0);
217 : }
218 :
219 8 : mpoFile->ExtendSegment(mnGrowingSegment, (nExtendSize + 511) / 512,
220 : false, false);
221 :
222 8 : return mnGrowingSegment;
223 : }
224 :
225 16 : uint64 CPCIDSKBlockFile::GetSegmentSize(uint16 nSegment)
226 : {
227 16 : PCIDSKSegment * poSegment = mpoFile->GetSegment(nSegment);
228 :
229 16 : return poSegment ? poSegment->GetContentSize() : 0;
230 : }
231 :
232 32 : void CPCIDSKBlockFile::WriteToSegment(uint16 nSegment, const void * pData,
233 : uint64 nOffset, uint64 nSize)
234 : {
235 32 : PCIDSKSegment * poSegment = mpoFile->GetSegment(nSegment);
236 :
237 32 : if (!poSegment)
238 0 : return;
239 :
240 32 : poSegment->WriteToFile(pData, nOffset, nSize);
241 : }
242 :
243 105 : void CPCIDSKBlockFile::ReadFromSegment(uint16 nSegment, void * pData,
244 : uint64 nOffset, uint64 nSize)
245 : {
246 105 : PCIDSKSegment * poSegment = mpoFile->GetSegment(nSegment);
247 :
248 105 : if (!poSegment)
249 0 : return;
250 :
251 105 : poSegment->ReadFromFile(pData, nOffset, nSize);
252 : }
|