LTP GCOV extension - code coverage report
Current view: directory - ogr/ogrsf_frmts/mitab - mitab_indfile.cpp
Test: gdal_filtered.info
Date: 2010-07-12 Instrumented lines: 604
Code covered: 47.7 % Executed lines: 288

       1                 : /**********************************************************************
       2                 :  * $Id: mitab_indfile.cpp,v 1.13 2008/01/29 20:46:32 dmorissette Exp $
       3                 :  *
       4                 :  * Name:     mitab_indfile.cpp
       5                 :  * Project:  MapInfo TAB Read/Write library
       6                 :  * Language: C++
       7                 :  * Purpose:  Implementation of the TABINDFile class used to handle
       8                 :  *           access to .IND file (table field indexes) attached to a .DAT file
       9                 :  * Author:   Daniel Morissette, dmorissette@dmsolutions.ca
      10                 :  *
      11                 :  **********************************************************************
      12                 :  * Copyright (c) 1999-2001, Daniel Morissette
      13                 :  *
      14                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      15                 :  * copy of this software and associated documentation files (the "Software"),
      16                 :  * to deal in the Software without restriction, including without limitation
      17                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      18                 :  * and/or sell copies of the Software, and to permit persons to whom the
      19                 :  * Software is furnished to do so, subject to the following conditions:
      20                 :  * 
      21                 :  * The above copyright notice and this permission notice shall be included
      22                 :  * in all copies or substantial portions of the Software.
      23                 :  * 
      24                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      25                 :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      26                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
      27                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      28                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      29                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
      30                 :  * DEALINGS IN THE SOFTWARE.
      31                 :  **********************************************************************
      32                 :  *
      33                 :  * $Log: mitab_indfile.cpp,v $
      34                 :  * Revision 1.13  2008/01/29 20:46:32  dmorissette
      35                 :  * Added support for v9 Time and DateTime fields (byg 1754)
      36                 :  *
      37                 :  * Revision 1.12  2007/12/11 03:43:03  dmorissette
      38                 :  * Added reporting access mode to error message in TABINDFile::Open()
      39                 :  * (GDAL changeset r12460, ticket 1620)
      40                 :  *
      41                 :  * Revision 1.11  2005/04/29 19:08:56  dmorissette
      42                 :  * Produce an error if m_nSubtreeDepth > 255 when creating a .IND (OGR bug 839)
      43                 :  *
      44                 :  * Revision 1.10  2004/06/30 20:29:04  dmorissette
      45                 :  * Fixed refs to old address danmo@videotron.ca
      46                 :  *
      47                 :  * Revision 1.9  2003/07/24 02:45:57  daniel
      48                 :  * Fixed problem scanning node in TABINDNode::FindNext() - bug 2176, FW
      49                 :  *
      50                 :  * Revision 1.8  2001/05/01 03:38:23  daniel
      51                 :  * Added update support (allows creating new index in existing IND files).
      52                 :  *
      53                 :  * Revision 1.7  2000/11/13 22:17:57  daniel
      54                 :  * When a (child) node's first entry is replaced by InsertEntry() then make
      55                 :  * sure that node's key is updated in its parent node.
      56                 :  *
      57                 :  * Revision 1.6  2000/03/01 00:32:00  daniel
      58                 :  * Added support for float keys, and completed support for generating indexes
      59                 :  *
      60                 :  * Revision 1.5  2000/02/28 16:57:42  daniel
      61                 :  * Added support for writing indexes
      62                 :  *
      63                 :  * Revision 1.4  2000/01/15 22:30:44  daniel
      64                 :  * Switch to MIT/X-Consortium OpenSource license
      65                 :  *
      66                 :  * Revision 1.3  1999/12/14 05:52:05  daniel
      67                 :  * Fixed compile error on Windows
      68                 :  *
      69                 :  * Revision 1.2  1999/12/14 02:19:42  daniel
      70                 :  * Completed .IND support for simple TABViews
      71                 :  *
      72                 :  * Revision 1.1  1999/11/20 15:49:07  daniel
      73                 :  * Initial version
      74                 :  *
      75                 :  **********************************************************************/
      76                 : 
      77                 : #include "mitab.h"
      78                 : #include "mitab_utils.h"
      79                 : 
      80                 : #include <ctype.h>      /* toupper() */
      81                 : 
      82                 : /*=====================================================================
      83                 :  *                      class TABINDFile
      84                 :  *====================================================================*/
      85                 : 
      86                 : #define IND_MAGIC_COOKIE  24242424
      87                 : 
      88                 : /**********************************************************************
      89                 :  *                   TABINDFile::TABINDFile()
      90                 :  *
      91                 :  * Constructor.
      92                 :  **********************************************************************/
      93               9 : TABINDFile::TABINDFile()
      94                 : {
      95               9 :     m_fp = NULL;
      96               9 :     m_pszFname = NULL;
      97               9 :     m_eAccessMode = TABRead;
      98               9 :     m_numIndexes = 0;
      99               9 :     m_papoIndexRootNodes = NULL;
     100               9 :     m_papbyKeyBuffers = NULL;
     101               9 : }
     102                 : 
     103                 : /**********************************************************************
     104                 :  *                   TABINDFile::~TABINDFile()
     105                 :  *
     106                 :  * Destructor.
     107                 :  **********************************************************************/
     108               9 : TABINDFile::~TABINDFile()
     109                 : {
     110               9 :     Close();
     111               9 : }
     112                 : 
     113                 : /**********************************************************************
     114                 :  *                   TABINDFile::Open()
     115                 :  *
     116                 :  * Open a .IND file, read the header and the root nodes for all the
     117                 :  * field indexes, and be ready to search the indexes.
     118                 :  *
     119                 :  * If the filename that is passed in contains a .DAT extension then
     120                 :  * the extension will be changed to .IND before trying to open the file.
     121                 :  *
     122                 :  * Note that we pass a pszAccess flag, but only read access is supported
     123                 :  * for now (and there are no plans to support write.)
     124                 :  *
     125                 :  * Set bTestOpenNoError=TRUE to silently return -1 with no error message
     126                 :  * if the file cannot be opened because it does not exist.
     127                 :  *
     128                 :  * Returns 0 on success, -1 on error.
     129                 :  **********************************************************************/
     130                 : int TABINDFile::Open(const char *pszFname, const char *pszAccess,
     131              11 :                      GBool bTestOpenNoError /*=FALSE*/)
     132                 : {
     133                 :     int         nLen;
     134                 : 
     135              11 :     if (m_fp)
     136                 :     {
     137                 :         CPLError(CE_Failure, CPLE_FileIO,
     138               0 :                  "Open() failed: object already contains an open file");
     139               0 :         return -1;
     140                 :     }
     141                 : 
     142                 :     /*-----------------------------------------------------------------
     143                 :      * Validate access mode and make sure we use binary access.
     144                 :      * Note that for write access, we actually need read/write access to
     145                 :      * the file.
     146                 :      *----------------------------------------------------------------*/
     147              13 :     if (EQUALN(pszAccess, "r", 1) && strchr(pszAccess, '+') != NULL)
     148                 :     {
     149               2 :         m_eAccessMode = TABReadWrite;
     150               2 :         pszAccess = "rb+";
     151                 :     }
     152               9 :     else if (EQUALN(pszAccess, "r", 1))
     153                 :     {
     154               7 :         m_eAccessMode = TABRead;
     155               7 :         pszAccess = "rb";
     156                 :     }
     157               2 :     else if (EQUALN(pszAccess, "w", 1))
     158                 :     {
     159               2 :         m_eAccessMode = TABWrite;
     160               2 :         pszAccess = "wb+";
     161                 :     }
     162                 :     else
     163                 :     {
     164                 :         CPLError(CE_Failure, CPLE_FileIO,
     165               0 :                  "Open() failed: access mode \"%s\" not supported", pszAccess);
     166               0 :         return -1;
     167                 :     }
     168                 : 
     169                 :     /*-----------------------------------------------------------------
     170                 :      * Change .DAT (or .TAB) extension to .IND if necessary
     171                 :      *----------------------------------------------------------------*/
     172              11 :     m_pszFname = CPLStrdup(pszFname);
     173                 : 
     174              11 :     nLen = strlen(m_pszFname);
     175              11 :     if (nLen > 4 && !EQUAL(m_pszFname+nLen-4, ".IND") )
     176               7 :         strcpy(m_pszFname+nLen-4, ".ind");
     177                 : 
     178                 : #ifndef _WIN32
     179              11 :     TABAdjustFilenameExtension(m_pszFname);
     180                 : #endif
     181                 : 
     182                 :     /*-----------------------------------------------------------------
     183                 :      * Open file
     184                 :      *----------------------------------------------------------------*/
     185              11 :     m_fp = VSIFOpen(m_pszFname, pszAccess);
     186                 : 
     187              11 :     if (m_fp == NULL)
     188                 :     {
     189               0 :         if (!bTestOpenNoError)
     190                 :             CPLError(CE_Failure, CPLE_FileIO,
     191               0 :                      "Open() failed for %s (%s)", m_pszFname, pszAccess);
     192                 : 
     193               0 :         CPLFree(m_pszFname);
     194               0 :         m_pszFname = NULL;
     195               0 :         return -1;
     196                 :     }
     197                 : 
     198                 :     /*-----------------------------------------------------------------
     199                 :      * Reset block manager to allocate first block at byte 512, after header.
     200                 :      *----------------------------------------------------------------*/
     201              11 :     m_oBlockManager.Reset();
     202              11 :     m_oBlockManager.AllocNewBlock();
     203                 : 
     204                 :     /*-----------------------------------------------------------------
     205                 :      * Read access: Read the header block
     206                 :      * This will also alloc and init the array of index root nodes.
     207                 :      *----------------------------------------------------------------*/
     208              11 :     if ((m_eAccessMode == TABRead || m_eAccessMode == TABReadWrite) &&
     209                 :         ReadHeader() != 0)
     210                 :     {
     211                 :         // Failed reading header... CPLError() has already been called
     212               0 :         Close();
     213               0 :         return -1;
     214                 :     }
     215                 : 
     216                 :     /*-----------------------------------------------------------------
     217                 :      * Write access: Init class members and write a dummy header block
     218                 :      *----------------------------------------------------------------*/
     219              11 :     if (m_eAccessMode == TABWrite)
     220                 :     {
     221               2 :         m_numIndexes = 0;
     222                 : 
     223               2 :         if (WriteHeader() != 0)
     224                 :         {
     225                 :             // Failed writing header... CPLError() has already been called
     226               0 :             Close();
     227               0 :             return -1;
     228                 :         }
     229                 :     }
     230                 : 
     231              11 :     return 0;
     232                 : }
     233                 : 
     234                 : /**********************************************************************
     235                 :  *                   TABINDFile::Close()
     236                 :  *
     237                 :  * Close current file, and release all memory used.
     238                 :  *
     239                 :  * Returns 0 on success, -1 on error.
     240                 :  **********************************************************************/
     241              20 : int TABINDFile::Close()
     242                 : {
     243              20 :     if (m_fp == NULL)
     244               9 :         return 0;
     245                 : 
     246                 :     /*-----------------------------------------------------------------
     247                 :      * In Write Mode, commit all indexes to the file
     248                 :      *----------------------------------------------------------------*/
     249              11 :     if (m_eAccessMode == TABWrite || m_eAccessMode == TABReadWrite)
     250                 :     {
     251               4 :         WriteHeader();
     252                 : 
     253              10 :         for(int iIndex=0; iIndex<m_numIndexes; iIndex++)
     254                 :         {
     255               6 :             if (m_papoIndexRootNodes &&
     256                 :                 m_papoIndexRootNodes[iIndex])
     257                 :             {
     258               6 :                 m_papoIndexRootNodes[iIndex]->CommitToFile();
     259                 :             }
     260                 :         }
     261                 :     }
     262                 : 
     263                 :     /*-----------------------------------------------------------------
     264                 :      * Free index nodes in memory
     265                 :      *----------------------------------------------------------------*/
     266              25 :     for (int iIndex=0; iIndex<m_numIndexes; iIndex++)
     267                 :     {
     268              14 :         if (m_papoIndexRootNodes && m_papoIndexRootNodes[iIndex])
     269              14 :             delete m_papoIndexRootNodes[iIndex];
     270              14 :         if (m_papbyKeyBuffers && m_papbyKeyBuffers[iIndex])
     271              14 :             CPLFree(m_papbyKeyBuffers[iIndex]);
     272                 :     }
     273              11 :     CPLFree(m_papoIndexRootNodes);
     274              11 :     m_papoIndexRootNodes = NULL;
     275              11 :     CPLFree(m_papbyKeyBuffers);
     276              11 :     m_papbyKeyBuffers = NULL;
     277              11 :     m_numIndexes = 0;
     278                 : 
     279                 :     /*-----------------------------------------------------------------
     280                 :      * Close file
     281                 :      *----------------------------------------------------------------*/
     282              11 :     VSIFClose(m_fp);
     283              11 :     m_fp = NULL;
     284                 : 
     285              11 :     CPLFree(m_pszFname);
     286              11 :     m_pszFname = NULL;
     287                 : 
     288              11 :     return 0;
     289                 : }
     290                 : 
     291                 : 
     292                 : /**********************************************************************
     293                 :  *                   TABINDFile::ReadHeader()
     294                 :  *
     295                 :  * (private method)
     296                 :  * Read the header block and init all class members for read access.
     297                 :  *
     298                 :  * Returns 0 on success, -1 on error.
     299                 :  **********************************************************************/
     300               9 : int TABINDFile::ReadHeader()
     301                 : {
     302                 : 
     303               9 :     CPLAssert(m_fp);
     304               9 :     CPLAssert(m_eAccessMode == TABRead || m_eAccessMode == TABReadWrite);
     305                 : 
     306                 :     /*-----------------------------------------------------------------
     307                 :      * In ReadWrite mode, we need to init BlockManager with file size
     308                 :      *----------------------------------------------------------------*/
     309                 :     VSIStatBuf  sStatBuf;
     310               9 :     if (m_eAccessMode == TABReadWrite && VSIStat(m_pszFname, &sStatBuf) != -1)
     311                 :     {
     312               2 :         m_oBlockManager.SetLastPtr(((sStatBuf.st_size-1)/512)*512);
     313                 :     }
     314                 : 
     315                 :     /*-----------------------------------------------------------------
     316                 :      * Read the header block
     317                 :      *----------------------------------------------------------------*/
     318                 :     TABRawBinBlock *poHeaderBlock;
     319               9 :     poHeaderBlock = new TABRawBinBlock(m_eAccessMode, TRUE);
     320               9 :     if (poHeaderBlock->ReadFromFile(m_fp, 0, 512) != 0)
     321                 :     {
     322                 :         // CPLError() has already been called.
     323               0 :         delete poHeaderBlock;
     324               0 :         return -1;
     325                 :     }
     326                 : 
     327               9 :     poHeaderBlock->GotoByteInBlock(0);
     328               9 :     GUInt32 nMagicCookie = poHeaderBlock->ReadInt32();
     329               9 :     if (nMagicCookie != IND_MAGIC_COOKIE)
     330                 :     {
     331                 :         CPLError(CE_Failure, CPLE_FileIO,
     332                 :                  "%s: Invalid Magic Cookie: got %d, expected %d",
     333               0 :                  m_pszFname, nMagicCookie, IND_MAGIC_COOKIE);
     334               0 :         delete poHeaderBlock;
     335               0 :         return -1;
     336                 :     }
     337                 : 
     338               9 :     poHeaderBlock->GotoByteInBlock(12);
     339               9 :     m_numIndexes = poHeaderBlock->ReadInt16();
     340               9 :     if (m_numIndexes < 1 || m_numIndexes > 29)
     341                 :     {
     342                 :         CPLError(CE_Failure, CPLE_FileIO,
     343                 :                  "Invalid number of indexes (%d) in file %s",
     344               0 :                  m_numIndexes, m_pszFname);
     345               0 :         delete poHeaderBlock;
     346               0 :         return -1;
     347                 :     }
     348                 : 
     349                 :     /*-----------------------------------------------------------------
     350                 :      * Alloc and init the array of index root nodes.
     351                 :      *----------------------------------------------------------------*/
     352                 :     m_papoIndexRootNodes = (TABINDNode**)CPLCalloc(m_numIndexes,
     353               9 :                                                    sizeof(TABINDNode*));
     354                 : 
     355               9 :     m_papbyKeyBuffers = (GByte **)CPLCalloc(m_numIndexes, sizeof(GByte*));
     356                 : 
     357                 :     /* First index def. starts at byte 48 */
     358               9 :     poHeaderBlock->GotoByteInBlock(48);
     359                 : 
     360              19 :     for(int iIndex=0; iIndex<m_numIndexes; iIndex++)
     361                 :     {
     362                 :         /*-------------------------------------------------------------
     363                 :          * Read next index definition
     364                 :          *------------------------------------------------------------*/
     365              10 :         GInt32 nRootNodePtr = poHeaderBlock->ReadInt32();
     366              10 :         poHeaderBlock->ReadInt16();   // skip... max. num of entries per node
     367              10 :         int nTreeDepth = poHeaderBlock->ReadByte();
     368              10 :         int nKeyLength = poHeaderBlock->ReadByte();
     369              10 :         poHeaderBlock->GotoByteRel(8); // skip next 8 bytes;
     370                 : 
     371                 :         /*-------------------------------------------------------------
     372                 :          * And init root node for this index.
     373                 :          * Note that if nRootNodePtr==0 then this means that the 
     374                 :          * corresponding index does not exist (i.e. has been deleted?)
     375                 :          * so we simply do not allocate the root node in this case.
     376                 :          * An error will be produced if the user tries to access this index
     377                 :          * later during execution.
     378                 :          *------------------------------------------------------------*/
     379              10 :         if (nRootNodePtr > 0)
     380                 :         {
     381              10 :             m_papoIndexRootNodes[iIndex] = new TABINDNode(m_eAccessMode);
     382              10 :             if (m_papoIndexRootNodes[iIndex]->InitNode(m_fp, nRootNodePtr,
     383                 :                                                        nKeyLength, nTreeDepth,
     384                 :                                                        FALSE,
     385                 :                                                        &m_oBlockManager)!= 0)
     386                 :             {
     387                 :                 // CPLError has already been called
     388               0 :                 delete poHeaderBlock;
     389               0 :                 return -1;
     390                 :             }
     391                 : 
     392                 :             // Alloc a temporary key buffer for this index.
     393                 :             // This buffer will be used by the BuildKey() method
     394                 :             m_papbyKeyBuffers[iIndex] = (GByte *)CPLCalloc(nKeyLength+1, 
     395              10 :                                                            sizeof(GByte));
     396                 :         }
     397                 :         else
     398                 :         {
     399               0 :             m_papoIndexRootNodes[iIndex] = NULL;
     400               0 :             m_papbyKeyBuffers[iIndex] = NULL;
     401                 :         }
     402                 :     }
     403                 : 
     404                 :     /*-----------------------------------------------------------------
     405                 :      * OK, we won't need the header block any more... free it.
     406                 :      *----------------------------------------------------------------*/
     407               9 :     delete poHeaderBlock;
     408                 : 
     409               9 :     return 0;
     410                 : }
     411                 : 
     412                 : 
     413                 : /**********************************************************************
     414                 :  *                   TABINDFile::WriteHeader()
     415                 :  *
     416                 :  * (private method)
     417                 :  * Write the header block based on current index information.
     418                 :  *
     419                 :  * Returns 0 on success, -1 on error.
     420                 :  **********************************************************************/
     421               6 : int TABINDFile::WriteHeader()
     422                 : {
     423               6 :     CPLAssert(m_fp);
     424               6 :     CPLAssert(m_eAccessMode == TABWrite || m_eAccessMode == TABReadWrite);
     425                 : 
     426                 :     /*-----------------------------------------------------------------
     427                 :      * Write the 48 bytes of file header
     428                 :      *----------------------------------------------------------------*/
     429                 :     TABRawBinBlock *poHeaderBlock;
     430               6 :     poHeaderBlock = new TABRawBinBlock(m_eAccessMode, TRUE);
     431               6 :     poHeaderBlock->InitNewBlock(m_fp, 512, 0);
     432                 : 
     433               6 :     poHeaderBlock->WriteInt32( IND_MAGIC_COOKIE );
     434                 : 
     435               6 :     poHeaderBlock->WriteInt16( 100 );   // ???
     436               6 :     poHeaderBlock->WriteInt16( 512 );   // ???
     437               6 :     poHeaderBlock->WriteInt32( 0 );     // ???
     438                 : 
     439               6 :     poHeaderBlock->WriteInt16( m_numIndexes );
     440                 : 
     441               6 :     poHeaderBlock->WriteInt16( 0x15e7); // ???
     442                 : 
     443               6 :     poHeaderBlock->WriteInt16( 10 );    // ???
     444               6 :     poHeaderBlock->WriteInt16( 0x611d); // ???
     445                 : 
     446               6 :     poHeaderBlock->WriteZeros( 28 );
     447                 : 
     448                 :     /*-----------------------------------------------------------------
     449                 :      * The first index definition starts at byte 48
     450                 :      *----------------------------------------------------------------*/
     451              12 :     for(int iIndex=0; iIndex<m_numIndexes; iIndex++)
     452                 :     {
     453               6 :         TABINDNode *poRootNode = m_papoIndexRootNodes[iIndex];
     454                 : 
     455               6 :         if (poRootNode)
     456                 :         {
     457                 :             /*---------------------------------------------------------
     458                 :              * Write next index definition
     459                 :              *--------------------------------------------------------*/
     460               6 :             poHeaderBlock->WriteInt32(poRootNode->GetNodeBlockPtr());
     461               6 :             poHeaderBlock->WriteInt16(poRootNode->GetMaxNumEntries());
     462               6 :             poHeaderBlock->WriteByte( poRootNode->GetSubTreeDepth());
     463               6 :             poHeaderBlock->WriteByte( poRootNode->GetKeyLength());
     464                 : 
     465               6 :             poHeaderBlock->WriteZeros( 8 );
     466                 : 
     467                 :             /*---------------------------------------------------------
     468                 :              * Look for overflow of the SubTreeDepth field (byte)
     469                 :              *--------------------------------------------------------*/
     470               6 :             if (poRootNode->GetSubTreeDepth() > 255)
     471                 :             {
     472                 :                 CPLError(CE_Failure, CPLE_AssertionFailed,
     473                 :                          "Index no %d is too large and will not be useable. "
     474                 :                          "(SubTreeDepth = %d, cannot exceed 255).",
     475               0 :                          iIndex+1, poRootNode->GetSubTreeDepth());
     476               0 :                 return -1;
     477                 :             }
     478                 :         }
     479                 :         else
     480                 :         {
     481                 :             /*---------------------------------------------------------
     482                 :              * NULL Root Node: This index has likely been deleted
     483                 :              *--------------------------------------------------------*/
     484               0 :             poHeaderBlock->WriteZeros( 16 );
     485                 :         }
     486                 :     }
     487                 : 
     488                 :     /*-----------------------------------------------------------------
     489                 :      * OK, we won't need the header block any more... write and free it.
     490                 :      *----------------------------------------------------------------*/
     491               6 :     if (poHeaderBlock->CommitToFile() != 0)
     492               0 :         return -1;
     493                 : 
     494               6 :     delete poHeaderBlock;
     495                 : 
     496               6 :     return 0;
     497                 : }
     498                 : 
     499                 : /**********************************************************************
     500                 :  *                   TABINDFile::ValidateIndexNo()
     501                 :  *
     502                 :  * Private method to validate the index no parameter of some methods...
     503                 :  * returns 0 if index no. is OK, or produces an error ands returns -1
     504                 :  * if index no is not valid. 
     505                 :  **********************************************************************/
     506             190 : int TABINDFile::ValidateIndexNo(int nIndexNumber)
     507                 : {
     508             190 :     if (m_fp == NULL)
     509                 :     {
     510                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
     511               0 :                  "TABINDFile: File has not been opened yet!");
     512               0 :         return -1;
     513                 :     }
     514                 : 
     515             190 :     if (nIndexNumber < 1 || nIndexNumber > m_numIndexes ||
     516                 :         m_papoIndexRootNodes == NULL || 
     517                 :         m_papoIndexRootNodes[nIndexNumber-1] == NULL)
     518                 :     {
     519                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
     520                 :                  "No field index number %d in %s: Valid range is [1..%d].",
     521               0 :                  nIndexNumber, m_pszFname, m_numIndexes);
     522               0 :         return -1;
     523                 :     }
     524                 : 
     525             190 :     return 0;  // Index seems valid
     526                 : }
     527                 : 
     528                 : /**********************************************************************
     529                 :  *                   TABINDFile::SetIndexFieldType()
     530                 :  *
     531                 :  * Sets the field type for the specified index.
     532                 :  * This information will then be used in building the key values, etc.
     533                 :  *
     534                 :  * Returns 0 on success, -1 on error.
     535                 :  **********************************************************************/
     536               0 : int TABINDFile::SetIndexFieldType(int nIndexNumber, TABFieldType eType)
     537                 : {
     538               0 :     if (ValidateIndexNo(nIndexNumber) != 0)
     539               0 :         return -1;
     540                 : 
     541               0 :     return m_papoIndexRootNodes[nIndexNumber-1]->SetFieldType(eType);
     542                 : }
     543                 : 
     544                 : /**********************************************************************
     545                 :  *                   TABINDFile::SetIndexUnique()
     546                 :  *
     547                 :  * Indicate that an index's keys are unique.  This allows for some 
     548                 :  * optimization with read access.  By default, an index is treated as if
     549                 :  * its keys could have duplicates.
     550                 :  *
     551                 :  * Returns 0 on success, -1 on error.
     552                 :  **********************************************************************/
     553               0 : int TABINDFile::SetIndexUnique(int nIndexNumber, GBool bUnique/*=TRUE*/)
     554                 : {
     555               0 :     if (ValidateIndexNo(nIndexNumber) != 0)
     556               0 :         return -1;
     557                 : 
     558               0 :     m_papoIndexRootNodes[nIndexNumber-1]->SetUnique(bUnique);
     559                 : 
     560               0 :     return 0;
     561                 : }
     562                 : 
     563                 : /**********************************************************************
     564                 :  *                   TABINDFile::BuildKey()
     565                 :  *
     566                 :  * Encode a field value in the form required to be compared with index
     567                 :  * keys in the specified index.
     568                 :  * 
     569                 :  * Note that index numbers are positive values starting at 1.
     570                 :  *
     571                 :  * Returns a reference to an internal buffer that is valid only until the
     572                 :  * next call to BuildKey().  (should not be freed by the caller).
     573                 :  * Returns NULL if field index is invalid.
     574                 :  *
     575                 :  * The first flavour of the function handles integer type of values, this
     576                 :  * corresponds to MapInfo types: integer, smallint, logical and date
     577                 :  **********************************************************************/
     578               2 : GByte *TABINDFile::BuildKey(int nIndexNumber, GInt32 nValue)
     579                 : {
     580               2 :     if (ValidateIndexNo(nIndexNumber) != 0)
     581               0 :         return NULL;
     582                 : 
     583               2 :     int nKeyLength = m_papoIndexRootNodes[nIndexNumber-1]->GetKeyLength();
     584                 :     
     585                 :     /*-----------------------------------------------------------------
     586                 :      * Convert all int values to MSB using the right number of bytes
     587                 :      * Note:
     588                 :      * The most significant bit has to be unset for negative values,
     589                 :      * and to be set for positive ones... that's the reverse of what it
     590                 :      * should usually be.  Adding 0x80 to the MSB byte will do the job.
     591                 :      *----------------------------------------------------------------*/
     592               2 :     switch(nKeyLength)
     593                 :     {
     594                 :       case 1:
     595               0 :         m_papbyKeyBuffers[nIndexNumber-1][0] = (GByte)(nValue & 0xff)+0x80;
     596               0 :         break;
     597                 :       case 2:
     598                 :         m_papbyKeyBuffers[nIndexNumber-1][0] = 
     599               0 :                                        (GByte)(nValue/0x100 & 0xff)+0x80;
     600               0 :         m_papbyKeyBuffers[nIndexNumber-1][1] = (GByte)(nValue & 0xff);
     601               0 :         break;
     602                 :       case 4:
     603                 :         m_papbyKeyBuffers[nIndexNumber-1][0] = 
     604               2 :                                        (GByte)(nValue/0x1000000 &0xff)+0x80;
     605               2 :         m_papbyKeyBuffers[nIndexNumber-1][1] = (GByte)(nValue/0x10000 & 0xff);
     606               2 :         m_papbyKeyBuffers[nIndexNumber-1][2] = (GByte)(nValue/0x100 &0xff);
     607               2 :         m_papbyKeyBuffers[nIndexNumber-1][3] = (GByte)(nValue & 0xff);
     608               2 :         break;
     609                 :       default:
     610                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
     611                 :                  "BuildKey(): %d bytes integer key length not supported",
     612               0 :                  nKeyLength);
     613                 :         break;
     614                 :     }
     615                 : 
     616               2 :     return m_papbyKeyBuffers[nIndexNumber-1];
     617                 : }
     618                 : 
     619                 : /**********************************************************************
     620                 :  *                   TABINDFile::BuildKey()
     621                 :  *
     622                 :  * BuildKey() for string fields
     623                 :  **********************************************************************/
     624              41 : GByte *TABINDFile::BuildKey(int nIndexNumber, const char *pszStr)
     625                 : {
     626              41 :     if (ValidateIndexNo(nIndexNumber) != 0 || pszStr == NULL)
     627               0 :         return NULL;
     628                 : 
     629              41 :     int nKeyLength = m_papoIndexRootNodes[nIndexNumber-1]->GetKeyLength();
     630                 : 
     631                 :     /*-----------------------------------------------------------------
     632                 :      * Strings keys are all in uppercase, and padded with '\0'
     633                 :      *----------------------------------------------------------------*/
     634              41 :     int i=0;
     635             348 :     for (i=0; i<nKeyLength && pszStr[i] != '\0'; i++)
     636                 :     {
     637             307 :         m_papbyKeyBuffers[nIndexNumber-1][i] = (GByte)toupper(pszStr[i]);
     638                 :     }
     639                 : 
     640                 :     /* Pad the end of the buffer with '\0' */
     641             390 :     for( ; i<nKeyLength; i++)
     642                 :     {   
     643             349 :         m_papbyKeyBuffers[nIndexNumber-1][i] = '\0';
     644                 :     }
     645                 :         
     646              41 :     return m_papbyKeyBuffers[nIndexNumber-1];
     647                 : }
     648                 : 
     649                 : /**********************************************************************
     650                 :  *                   TABINDFile::BuildKey()
     651                 :  *
     652                 :  * BuildKey() for float and decimal fields
     653                 :  **********************************************************************/
     654              47 : GByte *TABINDFile::BuildKey(int nIndexNumber, double dValue)
     655                 : {
     656              47 :     if (ValidateIndexNo(nIndexNumber) != 0)
     657               0 :         return NULL;
     658                 : 
     659              47 :     int nKeyLength = m_papoIndexRootNodes[nIndexNumber-1]->GetKeyLength();
     660              47 :     CPLAssert(nKeyLength == 8 && sizeof(double) == 8);
     661                 : 
     662                 :     /*-----------------------------------------------------------------
     663                 :      * Convert double and decimal values... 
     664                 :      * Reverse the sign of the value, and convert to MSB
     665                 :      *----------------------------------------------------------------*/
     666              47 :     dValue = -dValue;
     667                 : 
     668                 : #ifndef CPL_MSB
     669              47 :     CPL_SWAPDOUBLE(&dValue);
     670                 : #endif
     671                 : 
     672              47 :     memcpy(m_papbyKeyBuffers[nIndexNumber-1], (GByte*)(&dValue), nKeyLength);
     673                 : 
     674              47 :     return m_papbyKeyBuffers[nIndexNumber-1];
     675                 : }
     676                 : 
     677                 : 
     678                 : /**********************************************************************
     679                 :  *                   TABINDFile::FindFirst()
     680                 :  *
     681                 :  * Search one of the indexes for a key value.  
     682                 :  *
     683                 :  * Note that index numbers are positive values starting at 1.
     684                 :  *
     685                 :  * Return value:
     686                 :  *  - the key's corresponding record number in the .DAT file (greater than 0)
     687                 :  *  - 0 if the key was not found
     688                 :  *  - or -1 if an error happened
     689                 :  **********************************************************************/
     690              10 : GInt32 TABINDFile::FindFirst(int nIndexNumber, GByte *pKeyValue)
     691                 : {
     692              10 :     if (ValidateIndexNo(nIndexNumber) != 0)
     693               0 :         return -1;
     694                 : 
     695              10 :     return m_papoIndexRootNodes[nIndexNumber-1]->FindFirst(pKeyValue);
     696                 : }
     697                 : 
     698                 : /**********************************************************************
     699                 :  *                   TABINDFile::FindNext()
     700                 :  *
     701                 :  * Continue the Search for pKeyValue previously initiated by FindFirst().  
     702                 :  * NOTE: FindFirst() MUST have been previously called for this call to
     703                 :  *       work...
     704                 :  *
     705                 :  * Note that index numbers are positive values starting at 1.
     706                 :  *
     707                 :  * Return value:
     708                 :  *  - the key's corresponding record number in the .DAT file (greater than 0)
     709                 :  *  - 0 if the key was not found
     710                 :  *  - or -1 if an error happened
     711                 :  **********************************************************************/
     712              10 : GInt32 TABINDFile::FindNext(int nIndexNumber, GByte *pKeyValue)
     713                 : {
     714              10 :     if (ValidateIndexNo(nIndexNumber) != 0)
     715               0 :         return -1;
     716                 : 
     717              10 :     return m_papoIndexRootNodes[nIndexNumber-1]->FindNext(pKeyValue);
     718                 : }
     719                 : 
     720                 : 
     721                 : /**********************************************************************
     722                 :  *                   TABINDFile::CreateIndex()
     723                 :  *
     724                 :  * Create a new index with the specified field type and size.
     725                 :  * Field size applies only to char field type... the other types have a
     726                 :  * predefined key length.
     727                 :  *
     728                 :  * Key length is limited to 128 chars. char fields longer than 128 chars
     729                 :  * will have their key truncated to 128 bytes.
     730                 :  *
     731                 :  * Note that a .IND file can contain only a maximum of 29 indexes.
     732                 :  *
     733                 :  * Returns the new field index on success (greater than 0), or -1 on error.
     734                 :  **********************************************************************/
     735               4 : int TABINDFile::CreateIndex(TABFieldType eType, int nFieldSize)
     736                 : {
     737               4 :     int i, nNewIndexNo = -1;
     738                 : 
     739               4 :     if (m_fp == NULL || 
     740                 :         (m_eAccessMode != TABWrite && m_eAccessMode != TABReadWrite))
     741               0 :         return -1;
     742                 : 
     743                 :     // __TODO__
     744                 :     // We'll need more work in TABDATFile::WriteDateTimeField() before
     745                 :     // we can support indexes on fields of type DateTime (see bug #1844)
     746               4 :     if (eType == TABFDateTime)
     747                 :     {
     748                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
     749               0 :                  "Index on fields of type DateTime not supported yet.");
     750               0 :         return -1;
     751                 :     }
     752                 : 
     753                 :     /*-----------------------------------------------------------------
     754                 :      * Look for an empty slot in the current array, if there is none
     755                 :      * then extend the array.
     756                 :      *----------------------------------------------------------------*/
     757               6 :     for(i=0; m_papoIndexRootNodes && i<m_numIndexes; i++)
     758                 :     {
     759               2 :         if (m_papoIndexRootNodes[i] == NULL)
     760                 :         {
     761               0 :             nNewIndexNo = i;
     762               0 :             break;
     763                 :         }
     764                 :     }
     765                 : 
     766               4 :     if (nNewIndexNo == -1 && m_numIndexes >= 29)
     767                 :     {
     768                 :         CPLError(CE_Failure, CPLE_AppDefined,
     769                 :                  "Cannot add new index to %s.  A dataset can contain only a "
     770               0 :                  "maximum of 29 indexes.", m_pszFname);
     771               0 :         return -1;
     772                 :     }
     773                 : 
     774               4 :     if (nNewIndexNo == -1)
     775                 :     {
     776                 :         /*-------------------------------------------------------------
     777                 :          * Add a slot for new index at the end of the nodes array.
     778                 :          *------------------------------------------------------------*/
     779               4 :         m_numIndexes++;
     780                 :         m_papoIndexRootNodes = (TABINDNode**)CPLRealloc( m_papoIndexRootNodes,
     781                 :                                                          m_numIndexes*
     782               4 :                                                          sizeof(TABINDNode*));
     783                 : 
     784                 :         m_papbyKeyBuffers = (GByte **)CPLRealloc(m_papbyKeyBuffers,
     785               4 :                                                  m_numIndexes*sizeof(GByte*));
     786                 : 
     787               4 :         nNewIndexNo = m_numIndexes-1;
     788                 :     }
     789                 : 
     790                 :     /*-----------------------------------------------------------------
     791                 :      * Alloc and init new node
     792                 :      * The call to InitNode() automatically allocates storage space for
     793                 :      * the node in the file.
     794                 :      * New nodes are created with a subtree_depth=1 since they start as
     795                 :      * leaf nodes, i.e. their entries point directly to .DAT records
     796                 :      *----------------------------------------------------------------*/
     797                 :     int nKeyLength = ((eType == TABFInteger)  ? 4:
     798                 :                       (eType == TABFSmallInt) ? 2:
     799                 :                       (eType == TABFFloat)    ? 8:
     800                 :                       (eType == TABFDecimal)  ? 8:
     801                 :                       (eType == TABFDate)     ? 4:
     802                 :                       (eType == TABFTime)     ? 4:
     803                 :                       (eType == TABFDateTime) ? 8:
     804               4 :                       (eType == TABFLogical)  ? 4: MIN(128,nFieldSize));
     805                 : 
     806               4 :     m_papoIndexRootNodes[nNewIndexNo] = new TABINDNode(m_eAccessMode);
     807               4 :     if (m_papoIndexRootNodes[nNewIndexNo]->InitNode(m_fp, 0, nKeyLength, 
     808                 :                                                     1,  // subtree depth=1
     809                 :                                                     FALSE, // not unique
     810                 :                                                     &m_oBlockManager, 
     811                 :                                                     NULL, 0, 0)!= 0)
     812                 :     {
     813                 :         // CPLError has already been called
     814               0 :         return -1;
     815                 :     }
     816                 : 
     817                 :     // Alloc a temporary key buffer for this index.
     818                 :     // This buffer will be used by the BuildKey() method
     819                 :     m_papbyKeyBuffers[nNewIndexNo] = (GByte *)CPLCalloc(nKeyLength+1,
     820               4 :                                                         sizeof(GByte));
     821                 : 
     822                 :     // Return 1-based index number
     823               4 :     return nNewIndexNo+1;
     824                 : }
     825                 : 
     826                 : 
     827                 : /**********************************************************************
     828                 :  *                   TABINDFile::AddEntry()
     829                 :  *
     830                 :  * Add an .DAT record entry for pKeyValue in the specified index.
     831                 :  *
     832                 :  * Note that index numbers are positive values starting at 1.
     833                 :  * nRecordNo is the .DAT record number, record numbers start at 1.
     834                 :  *
     835                 :  * Returns 0 on success, -1 on error
     836                 :  **********************************************************************/
     837              80 : int TABINDFile::AddEntry(int nIndexNumber, GByte *pKeyValue, GInt32 nRecordNo)
     838                 : {
     839              80 :     if ((m_eAccessMode != TABWrite && m_eAccessMode != TABReadWrite) || 
     840                 :         ValidateIndexNo(nIndexNumber) != 0)
     841               0 :         return -1;
     842                 : 
     843              80 :     return m_papoIndexRootNodes[nIndexNumber-1]->AddEntry(pKeyValue,nRecordNo);
     844                 : }
     845                 : 
     846                 : 
     847                 : /**********************************************************************
     848                 :  *                   TABINDFile::Dump()
     849                 :  *
     850                 :  * Dump block contents... available only in DEBUG mode.
     851                 :  **********************************************************************/
     852                 : #ifdef DEBUG
     853                 : 
     854               0 : void TABINDFile::Dump(FILE *fpOut /*=NULL*/)
     855                 : {
     856               0 :     if (fpOut == NULL)
     857               0 :         fpOut = stdout;
     858                 : 
     859               0 :     fprintf(fpOut, "----- TABINDFile::Dump() -----\n");
     860                 : 
     861               0 :     if (m_fp == NULL)
     862                 :     {
     863               0 :         fprintf(fpOut, "File is not opened.\n");
     864                 :     }
     865                 :     else
     866                 :     {
     867               0 :         fprintf(fpOut, "File is opened: %s\n", m_pszFname);
     868               0 :         fprintf(fpOut, "   m_numIndexes   = %d\n", m_numIndexes);
     869               0 :         for(int i=0; i<m_numIndexes && m_papoIndexRootNodes; i++)
     870                 :         {
     871               0 :             if (m_papoIndexRootNodes[i])
     872                 :             {
     873               0 :                 fprintf(fpOut, "  ----- Index # %d -----\n", i+1);
     874               0 :                 m_papoIndexRootNodes[i]->Dump(fpOut);
     875                 :             }
     876                 :         }
     877                 : 
     878                 :     }
     879                 : 
     880               0 :     fflush(fpOut);
     881               0 : }
     882                 : 
     883                 : #endif // DEBUG
     884                 : 
     885                 : 
     886                 : 
     887                 : 
     888                 : 
     889                 : /*=====================================================================
     890                 :  *                      class TABINDNode
     891                 :  *====================================================================*/
     892                 : 
     893                 : /**********************************************************************
     894                 :  *                   TABINDNode::TABINDNode()
     895                 :  *
     896                 :  * Constructor.
     897                 :  **********************************************************************/
     898              14 : TABINDNode::TABINDNode(TABAccess eAccessMode /*=TABRead*/)
     899                 : {
     900              14 :     m_fp = NULL;
     901              14 :     m_poCurChildNode = NULL;
     902              14 :     m_nSubTreeDepth = 0;
     903              14 :     m_nKeyLength = 0;
     904              14 :     m_eFieldType = TABFUnknown;
     905              14 :     m_poDataBlock = NULL;
     906              14 :     m_numEntriesInNode = 0;
     907              14 :     m_nCurIndexEntry = 0;
     908              14 :     m_nPrevNodePtr = 0;
     909              14 :     m_nNextNodePtr = 0;
     910              14 :     m_poBlockManagerRef = NULL;
     911              14 :     m_poParentNodeRef = NULL;
     912              14 :     m_bUnique = FALSE;
     913                 : 
     914              14 :     m_eAccessMode = eAccessMode;
     915              14 : }
     916                 : 
     917                 : /**********************************************************************
     918                 :  *                   TABINDNode::~TABINDNode()
     919                 :  *
     920                 :  * Destructor.
     921                 :  **********************************************************************/
     922              14 : TABINDNode::~TABINDNode()
     923                 : {
     924              14 :     if (m_poCurChildNode)
     925               0 :         delete m_poCurChildNode;
     926                 : 
     927              14 :     if (m_poDataBlock)
     928              14 :         delete m_poDataBlock;
     929              14 : }
     930                 : 
     931                 : /**********************************************************************
     932                 :  *                   TABINDNode::InitNode()
     933                 :  *
     934                 :  * Init a node... this function can be used either to initialize a new
     935                 :  * node, or to make it point to a new data block in the file.
     936                 :  *
     937                 :  * By default, this call will read the data from the file at the
     938                 :  * specified location if necessary, and leave the object ready to be searched.
     939                 :  *
     940                 :  * In write access, if the block does not exist (i.e. nBlockPtr=0) then a
     941                 :  * new one is created and initialized.
     942                 :  *
     943                 :  * poParentNode is used in write access in order to update the parent node
     944                 :  * when this node becomes full and has to be split.
     945                 :  *
     946                 :  * Returns 0 on success, -1 on error.
     947                 :  **********************************************************************/
     948                 : int TABINDNode::InitNode(FILE *fp, int nBlockPtr, 
     949                 :                          int nKeyLength, int nSubTreeDepth, 
     950                 :                          GBool bUnique,
     951                 :                          TABBinBlockManager *poBlockMgr /*=NULL*/,
     952                 :                          TABINDNode *poParentNode /*=NULL*/,
     953              14 :                          int nPrevNodePtr /*=0*/, int nNextNodePtr /*=0*/)
     954                 : {
     955                 :     /*-----------------------------------------------------------------
     956                 :      * If the block already points to the right block, then don't do 
     957                 :      * anything here.
     958                 :      *----------------------------------------------------------------*/
     959              14 :     if (m_fp == fp && nBlockPtr> 0 && m_nCurDataBlockPtr == nBlockPtr)
     960               0 :         return 0;
     961                 : 
     962                 :     // Keep track of some info
     963              14 :     m_fp = fp;
     964              14 :     m_nKeyLength = nKeyLength;
     965              14 :     m_nSubTreeDepth = nSubTreeDepth;
     966              14 :     m_nCurDataBlockPtr = nBlockPtr;
     967              14 :     m_bUnique = bUnique;
     968                 : 
     969                 :     // Do not overwrite the following values if we receive NULL (the defaults)
     970              14 :     if (poBlockMgr)
     971              14 :         m_poBlockManagerRef = poBlockMgr;
     972              14 :     if (poParentNode)
     973               0 :         m_poParentNodeRef = poParentNode;
     974                 : 
     975                 :     // Set some defaults
     976              14 :     m_numEntriesInNode = 0;
     977              14 :     m_nPrevNodePtr = nPrevNodePtr;
     978              14 :     m_nNextNodePtr = nNextNodePtr;
     979                 : 
     980              14 :     m_nCurIndexEntry = 0;
     981                 : 
     982                 :     /*-----------------------------------------------------------------
     983                 :      * Init RawBinBlock
     984                 :      * The node's buffer has to be created with read/write access since
     985                 :      * the index is a very dynamic structure!
     986                 :      *----------------------------------------------------------------*/
     987              14 :     if (m_poDataBlock == NULL)
     988              14 :         m_poDataBlock = new TABRawBinBlock(TABReadWrite, TRUE);
     989                 : 
     990              18 :     if ((m_eAccessMode == TABWrite || m_eAccessMode == TABReadWrite) && 
     991                 :         nBlockPtr == 0 && m_poBlockManagerRef)
     992                 :     {
     993                 :         /*-------------------------------------------------------------
     994                 :          * Write access: Create and init a new block
     995                 :          *------------------------------------------------------------*/
     996               4 :         m_nCurDataBlockPtr = m_poBlockManagerRef->AllocNewBlock();
     997               4 :         m_poDataBlock->InitNewBlock(m_fp, 512, m_nCurDataBlockPtr);
     998                 : 
     999               4 :         m_poDataBlock->WriteInt32( m_numEntriesInNode );
    1000               4 :         m_poDataBlock->WriteInt32( m_nPrevNodePtr );
    1001               4 :         m_poDataBlock->WriteInt32( m_nNextNodePtr );
    1002                 :     }
    1003                 :     else
    1004                 :     {
    1005              10 :         CPLAssert(m_nCurDataBlockPtr > 0);
    1006                 :         /*-------------------------------------------------------------
    1007                 :          * Read the data block from the file, applies to read access, or
    1008                 :          * to write access (to modify an existing block)
    1009                 :          *------------------------------------------------------------*/
    1010              10 :         if (m_poDataBlock->ReadFromFile(m_fp, m_nCurDataBlockPtr, 512) != 0)
    1011                 :         {
    1012                 :             // CPLError() has already been called.
    1013               0 :             return -1;
    1014                 :         }
    1015                 : 
    1016              10 :         m_poDataBlock->GotoByteInBlock(0);
    1017              10 :         m_numEntriesInNode = m_poDataBlock->ReadInt32();
    1018              10 :         m_nPrevNodePtr = m_poDataBlock->ReadInt32();
    1019              10 :         m_nNextNodePtr = m_poDataBlock->ReadInt32();
    1020                 :     }
    1021                 : 
    1022                 :     // m_poDataBlock is now positioned at the beginning of the key entries
    1023                 : 
    1024              14 :     return 0;
    1025                 : }
    1026                 : 
    1027                 : 
    1028                 : /**********************************************************************
    1029                 :  *                   TABINDNode::GotoNodePtr()
    1030                 :  *
    1031                 :  * Move to the specified node ptr, and read the new node data from the file.
    1032                 :  *
    1033                 :  * This is just a cover funtion on top of InitNode()
    1034                 :  **********************************************************************/
    1035               0 : int TABINDNode::GotoNodePtr(GInt32 nNewNodePtr)
    1036                 : {
    1037                 :     // First flush current changes if any.
    1038               0 :     if ((m_eAccessMode == TABWrite || m_eAccessMode == TABReadWrite) && 
    1039                 :         m_poDataBlock && m_poDataBlock->CommitToFile() != 0)
    1040               0 :         return -1;
    1041                 : 
    1042               0 :     CPLAssert(nNewNodePtr % 512 == 0);
    1043                 : 
    1044                 :     // Then move to the requested location.
    1045                 :     return InitNode(m_fp, nNewNodePtr, m_nKeyLength, m_nSubTreeDepth, 
    1046               0 :                     m_bUnique);
    1047                 : }
    1048                 : 
    1049                 : /**********************************************************************
    1050                 :  *                   TABINDNode::ReadIndexEntry()
    1051                 :  *
    1052                 :  * Read the key value and record/node ptr for the specified index entry
    1053                 :  * inside the current node data.
    1054                 :  *
    1055                 :  * nEntryNo is the 0-based index of the index entry that we are interested
    1056                 :  * in inside the current node.
    1057                 :  *
    1058                 :  * Returns the record/node ptr, and copies the key value inside the
    1059                 :  * buffer pointed to by *pKeyValue... this assumes that *pKeyValue points
    1060                 :  * to a buffer big enough to hold the key value (m_nKeyLength bytes).
    1061                 :  * If pKeyValue == NULL, then this parameter is ignored and the key value
    1062                 :  * is not copied.
    1063                 :  **********************************************************************/
    1064              10 : GInt32 TABINDNode::ReadIndexEntry(int nEntryNo, GByte *pKeyValue)
    1065                 : {
    1066              10 :     GInt32 nRecordPtr = 0;
    1067              10 :     if (nEntryNo >= 0 && nEntryNo < m_numEntriesInNode)
    1068                 :     {
    1069              10 :         if (pKeyValue)
    1070                 :         {
    1071               0 :             m_poDataBlock->GotoByteInBlock(12 + nEntryNo*(m_nKeyLength+4));
    1072               0 :             m_poDataBlock->ReadBytes(m_nKeyLength, pKeyValue);
    1073                 :         }
    1074                 :         else
    1075                 :         {
    1076                 :             m_poDataBlock->GotoByteInBlock(12 + nEntryNo*(m_nKeyLength+4)+
    1077              10 :                                                                  m_nKeyLength);
    1078                 :         }
    1079                 : 
    1080              10 :         nRecordPtr = m_poDataBlock->ReadInt32();
    1081                 :     }
    1082                 : 
    1083              10 :     return nRecordPtr;
    1084                 : }
    1085                 : 
    1086                 : /**********************************************************************
    1087                 :  *                   TABINDNode::IndexKeyCmp()
    1088                 :  *
    1089                 :  * Compare the specified index entry with the key value, and 
    1090                 :  * return 0 if equal, an integer less than 0 if key is smaller than 
    1091                 :  * index entry, and an integer greater than 0 if key is bigger than 
    1092                 :  * index entry.
    1093                 :  *
    1094                 :  * nEntryNo is the 0-based index of the index entry that we are interested
    1095                 :  * in inside the current node.
    1096                 :  **********************************************************************/
    1097            1321 : int   TABINDNode::IndexKeyCmp(GByte *pKeyValue, int nEntryNo)
    1098                 : {
    1099            1321 :     CPLAssert(pKeyValue);
    1100            1321 :     CPLAssert(nEntryNo >= 0 && nEntryNo < m_numEntriesInNode);
    1101                 : 
    1102            1321 :     m_poDataBlock->GotoByteInBlock(12 + nEntryNo*(m_nKeyLength+4));
    1103                 : 
    1104            1321 :     return memcmp(pKeyValue, m_poDataBlock->GetCurDataPtr(), m_nKeyLength);
    1105                 : }
    1106                 : 
    1107                 : /**********************************************************************
    1108                 :  *                   TABINDNode::SetFieldType()
    1109                 :  *
    1110                 :  * Sets the field type for the current index and recursively set all 
    1111                 :  * children as well.
    1112                 :  * This information will then be used in building the key values, etc.
    1113                 :  *
    1114                 :  * Returns 0 on success, -1 on error.
    1115                 :  **********************************************************************/
    1116               0 : int TABINDNode::SetFieldType(TABFieldType eType)
    1117                 : {
    1118               0 :     if (m_fp == NULL)
    1119                 :     {
    1120                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    1121               0 :                  "TABINDNode::SetFieldType(): File has not been opened yet!");
    1122               0 :         return -1;
    1123                 :     }
    1124                 : 
    1125                 :     /*-----------------------------------------------------------------
    1126                 :      * Validate field type with key length
    1127                 :      *----------------------------------------------------------------*/
    1128               0 :     if ((eType == TABFInteger && m_nKeyLength != 4) ||
    1129                 :         (eType == TABFSmallInt && m_nKeyLength != 2) ||
    1130                 :         (eType == TABFFloat && m_nKeyLength != 8) ||
    1131                 :         (eType == TABFDecimal && m_nKeyLength != 8) ||
    1132                 :         (eType == TABFDate && m_nKeyLength != 4) ||
    1133                 :         (eType == TABFTime && m_nKeyLength != 4) ||
    1134                 :         (eType == TABFDateTime && m_nKeyLength != 8) ||
    1135                 :         (eType == TABFLogical && m_nKeyLength != 4) )
    1136                 :     {
    1137                 :         CPLError(CE_Failure, CPLE_IllegalArg,
    1138                 :                  "Index key length (%d) does not match field type (%s).",
    1139               0 :                  m_nKeyLength, TABFIELDTYPE_2_STRING(eType) );
    1140               0 :         return -1;
    1141                 :     }           
    1142                 :     
    1143               0 :     m_eFieldType = eType;
    1144                 : 
    1145                 :     /*-----------------------------------------------------------------
    1146                 :      * Pass the field type info to child nodes
    1147                 :      *----------------------------------------------------------------*/
    1148               0 :     if (m_poCurChildNode)
    1149               0 :         return m_poCurChildNode->SetFieldType(eType);
    1150                 : 
    1151               0 :     return 0;
    1152                 : }
    1153                 : 
    1154                 : /**********************************************************************
    1155                 :  *                   TABINDNode::FindFirst()
    1156                 :  *
    1157                 :  * Start a new search in this node and its children for a key value.
    1158                 :  * If the index is not unique, then FindNext() can be used to return
    1159                 :  * the other values that correspond to the key.
    1160                 :  *
    1161                 :  * Return value:
    1162                 :  *  - the key's corresponding record number in the .DAT file (greater than 0)
    1163                 :  *  - 0 if the key was not found
    1164                 :  *  - or -1 if an error happened
    1165                 :  **********************************************************************/
    1166              90 : GInt32 TABINDNode::FindFirst(GByte *pKeyValue)
    1167                 : {
    1168              90 :     if (m_poDataBlock == NULL)
    1169                 :     {
    1170                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    1171               0 :                  "TABINDNode::Search(): Node has not been initialized yet!");
    1172               0 :         return -1;
    1173                 :     }
    1174                 : 
    1175                 :     /*-----------------------------------------------------------------
    1176                 :      * Unless something has been broken, this method will be called by our
    1177                 :      * parent node after it has established that we are the best candidate
    1178                 :      * to contain the first instance of the key value.  So there is no
    1179                 :      * need to look in the previous or next nodes in the chain... if the
    1180                 :      * value is not found in the current node block then it is not present
    1181                 :      * in the index at all.
    1182                 :      *
    1183                 :      * m_nCurIndexEntry will be used to keep track of the search pointer
    1184                 :      * when FindNext() will be used.
    1185                 :      *----------------------------------------------------------------*/
    1186              90 :     m_nCurIndexEntry = 0;
    1187                 : 
    1188              90 :     if (m_nSubTreeDepth == 1)
    1189                 :     {
    1190                 :         /*-------------------------------------------------------------
    1191                 :          * Leaf node level... we look for an exact match
    1192                 :          *------------------------------------------------------------*/
    1193             841 :         while(m_nCurIndexEntry < m_numEntriesInNode)
    1194                 :         {
    1195             691 :             int nCmpStatus = IndexKeyCmp(pKeyValue, m_nCurIndexEntry);
    1196             691 :             if (nCmpStatus > 0)
    1197                 :             {
    1198                 :                 /* Not there yet... (pKey > IndexEntry) */
    1199             661 :                 m_nCurIndexEntry++;
    1200                 :             }
    1201              30 :             else if (nCmpStatus == 0)
    1202                 :             {
    1203                 :                 /* Found it!  Return the record number */
    1204              10 :                 return ReadIndexEntry(m_nCurIndexEntry, NULL);
    1205                 :             }
    1206                 :             else
    1207                 :             {
    1208                 :                 /* Item does not exist... return 0 */
    1209              20 :                 return 0;
    1210                 :             }
    1211                 :         }
    1212                 :     }
    1213                 :     else
    1214                 :     {
    1215                 :         /*-------------------------------------------------------------
    1216                 :          * Index Node: Find the child node that is the best candidate to
    1217                 :          * contain the value
    1218                 :          *
    1219                 :          * In the index tree at the node level, for each node entry inside
    1220                 :          * the parent node, the key value (in the parent) corresponds to 
    1221                 :          * the value of the first key that you will find when you access
    1222                 :          * the corresponding child node.
    1223                 :          *
    1224                 :          * This means that to find the child that contains the searched
    1225                 :          * key, we look for the first index key >= pKeyValue and the child
    1226                 :          * node that we are looking for is the one that precedes it.
    1227                 :          *
    1228                 :          * If the first key in the list is >= pKeyValue then this means
    1229                 :          * that the pKeyValue does not exist in our children and we just
    1230                 :          * return 0.  We do not bother searching the previous node at the
    1231                 :          * same level since this is the responsibility of our parent.
    1232                 :          *
    1233                 :          * The same way if the last indexkey in this node is < pKeyValue
    1234                 :          * we won't bother searching the next node since this should also
    1235                 :          * be taken care of by our parent.
    1236                 :          *------------------------------------------------------------*/
    1237               0 :         while(m_nCurIndexEntry < m_numEntriesInNode)
    1238                 :         {
    1239               0 :             int nCmpStatus = IndexKeyCmp(pKeyValue, m_nCurIndexEntry);
    1240                 : 
    1241               0 :             if (nCmpStatus > 0 && m_nCurIndexEntry+1 < m_numEntriesInNode)
    1242                 :             {
    1243                 :                 /* Not there yet... (pKey > IndexEntry) */
    1244               0 :                 m_nCurIndexEntry++;
    1245                 :             }
    1246                 :             else
    1247                 :             {
    1248                 :                 /*-----------------------------------------------------
    1249                 :                  * We either found an indexkey >= pKeyValue or reached 
    1250                 :                  * the last entry in this node... still have to decide 
    1251                 :                  * what we're going to do... 
    1252                 :                  *----------------------------------------------------*/
    1253               0 :                 if (nCmpStatus < 0 && m_nCurIndexEntry == 0)
    1254                 :                 {
    1255                 :                     /*-------------------------------------------------
    1256                 :                      * First indexkey in block is > pKeyValue...
    1257                 :                      * the key definitely does not exist in our children.
    1258                 :                      * However, we still want to drill down the rest of the
    1259                 :                      * tree because this function is also used when looking
    1260                 :                      * for a node to insert a new value.
    1261                 :                      *-------------------------------------------------*/
    1262                 :                     // Nothing special to do... just continue processing.
    1263                 :                 }
    1264                 : 
    1265                 :                 /*-----------------------------------------------------
    1266                 :                  * If we found an node for which pKeyValue < indexkey 
    1267                 :                  * (or pKeyValue <= indexkey for non-unique indexes) then 
    1268                 :                  * we access the preceding child node.
    1269                 :                  *
    1270                 :                  * Note that for indexkey == pKeyValue in non-unique indexes
    1271                 :                  * we also check in the preceding node because when keys
    1272                 :                  * are not unique then there are chances that the requested
    1273                 :                  * key could also be found at the end of the preceding node.
    1274                 :                  * In this case, if we don't find the key in the preceding
    1275                 :                  * node then we'll do a second search in the current node.
    1276                 :                  *----------------------------------------------------*/
    1277               0 :                 int numChildrenToVisit=1;
    1278               0 :                 if (m_nCurIndexEntry > 0 &&
    1279                 :                     (nCmpStatus < 0 || (nCmpStatus==0 && !m_bUnique)) )
    1280                 :                 {
    1281               0 :                     m_nCurIndexEntry--;
    1282               0 :                     if (nCmpStatus == 0)
    1283               0 :                         numChildrenToVisit = 2;
    1284                 :                 }
    1285                 : 
    1286                 :                 /*-----------------------------------------------------
    1287                 :                  * OK, now it's time to load/access the candidate child nodes.
    1288                 :                  *----------------------------------------------------*/
    1289               0 :                 int nRetValue = 0;
    1290               0 :                 for(int iChild=0; nRetValue==0 && 
    1291                 :                                   iChild<numChildrenToVisit; iChild++)
    1292                 :                 {
    1293                 :                     // If we're doing a second pass then jump to next entry
    1294               0 :                     if (iChild > 0)
    1295               0 :                         m_nCurIndexEntry++;
    1296                 : 
    1297               0 :                     int nChildNodePtr = ReadIndexEntry(m_nCurIndexEntry, NULL);
    1298               0 :                     if (nChildNodePtr == 0)
    1299                 :                     {
    1300                 :                         /* Invalid child node??? */
    1301               0 :                         nRetValue = 0;
    1302               0 :                         continue;
    1303                 :                     }
    1304               0 :                     else if (m_poCurChildNode == NULL)
    1305                 :                     {
    1306                 :                         /* Child node has never been initialized...do it now!*/
    1307                 : 
    1308               0 :                         m_poCurChildNode = new TABINDNode(m_eAccessMode);
    1309               0 :                         if ( m_poCurChildNode->InitNode(m_fp, nChildNodePtr, 
    1310                 :                                                         m_nKeyLength, 
    1311                 :                                                         m_nSubTreeDepth-1,
    1312                 :                                                         m_bUnique,
    1313                 :                                                         m_poBlockManagerRef, 
    1314                 :                                                         this) != 0 ||
    1315                 :                              m_poCurChildNode->SetFieldType(m_eFieldType)!=0)
    1316                 :                         {
    1317                 :                             // An error happened... and was already reported
    1318               0 :                             return -1;
    1319                 :                         }
    1320                 :                     }
    1321                 : 
    1322               0 :                     if (m_poCurChildNode->GotoNodePtr(nChildNodePtr) != 0)
    1323                 :                     {
    1324                 :                         // An error happened and has already been reported
    1325               0 :                         return -1;
    1326                 :                     }
    1327                 : 
    1328               0 :                     nRetValue = m_poCurChildNode->FindFirst(pKeyValue);
    1329                 :                 }/*for iChild*/
    1330                 : 
    1331               0 :                 return nRetValue;
    1332                 : 
    1333                 :             }/*else*/
    1334                 : 
    1335                 :         }/*while numEntries*/
    1336                 : 
    1337                 :         // No node was found that contains the key value.
    1338                 :         // We should never get here... only leaf nodes should return 0
    1339               0 :         CPLAssert(FALSE);
    1340               0 :         return 0;
    1341                 :     }
    1342                 : 
    1343              60 :     return 0;  // Not found
    1344                 : }
    1345                 : 
    1346                 : /**********************************************************************
    1347                 :  *                   TABINDNode::FindNext()
    1348                 :  *
    1349                 :  * Continue the search previously started by FindFirst() in this node 
    1350                 :  * and its children for a key value.
    1351                 :  *
    1352                 :  * Return value:
    1353                 :  *  - the key's corresponding record number in the .DAT file (greater than 0)
    1354                 :  *  - 0 if the key was not found
    1355                 :  *  - or -1 if an error happened
    1356                 :  **********************************************************************/
    1357              10 : GInt32 TABINDNode::FindNext(GByte *pKeyValue)
    1358                 : {
    1359              10 :     if (m_poDataBlock == NULL)
    1360                 :     {
    1361                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    1362               0 :                  "TABINDNode::Search(): Node has not been initialized yet!");
    1363               0 :         return -1;
    1364                 :     }
    1365                 : 
    1366                 :     /*-----------------------------------------------------------------
    1367                 :      * m_nCurIndexEntry is the index of the last item that has been 
    1368                 :      * returned by FindFirst()/FindNext().
    1369                 :      *----------------------------------------------------------------*/
    1370                 : 
    1371              10 :     if (m_nSubTreeDepth == 1)
    1372                 :     {
    1373                 :         /*-------------------------------------------------------------
    1374                 :          * Leaf node level... check if the next entry is an exact match
    1375                 :          *------------------------------------------------------------*/
    1376              10 :         m_nCurIndexEntry++;
    1377              10 :         if (m_nCurIndexEntry >= m_numEntriesInNode && m_nNextNodePtr > 0)
    1378                 :         {
    1379                 :             // We're at the end of a node ... continue with next node
    1380               0 :             GotoNodePtr(m_nNextNodePtr);
    1381               0 :             m_nCurIndexEntry = 0;
    1382                 :         }
    1383                 : 
    1384              10 :         if (m_nCurIndexEntry < m_numEntriesInNode &&
    1385                 :             IndexKeyCmp(pKeyValue, m_nCurIndexEntry) == 0)
    1386                 :         {
    1387                 :            /* Found it!  Return the record number */
    1388               0 :             return ReadIndexEntry(m_nCurIndexEntry, NULL);
    1389                 :         }
    1390                 :         else
    1391                 :         {
    1392                 :             /* No more items with that key... return 0 */
    1393              10 :             return 0;
    1394                 :         }
    1395                 :     }
    1396                 :     else
    1397                 :     {
    1398                 :         /*-------------------------------------------------------------
    1399                 :          * Index Node: just pass the search to this child node.
    1400                 :          *------------------------------------------------------------*/
    1401               0 :         while(m_nCurIndexEntry < m_numEntriesInNode)
    1402                 :         {
    1403               0 :             if (m_poCurChildNode != NULL)
    1404               0 :                 return m_poCurChildNode->FindNext(pKeyValue);
    1405                 :         }
    1406                 :     }
    1407                 : 
    1408                 :     // No more nodes were found that contain the key value.
    1409               0 :     return 0;
    1410                 : }
    1411                 : 
    1412                 : 
    1413                 : /**********************************************************************
    1414                 :  *                   TABINDNode::CommitToFile()
    1415                 :  *
    1416                 :  * For write access, write current block and its children to file.
    1417                 :  *
    1418                 :  * note: TABRawBinBlock::CommitToFile() does nothing unless the block has
    1419                 :  *       been modified.  (it has an internal bModified flag)
    1420                 :  *
    1421                 :  * Returns 0 on success, -1 on error.
    1422                 :  **********************************************************************/
    1423               6 : int TABINDNode::CommitToFile()
    1424                 : {
    1425               6 :     if ((m_eAccessMode != TABWrite && m_eAccessMode != TABReadWrite) || 
    1426                 :         m_poDataBlock == NULL)
    1427               0 :         return -1;
    1428                 : 
    1429               6 :     if (m_poCurChildNode)
    1430                 :     {
    1431               0 :         if (m_poCurChildNode->CommitToFile() != 0)
    1432               0 :             return -1;
    1433                 : 
    1434               0 :         m_nSubTreeDepth = m_poCurChildNode->GetSubTreeDepth() + 1;
    1435                 :     }
    1436                 : 
    1437               6 :     return m_poDataBlock->CommitToFile();
    1438                 : }
    1439                 : 
    1440                 : /**********************************************************************
    1441                 :  *                   TABINDNode::AddEntry()
    1442                 :  *
    1443                 :  * Add an .DAT record entry for pKeyValue in this index
    1444                 :  *
    1445                 :  * nRecordNo is the .DAT record number, record numbers start at 1.
    1446                 :  *
    1447                 :  * In order to insert a new value, the root node first does a FindFirst()
    1448                 :  * that will load the whole tree branch up to the insertion point.
    1449                 :  * Then AddEntry() is recursively called up to the leaf node level for
    1450                 :  * the insertion of the actual value.
    1451                 :  * If the leaf node is full then it will be split and if necessary the 
    1452                 :  * split will propagate up in the tree through the pointer that each node
    1453                 :  * has on its parent.
    1454                 :  *
    1455                 :  * If bAddInThisNodeOnly=TRUE, then the entry is added only locally and
    1456                 :  * we do not try to update the child node.  This is used when the parent 
    1457                 :  * of a node that is being splitted has to be updated.
    1458                 :  *
    1459                 :  * bInsertAfterCurChild forces the insertion to happen immediately after
    1460                 :  * the m_nCurIndexEntry.  This works only when bAddInThisNodeOnly=TRUE.
    1461                 :  * The default is to search the node for a an insertion point.
    1462                 :  *
    1463                 :  * Returns 0 on success, -1 on error
    1464                 :  **********************************************************************/
    1465                 : int TABINDNode::AddEntry(GByte *pKeyValue, GInt32 nRecordNo,
    1466                 :                          GBool bAddInThisNodeOnly /*=FALSE*/,
    1467                 :                          GBool bInsertAfterCurChild /*=FALSE*/,
    1468              80 :                          GBool bMakeNewEntryCurChild /*=FALSE*/)
    1469                 : {
    1470              80 :     if ((m_eAccessMode != TABWrite && m_eAccessMode != TABReadWrite) || 
    1471                 :         m_poDataBlock == NULL)
    1472               0 :         return -1;
    1473                 : 
    1474                 :     /*-----------------------------------------------------------------
    1475                 :      * If I'm the root node, then do a FindFirst() to init all the nodes
    1476                 :      * and to make all of them point ot the insertion point.
    1477                 :      *----------------------------------------------------------------*/
    1478              80 :     if (m_poParentNodeRef == NULL && !bAddInThisNodeOnly)
    1479                 :     {
    1480              80 :         if (FindFirst(pKeyValue) < 0)
    1481               0 :             return -1;  // Error happened and has already been reported.
    1482                 :     }
    1483                 : 
    1484              80 :     if (m_poCurChildNode && !bAddInThisNodeOnly)
    1485                 :     {
    1486               0 :         CPLAssert(m_nSubTreeDepth > 1);
    1487                 :         /*-------------------------------------------------------------
    1488                 :          * Propagate the call down to our children
    1489                 :          * Note: this recursive call could result in new levels of nodes
    1490                 :          * being added under our feet by SplitRootnode() so it is very 
    1491                 :          * important to return right after this call or we might not be 
    1492                 :          * able to recognize this node at the end of the call!
    1493                 :          *------------------------------------------------------------*/
    1494               0 :         return m_poCurChildNode->AddEntry(pKeyValue, nRecordNo);
    1495                 :     }
    1496                 :     else
    1497                 :     {
    1498                 :         /*-------------------------------------------------------------
    1499                 :          * OK, we're a leaf node... this is where the real work happens!!!
    1500                 :          *------------------------------------------------------------*/
    1501              80 :         CPLAssert(m_nSubTreeDepth == 1 || bAddInThisNodeOnly);
    1502                 : 
    1503                 :         /*-------------------------------------------------------------
    1504                 :          * First thing to do is make sure that there is room for a new
    1505                 :          * entry in this node, and to split it if necessary.
    1506                 :          *------------------------------------------------------------*/
    1507              80 :         if (GetNumEntries() == GetMaxNumEntries())
    1508                 :         {
    1509               0 :             if (m_poParentNodeRef == NULL)
    1510                 :             {
    1511                 :                 /*-----------------------------------------------------
    1512                 :                  * Splitting the root node adds one level to the tree, so
    1513                 :                  * after splitting we just redirect the call to our child.
    1514                 :                  *----------------------------------------------------*/
    1515               0 :                 if (SplitRootNode() != 0)
    1516               0 :                     return -1;  // Error happened and has already been reported
    1517                 : 
    1518               0 :                 CPLAssert(m_poCurChildNode);
    1519               0 :                 CPLAssert(m_nSubTreeDepth > 1);
    1520                 :                 return m_poCurChildNode->AddEntry(pKeyValue, nRecordNo,
    1521                 :                                                   bAddInThisNodeOnly,
    1522                 :                                                   bInsertAfterCurChild,
    1523               0 :                                                   bMakeNewEntryCurChild);
    1524                 :             }
    1525                 :             else
    1526                 :             {
    1527                 :                 /*-----------------------------------------------------
    1528                 :                  * Splitting a regular node will leave it 50% full.
    1529                 :                  *----------------------------------------------------*/
    1530               0 :                 if (SplitNode() != 0)
    1531               0 :                     return -1; 
    1532                 :             }
    1533                 :         }
    1534                 : 
    1535                 :         /*-------------------------------------------------------------
    1536                 :          * Insert new key/value at the right position in node.
    1537                 :          *------------------------------------------------------------*/
    1538              80 :         if (InsertEntry(pKeyValue, nRecordNo, 
    1539                 :                         bInsertAfterCurChild, bMakeNewEntryCurChild) != 0)
    1540               0 :             return -1;
    1541                 :     }
    1542                 : 
    1543              80 :     return 0;
    1544                 : }
    1545                 : 
    1546                 : /**********************************************************************
    1547                 :  *                   TABINDNode::InsertEntry()
    1548                 :  *
    1549                 :  * (private method)
    1550                 :  *
    1551                 :  * Insert a key/value pair in the current node buffer.
    1552                 :  *
    1553                 :  * Returns 0 on success, -1 on error
    1554                 :  **********************************************************************/
    1555                 : int TABINDNode::InsertEntry(GByte *pKeyValue, GInt32 nRecordNo,
    1556                 :                             GBool bInsertAfterCurChild /*=FALSE*/,
    1557              80 :                             GBool bMakeNewEntryCurChild /*=FALSE*/)
    1558                 : {
    1559              80 :     int iInsertAt=0;
    1560                 : 
    1561              80 :     if (GetNumEntries() >= GetMaxNumEntries())
    1562                 :     {   
    1563                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    1564               0 :                  "Node is full!  Cannot insert key!");
    1565               0 :         return -1;
    1566                 :     }
    1567                 : 
    1568                 :     /*-----------------------------------------------------------------
    1569                 :      * Find the spot where the key belongs
    1570                 :      *----------------------------------------------------------------*/
    1571              80 :     if (bInsertAfterCurChild)
    1572                 :     {
    1573               0 :         iInsertAt = m_nCurIndexEntry+1;
    1574                 :     }
    1575                 :     else
    1576                 :     {
    1577             760 :         while(iInsertAt < m_numEntriesInNode)
    1578                 :         {
    1579             620 :             int nCmpStatus = IndexKeyCmp(pKeyValue, iInsertAt);
    1580             620 :             if (nCmpStatus <= 0)
    1581                 :             {
    1582              20 :                 break;
    1583                 :             }
    1584             600 :             iInsertAt++;
    1585                 :         }
    1586                 :     }
    1587                 : 
    1588              80 :     m_poDataBlock->GotoByteInBlock(12 + iInsertAt*(m_nKeyLength+4));
    1589                 : 
    1590                 :     /*-----------------------------------------------------------------
    1591                 :      * Shift all entries that follow in the array
    1592                 :      *----------------------------------------------------------------*/
    1593              80 :     if (iInsertAt < m_numEntriesInNode)
    1594                 :     {
    1595                 :         // Since we use memmove() directly, we need to inform 
    1596                 :         // m_poDataBlock that the upper limit of the buffer will move
    1597                 :         m_poDataBlock->GotoByteInBlock(12 + (m_numEntriesInNode+1)*
    1598              20 :                                                         (m_nKeyLength+4));
    1599              20 :         m_poDataBlock->GotoByteInBlock(12 + iInsertAt*(m_nKeyLength+4));
    1600                 : 
    1601                 :         memmove(m_poDataBlock->GetCurDataPtr()+(m_nKeyLength+4),
    1602                 :                 m_poDataBlock->GetCurDataPtr(),
    1603              20 :                 (m_numEntriesInNode-iInsertAt)*(m_nKeyLength+4));
    1604                 : 
    1605                 :     }
    1606                 : 
    1607                 :     /*-----------------------------------------------------------------
    1608                 :      * Write new entry
    1609                 :      *----------------------------------------------------------------*/
    1610              80 :     m_poDataBlock->WriteBytes(m_nKeyLength, pKeyValue);
    1611              80 :     m_poDataBlock->WriteInt32(nRecordNo);
    1612                 : 
    1613              80 :     m_numEntriesInNode++;
    1614              80 :     m_poDataBlock->GotoByteInBlock(0);
    1615              80 :     m_poDataBlock->WriteInt32(m_numEntriesInNode);
    1616                 : 
    1617              80 :     if (bMakeNewEntryCurChild)
    1618               0 :         m_nCurIndexEntry = iInsertAt;
    1619              80 :     else if (m_nCurIndexEntry >= iInsertAt)
    1620              80 :         m_nCurIndexEntry++;
    1621                 : 
    1622                 :     /*-----------------------------------------------------------------
    1623                 :      * If we replaced the first entry in the node, then this node's key
    1624                 :      * changes and we have to update the reference in the parent node.
    1625                 :      *----------------------------------------------------------------*/
    1626              80 :     if (iInsertAt == 0 && m_poParentNodeRef)
    1627                 :     {
    1628               0 :         if (m_poParentNodeRef->UpdateCurChildEntry(GetNodeKey(),
    1629                 :                                                    GetNodeBlockPtr()) != 0)
    1630               0 :             return -1;
    1631                 :     }
    1632                 : 
    1633              80 :     return 0;
    1634                 : }
    1635                 : 
    1636                 : 
    1637                 : /**********************************************************************
    1638                 :  *                   TABINDNode::UpdateCurChildEntry()
    1639                 :  *
    1640                 :  * Update the key for the current child node.  This method is called by
    1641                 :  * the child when its first entry (defining its node key) is changed.
    1642                 :  *
    1643                 :  * Returns 0 on success, -1 on error
    1644                 :  **********************************************************************/
    1645               0 : int TABINDNode::UpdateCurChildEntry(GByte *pKeyValue, GInt32 nRecordNo)
    1646                 : {
    1647                 : 
    1648                 :     /*-----------------------------------------------------------------
    1649                 :      * Update current child entry with the info for the first node.
    1650                 :      *
    1651                 :      * For some reason, the key for first entry of the first node of each
    1652                 :      * level has to be set to 0 except for the leaf level.
    1653                 :      *----------------------------------------------------------------*/
    1654               0 :     m_poDataBlock->GotoByteInBlock(12 + m_nCurIndexEntry*(m_nKeyLength+4));
    1655                 : 
    1656               0 :     if (m_nCurIndexEntry == 0 && m_nSubTreeDepth > 1 && m_nPrevNodePtr == 0)
    1657                 :     {
    1658               0 :         m_poDataBlock->WriteZeros(m_nKeyLength);
    1659                 :     }
    1660                 :     else
    1661                 :     {
    1662               0 :         m_poDataBlock->WriteBytes(m_nKeyLength, pKeyValue);
    1663                 :     }
    1664               0 :     m_poDataBlock->WriteInt32(nRecordNo);
    1665                 : 
    1666               0 :     return 0;
    1667                 : }
    1668                 : 
    1669                 : 
    1670                 : 
    1671                 : /**********************************************************************
    1672                 :  *                   TABINDNode::UpdateSplitChild()
    1673                 :  *
    1674                 :  * Update the key and/or record ptr information corresponding to the 
    1675                 :  * current child node.
    1676                 :  *
    1677                 :  * Returns 0 on success, -1 on error
    1678                 :  **********************************************************************/
    1679                 : int TABINDNode::UpdateSplitChild(GByte *pKeyValue1, GInt32 nRecordNo1,
    1680                 :                                  GByte *pKeyValue2, GInt32 nRecordNo2,
    1681               0 :                                  int nNewCurChildNo /* 1 or 2 */)
    1682                 : {
    1683                 : 
    1684                 :     /*-----------------------------------------------------------------
    1685                 :      * Update current child entry with the info for the first node.
    1686                 :      *
    1687                 :      * For some reason, the key for first entry of the first node of each
    1688                 :      * level has to be set to 0 except for the leaf level.
    1689                 :      *----------------------------------------------------------------*/
    1690               0 :     m_poDataBlock->GotoByteInBlock(12 + m_nCurIndexEntry*(m_nKeyLength+4));
    1691                 : 
    1692               0 :     if (m_nCurIndexEntry == 0 && m_nSubTreeDepth > 1 && m_nPrevNodePtr == 0)
    1693                 :     {
    1694               0 :         m_poDataBlock->WriteZeros(m_nKeyLength);
    1695                 :     }
    1696                 :     else
    1697                 :     {
    1698               0 :         m_poDataBlock->WriteBytes(m_nKeyLength, pKeyValue1);
    1699                 :     }
    1700               0 :     m_poDataBlock->WriteInt32(nRecordNo1);
    1701                 : 
    1702                 :     /*-----------------------------------------------------------------
    1703                 :      * Add an entry for the second node after the current one and ask 
    1704                 :      * AddEntry() to update m_nCurIndexEntry if the new node should 
    1705                 :      * become the new current child.
    1706                 :      *----------------------------------------------------------------*/
    1707               0 :     if (AddEntry(pKeyValue2, nRecordNo2, 
    1708                 :                  TRUE, /* bInThisNodeOnly */
    1709                 :                  TRUE, /* bInsertAfterCurChild */
    1710                 :                  (nNewCurChildNo==2)) != 0)
    1711                 :     {
    1712               0 :             return -1;
    1713                 :     }
    1714                 : 
    1715               0 :     return 0;
    1716                 : }
    1717                 : 
    1718                 : 
    1719                 : /**********************************************************************
    1720                 :  *                   TABINDNode::SplitNode()
    1721                 :  *
    1722                 :  * (private method)
    1723                 :  *
    1724                 :  * Split a node, update the references in the parent node, etc.
    1725                 :  * Note that Root Nodes cannot be split using this method... SplitRootNode()
    1726                 :  * should be used instead.
    1727                 :  *
    1728                 :  * The node is split in a way that the current child stays inside this
    1729                 :  * node object, and a new node is created for the other half of the
    1730                 :  * entries.  This way, the object references in this node's parent and in its 
    1731                 :  * current child all remain valid.  The new node is not kept in memory, 
    1732                 :  * it is written to disk right away.
    1733                 :  *
    1734                 :  * Returns 0 on success, -1 on error
    1735                 :  **********************************************************************/
    1736               0 : int TABINDNode::SplitNode()
    1737                 : {
    1738               0 :     TABINDNode *poNewNode=NULL;
    1739                 :     int numInNode1, numInNode2;
    1740                 : 
    1741               0 :     CPLAssert(m_numEntriesInNode >= 2);
    1742               0 :     CPLAssert(m_poParentNodeRef);  // This func. does not work for root nodes
    1743                 : 
    1744                 :     /*-----------------------------------------------------------------
    1745                 :      * Prepare new node
    1746                 :      *----------------------------------------------------------------*/
    1747               0 :     numInNode1 = (m_numEntriesInNode+1)/2;
    1748               0 :     numInNode2 = m_numEntriesInNode - numInNode1;
    1749                 : 
    1750               0 :     poNewNode = new TABINDNode(m_eAccessMode);
    1751                 : 
    1752               0 :     if (m_nCurIndexEntry < numInNode1)
    1753                 :     {
    1754                 :         /*-------------------------------------------------------------
    1755                 :          * We will move the second half of the array to a new node.
    1756                 :          *------------------------------------------------------------*/
    1757               0 :         if (poNewNode->InitNode(m_fp, 0, m_nKeyLength, 
    1758                 :                                 m_nSubTreeDepth, m_bUnique, 
    1759                 :                                 m_poBlockManagerRef, m_poParentNodeRef, 
    1760                 :                                 GetNodeBlockPtr(), m_nNextNodePtr)!= 0 ||
    1761                 :             poNewNode->SetFieldType(m_eFieldType) != 0 )
    1762                 :         {
    1763               0 :             return -1;
    1764                 :         }
    1765                 : 
    1766                 :         // We have to update m_nPrevNodePtr in the node that used to follow
    1767                 :         // the current node and will now follow the new node.
    1768               0 :         if (m_nNextNodePtr)
    1769                 :         {
    1770               0 :             TABINDNode *poTmpNode = new TABINDNode(m_eAccessMode);
    1771               0 :             if (poTmpNode->InitNode(m_fp, m_nNextNodePtr, 
    1772                 :                                     m_nKeyLength, m_nSubTreeDepth,
    1773                 :                                     m_bUnique, m_poBlockManagerRef, 
    1774                 :                                     m_poParentNodeRef) != 0 ||
    1775                 :                 poTmpNode->SetPrevNodePtr(poNewNode->GetNodeBlockPtr()) != 0 ||
    1776                 :                 poTmpNode->CommitToFile() != 0)
    1777                 :             {
    1778               0 :                 return -1;
    1779                 :             }
    1780               0 :             delete poTmpNode;
    1781                 :         }
    1782                 : 
    1783               0 :         m_nNextNodePtr = poNewNode->GetNodeBlockPtr();
    1784                 : 
    1785                 :         // Move half the entries to the new block
    1786               0 :         m_poDataBlock->GotoByteInBlock(12 + numInNode1*(m_nKeyLength+4));
    1787                 : 
    1788               0 :         if (poNewNode->SetNodeBufferDirectly(numInNode2, 
    1789                 :                                         m_poDataBlock->GetCurDataPtr()) != 0)
    1790               0 :             return -1;
    1791                 : 
    1792                 : #ifdef DEBUG
    1793                 :         // Just in case, reset space previously used by moved entries
    1794               0 :         memset(m_poDataBlock->GetCurDataPtr(), 0, numInNode2*(m_nKeyLength+4));
    1795                 : #endif
    1796                 :         // And update current node members
    1797               0 :         m_numEntriesInNode = numInNode1;
    1798                 : 
    1799                 :         // Update parent node with new children info
    1800               0 :         if (m_poParentNodeRef)
    1801                 :         {
    1802               0 :             if (m_poParentNodeRef->UpdateSplitChild(GetNodeKey(),
    1803                 :                                                     GetNodeBlockPtr(),
    1804                 :                                                     poNewNode->GetNodeKey(),
    1805                 :                                         poNewNode->GetNodeBlockPtr(), 1) != 0)
    1806               0 :                 return -1;
    1807                 :         }
    1808                 : 
    1809                 :     }
    1810                 :     else
    1811                 :     {
    1812                 :         /*-------------------------------------------------------------
    1813                 :          * We will move the first half of the array to a new node.
    1814                 :          *------------------------------------------------------------*/
    1815               0 :         if (poNewNode->InitNode(m_fp, 0, m_nKeyLength, 
    1816                 :                                 m_nSubTreeDepth, m_bUnique, 
    1817                 :                                 m_poBlockManagerRef, m_poParentNodeRef, 
    1818                 :                                 m_nPrevNodePtr, GetNodeBlockPtr())!= 0 ||
    1819                 :             poNewNode->SetFieldType(m_eFieldType) != 0 )
    1820                 :         {
    1821               0 :             return -1;
    1822                 :         }
    1823                 : 
    1824                 :         // We have to update m_nNextNodePtr in the node that used to precede
    1825                 :         // the current node and will now precede the new node.
    1826               0 :         if (m_nPrevNodePtr)
    1827                 :         {
    1828               0 :             TABINDNode *poTmpNode = new TABINDNode(m_eAccessMode);
    1829               0 :             if (poTmpNode->InitNode(m_fp, m_nPrevNodePtr, 
    1830                 :                                     m_nKeyLength, m_nSubTreeDepth,
    1831                 :                                     m_bUnique, m_poBlockManagerRef, 
    1832                 :                                     m_poParentNodeRef) != 0 ||
    1833                 :                 poTmpNode->SetNextNodePtr(poNewNode->GetNodeBlockPtr()) != 0 ||
    1834                 :                 poTmpNode->CommitToFile() != 0)
    1835                 :             {
    1836               0 :                 return -1;
    1837                 :             }
    1838               0 :             delete poTmpNode;
    1839                 :         }
    1840                 : 
    1841               0 :         m_nPrevNodePtr = poNewNode->GetNodeBlockPtr();
    1842                 : 
    1843                 :         // Move half the entries to the new block
    1844               0 :         m_poDataBlock->GotoByteInBlock(12 + 0);
    1845                 : 
    1846               0 :         if (poNewNode->SetNodeBufferDirectly(numInNode1, 
    1847                 :                                         m_poDataBlock->GetCurDataPtr()) != 0)
    1848               0 :             return -1;
    1849                 : 
    1850                 :         // Shift the second half of the entries to beginning of buffer
    1851                 :         memmove (m_poDataBlock->GetCurDataPtr(),
    1852                 :                  m_poDataBlock->GetCurDataPtr()+numInNode1*(m_nKeyLength+4),
    1853               0 :                  numInNode2*(m_nKeyLength+4));
    1854                 : 
    1855                 : #ifdef DEBUG
    1856                 :         // Just in case, reset space previously used by moved entries
    1857                 :         memset(m_poDataBlock->GetCurDataPtr()+numInNode2*(m_nKeyLength+4),
    1858               0 :                0, numInNode1*(m_nKeyLength+4));
    1859                 : #endif
    1860                 : 
    1861                 :         // And update current node members
    1862               0 :         m_numEntriesInNode = numInNode2;
    1863               0 :         m_nCurIndexEntry -= numInNode1;
    1864                 : 
    1865                 :         // Update parent node with new children info
    1866               0 :         if (m_poParentNodeRef)
    1867                 :         {
    1868               0 :             if (m_poParentNodeRef->UpdateSplitChild(poNewNode->GetNodeKey(),
    1869                 :                                                   poNewNode->GetNodeBlockPtr(),
    1870                 :                                                     GetNodeKey(),
    1871                 :                                                     GetNodeBlockPtr(), 2) != 0)
    1872               0 :                 return -1;
    1873                 :         }
    1874                 : 
    1875                 :     }
    1876                 : 
    1877                 :     /*-----------------------------------------------------------------
    1878                 :      * Update current node header
    1879                 :      *----------------------------------------------------------------*/
    1880               0 :     m_poDataBlock->GotoByteInBlock(0);
    1881               0 :     m_poDataBlock->WriteInt32(m_numEntriesInNode);
    1882               0 :     m_poDataBlock->WriteInt32(m_nPrevNodePtr);
    1883               0 :     m_poDataBlock->WriteInt32(m_nNextNodePtr);
    1884                 : 
    1885                 :     /*-----------------------------------------------------------------
    1886                 :      * Flush and destroy temporary node
    1887                 :      *----------------------------------------------------------------*/
    1888               0 :     if (poNewNode->CommitToFile() != 0)
    1889               0 :         return -1;
    1890                 : 
    1891               0 :     delete poNewNode;
    1892                 : 
    1893               0 :     return 0;
    1894                 : }
    1895                 : 
    1896                 : /**********************************************************************
    1897                 :  *                   TABINDNode::SplitRootNode()
    1898                 :  *
    1899                 :  * (private method)
    1900                 :  *
    1901                 :  * Split a Root Node.
    1902                 :  * First, a level of nodes must be added to the tree, then the contents
    1903                 :  * of what used to be the root node is moved 1 level down and then that
    1904                 :  * node is split like a regular node.
    1905                 :  *
    1906                 :  * Returns 0 on success, -1 on error
    1907                 :  **********************************************************************/
    1908               0 : int TABINDNode::SplitRootNode()
    1909                 : {
    1910                 :     /*-----------------------------------------------------------------
    1911                 :      * Since a root note cannot be split, we add a level of nodes
    1912                 :      * under it and we'll do the split at that level.
    1913                 :      *----------------------------------------------------------------*/
    1914               0 :     TABINDNode *poNewNode = new TABINDNode(m_eAccessMode);
    1915                 : 
    1916               0 :     if (poNewNode->InitNode(m_fp, 0, m_nKeyLength, 
    1917                 :                             m_nSubTreeDepth, m_bUnique, m_poBlockManagerRef, 
    1918                 :                             this, 0, 0)!= 0 ||
    1919                 :         poNewNode->SetFieldType(m_eFieldType) != 0)
    1920                 :     {
    1921               0 :         return -1;
    1922                 :     }
    1923                 : 
    1924                 :     // Move all entries to the new child
    1925               0 :     m_poDataBlock->GotoByteInBlock(12 + 0);
    1926               0 :     if (poNewNode->SetNodeBufferDirectly(m_numEntriesInNode, 
    1927                 :                                          m_poDataBlock->GetCurDataPtr(),
    1928                 :                                          m_nCurIndexEntry,
    1929                 :                                          m_poCurChildNode) != 0)
    1930                 :     {
    1931               0 :         return -1;
    1932                 :     }
    1933                 : 
    1934                 : #ifdef DEBUG
    1935                 :     // Just in case, reset space previously used by moved entries
    1936                 :     memset(m_poDataBlock->GetCurDataPtr(), 0,
    1937               0 :            m_numEntriesInNode*(m_nKeyLength+4));
    1938                 : #endif
    1939                 : 
    1940                 :     /*-----------------------------------------------------------------
    1941                 :      * Rewrite current node. (the new root node)
    1942                 :      *----------------------------------------------------------------*/
    1943               0 :     m_numEntriesInNode = 0;
    1944               0 :     m_nSubTreeDepth++;
    1945                 : 
    1946               0 :     m_poDataBlock->GotoByteInBlock(0);
    1947               0 :     m_poDataBlock->WriteInt32(m_numEntriesInNode);
    1948                 : 
    1949               0 :     InsertEntry(poNewNode->GetNodeKey(), poNewNode->GetNodeBlockPtr());
    1950                 : 
    1951                 :     /*-----------------------------------------------------------------
    1952                 :      * Keep a reference to the new child
    1953                 :      *----------------------------------------------------------------*/
    1954               0 :     m_poCurChildNode = poNewNode;
    1955               0 :     m_nCurIndexEntry = 0;
    1956                 : 
    1957                 :     /*-----------------------------------------------------------------
    1958                 :      * And finally force the child to split itself
    1959                 :      *----------------------------------------------------------------*/
    1960               0 :     return m_poCurChildNode->SplitNode();
    1961                 : }
    1962                 : 
    1963                 : /**********************************************************************
    1964                 :  *                   TABINDNode::SetNodeBufferDirectly()
    1965                 :  *
    1966                 :  * (private method)
    1967                 :  *
    1968                 :  * Set the key/value part of the nodes buffer and the pointers to the
    1969                 :  * current child direclty.  This is used when copying info to a new node
    1970                 :  * in SplitNode() and SplitRootNode()
    1971                 :  *
    1972                 :  * Returns 0 on success, -1 on error
    1973                 :  **********************************************************************/
    1974                 : int TABINDNode::SetNodeBufferDirectly(int numEntries, GByte *pBuf,
    1975                 :                                       int nCurIndexEntry/*=0*/, 
    1976               0 :                                       TABINDNode *poCurChild/*=NULL*/)
    1977                 : {
    1978               0 :     m_poDataBlock->GotoByteInBlock(0);
    1979               0 :     m_poDataBlock->WriteInt32(numEntries);
    1980                 : 
    1981               0 :     m_numEntriesInNode = numEntries;
    1982                 : 
    1983               0 :     m_poDataBlock->GotoByteInBlock(12);
    1984               0 :     if ( m_poDataBlock->WriteBytes(numEntries*(m_nKeyLength+4), pBuf) != 0)
    1985                 :     {
    1986               0 :         return -1; // An error msg should have been reported already
    1987                 :     }
    1988                 : 
    1989               0 :     m_nCurIndexEntry = nCurIndexEntry;
    1990               0 :     m_poCurChildNode = poCurChild;
    1991               0 :     if (m_poCurChildNode)
    1992               0 :         m_poCurChildNode->m_poParentNodeRef = this;
    1993                 : 
    1994               0 :     return 0;
    1995                 : }
    1996                 : 
    1997                 : /**********************************************************************
    1998                 :  *                   TABINDNode::GetNodeKey()
    1999                 :  *
    2000                 :  * Returns a reference to the key for the first entry in the node, which
    2001                 :  * is also the key for this node at the level above it in the tree.
    2002                 :  *
    2003                 :  * Returns NULL if node is empty.
    2004                 :  **********************************************************************/
    2005               0 : GByte* TABINDNode::GetNodeKey()
    2006                 : {
    2007               0 :     if (m_poDataBlock == NULL || m_numEntriesInNode == 0)
    2008               0 :         return NULL;
    2009                 : 
    2010               0 :     m_poDataBlock->GotoByteInBlock(12);
    2011                 : 
    2012               0 :     return m_poDataBlock->GetCurDataPtr();
    2013                 : }
    2014                 : 
    2015                 : /**********************************************************************
    2016                 :  *                   TABINDNode::SetPrevNodePtr()
    2017                 :  *
    2018                 :  * Update the m_nPrevNodePtr member.
    2019                 :  *
    2020                 :  * Returns 0 on success, -1 on error.
    2021                 :  **********************************************************************/
    2022               0 : int TABINDNode::SetPrevNodePtr(GInt32 nPrevNodePtr)
    2023                 : {
    2024               0 :     if ((m_eAccessMode != TABWrite && m_eAccessMode != TABReadWrite) ||
    2025                 :         m_poDataBlock == NULL)
    2026               0 :         return -1;
    2027                 : 
    2028               0 :     if (m_nPrevNodePtr == nPrevNodePtr)
    2029               0 :         return 0;  // Nothing to do.
    2030                 : 
    2031               0 :     m_poDataBlock->GotoByteInBlock(4);
    2032               0 :     return m_poDataBlock->WriteInt32(nPrevNodePtr);
    2033                 : }
    2034                 : 
    2035                 : /**********************************************************************
    2036                 :  *                   TABINDNode::SetNextNodePtr()
    2037                 :  *
    2038                 :  * Update the m_nNextNodePtr member.
    2039                 :  *
    2040                 :  * Returns 0 on success, -1 on error.
    2041                 :  **********************************************************************/
    2042               0 : int TABINDNode::SetNextNodePtr(GInt32 nNextNodePtr)
    2043                 : {
    2044               0 :     if ((m_eAccessMode != TABWrite && m_eAccessMode != TABReadWrite) ||
    2045                 :         m_poDataBlock == NULL)
    2046               0 :         return -1;
    2047                 : 
    2048               0 :     if (m_nNextNodePtr == nNextNodePtr)
    2049               0 :         return 0;  // Nothing to do.
    2050                 : 
    2051               0 :     m_poDataBlock->GotoByteInBlock(8);
    2052               0 :     return m_poDataBlock->WriteInt32(nNextNodePtr);
    2053                 : }
    2054                 : 
    2055                 : 
    2056                 : 
    2057                 : /**********************************************************************
    2058                 :  *                   TABINDNode::Dump()
    2059                 :  *
    2060                 :  * Dump block contents... available only in DEBUG mode.
    2061                 :  **********************************************************************/
    2062                 : #ifdef DEBUG
    2063                 : 
    2064               0 : void TABINDNode::Dump(FILE *fpOut /*=NULL*/)
    2065                 : {
    2066               0 :     if (fpOut == NULL)
    2067               0 :         fpOut = stdout;
    2068                 : 
    2069               0 :     fprintf(fpOut, "----- TABINDNode::Dump() -----\n");
    2070                 : 
    2071               0 :     if (m_fp == NULL)
    2072                 :     {
    2073               0 :         fprintf(fpOut, "Node is not initialized.\n");
    2074                 :     }
    2075                 :     else
    2076                 :     {
    2077               0 :         fprintf(fpOut, "   m_numEntriesInNode   = %d\n", m_numEntriesInNode);
    2078               0 :         fprintf(fpOut, "   m_nCurDataBlockPtr   = %d\n", m_nCurDataBlockPtr);
    2079               0 :         fprintf(fpOut, "   m_nPrevNodePtr       = %d\n", m_nPrevNodePtr);
    2080               0 :         fprintf(fpOut, "   m_nNextNodePtr       = %d\n", m_nNextNodePtr);
    2081               0 :         fprintf(fpOut, "   m_nSubTreeDepth      = %d\n", m_nSubTreeDepth);
    2082               0 :         fprintf(fpOut, "   m_nKeyLength         = %d\n", m_nKeyLength);
    2083                 :         fprintf(fpOut, "   m_eFieldtype         = %s\n", 
    2084               0 :                                         TABFIELDTYPE_2_STRING(m_eFieldType) );
    2085               0 :         if (m_nSubTreeDepth > 0)
    2086                 :         {
    2087                 :             GByte  aKeyValBuf[255];
    2088                 :             GInt32 nRecordPtr, nValue;
    2089               0 :             TABINDNode oChildNode;
    2090                 : 
    2091               0 :             if (m_nKeyLength > 254)
    2092                 :             {
    2093                 :                 CPLError(CE_Failure, CPLE_NotSupported,
    2094               0 :                          "Dump() cannot handle keys longer than 254 chars.");
    2095               0 :                 return;
    2096                 :             }
    2097                 : 
    2098               0 :             fprintf(fpOut, "\n");
    2099               0 :             for (int i=0; i<m_numEntriesInNode; i++)
    2100                 :             {
    2101               0 :               if (m_nSubTreeDepth > 1)
    2102                 :               {
    2103                 :                 fprintf(fpOut, "   >>>> Child %d of %d <<<<<\n", i, 
    2104               0 :                                                          m_numEntriesInNode);
    2105                 :               }
    2106                 :               else
    2107                 :               {
    2108                 :                 fprintf(fpOut, "   >>>> Record (leaf) %d of %d <<<<<\n", i, 
    2109               0 :                                                          m_numEntriesInNode);
    2110                 :               }
    2111                 : 
    2112               0 :               if (m_eFieldType == TABFChar)
    2113                 :               {
    2114               0 :                   nRecordPtr = ReadIndexEntry(i, aKeyValBuf);
    2115               0 :                   fprintf(fpOut, "   nRecordPtr = %d\n", nRecordPtr);
    2116               0 :                   fprintf(fpOut, "   Char Val= \"%s\"\n", (char*)aKeyValBuf);
    2117                 :               }
    2118               0 :               else if (m_nKeyLength != 4)
    2119                 :               {
    2120               0 :                 nRecordPtr = ReadIndexEntry(i, aKeyValBuf);
    2121               0 :                 fprintf(fpOut, "   nRecordPtr = %d\n", nRecordPtr);
    2122               0 :                 fprintf(fpOut, "   Int Value = %d\n", *(GInt32*)aKeyValBuf);
    2123               0 :                 fprintf(fpOut, "   Int16 Val= %d\n",*(GInt16*)(aKeyValBuf+2));
    2124               0 :                 fprintf(fpOut, "   Hex Val= 0x%8.8x\n",*(GUInt32*)aKeyValBuf);
    2125                 :               }
    2126                 :               else
    2127                 :               {
    2128               0 :                 nRecordPtr = ReadIndexEntry(i, (GByte*)&nValue);
    2129               0 :                 fprintf(fpOut, "   nRecordPtr = %d\n", nRecordPtr);
    2130               0 :                 fprintf(fpOut, "   Int Value = %d\n", nValue);
    2131               0 :                 fprintf(fpOut, "   Hex Value = 0x%8.8x\n",nValue);
    2132                 :               }
    2133                 : 
    2134               0 :               if (m_nSubTreeDepth > 1)
    2135                 :               {
    2136                 :                 oChildNode.InitNode(m_fp, nRecordPtr, m_nKeyLength, 
    2137               0 :                                     m_nSubTreeDepth - 1, FALSE);
    2138               0 :                 oChildNode.SetFieldType(m_eFieldType);
    2139               0 :                 oChildNode.Dump(fpOut);
    2140                 :               }
    2141               0 :             }
    2142                 :         }
    2143                 :     }
    2144                 : 
    2145               0 :     fflush(fpOut);
    2146                 : }
    2147                 : 
    2148                 : #endif // DEBUG

Generated by: LTP GCOV extension version 1.5