/********************************************************************** * 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; }
/********************************************************************** * 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; }