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 "core/cpcidskblockfile.h" 13 : #include "core/cpcidskfile.h" 14 : #include "segment/systiledir.h" 15 : #include "blockdir/asciitiledir.h" 16 : #include "blockdir/binarytiledir.h" 17 : #include "pcidsk_channel.h" 18 : #include <cassert> 19 : #include <algorithm> 20 : 21 : using namespace PCIDSK; 22 : 23 76 : CPCIDSKBlockFile::CPCIDSKBlockFile(PCIDSKFile * poFile) 24 76 : : mpoFile(dynamic_cast<CPCIDSKFile *>(poFile)), 25 76 : mnGrowingSegment(0) 26 : { 27 76 : assert(mpoFile); 28 76 : } 29 : 30 37 : SysTileDir * CPCIDSKBlockFile::GetTileDir(void) 31 : { 32 16 : SysTileDir * poTileDir = dynamic_cast<SysTileDir *> 33 53 : (mpoFile->GetSegment(SEG_SYS, "TileDir")); 34 : 35 37 : if (!poTileDir) 36 : { 37 1 : poTileDir = dynamic_cast<SysTileDir *> 38 17 : (mpoFile->GetSegment(SEG_SYS, "SysBMDir")); 39 : } 40 : 41 37 : return poTileDir; 42 : } 43 : 44 8 : SysTileDir * CPCIDSKBlockFile::CreateTileDir(void) 45 : { 46 8 : SysTileDir * poTileDir = nullptr; 47 : 48 8 : std::string oFileOptions = GetFileOptions(); 49 : 50 100 : for (char & chIter : oFileOptions) 51 92 : chIter = (char) toupper(static_cast<unsigned char>(chIter)); 52 : 53 : // Check if we should create a TILEV1 or TILEV2 block directory. 54 8 : bool bTileV1 = oFileOptions.find("TILEV1") != std::string::npos; 55 8 : bool bTileV2 = oFileOptions.find("TILEV2") != std::string::npos; 56 : 57 : // The TILEV1 block directory has a limit of 762GB, so default 58 : // to TILEV2 if the image file size exceed 512GB. 59 12 : if (!bTileV2 && !bTileV1 && 60 4 : GetImageFileSize() > (uint64) 549755813888ULL) 61 : { 62 0 : bTileV2 = true; 63 : } 64 : 65 : // We now use TILEV2 by default. 66 8 : if (bTileV2 || !bTileV1) 67 : { 68 6 : const char * pszDesc = "Block Tile Directory - Do not modify."; 69 : 70 6 : size_t nSegmentSize = BinaryTileDir::GetOptimizedDirSize(this); 71 : 72 : int nSegment = 73 6 : mpoFile->CreateSegment("TileDir", pszDesc, SEG_SYS, 74 6 : (int) ((nSegmentSize + 511) / 512)); 75 : 76 6 : poTileDir = dynamic_cast<SysTileDir *>(mpoFile->GetSegment(nSegment)); 77 : } 78 : else 79 : { 80 2 : const char * pszDesc = 81 : "System Block Map Directory - Do not modify."; 82 : 83 2 : size_t nSegmentSize = AsciiTileDir::GetOptimizedDirSize(this); 84 : 85 : int nSegment = 86 2 : mpoFile->CreateSegment("SysBMDir", pszDesc, SEG_SYS, 87 2 : (int) ((nSegmentSize + 511) / 512)); 88 : 89 2 : poTileDir = dynamic_cast<SysTileDir *>(mpoFile->GetSegment(nSegment)); 90 : } 91 : 92 8 : assert(poTileDir); 93 : 94 8 : poTileDir->CreateTileDir(); 95 : 96 16 : return poTileDir; 97 : } 98 : 99 0 : std::string CPCIDSKBlockFile::GetFilename(void) const 100 : { 101 0 : return mpoFile->GetFilename(); 102 : } 103 : 104 16 : bool CPCIDSKBlockFile::GetUpdatable(void) const 105 : { 106 16 : return mpoFile->GetUpdatable(); 107 : } 108 : 109 0 : uint32 CPCIDSKBlockFile::GetWidth(void) const 110 : { 111 0 : return mpoFile->GetWidth(); 112 : } 113 : 114 0 : uint32 CPCIDSKBlockFile::GetHeight(void) const 115 : { 116 0 : return mpoFile->GetHeight(); 117 : } 118 : 119 8 : uint32 CPCIDSKBlockFile::GetChannels(void) const 120 : { 121 8 : return mpoFile->GetChannels(); 122 : } 123 : 124 28 : std::string CPCIDSKBlockFile::GetFileOptions(void) const 125 : { 126 28 : return mpoFile->GetMetadataValue("_DBLayout"); 127 : } 128 : 129 20 : uint64 CPCIDSKBlockFile::GetImageFileSize(void) const 130 : { 131 20 : uint64 nImageSize = 0; 132 : 133 20 : int nChanCount = mpoFile->GetChannels(); 134 : 135 40 : for (int iChan = 1; iChan <= nChanCount; iChan++) 136 : { 137 20 : PCIDSKChannel * poChannel = mpoFile->GetChannel(iChan); 138 : 139 20 : nImageSize += DataTypeSize(poChannel->GetType()); 140 : } 141 : 142 20 : return nImageSize * mpoFile->GetWidth() * mpoFile->GetHeight(); 143 : } 144 : 145 58 : bool CPCIDSKBlockFile::IsValidFileOffset(uint64 nOffset) const 146 : { 147 58 : return nOffset <= mpoFile->GetFileSize() * 512; 148 : } 149 : 150 46 : bool CPCIDSKBlockFile::IsCorruptedSegment(uint16 nSegment, uint64 nOffset, uint64 nSize) const 151 : { 152 46 : PCIDSKSegment * poSegment = mpoFile->GetSegment(nSegment); 153 : 154 46 : return (!poSegment || 155 92 : nOffset + nSize > poSegment->GetContentSize() || 156 92 : !IsValidFileOffset(nOffset + nSize + poSegment->GetContentOffset())); 157 : } 158 : 159 8 : uint16 CPCIDSKBlockFile::ExtendSegment(const std::string & oName, 160 : const std::string & oDesc, 161 : uint64 nExtendSize) 162 : { 163 : // Check to see if the cached growing segment is still valid. 164 8 : if (mnGrowingSegment > 0) 165 : { 166 0 : PCIDSKSegment * poSegment = mpoFile->GetSegment(mnGrowingSegment); 167 : 168 0 : if (!poSegment->IsAtEOF() || !poSegment->CanExtend(nExtendSize)) 169 0 : mnGrowingSegment = 0; 170 : } 171 : else 172 : { 173 8 : mnGrowingSegment = 0; 174 : } 175 : 176 : // Try to find an extendable segment. 177 8 : if (mnGrowingSegment < 1) 178 : { 179 8 : int nSegment = 0; 180 : 181 : PCIDSKSegment * poSegment; 182 : 183 0 : while ((poSegment = 184 8 : mpoFile->GetSegment(SEG_SYS, oName, nSegment)) != nullptr) 185 : { 186 0 : nSegment = poSegment->GetSegmentNumber(); 187 : 188 0 : if (poSegment->IsAtEOF() && poSegment->CanExtend(nExtendSize)) 189 : { 190 0 : mnGrowingSegment = (uint16) nSegment; 191 0 : break; 192 : } 193 : } 194 : } 195 : 196 : // Create a new segment if we could not found an extendable segment. 197 8 : if (mnGrowingSegment < 1) 198 : { 199 8 : mnGrowingSegment = 200 8 : (uint16) mpoFile->CreateSegment(oName, oDesc, SEG_SYS, 0); 201 : } 202 : 203 8 : mpoFile->ExtendSegment(mnGrowingSegment, (nExtendSize + 511) / 512, 204 : false, false); 205 : 206 8 : return mnGrowingSegment; 207 : } 208 : 209 16 : uint64 CPCIDSKBlockFile::GetSegmentSize(uint16 nSegment) 210 : { 211 16 : PCIDSKSegment * poSegment = mpoFile->GetSegment(nSegment); 212 : 213 16 : return poSegment ? poSegment->GetContentSize() : 0; 214 : } 215 : 216 32 : void CPCIDSKBlockFile::WriteToSegment(uint16 nSegment, const void * pData, 217 : uint64 nOffset, uint64 nSize) 218 : { 219 32 : PCIDSKSegment * poSegment = mpoFile->GetSegment(nSegment); 220 : 221 32 : if (!poSegment) 222 0 : return; 223 : 224 32 : poSegment->WriteToFile(pData, nOffset, nSize); 225 : } 226 : 227 105 : void CPCIDSKBlockFile::ReadFromSegment(uint16 nSegment, void * pData, 228 : uint64 nOffset, uint64 nSize) 229 : { 230 105 : PCIDSKSegment * poSegment = mpoFile->GetSegment(nSegment); 231 : 232 105 : if (!poSegment) 233 0 : return; 234 : 235 105 : poSegment->ReadFromFile(pData, nOffset, nSize); 236 : }