/********************************************************************** * DumpMapFileBlocks() * * Read and dump a .MAP file... simply dump all blocks sequentially. **********************************************************************/ static int DumpMapFileBlocks(const char *pszFname) { FILE *fp; TABRawBinBlock *poBlock; int nOffset = 0; VSIStatBuf sStatBuf; /*--------------------------------------------------------------------- * Try to open source file * Note: we use stat() to fetch the file size. *--------------------------------------------------------------------*/ if ( VSIStat(pszFname, &sStatBuf) == -1 ) { printf("stat() failed for %s\n", pszFname); return -1; } fp = fopen(pszFname, "rb"); if (fp == NULL) { printf("Failed to open %s\n", pszFname); return -1; } /*--------------------------------------------------------------------- * Read/Dump blocks until EOF is reached *--------------------------------------------------------------------*/ while (nOffset < sStatBuf.st_size ) { poBlock = TABCreateMAPBlockFromFile(fp, nOffset, 512); if (poBlock) { poBlock->Dump(); printf("\n"); delete poBlock; } else { // An error happened (could be EOF)... abort now. break; } nOffset += 512; } /*--------------------------------------------------------------------- * Cleanup and exit. *--------------------------------------------------------------------*/ fclose(fp); return 0; }
/********************************************************************** * DumpMapFileBlockDetails() * * Read and dump specified map file block. **********************************************************************/ static int DumpMapFileBlockDetails(const char *pszFname, int nOffset) { FILE *fp; TABRawBinBlock *poBlock; /*--------------------------------------------------------------------- * Try to open source file * Note: we use stat() to fetch the file size. *--------------------------------------------------------------------*/ fp = fopen(pszFname, "rb"); if (fp == NULL) { printf("Failed to open %s\n", pszFname); return -1; } /*--------------------------------------------------------------------- * Read/Dump blocks until EOF is reached *--------------------------------------------------------------------*/ poBlock = TABCreateMAPBlockFromFile(fp, nOffset, 512); if (poBlock) { switch(poBlock->GetBlockClass()) { case TABMAP_OBJECT_BLOCK: ((TABMAPObjectBlock*)poBlock)->Dump(NULL, TRUE); break; default: poBlock->Dump(NULL); } printf("\n"); delete poBlock; } /*--------------------------------------------------------------------- * Cleanup and exit. *--------------------------------------------------------------------*/ fclose(fp); return 0; }
static void DumpBlocks( TABMAPFile *poMF, int nFileOffset ) { TABRawBinBlock *poBlock; poBlock = poMF->GetIndexObjectBlock( nFileOffset ); if( poBlock == NULL ) return; if( poBlock->GetBlockType() == TABMAP_INDEX_BLOCK ) { TABMAPIndexBlock *poIndexBlock = (TABMAPIndexBlock *) poBlock; int i; #ifdef DEBUG poIndexBlock->Dump( stdout ); #else printf("poIndexBlock->Dump() available inly with -DDEBUG\n"); #endif for( i = 0; i < poIndexBlock->GetNumEntries(); i++ ) { TABMAPIndexEntry *poEntry = poIndexBlock->GetEntry( i ); DumpBlocks( poMF, poEntry->nBlockPtr ); } } else if( poBlock->GetBlockType() == TABMAP_OBJECT_BLOCK ) { TABMAPObjectBlock *poObjectBlock = (TABMAPObjectBlock *) poBlock; #ifdef DEBUG poObjectBlock->Dump( stdout ); #else printf("poObjectBlock->Dump() available inly with -DDEBUG\n"); #endif } }
/********************************************************************** * TABCreateMAPBlockFromFile() * * Load data from the specified file location and create and initialize * a TABMAP*Block of the right type to handle it. * * Returns the new object if succesful or NULL if an error happened, in * which case CPLError() will have been called. **********************************************************************/ TABRawBinBlock *TABCreateMAPBlockFromFile(FILE *fpSrc, int nOffset, int nSize /*= 512*/, GBool bHardBlockSize /*= TRUE */, TABAccess eAccessMode /*= TABRead*/) { TABRawBinBlock *poBlock = NULL; GByte *pabyBuf; if (fpSrc == NULL || nSize == 0) { CPLError(CE_Failure, CPLE_AssertionFailed, "TABCreateMAPBlockFromFile(): Assertion Failed!"); return NULL; } /*---------------------------------------------------------------- * Alloc a buffer to contain the data *---------------------------------------------------------------*/ pabyBuf = (GByte*)CPLMalloc(nSize*sizeof(GByte)); /*---------------------------------------------------------------- * Read from the file *---------------------------------------------------------------*/ if (VSIFSeek(fpSrc, nOffset, SEEK_SET) != 0 || VSIFRead(pabyBuf, sizeof(GByte), nSize, fpSrc)!=(unsigned int)nSize ) { CPLError(CE_Failure, CPLE_FileIO, "TABCreateMAPBlockFromFile() failed reading %d bytes at offset %d.", nSize, nOffset); return NULL; } /*---------------------------------------------------------------- * Create an object of the right type * Header block is different: it does not start with the object * type byte but it is always the first block in a file *---------------------------------------------------------------*/ if (nOffset == 0) { poBlock = new TABMAPHeaderBlock; } else { switch(pabyBuf[0]) { case TABMAP_INDEX_BLOCK: poBlock = new TABMAPIndexBlock(eAccessMode); break; case TABMAP_OBJECT_BLOCK: poBlock = new TABMAPObjectBlock(eAccessMode); break; case TABMAP_COORD_BLOCK: poBlock = new TABMAPCoordBlock(eAccessMode); break; case TABMAP_TOOL_BLOCK: poBlock = new TABMAPToolBlock(eAccessMode); break; case TABMAP_GARB_BLOCK: default: poBlock = new TABRawBinBlock(eAccessMode, bHardBlockSize); break; } } /*---------------------------------------------------------------- * Init new object with the data we just read *---------------------------------------------------------------*/ if (poBlock->InitBlockFromData(pabyBuf, nSize, FALSE, fpSrc, nOffset) != 0) { // Some error happened... and CPLError() has been called delete poBlock; poBlock = NULL; } return poBlock; }
/********************************************************************** * TABMAPIndexBlock::AddEntry() * * Recursively search the tree until we encounter the best leaf to * contain the specified object MBR and add the new entry to it. * * In the even that the selected leaf node would be full, then it will be * split and this split can propagate up to its parent, etc. * * If bAddInThisNodeOnly=TRUE, then the entry is added only locally and * we do not try to update the child node. This is used when the parent * of a node that is being splitted has to be updated. * * Returns 0 on success, -1 on error. **********************************************************************/ int TABMAPIndexBlock::AddEntry(GInt32 nXMin, GInt32 nYMin, GInt32 nXMax, GInt32 nYMax, GInt32 nBlockPtr, GBool bAddInThisNodeOnly /*=FALSE*/) { int i; GBool bFound = FALSE; if (m_eAccess != TABWrite && m_eAccess != TABReadWrite) { CPLError(CE_Failure, CPLE_AssertionFailed, "Failed adding index entry: File not opened for write access."); return -1; } /*----------------------------------------------------------------- * Update MBR now... even if we're going to split current node later. *----------------------------------------------------------------*/ if (nXMin < m_nMinX) m_nMinX = nXMin; if (nXMax > m_nMaxX) m_nMaxX = nXMax; if (nYMin < m_nMinY) m_nMinY = nYMin; if (nYMax > m_nMaxY) m_nMaxY = nYMax; /*----------------------------------------------------------------- * Look for the best candidate to contain the new entry * __TODO__ For now we'll just look for the first entry that can * contain the MBR, but we could probably have a better * search criteria to optimize the resulting tree *----------------------------------------------------------------*/ /*----------------------------------------------------------------- * If bAddInThisNodeOnly=TRUE then we add the entry only locally * and do not need to look for the proper leaf to insert it. *----------------------------------------------------------------*/ if (bAddInThisNodeOnly) bFound = TRUE; /*----------------------------------------------------------------- * First check if current child could be a valid candidate. *----------------------------------------------------------------*/ if (!bFound && m_poCurChild && (m_asEntries[m_nCurChildIndex].XMin <= nXMin && m_asEntries[m_nCurChildIndex].XMax >= nXMax && m_asEntries[m_nCurChildIndex].YMin <= nYMin && m_asEntries[m_nCurChildIndex].YMax >= nYMax ) ) { bFound = TRUE; } /*----------------------------------------------------------------- * Scan all entries to find a valid candidate * We look for the entry whose center is the closest to the center * of the object to add. *----------------------------------------------------------------*/ if (!bFound) { int nObjCenterX = (nXMin + nXMax)/2; int nObjCenterY = (nYMin + nYMax)/2; // Make sure blocks currently in memory are written to disk. if (m_poCurChild) { m_poCurChild->CommitToFile(); delete m_poCurChild; m_poCurChild = NULL; m_nCurChildIndex = -1; } // Look for entry whose center is closest to center of new object int nBestCandidate = -1; int nMinDist = 2000000000; for(i=0; i<m_numEntries; i++) { int nX = (m_asEntries[i].XMin + m_asEntries[i].XMax)/2; int nY = (m_asEntries[i].YMin + m_asEntries[i].YMax)/2; int nDist = (nX-nObjCenterX)*(nX-nObjCenterX) + (nY-nObjCenterY)*(nY-nObjCenterY); if (nBestCandidate==-1 || nDist < nMinDist) { nBestCandidate = i; nMinDist = nDist; } } if (nBestCandidate != -1) { // Try to load corresponding child... if it fails then we are // likely in a leaf node, so we'll add the new entry in the current // node. TABRawBinBlock *poBlock = NULL; // Prevent error message if referred block not committed yet. CPLPushErrorHandler(CPLQuietErrorHandler); if ((poBlock = TABCreateMAPBlockFromFile(m_fp, m_asEntries[nBestCandidate].nBlockPtr, 512, TRUE, TABReadWrite)) && poBlock->GetBlockClass() == TABMAP_INDEX_BLOCK) { m_poCurChild = (TABMAPIndexBlock*)poBlock; poBlock = NULL; m_nCurChildIndex = nBestCandidate; m_poCurChild->SetParentRef(this); m_poCurChild->SetMAPBlockManagerRef(m_poBlockManagerRef); bFound = TRUE; } if (poBlock) delete poBlock; CPLPopErrorHandler(); CPLErrorReset(); } } if (bFound && !bAddInThisNodeOnly) { /*------------------------------------------------------------- * Found a child leaf... pass the call to it. *------------------------------------------------------------*/ if (m_poCurChild->AddEntry(nXMin, nYMin, nXMax, nYMax, nBlockPtr) != 0) return -1; } else { /*------------------------------------------------------------- * Found no child to store new object... we're likely at the leaf * level so we'll store new object in current node *------------------------------------------------------------*/ /*------------------------------------------------------------- * First thing to do is make sure that there is room for a new * entry in this node, and to split it if necessary. *------------------------------------------------------------*/ if (GetNumFreeEntries() < 1) { if (m_poParentRef == NULL) { /*----------------------------------------------------- * Splitting the root node adds one level to the tree, so * after splitting we just redirect the call to the new * child that's just been created. *----------------------------------------------------*/ if (SplitRootNode((nXMin+nXMax)/2, (nYMin+nYMax)/2) != 0) return -1; // Error happened and has already been reported CPLAssert(m_poCurChild); return m_poCurChild->AddEntry(nXMin, nYMin, nXMax, nYMax, nBlockPtr, TRUE); } else { /*----------------------------------------------------- * Splitting a regular node *----------------------------------------------------*/ if (SplitNode((nXMin+nXMax)/2, (nYMin+nYMax)/2) != 0) return -1; } } if (InsertEntry(nXMin, nYMin, nXMax, nYMax, nBlockPtr) != 0) return -1; } /*----------------------------------------------------------------- * Update current node MBR and the reference to it in our parent. *----------------------------------------------------------------*/ RecomputeMBR(); return 0; }