avce00-2.0.0/0040775000076400007640000000000010471150033012051 5ustar danieldanielavce00-2.0.0/avc_e00read.c0100664000076400007640000024423410471144245014304 0ustar danieldaniel/********************************************************************** * $Id: avc_e00read.c,v 1.23 2006/08/17 19:51:01 dmorissette Exp $ * * Name: avc_e00read.c * Project: Arc/Info vector coverage (AVC) BIN->E00 conversion library * Language: ANSI C * Purpose: Functions to open a binary coverage and read it as if it * was an ASCII E00 file. This file is the main entry point * for the library. * Author: Daniel Morissette, dmorissette@dmsolutions.ca * ********************************************************************** * Copyright (c) 1999-2005, Daniel Morissette * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ********************************************************************** * * $Log: avc_e00read.c,v $ * Revision 1.23 2006/08/17 19:51:01 dmorissette * #include to solve warning on 64 bit platforms (bug 1461) * * Revision 1.22 2006/08/17 18:56:42 dmorissette * Support for reading standalone info tables (just tables, no coverage * data) by pointing AVCE00ReadOpen() to the info directory (bug 1549). * * Revision 1.21 2006/06/27 18:38:43 dmorissette * Cleaned up E00 reading (bug 1497, patch from James F.) * * Revision 1.20 2006/06/27 18:06:34 dmorissette * Applied patch for EOP processing from James F. (bug 1497) * * Revision 1.19 2006/06/16 11:48:11 daniel * New functions to read E00 files directly as opposed to translating to * binary coverage. Used in the implementation of E00 read support in OGR. * Contributed by James E. Flemer. (bug 1497) * * Revision 1.18 2006/06/14 16:31:28 daniel * Added support for AVCCoverPC2 type (bug 1491) * * Revision 1.17 2005/06/03 03:49:58 daniel * Update email address, website url, and copyright dates * * Revision 1.16 2004/07/14 18:49:50 daniel * Fixed leak when trying to open something that's not a coverage (bug513) * * Revision 1.15 2002/08/27 15:46:15 daniel * Applied fix made in GDAL/OGR by 'aubin' (moved include ctype.h after avc.h) * * Revision 1.14 2000/09/22 19:45:21 daniel * Switch to MIT-style license * * Revision 1.13 2000/05/29 15:31:31 daniel * Added Japanese DBCS support * * Revision 1.12 2000/02/14 17:21:01 daniel * Made more robust for corrupted or invalid files in cover directory * * Revision 1.11 2000/02/02 04:26:04 daniel * Support reading TX6/TX7/RXP/RPL files in weird coverages * * Revision 1.10 2000/01/10 02:56:30 daniel * Added read support for "weird" coverages * * Revision 1.9 2000/01/07 07:12:49 daniel * Added support for reading PC Coverage TXT files * * Revision 1.8 1999/12/24 07:41:08 daniel * Check fname length before testing for extension in AVCE00ReadFindCoverType() * * Revision 1.7 1999/12/24 07:18:34 daniel * Added PC Arc/Info coverages support * * Revision 1.6 1999/08/26 17:22:18 daniel * Use VSIFopen() instead of fopen() directly * * Revision 1.5 1999/08/23 18:21:41 daniel * New syntax for AVCBinReadListTables() * * Revision 1.4 1999/05/11 02:10:01 daniel * Free psInfo struct inside AVCE00ReadClose() * * Revision 1.3 1999/04/06 19:43:26 daniel * Added E00 coverage path in EXP 0 header line * * Revision 1.2 1999/02/25 04:19:01 daniel * Added TXT, TX6/TX7, RXP and RPL support + other minor changes * * Revision 1.1 1999/01/29 16:28:52 daniel * Initial revision * **********************************************************************/ #ifdef WIN32 # include /* getcwd() */ #else # include /* getcwd() */ #endif #include "avc.h" #include /* toupper() */ static void _AVCE00ReadScanE00(AVCE00ReadE00Ptr psRead); static int _AVCE00ReadBuildSqueleton(AVCE00ReadPtr psInfo, char **papszCoverDir); static AVCCoverType _AVCE00ReadFindCoverType(char **papszCoverDir); /********************************************************************** * AVCE00ReadOpen() * * Open a Arc/Info coverage to read it as if it was an E00 file. * * You can either pass the name of the coverage directory, or the path * to one of the files in the coverage directory. The name of the * coverage MUST be included in pszCoverPath... this means that * passing "." is invalid. * The following are all valid values for pszCoverPath: * /home/data/country * /home/data/country/ * /home/data/country/arc.adf * (Of course you should replace the '/' with '\\' on DOS systems!) * * Returns a new AVCE00ReadPtr handle or NULL if the coverage could * not be opened or if it does not appear to be a valid Arc/Info coverage. * * The handle will eventually have to be released with AVCE00ReadClose(). **********************************************************************/ AVCE00ReadPtr AVCE00ReadOpen(const char *pszCoverPath) { AVCE00ReadPtr psInfo; int i, nLen, nCoverPrecision; VSIStatBuf sStatBuf; char **papszCoverDir = NULL; CPLErrorReset(); /*----------------------------------------------------------------- * pszCoverPath must be either a valid directory name or a valid * file name. *----------------------------------------------------------------*/ if (pszCoverPath == NULL || strlen(pszCoverPath) == 0 || VSIStat(pszCoverPath, &sStatBuf) == -1) { CPLError(CE_Failure, CPLE_OpenFailed, "Invalid coverage path: %s.", pszCoverPath?pszCoverPath:"(NULL)"); return NULL; } /*----------------------------------------------------------------- * Alloc the AVCE00ReadPtr handle *----------------------------------------------------------------*/ psInfo = (AVCE00ReadPtr)CPLCalloc(1, sizeof(struct AVCE00ReadInfo_t)); /*----------------------------------------------------------------- * 2 possibilities about the value passed in pszCoverPath: * - It can be the directory name of the coverage * - or it can be the path to one of the files in the coverage * * If the name passed in pszCoverPath is not a directory, then we * need to strip the last part of the filename to keep only the * path, terminated by a '/' (or a '\\'). *----------------------------------------------------------------*/ if (VSI_ISDIR(sStatBuf.st_mode)) { /*------------------------------------------------------------- * OK, we have a valid directory name... make sure it is * terminated with a '/' (or '\\') *------------------------------------------------------------*/ nLen = strlen(pszCoverPath); if (pszCoverPath[nLen-1] == '/' || pszCoverPath[nLen-1] == '\\') psInfo->pszCoverPath = CPLStrdup(pszCoverPath); else { #ifdef WIN32 psInfo->pszCoverPath = CPLStrdup(CPLSPrintf("%s\\",pszCoverPath)); #else psInfo->pszCoverPath = CPLStrdup(CPLSPrintf("%s/",pszCoverPath)); #endif } } else { /*------------------------------------------------------------- * We are dealing with a filename. * Extract the coverage path component and store it. * The coverage path will remain terminated by a '/' or '\\' char. *------------------------------------------------------------*/ psInfo->pszCoverPath = CPLStrdup(pszCoverPath); for( i = strlen(psInfo->pszCoverPath)-1; i > 0 && psInfo->pszCoverPath[i] != '/' && psInfo->pszCoverPath[i] != '\\'; i-- ) {} psInfo->pszCoverPath[i+1] = '\0'; } /*----------------------------------------------------------------- * Extract the coverage name from the coverage path. Note that * for this the coverage path must be in the form: * "dir1/dir2/dir3/covername/" ... if it is not the case, then * we would have to use getcwd() to find the current directory name... * but for now we'll just produce an error if this happens. *----------------------------------------------------------------*/ nLen = 0; for( i = strlen(psInfo->pszCoverPath)-1; i > 0 && psInfo->pszCoverPath[i-1] != '/' && psInfo->pszCoverPath[i-1] != '\\'&& psInfo->pszCoverPath[i-1] != ':'; i-- ) { nLen++; } if (nLen > 0) { psInfo->pszCoverName = CPLStrdup(psInfo->pszCoverPath+i); psInfo->pszCoverName[nLen] = '\0'; } else { CPLError(CE_Failure, CPLE_OpenFailed, "Invalid coverage path (%s): " "coverage name must be included in path.", pszCoverPath); CPLFree(psInfo->pszCoverPath); CPLFree(psInfo); return NULL; } /*----------------------------------------------------------------- * Read the coverage directory listing and try to establish the cover type *----------------------------------------------------------------*/ papszCoverDir = CPLReadDir(psInfo->pszCoverPath); psInfo->eCoverType = _AVCE00ReadFindCoverType(papszCoverDir); if (psInfo->eCoverType == AVCCoverTypeUnknown ) { CPLError(CE_Failure, CPLE_OpenFailed, "Invalid coverage (%s): directory does not appear to " "contain any supported vector coverage file.", pszCoverPath); CPLFree(psInfo->pszCoverName); CPLFree(psInfo->pszCoverPath); CPLFree(psInfo->pszInfoPath); CPLFree(psInfo); CSLDestroy(papszCoverDir); return NULL; } /*----------------------------------------------------------------- * INFO path: PC Coverages have all files in the same dir, and unix * covers have the INFO files in ../info *----------------------------------------------------------------*/ if (psInfo->eCoverType == AVCCoverPC || psInfo->eCoverType == AVCCoverPC2) { psInfo->pszInfoPath = CPLStrdup(psInfo->pszCoverPath); } else { /*------------------------------------------------------------- * Lazy way to build the INFO path: simply add "../info/"... * this could probably be improved! *------------------------------------------------------------*/ psInfo->pszInfoPath =(char*)CPLMalloc((strlen(psInfo->pszCoverPath)+9)* sizeof(char)); #ifdef WIN32 # define AVC_INFOPATH "..\\info\\" #else # define AVC_INFOPATH "../info/" #endif sprintf(psInfo->pszInfoPath, "%s%s", psInfo->pszCoverPath, AVC_INFOPATH); AVCAdjustCaseSensitiveFilename(psInfo->pszInfoPath); } /*----------------------------------------------------------------- * For Unix coverages, check that the info directory exists and * contains the "arc.dir". In AVCCoverWeird, the arc.dir is * called "../INFO/ARCDR9". * PC Coverages have their info tables in the same direcotry as * the coverage files. *----------------------------------------------------------------*/ if (((psInfo->eCoverType == AVCCoverV7 || psInfo->eCoverType == AVCCoverV7Tables) && ! AVCFileExists(psInfo->pszInfoPath, "arc.dir") ) || (psInfo->eCoverType == AVCCoverWeird && ! AVCFileExists(psInfo->pszInfoPath, "arcdr9") ) ) { CPLError(CE_Failure, CPLE_OpenFailed, "Invalid coverage (%s): 'info' directory not found or invalid.", pszCoverPath); CPLFree(psInfo->pszCoverName); CPLFree(psInfo->pszCoverPath); CPLFree(psInfo->pszInfoPath); CPLFree(psInfo); CSLDestroy(papszCoverDir); return NULL; } /*----------------------------------------------------------------- * Make sure there was no error until now before we build squeleton. *----------------------------------------------------------------*/ if (CPLGetLastErrorNo() != 0) { CPLFree(psInfo->pszCoverName); CPLFree(psInfo->pszCoverPath); CPLFree(psInfo->pszInfoPath); CPLFree(psInfo); CSLDestroy(papszCoverDir); return NULL; } /*----------------------------------------------------------------- * Build the E00 file squeleton and be ready to return a E00 header... * We'll also read the coverage precision by the same way. *----------------------------------------------------------------*/ nCoverPrecision = _AVCE00ReadBuildSqueleton(psInfo, papszCoverDir); /* Ignore warnings produced while building squeleton */ CPLErrorReset(); CSLDestroy(papszCoverDir); papszCoverDir = NULL; psInfo->iCurSection = 0; psInfo->iCurStep = AVC_GEN_NOTSTARTED; psInfo->bReadAllSections = TRUE; /*----------------------------------------------------------------- * Init the E00 generator. *----------------------------------------------------------------*/ psInfo->hGenInfo = AVCE00GenInfoAlloc(nCoverPrecision); /*----------------------------------------------------------------- * Init multibyte encoding info *----------------------------------------------------------------*/ psInfo->psDBCSInfo = AVCAllocDBCSInfo(); /*----------------------------------------------------------------- * If an error happened during the open call, cleanup and return NULL. *----------------------------------------------------------------*/ if (CPLGetLastErrorNo() != 0) { AVCE00ReadClose(psInfo); psInfo = NULL; } return psInfo; } /********************************************************************** * AVCE00ReadOpenE00() * * Open a E00 file for reading. * * Returns a new AVCE00ReadE00Ptr handle or NULL if the file could * not be opened or if it does not appear to be a valid E00 file. * * The handle will eventually have to be released with * AVCE00ReadCloseE00(). **********************************************************************/ AVCE00ReadE00Ptr AVCE00ReadOpenE00(const char *pszE00FileName) { AVCE00ReadE00Ptr psRead; VSIStatBuf sStatBuf; FILE *fp; char *p; CPLErrorReset(); /*----------------------------------------------------------------- * pszE00FileName must be a valid file that can be opened for * reading *----------------------------------------------------------------*/ if (pszE00FileName == NULL || strlen(pszE00FileName) == 0 || VSIStat(pszE00FileName, &sStatBuf) == -1 || VSI_ISDIR(sStatBuf.st_mode)) { CPLError(CE_Failure, CPLE_OpenFailed, "Invalid E00 file path: %s.", pszE00FileName?pszE00FileName:"(NULL)"); return NULL; } if (NULL == (fp = fopen(pszE00FileName, "r"))) return NULL; /*----------------------------------------------------------------- * Alloc the AVCE00ReadE00Ptr handle *----------------------------------------------------------------*/ psRead = (AVCE00ReadE00Ptr)CPLCalloc(1, sizeof(struct AVCE00ReadInfoE00_t)); psRead->hFile = fp; psRead->pszCoverPath = CPLStrdup(pszE00FileName); psRead->eCurFileType = AVCFileUnknown; /*----------------------------------------------------------------- * Extract the coverage name from the coverage path. *----------------------------------------------------------------*/ if (NULL != (p = strrchr(psRead->pszCoverPath, '/')) || NULL != (p = strrchr(psRead->pszCoverPath, '\\')) || NULL != (p = strrchr(psRead->pszCoverPath, ':'))) { psRead->pszCoverName = CPLStrdup(p + 1); } else { psRead->pszCoverName = CPLStrdup(psRead->pszCoverPath); } if (NULL != (p = strrchr(psRead->pszCoverName, '.'))) { *p = '\0'; } /*----------------------------------------------------------------- * Make sure there was no error until now before we scan file. *----------------------------------------------------------------*/ if (CPLGetLastErrorNo() != 0) { AVCE00ReadCloseE00(psRead); return NULL; } psRead->hParseInfo = AVCE00ParseInfoAlloc(); /*----------------------------------------------------------------- * Scan the E00 file for sections *----------------------------------------------------------------*/ _AVCE00ReadScanE00(psRead); AVCE00ReadRewindE00(psRead); CPLErrorReset(); if (psRead->numSections < 1) { AVCE00ReadCloseE00(psRead); return NULL; } psRead->bReadAllSections = TRUE; /*----------------------------------------------------------------- * If an error happened during the open call, cleanup and return NULL. *----------------------------------------------------------------*/ if (CPLGetLastErrorNo() != 0) { AVCE00ReadCloseE00(psRead); psRead = NULL; } return psRead; } /********************************************************************** * AVCE00ReadClose() * * Close a coverage and release all memory used by the AVCE00ReadPtr * handle. **********************************************************************/ void AVCE00ReadClose(AVCE00ReadPtr psInfo) { CPLErrorReset(); if (psInfo == NULL) return; CPLFree(psInfo->pszCoverPath); CPLFree(psInfo->pszInfoPath); CPLFree(psInfo->pszCoverName); if (psInfo->hFile) AVCBinReadClose(psInfo->hFile); if (psInfo->hGenInfo) AVCE00GenInfoFree(psInfo->hGenInfo); if (psInfo->pasSections) { int i; for(i=0; inumSections; i++) { CPLFree(psInfo->pasSections[i].pszName); CPLFree(psInfo->pasSections[i].pszFilename); } CPLFree(psInfo->pasSections); } AVCFreeDBCSInfo(psInfo->psDBCSInfo); CPLFree(psInfo); } /********************************************************************** * AVCE00ReadCloseE00() * * Close a coverage and release all memory used by the AVCE00ReadE00Ptr * handle. **********************************************************************/ void AVCE00ReadCloseE00(AVCE00ReadE00Ptr psRead) { CPLErrorReset(); if (psRead == NULL) return; CPLFree(psRead->pszCoverPath); CPLFree(psRead->pszCoverName); if (psRead->hFile) { fclose(psRead->hFile); psRead->hFile = 0; } if (psRead->pasSections) { int i; for(i=0; inumSections; i++) { CPLFree(psRead->pasSections[i].pszName); CPLFree(psRead->pasSections[i].pszFilename); } CPLFree(psRead->pasSections); } /* These Free calls handle NULL's */ AVCE00ParseInfoFree(psRead->hParseInfo); psRead->hParseInfo = NULL; CPLFree(psRead); } /********************************************************************** * _AVCIncreaseSectionsArray() * * Add a number of structures to the Sections array and return the * index of the first one that was added. Note that the address of the * original array (*pasArray) is quite likely to change! * * The value of *pnumItems will be updated to reflect the new array size. **********************************************************************/ static int _AVCIncreaseSectionsArray(AVCE00Section **pasArray, int *pnumItems, int numToAdd) { int i; *pasArray = (AVCE00Section*)CPLRealloc(*pasArray, (*pnumItems+numToAdd)* sizeof(AVCE00Section)); for(i=0; i 4 && EQUAL(papszCoverDir[i]+nLen-4, ".adf") ) { bFoundAdfFile = TRUE; } else if (nLen > 4 && EQUAL(papszCoverDir[i]+nLen-4, ".dbf") ) { bFoundDbfFile = TRUE; } else if (EQUAL(papszCoverDir[i], "arc") || EQUAL(papszCoverDir[i], "cnt") || EQUAL(papszCoverDir[i], "pal") || EQUAL(papszCoverDir[i], "lab") || EQUAL(papszCoverDir[i], "prj") || EQUAL(papszCoverDir[i], "tol") ) { bFoundArcFile = TRUE; } else if (EQUAL(papszCoverDir[i], "aat") || EQUAL(papszCoverDir[i], "pat") || EQUAL(papszCoverDir[i], "bnd") || EQUAL(papszCoverDir[i], "tic") ) { bFoundTableFile = TRUE; } else if (EQUAL(papszCoverDir[i], "arc.dir") ) { bFoundArcDirFile = TRUE; } } /*----------------------------------------------------------------- * Check for PC Arc/Info coverage - variant 1. * These PC coverages have files with no extension (e.g. "ARC","PAL",...) * and their tables filenames are in the form "???.dbf" *----------------------------------------------------------------*/ if (bFoundArcFile && bFoundDbfFile) return AVCCoverPC; /*----------------------------------------------------------------- * Check for PC Arc/Info coverage - variant 2. * looks like a hybrid between AVCCoverPC and AVCCoverV7 * These PC coverages have files with .adf extension (e.g."ARC.ADF"), * and their tables filenames are in the form "???.dbf" *----------------------------------------------------------------*/ if (bFoundAdfFile && bFoundDbfFile) return AVCCoverPC2; /*----------------------------------------------------------------- * Check for the weird coverages. * Their coverage files have no extension just like PC Coverages, * and their tables have 3 letters filenames with no extension * either (e.g. "AAT", "PAT", etc.) * They also have a ../info directory, but we don't really need * to check that (not yet!). *----------------------------------------------------------------*/ if (bFoundArcFile && bFoundTableFile) return AVCCoverWeird; /*----------------------------------------------------------------- * V7 Coverages... they are the easiest to recognize * because of the ".adf" file extension *----------------------------------------------------------------*/ if (bFoundAdfFile) return AVCCoverV7; /*----------------------------------------------------------------- * Standalone info tables. * We were pointed at the "info" directory. We'll treat this as * a coverage with just info tables. *----------------------------------------------------------------*/ if (bFoundArcDirFile) return AVCCoverV7Tables; return AVCCoverTypeUnknown; } /********************************************************************** * _AVCE00ReadAddJabberwockySection() * * Add to the squeleton a section that contains subsections * for all the files with a given extension. * * Returns Updated Coverage precision **********************************************************************/ static int _AVCE00ReadAddJabberwockySection(AVCE00ReadPtr psInfo, AVCFileType eFileType, const char *pszSectionName, int nCoverPrecision, const char *pszFileExtension, char **papszCoverDir ) { int iSect, iDirEntry, nLen, nExtLen; GBool bFoundFiles = FALSE; AVCBinFile *psFile=NULL; nExtLen = strlen(pszFileExtension); /*----------------------------------------------------------------- * Scan the directory for files with a ".txt" extension. *----------------------------------------------------------------*/ for (iDirEntry=0; papszCoverDir && papszCoverDir[iDirEntry]; iDirEntry++) { nLen = strlen(papszCoverDir[iDirEntry]); if (nLen > nExtLen && EQUAL(papszCoverDir[iDirEntry] + nLen-nExtLen, pszFileExtension) && (psFile = AVCBinReadOpen(psInfo->pszCoverPath, papszCoverDir[iDirEntry], psInfo->eCoverType, eFileType, psInfo->psDBCSInfo)) != NULL) { if (nCoverPrecision == AVC_DEFAULT_PREC) nCoverPrecision = psFile->nPrecision; AVCBinReadClose(psFile); if (bFoundFiles == FALSE) { /* Insert a "TX6 #" header before the first TX6 file */ iSect = _AVCIncreaseSectionsArray(&(psInfo->pasSections), &(psInfo->numSections), 1); psInfo->pasSections[iSect].eType = AVCFileUnknown; psInfo->pasSections[iSect].pszName = CPLStrdup(CPLSPrintf("%s %c", pszSectionName, (nCoverPrecision==AVC_DOUBLE_PREC)?'3':'2')); bFoundFiles = TRUE; } /* Add this file to the squeleton */ iSect = _AVCIncreaseSectionsArray(&(psInfo->pasSections), &(psInfo->numSections), 1); psInfo->pasSections[iSect].eType = eFileType; psInfo->pasSections[iSect].pszFilename= CPLStrdup(papszCoverDir[iDirEntry]); /* pszName will contain only the classname without the file * extension */ psInfo->pasSections[iSect].pszName = CPLStrdup(papszCoverDir[iDirEntry]); psInfo->pasSections[iSect].pszName[nLen-nExtLen] = '\0'; } } if (bFoundFiles) { /* Add a line to close the TX6 section. */ iSect = _AVCIncreaseSectionsArray(&(psInfo->pasSections), &(psInfo->numSections), 1); psInfo->pasSections[iSect].eType = AVCFileUnknown; psInfo->pasSections[iSect].pszName = CPLStrdup("JABBERWOCKY"); } return nCoverPrecision; } /********************************************************************** * _AVCE00ReadNextLineE00() * * Processes the next line of input from the E00 file. * (See AVCE00WriteNextLine() for similar processing.) * * Returns the next object from the E00 file, or NULL. **********************************************************************/ static void *_AVCE00ReadNextLineE00(AVCE00ReadE00Ptr psRead, const char *pszLine) { int nStatus = 0; void *psObj = 0; AVCE00ParseInfo *psInfo = psRead->hParseInfo; CPLErrorReset(); ++psInfo->nCurLineNum; if (psInfo->bForceEndOfSection) { /*------------------------------------------------------------- * The last call encountered an implicit end of section, so * we close the section now without waiting for an end-of-section * line (there won't be any!)... and get ready to proceed with * the next section. * This is used for TABLEs. *------------------------------------------------------------*/ AVCE00ParseSectionEnd(psInfo, pszLine, TRUE); psRead->eCurFileType = AVCFileUnknown; } /*----------------------------------------------------------------- * If we're at the top level inside a supersection... check if this * supersection ends here. *----------------------------------------------------------------*/ if (AVCE00ParseSuperSectionEnd(psInfo, pszLine) == TRUE) { /* Nothing to do... it's all been done by the call to * AVCE00ParseSuperSectionEnd() */ } else if (psRead->eCurFileType == AVCFileUnknown) { /*------------------------------------------------------------- * We're at the top level or inside a supersection... waiting * to encounter a valid section or supersection header * (i.e. "ARC 2", etc...) *------------------------------------------------------------*/ /*------------------------------------------------------------- * First check for a supersection header (TX6, RXP, IFO, ...) *------------------------------------------------------------*/ if ( AVCE00ParseSuperSectionHeader(psInfo, pszLine) == AVCFileUnknown ) { /*--------------------------------------------------------- * This was not a supersection header... check if it's a simple * section header *--------------------------------------------------------*/ psRead->eCurFileType = AVCE00ParseSectionHeader(psInfo, pszLine); } else { /* got supersection */ } if (psRead->eCurFileType == AVCFileTABLE) { /*--------------------------------------------------------- * send the first header line to the parser and wait until * the whole header has been read. *--------------------------------------------------------*/ AVCE00ParseNextLine(psInfo, pszLine); } else if (psRead->eCurFileType != AVCFileUnknown) { /*--------------------------------------------------------- * found a valid section header *--------------------------------------------------------*/ } } else if (psRead->eCurFileType == AVCFileTABLE && ! psInfo->bTableHdrComplete ) { /*------------------------------------------------------------- * We're reading a TABLE header... continue reading lines * from the header * * Note: When parsing a TABLE, the first object returned will * be the AVCTableDef, then data records will follow. *------------------------------------------------------------*/ psObj = AVCE00ParseNextLine(psInfo, pszLine); if (psObj) { /* got table header */ /* TODO: Enable return of table definition? */ psObj = NULL; } } else { /*------------------------------------------------------------- * We're are in the middle of a section... first check if we * have reached the end. * * note: The first call to AVCE00ParseSectionEnd() with FALSE will * not reset the parser until we close the file... and then * we call the function again to reset the parser. *------------------------------------------------------------*/ if (AVCE00ParseSectionEnd(psInfo, pszLine, FALSE)) { psRead->eCurFileType = AVCFileUnknown; AVCE00ParseSectionEnd(psInfo, pszLine, TRUE); } else /*------------------------------------------------------------- * ... not at the end yet, so continue reading objects. *------------------------------------------------------------*/ { psObj = AVCE00ParseNextLine(psInfo, pszLine); if (psObj) { /* got object */ } } } if (CPLGetLastErrorNo() != 0) nStatus = -1; return psObj; } /********************************************************************** * _AVCE00ReadBuildSqueleton() * * Build the squeleton of the E00 file corresponding to the specified * coverage and set the appropriate fields in the AVCE00ReadPtr struct. * * Note that the order of the sections in the squeleton is important * since some software may rely on this ordering when they read E00 files. * * The function returns the coverage precision that it will read from one * of the file headers. **********************************************************************/ static int _AVCE00ReadBuildSqueleton(AVCE00ReadPtr psInfo, char **papszCoverDir) { int iSect, iTable, numTables, iFile, nLen; char **papszTables, **papszFiles, szCWD[75]="", *pcTmp; char *pszEXPPath=NULL; int nCoverPrecision = AVC_DEFAULT_PREC; char cPrecisionCode = '2'; const char *szFname = NULL; AVCBinFile *psFile=NULL; psInfo->numSections = 0; psInfo->pasSections = NULL; /*----------------------------------------------------------------- * Build the absolute coverage path to include in the EXP 0 line * This line usually contains the full path of the E00 file that * is being created, but since the lib does not write the output * file directly, there is no simple way to get that value. Instead, * we will use the absolute coverage path to which we add a .E00 * extension. * We need also make sure cover path is all in uppercase. *----------------------------------------------------------------*/ #ifdef WIN32 if (psInfo->pszCoverPath[0] != '\\' && !(isalpha(psInfo->pszCoverPath[0]) && psInfo->pszCoverPath[1] == ':')) #else if (psInfo->pszCoverPath[0] != '/') #endif { if (getcwd(szCWD, 74) == NULL) szCWD[0] = '\0'; /* Failed: buffer may be too small */ nLen = strlen(szCWD); #ifdef WIN32 if (nLen > 0 && szCWD[nLen -1] != '\\') strcat(szCWD, "\\"); #else if (nLen > 0 && szCWD[nLen -1] != '/') strcat(szCWD, "/"); #endif } pszEXPPath = CPLStrdup(CPLSPrintf("EXP 0 %s%-.*s.E00", szCWD, strlen(psInfo->pszCoverPath)-1, psInfo->pszCoverPath)); pcTmp = pszEXPPath; for( ; *pcTmp != '\0'; pcTmp++) *pcTmp = toupper(*pcTmp); /*----------------------------------------------------------------- * EXP Header *----------------------------------------------------------------*/ iSect = _AVCIncreaseSectionsArray(&(psInfo->pasSections), &(psInfo->numSections), 1); psInfo->pasSections[iSect].eType = AVCFileUnknown; psInfo->pasSections[iSect].pszName = pszEXPPath; /*----------------------------------------------------------------- * We have to try to open each file as we go for 2 reasons: * - To validate the file's signature in order to detect cases like a user * that places files such as "mystuff.txt" in the cover directory... * this has already happened and obviously lead to problems!) * - We also need to find the coverage's precision from the headers *----------------------------------------------------------------*/ /*----------------------------------------------------------------- * ARC section (arc.adf) *----------------------------------------------------------------*/ szFname = (psInfo->eCoverType==AVCCoverV7 || psInfo->eCoverType==AVCCoverPC2 ) ? "arc.adf": "arc"; if ( (iFile=CSLFindString(papszCoverDir, szFname)) != -1 && (psFile = AVCBinReadOpen(psInfo->pszCoverPath, szFname, psInfo->eCoverType, AVCFileARC, psInfo->psDBCSInfo)) != NULL) { if (nCoverPrecision == AVC_DEFAULT_PREC) nCoverPrecision = psFile->nPrecision; AVCBinReadClose(psFile); iSect = _AVCIncreaseSectionsArray(&(psInfo->pasSections), &(psInfo->numSections), 1); psInfo->pasSections[iSect].eType = AVCFileARC; psInfo->pasSections[iSect].pszName = CPLStrdup("ARC"); psInfo->pasSections[iSect].pszFilename=CPLStrdup(papszCoverDir[iFile]); } /*----------------------------------------------------------------- * CNT section (cnt.adf) *----------------------------------------------------------------*/ szFname = (psInfo->eCoverType==AVCCoverV7 || psInfo->eCoverType==AVCCoverPC2 ) ? "cnt.adf": "cnt"; if ( (iFile=CSLFindString(papszCoverDir, szFname)) != -1 && (psFile = AVCBinReadOpen(psInfo->pszCoverPath, szFname, psInfo->eCoverType, AVCFileCNT, psInfo->psDBCSInfo)) != NULL) { if (nCoverPrecision == AVC_DEFAULT_PREC) nCoverPrecision = psFile->nPrecision; AVCBinReadClose(psFile); iSect = _AVCIncreaseSectionsArray(&(psInfo->pasSections), &(psInfo->numSections), 1); psInfo->pasSections[iSect].eType = AVCFileCNT; psInfo->pasSections[iSect].pszName = CPLStrdup("CNT"); psInfo->pasSections[iSect].pszFilename=CPLStrdup(papszCoverDir[iFile]); } /*----------------------------------------------------------------- * LAB section (lab.adf) *----------------------------------------------------------------*/ szFname = (psInfo->eCoverType==AVCCoverV7 || psInfo->eCoverType==AVCCoverPC2 ) ? "lab.adf": "lab"; if ( (iFile=CSLFindString(papszCoverDir, szFname)) != -1 && (psFile = AVCBinReadOpen(psInfo->pszCoverPath, szFname, psInfo->eCoverType, AVCFileLAB, psInfo->psDBCSInfo)) != NULL) { if (nCoverPrecision == AVC_DEFAULT_PREC) nCoverPrecision = psFile->nPrecision; AVCBinReadClose(psFile); iSect = _AVCIncreaseSectionsArray(&(psInfo->pasSections), &(psInfo->numSections), 1); psInfo->pasSections[iSect].eType = AVCFileLAB; psInfo->pasSections[iSect].pszName = CPLStrdup("LAB"); psInfo->pasSections[iSect].pszFilename=CPLStrdup(papszCoverDir[iFile]); } /*----------------------------------------------------------------- * PAL section (pal.adf) *----------------------------------------------------------------*/ szFname = (psInfo->eCoverType==AVCCoverV7 || psInfo->eCoverType==AVCCoverPC2 ) ? "pal.adf": "pal"; if ( (iFile=CSLFindString(papszCoverDir, szFname)) != -1 && (psFile = AVCBinReadOpen(psInfo->pszCoverPath, szFname, psInfo->eCoverType, AVCFilePAL, psInfo->psDBCSInfo)) != NULL) { if (nCoverPrecision == AVC_DEFAULT_PREC) nCoverPrecision = psFile->nPrecision; AVCBinReadClose(psFile); iSect = _AVCIncreaseSectionsArray(&(psInfo->pasSections), &(psInfo->numSections), 1); psInfo->pasSections[iSect].eType = AVCFilePAL; psInfo->pasSections[iSect].pszName = CPLStrdup("PAL"); psInfo->pasSections[iSect].pszFilename=CPLStrdup(papszCoverDir[iFile]); } /*----------------------------------------------------------------- * TOL section (tol.adf for single precision, par.adf for double) *----------------------------------------------------------------*/ szFname = (psInfo->eCoverType==AVCCoverV7 || psInfo->eCoverType==AVCCoverPC2 ) ? "tol.adf": "tol"; if ( (iFile=CSLFindString(papszCoverDir, szFname)) != -1 && (psFile = AVCBinReadOpen(psInfo->pszCoverPath, szFname, psInfo->eCoverType, AVCFileTOL, psInfo->psDBCSInfo)) != NULL) { if (nCoverPrecision == AVC_DEFAULT_PREC) nCoverPrecision = psFile->nPrecision; AVCBinReadClose(psFile); iSect = _AVCIncreaseSectionsArray(&(psInfo->pasSections), &(psInfo->numSections), 1); psInfo->pasSections[iSect].eType = AVCFileTOL; psInfo->pasSections[iSect].pszName = CPLStrdup("TOL"); psInfo->pasSections[iSect].pszFilename=CPLStrdup(papszCoverDir[iFile]); } szFname = (psInfo->eCoverType==AVCCoverV7 || psInfo->eCoverType==AVCCoverPC2 ) ? "par.adf": "par"; if ( (iFile=CSLFindString(papszCoverDir, szFname)) != -1 && (psFile = AVCBinReadOpen(psInfo->pszCoverPath, szFname, psInfo->eCoverType, AVCFileTOL, psInfo->psDBCSInfo)) != NULL) { if (nCoverPrecision == AVC_DEFAULT_PREC) nCoverPrecision = psFile->nPrecision; AVCBinReadClose(psFile); iSect = _AVCIncreaseSectionsArray(&(psInfo->pasSections), &(psInfo->numSections), 1); psInfo->pasSections[iSect].eType = AVCFileTOL; psInfo->pasSections[iSect].pszName = CPLStrdup("TOL"); psInfo->pasSections[iSect].pszFilename=CPLStrdup(papszCoverDir[iFile]); } /*----------------------------------------------------------------- * TXT section (txt.adf) *----------------------------------------------------------------*/ szFname = (psInfo->eCoverType==AVCCoverV7 || psInfo->eCoverType==AVCCoverPC2 ) ? "txt.adf": "txt"; if ( (iFile=CSLFindString(papszCoverDir, szFname)) != -1 && (psFile = AVCBinReadOpen(psInfo->pszCoverPath, szFname, psInfo->eCoverType, AVCFileTXT, psInfo->psDBCSInfo)) != NULL) { if (nCoverPrecision == AVC_DEFAULT_PREC) nCoverPrecision = psFile->nPrecision; AVCBinReadClose(psFile); iSect = _AVCIncreaseSectionsArray(&(psInfo->pasSections), &(psInfo->numSections), 1); psInfo->pasSections[iSect].eType = AVCFileTXT; psInfo->pasSections[iSect].pszName = CPLStrdup("TXT"); psInfo->pasSections[iSect].pszFilename=CPLStrdup(papszCoverDir[iFile]); } /*----------------------------------------------------------------- * TX6 section (*.txt) * Scan the directory for files with a ".txt" extension. * Note: Never seen those in a PC Arc/Info coverage! * In weird coverages, the filename ends with "txt" but there is no "." *----------------------------------------------------------------*/ if (psInfo->eCoverType == AVCCoverV7) nCoverPrecision = _AVCE00ReadAddJabberwockySection(psInfo, AVCFileTX6, "TX6", nCoverPrecision, ".txt", papszCoverDir); else if (psInfo->eCoverType == AVCCoverWeird) nCoverPrecision = _AVCE00ReadAddJabberwockySection(psInfo, AVCFileTX6, "TX6", nCoverPrecision, "txt", papszCoverDir); /*----------------------------------------------------------------- * At this point, we should have read the coverage precsion... and if * we haven't yet then we'll just use single by default. * We'll need cPrecisionCode for some of the sections that follow. *----------------------------------------------------------------*/ if (nCoverPrecision == AVC_DOUBLE_PREC) cPrecisionCode = '3'; else cPrecisionCode = '2'; /*----------------------------------------------------------------- * SIN 2/3 and EOX lines ... ??? *----------------------------------------------------------------*/ iSect = _AVCIncreaseSectionsArray(&(psInfo->pasSections), &(psInfo->numSections), 2); psInfo->pasSections[iSect].eType = AVCFileUnknown; psInfo->pasSections[iSect].pszName = CPLStrdup("SIN X"); psInfo->pasSections[iSect].pszName[5] = cPrecisionCode; iSect++; psInfo->pasSections[iSect].eType = AVCFileUnknown; psInfo->pasSections[iSect].pszName = CPLStrdup("EOX"); iSect++; /*----------------------------------------------------------------- * LOG section (log.adf) (ends with EOL) *----------------------------------------------------------------*/ /*----------------------------------------------------------------- * PRJ section (prj.adf) (ends with EOP) *----------------------------------------------------------------*/ szFname = (psInfo->eCoverType==AVCCoverV7 || psInfo->eCoverType==AVCCoverPC2 ) ? "prj.adf": "prj"; if ( (iFile=CSLFindString(papszCoverDir, szFname)) != -1 ) { iSect = _AVCIncreaseSectionsArray(&(psInfo->pasSections), &(psInfo->numSections), 1); psInfo->pasSections[iSect].eType = AVCFilePRJ; psInfo->pasSections[iSect].pszName = CPLStrdup("PRJ"); psInfo->pasSections[iSect].pszFilename=CPLStrdup(papszCoverDir[iFile]); } /*----------------------------------------------------------------- * RXP section (*.rxp) * Scan the directory for files with a ".rxp" extension. *----------------------------------------------------------------*/ if (psInfo->eCoverType == AVCCoverV7) _AVCE00ReadAddJabberwockySection(psInfo, AVCFileRXP, "RXP", nCoverPrecision,".rxp",papszCoverDir); else if (psInfo->eCoverType == AVCCoverWeird) _AVCE00ReadAddJabberwockySection(psInfo, AVCFileRXP, "RXP", nCoverPrecision,"rxp",papszCoverDir); /*----------------------------------------------------------------- * RPL section (*.pal) * Scan the directory for files with a ".rpl" extension. *----------------------------------------------------------------*/ if (psInfo->eCoverType == AVCCoverV7) _AVCE00ReadAddJabberwockySection(psInfo, AVCFileRPL, "RPL", nCoverPrecision,".pal",papszCoverDir); else if (psInfo->eCoverType == AVCCoverWeird) _AVCE00ReadAddJabberwockySection(psInfo, AVCFileRPL, "RPL", nCoverPrecision,"rpl",papszCoverDir); /*----------------------------------------------------------------- * IFO section (tables) *----------------------------------------------------------------*/ papszTables = papszFiles = NULL; if (psInfo->eCoverType == AVCCoverV7 || psInfo->eCoverType == AVCCoverV7Tables || psInfo->eCoverType == AVCCoverWeird) { /*------------------------------------------------------------- * Unix coverages: get tables from the ../info/arc.dir * Weird coverages: the arc.dir is similar but called "arcdr9" *------------------------------------------------------------*/ papszTables = AVCBinReadListTables(psInfo->pszInfoPath, psInfo->pszCoverName, &papszFiles, psInfo->eCoverType, psInfo->psDBCSInfo); } else if (psInfo->eCoverType == AVCCoverPC || psInfo->eCoverType == AVCCoverPC2) { /*------------------------------------------------------------- * PC coverages: look for "???.dbf" in the coverage directory * and build the table name using the coverage name * as the table basename, and the dbf file basename * as the table extension. *------------------------------------------------------------*/ for(iFile=0; papszCoverDir && papszCoverDir[iFile]; iFile++) { if ((nLen = strlen(papszCoverDir[iFile])) == 7 && EQUAL(papszCoverDir[iFile] + nLen -4, ".dbf")) { papszCoverDir[iFile][nLen - 4] = '\0'; szFname = CPLSPrintf("%s.%s", psInfo->pszCoverName, papszCoverDir[iFile]); pcTmp = (char*)szFname; for( ; *pcTmp != '\0'; pcTmp++) *pcTmp = toupper(*pcTmp); papszCoverDir[iFile][nLen - 4] = '.'; papszTables = CSLAddString(papszTables, szFname); papszFiles = CSLAddString(papszFiles, papszCoverDir[iFile]); } } } if ((numTables = CSLCount(papszTables)) > 0) { iSect = _AVCIncreaseSectionsArray(&(psInfo->pasSections), &(psInfo->numSections), numTables+2); psInfo->pasSections[iSect].eType = AVCFileUnknown; psInfo->pasSections[iSect].pszName = CPLStrdup("IFO X"); psInfo->pasSections[iSect].pszName[5] = cPrecisionCode; iSect++; for(iTable=0; iTablepasSections[iSect].eType = AVCFileTABLE; psInfo->pasSections[iSect].pszName=CPLStrdup(papszTables[iTable]); if (papszFiles) { psInfo->pasSections[iSect].pszFilename= CPLStrdup(papszFiles[iTable]); } iSect++; } psInfo->pasSections[iSect].eType = AVCFileUnknown; psInfo->pasSections[iSect].pszName = CPLStrdup("EOI"); iSect++; } CSLDestroy(papszTables); CSLDestroy(papszFiles); /*----------------------------------------------------------------- * File ends with EOS *----------------------------------------------------------------*/ iSect = _AVCIncreaseSectionsArray(&(psInfo->pasSections), &(psInfo->numSections), 1); psInfo->pasSections[iSect].eType = AVCFileUnknown; psInfo->pasSections[iSect].pszName = CPLStrdup("EOS"); return nCoverPrecision; } /********************************************************************** * _AVCE00ReadScanE00() * * Processes an entire E00 file to find all the interesting sections. **********************************************************************/ static void _AVCE00ReadScanE00(AVCE00ReadE00Ptr psRead) { AVCE00ParseInfo *psInfo = psRead->hParseInfo; const char *pszLine; const char *pszName = 0; void *obj; int iSect = 0; while (CPLGetLastErrorNo() == 0 && (pszLine = CPLReadLine(psRead->hFile) ) != NULL ) { obj = _AVCE00ReadNextLineE00(psRead, pszLine); if (obj) { pszName = 0; switch (psInfo->eFileType) { case AVCFileARC: pszName = "ARC"; break; case AVCFilePAL: pszName = "PAL"; break; case AVCFileCNT: pszName = "CNT"; break; case AVCFileLAB: pszName = "LAB"; break; case AVCFileRPL: pszName = "RPL"; break; case AVCFileTXT: pszName = "TXT"; break; case AVCFileTX6: pszName = "TX6"; break; case AVCFilePRJ: pszName = "PRJ"; break; case AVCFileTABLE: pszName = psInfo->hdr.psTableDef->szTableName; break; default: break; } if (pszName && (psRead->numSections == 0 || psRead->pasSections[iSect].eType != psInfo->eFileType || !EQUAL(pszName, psRead->pasSections[iSect].pszName))) { iSect = _AVCIncreaseSectionsArray(&(psRead->pasSections), &(psRead->numSections), 1); psRead->pasSections[iSect].eType = psInfo->eFileType; /* psRead->pasSections[iSect].pszName = CPLStrdup(psRead->pszCoverName); */ psRead->pasSections[iSect].pszName = CPLStrdup(pszName); psRead->pasSections[iSect].pszFilename = CPLStrdup(psRead->pszCoverPath); psRead->pasSections[iSect].nLineNum = psInfo->nStartLineNum; psRead->pasSections[iSect].nFeatureCount = 0; } if (pszName && psRead->numSections) { /* increase feature count for current layer */ ++psRead->pasSections[iSect].nFeatureCount; } } } } /********************************************************************** * _AVCE00ReadNextTableLine() * * Return the next line of the E00 representation of a info table. * * This function is used by AVCE00ReadNextLine() to generate table * output... it should never be called directly. **********************************************************************/ static const char *_AVCE00ReadNextTableLine(AVCE00ReadPtr psInfo) { const char *pszLine = NULL; AVCE00Section *psSect; psSect = &(psInfo->pasSections[psInfo->iCurSection]); CPLAssert(psSect->eType == AVCFileTABLE); if (psInfo->iCurStep == AVC_GEN_NOTSTARTED) { /*--------------------------------------------------------- * Open table and start returning header *--------------------------------------------------------*/ if (psInfo->eCoverType == AVCCoverPC || psInfo->eCoverType == AVCCoverPC2) { /*--------------------------------------------------------- * PC Arc/Info: We pass the DBF table's full filename + the * Arc/Info table name (for E00 header) *--------------------------------------------------------*/ char *pszFname; pszFname = CPLStrdup(CPLSPrintf("%s%s", psInfo->pszInfoPath, psSect->pszFilename )); psInfo->hFile = AVCBinReadOpen(pszFname, psSect->pszName, psInfo->eCoverType, psSect->eType, psInfo->psDBCSInfo); CPLFree(pszFname); } else { /*--------------------------------------------------------- * AVCCoverV7 and AVCCoverWeird: * We pass the INFO dir's path, and the Arc/Info table name * will be searched in the arc.dir *--------------------------------------------------------*/ psInfo->hFile = AVCBinReadOpen(psInfo->pszInfoPath, psSect->pszName, psInfo->eCoverType, psSect->eType, psInfo->psDBCSInfo); } /* For some reason the file could not be opened... abort now. * An error message should have already been produced by * AVCBinReadOpen() */ if (psInfo->hFile == NULL) return NULL; psInfo->iCurStep = AVC_GEN_TABLEHEADER; pszLine = AVCE00GenTableHdr(psInfo->hGenInfo, psInfo->hFile->hdr.psTableDef, FALSE); } if (pszLine == NULL && psInfo->iCurStep == AVC_GEN_TABLEHEADER) { /*--------------------------------------------------------- * Continue table header *--------------------------------------------------------*/ pszLine = AVCE00GenTableHdr(psInfo->hGenInfo, psInfo->hFile->hdr.psTableDef, TRUE); if (pszLine == NULL) { /* Finished with table header... time to proceed with the * table data. * Reset the AVCE00GenInfo struct. so that it returns NULL, * which will force reading of the first record from the * file on the next call to AVCE00ReadNextLine() */ AVCE00GenReset(psInfo->hGenInfo); psInfo->iCurStep = AVC_GEN_TABLEDATA; } } if (pszLine == NULL && psInfo->iCurStep == AVC_GEN_TABLEDATA) { /*--------------------------------------------------------- * Continue with records of data *--------------------------------------------------------*/ pszLine = AVCE00GenTableRec(psInfo->hGenInfo, psInfo->hFile->hdr.psTableDef->numFields, psInfo->hFile->hdr.psTableDef->pasFieldDef, psInfo->hFile->cur.pasFields, TRUE); if (pszLine == NULL) { /* Current record is finished generating... we need to read * a new one from the file. */ if (AVCBinReadNextObject(psInfo->hFile) != NULL) { pszLine = AVCE00GenTableRec(psInfo->hGenInfo, psInfo->hFile->hdr.psTableDef->numFields, psInfo->hFile->hdr.psTableDef->pasFieldDef, psInfo->hFile->cur.pasFields, FALSE); } } } if (pszLine == NULL) { /*--------------------------------------------------------- * No more lines to output for this table ... Close it. *--------------------------------------------------------*/ AVCBinReadClose(psInfo->hFile); psInfo->hFile = NULL; /*--------------------------------------------------------- * And now proceed to the next section... * OK, I don't really like recursivity either... but it was * the simplest way to do this, and anyways we should never * have more than one level of recursivity. *--------------------------------------------------------*/ if (psInfo->bReadAllSections) psInfo->iCurSection++; else psInfo->iCurSection = psInfo->numSections; psInfo->iCurStep = AVC_GEN_NOTSTARTED; pszLine = AVCE00ReadNextLine(psInfo); } /*----------------------------------------------------------------- * Check for errors... if any error happened, tehn return NULL *----------------------------------------------------------------*/ if (CPLGetLastErrorNo() != 0) { pszLine = NULL; } return pszLine; } /********************************************************************** * AVCE00ReadNextLine() * * Returns the next line of the E00 representation of the coverage * or NULL when there are no more lines to generate, or if an error happened. * The returned line is a null-terminated string, and it does not * include a newline character. * * Call CPLGetLastErrorNo() after calling AVCE00ReadNextLine() to * make sure that the line was generated succesfully. * * Note that AVCE00ReadNextLine() returns a reference to an * internal buffer whose contents will * be valid only until the next call to this function. The caller should * not attempt to free() the returned pointer. **********************************************************************/ const char *AVCE00ReadNextLine(AVCE00ReadPtr psInfo) { const char *pszLine = NULL; AVCE00Section *psSect; CPLErrorReset(); /*----------------------------------------------------------------- * Check if we have finished generating E00 output *----------------------------------------------------------------*/ if (psInfo->iCurSection >= psInfo->numSections) return NULL; psSect = &(psInfo->pasSections[psInfo->iCurSection]); /*----------------------------------------------------------------- * For simplicity, the generation of table output is in a separate * function. *----------------------------------------------------------------*/ if (psSect->eType == AVCFileTABLE) { return _AVCE00ReadNextTableLine(psInfo); } if (psSect->eType == AVCFileUnknown) { /*----------------------------------------------------------------- * Section not attached to any file, used to hold header lines * or section separators, etc... just return the line directly and * move pointer to the next section. *----------------------------------------------------------------*/ pszLine = psSect->pszName; if (psInfo->bReadAllSections) psInfo->iCurSection++; else psInfo->iCurSection = psInfo->numSections; psInfo->iCurStep = AVC_GEN_NOTSTARTED; } /*================================================================= * ARC, PAL, CNT, LAB, TOL and TXT *================================================================*/ else if (psInfo->iCurStep == AVC_GEN_NOTSTARTED && (psSect->eType == AVCFileARC || psSect->eType == AVCFilePAL || psSect->eType == AVCFileRPL || psSect->eType == AVCFileCNT || psSect->eType == AVCFileLAB || psSect->eType == AVCFileTOL || psSect->eType == AVCFileTXT || psSect->eType == AVCFileTX6 || psSect->eType == AVCFileRXP ) ) { /*----------------------------------------------------------------- * Start processing of an ARC, PAL, CNT, LAB or TOL section: * Open the file, get ready to read the first object from the * file, and return the header line. * If the file fails to open then we will return NULL. *----------------------------------------------------------------*/ psInfo->hFile = AVCBinReadOpen(psInfo->pszCoverPath, psSect->pszFilename, psInfo->eCoverType, psSect->eType, psInfo->psDBCSInfo); /*------------------------------------------------------------- * For some reason the file could not be opened... abort now. * An error message should have already been produced by * AVCBinReadOpen() *------------------------------------------------------------*/ if (psInfo->hFile == NULL) return NULL; pszLine = AVCE00GenStartSection(psInfo->hGenInfo, psSect->eType, psSect->pszName); /*------------------------------------------------------------- * Reset the AVCE00GenInfo struct. so that it returns NULL, * which will force reading of the first object from the * file on the next call to AVCE00ReadNextLine() *------------------------------------------------------------*/ AVCE00GenReset(psInfo->hGenInfo); psInfo->iCurStep = AVC_GEN_DATA; } else if (psInfo->iCurStep == AVC_GEN_DATA && (psSect->eType == AVCFileARC || psSect->eType == AVCFilePAL || psSect->eType == AVCFileRPL || psSect->eType == AVCFileCNT || psSect->eType == AVCFileLAB || psSect->eType == AVCFileTOL || psSect->eType == AVCFileTXT || psSect->eType == AVCFileTX6 || psSect->eType == AVCFileRXP ) ) { /*----------------------------------------------------------------- * Return the next line of an ARC/PAL/CNT/TOL/TXT object... * if necessary, read the next object from the binary file. *----------------------------------------------------------------*/ pszLine = AVCE00GenObject(psInfo->hGenInfo, psSect->eType, (psSect->eType==AVCFileARC?(void*)(psInfo->hFile->cur.psArc): psSect->eType==AVCFilePAL?(void*)(psInfo->hFile->cur.psPal): psSect->eType==AVCFileRPL?(void*)(psInfo->hFile->cur.psPal): psSect->eType==AVCFileCNT?(void*)(psInfo->hFile->cur.psCnt): psSect->eType==AVCFileLAB?(void*)(psInfo->hFile->cur.psLab): psSect->eType==AVCFileTOL?(void*)(psInfo->hFile->cur.psTol): psSect->eType==AVCFileTXT?(void*)(psInfo->hFile->cur.psTxt): psSect->eType==AVCFileTX6?(void*)(psInfo->hFile->cur.psTxt): psSect->eType==AVCFileRXP?(void*)(psInfo->hFile->cur.psRxp): NULL), TRUE); if (pszLine == NULL) { /*--------------------------------------------------------- * Current object is finished generating... we need to read * a new one from the file. *--------------------------------------------------------*/ if (AVCBinReadNextObject(psInfo->hFile) != NULL) { pszLine = AVCE00GenObject(psInfo->hGenInfo, psSect->eType, (psSect->eType==AVCFileARC?(void*)(psInfo->hFile->cur.psArc): psSect->eType==AVCFilePAL?(void*)(psInfo->hFile->cur.psPal): psSect->eType==AVCFileRPL?(void*)(psInfo->hFile->cur.psPal): psSect->eType==AVCFileCNT?(void*)(psInfo->hFile->cur.psCnt): psSect->eType==AVCFileLAB?(void*)(psInfo->hFile->cur.psLab): psSect->eType==AVCFileTOL?(void*)(psInfo->hFile->cur.psTol): psSect->eType==AVCFileTXT?(void*)(psInfo->hFile->cur.psTxt): psSect->eType==AVCFileTX6?(void*)(psInfo->hFile->cur.psTxt): psSect->eType==AVCFileRXP?(void*)(psInfo->hFile->cur.psRxp): NULL), FALSE); } } if (pszLine == NULL) { /*--------------------------------------------------------- * Still NULL ??? This means we finished reading this file... * Start returning the "end of section" line(s)... *--------------------------------------------------------*/ AVCBinReadClose(psInfo->hFile); psInfo->hFile = NULL; psInfo->iCurStep = AVC_GEN_ENDSECTION; pszLine = AVCE00GenEndSection(psInfo->hGenInfo, psSect->eType, FALSE); } } /*================================================================= * PRJ *================================================================*/ else if (psInfo->iCurStep == AVC_GEN_NOTSTARTED && psSect->eType == AVCFilePRJ ) { /*------------------------------------------------------------- * Start processing of PRJ section... return first header line. *------------------------------------------------------------*/ pszLine = AVCE00GenStartSection(psInfo->hGenInfo, psSect->eType, NULL); psInfo->hFile = NULL; psInfo->iCurStep = AVC_GEN_DATA; } else if (psInfo->iCurStep == AVC_GEN_DATA && psSect->eType == AVCFilePRJ ) { /*------------------------------------------------------------- * Return the next line of a PRJ section *------------------------------------------------------------*/ if (psInfo->hFile == NULL) { /*--------------------------------------------------------- * File has not been read yet... * Read the PRJ file, and return the first PRJ line. *--------------------------------------------------------*/ psInfo->hFile = AVCBinReadOpen(psInfo->pszCoverPath, psSect->pszFilename, psInfo->eCoverType, psSect->eType, psInfo->psDBCSInfo); /* For some reason the file could not be opened... abort now. * An error message should have already been produced by * AVCBinReadOpen() */ if (psInfo->hFile == NULL) return NULL; pszLine = AVCE00GenPrj(psInfo->hGenInfo, psInfo->hFile->cur.papszPrj, FALSE); } else { /*--------------------------------------------------------- * Generate the next line of output. *--------------------------------------------------------*/ pszLine = AVCE00GenPrj(psInfo->hGenInfo, psInfo->hFile->cur.papszPrj, TRUE); } if (pszLine == NULL) { /*--------------------------------------------------------- * Still NULL ??? This means we finished generating this PRJ * section... * Start returning the "end of section" line(s)... *--------------------------------------------------------*/ AVCBinReadClose(psInfo->hFile); psInfo->hFile = NULL; psInfo->iCurStep = AVC_GEN_ENDSECTION; pszLine = AVCE00GenEndSection(psInfo->hGenInfo, psSect->eType, FALSE); } } else if (psInfo->iCurStep != AVC_GEN_ENDSECTION) { /* We should never get here! */ CPLAssert(FALSE); } /*================================================================= * End of section, for all files *================================================================*/ /*----------------------------------------------------------------- * Finished processing of an ARC, PAL, CNT, LAB, TOL, PRJ file ... * continue returning the "end of section" line(s), and move the pointer * to the next section once we're done. *----------------------------------------------------------------*/ if (psInfo->iCurStep == AVC_GEN_ENDSECTION && pszLine == NULL) { pszLine = AVCE00GenEndSection(psInfo->hGenInfo, psSect->eType, TRUE); if (pszLine == NULL) { /*--------------------------------------------------------- * Finished returning the last lines of the section... * proceed to the next section... * OK, I don't really like recursivity either... but it was * the simplest way to do this, and anyways we should never * have more than one level of recursivity. *--------------------------------------------------------*/ if (psInfo->bReadAllSections) psInfo->iCurSection++; else psInfo->iCurSection = psInfo->numSections; psInfo->iCurStep = AVC_GEN_NOTSTARTED; pszLine = AVCE00ReadNextLine(psInfo); } } return pszLine; } /********************************************************************** * AVCE00ReadSectionsList() * * Returns an array of AVCE00Section structures that describe the * squeleton of the whole coverage. The value of *numSect will be * set to the number of sections in the array. * * You can scan the returned array, and use AVCE00ReadGotoSection() to move * the read pointer directly to the beginning of a given section * of the file. * * Sections of type AVCFileUnknown correspond to lines in the * E00 output that are not directly linked to any coverage file, like * the "EXP 0" line, the "IFO X", "SIN X", etc. * * THE RETURNED ARRAY IS AN INTERNAL STRUCTURE AND SHOULD NOT BE * MODIFIED OR FREED BY THE CALLER... its contents will be valid * for as long as the coverage will remain open. **********************************************************************/ AVCE00Section *AVCE00ReadSectionsList(AVCE00ReadPtr psInfo, int *numSect) { CPLErrorReset(); *numSect = psInfo->numSections; return psInfo->pasSections; } /********************************************************************** * AVCE00ReadGotoSection() * * Move the read pointer to the E00 section (coverage file) described in * the psSect structure. Call AVCE00ReadSectionsList() to get the list of * sections for the current coverage. * * if bContinue=TRUE, then reading will automatically continue with the * next sections of the file once the requested section is finished. * Otherwise, if bContinue=FALSE then reading will stop at the end * of this section (i.e. AVCE00ReadNextLine() will return NULL when * it reaches the end of this section) * * Sections of type AVCFileUnknown returned by AVCE00ReadSectionsList() * correspond to lines in the E00 output that are not directly linked * to any coverage file, like the "EXP 0" line, the "IFO X", "SIN X", etc. * You can jump to these sections or any other one without problems. * * This function returns 0 on success or -1 on error. **********************************************************************/ int AVCE00ReadGotoSection(AVCE00ReadPtr psInfo, AVCE00Section *psSect, GBool bContinue) { int iSect; GBool bFound = FALSE; CPLErrorReset(); /*----------------------------------------------------------------- * Locate the requested section in the array. *----------------------------------------------------------------*/ for(iSect=0; iSectnumSections; iSect++) { if (psInfo->pasSections[iSect].eType == psSect->eType && EQUAL(psInfo->pasSections[iSect].pszName, psSect->pszName)) { bFound = TRUE; break; } } /*----------------------------------------------------------------- * Not found ... generate an error... *----------------------------------------------------------------*/ if (!bFound) { CPLError(CE_Failure, CPLE_IllegalArg, "Requested E00 section does not exist!"); return -1; } /*----------------------------------------------------------------- * Found it ... close current section and get ready to read * the new one. *----------------------------------------------------------------*/ if (psInfo->hFile) { AVCBinReadClose(psInfo->hFile); psInfo->hFile = NULL; } psInfo->bReadAllSections = bContinue; psInfo->iCurSection = iSect; psInfo->iCurStep = AVC_GEN_NOTSTARTED; return 0; } /********************************************************************** * AVCE00ReadRewind() * * Rewinds the AVCE00ReadPtr just like the stdio rewind() * function would do if you were reading an ASCII E00 file. * * Returns 0 on success or -1 on error. **********************************************************************/ int AVCE00ReadRewind(AVCE00ReadPtr psInfo) { CPLErrorReset(); return AVCE00ReadGotoSection(psInfo, &(psInfo->pasSections[0]), TRUE); } /********************************************************************** * AVCE00ReadRewindE00() * * Rewinds the AVCE00ReadE00Ptr just like the stdio rewind() * function would do if you were reading an ASCII E00 file. * * Returns 0 on success or -1 on error. **********************************************************************/ int AVCE00ReadRewindE00(AVCE00ReadE00Ptr psRead) { CPLErrorReset(); psRead->bReadAllSections = TRUE; psRead->eCurFileType = AVCFileUnknown; psRead->hParseInfo->nCurLineNum = 0; psRead->hParseInfo->nStartLineNum = 0; psRead->hParseInfo->bForceEndOfSection = TRUE; psRead->hParseInfo->eSuperSectionType = AVCFileUnknown; AVCE00ParseSectionEnd(psRead->hParseInfo, NULL, 1); return fseek(psRead->hFile, 0, SEEK_SET); } /********************************************************************** * _AVCE00ReadSeekE00() * * Seeks to a new location in the E00 file, keeping parse state * appropriately. * * NOTE: This is a pretty slow implementation. * NOTE: The SEEK_END is not implemented. * * Returns 0 on success or -1 on error. **********************************************************************/ static int _AVCE00ReadSeekE00(AVCE00ReadE00Ptr psRead, int nOffset, int nWhence) { const char *pszLine; void *obj; switch (nWhence) { case SEEK_CUR: break; case SEEK_SET: AVCE00ReadRewindE00(psRead); break; default: CPLAssert(nWhence == SEEK_CUR || nWhence == SEEK_SET); break; } while (nOffset-- && CPLGetLastErrorNo() == 0 && (pszLine = CPLReadLine(psRead->hFile) ) != NULL ) { obj = _AVCE00ReadNextLineE00(psRead, pszLine); } return nOffset ? -1 : 0; } /********************************************************************** * AVCE00ReadNextObjectE00() * * Returns the next object in an E00 file or NULL when there are no * more objects, or if an error happened. The object type can be * determined via the eCurFileType attribute of the * AVCE00ReadE00Ptr object. * * Note that AVCE00ReadNextLine() returns a reference to an internal * buffer whose contents will be valid only until the next call to * this function. The caller should not attempt to free() the * returned pointer. **********************************************************************/ void *AVCE00ReadNextObjectE00(AVCE00ReadE00Ptr psRead) { const char *pszLine; void *obj = NULL; do { pszLine = CPLReadLine(psRead->hFile); if (pszLine == 0) break; obj = _AVCE00ReadNextLineE00(psRead, pszLine); } while (obj == NULL && (psRead->bReadAllSections || psRead->eCurFileType != AVCFileUnknown) && CPLGetLastErrorNo() == 0); return obj; } /********************************************************************** * AVCE00ReadSectionsListE00() * * Returns an array of AVCE00Section structures that describe the * sections in the E00 file. The value of *numSect will be set to the * number of sections in the array. * * You can scan the returned array, and use AVCE00ReadGotoSectionE00() * to move the read pointer directly to the beginning of a given * section of the file. * * THE RETURNED ARRAY IS AN INTERNAL STRUCTURE AND SHOULD NOT BE * MODIFIED OR FREED BY THE CALLER... its contents will be valid * for as long as the coverage will remain open. **********************************************************************/ AVCE00Section *AVCE00ReadSectionsListE00(AVCE00ReadE00Ptr psRead, int *numSect) { CPLErrorReset(); *numSect = psRead->numSections; return psRead->pasSections; } /********************************************************************** * AVCE00ReadGotoSectionE00() * * Move the read pointer to the E00 section described in the psSect * structure. Call AVCE00ReadSectionsListE00() to get the list of * sections for the current coverage. * * If bContinue is TRUE, then reading will automatically continue with * the next section of the file once the requested section is finished. * Otherwise, if bContinue is FALSE then reading will stop at the end * of this section (i.e. AVCE00ReadNextObjectE00() will return NULL * when the end of this section is reached) * * This function returns 0 on success or -1 on error. **********************************************************************/ int AVCE00ReadGotoSectionE00(AVCE00ReadE00Ptr psRead, AVCE00Section *psSect, GBool bContinue) { int iSect; GBool bFound = FALSE; CPLErrorReset(); /*----------------------------------------------------------------- * Locate the requested section in the array. *----------------------------------------------------------------*/ for(iSect=0; iSectnumSections; iSect++) { if (psRead->pasSections[iSect].eType == psSect->eType && EQUAL(psRead->pasSections[iSect].pszName, psSect->pszName)) { bFound = TRUE; break; } } /*----------------------------------------------------------------- * Not found ... generate an error... *----------------------------------------------------------------*/ if (!bFound) { CPLError(CE_Failure, CPLE_IllegalArg, "Requested E00 section does not exist!"); return -1; } /*----------------------------------------------------------------- * Found it ... advance parser to line number of start of section *----------------------------------------------------------------*/ _AVCE00ReadSeekE00(psRead, psRead->pasSections[iSect].nLineNum, SEEK_SET); psRead->bReadAllSections = bContinue; return 0; } avce00-2.0.0/cpl_conv.c0100664000076400007640000002500506761516063014037 0ustar danieldaniel/****************************************************************************** * Copyright (c) 1998, Frank Warmerdam * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ****************************************************************************** * * cpl_conv.c: Various CPL convenience functions (from cpl_conv.h). * * $Log: cpl_conv.c,v $ * Revision 1.1 1999/08/27 14:09:55 daniel * Update CPL files * * Revision 1.7 1999/08/27 12:55:39 danmo * Support 0 bytes allocations in CPLRealloc() * * Revision 1.6 1999/06/25 04:38:03 warmerda * Fixed CPLReadLine() to work for long lines. * * Revision 1.5 1999/05/20 02:54:37 warmerda * Added API documentation * * Revision 1.4 1999/01/02 20:29:53 warmerda * Allow zero length allocations * * Revision 1.3 1998/12/15 19:01:07 warmerda * Added CPLReadLine(). * * Revision 1.2 1998/12/03 18:30:04 warmerda * Use CPLError() instead of GPSError(). * * Revision 1.1 1998/12/02 19:33:23 warmerda * New * */ #include "cpl_conv.h" /************************************************************************/ /* CPLCalloc() */ /************************************************************************/ /** * Safe version of calloc(). * * This function is like the C library calloc(), but raises a CE_Fatal * error with CPLError() if it fails to allocate the desired memory. It * should be used for small memory allocations that are unlikely to fail * and for which the application is unwilling to test for out of memory * conditions. It uses VSICalloc() to get the memory, so any hooking of * VSICalloc() will apply to CPLCalloc() as well. CPLFree() or VSIFree() * can be used free memory allocated by CPLCalloc(). * * @param nCount number of objects to allocate. * @param nSize size (in bytes) of object to allocate. * @return pointer to newly allocated memory, only NULL if nSize * nCount is * NULL. */ void *CPLCalloc( size_t nCount, size_t nSize ) { void *pReturn; if( nSize * nCount == 0 ) return NULL; pReturn = VSICalloc( nCount, nSize ); if( pReturn == NULL ) { CPLError( CE_Fatal, CPLE_OutOfMemory, "CPLCalloc(): Out of memory allocating %d bytes.\n", nSize * nCount ); } return pReturn; } /************************************************************************/ /* CPLMalloc() */ /************************************************************************/ /** * Safe version of malloc(). * * This function is like the C library malloc(), but raises a CE_Fatal * error with CPLError() if it fails to allocate the desired memory. It * should be used for small memory allocations that are unlikely to fail * and for which the application is unwilling to test for out of memory * conditions. It uses VSIMalloc() to get the memory, so any hooking of * VSIMalloc() will apply to CPLMalloc() as well. CPLFree() or VSIFree() * can be used free memory allocated by CPLMalloc(). * * @param nSize size (in bytes) of memory block to allocate. * @return pointer to newly allocated memory, only NULL if nSize is zero. */ void *CPLMalloc( size_t nSize ) { void *pReturn; if( nSize == 0 ) return NULL; pReturn = VSIMalloc( nSize ); if( pReturn == NULL ) { CPLError( CE_Fatal, CPLE_OutOfMemory, "CPLMalloc(): Out of memory allocating %d bytes.\n", nSize ); } return pReturn; } /************************************************************************/ /* CPLRealloc() */ /************************************************************************/ /** * Safe version of realloc(). * * This function is like the C library realloc(), but raises a CE_Fatal * error with CPLError() if it fails to allocate the desired memory. It * should be used for small memory allocations that are unlikely to fail * and for which the application is unwilling to test for out of memory * conditions. It uses VSIRealloc() to get the memory, so any hooking of * VSIRealloc() will apply to CPLRealloc() as well. CPLFree() or VSIFree() * can be used free memory allocated by CPLRealloc(). * * It is also safe to pass NULL in as the existing memory block for * CPLRealloc(), in which case it uses VSIMalloc() to allocate a new block. * * @param pData existing memory block which should be copied to the new block. * @param nNewSize new size (in bytes) of memory block to allocate. * @return pointer to allocated memory, only NULL if nNewSize is zero. */ void * CPLRealloc( void * pData, size_t nNewSize ) { void *pReturn; if ( nNewSize == 0 ) { VSIFree(pData); return NULL; } if( pData == NULL ) pReturn = VSIMalloc( nNewSize ); else pReturn = VSIRealloc( pData, nNewSize ); if( pReturn == NULL ) { CPLError( CE_Fatal, CPLE_OutOfMemory, "CPLRealloc(): Out of memory allocating %d bytes.\n", nNewSize ); } return pReturn; } /************************************************************************/ /* CPLStrdup() */ /************************************************************************/ /** * Safe version of strdup() function. * * This function is similar to the C library strdup() function, but if * the memory allocation fails it will issue a CE_Fatal error with * CPLError() instead of returning NULL. It uses VSIStrdup(), so any * hooking of that function will apply to CPLStrdup() as well. Memory * allocated with CPLStrdup() can be freed with CPLFree() or VSIFree(). * * It is also safe to pass a NULL string into CPLStrdup(). CPLStrdup() * will allocate and return a zero length string (as opposed to a NULL * string). * * @param pszString input string to be duplicated. May be NULL. * @return pointer to a newly allocated copy of the string. Free with * CPLFree() or VSIFree(). */ char *CPLStrdup( const char * pszString ) { char *pszReturn; if( pszString == NULL ) pszString = ""; pszReturn = VSIStrdup( pszString ); if( pszReturn == NULL ) { CPLError( CE_Fatal, CPLE_OutOfMemory, "CPLStrdup(): Out of memory allocating %d bytes.\n", strlen(pszString) ); } return( pszReturn ); } /************************************************************************/ /* CPLReadLine() */ /************************************************************************/ /** * Simplified line reading from text file. * * Read a line of text from the given file handle, taking care * to capture CR and/or LF and strip off ... equivelent of * DKReadLine(). Pointer to an internal buffer is returned. * The application shouldn't free it, or depend on it's value * past the next call to CPLReadLine(). * * Note that CPLReadLine() uses VSIFGets(), so any hooking of VSI file * services should apply to CPLReadLine() as well. * * @param fp file pointer opened with VSIFOpen(). * @return pointer to an internal buffer containing a line of text read * from the file or NULL if the end of file was encountered. */ const char *CPLReadLine( FILE * fp ) { static char *pszRLBuffer = NULL; static int nRLBufferSize = 0; int nLength, nReadSoFar = 0; /* -------------------------------------------------------------------- */ /* Loop reading chunks of the line till we get to the end of */ /* the line. */ /* -------------------------------------------------------------------- */ do { /* -------------------------------------------------------------------- */ /* Grow the working buffer if we have it nearly full. Fail out */ /* of read line if we can't reallocate it big enough (for */ /* instance for a _very large_ file with no newlines). */ /* -------------------------------------------------------------------- */ if( nRLBufferSize-nReadSoFar < 128 ) { nRLBufferSize = nRLBufferSize*2 + 128; pszRLBuffer = (char *) VSIRealloc(pszRLBuffer, nRLBufferSize); if( pszRLBuffer == NULL ) { nRLBufferSize = 0; return NULL; } } /* -------------------------------------------------------------------- */ /* Do the actual read. */ /* -------------------------------------------------------------------- */ if( VSIFGets( pszRLBuffer+nReadSoFar, nRLBufferSize-nReadSoFar, fp ) == NULL ) return NULL; nReadSoFar = strlen(pszRLBuffer); } while( nReadSoFar == nRLBufferSize - 1 && pszRLBuffer[nRLBufferSize-2] != 13 && pszRLBuffer[nRLBufferSize-2] != 10 ); /* -------------------------------------------------------------------- */ /* Clear CR and LF off the end. */ /* -------------------------------------------------------------------- */ nLength = strlen(pszRLBuffer); if( nLength > 0 && (pszRLBuffer[nLength-1] == 10 || pszRLBuffer[nLength-1] == 13) ) { pszRLBuffer[--nLength] = '\0'; } if( nLength > 0 && (pszRLBuffer[nLength-1] == 10 || pszRLBuffer[nLength-1] == 13) ) { pszRLBuffer[--nLength] = '\0'; } return( pszRLBuffer ); } avce00-2.0.0/cpl_error.c0100664000076400007640000003137210247751547014231 0ustar danieldaniel/********************************************************************** * $Id: cpl_error.c,v 1.3 2005/06/03 03:49:59 daniel Exp $ * * Name: cpl_error.cpp * Project: CPL - Common Portability Library * Purpose: Error handling functions. * Author: Daniel Morissette, dmorissette@dmsolutions.ca * ********************************************************************** * Copyright (c) 1998, Daniel Morissette * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ********************************************************************** * * $Log: cpl_error.c,v $ * Revision 1.3 2005/06/03 03:49:59 daniel * Update email address, website url, and copyright dates * * Revision 1.2 1999/11/23 04:18:45 daniel * Fixed var. initialization that failed to compile in C * * Revision 1.1 1999/08/27 14:09:55 daniel * Update CPL files * * Revision 1.8 1999/07/23 14:27:47 warmerda * CPLSetErrorHandler returns old handler * * Revision 1.7 1999/06/27 16:50:52 warmerda * added support for CPL_DEBUG and CPL_LOG variables * * Revision 1.6 1999/06/26 02:46:11 warmerda * Fixed initialization of debug messages. * * Revision 1.5 1999/05/20 14:59:05 warmerda * added CPLDebug() * * Revision 1.4 1999/05/20 02:54:38 warmerda * Added API documentation * * Revision 1.3 1998/12/15 19:02:27 warmerda * Avoid use of errno as a variable * * Revision 1.2 1998/12/06 02:52:52 warmerda * Implement assert support * * Revision 1.1 1998/12/03 18:26:02 warmerda * New * **********************************************************************/ #include "cpl_error.h" #include "cpl_vsi.h" /* static buffer to store the last error message. We'll assume that error * messages cannot be longer than 2000 chars... which is quite reasonable * (that's 25 lines of 80 chars!!!) */ static char gszCPLLastErrMsg[2000] = ""; static int gnCPLLastErrNo = 0; static void CPLDefaultErrorHandler( CPLErr, int, const char *); static CPLErrorHandler gpfnCPLErrorHandler = CPLDefaultErrorHandler; /********************************************************************** * CPLError() **********************************************************************/ /** * Report an error. * * This function reports an error in a manner that can be hooked * and reported appropriate by different applications. * * The effect of this function can be altered by applications by installing * a custom error handling using CPLSetErrorHandler(). * * The eErrClass argument can have the value CE_Warning indicating that the * message is an informational warning, CE_Failure indicating that the * action failed, but that normal recover mechanisms will be used or * CE_Fatal meaning that a fatal error has occured, and that CPLError() * should not return. * * The default behaviour of CPLError() is to report errors to stderr, * and to abort() after reporting a CE_Fatal error. It is expected that * some applications will want to supress error reporting, and will want to * install a C++ exception, or longjmp() approach to no local fatal error * recovery. * * Regardless of how application error handlers or the default error * handler choose to handle an error, the error number, and message will * be stored for recovery with CPLGetLastErrorNo() and CPLGetLastErrorMsg(). * * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal. * @param err_no the error number (CPLE_*) from cpl_error.h. * @param fmt a printf() style format string. Any additional arguments * will be treated as arguments to fill in this format in a manner * similar to printf(). */ void CPLError(CPLErr eErrClass, int err_no, const char *fmt, ...) { va_list args; /* Expand the error message */ va_start(args, fmt); vsprintf(gszCPLLastErrMsg, fmt, args); va_end(args); /* If the user provided his own error handling function, then call * it, otherwise print the error to stderr and return. */ gnCPLLastErrNo = err_no; if( gpfnCPLErrorHandler ) gpfnCPLErrorHandler(eErrClass, err_no, gszCPLLastErrMsg); if( eErrClass == CE_Fatal ) abort(); } /************************************************************************/ /* CPLDebug() */ /************************************************************************/ /** * Display a debugging message. * * The category argument is used in conjunction with the CPL_DEBUG * environment variable to establish if the message should be displayed. * If the CPL_DEBUG environment variable is not set, no debug messages * are emitted (use CPLError(CE_Warning,...) to ensure messages are displayed). * If CPL_DEBUG is set, but is an empty string or the word "ON" then all * debug messages are shown. Otherwise only messages whose category appears * somewhere within the CPL_DEBUG value are displayed (as determinted by * strstr()). * * Categories are usually an identifier for the subsystem producing the * error. For instance "GDAL" might be used for the GDAL core, and "TIFF" * for messages from the TIFF translator. * * @param pszCategory name of the debugging message category. * @param pszFormat printf() style format string for message to display. * Remaining arguments are assumed to be for format. */ void CPLDebug( const char * pszCategory, const char * pszFormat, ... ) { char *pszMessage; va_list args; const char *pszDebug = getenv("CPL_DEBUG"); /* -------------------------------------------------------------------- */ /* Does this message pass our current criteria? */ /* -------------------------------------------------------------------- */ if( pszDebug == NULL ) return; if( !EQUAL(pszDebug,"ON") && !EQUAL(pszDebug,"") ) { int i, nLen = strlen(pszCategory); for( i = 0; pszDebug[i] != '\0'; i++ ) { if( EQUALN(pszCategory,pszDebug+i,nLen) ) break; } if( pszDebug[i] == '\0' ) return; } /* -------------------------------------------------------------------- */ /* Format the error message */ /* -------------------------------------------------------------------- */ pszMessage = (char *) VSIMalloc(25000); if( pszMessage == NULL ) return; strcpy( pszMessage, pszCategory ); strcat( pszMessage, ": " ); va_start(args, pszFormat); vsprintf(pszMessage+strlen(pszMessage), pszFormat, args); va_end(args); /* -------------------------------------------------------------------- */ /* If the user provided his own error handling function, then call */ /* it, otherwise print the error to stderr and return. */ /* -------------------------------------------------------------------- */ if( gpfnCPLErrorHandler ) gpfnCPLErrorHandler(CE_Debug, CPLE_None, pszMessage); VSIFree( pszMessage ); } /********************************************************************** * CPLErrorReset() **********************************************************************/ /** * Erase any traces of previous errors. * * This is normally used to ensure that an error which has been recovered * from does not appear to be still in play with high level functions. */ void CPLErrorReset() { gnCPLLastErrNo = CPLE_None; gszCPLLastErrMsg[0] = '\0'; } /********************************************************************** * CPLGetLastErrorNo() **********************************************************************/ /** * Fetch the last error number. * * This is the error number, not the error class. * * @return the error number of the last error to occur, or CPLE_None (0) * if there are no posted errors. */ int CPLGetLastErrorNo() { return gnCPLLastErrNo; } /********************************************************************** * CPLGetLastErrorMsg() **********************************************************************/ /** * Get the last error message. * * Fetches the last error message posted with CPLError(), that hasn't * been cleared by CPLErrorReset(). The returned pointer is to an internal * string that should not be altered or freed. * * @return the last error message, or NULL if there is no posted error * message. */ const char* CPLGetLastErrorMsg() { return gszCPLLastErrMsg; } /************************************************************************/ /* CPLDefaultErrorHandler() */ /************************************************************************/ static void CPLDefaultErrorHandler( CPLErr eErrClass, int nError, const char * pszErrorMsg ) { static int bLogInit = FALSE; static FILE * fpLog; fpLog = stderr; if( !bLogInit ) { bLogInit = TRUE; if( getenv( "CPL_LOG" ) != NULL ) { fpLog = fopen( getenv("CPL_LOg"), "wt" ); if( fpLog == NULL ) fpLog = stderr; } } if( eErrClass == CE_Debug ) fprintf( fpLog, "%s\n", pszErrorMsg ); else if( eErrClass == CE_Warning ) fprintf( fpLog, "Warning %d: %s\n", nError, pszErrorMsg ); else fprintf( fpLog, "ERROR %d: %s\n", nError, pszErrorMsg ); fflush( fpLog ); } /********************************************************************** * CPLSetErrorHandler() **********************************************************************/ /** * Install custom error handler. * * Allow the library's user to specify his own error handler function. * A valid error handler is a C function with the following prototype: * *
 *     void MyErrorHandler(CPLErr eErrClass, int errno, const char *msg)
 * 
* * Pass NULL to come back to the default behavior. The default behaviour * is to write the message to * * The msg will be a partially formatted error message not containing the * "ERROR %d:" portion emitted by the default handler. Message formatting * is handled by CPLError() before calling the handler. If the error * handler function is passed a CE_Fatal class error and returns, then * CPLError() will call abort(). Applications wanting to interrupt this * fatal behaviour will have to use longjmp(), or a C++ exception to * indirectly exit the function. * * @param pfnErrorHandler new error handler function. * @return returns the previously installed error handler. */ CPLErrorHandler CPLSetErrorHandler( CPLErrorHandler pfnErrorHandler ) { CPLErrorHandler pfnOldHandler = gpfnCPLErrorHandler; gpfnCPLErrorHandler = pfnErrorHandler; return pfnOldHandler; } /************************************************************************/ /* _CPLAssert() */ /* */ /* This function is called only when an assertion fails. */ /************************************************************************/ /** * Report failure of a logical assertion. * * Applications would normally use the CPLAssert() macro which expands * into code calling _CPLAssert() only if the condition fails. _CPLAssert() * will generate a CE_Fatal error call to CPLError(), indicating the file * name, and line number of the failed assertion, as well as containing * the assertion itself. * * There is no reason for application code to call _CPLAssert() directly. */ void _CPLAssert( const char * pszExpression, const char * pszFile, int iLine ) { CPLError( CE_Fatal, CPLE_AssertionFailed, "Assertion `%s' failed\n" "in file `%s', line %d\n", pszExpression, pszFile, iLine ); } avce00-2.0.0/avc_bin.c0100664000076400007640000027375110471135752013645 0ustar danieldaniel/********************************************************************** * $Id: avc_bin.c,v 1.29 2006/08/17 18:56:42 dmorissette Exp $ * * Name: avc_bin.c * Project: Arc/Info vector coverage (AVC) BIN->E00 conversion library * Language: ANSI C * Purpose: Binary files access functions. * Author: Daniel Morissette, dmorissette@dmsolutions.ca * ********************************************************************** * Copyright (c) 1999-2005, Daniel Morissette * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ********************************************************************** * * $Log: avc_bin.c,v $ * Revision 1.29 2006/08/17 18:56:42 dmorissette * Support for reading standalone info tables (just tables, no coverage * data) by pointing AVCE00ReadOpen() to the info directory (bug 1549). * * Revision 1.28 2006/06/14 16:31:28 daniel * Added support for AVCCoverPC2 type (bug 1491) * * Revision 1.27 2005/06/03 03:49:58 daniel * Update email address, website url, and copyright dates * * Revision 1.26 2004/02/28 06:35:49 warmerda * Fixed AVCBinReadObject() index support to use 'x' or 'X' for index * depending on the case of the original name. * Fixed so that PC Arc/Info coverages with the extra 256 byte header work * properly when using indexes to read them. * http://bugzilla.remotesensing.org/show_bug.cgi?id=493 * * Revision 1.25 2004/02/11 05:49:44 daniel * Added support for deleted flag in arc.dir (bug 2332) * * Revision 1.24 2002/08/27 15:26:06 daniel * Removed C++ style comments for IRIX compiler (GDAL bug 192) * * Revision 1.23 2002/04/16 20:04:24 daniel * Use record size while reading ARC, PAL, CNT to skip junk bytes. (bug940) * * Revision 1.22 2002/03/18 19:03:37 daniel * Fixed AVCBinReadObject() for PAL objects (bug 848) * * Revision 1.21 2002/02/14 22:54:13 warmerda * added polygon and table support for random reading * * Revision 1.20 2002/02/13 20:35:24 warmerda * added AVCBinReadObject * * Revision 1.19 2001/11/25 22:01:23 daniel * Fixed order of args to AVCRawBinFSeek() in _AVCBinReadNextTableRec() * * Revision 1.18 2000/10/16 16:16:20 daniel * Accept TXT files in AVCCoverWeird that use both PC or V7 TXT structure * * Revision 1.17 2000/09/26 20:21:04 daniel * Added AVCCoverPC write * * Revision 1.16 2000/09/22 19:45:20 daniel * Switch to MIT-style license * * Revision 1.15 2000/09/20 15:09:34 daniel * Check for DAT/NIT fnames sometimes truncated to 8 chars in weird coverages * * Revision 1.14 2000/06/05 21:38:53 daniel * Handle precision field > 1000 in cover file header as meaning double prec. * * Revision 1.13 2000/05/29 15:31:30 daniel * Added Japanese DBCS support * * Revision 1.12 2000/02/14 17:22:36 daniel * Check file signature (9993 or 9994) when reading header. * * Revision 1.11 2000/02/02 04:24:52 daniel * Support double precision "weird" coverages * * Revision 1.10 2000/01/10 02:54:10 daniel * Added read support for "weird" coverages * * Revision 1.9 2000/01/07 07:11:51 daniel * Added support for reading PC Coverage TXT files * * Revision 1.8 1999/12/24 07:38:10 daniel * Added missing DBFClose() * * Revision 1.7 1999/12/24 07:18:34 daniel * Added PC Arc/Info coverages support * * Revision 1.6 1999/08/23 18:17:16 daniel * Modified AVCBinReadListTables() to return INFO fnames for DeleteCoverage() * * Revision 1.5 1999/05/11 01:49:08 daniel * Simple changes required by addition of coverage write support * * Revision 1.4 1999/03/03 18:42:53 daniel * Fixed problem with INFO table headers (arc.dir) that sometimes contain an * invalid number of records. * * Revision 1.3 1999/02/25 17:01:53 daniel * Added support for 16 bit integers in INFO tables (type=50, size=2) * * Revision 1.2 1999/02/25 03:41:28 daniel * Added TXT, TX6/TX7, RXP and RPL support * * Revision 1.1 1999/01/29 16:28:52 daniel * Initial revision * **********************************************************************/ #include "avc.h" #include /* for isspace() */ /*===================================================================== * Prototypes for some static functions *====================================================================*/ static AVCBinFile *_AVCBinReadOpenTable(const char *pszInfoPath, const char *pszTableName, AVCCoverType eCoverType, AVCDBCSInfo *psDBCSInfo); static AVCBinFile *_AVCBinReadOpenDBFTable(const char *pszInfoPath, const char *pszTableName); static AVCBinFile *_AVCBinReadOpenPrj(const char *pszPath,const char *pszName); static int _AVCBinReadNextTableRec(AVCRawBinFile *psFile, int nFields, AVCFieldInfo *pasDef, AVCField *pasFields, int nRecordSize); static int _AVCBinReadNextDBFTableRec(DBFHandle hDBFFile, int *piRecordIndex, int nFields, AVCFieldInfo *pasDef, AVCField *pasFields); /*===================================================================== * Stuff related to reading the binary coverage files *====================================================================*/ /********************************************************************** * AVCBinReadOpen() * * Open a coverage file for reading, read the file header if applicable, * and initialize a temp. storage structure to be ready to read objects * from the file. * * pszPath is the coverage (or info directory) path, terminated by * a '/' or a '\\' * pszName is the name of the file to open relative to this directory. * * Note: For most file types except tables, passing pszPath="" and * including the coverage path as part of pszName instead would work. * * Returns a valid AVCBinFile handle, or NULL if the file could * not be opened. * * AVCBinClose() will eventually have to be called to release the * resources used by the AVCBinFile structure. **********************************************************************/ AVCBinFile *AVCBinReadOpen(const char *pszPath, const char *pszName, AVCCoverType eCoverType, AVCFileType eFileType, AVCDBCSInfo *psDBCSInfo) { AVCBinFile *psFile; /*----------------------------------------------------------------- * The case of INFO tables is a bit more complicated... * pass the control to a separate function. *----------------------------------------------------------------*/ if (eFileType == AVCFileTABLE) { if (eCoverType == AVCCoverPC || eCoverType == AVCCoverPC2) return _AVCBinReadOpenDBFTable(pszPath, pszName); else return _AVCBinReadOpenTable(pszPath, pszName, eCoverType, psDBCSInfo); } /*----------------------------------------------------------------- * PRJ files are text files... we won't use the AVCRawBin*() * functions for them... *----------------------------------------------------------------*/ if (eFileType == AVCFilePRJ) { return _AVCBinReadOpenPrj(pszPath, pszName); } /*----------------------------------------------------------------- * All other file types share a very similar opening method. *----------------------------------------------------------------*/ psFile = (AVCBinFile*)CPLCalloc(1, sizeof(AVCBinFile)); psFile->eFileType = eFileType; psFile->eCoverType = eCoverType; psFile->pszFilename = (char*)CPLMalloc((strlen(pszPath)+strlen(pszName)+1)* sizeof(char)); sprintf(psFile->pszFilename, "%s%s", pszPath, pszName); AVCAdjustCaseSensitiveFilename(psFile->pszFilename); psFile->psRawBinFile = AVCRawBinOpen(psFile->pszFilename, "r", AVC_COVER_BYTE_ORDER(eCoverType), psDBCSInfo); if (psFile->psRawBinFile == NULL) { /* Failed to open file... just return NULL since an error message * has already been issued by AVCRawBinOpen() */ CPLFree(psFile->pszFilename); CPLFree(psFile); return NULL; } /*----------------------------------------------------------------- * Read the header, and set the precision field if applicable *----------------------------------------------------------------*/ if (AVCBinReadRewind(psFile) != 0) { CPLFree(psFile->pszFilename); CPLFree(psFile); return NULL; } /*----------------------------------------------------------------- * Allocate a temp. structure to use to read objects from the file * (Using Calloc() will automatically initialize the struct contents * to NULL... this is very important for ARCs and PALs) *----------------------------------------------------------------*/ if (psFile->eFileType == AVCFileARC) { psFile->cur.psArc = (AVCArc*)CPLCalloc(1, sizeof(AVCArc)); } else if (psFile->eFileType == AVCFilePAL || psFile->eFileType == AVCFileRPL ) { psFile->cur.psPal = (AVCPal*)CPLCalloc(1, sizeof(AVCPal)); } else if (psFile->eFileType == AVCFileCNT) { psFile->cur.psCnt = (AVCCnt*)CPLCalloc(1, sizeof(AVCCnt)); } else if (psFile->eFileType == AVCFileLAB) { psFile->cur.psLab = (AVCLab*)CPLCalloc(1, sizeof(AVCLab)); } else if (psFile->eFileType == AVCFileTOL) { psFile->cur.psTol = (AVCTol*)CPLCalloc(1, sizeof(AVCTol)); } else if (psFile->eFileType == AVCFileTXT || psFile->eFileType == AVCFileTX6) { psFile->cur.psTxt = (AVCTxt*)CPLCalloc(1, sizeof(AVCTxt)); } else if (psFile->eFileType == AVCFileRXP) { psFile->cur.psRxp = (AVCRxp*)CPLCalloc(1, sizeof(AVCRxp)); } else { CPLError(CE_Failure, CPLE_IllegalArg, "%s: Unsupported file type or corrupted file.", psFile->pszFilename); CPLFree(psFile->pszFilename); CPLFree(psFile); psFile = NULL; } return psFile; } /********************************************************************** * AVCBinReadClose() * * Close a coverage file, and release all memory (object strcut., buffers, * etc.) associated with this file. **********************************************************************/ void AVCBinReadClose(AVCBinFile *psFile) { AVCRawBinClose(psFile->psRawBinFile); psFile->psRawBinFile = NULL; CPLFree(psFile->pszFilename); psFile->pszFilename = NULL; if (psFile->hDBFFile) DBFClose(psFile->hDBFFile); if( psFile->psIndexFile != NULL ) AVCRawBinClose( psFile->psIndexFile ); if (psFile->eFileType == AVCFileARC) { if (psFile->cur.psArc) CPLFree(psFile->cur.psArc->pasVertices); CPLFree(psFile->cur.psArc); } else if (psFile->eFileType == AVCFilePAL || psFile->eFileType == AVCFileRPL ) { if (psFile->cur.psPal) CPLFree(psFile->cur.psPal->pasArcs); CPLFree(psFile->cur.psPal); } else if (psFile->eFileType == AVCFileCNT) { if (psFile->cur.psCnt) CPLFree(psFile->cur.psCnt->panLabelIds); CPLFree(psFile->cur.psCnt); } else if (psFile->eFileType == AVCFileLAB) { CPLFree(psFile->cur.psLab); } else if (psFile->eFileType == AVCFileTOL) { CPLFree(psFile->cur.psTol); } else if (psFile->eFileType == AVCFilePRJ) { CSLDestroy(psFile->cur.papszPrj); } else if (psFile->eFileType == AVCFileTXT || psFile->eFileType == AVCFileTX6) { if (psFile->cur.psTxt) { CPLFree(psFile->cur.psTxt->pasVertices); CPLFree(psFile->cur.psTxt->pszText); } CPLFree(psFile->cur.psTxt); } else if (psFile->eFileType == AVCFileRXP) { CPLFree(psFile->cur.psRxp); } else if (psFile->eFileType == AVCFileTABLE) { _AVCDestroyTableFields(psFile->hdr.psTableDef, psFile->cur.pasFields); _AVCDestroyTableDef(psFile->hdr.psTableDef); } else { CPLError(CE_Failure, CPLE_IllegalArg, "Unsupported file type or invalid file handle!"); } CPLFree(psFile); } /********************************************************************** * _AVCBinReadHeader() * * (This function is for internal library use... external calls should * go to AVCBinReadRewind() instead) * * Read the first 100 bytes header of the file and fill the AVCHeader * structure. * * Returns 0 on success or -1 on error. **********************************************************************/ int _AVCBinReadHeader(AVCRawBinFile *psFile, AVCBinHeader *psHeader, AVCCoverType eCoverType) { int nStatus = 0; /*----------------------------------------------------------------- * For AVCCoverPC coverages (files without hte .adf extension), * there is a first 256 bytes header that we just skip and that * precedes the 100 bytes header block. * * In AVCCoverV7, we only have the 100 bytes header. *----------------------------------------------------------------*/ if (eCoverType == AVCCoverPC) AVCRawBinFSeek(psFile, 256, SEEK_SET); else AVCRawBinFSeek(psFile, 0, SEEK_SET); psHeader->nSignature = AVCRawBinReadInt32(psFile); if (AVCRawBinEOF(psFile)) nStatus = -1; psHeader->nPrecision = AVCRawBinReadInt32(psFile); psHeader->nRecordSize= AVCRawBinReadInt32(psFile); /* Jump to 24th byte in header */ AVCRawBinFSeek(psFile, 12, SEEK_CUR); psHeader->nLength = AVCRawBinReadInt32(psFile); /*----------------------------------------------------------------- * File length, in words (16 bits)... pass the info to the RawBinFile * to prevent it from trying to read junk bytes at the end of files... * this problem happens specially with PC Arc/Info files. *----------------------------------------------------------------*/ if (eCoverType == AVCCoverPC) AVCRawBinSetFileDataSize(psFile, psHeader->nLength*2 + 256); else AVCRawBinSetFileDataSize(psFile, psHeader->nLength*2 ); /* Move the pointer at the end of the 100 bytes header */ AVCRawBinFSeek(psFile, 72, SEEK_CUR); return nStatus; } /********************************************************************** * AVCBinReadRewind() * * Rewind the read pointer, and read/skip the header if necessary so * that we are ready to read the data objects from the file after * this call. * * Returns 0 on success, -1 on error, and -2 if file has an invalid * signature and is possibly corrupted. **********************************************************************/ int AVCBinReadRewind(AVCBinFile *psFile) { AVCBinHeader sHeader; int nStatus=0; /*----------------------------------------------------------------- * For AVCCoverPC coverages, there is a first 256 bytes header * that we just skip and that precedes the 100 bytes header block. * * In AVCCoverV7, AVCCoverPC2 and AVCCoverWeird, we only find the * 100 bytes header. * * Note: it is the call to _AVCBinReadHeader() that takes care * of skipping the first 256 bytes header if necessary. *----------------------------------------------------------------*/ AVCRawBinFSeek(psFile->psRawBinFile, 0, SEEK_SET); if ( psFile->eFileType == AVCFileARC || psFile->eFileType == AVCFilePAL || psFile->eFileType == AVCFileRPL || psFile->eFileType == AVCFileCNT || psFile->eFileType == AVCFileLAB || psFile->eFileType == AVCFileTXT || psFile->eFileType == AVCFileTX6 ) { nStatus = _AVCBinReadHeader(psFile->psRawBinFile, &sHeader, psFile->eCoverType); /* Store the precision information inside the file handle. * * Of course, there had to be an exception... * At least PAL and TXT files in PC Arc/Info coverages sometimes * have a negative precision flag even if they contain single * precision data... why is that???? A PC Arc bug? * * 2000-06-05: Found a double-precision PAL file with a signature * of 1011 (should have been -11). So we'll assume * that signature > 1000 also means double precision. */ if ((sHeader.nPrecision < 0 || sHeader.nPrecision > 1000) && psFile->eCoverType != AVCCoverPC) psFile->nPrecision = AVC_DOUBLE_PREC; else psFile->nPrecision = AVC_SINGLE_PREC; /* Validate the signature value... this will allow us to detect * corrupted files or files that do not belong in the coverage. */ if (sHeader.nSignature != 9993 && sHeader.nSignature != 9994) { CPLError(CE_Warning, CPLE_AssertionFailed, "%s appears to have an invalid file header.", psFile->pszFilename); return -2; } /* In Weird coverages, TXT files can be stored in the PC or the V7 * format. Look at the 'precision' field in the header to tell which * type we have. * Weird TXT in PC format: nPrecision = 16 * Weird TXT in V7 format: nPrecision = +/-67 * Use AVCFileTXT for PC type, and AVCFileTX6 for V7 type. */ if (psFile->eCoverType == AVCCoverWeird && psFile->eFileType == AVCFileTXT && ABS(sHeader.nPrecision) == 67) { /* TXT file will be processed as V7 TXT/TX6/TX7 */ psFile->eFileType = AVCFileTX6; } } else if (psFile->eFileType == AVCFileTOL) { /*------------------------------------------------------------- * For some reason, the tolerance files do not follow the * general rules! * Single precision "tol.adf" have no header * Double precision "par.adf" have the usual 100 bytes header, * but the 3rd field, which usually defines the precision has * a positive value, even if the file is double precision! * * Also, we have a problem with PC Arc/Info TOL files since they * do not contain the first 256 bytes header either... so we will * just assume that double precision TOL files cannot exist in * PC Arc/Info coverages... this should be OK. *------------------------------------------------------------*/ int nSignature = 0; nSignature = AVCRawBinReadInt32(psFile->psRawBinFile); if (nSignature == 9993) { /* We have a double precision par.adf... read the 100 bytes * header and set the precision information inside the file * handle. */ nStatus = _AVCBinReadHeader(psFile->psRawBinFile, &sHeader, psFile->eCoverType); psFile->nPrecision = AVC_DOUBLE_PREC; } else { /* It's a single precision tol.adf ... just set the * precision field. */ AVCRawBinFSeek(psFile->psRawBinFile, 0, SEEK_SET); psFile->nPrecision = AVC_SINGLE_PREC; } } return nStatus; } /********************************************************************** * AVCBinReadObject() * * Read the object with a particular index. For fixed length record * files we seek directly to the object. For variable files we try to * get the offset from the corresponding index file. * * NOTE: Currently only implemented for ARC, PAL and TABLE files. * * Returns the read object on success or NULL on error. **********************************************************************/ void *AVCBinReadObject(AVCBinFile *psFile, int iObjIndex ) { int bIndexed = FALSE; int nObjectOffset, nRecordSize=0, nRecordStart = 0, nLen; char *pszExt = NULL; if( iObjIndex < 0 ) return NULL; /*----------------------------------------------------------------- * Determine some information from based on the coverage type. *----------------------------------------------------------------*/ nLen = strlen(psFile->pszFilename); if( psFile->eFileType == AVCFileARC && ((nLen>=3 && EQUALN((pszExt=psFile->pszFilename+nLen-3), "arc", 3)) || (nLen>=7 && EQUALN((pszExt=psFile->pszFilename+nLen-7),"arc.adf",7)))) { bIndexed = TRUE; } else if( psFile->eFileType == AVCFilePAL && ((nLen>=3 && EQUALN((pszExt=psFile->pszFilename+nLen-3), "pal", 3)) || (nLen>=7 && EQUALN((pszExt=psFile->pszFilename+nLen-7),"pal.adf",7)))) { bIndexed = TRUE; } else if( psFile->eFileType == AVCFileTABLE ) { bIndexed = FALSE; nRecordSize = psFile->hdr.psTableDef->nRecSize; nRecordStart = 0; } else return NULL; /*----------------------------------------------------------------- * Ensure the index file is opened if an index file is required. *----------------------------------------------------------------*/ if( bIndexed && psFile->psIndexFile == NULL ) { char chOrig; if( pszExt == NULL ) return NULL; chOrig = pszExt[2]; if( chOrig > 'A' && chOrig < 'Z' ) pszExt[2] = 'X'; else pszExt[2] = 'x'; psFile->psIndexFile = AVCRawBinOpen( psFile->pszFilename, "rb", psFile->psRawBinFile->eByteOrder, psFile->psRawBinFile->psDBCSInfo); pszExt[2] = chOrig; if( psFile->psIndexFile == NULL ) return NULL; } /*----------------------------------------------------------------- * Establish the offset to read the object from. *----------------------------------------------------------------*/ if( bIndexed ) { int nIndexOffset; if (psFile->eCoverType == AVCCoverPC) nIndexOffset = 356 + (iObjIndex-1)*8; else nIndexOffset = 100 + (iObjIndex-1)*8; AVCRawBinFSeek( psFile->psIndexFile, nIndexOffset, SEEK_SET ); if( AVCRawBinEOF( psFile->psIndexFile ) ) return NULL; nObjectOffset = AVCRawBinReadInt32( psFile->psIndexFile ); nObjectOffset *= 2; if (psFile->eCoverType == AVCCoverPC) nObjectOffset += 256; } else nObjectOffset = nRecordStart + nRecordSize * (iObjIndex-1); /*----------------------------------------------------------------- * Seek to the start of the object in the data file. *----------------------------------------------------------------*/ AVCRawBinFSeek( psFile->psRawBinFile, nObjectOffset, SEEK_SET ); if( AVCRawBinEOF( psFile->psRawBinFile ) ) return NULL; /*----------------------------------------------------------------- * Read and return the object. *----------------------------------------------------------------*/ return AVCBinReadNextObject( psFile ); } /********************************************************************** * AVCBinReadNextObject() * * Read the next structure from the file. This function is just a generic * cover on top of the AVCBinReadNextArc/Lab/Pal/Cnt() functions. * * Returns a (void*) to a static structure with the contents of the object * that was read. The contents of the structure will be valid only until * the next call. * If you use the returned value, then make sure that you cast it to * the right type for the current file! (AVCArc, AVCPal, AVCCnt, ...) * * Returns NULL if an error happened or if EOF was reached. **********************************************************************/ void *AVCBinReadNextObject(AVCBinFile *psFile) { void *psObj = NULL; switch(psFile->eFileType) { case AVCFileARC: psObj = (void*)AVCBinReadNextArc(psFile); break; case AVCFilePAL: case AVCFileRPL: psObj = (void*)AVCBinReadNextPal(psFile); break; case AVCFileCNT: psObj = (void*)AVCBinReadNextCnt(psFile); break; case AVCFileLAB: psObj = (void*)AVCBinReadNextLab(psFile); break; case AVCFileTOL: psObj = (void*)AVCBinReadNextTol(psFile); break; case AVCFileTXT: case AVCFileTX6: psObj = (void*)AVCBinReadNextTxt(psFile); break; case AVCFileRXP: psObj = (void*)AVCBinReadNextRxp(psFile); break; case AVCFileTABLE: psObj = (void*)AVCBinReadNextTableRec(psFile); break; default: CPLError(CE_Failure, CPLE_IllegalArg, "AVCBinReadNextObject(): Unsupported file type!"); } return psObj; } /********************************************************************** * AVCBinReadNextTableRec() * * Reads the next record from an attribute table. * * Returns a pointer to an array of static AVCField structure whose * contents will be valid only until the next call, * or NULL if an error happened or if EOF was reached. **********************************************************************/ AVCField *AVCBinReadNextTableRec(AVCBinFile *psFile) { if (psFile->eCoverType != AVCCoverPC && psFile->eCoverType != AVCCoverPC2 && psFile->eFileType == AVCFileTABLE && psFile->hdr.psTableDef->numRecords > 0 && ! AVCRawBinEOF(psFile->psRawBinFile) && _AVCBinReadNextTableRec(psFile->psRawBinFile, psFile->hdr.psTableDef->numFields, psFile->hdr.psTableDef->pasFieldDef, psFile->cur.pasFields, psFile->hdr.psTableDef->nRecSize) == 0 ) { return psFile->cur.pasFields; } else if ((psFile->eCoverType == AVCCoverPC || psFile->eCoverType == AVCCoverPC2 ) && psFile->eFileType == AVCFileTABLE && psFile->hdr.psTableDef->numRecords > 0 && _AVCBinReadNextDBFTableRec(psFile->hDBFFile, &(psFile->nCurDBFRecord), psFile->hdr.psTableDef->numFields, psFile->hdr.psTableDef->pasFieldDef, psFile->cur.pasFields) == 0) { return psFile->cur.pasFields; } return NULL; } /*===================================================================== * ARC *====================================================================*/ /********************************************************************** * _AVCBinReadNextArc() * * (This function is for internal library use... external calls should * go to AVCBinReadNextArc() instead) * * Read the next Arc structure from the file. * * The contents of the psArc structure is assumed to be valid, and the * psArc->pasVertices buffer may be reallocated or free()'d if it is not * NULL. * * Returns 0 on success or -1 on error. **********************************************************************/ int _AVCBinReadNextArc(AVCRawBinFile *psFile, AVCArc *psArc, int nPrecision) { int i, numVertices; int nRecordSize, nStartPos, nBytesRead; psArc->nArcId = AVCRawBinReadInt32(psFile); if (AVCRawBinEOF(psFile)) return -1; nRecordSize = AVCRawBinReadInt32(psFile) * 2; nStartPos = psFile->nCurPos+psFile->nOffset; psArc->nUserId = AVCRawBinReadInt32(psFile); psArc->nFNode = AVCRawBinReadInt32(psFile); psArc->nTNode = AVCRawBinReadInt32(psFile); psArc->nLPoly = AVCRawBinReadInt32(psFile); psArc->nRPoly = AVCRawBinReadInt32(psFile); numVertices = AVCRawBinReadInt32(psFile); /* Realloc the vertices array only if it needs to grow... * do not realloc to a smaller size. * Note that for simplicity reasons, we always store the vertices as * double values in memory, even for single precision coverages. */ if (psArc->pasVertices == NULL || numVertices > psArc->numVertices) psArc->pasVertices = (AVCVertex*)CPLRealloc(psArc->pasVertices, numVertices*sizeof(AVCVertex)); psArc->numVertices = numVertices; if (nPrecision == AVC_SINGLE_PREC) { for(i=0; ipasVertices[i].x = AVCRawBinReadFloat(psFile); psArc->pasVertices[i].y = AVCRawBinReadFloat(psFile); } } else { for(i=0; ipasVertices[i].x = AVCRawBinReadDouble(psFile); psArc->pasVertices[i].y = AVCRawBinReadDouble(psFile); } } /*----------------------------------------------------------------- * Record size may be larger than number of vertices. Skip up to * start of next object. *----------------------------------------------------------------*/ nBytesRead = (psFile->nCurPos + psFile->nOffset) - nStartPos; if ( nBytesRead < nRecordSize) AVCRawBinFSeek(psFile, nRecordSize - nBytesRead, SEEK_CUR); return 0; } /********************************************************************** * AVCBinReadNextArc() * * Read the next Arc structure from the file. * * Returns a pointer to a static AVCArc structure whose contents will be * valid only until the next call or NULL if an error happened or if EOF * was reached. **********************************************************************/ AVCArc *AVCBinReadNextArc(AVCBinFile *psFile) { if (psFile->eFileType != AVCFileARC || AVCRawBinEOF(psFile->psRawBinFile) || _AVCBinReadNextArc(psFile->psRawBinFile, psFile->cur.psArc, psFile->nPrecision) !=0) { return NULL; } return psFile->cur.psArc; } /*===================================================================== * PAL *====================================================================*/ /********************************************************************** * _AVCBinReadNextPal() * * (This function is for internal library use... external calls should * go to AVCBinReadNextPal() instead) * * Read the next PAL (Polygon Arc List) structure from the file. * * The contents of the psPal structure is assumed to be valid, and the * psPal->paVertices buffer may be reallocated or free()'d if it is not * NULL. * * Returns 0 on success or -1 on error. **********************************************************************/ int _AVCBinReadNextPal(AVCRawBinFile *psFile, AVCPal *psPal, int nPrecision) { int i, numArcs; int nRecordSize, nStartPos, nBytesRead; psPal->nPolyId = AVCRawBinReadInt32(psFile); nRecordSize = AVCRawBinReadInt32(psFile) * 2; nStartPos = psFile->nCurPos+psFile->nOffset; if (AVCRawBinEOF(psFile)) return -1; if (nPrecision == AVC_SINGLE_PREC) { psPal->sMin.x = AVCRawBinReadFloat(psFile); psPal->sMin.y = AVCRawBinReadFloat(psFile); psPal->sMax.x = AVCRawBinReadFloat(psFile); psPal->sMax.y = AVCRawBinReadFloat(psFile); } else { psPal->sMin.x = AVCRawBinReadDouble(psFile); psPal->sMin.y = AVCRawBinReadDouble(psFile); psPal->sMax.x = AVCRawBinReadDouble(psFile); psPal->sMax.y = AVCRawBinReadDouble(psFile); } numArcs = AVCRawBinReadInt32(psFile); /* Realloc the arc list array only if it needs to grow... * do not realloc to a smaller size. */ if (psPal->pasArcs == NULL || numArcs > psPal->numArcs) psPal->pasArcs = (AVCPalArc*)CPLRealloc(psPal->pasArcs, numArcs*sizeof(AVCPalArc)); psPal->numArcs = numArcs; for(i=0; ipasArcs[i].nArcId = AVCRawBinReadInt32(psFile); psPal->pasArcs[i].nFNode = AVCRawBinReadInt32(psFile); psPal->pasArcs[i].nAdjPoly = AVCRawBinReadInt32(psFile); } /*----------------------------------------------------------------- * Record size may be larger than number of vertices. Skip up to * start of next object. *----------------------------------------------------------------*/ nBytesRead = (psFile->nCurPos + psFile->nOffset) - nStartPos; if ( nBytesRead < nRecordSize) AVCRawBinFSeek(psFile, nRecordSize - nBytesRead, SEEK_CUR); return 0; } /********************************************************************** * AVCBinReadNextPal() * * Read the next PAL structure from the file. * * Returns a pointer to a static AVCPal structure whose contents will be * valid only until the next call or NULL if an error happened or if EOF * was reached. **********************************************************************/ AVCPal *AVCBinReadNextPal(AVCBinFile *psFile) { if ((psFile->eFileType!=AVCFilePAL && psFile->eFileType!=AVCFileRPL) || AVCRawBinEOF(psFile->psRawBinFile) || _AVCBinReadNextPal(psFile->psRawBinFile, psFile->cur.psPal, psFile->nPrecision) !=0) { return NULL; } return psFile->cur.psPal; } /*===================================================================== * CNT *====================================================================*/ /********************************************************************** * _AVCBinReadNextCnt() * * (This function is for internal library use... external calls should * go to AVCBinReadNextCnt() instead) * * Read the next CNT (Polygon Centroid) structure from the file. * * Returns 0 on success or -1 on error. **********************************************************************/ int _AVCBinReadNextCnt(AVCRawBinFile *psFile, AVCCnt *psCnt, int nPrecision) { int i, numLabels; int nRecordSize, nStartPos, nBytesRead; psCnt->nPolyId = AVCRawBinReadInt32(psFile); nRecordSize = AVCRawBinReadInt32(psFile) * 2; nStartPos = psFile->nCurPos+psFile->nOffset; if (AVCRawBinEOF(psFile)) return -1; if (nPrecision == AVC_SINGLE_PREC) { psCnt->sCoord.x = AVCRawBinReadFloat(psFile); psCnt->sCoord.y = AVCRawBinReadFloat(psFile); } else { psCnt->sCoord.x = AVCRawBinReadDouble(psFile); psCnt->sCoord.y = AVCRawBinReadDouble(psFile); } numLabels = AVCRawBinReadInt32(psFile); /* Realloc the LabelIds array only if it needs to grow... * do not realloc to a smaller size. */ if (psCnt->panLabelIds == NULL || numLabels > psCnt->numLabels) psCnt->panLabelIds = (GInt32 *)CPLRealloc(psCnt->panLabelIds, numLabels*sizeof(GInt32)); psCnt->numLabels = numLabels; for(i=0; ipanLabelIds[i] = AVCRawBinReadInt32(psFile); } /*----------------------------------------------------------------- * Record size may be larger than number of vertices. Skip up to * start of next object. *----------------------------------------------------------------*/ nBytesRead = (psFile->nCurPos + psFile->nOffset) - nStartPos; if ( nBytesRead < nRecordSize) AVCRawBinFSeek(psFile, nRecordSize - nBytesRead, SEEK_CUR); return 0; } /********************************************************************** * AVCBinReadNextCnt() * * Read the next CNT structure from the file. * * Returns a pointer to a static AVCCnt structure whose contents will be * valid only until the next call or NULL if an error happened or if EOF * was reached. **********************************************************************/ AVCCnt *AVCBinReadNextCnt(AVCBinFile *psFile) { if (psFile->eFileType != AVCFileCNT || AVCRawBinEOF(psFile->psRawBinFile) || _AVCBinReadNextCnt(psFile->psRawBinFile, psFile->cur.psCnt, psFile->nPrecision) !=0) { return NULL; } return psFile->cur.psCnt; } /*===================================================================== * LAB *====================================================================*/ /********************************************************************** * _AVCBinReadNextLab() * * (This function is for internal library use... external calls should * go to AVCBinReadNextLab() instead) * * Read the next LAB (Centroid Label) structure from the file. * * Returns 0 on success or -1 on error. **********************************************************************/ int _AVCBinReadNextLab(AVCRawBinFile *psFile, AVCLab *psLab, int nPrecision) { psLab->nValue = AVCRawBinReadInt32(psFile); psLab->nPolyId = AVCRawBinReadInt32(psFile); if (AVCRawBinEOF(psFile)) return -1; if (nPrecision == AVC_SINGLE_PREC) { psLab->sCoord1.x = AVCRawBinReadFloat(psFile); psLab->sCoord1.y = AVCRawBinReadFloat(psFile); psLab->sCoord2.x = AVCRawBinReadFloat(psFile); psLab->sCoord2.y = AVCRawBinReadFloat(psFile); psLab->sCoord3.x = AVCRawBinReadFloat(psFile); psLab->sCoord3.y = AVCRawBinReadFloat(psFile); } else { psLab->sCoord1.x = AVCRawBinReadDouble(psFile); psLab->sCoord1.y = AVCRawBinReadDouble(psFile); psLab->sCoord2.x = AVCRawBinReadDouble(psFile); psLab->sCoord2.y = AVCRawBinReadDouble(psFile); psLab->sCoord3.x = AVCRawBinReadDouble(psFile); psLab->sCoord3.y = AVCRawBinReadDouble(psFile); } return 0; } /********************************************************************** * AVCBinReadNextLab() * * Read the next LAB structure from the file. * * Returns a pointer to a static AVCLab structure whose contents will be * valid only until the next call or NULL if an error happened or if EOF * was reached. **********************************************************************/ AVCLab *AVCBinReadNextLab(AVCBinFile *psFile) { if (psFile->eFileType != AVCFileLAB || AVCRawBinEOF(psFile->psRawBinFile) || _AVCBinReadNextLab(psFile->psRawBinFile, psFile->cur.psLab, psFile->nPrecision) !=0) { return NULL; } return psFile->cur.psLab; } /*===================================================================== * TOL *====================================================================*/ /********************************************************************** * _AVCBinReadNextTol() * * (This function is for internal library use... external calls should * go to AVCBinReadNextTol() instead) * * Read the next TOL (tolerance) structure from the file. * * Returns 0 on success or -1 on error. **********************************************************************/ int _AVCBinReadNextTol(AVCRawBinFile *psFile, AVCTol *psTol, int nPrecision) { psTol->nIndex = AVCRawBinReadInt32(psFile); psTol->nFlag = AVCRawBinReadInt32(psFile); if (AVCRawBinEOF(psFile)) return -1; if (nPrecision == AVC_SINGLE_PREC) { psTol->dValue = AVCRawBinReadFloat(psFile); } else { psTol->dValue = AVCRawBinReadDouble(psFile); } return 0; } /********************************************************************** * AVCBinReadNextTol() * * Read the next TOL structure from the file. * * Returns a pointer to a static AVCTol structure whose contents will be * valid only until the next call or NULL if an error happened or if EOF * was reached. **********************************************************************/ AVCTol *AVCBinReadNextTol(AVCBinFile *psFile) { if (psFile->eFileType != AVCFileTOL || AVCRawBinEOF(psFile->psRawBinFile) || _AVCBinReadNextTol(psFile->psRawBinFile, psFile->cur.psTol, psFile->nPrecision) !=0) { return NULL; } return psFile->cur.psTol; } /*===================================================================== * PRJ *====================================================================*/ /********************************************************************** * _AVCBinReadOpenPrj() * * (This function is for internal library use... external calls should * go to AVCBinReadOpen() with type AVCFilePRJ instead) * * Open a PRJ file. * * This call will actually read the whole PRJ file in memory since PRJ * files are small text files. **********************************************************************/ AVCBinFile *_AVCBinReadOpenPrj(const char *pszPath, const char *pszName) { AVCBinFile *psFile; char *pszFname, **papszPrj; /*----------------------------------------------------------------- * Load the PRJ file contents into a stringlist. *----------------------------------------------------------------*/ pszFname = (char*)CPLMalloc((strlen(pszPath)+strlen(pszName)+1)* sizeof(char)); sprintf(pszFname, "%s%s", pszPath, pszName); papszPrj = CSLLoad(pszFname); CPLFree(pszFname); if (papszPrj == NULL) { /* Failed to open file... just return NULL since an error message * has already been issued by CSLLoad() */ return NULL; } /*----------------------------------------------------------------- * Alloc and init the AVCBinFile handle. *----------------------------------------------------------------*/ psFile = (AVCBinFile*)CPLCalloc(1, sizeof(AVCBinFile)); psFile->eFileType = AVCFilePRJ; psFile->psRawBinFile = NULL; psFile->cur.papszPrj = papszPrj; psFile->pszFilename = NULL; return psFile; } /********************************************************************** * AVCBinReadPrj() * * Return the contents of the previously opened PRJ (projection) file. * * PRJ files are simple text files with variable length lines, so we * don't use the AVCRawBin*() functions for this case. * * Returns a reference to a static stringlist with the whole file * contents, or NULL in case of error. * * The returned stringlist should NOT be freed by the caller. **********************************************************************/ char **AVCBinReadNextPrj(AVCBinFile *psFile) { /*----------------------------------------------------------------- * The file should have already been loaded by AVCBinFileOpen(), * so there is not much to do here! *----------------------------------------------------------------*/ return psFile->cur.papszPrj; } /*===================================================================== * TXT/TX6/TX7 *====================================================================*/ /********************************************************************** * _AVCBinReadNextTxt() * * (This function is for internal library use... external calls should * go to AVCBinReadNextTxt() instead) * * Read the next TXT/TX6/TX7 (Annotation) structure from the file. * * Returns 0 on success or -1 on error. **********************************************************************/ int _AVCBinReadNextTxt(AVCRawBinFile *psFile, AVCTxt *psTxt, int nPrecision) { int i, numVerticesBefore, numVertices, numCharsToRead, nRecordSize; int numBytesRead; numVerticesBefore = ABS(psTxt->numVerticesLine) + ABS(psTxt->numVerticesArrow); psTxt->nTxtId = AVCRawBinReadInt32(psFile); if (AVCRawBinEOF(psFile)) return -1; nRecordSize = 8 + 2*AVCRawBinReadInt32(psFile); psTxt->nUserId = AVCRawBinReadInt32(psFile); psTxt->nLevel = AVCRawBinReadInt32(psFile); psTxt->f_1e2 = AVCRawBinReadFloat(psFile); psTxt->nSymbol = AVCRawBinReadInt32(psFile); psTxt->numVerticesLine = AVCRawBinReadInt32(psFile); psTxt->n28 = AVCRawBinReadInt32(psFile); psTxt->numChars = AVCRawBinReadInt32(psFile); psTxt->numVerticesArrow = AVCRawBinReadInt32(psFile); for(i=0; i<20; i++) { psTxt->anJust1[i] = AVCRawBinReadInt16(psFile); } for(i=0; i<20; i++) { psTxt->anJust2[i] = AVCRawBinReadInt16(psFile); } if (nPrecision == AVC_SINGLE_PREC) { psTxt->dHeight = AVCRawBinReadFloat(psFile); psTxt->dV2 = AVCRawBinReadFloat(psFile); psTxt->dV3 = AVCRawBinReadFloat(psFile); } else { psTxt->dHeight = AVCRawBinReadDouble(psFile); psTxt->dV2 = AVCRawBinReadDouble(psFile); psTxt->dV3 = AVCRawBinReadDouble(psFile); } numCharsToRead = ((int)(psTxt->numChars + 3)/4)*4; if (psTxt->pszText == NULL || ((int)(strlen(psTxt->pszText)+3)/4)*4 < numCharsToRead ) { psTxt->pszText = (char*)CPLRealloc(psTxt->pszText, (numCharsToRead+1)*sizeof(char)); } AVCRawBinReadString(psFile, numCharsToRead, psTxt->pszText); psTxt->pszText[psTxt->numChars] = '\0'; /* Realloc the vertices array only if it needs to grow... * do not realloc to a smaller size. */ numVertices = ABS(psTxt->numVerticesLine) + ABS(psTxt->numVerticesArrow); if (psTxt->pasVertices == NULL || numVertices > numVerticesBefore) psTxt->pasVertices = (AVCVertex*)CPLRealloc(psTxt->pasVertices, numVertices*sizeof(AVCVertex)); if (nPrecision == AVC_SINGLE_PREC) { for(i=0; ipasVertices[i].x = AVCRawBinReadFloat(psFile); psTxt->pasVertices[i].y = AVCRawBinReadFloat(psFile); } } else { for(i=0; ipasVertices[i].x = AVCRawBinReadDouble(psFile); psTxt->pasVertices[i].y = AVCRawBinReadDouble(psFile); } } /* In V7 Coverages, we always have 8 bytes of junk at end of record. * In Weird coverages, these 8 bytes are sometimes present, and * sometimes not!!! (Probably another AI "random feature"! ;-) * So we use the record size to establish if there is any junk to skip */ if (nPrecision == AVC_SINGLE_PREC) numBytesRead = 132 + numCharsToRead + numVertices * 2 * 4; else numBytesRead = 144 + numCharsToRead + numVertices * 2 * 8; if (numBytesRead < nRecordSize) AVCRawBinFSeek(psFile, nRecordSize - numBytesRead, SEEK_CUR); return 0; } /********************************************************************** * _AVCBinReadNextPCCoverageTxt() * * (This function is for internal library use... external calls should * go to AVCBinReadNextTxt() instead) * * Read the next TXT (Annotation) structure from a PC Coverage file. * Note that it is assumed that PC Coverage files are always single * precision. * * Returns 0 on success or -1 on error. **********************************************************************/ int _AVCBinReadNextPCCoverageTxt(AVCRawBinFile *psFile, AVCTxt *psTxt, int nPrecision) { int i, numVerticesBefore, numVertices, numCharsToRead, nRecordSize; numVerticesBefore = ABS(psTxt->numVerticesLine) + ABS(psTxt->numVerticesArrow); psTxt->nTxtId = AVCRawBinReadInt32(psFile); if (AVCRawBinEOF(psFile)) return -1; nRecordSize = 8 + 2*AVCRawBinReadInt32(psFile); psTxt->nUserId = 0; psTxt->nLevel = AVCRawBinReadInt32(psFile); psTxt->numVerticesLine = AVCRawBinReadInt32(psFile); /* We are not expecting more than 4 vertices */ psTxt->numVerticesLine = MIN(psTxt->numVerticesLine, 4); psTxt->numVerticesArrow = 0; /* Realloc the vertices array only if it needs to grow... * do not realloc to a smaller size. * * Note that because of the way V7 binary TXT files work, the rest of the * lib expects to receive duplicate coords for the first vertex, so * we have to include an additional vertex for that. */ psTxt->numVerticesLine += 1; numVertices = ABS(psTxt->numVerticesLine) + ABS(psTxt->numVerticesArrow); if (psTxt->pasVertices == NULL || numVertices > numVerticesBefore) psTxt->pasVertices = (AVCVertex*)CPLRealloc(psTxt->pasVertices, numVertices*sizeof(AVCVertex)); for(i=1; ipasVertices[i].x = AVCRawBinReadFloat(psFile); psTxt->pasVertices[i].y = AVCRawBinReadFloat(psFile); } else { psTxt->pasVertices[i].x = AVCRawBinReadDouble(psFile); psTxt->pasVertices[i].y = AVCRawBinReadDouble(psFile); } } /* Duplicate the first vertex because that's the way the other binary TXT * files work and that's what the lib expects to generate the E00. */ psTxt->pasVertices[0].x = psTxt->pasVertices[1].x; psTxt->pasVertices[0].y = psTxt->pasVertices[1].y; /* Skip the other floats (vertices) that are unused */ if (nPrecision == AVC_SINGLE_PREC) AVCRawBinFSeek(psFile, 4*(15-2*(numVertices-1)) , SEEK_CUR); else AVCRawBinFSeek(psFile, 8*(15-2*(numVertices-1)) , SEEK_CUR); if (nPrecision == AVC_SINGLE_PREC) { psTxt->dHeight = AVCRawBinReadFloat(psFile); } else { psTxt->dHeight = AVCRawBinReadDouble(psFile); } psTxt->f_1e2 = AVCRawBinReadFloat(psFile); psTxt->nSymbol = AVCRawBinReadInt32(psFile); psTxt->numChars = AVCRawBinReadInt32(psFile); /* In some cases, we may need to skip additional spaces after the * text string... more than should be required to simply align with * a 4 bytes boundary... include that in numCharsToRead */ if (nPrecision == AVC_SINGLE_PREC) { numCharsToRead = nRecordSize - (28 + 16*4); } else { numCharsToRead = nRecordSize - (28 + 16*8); } /* Do a quick check in case file is corrupt! */ psTxt->numChars = MIN(psTxt->numChars, numCharsToRead); if (psTxt->pszText == NULL || ((int)(strlen(psTxt->pszText)+3)/4)*4 < numCharsToRead ) { psTxt->pszText = (char*)CPLRealloc(psTxt->pszText, (numCharsToRead+5)*sizeof(char)); } AVCRawBinReadString(psFile, numCharsToRead, psTxt->pszText); psTxt->pszText[psTxt->numChars] = '\0'; /* Set unused members to default values... */ psTxt->dV2 = 0.0; psTxt->dV3 = 0.0; psTxt->n28 = 0; for(i=0; i<20; i++) { psTxt->anJust1[i] = 0; psTxt->anJust2[i] = 0; } return 0; } /********************************************************************** * AVCBinReadNextTxt() * * Read the next TXT/TX6/TX7 structure from the file. * * Returns a pointer to a static AVCTxt structure whose contents will be * valid only until the next call or NULL if an error happened or if EOF * was reached. **********************************************************************/ AVCTxt *AVCBinReadNextTxt(AVCBinFile *psFile) { int nStatus = 0; if ((psFile->eFileType != AVCFileTXT && psFile->eFileType != AVCFileTX6) || AVCRawBinEOF(psFile->psRawBinFile) ) { return NULL; } /* AVCCoverPC have a different TXT format than AVCCoverV7 * * Note: Some Weird coverages use the PC TXT structure, and some use the * V7 structure. We distinguish them using the header's precision * field in AVCBinReadRewind(). */ if (psFile->eFileType == AVCFileTXT && (psFile->eCoverType == AVCCoverPC || psFile->eCoverType == AVCCoverWeird) ) { /* TXT file in PC Coverages (and some Weird Coverages) */ nStatus = _AVCBinReadNextPCCoverageTxt(psFile->psRawBinFile, psFile->cur.psTxt, psFile->nPrecision); } else { /* TXT in V7 Coverages (and some Weird Coverages), and TX6/TX7 in * all coverage types */ nStatus = _AVCBinReadNextTxt(psFile->psRawBinFile, psFile->cur.psTxt, psFile->nPrecision); } if (nStatus != 0) { return NULL; } return psFile->cur.psTxt; } /*===================================================================== * RXP *====================================================================*/ /********************************************************************** * _AVCBinReadNextRxp() * * (This function is for internal library use... external calls should * go to AVCBinReadNextRxp() instead) * * Read the next RXP (Region something...) structure from the file. * * Returns 0 on success or -1 on error. **********************************************************************/ int _AVCBinReadNextRxp(AVCRawBinFile *psFile, AVCRxp *psRxp, int nPrecision) { psRxp->n1 = AVCRawBinReadInt32(psFile); if (AVCRawBinEOF(psFile)) return -1; psRxp->n2 = AVCRawBinReadInt32(psFile); return 0; } /********************************************************************** * AVCBinReadNextRxp() * * Read the next RXP structure from the file. * * Returns a pointer to a static AVCRxp structure whose contents will be * valid only until the next call or NULL if an error happened or if EOF * was reached. **********************************************************************/ AVCRxp *AVCBinReadNextRxp(AVCBinFile *psFile) { if (psFile->eFileType != AVCFileRXP || AVCRawBinEOF(psFile->psRawBinFile) || _AVCBinReadNextRxp(psFile->psRawBinFile, psFile->cur.psRxp, psFile->nPrecision) !=0) { return NULL; } return psFile->cur.psRxp; } /*===================================================================== * NATIVE (V7.x) TABLEs * * Note: Also applies to AVCCoverWeird *====================================================================*/ /********************************************************************** * _AVCBinReadNextArcDir() * * (This function is for internal library use... external calls should * go to AVCBinReadOpen() with type AVCFileTABLE instead) * * Read the next record from an arc.dir (or "arcdr9") file. * * Note that arc.dir files have no header... they start with the * first record immediately. * * Returns 0 on success or -1 on error. **********************************************************************/ int _AVCBinReadNextArcDir(AVCRawBinFile *psFile, AVCTableDef *psArcDir) { int i; /* Arc/Info Table name */ AVCRawBinReadString(psFile, 32, psArcDir->szTableName); psArcDir->szTableName[32] = '\0'; if (AVCRawBinEOF(psFile)) return -1; /* "ARC####" basename for .DAT and .NIT files */ AVCRawBinReadString(psFile, 8, psArcDir->szInfoFile); psArcDir->szInfoFile[7] = '\0'; for (i=6; i>0 && psArcDir->szInfoFile[i]==' '; i--) psArcDir->szInfoFile[i] = '\0'; psArcDir->numFields = AVCRawBinReadInt16(psFile); psArcDir->nRecSize = AVCRawBinReadInt16(psFile); AVCRawBinFSeek(psFile, 18, SEEK_CUR); /* Skip 18 bytes */ psArcDir->bDeletedFlag = AVCRawBinReadInt16(psFile); psArcDir->numRecords = AVCRawBinReadInt32(psFile); AVCRawBinFSeek(psFile, 10, SEEK_CUR); /* Skip 10 bytes */ AVCRawBinReadBytes(psFile, 2, psArcDir->szExternal); psArcDir->szExternal[2] = '\0'; AVCRawBinFSeek(psFile, 300, SEEK_CUR); /* Skip the remaining 300 bytes */ return 0; } /********************************************************************** * _AVCBinReadNextNit() * * (This function is for internal library use... external calls should * go to AVCBinReadOpen() with type AVCFileTABLE instead) * * Read the next record from an arc####.nit file. * * Note that arc####.nit files have no header... they start with the * first record immediately. * * Returns 0 on success or -1 on error. **********************************************************************/ int _AVCBinReadNextArcNit(AVCRawBinFile *psFile, AVCFieldInfo *psField) { AVCRawBinReadString(psFile, 16, psField->szName); psField->szName[16] = '\0'; if (AVCRawBinEOF(psFile)) return -1; psField->nSize = AVCRawBinReadInt16(psFile); psField->v2 = AVCRawBinReadInt16(psFile); /* Always -1 ? */ psField->nOffset = AVCRawBinReadInt16(psFile); psField->v4 = AVCRawBinReadInt16(psFile); /* Always 4 ? */ psField->v5 = AVCRawBinReadInt16(psFile); /* Always -1 ? */ psField->nFmtWidth = AVCRawBinReadInt16(psFile); psField->nFmtPrec = AVCRawBinReadInt16(psFile); psField->nType1 = AVCRawBinReadInt16(psFile); psField->nType2 = AVCRawBinReadInt16(psFile); /* Always 0 ? */ psField->v10 = AVCRawBinReadInt16(psFile); /* Always -1 ? */ psField->v11 = AVCRawBinReadInt16(psFile); /* Always -1 ? */ psField->v12 = AVCRawBinReadInt16(psFile); /* Always -1 ? */ psField->v13 = AVCRawBinReadInt16(psFile); /* Always -1 ? */ AVCRawBinReadString(psFile, 16, psField->szAltName); /* Always Blank ? */ psField->szAltName[16] = '\0'; AVCRawBinFSeek(psFile, 56, SEEK_CUR); /* Skip 56 bytes */ psField->nIndex = AVCRawBinReadInt16(psFile); AVCRawBinFSeek(psFile, 28, SEEK_CUR); /* Skip the remaining 28 bytes */ return 0; } /********************************************************************** * _AVCBinReadGetInfoFilename() * * Look for the DAT or NIT files for a given table... returns TRUE if * they exist, or FALSE otherwise. * * If pszRetFnmae/pszRetNitFile != NULL then the filename with full path * will be copied to the specified buffer. **********************************************************************/ GBool _AVCBinReadGetInfoFilename(const char *pszInfoPath, const char *pszBasename, const char *pszDatOrNit, AVCCoverType eCoverType, char *pszRetFname) { GBool bFilesExist = FALSE; char *pszBuf = NULL; VSIStatBuf sStatBuf; if (pszRetFname) pszBuf = pszRetFname; else pszBuf = (char*)CPLMalloc((strlen(pszInfoPath)+strlen(pszBasename)+10)* sizeof(char)); if (eCoverType == AVCCoverWeird) { sprintf(pszBuf, "%s%s%s", pszInfoPath, pszBasename, pszDatOrNit); } else { sprintf(pszBuf, "%s%s.%s", pszInfoPath, pszBasename, pszDatOrNit); } AVCAdjustCaseSensitiveFilename(pszBuf); if (VSIStat(pszBuf, &sStatBuf) == 0) bFilesExist = TRUE; if (eCoverType == AVCCoverWeird && !bFilesExist) { /* In some cases, the filename can be truncated to 8 chars * and we end up with "ARC000DA"... check that possibility. */ pszBuf[strlen(pszBuf)-1] = '\0'; AVCAdjustCaseSensitiveFilename(pszBuf); if (VSIStat(pszBuf, &sStatBuf) == 0) bFilesExist = TRUE; } if (pszRetFname == NULL) CPLFree(pszBuf); return bFilesExist; } /********************************************************************** * _AVCBinReadInfoFilesExist() * * Look for the DAT and NIT files for a given table... returns TRUE if * they exist, or FALSE otherwise. * * If pszRetDatFile/pszRetNitFile != NULL then the .DAT and .NIT filename * without the info path will be copied to the specified buffers. **********************************************************************/ GBool _AVCBinReadInfoFileExists(const char *pszInfoPath, const char *pszBasename, AVCCoverType eCoverType) { return (_AVCBinReadGetInfoFilename(pszInfoPath, pszBasename, "dat", eCoverType, NULL) == TRUE && _AVCBinReadGetInfoFilename(pszInfoPath, pszBasename, "nit", eCoverType, NULL) == TRUE); } /********************************************************************** * AVCBinReadListTables() * * Scan the arc.dir file and return stringlist with one entry for the * Arc/Info name of each table that belongs to the specified coverage. * Pass pszCoverName = NULL to get the list of all tables. * * ppapszArcDatFiles if not NULL will be set to point to a stringlist * with the corresponding "ARC????" info file basenames corresponding * to each table found. * * Note that arc.dir files have no header... they start with the * first record immediately. * * In AVCCoverWeird, the file is called "arcdr9" * * Returns a stringlist that should be deallocated by the caller * with CSLDestroy(), or NULL on error. **********************************************************************/ char **AVCBinReadListTables(const char *pszInfoPath, const char *pszCoverName, char ***ppapszArcDatFiles, AVCCoverType eCoverType, AVCDBCSInfo *psDBCSInfo) { char **papszList = NULL; char *pszFname; char szNameToFind[33] = ""; int nLen; AVCRawBinFile *hFile; AVCTableDef sEntry; if (ppapszArcDatFiles) *ppapszArcDatFiles = NULL; /*----------------------------------------------------------------- * For AVCCoverV7Tables type we do not look for tables for a specific * coverage, we return all tables from the info dir. *----------------------------------------------------------------*/ if (eCoverType == AVCCoverV7Tables) pszCoverName = NULL; /*----------------------------------------------------------------- * All tables that belong to a given coverage have their name starting * with the coverage name (in uppercase letters), followed by a 3 * letters extension. *----------------------------------------------------------------*/ if (pszCoverName != NULL) sprintf(szNameToFind, "%-.28s.", pszCoverName); nLen = strlen(szNameToFind); /*----------------------------------------------------------------- * Open the arc.dir and add all entries that match the criteria * to our list. * In AVCCoverWeird, the file is called "arcdr9" *----------------------------------------------------------------*/ pszFname = (char*)CPLMalloc((strlen(pszInfoPath)+9)*sizeof(char)); if (eCoverType == AVCCoverWeird) sprintf(pszFname, "%sarcdr9", pszInfoPath); else sprintf(pszFname, "%sarc.dir", pszInfoPath); AVCAdjustCaseSensitiveFilename(pszFname); hFile = AVCRawBinOpen(pszFname, "r", AVC_COVER_BYTE_ORDER(eCoverType), psDBCSInfo); if (hFile) { while (!AVCRawBinEOF(hFile) && _AVCBinReadNextArcDir(hFile, &sEntry) == 0) { if (/* sEntry.numRecords > 0 && (DO NOT skip empty tables) */ !sEntry.bDeletedFlag && (pszCoverName == NULL || EQUALN(szNameToFind, sEntry.szTableName, nLen)) && _AVCBinReadInfoFileExists(pszInfoPath, sEntry.szInfoFile, eCoverType) ) { papszList = CSLAddString(papszList, sEntry.szTableName); if (ppapszArcDatFiles) *ppapszArcDatFiles = CSLAddString(*ppapszArcDatFiles, sEntry.szInfoFile); } } AVCRawBinClose(hFile); } CPLFree(pszFname); return papszList; } /********************************************************************** * _AVCBinReadOpenTable() * * (This function is for internal library use... external calls should * go to AVCBinReadOpen() with type AVCFileTABLE instead) * * Open a INFO table, read the header file (.NIT), and finally open * the associated data file to be ready to read records from it. * * Returns a valid AVCBinFile handle, or NULL if the file could * not be opened. * * _AVCBinReadCloseTable() will eventually have to be called to release the * resources used by the AVCBinFile structure. **********************************************************************/ AVCBinFile *_AVCBinReadOpenTable(const char *pszInfoPath, const char *pszTableName, AVCCoverType eCoverType, AVCDBCSInfo *psDBCSInfo) { AVCBinFile *psFile; AVCRawBinFile *hFile; AVCTableDef sTableDef; AVCFieldInfo *pasFieldDef; char *pszFname; GBool bFound; int i; /* Alloc a buffer big enough for the longest possible filename... */ pszFname = (char*)CPLMalloc((strlen(pszInfoPath)+81)*sizeof(char)); /*----------------------------------------------------------------- * Fetch info about this table from the "arc.dir" *----------------------------------------------------------------*/ if (eCoverType == AVCCoverWeird) sprintf(pszFname, "%sarcdr9", pszInfoPath); else sprintf(pszFname, "%sarc.dir", pszInfoPath); AVCAdjustCaseSensitiveFilename(pszFname); hFile = AVCRawBinOpen(pszFname, "r", AVC_COVER_BYTE_ORDER(eCoverType), psDBCSInfo); bFound = FALSE; if (hFile) { while(!bFound && _AVCBinReadNextArcDir(hFile, &sTableDef) == 0) { if (!sTableDef.bDeletedFlag && EQUALN(sTableDef.szTableName, pszTableName, strlen(pszTableName)) && _AVCBinReadInfoFileExists(pszInfoPath, sTableDef.szInfoFile, eCoverType)) { bFound = TRUE; } } AVCRawBinClose(hFile); } /* Hummm... quite likely that this table does not exist! */ if (!bFound) { CPLError(CE_Failure, CPLE_OpenFailed, "Failed to open table %s", pszTableName); CPLFree(pszFname); return NULL; } /*----------------------------------------------------------------- * Establish the location of the data file... depends on the * szExternal[] field. *----------------------------------------------------------------*/ if (EQUAL(sTableDef.szExternal, "XX")) { /*------------------------------------------------------------- * The data file is located outside of the INFO directory. * Read the path to the data file from the arc####.dat file *------------------------------------------------------------*/ _AVCBinReadGetInfoFilename(pszInfoPath, sTableDef.szInfoFile, "dat", eCoverType, pszFname); AVCAdjustCaseSensitiveFilename(pszFname); hFile = AVCRawBinOpen(pszFname, "r", AVC_COVER_BYTE_ORDER(eCoverType), psDBCSInfo); if (hFile) { /* Read the relative file path, and remove trailing spaces. */ AVCRawBinReadBytes(hFile, 80, sTableDef.szDataFile); sTableDef.szDataFile[80] = '\0'; for(i = strlen(sTableDef.szDataFile)-1; isspace(sTableDef.szDataFile[i]); i--) { sTableDef.szDataFile[i] = '\0'; } AVCRawBinClose(hFile); } else { CPLError(CE_Failure, CPLE_OpenFailed, "Failed to open file %s", pszFname); CPLFree(pszFname); return NULL; } } else { /*------------------------------------------------------------- * The data file IS the arc####.dat file * Note: sTableDef.szDataFile must be relative to info directory *------------------------------------------------------------*/ _AVCBinReadGetInfoFilename(pszInfoPath, sTableDef.szInfoFile, "dat", eCoverType, pszFname); strcpy(sTableDef.szDataFile, pszFname+strlen(pszInfoPath)); } /*----------------------------------------------------------------- * Read the table field definitions from the "arc####.nit" file. *----------------------------------------------------------------*/ _AVCBinReadGetInfoFilename(pszInfoPath, sTableDef.szInfoFile, "nit", eCoverType, pszFname); AVCAdjustCaseSensitiveFilename(pszFname); hFile = AVCRawBinOpen(pszFname, "r", AVC_COVER_BYTE_ORDER(eCoverType), psDBCSInfo); if (hFile) { int iField; pasFieldDef = (AVCFieldInfo*)CPLCalloc(sTableDef.numFields, sizeof(AVCFieldInfo)); /*------------------------------------------------------------- * There must be at least sTableDef.numFields valid entries * in the .NIT file... * * Note that we ignore any deleted field entries (entries with * index=-1)... I don't see any use for these deleted fields... * and I don't understand why Arc/Info includes them in their * E00 table headers... *------------------------------------------------------------*/ for(i=0, iField=0; iField 0) iField++; } AVCRawBinClose(hFile); } else { CPLError(CE_Failure, CPLE_OpenFailed, "Failed to open file %s", pszFname); CPLFree(pszFname); return NULL; } /*----------------------------------------------------------------- * Open the data file... ready to read records from it. * If the header says that table has 0 records, then we don't * try to open the file... but we don't consider that as an error. *----------------------------------------------------------------*/ if (sTableDef.numRecords > 0 && AVCFileExists(pszInfoPath, sTableDef.szDataFile)) { VSIStatBuf sStatBuf; sprintf(pszFname, "%s%s", pszInfoPath, sTableDef.szDataFile); AVCAdjustCaseSensitiveFilename(pszFname); hFile = AVCRawBinOpen(pszFname, "r", AVC_COVER_BYTE_ORDER(eCoverType), psDBCSInfo); /* OOPS... data file does not exist! */ if (hFile == NULL) { CPLError(CE_Failure, CPLE_OpenFailed, "Failed to open file %s", pszFname); CPLFree(pszFname); return NULL; } /*------------------------------------------------------------- * In some cases, the number of records field for a table in the * arc.dir does not correspond to the real number of records * in the data file. In this kind of situation, the number of * records returned by Arc/Info in an E00 file will be based * on the real data file size, and not on the value from the arc.dir. * * Fetch the data file size, and correct the number of record * field in the table header if necessary. *------------------------------------------------------------*/ if ( VSIStat(pszFname, &sStatBuf) != -1 && sTableDef.nRecSize > 0 && sStatBuf.st_size/sTableDef.nRecSize != sTableDef.numRecords) { sTableDef.numRecords = sStatBuf.st_size/sTableDef.nRecSize; } } else { hFile = NULL; sTableDef.numRecords = 0; } /*----------------------------------------------------------------- * Alloc. and init. the AVCBinFile structure. *----------------------------------------------------------------*/ psFile = (AVCBinFile*)CPLCalloc(1, sizeof(AVCBinFile)); psFile->psRawBinFile = hFile; psFile->eCoverType = AVCCoverV7; psFile->eFileType = AVCFileTABLE; psFile->pszFilename = pszFname; psFile->hdr.psTableDef = (AVCTableDef*)CPLMalloc(sizeof(AVCTableDef)); *(psFile->hdr.psTableDef) = sTableDef; psFile->hdr.psTableDef->pasFieldDef = pasFieldDef; /* We can't really tell the precision from a Table header... * just set an arbitrary value... it probably won't be used anyways! */ psFile->nPrecision = AVC_SINGLE_PREC; /*----------------------------------------------------------------- * Allocate temp. structures to use to read records from the file * And allocate buffers for those fields that are stored as strings. *----------------------------------------------------------------*/ psFile->cur.pasFields = (AVCField*)CPLCalloc(sTableDef.numFields, sizeof(AVCField)); for(i=0; icur.pasFields[i].pszStr = (char*)CPLCalloc(pasFieldDef[i].nSize+1, sizeof(char)); } } return psFile; } /********************************************************************** * _AVCBinReadNextTableRec() * * (This function is for internal library use... external calls should * go to AVCBinReadNextTableRec() instead) * * Reads the next record from an attribute table and fills the * pasFields[] array. * * Note that it is assumed that the pasFields[] array has been properly * initialized, re the allocation of buffers for fields strored as * strings. * * Returns 0 on success or -1 on error. **********************************************************************/ int _AVCBinReadNextTableRec(AVCRawBinFile *psFile, int nFields, AVCFieldInfo *pasDef, AVCField *pasFields, int nRecordSize) { int i, nType, nBytesRead=0; if (psFile == NULL) return -1; for(i=0; ihDBFFile = hDBFFile; psFile->eCoverType = AVCCoverPC; psFile->eFileType = AVCFileTABLE; psFile->pszFilename = CPLStrdup(pszDBFFilename); psFile->hdr.psTableDef = NULL; /* nCurDBFRecord is used to keep track of the 0-based index of the * last record we read from the DBF file... this is to emulate * sequential access which is assumed by the rest of the lib. * Since the first record (record 0) has not been read yet, then * we init the index at -1. */ psFile->nCurDBFRecord = -1; /* We can't really tell the precision from a Table header... * just set an arbitrary value... it probably won't be used anyways! */ psFile->nPrecision = AVC_SINGLE_PREC; /*----------------------------------------------------------------- * Build TableDef from the info in the DBF header *----------------------------------------------------------------*/ /* Use calloc() to init some unused struct members */ psTableDef = (AVCTableDef*)CPLCalloc(1, sizeof(AVCTableDef)); psFile->hdr.psTableDef = psTableDef; sprintf(psTableDef->szTableName, "%-32.32s", pszArcInfoTableName); psTableDef->numFields = DBFGetFieldCount(hDBFFile); /* We'll compute nRecSize value when we read fields info later */ psTableDef->nRecSize = 0; psTableDef->numRecords = DBFGetRecordCount(hDBFFile); /* All DBF tables are considered External */ strcpy(psTableDef->szExternal, "XX"); /*----------------------------------------------------------------- * Build Field definitions *----------------------------------------------------------------*/ pasFieldDef = (AVCFieldInfo*)CPLCalloc(psTableDef->numFields, sizeof(AVCFieldInfo)); psTableDef->pasFieldDef = pasFieldDef; for(iField=0; iField< psTableDef->numFields; iField++) { int nWidth, nDecimals; DBFFieldType eDBFType; char cNativeType; /*------------------------------------------------------------- * Fetch DBF Field info and convert to Arc/Info type... * Note that since DBF fields names are limited to 10 chars, * we do not have to worry about field name length in the process. *------------------------------------------------------------*/ eDBFType = DBFGetFieldInfo(hDBFFile, iField, pasFieldDef[iField].szName, &nWidth, &nDecimals); cNativeType = DBFGetNativeFieldType(hDBFFile, iField); pasFieldDef[iField].nFmtWidth = (GInt16)nWidth; pasFieldDef[iField].nFmtPrec = (GInt16)nDecimals; /* nIndex is the 1-based field index that we see in the E00 header */ pasFieldDef[iField].nIndex = iField+1; if (cNativeType == 'F' || (cNativeType == 'N' && nDecimals > 0) ) { /*--------------------------------------------------------- * BINARY FLOAT *--------------------------------------------------------*/ pasFieldDef[iField].nType1 = AVC_FT_BINFLOAT/10; pasFieldDef[iField].nSize = 4; pasFieldDef[iField].nFmtWidth = 12; /* PC Arc/Info ignores the */ pasFieldDef[iField].nFmtPrec = 3; /* DBF width/precision */ } else if (cNativeType == 'N') { /*--------------------------------------------------------- * BINARY INTEGER *--------------------------------------------------------*/ pasFieldDef[iField].nType1 = AVC_FT_BININT/10; pasFieldDef[iField].nSize = 4; pasFieldDef[iField].nFmtWidth = 5; /* PC Arc/Info ignores the */ pasFieldDef[iField].nFmtPrec = -1; /* DBF width/precision */ /*--------------------------------------------------------- * Some special integer fields need to have their names * repaired because DBF does not support special characters. *--------------------------------------------------------*/ _AVCBinReadRepairDBFFieldName(pasFieldDef[iField].szName); } else if (cNativeType == 'D') { /*--------------------------------------------------------- * DATE - Actually handled as a string internally *--------------------------------------------------------*/ pasFieldDef[iField].nType1 = AVC_FT_DATE/10; pasFieldDef[iField].nSize = nWidth; pasFieldDef[iField].nFmtPrec = -1; } else /* (cNativeType == 'C' || cNativeType == 'L') */ { /*--------------------------------------------------------- * CHAR STRINGS ... and all unknown types also handled as strings *--------------------------------------------------------*/ pasFieldDef[iField].nType1 = AVC_FT_CHAR/10; pasFieldDef[iField].nSize = nWidth; pasFieldDef[iField].nFmtPrec = -1; } /*--------------------------------------------------------- * Keep track of position of field in record... first one always * starts at offset=1 *--------------------------------------------------------*/ if (iField == 0) pasFieldDef[iField].nOffset = 1; else pasFieldDef[iField].nOffset = (pasFieldDef[iField-1].nOffset + pasFieldDef[iField-1].nSize ); /*--------------------------------------------------------- * Set default values for all other unused members in the struct *--------------------------------------------------------*/ pasFieldDef[iField].v2 = -1; /* Always -1 ? */ pasFieldDef[iField].v4 = 4; /* Always 4 ? */ pasFieldDef[iField].v5 = -1; /* Always -1 ? */ pasFieldDef[iField].nType2 = 0; /* Always 0 ? */ pasFieldDef[iField].v10 = -1; /* Always -1 ? */ pasFieldDef[iField].v11 = -1; /* Always -1 ? */ pasFieldDef[iField].v12 = -1; /* Always -1 ? */ pasFieldDef[iField].v13 = -1; /* Always -1 ? */ } /*----------------------------------------------------------------- * Compute record size... * Record size has to be rounded to a multiple of 2 bytes. *----------------------------------------------------------------*/ if (psTableDef->numFields > 0) { psTableDef->nRecSize = (pasFieldDef[psTableDef->numFields-1].nOffset-1+ pasFieldDef[psTableDef->numFields-1].nSize); psTableDef->nRecSize = ((psTableDef->nRecSize+1)/2)*2; } else psTableDef->nRecSize = 0; /*----------------------------------------------------------------- * Allocate temp. structures to use to read records from the file * And allocate buffers for those fields that are stored as strings. *----------------------------------------------------------------*/ psFile->cur.pasFields = (AVCField*)CPLCalloc(psTableDef->numFields, sizeof(AVCField)); for(iField=0; iFieldnumFields; iField++) { if (pasFieldDef[iField].nType1*10 == AVC_FT_DATE || pasFieldDef[iField].nType1*10 == AVC_FT_CHAR || pasFieldDef[iField].nType1*10 == AVC_FT_FIXINT || pasFieldDef[iField].nType1*10 == AVC_FT_FIXNUM ) { psFile->cur.pasFields[iField].pszStr = (char*)CPLCalloc(pasFieldDef[iField].nSize+1, sizeof(char)); } } return psFile; } /********************************************************************** * _AVCBinReadNextDBFTableRec() * * (This function is for internal library use... external calls should * go to AVCBinReadNextTableRec() instead) * * Reads the next record from a AVCCoverPC DBF attribute table and fills the * pasFields[] array. * * Note that it is assumed that the pasFields[] array has been properly * initialized, re the allocation of buffers for fields stored as * strings. * * Returns 0 on success or -1 on error. **********************************************************************/ int _AVCBinReadNextDBFTableRec(DBFHandle hDBFFile, int *piRecordIndex, int nFields, AVCFieldInfo *pasDef, AVCField *pasFields) { int i, nType; /*----------------------------------------------------------------- * Increment current record index. * We use nCurDBFRecord to keep track of the 0-based index of the * last record we read from the DBF file... this is to emulate * sequential access which is assumed by the rest of the lib. *----------------------------------------------------------------*/ if (hDBFFile == NULL || piRecordIndex == NULL || pasDef == NULL || pasFields == NULL) return -1; (*piRecordIndex)++; if (*piRecordIndex >= DBFGetRecordCount(hDBFFile)) return -1; /* Reached EOF */ /*----------------------------------------------------------------- * Read/convert each field based on type *----------------------------------------------------------------*/ for(i=0; i /********************************************************************** * CPLReadDir() * * Return a stringlist with the list of files in a directory. * The returned stringlist should be freed with CSLDestroy(). * * Returns NULL if an error happened or if the directory could not * be read. **********************************************************************/ /** * Read names in a directory. * * This function abstracts access to directory contains. It returns a * list of strings containing the names of files, and directories in this * directory. The resulting string list becomes the responsibility of the * application and should be freed with CSLDestroy() when no longer needed. * * Note that no error is issued via CPLError() if the directory path is * invalid, though NULL is returned. * * @param pszPath the relative, or absolute path of a directory to read. * @return The list of entries in the directory, or NULL if the directory * doesn't exist. */ char **CPLReadDir(const char *pszPath) { struct _finddata_t c_file; long hFile; char *pszFileSpec, **papszDir = NULL; if (strlen(pszPath) == 0) pszPath = "."; pszFileSpec = CPLStrdup(CPLSPrintf("%s\\*.*", pszPath)); if ( (hFile = _findfirst( pszFileSpec, &c_file )) != -1L ) { do { papszDir = CSLAddString(papszDir, c_file.name); } while( _findnext( hFile, &c_file ) == 0 ); _findclose( hFile ); } else { /* Should we generate an error??? * For now we'll just return NULL (at the end of the function) */ } CPLFree(pszFileSpec); return papszDir; } #else /*===================================================================== POSIX (Unix) implementation *====================================================================*/ #include #include /********************************************************************** * CPLReadDir() * * Return a stringlist with the list of files in a directory. * The returned stringlist should be freed with CSLDestroy(). * * Returns NULL if an error happened or if the directory could not * be read. **********************************************************************/ char **CPLReadDir(const char *pszPath) { DIR *hDir; struct dirent *psDirEntry; char **papszDir = NULL; if (strlen(pszPath) == 0) pszPath = "."; if ( (hDir = opendir(pszPath)) != NULL ) { while( (psDirEntry = readdir(hDir)) != NULL ) { papszDir = CSLAddString(papszDir, psDirEntry->d_name); } closedir( hDir ); } else { /* Should we generate an error??? * For now we'll just return NULL (at the end of the function) */ } return papszDir; } #endif avce00-2.0.0/HISTORY.TXT0100775000076400007640000002312710471146411013625 0ustar danieldanielAVCE00 library - Revision History ================================= Current Version: ---------------- Version 2.0.0 (2006-08-17): --------------------------- - New functions to read E00 files directly as opposed to translating to binary coverage. Used in the implementation of E00 read support in OGR. Contributed by James E. Flemer (bug 1497) Adds the following new functions: AVCE00ReadE00Ptr AVCE00ReadOpenE00(const char *pszE00FileName); void AVCE00ReadCloseE00(AVCE00ReadE00Ptr psRead); int AVCE00ReadRewindE00(AVCE00ReadE00Ptr psRead); int AVCE00ReadSeekE00(AVCE00ReadE00Ptr psRead, int nOffset, int nWhence); void *AVCE00ReadNextObjectE00(AVCE00ReadE00Ptr psRead, int bContinue); - Support for a new AVCCoverPC2 coverage type that is a hybrid between AVCCoverPC and AVCCoverV7 (bug 1491) - Accept empty subclass names for TX6/TX7 sections (bug 1261) - Applied patch to remove any embedded '\0' from data line in AVCE00GenTableRec() - Support for reading standalone info tables (just tables, no coverage data) by pointing AVCE00ReadOpen() to the info directory (bug 1549). - #include to solve warning on 64 bit platforms (bug 1461) Version 1.3.0 (2005-06-02): --------------------------- - Applied Carl Anderson's patch to reduce the amount of stating while trying to discover filename "case" on Unix in AVCAdjustCaseSensitiveFilename. http://bugzilla.remotesensing.org/show_bug.cgi?id=314 - Fixed leak in AVCE00ReadOpen() when trying to open something that's not a coverage (bug513) - Added AVCBinReadObject() to randomly read an object using the index file. Currently only works for Arcs, info records and polygons. NFW - Fixed up AVCBinReadObject() to work properly for PC Arc/Info style coverages. Also fixed to use upper/lower case 'X' for index based on base file type. NFW OGR Bug#493. - avc_e00write.c: modified to use VSIMkdir(). - Use record size while reading ARC, PAL, CNT to skip junk bytes. (bug940) - Fixed parsing of type 40 fields (modified for bug#599) to detect exponent format with negative exponents (bug#1272) - Minor fixes in avc_e00gen.c to avoid compile warnings. (NFW) - Fixed pointer aliasing ("type punning") problem re: gcc 3.3.x. (NFW) http://bugzilla.remotesensing.org/show_bug.cgi?id=592 Version 1.2.1 (2000-11-25): --------------------------- - Remove trailing '/' in info directory path when creating the info dir since mkdir() on some UNIXes doesn't like it. - Fixed a problem writing arc.dir on NT4 networked drives in an empty dir. (bugzilla bug#353) - Fixed E00 parsing to properly handle PAL entries with 0 arcs which happen to contain a single "0 0 0" entry. - Fixed E00 generation to correctly format 0-arc PAL records so that they have a single "0 0 0" (filler) arc record (bug#597) - Fixed reading of type 40 fields from E00: when a type 40 field is not stored in exponent format then a decimal format may be used but the decimal position is shifted to the right in the E00 value. So we have to shift the decimal point to the left (i.e. divide by 10) as we interpret the value (bug#599). Really odd! - Added a hack to remap type 40 fields bigger than 8 digits to double precision binary floats while generating E00 output (bug#599). In E00 format, type 40 fields bigger than 8 digits would lose some digits of precision and double precision floats can carry up to 18 digits of precision. This hack is enabled using "-DAVC_MAP_TYPE40_TO_DOUBLE" in OPTFLAGS. - Fixed problem with info/arc####.dat files coming from Windows that contained '\\' in the data file path. Remap '\\' in path to '/' on Unix. This problem seems to be new with Arc8 on Windows. - Fixed args to fseek() call in _AVCBinReadNextTableRec()... how come we never ran into this before??? Version 1.2.0 (2000-10-17): --------------------------- - Added Japanese (multibyte characters) support. - Made validation on new coverage name more flexible (used to accept only isalnum() chars and '_') - Added a case to treat pal.adf files with nPrecision==1011 as double prec. Actually, any file with nPrecision > 1000 is now treated as double prec. - Switch to MIT-style license - Added PC Coverage write. - Added optional -DAVC_IGNORE_RMDIR_ERROR to prevent generation of an error when AVCDeleteCoverage() fails to delete the actual coverage directory. - Accept TXT files in AVCCoverWeird that use both PC or V7 TXT structure Version 1.1.1 (2000-04-01): --------------------------- - Support double-precision "weird" coverages... previous version assumed that "weird" coverages were always single precision. - Fix problem with TX6/TXT object with strings > 80 chars. String has to be split in 80 chars chunks in E00. - Made lib more robust to detect corrupted or invalid files in a coverage directory by checking signature and skipping invalid files. Version 1.1 (2000-01-10): ------------------------- - PC Arc/Info Coverage support - Support for reading "Weird" coverages (a kind of hybrid between PC and Unix V7 Coverages). Version 1.0 (1999-12-04): ------------------------- - Improved parsing of integer values in E00... big numbers in INFO table headers were sometimes merged and this resulted in unpredictable behavior. Version 0.6 (1999-08-26): ------------------------- - Added AVCE00DeleteCoverage() - Fixed problem with handling of attribs of type 40 in E00 input/output - Fixed VC++ warnings - Fixed some memory leaks. - Fixed a Windows-specific bug: the arc.dir was sometimes overwritten when several coverages were created by the same process... likely a buffering issue. Version 0.5 (1999-06-10): ------------------------- - Overwrite existing arc.dir entries when necessary while creating INFO tables. The problem was that when same coverage name was used twice with the same info directory... we ended up with 2 sets of tables with the same names. This happened if a user deleted a coverage directory using "rm". In this case, IMPORT71 reuses and overwrites the old table entry with the same name in the ARC.DIR... our lib now does the same. - Created NMAKE makefile.vc for Windows - Tested on Windows Version 0.4 (1999-05-17): ------------------------- - Added TXT/TX6/TX7 write support. - Added RXP write support - Fixed problem with double precision RPL sections: the second PAL termination line confused the parser. - The write library now detects the E00's precision and generate a coverage using that precision by default when AVCE00WriteOpen() is called using AVC_DEFAULT_PREC. (That's also the only valid option.) - Added a check for maximum coverage name length (13 chars) when creating a new one. Also force name to contain only alnum() and '_'. - INFO TABLES: the name of the system attributes (COVER#/COVER-ID) are now changed to the new coverage name when creating a new info table. - Fixed problem parsing an E00 INFO table that contains 0 records (yes, they exist!) Version 0.3 (1999-05-10): ------------------------- - Added support to create coverages from E00 (alpha version). Most file types are supported, but only single precision has been tested on Linux. There are still a number of known problems with the write support. - Added proper support and tested with tables containing 16 bits integers (type 50, size=2) - Fixed problem with 8 bytes floats in single-prec. tables, and 4 bytes floats in double-precision tables. - Fixed the following problem: In some cases, the "number of records" field for a table in the arc.dir does not correspond to the real number of records in the data file. In this kind of situation, the number of records returned by Arc/Info in an E00 file will be based on the real data file size, and not on the value from the arc.dir. - Tested on a CPL_MSB system Version 0.2 (1999-02-24): ------------------------- - Added support for Annotations: - TXT - TX6 - TX7 (Handled as TX6) - Added support for coverages with regions (RXP/RPL sections) - Tested with routes coverage - Added support for "par.adf": Double precision coverages have their tolerances stored in a file named "par.adf" which is different from the "tol.adf" we find in single precision coverages... - PRJ section: remove '\r' at end of lines when coverage generated on DOS systems is read on Unix. - Support centroids (CNT) with more than one label attached to them. - Do not skip INFO Tables with 0 records. Since Arc/Info exports them, we should probably do it as well! - Changed AVCE00ReadOpen() so that the coverage name does not absolutely have to be terminated by a "/". Now, you can either pass the name of the coverage directory (with or without a '/' at the end), or the path to one of the files in the coverage directory. - Added extra line after the end of PAL sections in double precision coverages: -1 0 0 0 0 0 0 0.00000000000000E+00 0.00000000000000E+00 Even if I consider this second line to be a glitch, I guess I have to mimic this behavior and add this extra line one as well! - Modified "avcconv" command-line program to accept an output_filename as a its second argument. Until now its output was always sent to stdout. - Updated documentation, mainly the list of error codes. Version 0.1 (1999-01-31): ------------------------- First version, supports the most common file types, still several know problems. --------- $Id: HISTORY.TXT,v 1.28 2006/08/17 20:09:45 dmorissette Exp $ avce00-2.0.0/avc_e00write.c0100664000076400007640000011515510450275463014526 0ustar danieldaniel/********************************************************************** * $Id: avc_e00write.c,v 1.20 2006/06/27 18:38:43 dmorissette Exp $ * * Name: avc_e00write.c * Project: Arc/Info vector coverage (AVC) E00->BIN conversion library * Language: ANSI C * Purpose: Functions to create a binary coverage from a stream of * ASCII E00 lines. * Author: Daniel Morissette, dmorissette@dmsolutions.ca * ********************************************************************** * Copyright (c) 1999-2001, Daniel Morissette * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ********************************************************************** * * $Log: avc_e00write.c,v $ * Revision 1.20 2006/06/27 18:38:43 dmorissette * Cleaned up E00 reading (bug 1497, patch from James F.) * * Revision 1.19 2006/06/14 16:31:28 daniel * Added support for AVCCoverPC2 type (bug 1491) * * Revision 1.18 2006/03/02 22:46:26 daniel * Accept empty subclass names for TX6/TX7 sections (bug 1261) * * Revision 1.17 2005/06/03 03:49:59 daniel * Update email address, website url, and copyright dates * * Revision 1.16 2002/08/27 15:46:15 daniel * Applied fix made in GDAL/OGR by 'aubin' (moved include ctype.h after avc.h) * * Revision 1.15 2002/04/16 21:19:10 daniel * Use VSIRmdir() * * Revision 1.14 2002/03/18 19:00:44 daniel * Use VSIMkdir() and not VSIMkDir() * * Revision 1.13 2002/02/18 21:16:33 warmerda * modified to use VSIMkDir * * Revision 1.12 2001/05/23 15:23:17 daniel * Remove trailing '/' in info directory path when creating the info dir. * * Revision 1.11 2000/09/26 20:21:04 daniel * Added AVCCoverPC write * * Revision 1.10 2000/09/22 19:45:21 daniel * Switch to MIT-style license * * Revision 1.9 2000/05/29 22:47:39 daniel * Made validation on new coverage name more flexible. * * Revision 1.8 2000/05/29 15:31:31 daniel * Added Japanese DBCS support * * Revision 1.7 2000/02/14 17:19:53 daniel * Accept '-' cahracter in new coverage name * * Revision 1.6 2000/01/10 02:57:44 daniel * Little changes to accomodate read support for "weird" coverages * * Revision 1.5 1999/12/24 07:18:34 daniel * Added PC Arc/Info coverages support * * Revision 1.4 1999/08/26 17:36:36 daniel * Avoid overwriting arc.dir on Windows... happened only when several * coverages are created by the same process on Windows. * * Revision 1.3 1999/08/23 18:23:35 daniel * Added AVCE00DeleteCoverage() * * Revision 1.2 1999/05/17 16:23:36 daniel * Added AVC_DEFAULT_PREC + more cover name validation in AVCE00WriteOpen(). * * Revision 1.1 1999/05/11 02:34:46 daniel * Initial revision * **********************************************************************/ #include "cpl_vsi.h" #include "avc.h" #include /* tolower() */ static GBool _IsStringAlnum(const char *pszFname); /********************************************************************** * AVCE00WriteOpen() * * Open (create) an Arc/Info coverage, ready to be receive a stream * of ASCII E00 lines and convert that to the binary coverage format. * * For now, writing to or overwriting existing coverages is not supported * (and may quite well never be!)... you can only create new coverages. * * Important Note: The E00 source lines are assumed to be valid... the * library performs no validation on the consistency of what it is * given as input (i.e. topology, polygons consistency, etc.). * So the coverage that will be created will be only as good as the * E00 input that is used to generate it. * * pszCoverPath MUST be the name of the coverage directory, including * the path to it. * (contrary to AVCE00ReadOpen(), you cannot pass the name of one of * the files in the coverage directory). * The name of the coverage MUST be included in pszCoverPath... this * means that passing "." is invalid. * * eNewCoverType is the type of coverage to create. * Either AVCCoverV7 (Arc/Info V7 (Unix) coverage) * or AVCCoverPC (PC Arc/Info coverage) * * nPrecision should always be AVC_DEFAULT_PREC to automagically detect the * source coverage's precision and use that same precision * for the new coverage. * * This parameter has been included to allow adding the * possibility to eventually create coverages with a precision * different from the source E00. * Given the way the lib is built, it could be possible to * also pass AVC_SINGLE_PREC or AVC_DOUBLE_PREC to explicitly * request the creation of a coverage with that precision, * but the library does not (not yet!) properly convert the * TABLE attributes' precision, and the resulting coverage may * be invalid in some cases. * This improvement is on the ToDo list! * * Returns a new AVCE00WritePtr handle or NULL if the coverage could * not be created or if a coverage with that name already exists. * * The handle will eventually have to be released with AVCE00ReadClose(). **********************************************************************/ AVCE00WritePtr AVCE00WriteOpen(const char *pszCoverPath, AVCCoverType eNewCoverType, int nPrecision ) { AVCE00WritePtr psInfo; int i, nLen; VSIStatBuf sStatBuf; CPLErrorReset(); /*----------------------------------------------------------------- * Create pszCoverPath directory. *----------------------------------------------------------------*/ if (pszCoverPath == NULL || strlen(pszCoverPath) == 0) { CPLError(CE_Failure, CPLE_AssertionFailed, "Invalid (empty) coverage directory name."); return NULL; } else if ( VSIStat(pszCoverPath, &sStatBuf) == 0 && VSI_ISDIR(sStatBuf.st_mode) ) { /*------------------------------------------------------------- * Directory already exists... make sure it is empty * otherwise we can't use it as a coverage directory. *------------------------------------------------------------*/ char **papszFiles; papszFiles = CPLReadDir(pszCoverPath); for(i=0; papszFiles && papszFiles[i]; i++) { if (!EQUAL(".", papszFiles[i]) && !EQUAL("..", papszFiles[i])) { CPLError(CE_Failure, CPLE_OpenFailed, "Cannot create coverage %s: directory already exists " "and is not empty.", pszCoverPath); CSLDestroy(papszFiles); papszFiles = NULL; return NULL; } } CSLDestroy(papszFiles); papszFiles = NULL; } else { /*------------------------------------------------------------- * Create new pszCoverPath directory. * This will fail if a file with the same name already exists. *------------------------------------------------------------*/ if( VSIMkdir(pszCoverPath, 0777) != 0 ) { CPLError(CE_Failure, CPLE_OpenFailed, "Unable to create coverage directory: %s.", pszCoverPath); return NULL; } } /*----------------------------------------------------------------- * Alloc the AVCE00WritePtr handle *----------------------------------------------------------------*/ psInfo = (AVCE00WritePtr)CPLCalloc(1, sizeof(struct AVCE00WriteInfo_t)); /*----------------------------------------------------------------- * Validate and store coverage type *----------------------------------------------------------------*/ if (eNewCoverType == AVCCoverV7 || eNewCoverType == AVCCoverPC) psInfo->eCoverType = eNewCoverType; else { CPLError(CE_Failure, CPLE_NotSupported, "Requested coverage type cannot be created. Please use " "the AVCCoverV7 or AVCCoverPC coverage type."); CPLFree(psInfo); return NULL; } /*----------------------------------------------------------------- * Requested precision for the new coverage... for now only * AVC_DEFAULT_PREC is supported. When the first section is * read, then this section's precision will be used for the whole * coverage. (This is done inside AVCE00WriteNextLine()) *----------------------------------------------------------------*/ if (psInfo->eCoverType == AVCCoverPC) psInfo->nPrecision = AVC_SINGLE_PREC; /* PC Cover always single prec.*/ else if (nPrecision == AVC_DEFAULT_PREC) psInfo->nPrecision = nPrecision; else { CPLError(CE_Failure, CPLE_IllegalArg, "Coverages can only be created using AVC_DEFAULT_PREC. " "Please see the documentation for AVCE00WriteOpen()."); CPLFree(psInfo); return NULL; } /*----------------------------------------------------------------- * Make sure coverage directory name is terminated with a '/' (or '\\') *----------------------------------------------------------------*/ nLen = strlen(pszCoverPath); if (pszCoverPath[nLen-1] == '/' || pszCoverPath[nLen-1] == '\\') psInfo->pszCoverPath = CPLStrdup(pszCoverPath); else { #ifdef WIN32 psInfo->pszCoverPath = CPLStrdup(CPLSPrintf("%s\\",pszCoverPath)); #else psInfo->pszCoverPath = CPLStrdup(CPLSPrintf("%s/",pszCoverPath)); #endif } /*----------------------------------------------------------------- * Extract the coverage name from the coverage path. Note that * for this the coverage path must be in the form: * "dir1/dir2/dir3/covername/" ... if it is not the case, then * we would have to use getcwd() to find the current directory name... * but for now we'll just produce an error if this happens. *----------------------------------------------------------------*/ nLen = 0; for( i = strlen(psInfo->pszCoverPath)-1; i > 0 && psInfo->pszCoverPath[i-1] != '/' && psInfo->pszCoverPath[i-1] != '\\'&& psInfo->pszCoverPath[i-1] != ':'; i-- ) { nLen++; } if (nLen > 0) { psInfo->pszCoverName = CPLStrdup(psInfo->pszCoverPath+i); psInfo->pszCoverName[nLen] = '\0'; } else { CPLError(CE_Failure, CPLE_OpenFailed, "Invalid coverage path (%s): " "coverage name must be included in path.", pszCoverPath); CPLFree(psInfo->pszCoverPath); CPLFree(psInfo); return NULL; } if (strlen(psInfo->pszCoverName) > 13 || !_IsStringAlnum(psInfo->pszCoverName) ) { CPLError(CE_Failure, CPLE_OpenFailed, "Invalid coverage name (%s): " "coverage name must be 13 chars or less and contain only " "alphanumerical characters, '-' or '_'.", psInfo->pszCoverName); CPLFree(psInfo->pszCoverPath); CPLFree(psInfo->pszCoverName); CPLFree(psInfo); return NULL; } if (psInfo->eCoverType == AVCCoverPC || psInfo->eCoverType == AVCCoverPC2) { /*------------------------------------------------------------- * No 'info' directory is required for PC coverages *------------------------------------------------------------*/ psInfo->pszInfoPath = NULL; } else { /*------------------------------------------------------------- * Lazy way to build the INFO path: simply add "../info/"... * this could probably be improved! *------------------------------------------------------------*/ psInfo->pszInfoPath = (char*)CPLMalloc((strlen(psInfo->pszCoverPath)+9) *sizeof(char)); #ifdef WIN32 # define AVC_INFOPATH "..\\info\\" #else # define AVC_INFOPATH "../info/" #endif sprintf(psInfo->pszInfoPath, "%s%s", psInfo->pszCoverPath, AVC_INFOPATH); /*------------------------------------------------------------- * Check if the info directory exists and contains the "arc.dir" * if the info dir does not exist, then make sure we can create * the arc.dir file (i.e. try to create an empty one) * * Note: On Windows, this VSIStat() call seems to sometimes fail even * when the directory exists (buffering issue?), and the * following if() block is sometimes executed even if it * should not, but this should not cause problems since the * arc.dir is opened with "a+b" access. *------------------------------------------------------------*/ if ( VSIStat(psInfo->pszInfoPath, &sStatBuf) == -1) { FILE *fp; char *pszArcDir; char *pszInfoDir; pszArcDir = CPLStrdup(CPLSPrintf("%s%s", psInfo->pszInfoPath, "arc.dir")); /* Remove the trailing "/" from pszInfoPath. Most OSes are * forgiving, and allow mkdir to include the trailing character, * but some UNIXes are not. [GEH 2001/05/17] */ pszInfoDir = CPLStrdup(psInfo->pszInfoPath); pszInfoDir[strlen(pszInfoDir)-1] = '\0'; VSIMkdir(pszInfoDir, 0777); fp = VSIFOpen(pszArcDir, "a+b"); CPLFree(pszArcDir); CPLFree(pszInfoDir); if (fp) { VSIFClose(fp); } else { CPLError(CE_Failure, CPLE_OpenFailed, "Unable to create (or write to) 'info' directory %s", psInfo->pszInfoPath); CPLFree(psInfo->pszCoverPath); CPLFree(psInfo->pszInfoPath); CPLFree(psInfo); return NULL; } } } /*----------------------------------------------------------------- * Init the E00 parser. *----------------------------------------------------------------*/ psInfo->hParseInfo = AVCE00ParseInfoAlloc(); psInfo->eCurFileType = AVCFileUnknown; /*----------------------------------------------------------------- * Init multibyte encoding info *----------------------------------------------------------------*/ psInfo->psDBCSInfo = AVCAllocDBCSInfo(); /*----------------------------------------------------------------- * If an error happened during the open call, cleanup and return NULL. *----------------------------------------------------------------*/ if (CPLGetLastErrorNo() != 0) { AVCE00WriteClose(psInfo); psInfo = NULL; } return psInfo; } /********************************************************************** * AVCE00WriteClose() * * Close a coverage and release all memory used by the AVCE00WritePtr * handle. **********************************************************************/ void AVCE00WriteClose(AVCE00WritePtr psInfo) { CPLErrorReset(); if (psInfo == NULL) return; CPLFree(psInfo->pszCoverPath); CPLFree(psInfo->pszCoverName); CPLFree(psInfo->pszInfoPath); if (psInfo->hFile) AVCBinWriteClose(psInfo->hFile); if (psInfo->hParseInfo) AVCE00ParseInfoFree(psInfo->hParseInfo); AVCFreeDBCSInfo(psInfo->psDBCSInfo); CPLFree(psInfo); } /********************************************************************** * _IsStringAlnum() * * Scan a string, and return TRUE if it contains only valid characters, * Return FALSE otherwise. * * We used to accept only isalnum() chars, but since extended chars with * accents seem to be accepted, we will only check for chars that * could confuse the lib. **********************************************************************/ static GBool _IsStringAlnum(const char *pszFname) { GBool bOK = TRUE; while(bOK && *pszFname != '\0') { if (strchr(" \t.,/\\", (unsigned char)*pszFname) != NULL) bOK = FALSE; pszFname ++; } return bOK; } /********************************************************************** * _AVCE00WriteRenameTable() * * Rename the table and the system fields in a tabledef that will * be written to a new coverage. **********************************************************************/ static void _AVCE00WriteRenameTable(AVCTableDef *psTableDef, const char *pszNewCoverName) { char szOldName[40], szOldExt[40], szNewName[40], *pszTmp; char szSysId[40], szUserId[40]; int i; strcpy(szNewName, pszNewCoverName); for(i=0; szNewName[i] != '\0'; i++) szNewName[i] = toupper(szNewName[i]); /*----------------------------------------------------------------- * Extract components from the current table name. *----------------------------------------------------------------*/ strcpy(szOldName, psTableDef->szTableName); if ( !EQUAL(psTableDef->szExternal, "XX") || (pszTmp = strchr(szOldName, '.')) == NULL ) return; /* We don't deal with that table */ *pszTmp = '\0'; pszTmp++; strcpy(szOldExt, pszTmp); if ( (pszTmp = strchr(szOldExt, ' ')) != NULL ) *pszTmp = '\0'; if (strlen(szOldExt) < 3) return; /* We don't deal with that table */ /*----------------------------------------------------------------- * Look for system attributes with same name as table * If the table name extension is followed by a subclass name * (e.g. "TEST.PATCOUNTY") then this subclass is used to build * the system attributes (COUNTY# and COUNTY-ID) and thus we do * not need to rename them * Otherwise (e.g. COUNTY.PAT) the coverage name is used and then * we need to rename these attribs for the new coverage name. *----------------------------------------------------------------*/ if (strlen(szOldExt) == 3) { sprintf(szSysId, "%s#", szOldName); sprintf(szUserId, "%s-ID", szOldName); for(i=0; inumFields; i++) { /* Remove trailing spaces */ if ((pszTmp=strchr(psTableDef->pasFieldDef[i].szName,' '))!=NULL) *pszTmp = '\0'; if (EQUAL(psTableDef->pasFieldDef[i].szName, szSysId)) { sprintf(psTableDef->pasFieldDef[i].szName, "%s#", szNewName); } else if (EQUAL(psTableDef->pasFieldDef[i].szName, szUserId)) { sprintf(psTableDef->pasFieldDef[i].szName, "%s-ID", szNewName); } } } /*----------------------------------------------------------------- * Build new table name *----------------------------------------------------------------*/ sprintf(psTableDef->szTableName, "%s.%s", szNewName, szOldExt); } /********************************************************************** * _AVCE00WriteCreateCoverFile() * * Create a coverage file for the specified file type. * * The main part of the work is to find the right filename to use based on * the file type, the coverage precision, etc... the rest of job is * done by AVCBinWriteCreate(). * * Returns 0 on success, or -1 if an error happened. * * AVCWriteCloseCoverFile() will eventually have to be called to release the * resources used by the AVCBinFile structure. **********************************************************************/ int _AVCE00WriteCreateCoverFile(AVCE00WritePtr psInfo, AVCFileType eType, const char *pszLine, AVCTableDef *psTableDef) { char *pszPath, szFname[50]=""; int i, nStatus = 0; /* By now, new coverage precision should have been established */ CPLAssert(psInfo->nPrecision != AVC_DEFAULT_PREC); /*----------------------------------------------------------------- * Establish filename based on file type, precision, and possibly the * contents of the header line. *----------------------------------------------------------------*/ pszPath = psInfo->pszCoverPath; switch(eType) { case AVCFileARC: strcpy(szFname, "arc"); break; case AVCFilePAL: strcpy(szFname, "pal"); break; case AVCFileCNT: strcpy(szFname, "cnt"); break; case AVCFileLAB: strcpy(szFname, "lab"); break; case AVCFileTOL: if (psInfo->nPrecision == AVC_SINGLE_PREC) strcpy(szFname, "tol"); else strcpy(szFname, "par"); break; case AVCFilePRJ: strcpy(szFname, "prj"); break; case AVCFileTXT: strcpy(szFname, "txt"); break; case AVCFileTX6: /* For TX6/TX7: the filename is subclass_name.txt */ /* See bug 1261: It seems that empty subclass names are valid * for TX7. In this case we'll default the filename to txt.txt */ if (pszLine[0] == '\0') { strcpy(szFname, "txt.txt"); } else if (strlen(pszLine) > 30 || strchr(pszLine, ' ') != NULL) CPLError(CE_Failure, CPLE_IllegalArg, "Invalid TX6/TX7 subclass name \"%s\"", pszLine); else sprintf(szFname, "%s.txt", pszLine); break; case AVCFileRPL: /* For RPL and RXP: the filename is region_name.pal or region_name.rxp */ if (strlen(pszLine) > 30 || strchr(pszLine, ' ') != NULL) CPLError(CE_Failure, CPLE_IllegalArg, "Invalid RPL region name \"%s\"", pszLine); else sprintf(szFname, "%s.pal", pszLine); break; case AVCFileRXP: if (strlen(pszLine) > 30 || strchr(pszLine, ' ') != NULL) CPLError(CE_Failure, CPLE_IllegalArg, "Invalid RXP name \"%s\"", pszLine); else sprintf(szFname, "%s.rxp", pszLine); break; case AVCFileTABLE: /*------------------------------------------------------------- * For tables, Filename will be based on info in the psTableDef * but we need to rename the table and the system attributes * based on the new coverage name. *------------------------------------------------------------*/ if (psInfo->eCoverType != AVCCoverPC && psInfo->eCoverType != AVCCoverPC2) pszPath = psInfo->pszInfoPath; _AVCE00WriteRenameTable(psTableDef, psInfo->pszCoverName); break; default: CPLError(CE_Failure, CPLE_IllegalArg, "_AVCE00WriteCreateCoverFile(): Unsupported file type!"); nStatus = -1; break; } /*----------------------------------------------------------------- * V7 coverage filenames default to have a .adf extension * but PC coverage filenames (except .dbf tables) have no extensions. *----------------------------------------------------------------*/ if (psInfo->eCoverType == AVCCoverV7 && strchr(szFname, '.') == NULL) strcat(szFname, ".adf"); /*----------------------------------------------------------------- * Make sure filename is all lowercase and attempt to create the file *----------------------------------------------------------------*/ for(i=0; szFname[i] != '\0'; i++) szFname[i] = tolower(szFname[i]); if (nStatus == 0) { psInfo->eCurFileType = eType; if (eType == AVCFileTABLE) psInfo->hFile = AVCBinWriteCreateTable(pszPath, psInfo->pszCoverName, psTableDef, psInfo->eCoverType, psInfo->nPrecision, psInfo->psDBCSInfo); else psInfo->hFile = AVCBinWriteCreate(pszPath, szFname, psInfo->eCoverType, eType, psInfo->nPrecision, psInfo->psDBCSInfo); if (psInfo->hFile == NULL) { nStatus = -1; psInfo->eCurFileType = AVCFileUnknown; } } return nStatus; } /********************************************************************** * _AVCE00WriteCloseCoverFile() * * Close current coverage file and reset the contents of psInfo. * * File should have been previously opened by _AVCE00WriteCreateCoverFile(). * **********************************************************************/ void _AVCE00WriteCloseCoverFile(AVCE00WritePtr psInfo) { /*----------------------------------------------------------------- * PRJ sections behave differently... since there is only one "object" * per section, they accumulate lines while we read them, and we * write everything at once when we reach the end-of-section (EOP) line. *----------------------------------------------------------------*/ if (psInfo->eCurFileType == AVCFilePRJ) { AVCBinWriteObject(psInfo->hFile, psInfo->hParseInfo->cur.papszPrj); } AVCBinWriteClose(psInfo->hFile); psInfo->hFile = NULL; psInfo->eCurFileType = AVCFileUnknown; } /********************************************************************** * AVCE00WriteNextLine() * * Take the next line of E00 input for this coverage, parse it and * write the result to the coverage. * * Important Note: The E00 source lines are assumed to be valid... the * library performs no validation on the consistency of what it is * given as input (i.e. topology, polygons consistency, etc.). * So the coverage that will be created will be only as good as the * E00 input that is used to generate it. * * Returns 0 on success or -1 on error. **********************************************************************/ int AVCE00WriteNextLine(AVCE00WritePtr psInfo, const char *pszLine) { /*----------------------------------------------------------------- * TODO: Update this call to use _AVCE00ReadNextLineE00(), if * possible. *----------------------------------------------------------------*/ int nStatus = 0; CPLErrorReset(); /*----------------------------------------------------------------- * If we're at the top level inside a supersection... check if this * supersection ends here. *----------------------------------------------------------------*/ if (AVCE00ParseSuperSectionEnd(psInfo->hParseInfo, pszLine) == TRUE) { /* Nothing to do... it's all been done by the call to * AVCE00ParseSuperSectionEnd() */ } else if (psInfo->eCurFileType == AVCFileUnknown) { /*------------------------------------------------------------- * We're at the top level or inside a supersection... waiting * to encounter a valid section or supersection header * (i.e. "ARC 2", etc...) *------------------------------------------------------------*/ /*------------------------------------------------------------- * First check for a supersection header (TX6, RXP, IFO, ...) *------------------------------------------------------------*/ if ( AVCE00ParseSuperSectionHeader(psInfo->hParseInfo, pszLine) == AVCFileUnknown ) { /*--------------------------------------------------------- * This was not a supersection header... check if it's a simple * section header *--------------------------------------------------------*/ psInfo->eCurFileType=AVCE00ParseSectionHeader(psInfo->hParseInfo, pszLine); } /*------------------------------------------------------------- * If the coverage was created using AVC_DEFAULT_PREC and we are * processing the first section header, then use this section's * precision for the new coverage. * (Note: this code segment will be executed only once per * coverage and only if AVC_DEFAULT_PREC was selected) *------------------------------------------------------------*/ if (psInfo->nPrecision == AVC_DEFAULT_PREC && psInfo->eCurFileType != AVCFileUnknown) { psInfo->nPrecision = psInfo->hParseInfo->nPrecision; } if (psInfo->eCurFileType == AVCFileTABLE) { /*--------------------------------------------------------- * We can't create the file for a TABLE until the * whole header has been read... send the first header * line to the parser and wait until the whole header has * been read. *--------------------------------------------------------*/ AVCE00ParseNextLine(psInfo->hParseInfo, pszLine); } else if (psInfo->eCurFileType != AVCFileUnknown) { /*--------------------------------------------------------- * OK, we've found a valid section header... create the * corresponding file in the coverage. * Note: supersection headers don't trigger the creation * of any output file... they just alter the psInfo state. *--------------------------------------------------------*/ nStatus = _AVCE00WriteCreateCoverFile(psInfo, psInfo->eCurFileType, psInfo->hParseInfo->pszSectionHdrLine, NULL); } } else if (psInfo->eCurFileType == AVCFileTABLE && ! psInfo->hParseInfo->bTableHdrComplete ) { /*------------------------------------------------------------- * We're reading a TABLE header... continue reading lines * from the header, and create the output file only once * the header will have been completely read. * * Note: When parsing a TABLE, the first object returned will * be the AVCTableDef, then data records will follow. *------------------------------------------------------------*/ AVCTableDef *psTableDef; psTableDef = (AVCTableDef*)AVCE00ParseNextLine(psInfo->hParseInfo, pszLine); if (psTableDef) { nStatus = _AVCE00WriteCreateCoverFile(psInfo, psInfo->eCurFileType, psInfo->hParseInfo->pszSectionHdrLine, psTableDef); } } else { /*------------------------------------------------------------- * We're are in the middle of a section... first check if we * have reached the end. * * note: The first call to AVCE00ParseSectionEnd() with FALSE will * not reset the parser until we close the file... and then * we call the function again to reset the parser. *------------------------------------------------------------*/ if (AVCE00ParseSectionEnd(psInfo->hParseInfo, pszLine, FALSE)) { _AVCE00WriteCloseCoverFile(psInfo); AVCE00ParseSectionEnd(psInfo->hParseInfo, pszLine, TRUE); } else /*------------------------------------------------------------- * ... not at the end yet, so continue reading objects. *------------------------------------------------------------*/ { void *psObj; psObj = AVCE00ParseNextLine(psInfo->hParseInfo, pszLine); if (psObj) AVCBinWriteObject(psInfo->hFile, psObj); } } if (psInfo->hParseInfo->bForceEndOfSection) { /*------------------------------------------------------------- * The last call encountered an implicit end of section, so * we close the section now without waiting for an end-of-section * line (there won't be any!)... and get ready to proceed with * the next section. * This is used for TABLEs. *------------------------------------------------------------*/ _AVCE00WriteCloseCoverFile(psInfo); AVCE00ParseSectionEnd(psInfo->hParseInfo, pszLine, TRUE); /* psInfo->hParseInfo->bForceEndOfSection = FALSE; */ } if (CPLGetLastErrorNo() != 0) nStatus = -1; return nStatus; } /********************************************************************** * AVCE00DeleteCoverage() * * Delete a coverage directory, its contents, and the associated info * tables. * * Note: * When deleting tables, only the ../info/arc????.nit and arc????.dat * need to be deleted; the arc.dir does not need to be updated. This * is exactly what Arc/Info's KILL command does. * * Returns 0 on success or -1 on error. **********************************************************************/ int AVCE00DeleteCoverage(const char *pszCoverToDelete) { int i, j, nStatus = 0; char *pszInfoPath, *pszCoverPath, *pszCoverName; const char *pszFname; char **papszTables=NULL, **papszFiles=NULL; AVCE00ReadPtr psInfo; VSIStatBuf sStatBuf; AVCCoverType eCoverType; CPLErrorReset(); /*----------------------------------------------------------------- * Since we don't want to duplicate all the logic to figure coverage * and info dir name, etc... we'll simply open the coverage and * grab the info we need from the coverage handle. * By the same way, this will verify that the coverage exists and is * valid. *----------------------------------------------------------------*/ psInfo = AVCE00ReadOpen(pszCoverToDelete); if (psInfo == NULL) { CPLError(CE_Failure, CPLE_FileIO, "Cannot delete coverage %s: it does not appear to be valid\n", pszCoverToDelete); return -1; } pszCoverPath = CPLStrdup(psInfo->pszCoverPath); pszInfoPath = CPLStrdup(psInfo->pszInfoPath); pszCoverName = CPLStrdup(psInfo->pszCoverName); eCoverType = psInfo->eCoverType; AVCE00ReadClose(psInfo); /*----------------------------------------------------------------- * Delete files in cover directory. *----------------------------------------------------------------*/ papszFiles = CPLReadDir(pszCoverPath); for(i=0; nStatus==0 && papszFiles && papszFiles[i]; i++) { if (!EQUAL(".", papszFiles[i]) && !EQUAL("..", papszFiles[i])) { pszFname = CPLSPrintf("%s%s", pszCoverPath, papszFiles[i]); if (unlink(pszFname) != 0) { CPLError(CE_Failure, CPLE_FileIO, "Failed deleting %s%s: %s", pszCoverPath, papszFiles[i], strerror); nStatus = -1; break; } } } CSLDestroy(papszFiles); papszFiles = NULL; /*----------------------------------------------------------------- * Get the list of info files (ARC????) to delete and delete them * (No 'info' directory for PC coverages) *----------------------------------------------------------------*/ if (nStatus == 0 && eCoverType != AVCCoverPC && eCoverType != AVCCoverPC2) { papszTables = AVCBinReadListTables(pszInfoPath, pszCoverName, &papszFiles, eCoverType, NULL /*DBCSInfo*/); for(i=0; nStatus==0 && papszFiles && papszFiles[i]; i++) { /* Convert table filename to lowercases */ for(j=0; papszFiles[i] && papszFiles[i][j]!='\0'; j++) papszFiles[i][j] = tolower(papszFiles[i][j]); /* Delete the .DAT file */ pszFname = CPLSPrintf("%s%s.dat", pszInfoPath, papszFiles[i]); if ( VSIStat(pszFname, &sStatBuf) != -1 && unlink(pszFname) != 0) { CPLError(CE_Failure, CPLE_FileIO, "Failed deleting %s%s: %s", pszInfoPath, papszFiles[i], strerror); nStatus = -1; break; } /* Delete the .DAT file */ pszFname = CPLSPrintf("%s%s.nit", pszInfoPath, papszFiles[i]); if ( VSIStat(pszFname, &sStatBuf) != -1 && unlink(pszFname) != 0) { CPLError(CE_Failure, CPLE_FileIO, "Failed deleting %s%s: %s", pszInfoPath, papszFiles[i], strerror); nStatus = -1; break; } } CSLDestroy(papszTables); CSLDestroy(papszFiles); } /*----------------------------------------------------------------- * Delete the coverage directory itself * In some cases, the directory could be locked by another application * on the same system or somewhere on the network. * Define AVC_IGNORE_RMDIR_ERROR at compile time if you want this * error to be ignored. *----------------------------------------------------------------*/ if (VSIRmdir(pszCoverPath) != 0) { #ifndef AVC_IGNORE_RMDIR_ERROR CPLError(CE_Failure, CPLE_FileIO, "Failed deleting directory %s: %s", pszCoverPath, strerror); nStatus = -1; #endif } CPLFree(pszCoverPath); CPLFree(pszInfoPath); CPLFree(pszCoverName); return nStatus; } avce00-2.0.0/cpl_port.h0100775000076400007640000002312406761516063014066 0ustar danieldaniel/****************************************************************************** * Copyright (c) 1998, Frank Warmerdam * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ****************************************************************************** * * cpl_port.h * * Include file providing low level portability services for CPL. This * should be the first include file for any CPL based code. It provides the * following: * * o Includes some standard system include files, such as stdio, and stdlib. * * o Defines CPL_C_START, CPL_C_END macros. * * o Ensures that some other standard macros like NULL are defined. * * o Defines some portability stuff like CPL_MSB, or CPL_LSB. * * o Ensures that core types such as GBool, GInt32, GInt16, GUInt32, * GUInt16, and GByte are defined. * * $Log: cpl_port.h,v $ * Revision 1.1 1999/08/27 14:09:55 daniel * Update CPL files * * Revision 1.13 1999/05/20 02:54:38 warmerda * Added API documentation * * Revision 1.12 1999/05/14 20:35:03 warmerda * added some more swapping macros * * Revision 1.11 1999/05/13 19:19:06 warmerda * Only use dbmalloc if DEBUG is set. * * Revision 1.10 1999/03/02 21:08:11 warmerda * autoconf switch * * Revision 1.9 1999/02/17 01:41:17 warmerda * Added NULL. * * Revision 1.8 1999/02/02 21:32:38 warmerda * Added CPL_{MSB,LSB}WORD{16,32} macros. * * Revision 1.7 1999/02/02 19:02:36 warmerda * Removed duplicates of base types, and CPL_LSB * * Revision 1.6 1999/01/28 18:36:06 warmerda * Ensure WIN32 is defined on Windows. * * Revision 1.5 1999/01/28 05:26:12 danmo * Added byte swapping macros. * * Revision 1.4 1998/12/15 19:05:30 warmerda * added errno.h * * Revision 1.3 1998/12/14 04:50:07 warmerda * Added DBMALLOC support * * Revision 1.2 1998/12/04 21:38:40 danmo * Changed str*casecmp() to str*icmp() for WIN32 * * Revision 1.1 1998/12/03 18:26:02 warmerda * New * */ #ifndef CPL_BASE_H_INCLUDED #define CPL_BASE_H_INCLUDED /** * \file cpl_port.h * * Core portability definitions for CPL. * */ /* ==================================================================== */ /* We will use WIN32 as a standard windows define. */ /* ==================================================================== */ #if defined(_WIN32) && !defined(WIN32) # define WIN32 #endif /* ==================================================================== */ /* Standard include files. */ /* ==================================================================== */ #include "cpl_config.h" #include #include #include #include #include #include #if defined(HAVE_LIBDBMALLOC) && defined(HAVE_DBMALLOC_H) && defined(DEBUG) # define DBMALLOC # include #endif /* ==================================================================== */ /* Base portability stuff ... this stuff may need to be */ /* modified for new platforms. */ /* ==================================================================== */ /*--------------------------------------------------------------------- * types for 16 and 32 bits integers, etc... *--------------------------------------------------------------------*/ #if UINT_MAX == 65535 typedef long GInt32; typedef unsigned long GUInt32; #else typedef int GInt32; typedef unsigned int GUInt32; #endif typedef short GInt16; typedef unsigned short GUInt16; typedef unsigned char GByte; typedef int GBool; /* ==================================================================== */ /* Other standard services. */ /* ==================================================================== */ #ifdef __cplusplus # define CPL_C_START extern "C" { # define CPL_C_END } #else # define CPL_C_START # define CPL_C_END #endif /* # define CPL_DLL __declspec(dllexport) */ #define CPL_DLL #ifndef NULL # define NULL 0 #endif #ifndef FALSE # define FALSE 0 #endif #ifndef TRUE # define TRUE 1 #endif #ifndef MAX # define MIN(a,b) ((ab) ? a : b) #endif #ifndef NULL #define NULL 0 #endif #ifndef ABS # define ABS(x) ((x<0) ? (-1*(x)) : x) #endif #ifndef EQUAL #ifdef WIN32 # define EQUALN(a,b,n) (strnicmp(a,b,n)==0) # define EQUAL(a,b) (stricmp(a,b)==0) #else # define EQUALN(a,b,n) (strncasecmp(a,b,n)==0) # define EQUAL(a,b) (strcasecmp(a,b)==0) #endif #endif /*--------------------------------------------------------------------- * CPL_LSB and CPL_MSB * Only one of these 2 macros should be defined and specifies the byte * ordering for the current platform. * This should be defined in the Makefile, but if it is not then * the default is CPL_LSB (Intel ordering, LSB first). *--------------------------------------------------------------------*/ #if defined(WORDS_BIGENDIAN) && !defined(CPL_MSB) && !defined(CPL_LSB) # define CPL_MSB #endif #if ! ( defined(CPL_LSB) || defined(CPL_MSB) ) #define CPL_LSB #endif /*--------------------------------------------------------------------- * Little endian <==> big endian byte swap macros. *--------------------------------------------------------------------*/ #define CPL_SWAP16(x) \ ((GUInt16)( \ (((GUInt16)(x) & 0x00ffU) << 8) | \ (((GUInt16)(x) & 0xff00U) >> 8) )) #define CPL_SWAP32(x) \ ((GUInt32)( \ (((GUInt32)(x) & (GUInt32)0x000000ffUL) << 24) | \ (((GUInt32)(x) & (GUInt32)0x0000ff00UL) << 8) | \ (((GUInt32)(x) & (GUInt32)0x00ff0000UL) >> 8) | \ (((GUInt32)(x) & (GUInt32)0xff000000UL) >> 24) )) #define CPL_SWAP32PTR(x) \ { \ GByte byTemp, *pabyData = (GByte *) (x); \ \ byTemp = pabyData[0]; \ pabyData[0] = pabyData[3]; \ pabyData[3] = byTemp; \ byTemp = pabyData[1]; \ pabyData[1] = pabyData[2]; \ pabyData[2] = byTemp; \ } #define CPL_SWAP64PTR(x) \ { \ GByte byTemp, *pabyData = (GByte *) (x); \ \ byTemp = pabyData[0]; \ pabyData[0] = pabyData[7]; \ pabyData[7] = byTemp; \ byTemp = pabyData[1]; \ pabyData[1] = pabyData[6]; \ pabyData[6] = byTemp; \ byTemp = pabyData[2]; \ pabyData[2] = pabyData[5]; \ pabyData[5] = byTemp; \ byTemp = pabyData[3]; \ pabyData[3] = pabyData[4]; \ pabyData[4] = byTemp; \ } /* Until we have a safe 64 bits integer data type defined, we'll replace m * this version of the CPL_SWAP64() macro with a less efficient one. */ /* #define CPL_SWAP64(x) \ ((uint64)( \ (uint64)(((uint64)(x) & (uint64)0x00000000000000ffULL) << 56) | \ (uint64)(((uint64)(x) & (uint64)0x000000000000ff00ULL) << 40) | \ (uint64)(((uint64)(x) & (uint64)0x0000000000ff0000ULL) << 24) | \ (uint64)(((uint64)(x) & (uint64)0x00000000ff000000ULL) << 8) | \ (uint64)(((uint64)(x) & (uint64)0x000000ff00000000ULL) >> 8) | \ (uint64)(((uint64)(x) & (uint64)0x0000ff0000000000ULL) >> 24) | \ (uint64)(((uint64)(x) & (uint64)0x00ff000000000000ULL) >> 40) | \ (uint64)(((uint64)(x) & (uint64)0xff00000000000000ULL) >> 56) )) */ #define CPL_SWAPDOUBLE(p) { \ double _tmp = *(double *)(p); \ ((GByte *)(p))[0] = ((GByte *)&_tmp)[7]; \ ((GByte *)(p))[1] = ((GByte *)&_tmp)[6]; \ ((GByte *)(p))[2] = ((GByte *)&_tmp)[5]; \ ((GByte *)(p))[3] = ((GByte *)&_tmp)[4]; \ ((GByte *)(p))[4] = ((GByte *)&_tmp)[3]; \ ((GByte *)(p))[5] = ((GByte *)&_tmp)[2]; \ ((GByte *)(p))[6] = ((GByte *)&_tmp)[1]; \ ((GByte *)(p))[7] = ((GByte *)&_tmp)[0]; \ } #ifdef CPL_MSB # define CPL_MSBWORD16(x) (x) # define CPL_LSBWORD16(x) CPL_SWAP16(x) # define CPL_MSBWORD32(x) (x) # define CPL_LSBWORD32(x) CPL_SWAP32(x) # define CPL_MSBPTR32(x) # define CPL_LSBPTR32(x) CPL_SWAP32PTR(x) #else # define CPL_LSBWORD16(x) (x) # define CPL_MSBWORD16(x) CPL_SWAP16(x) # define CPL_LSBWORD32(x) (x) # define CPL_MSBWORD32(x) CPL_SWAP32(x) # define CPL_LSBPTR32(x) # define CPL_MSBPTR32(x) CPL_SWAP32PTR(x) #endif #endif /* ndef CPL_BASE_H_INCLUDED */ avce00-2.0.0/avc_e00gen.c0100664000076400007640000014651710444022315014140 0ustar danieldaniel/********************************************************************** * $Id: avc_e00gen.c,v 1.17 2006/06/14 15:01:33 daniel Exp $ * * Name: avc_e00gen.c * Project: Arc/Info vector coverage (AVC) BIN->E00 conversion library * Language: ANSI C * Purpose: Functions to generate ASCII E00 lines form binary structures. * Author: Daniel Morissette, dmorissette@dmsolutions.ca * ********************************************************************** * Copyright (c) 1999-2005, Daniel Morissette * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ********************************************************************** * * $Log: avc_e00gen.c,v $ * Revision 1.17 2006/06/14 15:01:33 daniel * Remove any embeded '\0' from data line in AVCE00GenTableRec() * * Revision 1.16 2005/06/03 03:49:58 daniel * Update email address, website url, and copyright dates * * Revision 1.15 2004/08/19 17:48:20 warmerda * Avoid uninitialized variable warnings. * * Revision 1.14 2001/11/25 21:15:23 daniel * Added hack (AVC_MAP_TYPE40_TO_DOUBLE) to map type 40 fields bigger than 8 * digits to double precision as we generate E00 output (bug599) * * Revision 1.13 2001/11/19 20:39:48 daniel * Change to correctly format 0-arc PAL records, so that they have a * single "filler" arc record * * Revision 1.12 2000/09/26 20:21:04 daniel * Added AVCCoverPC write * * Revision 1.11 2000/09/22 19:45:20 daniel * Switch to MIT-style license * * Revision 1.10 2000/02/04 04:54:03 daniel * Fixed warnings * * Revision 1.9 2000/02/03 07:21:02 daniel * TXT/TX6 with string longer than 80 chars: split string in 80 chars chunks * * Revision 1.8 2000/02/02 04:28:00 daniel * Fixed support of TX6/RXP/RPL coming from "weird" coverages * * Revision 1.7 1999/08/23 18:20:49 daniel * Fixed support for attribute fields type 40 * * Revision 1.6 1999/05/17 16:19:39 daniel * Made sure ACVE00GenTableRec() removes all spaces at the end of a * table record line (it used to leave one space) * * Revision 1.5 1999/05/11 02:08:17 daniel * Simple changes related to the addition of coverage write support. * * Revision 1.4 1999/03/03 02:06:38 daniel * Properly handle 8 bytes floats inside single precision tables. * * Revision 1.3 1999/02/25 17:01:58 daniel * Added support for 16 bit integers in INFO tables (type=50, size=2) * * Revision 1.2 1999/02/25 04:17:51 daniel * Added TXT, TX6/TX7, RXP and RPL support + some minor changes * * Revision 1.1 1999/01/29 16:28:52 daniel * Initial revision * **********************************************************************/ #include "avc.h" #include /* toupper() */ /********************************************************************** * AVCE00GenInfoAlloc() * * Allocate and initialize a new AVCE00GenInfo structure. * * The structure will eventually have to be freed with AVCE00GenInfoFree(). **********************************************************************/ AVCE00GenInfo *AVCE00GenInfoAlloc(int nCoverPrecision) { AVCE00GenInfo *psInfo; psInfo = (AVCE00GenInfo*)CPLCalloc(1,sizeof(AVCE00GenInfo)); /* Allocate output buffer. * 2k should be enough... the biggest thing we'll need to store * in it will be 1 complete INFO table record. */ psInfo->nBufSize = 2048; psInfo->pszBuf = (char *)CPLMalloc(psInfo->nBufSize*sizeof(char)); psInfo->nPrecision = nCoverPrecision; return psInfo; } /********************************************************************** * AVCE00GenInfoFree() * * Free any memory associated with a AVCE00GenInfo structure. **********************************************************************/ void AVCE00GenInfoFree(AVCE00GenInfo *psInfo) { if (psInfo) CPLFree(psInfo->pszBuf); CPLFree(psInfo); } /********************************************************************** * AVCE00GenReset() * * Reset the fields in the AVCE00GenInfo structure so that further calls * with bCont = TRUE (ex: AVCE00GenArc(psInfo, TRUE)) would return NULL. **********************************************************************/ void AVCE00GenReset(AVCE00GenInfo *psInfo) { /* Reinitialize counters so that further calls with bCont = TRUE, * like AVCE00GenArc(psInfo, TRUE) would return NULL. */ psInfo->iCurItem = psInfo->numItems = 0; } /********************************************************************** * AVCE00GenStartSection() * * Generate the first line of an E00 section. * * pszClassName applies only to JABBERWOCKY type of sections. **********************************************************************/ const char *AVCE00GenStartSection(AVCE00GenInfo *psInfo, AVCFileType eType, const char *pszClassName) { char *pszName = "UNK"; AVCE00GenReset(psInfo); if (eType == AVCFileTX6 || eType == AVCFileRXP || eType == AVCFileRPL) { /* TX6/RXP/RPL sections start with the class name (the basename * of the file) in uppercase. * ex: The section for "cities.txt" would start with "CITIES" */ int i; for(i=0; pszClassName[i] != '\0'; i++) { psInfo->pszBuf[i] = toupper(pszClassName[i]); } psInfo->pszBuf[i] = '\0'; } else { /* In most cases, the section starts with a 3 letters code followed * by the precision code (2 or 3) */ switch(eType) { case AVCFileARC: pszName = "ARC"; break; case AVCFilePAL: pszName = "PAL"; break; case AVCFileCNT: pszName = "CNT"; break; case AVCFileLAB: pszName = "LAB"; break; case AVCFileTOL: pszName = "TOL"; break; case AVCFilePRJ: pszName = "PRJ"; break; case AVCFileTXT: pszName = "TXT"; break; default: CPLError(CE_Failure, CPLE_NotSupported, "Unsupported E00 section type!"); } if (psInfo->nPrecision == AVC_DOUBLE_PREC) sprintf(psInfo->pszBuf, "%s 3", pszName); else sprintf(psInfo->pszBuf, "%s 2", pszName); } return psInfo->pszBuf; } /********************************************************************** * AVCE00GenEndSection() * * Generate the last line(s) of an E00 section. * * This function should be called once with bCont=FALSE to get the * first "end of section" line for the current section, and then call * with bCont=TRUE to get all the other lines. * * The function returns NULL when there are no more lines to generate * for this "end of section". **********************************************************************/ const char *AVCE00GenEndSection(AVCE00GenInfo *psInfo, AVCFileType eType, GBool bCont) { if (bCont == FALSE) { /*------------------------------------------------------------- * Most section types end with only 1 line. *------------------------------------------------------------*/ AVCE00GenReset(psInfo); psInfo->iCurItem = 0; if (eType == AVCFileARC || eType == AVCFilePAL || eType == AVCFileRPL || eType == AVCFileCNT || eType == AVCFileTOL || eType == AVCFileTXT || eType == AVCFileTX6 ) { sprintf(psInfo->pszBuf, " -1 0 0 0 0 0 0"); } else if (eType == AVCFileLAB) { if (psInfo->nPrecision == AVC_DOUBLE_PREC) sprintf(psInfo->pszBuf, " -1 0 0.00000000000000E+00 0.00000000000000E+00"); else sprintf(psInfo->pszBuf, " -1 0 0.0000000E+00 0.0000000E+00"); } else if (eType == AVCFilePRJ) { sprintf(psInfo->pszBuf, "EOP"); } else if (eType == AVCFileRXP ) { sprintf(psInfo->pszBuf," -1 0"); } else { CPLError(CE_Failure, CPLE_NotSupported, "Unsupported E00 section type!"); return NULL; } } else if ( psInfo->iCurItem == 0 && psInfo->nPrecision == AVC_DOUBLE_PREC && (eType == AVCFilePAL || eType == AVCFileRPL) ) { /*--------------------------------------------------------- * Return the 2nd line for the end of a PAL or RPL section. *--------------------------------------------------------*/ sprintf(psInfo->pszBuf, " 0.00000000000000E+00 0.00000000000000E+00"); psInfo->iCurItem++; } else { /*----------------------------------------------------- * All other section types end with only one line, and thus * we return NULL when bCont==TRUE *----------------------------------------------------*/ return NULL; } return psInfo->pszBuf; } /********************************************************************** * AVCE00GenObject() * * Cover function on top of AVCE00GenArc/Pal/Cnt/Lab() that will * call the right function according to argument eType. * * Since there is no compiler type checking on psObj, you have to * be very careful to make sure you pass an object of the right type * when you use this function! * * The function returns NULL when there are no more lines to generate * for this ARC. **********************************************************************/ const char *AVCE00GenObject(AVCE00GenInfo *psInfo, AVCFileType eType, void *psObj, GBool bCont) { const char *pszLine = NULL; switch(eType) { case AVCFileARC: pszLine = AVCE00GenArc(psInfo, (AVCArc*)psObj, bCont); break; case AVCFilePAL: case AVCFileRPL: pszLine = AVCE00GenPal(psInfo, (AVCPal*)psObj, bCont); break; case AVCFileCNT: pszLine = AVCE00GenCnt(psInfo, (AVCCnt*)psObj, bCont); break; case AVCFileLAB: pszLine = AVCE00GenLab(psInfo, (AVCLab*)psObj, bCont); break; case AVCFileTOL: pszLine = AVCE00GenTol(psInfo, (AVCTol*)psObj, bCont); break; case AVCFileTXT: pszLine = AVCE00GenTxt(psInfo, (AVCTxt*)psObj, bCont); break; case AVCFileTX6: pszLine = AVCE00GenTx6(psInfo, (AVCTxt*)psObj, bCont); break; case AVCFilePRJ: pszLine = AVCE00GenPrj(psInfo, (char**)psObj, bCont); break; case AVCFileRXP: pszLine = AVCE00GenRxp(psInfo, (AVCRxp*)psObj, bCont); break; default: CPLError(CE_Failure, CPLE_NotSupported, "AVCE00GenObject(): Unsupported file type!"); } return pszLine; } /*===================================================================== ARC stuff =====================================================================*/ /********************************************************************** * AVCE00GenArc() * * Generate the next line of an E00 ARC. * * This function should be called once with bCont=FALSE to get the * first E00 line for the current ARC, and then call with bCont=TRUE * to get all the other lines for this ARC. * * The function returns NULL when there are no more lines to generate * for this ARC. **********************************************************************/ const char *AVCE00GenArc(AVCE00GenInfo *psInfo, AVCArc *psArc, GBool bCont) { if (bCont == FALSE) { /* Initialize the psInfo structure with info about the * current ARC. */ psInfo->iCurItem = 0; if (psInfo->nPrecision == AVC_DOUBLE_PREC) psInfo->numItems = psArc->numVertices; else psInfo->numItems = (psArc->numVertices+1)/2; /* And return the ARC header line */ sprintf(psInfo->pszBuf, "%10d%10d%10d%10d%10d%10d%10d", psArc->nArcId, psArc->nUserId, psArc->nFNode, psArc->nTNode, psArc->nLPoly, psArc->nRPoly, psArc->numVertices); } else if (psInfo->iCurItem < psInfo->numItems) { int iVertex; /* return the next set of vertices for the ARC. */ if (psInfo->nPrecision == AVC_DOUBLE_PREC) { iVertex = psInfo->iCurItem; psInfo->pszBuf[0] = '\0'; AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFileARC, psArc->pasVertices[iVertex].x); AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFileARC, psArc->pasVertices[iVertex].y); } else { iVertex = psInfo->iCurItem*2; psInfo->pszBuf[0] = '\0'; AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFileARC, psArc->pasVertices[iVertex].x); AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFileARC, psArc->pasVertices[iVertex].y); /* Check because if we have a odd number of vertices then * the last line contains only one pair of vertices. */ if (iVertex+1 < psArc->numVertices) { AVCPrintRealValue(psInfo->pszBuf,psInfo->nPrecision,AVCFileARC, psArc->pasVertices[iVertex+1].x); AVCPrintRealValue(psInfo->pszBuf,psInfo->nPrecision,AVCFileARC, psArc->pasVertices[iVertex+1].y); } } psInfo->iCurItem++; } else { /* No more lines to generate for this ARC. */ return NULL; } return psInfo->pszBuf; } /*===================================================================== PAL stuff =====================================================================*/ /********************************************************************** * AVCE00GenPal() * * Generate the next line of an E00 PAL (Polygon Arc List) entry. * * This function should be called once with bCont=FALSE to get the * first E00 line for the current PAL, and then call with bCont=TRUE * to get all the other lines for this PAL. * * The function returns NULL when there are no more lines to generate * for this PAL entry. **********************************************************************/ const char *AVCE00GenPal(AVCE00GenInfo *psInfo, AVCPal *psPal, GBool bCont) { if (bCont == FALSE) { /* Initialize the psInfo structure with info about the * current PAL. (Number of lines excluding header) */ psInfo->numItems = (psPal->numArcs+1)/2; /* And return the PAL header line. */ sprintf(psInfo->pszBuf, "%10d", psPal->numArcs); AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFilePAL, psPal->sMin.x); AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFilePAL, psPal->sMin.y); /* Double precision PAL entries have their header on 2 lines! */ if (psInfo->nPrecision == AVC_DOUBLE_PREC) { psInfo->iCurItem = -1; /* Means 1 line left in header */ } else { AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFilePAL, psPal->sMax.x); AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFilePAL, psPal->sMax.y); psInfo->iCurItem = 0; /* Next thing = first Arc entry */ } } else if (psInfo->iCurItem == -1) { /* Second (and last) header line for double precision coverages */ psInfo->pszBuf[0] = '\0'; AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFilePAL, psPal->sMax.x); AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFilePAL, psPal->sMax.y); if ( psInfo->numItems == 0 ) { psInfo->iCurItem = -2; /* We have a 0-arc polygon, which needs an arc list with one "0 0 0" element */ } else { psInfo->iCurItem = 0; /* Next thing = first Arc entry */ } } else if (psInfo->iCurItem == -2) { sprintf(psInfo->pszBuf, "%10d%10d%10d", 0, 0, 0); psInfo->iCurItem = 0; /* Next thing = first Arc entry */ } else if (psInfo->iCurItem < psInfo->numItems) { /* Return PAL Arc entries... */ int iArc; iArc = psInfo->iCurItem*2; /* If we have a odd number of arcs then * the last line contains only one arc entry. */ if (iArc+1 < psPal->numArcs) { sprintf(psInfo->pszBuf, "%10d%10d%10d%10d%10d%10d", psPal->pasArcs[iArc].nArcId, psPal->pasArcs[iArc].nFNode, psPal->pasArcs[iArc].nAdjPoly, psPal->pasArcs[iArc+1].nArcId, psPal->pasArcs[iArc+1].nFNode, psPal->pasArcs[iArc+1].nAdjPoly); } else { sprintf(psInfo->pszBuf, "%10d%10d%10d", psPal->pasArcs[iArc].nArcId, psPal->pasArcs[iArc].nFNode, psPal->pasArcs[iArc].nAdjPoly); } psInfo->iCurItem++; } else { /* No more lines to generate for this PAL. */ return NULL; } return psInfo->pszBuf; } /*===================================================================== CNT stuff =====================================================================*/ /********************************************************************** * AVCE00GenCnt() * * Generate the next line of an E00 CNT (Polygon Centroid) entry. * * This function should be called once with bCont=FALSE to get the * first E00 line for the current CNT, and then call with bCont=TRUE * to get all the other lines for this CNT. * * The function returns NULL when there are no more lines to generate * for this CNT entry. **********************************************************************/ const char *AVCE00GenCnt(AVCE00GenInfo *psInfo, AVCCnt *psCnt, GBool bCont) { if (bCont == FALSE) { /* Initialize the psInfo structure with info about the * current CNT. */ psInfo->iCurItem = 0; psInfo->numItems = (psCnt->numLabels+7)/8; /* And return the CNT header line. */ sprintf(psInfo->pszBuf, "%10d", psCnt->numLabels); AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFileCNT, psCnt->sCoord.x); AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFileCNT, psCnt->sCoord.y); } else if (psInfo->iCurItem < psInfo->numItems) { /* Return CNT Label Ids, 8 label Ids per line... */ int i, nFirstLabel, numLabels; nFirstLabel = psInfo->iCurItem * 8; numLabels = MIN(8, (psCnt->numLabels-nFirstLabel)); psInfo->pszBuf[0] = '\0'; for(i=0; i < numLabels; i++) { sprintf(psInfo->pszBuf + strlen(psInfo->pszBuf), "%10d", psCnt->panLabelIds[nFirstLabel+i] ); } psInfo->iCurItem++; } else { /* No more lines to generate for this CNT. */ return NULL; } return psInfo->pszBuf; } /*===================================================================== LAB stuff =====================================================================*/ /********************************************************************** * AVCE00GenLab() * * Generate the next line of an E00 LAB (Label) entry. * * This function should be called once with bCont=FALSE to get the * first E00 line for the current LAB, and then call with bCont=TRUE * to get all the other lines for this LAB. * * The function returns NULL when there are no more lines to generate * for this LAB entry. **********************************************************************/ const char *AVCE00GenLab(AVCE00GenInfo *psInfo, AVCLab *psLab, GBool bCont) { if (bCont == FALSE) { /* Initialize the psInfo structure with info about the * current LAB. (numItems = Number of lines excluding header) */ psInfo->iCurItem = 0; if (psInfo->nPrecision == AVC_DOUBLE_PREC) psInfo->numItems = 2; else psInfo->numItems = 1; /* And return the LAB header line. */ sprintf(psInfo->pszBuf, "%10d%10d", psLab->nValue, psLab->nPolyId); AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFileLAB, psLab->sCoord1.x); AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFileLAB, psLab->sCoord1.y); } else if (psInfo->iCurItem < psInfo->numItems) { /* Return next Label coordinates... */ if (psInfo->nPrecision != AVC_DOUBLE_PREC) { /* Single precision, all on the same line */ psInfo->pszBuf[0] = '\0'; AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFileLAB, psLab->sCoord2.x); AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFileLAB, psLab->sCoord2.y); AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFileLAB, psLab->sCoord3.x); AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFileLAB, psLab->sCoord3.y); } else if (psInfo->iCurItem == 0) { /* 2nd line, in a double precision coverage */ psInfo->pszBuf[0] = '\0'; AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFileLAB, psLab->sCoord2.x); AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFileLAB, psLab->sCoord2.y); } else { /* 3rd line, in a double precision coverage */ psInfo->pszBuf[0] = '\0'; AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFileLAB, psLab->sCoord3.x); AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFileLAB, psLab->sCoord3.y); } psInfo->iCurItem++; } else { /* No more lines to generate for this LAB. */ return NULL; } return psInfo->pszBuf; } /*===================================================================== TOL stuff =====================================================================*/ /********************************************************************** * AVCE00GenTol() * * Generate the next line of an E00 TOL (Tolerance) entry. * * This function should be called once with bCont=FALSE to get the * first E00 line for the current TOL, and then call with bCont=TRUE * to get all the other lines for this TOL. * * The function returns NULL when there are no more lines to generate * for this TOL entry. **********************************************************************/ const char *AVCE00GenTol(AVCE00GenInfo *psInfo, AVCTol *psTol, GBool bCont) { if (bCont == TRUE) { /*--------------------------------------------------------- * TOL entries are only 1 line, we support the bCont flag * only for compatibility with the other AVCE00Gen*() functions. *--------------------------------------------------------*/ return NULL; } sprintf(psInfo->pszBuf, "%10d%10d", psTol->nIndex, psTol->nFlag); AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFileTOL, psTol->dValue); return psInfo->pszBuf; } /*===================================================================== PRJ stuff =====================================================================*/ /********************************************************************** * AVCE00GenPrj() * * Generate the next line of an E00 PRJ (Projection) section. * * This function should be called once with bCont=FALSE to get the * first E00 line for the current PRJ, and then call with bCont=TRUE * to get all the other lines for this PRJ. * * The function returns NULL when there are no more lines to generate * for this PRJ entry. **********************************************************************/ const char *AVCE00GenPrj(AVCE00GenInfo *psInfo, char **papszPrj, GBool bCont) { if (bCont == FALSE) { /*--------------------------------------------------------- * Initialize the psInfo structure with info about the * current PRJ. (numItems = Number of lines to output) *--------------------------------------------------------*/ psInfo->iCurItem = 0; psInfo->numItems = CSLCount(papszPrj) * 2; } if (psInfo->iCurItem < psInfo->numItems) { /*--------------------------------------------------------- * Return the next PRJ section line. Note that every * second line of the output is only a "~". *--------------------------------------------------------*/ if (psInfo->iCurItem % 2 == 0) { /*----------------------------------------------------- * In theory we should split lines longer than 80 chars on * several lines, but I won't do it for now since I never * saw any projection line longer than 80 chars. *----------------------------------------------------*/ sprintf(psInfo->pszBuf, "%s", papszPrj[psInfo->iCurItem/2]); } else { /*----------------------------------------------------- * Every second line in a PRJ section contains only a "~", * this is a way to tell that the previous line was complete. *----------------------------------------------------*/ sprintf(psInfo->pszBuf, "~"); } psInfo->iCurItem++; } else { /* No more lines to generate for this PRJ. */ return NULL; } return psInfo->pszBuf; } /*===================================================================== TXT stuff =====================================================================*/ /********************************************************************** * AVCE00GenTxt() * * Generate the next line of an E00 TXT (Annotation) entry. * * This function should be called once with bCont=FALSE to get the * first E00 line for the current TXT, and then call with bCont=TRUE * to get all the other lines for this TXT. * * The function returns NULL when there are no more lines to generate * for this TXT entry. **********************************************************************/ const char *AVCE00GenTxt(AVCE00GenInfo *psInfo, AVCTxt *psTxt, GBool bCont) { int numFixedLines; /* numFixedLines is the number of lines to generate before the line(s) * with the text string */ if (psInfo->nPrecision == AVC_SINGLE_PREC) numFixedLines = 4; else numFixedLines = 6; if (bCont == FALSE) { /*------------------------------------------------------------- * Initialize the psInfo structure with info about the * current TXT. (numItems = Number of lines excluding header) *------------------------------------------------------------*/ psInfo->iCurItem = 0; psInfo->numItems = numFixedLines + ((psTxt->numChars-1)/80 + 1); /* And return the TXT header line. */ sprintf(psInfo->pszBuf, "%10d%10d%10d%10d%10d", psTxt->nLevel, psTxt->numVerticesLine - 1, psTxt->numVerticesArrow, psTxt->nSymbol, psTxt->numChars); } else if (psInfo->iCurItem < psInfo->numItems && psInfo->iCurItem < numFixedLines-1) { /*------------------------------------------------------------- * Return next line of coordinates... start by placing the coord. * values in the order that they should appear, and then generate the * current line * (This is a little bit less efficient, but will give much easier * code to read ;-) *------------------------------------------------------------*/ double dXY[15]; int i, nFirstValue, numValuesPerLine; for(i=0; i<14; i++) dXY[i] = 0.0; dXY[14] = psTxt->dHeight; /* note that the first vertex in the vertices list is never exported */ for(i=0; i < 4 && i< (psTxt->numVerticesLine-1); i++) { dXY[i] = psTxt->pasVertices[i+1].x; dXY[i+4] = psTxt->pasVertices[i+1].y; } for(i=0; i < 3 && inumVerticesArrow); i++) { dXY[i+8] = psTxt->pasVertices[i+psTxt->numVerticesLine].x; dXY[i+11] = psTxt->pasVertices[i+psTxt->numVerticesLine].y; } /* OK, now that we prepared the coord. values, return the next line * of coordinates. The only difference between double and single * precision is the number of coordinates per line. */ if (psInfo->nPrecision != AVC_DOUBLE_PREC) { /* Single precision */ numValuesPerLine = 5; } else { /* Double precision */ numValuesPerLine = 3; } nFirstValue = psInfo->iCurItem*numValuesPerLine; psInfo->pszBuf[0] = '\0'; for(i=0; ipszBuf, psInfo->nPrecision, AVCFileTXT, dXY[nFirstValue+i] ); } psInfo->iCurItem++; } else if (psInfo->iCurItem < psInfo->numItems && psInfo->iCurItem == numFixedLines-1) { /*------------------------------------------------------------- * Line with a -1.000E+02 value, ALWAYS SINGLE PRECISION !!! *------------------------------------------------------------*/ psInfo->pszBuf[0] = '\0'; AVCPrintRealValue(psInfo->pszBuf, AVC_SINGLE_PREC, AVCFileTXT, psTxt->f_1e2 ); psInfo->iCurItem++; } else if (psInfo->iCurItem < psInfo->numItems && psInfo->iCurItem >= numFixedLines ) { /*------------------------------------------------------------- * Last line, contains the text string * Strings longer than 80 chars have to be in 80 chars chunks *------------------------------------------------------------*/ int numLines, iLine; numLines = (psTxt->numChars-1)/80 + 1; iLine = numLines - (psInfo->numItems - psInfo->iCurItem); if ((int)strlen(psTxt->pszText) > (iLine*80)) sprintf(psInfo->pszBuf, "%-.80s", psTxt->pszText + (iLine*80) ); else psInfo->pszBuf[0] = '\0'; psInfo->iCurItem++; } else { /* No more lines to generate for this TXT. */ return NULL; } return psInfo->pszBuf; } /*===================================================================== TX6 stuff =====================================================================*/ /********************************************************************** * AVCE00GenTx6() * * Generate the next line of an E00 TX6 (Annotation) entry. * * This function should be called once with bCont=FALSE to get the * first E00 line for the current TX6, and then call with bCont=TRUE * to get all the other lines for this TX6. * * Note that E00 files can also contain TX7 sections, they seem identical * to TX6 sections, except for one value in each entry, and it was * impossible to find where this value comes from... so we will always * generate TX6 sections and not bother with TX7. * * The function returns NULL when there are no more lines to generate * for this TX6 entry. **********************************************************************/ const char *AVCE00GenTx6(AVCE00GenInfo *psInfo, AVCTxt *psTxt, GBool bCont) { if (bCont == FALSE) { /*------------------------------------------------------------- * Initialize the psInfo structure with info about the * current TX6. (numItems = Number of lines excluding header) *------------------------------------------------------------*/ psInfo->iCurItem = 0; psInfo->numItems = 8 + psTxt->numVerticesLine + ABS(psTxt->numVerticesArrow) + ((psTxt->numChars-1)/80 + 1); /* And return the TX6 header line. */ sprintf(psInfo->pszBuf, "%10d%10d%10d%10d%10d%10d%10d", psTxt->nUserId, psTxt->nLevel, psTxt->numVerticesLine, psTxt->numVerticesArrow, psTxt->nSymbol, psTxt->n28, psTxt->numChars); } else if (psInfo->iCurItem < psInfo->numItems && psInfo->iCurItem < 6) { /*------------------------------------------------------------- * Text Justification stuff... 2 sets of 20 int16 values. *------------------------------------------------------------*/ GInt16 *pValue; if (psInfo->iCurItem < 3) pValue = psTxt->anJust2 + psInfo->iCurItem * 7; else pValue = psTxt->anJust1 + (psInfo->iCurItem-3) * 7; if (psInfo->iCurItem == 2 || psInfo->iCurItem == 5) { sprintf(psInfo->pszBuf, "%10d%10d%10d%10d%10d%10d", pValue[0], pValue[1], pValue[2], pValue[3], pValue[4], pValue[5]); } else { sprintf(psInfo->pszBuf, "%10d%10d%10d%10d%10d%10d%10d", pValue[0], pValue[1], pValue[2], pValue[3], pValue[4], pValue[5], pValue[6]); } psInfo->iCurItem++; } else if (psInfo->iCurItem < psInfo->numItems && psInfo->iCurItem == 6) { /*------------------------------------------------------------- * Line with a -1.000E+02 value, ALWAYS SINGLE PRECISION !!! *------------------------------------------------------------*/ psInfo->pszBuf[0] = '\0'; AVCPrintRealValue(psInfo->pszBuf, AVC_SINGLE_PREC, AVCFileTX6, psTxt->f_1e2 ); psInfo->iCurItem++; } else if (psInfo->iCurItem < psInfo->numItems && psInfo->iCurItem == 7) { /*------------------------------------------------------------- * Line with 3 values, 1st value is probably text height. *------------------------------------------------------------*/ psInfo->pszBuf[0] = '\0'; AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFileTX6, psTxt->dHeight ); AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFileTX6, psTxt->dV2 ); AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFileTX6, psTxt->dV3 ); psInfo->iCurItem++; } else if (psInfo->iCurItem < psInfo->numItems-((psTxt->numChars-1)/80 + 1)) { /*------------------------------------------------------------- * One line for each pair of X,Y coordinates *------------------------------------------------------------*/ psInfo->pszBuf[0] = '\0'; AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFileTX6, psTxt->pasVertices[ psInfo->iCurItem-8 ].x ); AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFileTX6, psTxt->pasVertices[ psInfo->iCurItem-8 ].y ); psInfo->iCurItem++; } else if (psInfo->iCurItem < psInfo->numItems && psInfo->iCurItem >= psInfo->numItems-((psTxt->numChars-1)/80 + 1)) { /*------------------------------------------------------------- * Last line, contains the text string * Strings longer than 80 chars have to be in 80 chars chunks *------------------------------------------------------------*/ int numLines, iLine; numLines = (psTxt->numChars-1)/80 + 1; iLine = numLines - (psInfo->numItems - psInfo->iCurItem); if ((int)strlen(psTxt->pszText) > (iLine*80)) sprintf(psInfo->pszBuf, "%-.80s", psTxt->pszText + (iLine*80) ); else psInfo->pszBuf[0] = '\0'; psInfo->iCurItem++; } else { /* No more lines to generate for this TX6. */ return NULL; } return psInfo->pszBuf; } /*===================================================================== RXP stuff =====================================================================*/ /********************************************************************** * AVCE00GenRxp() * * Generate the next line of an E00 RXP entry (RXPs are related to regions). * * This function should be called once with bCont=FALSE to get the * first E00 line for the current RXP, and then call with bCont=TRUE * to get all the other lines for this RXP. * * The function returns NULL when there are no more lines to generate * for this RXP entry. **********************************************************************/ const char *AVCE00GenRxp(AVCE00GenInfo *psInfo, AVCRxp *psRxp, GBool bCont) { if (bCont == TRUE) { /*--------------------------------------------------------- * RXP entries are only 1 line, we support the bCont flag * only for compatibility with the other AVCE00Gen*() functions. *--------------------------------------------------------*/ return NULL; } sprintf(psInfo->pszBuf, "%10d%10d", psRxp->n1, psRxp->n2); return psInfo->pszBuf; } /*===================================================================== TABLE stuff =====================================================================*/ /********************************************************************** * AVCE00GenTableHdr() * * Generate the next line of an E00 Table header. * * This function should be called once with bCont=FALSE to get the * first E00 line for the current table header, and then call with * bCont=TRUE to get all the other lines. * * The function returns NULL when there are no more lines to generate. **********************************************************************/ const char *AVCE00GenTableHdr(AVCE00GenInfo *psInfo, AVCTableDef *psDef, GBool bCont) { if (bCont == FALSE) { int nRecSize; /* Initialize the psInfo structure with info about the * current Table Header */ psInfo->iCurItem = 0; psInfo->numItems = psDef->numFields; nRecSize = psDef->nRecSize; #ifdef AVC_MAP_TYPE40_TO_DOUBLE { /* Adjust Table record size if we're remapping type 40 fields */ int i; for(i=0; inumFields; i++) { if (psDef->pasFieldDef[i].nType1*10 == AVC_FT_FIXNUM && psDef->pasFieldDef[i].nSize > 8) { nRecSize -= psDef->pasFieldDef[i].nSize; nRecSize += 8; } } nRecSize = ((nRecSize+1)/2)*2; } #endif /* And return the header's header line(!). */ sprintf(psInfo->pszBuf, "%-32.32s%s%4d%4d%4d%10d", psDef->szTableName, psDef->szExternal, psDef->numFields, psDef->numFields, nRecSize, psDef->numRecords); } else if (psInfo->iCurItem < psInfo->numItems) { int nSize, nType, nOffset; nSize = psDef->pasFieldDef[psInfo->iCurItem].nSize; nType = psDef->pasFieldDef[psInfo->iCurItem].nType1 * 10; nOffset = psDef->pasFieldDef[psInfo->iCurItem].nOffset; #ifdef AVC_MAP_TYPE40_TO_DOUBLE /* Type 40 fields with more than 12 digits written to E00 by Arc/Info * will lose some digits of precision (and we starts losing them at 8 * with the way AVC lib writes type 40). This (optional) hack will * remap type 40 fields with more than 8 digits to double precision * floats which can carry up to 18 digits of precision. (bug 599) */ if (nType == AVC_FT_FIXNUM && nSize > 8) { /* Remap to double-precision float */ nType = AVC_FT_BINFLOAT; nSize = 8; } /* Adjust field offset if this field is preceded by any type40 fields * that were remapped. */ { int i; for(i=0; i < psInfo->iCurItem; i++) { if (psDef->pasFieldDef[i].nType1*10 == AVC_FT_FIXNUM && psDef->pasFieldDef[i].nSize > 8) { nOffset -= psDef->pasFieldDef[i].nSize; nOffset += 8; } } } #endif /* Return next Field definition line */ sprintf(psInfo->pszBuf, "%-16.16s%3d%2d%4d%1d%2d%4d%2d%3d%2d%4d%4d%2d%-16.16s%4d-", psDef->pasFieldDef[psInfo->iCurItem].szName, nSize, psDef->pasFieldDef[psInfo->iCurItem].v2, nOffset, psDef->pasFieldDef[psInfo->iCurItem].v4, psDef->pasFieldDef[psInfo->iCurItem].v5, psDef->pasFieldDef[psInfo->iCurItem].nFmtWidth, psDef->pasFieldDef[psInfo->iCurItem].nFmtPrec, nType, psDef->pasFieldDef[psInfo->iCurItem].v10, psDef->pasFieldDef[psInfo->iCurItem].v11, psDef->pasFieldDef[psInfo->iCurItem].v12, psDef->pasFieldDef[psInfo->iCurItem].v13, psDef->pasFieldDef[psInfo->iCurItem].szAltName, psDef->pasFieldDef[psInfo->iCurItem].nIndex ); psInfo->iCurItem++; } else { /* No more lines to generate. */ return NULL; } return psInfo->pszBuf; } /********************************************************************** * AVCE00GenTableRec() * * Generate the next line of an E00 Table Data Record. * * This function should be called once with bCont=FALSE to get the * first E00 line for the current table record, and then call with * bCont=TRUE to get all the other lines. * * The function returns NULL when there are no more lines to generate. **********************************************************************/ const char *AVCE00GenTableRec(AVCE00GenInfo *psInfo, int numFields, AVCFieldInfo *pasDef, AVCField *pasFields, GBool bCont) { int i, nSize, nType, nLen; char *pszBuf2; if (bCont == FALSE) { /*------------------------------------------------------------- * Initialize the psInfo structure to be ready to process this * new Table Record *------------------------------------------------------------*/ psInfo->iCurItem = 0; #ifdef AVC_MAP_TYPE40_TO_DOUBLE psInfo->numItems = _AVCE00ComputeRecSize(numFields, pasDef, TRUE); #else psInfo->numItems = _AVCE00ComputeRecSize(numFields, pasDef, FALSE); #endif /*------------------------------------------------------------- * First, we need to make sure that the output buffer is big * enough to hold the whole record, plus 81 chars to hold * the line that we'll return to the caller. *------------------------------------------------------------*/ nSize = psInfo->numItems + 1 + 81; if (psInfo->nBufSize < nSize) { psInfo->pszBuf = (char*)CPLRealloc(psInfo->pszBuf, nSize*sizeof(char)); psInfo->nBufSize = nSize; } /*------------------------------------------------------------- * Generate the whole record now, and we'll return it to the * caller by chunks of 80 chars. * The first 80 chars of the buffer will be used to return * one line at a time, and the rest of the buffer is used to * hold the whole record. *------------------------------------------------------------*/ pszBuf2 = psInfo->pszBuf+81; for(i=0; i 8) { pszBuf2[0] = '\0'; /* NOTE: The E00 representation for a binary float is * defined by its binary size, not by the coverage's * precision. */ nLen = AVCPrintRealValue(pszBuf2, AVC_DOUBLE_PREC, AVCFileTABLE, atof(pasFields[i].pszStr)); pszBuf2 += nLen; } #endif else if (nType == AVC_FT_FIXNUM) { /* TYPE 40 attributes are stored with 1 byte per digit * in binary format, and as single precision floats in * E00 tables, even in double precision coverages. */ pszBuf2[0] = '\0'; nLen = AVCPrintRealValue(pszBuf2, AVC_SINGLE_PREC, AVCFileTABLE, atof(pasFields[i].pszStr)); pszBuf2 += nLen; } else if (nType == AVC_FT_BININT && nSize == 4) { sprintf(pszBuf2, "%11d", pasFields[i].nInt32); pszBuf2 += 11; } else if (nType == AVC_FT_BININT && nSize == 2) { sprintf(pszBuf2, "%6d", pasFields[i].nInt16); pszBuf2 += 6; } else if (nType == AVC_FT_BINFLOAT && nSize == 4) { pszBuf2[0] = '\0'; /* NOTE: The E00 representation for a binary float is * defined by its binary size, not by the coverage's * precision. */ nLen = AVCPrintRealValue(pszBuf2, AVC_SINGLE_PREC, AVCFileTABLE, pasFields[i].fFloat); pszBuf2 += nLen; } else if (nType == AVC_FT_BINFLOAT && nSize == 8) { pszBuf2[0] = '\0'; /* NOTE: The E00 representation for a binary float is * defined by its binary size, not by the coverage's * precision. */ nLen = AVCPrintRealValue(pszBuf2, AVC_DOUBLE_PREC, AVCFileTABLE, pasFields[i].dDouble); pszBuf2 += nLen; } else { /*----------------------------------------------------- * Hummm... unsupported field type... *----------------------------------------------------*/ CPLError(CE_Failure, CPLE_NotSupported, "Unsupported field type: (type=%d, size=%d)", nType, nSize); return NULL; } } *pszBuf2 = '\0'; /* Make sure that we remove any embedded NUL characters from the * data line before returning it, otherwise we may be accidentally * truncating results. */ while ( --pszBuf2 >= psInfo->pszBuf+81 ) { if ( *pszBuf2 == '\0' ) { *pszBuf2 = ' '; } } } if (psInfo->iCurItem < psInfo->numItems) { /*------------------------------------------------------------- * Return the next 80 chars chunk. * The first 80 chars of the buffer is used to return * one line at a time, and the rest of the buffer (chars 81+) * is used to hold the whole record. *------------------------------------------------------------*/ nLen = psInfo->numItems - psInfo->iCurItem; if (nLen > 80) nLen = 80; strncpy(psInfo->pszBuf, psInfo->pszBuf+(81+psInfo->iCurItem), nLen); psInfo->pszBuf[nLen] = '\0'; psInfo->iCurItem += nLen; /*------------------------------------------------------------- * Arc/Info removes spaces at the end of the lines... let's * remove them as well since it can reduce the E00 file size. *------------------------------------------------------------*/ nLen--; while(nLen >= 0 && psInfo->pszBuf[nLen] == ' ') { psInfo->pszBuf[nLen] = '\0'; nLen--; } } else { /* No more lines to generate. */ return NULL; } return psInfo->pszBuf; } avce00-2.0.0/avc_rawbin.c0100664000076400007640000005245010247751547014355 0ustar danieldaniel/********************************************************************** * $Id: avc_rawbin.c,v 1.13 2005/06/03 03:49:59 daniel Exp $ * * Name: avc_rawbin.c * Project: Arc/Info vector coverage (AVC) BIN->E00 conversion library * Language: ANSI C * Purpose: Raw Binary file access functions. * Author: Daniel Morissette, dmorissette@dmsolutions.ca * ********************************************************************** * Copyright (c) 1999-2005, Daniel Morissette * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ********************************************************************** * * $Log: avc_rawbin.c,v $ * Revision 1.13 2005/06/03 03:49:59 daniel * Update email address, website url, and copyright dates * * Revision 1.12 2004/08/19 23:41:04 warmerda * fixed pointer aliasing optimization bug * * Revision 1.11 2000/09/22 19:45:21 daniel * Switch to MIT-style license * * Revision 1.10 2000/05/29 15:36:07 daniel * Fixed compile warning * * Revision 1.9 2000/05/29 15:31:31 daniel * Added Japanese DBCS support * * Revision 1.8 2000/01/10 02:59:11 daniel * Fixed problem in AVCRawBinOpen() when file not found * * Revision 1.7 1999/12/24 07:18:34 daniel * Added PC Arc/Info coverages support * * Revision 1.6 1999/08/29 15:05:43 daniel * Added source filename in "Attempt to read past EOF" error message * * Revision 1.5 1999/06/08 22:09:03 daniel * Allow opening file with "r+" (but no real random access support yet) * * Revision 1.4 1999/05/11 02:10:51 daniel * Added write support * * Revision 1.3 1999/03/03 19:55:21 daniel * Fixed syntax error in the CPL_MSB version of AVCRawBinReadInt32() * * Revision 1.2 1999/02/25 04:20:08 daniel * Modified AVCRawBinEOF() to detect EOF even if AVCRawBinFSeek() was used. * * Revision 1.1 1999/01/29 16:28:52 daniel * Initial revision * **********************************************************************/ #include "avc.h" #include "avc_mbyte.h" /*--------------------------------------------------------------------- * Define a static flag and set it with the byte ordering on this machine * we will then compare with this value to decide if we nned to swap * bytes or not. * * CPL_MSB or CPL_LSB should be set in the makefile... the default is * CPL_LSB. *--------------------------------------------------------------------*/ #ifndef CPL_LSB static AVCByteOrder geSystemByteOrder = AVCBigEndian; #else static AVCByteOrder geSystemByteOrder = AVCLittleEndian; #endif /*===================================================================== * Stuff related to buffered reading of raw binary files *====================================================================*/ /********************************************************************** * AVCRawBinOpen() * * Open a binary file for reading with buffering, or writing. * * Returns a valid AVCRawBinFile structure, or NULL if the file could * not be opened or created. * * AVCRawBinClose() will eventually have to be called to release the * resources used by the AVCRawBinFile structure. **********************************************************************/ AVCRawBinFile *AVCRawBinOpen(const char *pszFname, const char *pszAccess, AVCByteOrder eFileByteOrder, AVCDBCSInfo *psDBCSInfo) { AVCRawBinFile *psFile; psFile = (AVCRawBinFile*)CPLCalloc(1, sizeof(AVCRawBinFile)); /*----------------------------------------------------------------- * Validate access mode and open/create file. * For now we support only: "r" for read-only or "w" for write-only * or "a" for append. * * A case for "r+" is included here, but random access is not * properly supported yet... so this option should be used with care. *----------------------------------------------------------------*/ if (EQUALN(pszAccess, "r+", 2)) { psFile->eAccess = AVCReadWrite; psFile->fp = VSIFOpen(pszFname, "r+b"); } else if (EQUALN(pszAccess, "r", 1)) { psFile->eAccess = AVCRead; psFile->fp = VSIFOpen(pszFname, "rb"); } else if (EQUALN(pszAccess, "w", 1)) { psFile->eAccess = AVCWrite; psFile->fp = VSIFOpen(pszFname, "wb"); } else if (EQUALN(pszAccess, "a", 1)) { psFile->eAccess = AVCWrite; psFile->fp = VSIFOpen(pszFname, "ab"); } else { CPLError(CE_Failure, CPLE_IllegalArg, "Acces mode \"%s\" not supported.", pszAccess); CPLFree(psFile); return NULL; } /*----------------------------------------------------------------- * Check that file was opened succesfully, and init struct. *----------------------------------------------------------------*/ if (psFile->fp == NULL) { CPLError(CE_Failure, CPLE_OpenFailed, "Failed to open file %s", pszFname); CPLFree(psFile); return NULL; } /*----------------------------------------------------------------- * OK... Init psFile struct *----------------------------------------------------------------*/ psFile->pszFname = CPLStrdup(pszFname); psFile->eByteOrder = eFileByteOrder; psFile->psDBCSInfo = psDBCSInfo; /* Handle on dataset DBCS info */ /*----------------------------------------------------------------- * One can set nFileDataSize based on some header fields to force * EOF beyond a given point in the file. Useful for cases like * PC Arc/Info where the physical file size is always a multiple of * 256 bytes padded with some junk at the end. *----------------------------------------------------------------*/ psFile->nFileDataSize = -1; return psFile; } /********************************************************************** * AVCRawBinClose() * * Close a binary file previously opened with AVCRawBinOpen() and release * any memory used by the handle. **********************************************************************/ void AVCRawBinClose(AVCRawBinFile *psFile) { if (psFile) { if (psFile->fp) VSIFClose(psFile->fp); CPLFree(psFile->pszFname); CPLFree(psFile); } } /********************************************************************** * AVCRawBinSetFileDataSize() * * One can set nFileDataSize based on some header fields to force * EOF beyond a given point in the file. Useful for cases like * PC Arc/Info where the physical file size is always a multiple of * 256 bytes padded with some junk at the end. * * The default value is -1 which just looks for the real EOF. **********************************************************************/ void AVCRawBinSetFileDataSize(AVCRawBinFile *psFile, int nFileDataSize) { if (psFile) { psFile->nFileDataSize = nFileDataSize; } } /********************************************************************** * AVCRawBinReadBytes() * * Copy the number of bytes from the input file to the specified * memory location. **********************************************************************/ static GBool bDisableReadBytesEOFError = FALSE; void AVCRawBinReadBytes(AVCRawBinFile *psFile, int nBytesToRead, GByte *pBuf) { /* Make sure file is opened with Read access */ if (psFile == NULL || (psFile->eAccess != AVCRead && psFile->eAccess != AVCReadWrite)) { CPLError(CE_Failure, CPLE_FileIO, "AVCRawBinReadBytes(): call not compatible with access mode."); return; } /* Quick method: check to see if we can satisfy the request with a * simple memcpy... most calls should take this path. */ if (psFile->nCurPos + nBytesToRead <= psFile->nCurSize) { memcpy(pBuf, psFile->abyBuf+psFile->nCurPos, nBytesToRead); psFile->nCurPos += nBytesToRead; return; } /* This is the long method... it supports reading data that * overlaps the input buffer boundaries. */ while(nBytesToRead > 0) { /* If we reached the end of our memory buffer then read another * chunk from the file */ CPLAssert(psFile->nCurPos <= psFile->nCurSize); if (psFile->nCurPos == psFile->nCurSize) { psFile->nOffset += psFile->nCurSize; psFile->nCurSize = VSIFRead(psFile->abyBuf, sizeof(GByte), AVCRAWBIN_READBUFSIZE, psFile->fp); psFile->nCurPos = 0; } if (psFile->nCurSize == 0) { /* Attempt to read past EOF... generate an error. * * Note: AVCRawBinEOF() can set bDisableReadBytesEOFError=TRUE * to disable the error message whils it is testing * for EOF. */ if (bDisableReadBytesEOFError == FALSE) CPLError(CE_Failure, CPLE_FileIO, "Attempt to read past EOF in %s.", psFile->pszFname); return; } /* If the requested bytes are not all in the current buffer then * just read the part that's in memory for now... the loop will * take care of the rest. */ if (psFile->nCurPos + nBytesToRead > psFile->nCurSize) { int nBytes; nBytes = psFile->nCurSize-psFile->nCurPos; memcpy(pBuf, psFile->abyBuf+psFile->nCurPos, nBytes); psFile->nCurPos += nBytes; pBuf += nBytes; nBytesToRead -= nBytes; } else { /* All the requested bytes are now in the buffer... * simply copy them and return. */ memcpy(pBuf, psFile->abyBuf+psFile->nCurPos, nBytesToRead); psFile->nCurPos += nBytesToRead; nBytesToRead = 0; /* Terminate the loop */ } } } /********************************************************************** * AVCRawBinReadString() * * Same as AVCRawBinReadBytes() except that the string is run through * the DBCS conversion function. * * pBuf should be allocated with a size of at least nBytesToRead+1 bytes. **********************************************************************/ void AVCRawBinReadString(AVCRawBinFile *psFile, int nBytesToRead, GByte *pBuf) { const GByte *pszConvBuf; AVCRawBinReadBytes(psFile, nBytesToRead, pBuf); pBuf[nBytesToRead] = '\0'; pszConvBuf = AVCE00ConvertFromArcDBCS(psFile->psDBCSInfo, pBuf, nBytesToRead); if (pszConvBuf != pBuf) { memcpy(pBuf, pszConvBuf, nBytesToRead); } } /********************************************************************** * AVCRawBinFSeek() * * Move the read pointer to the specified location. * * As with fseek(), the specified position can be relative to the * beginning of the file (SEEK_SET), or the current position (SEEK_CUR). * SEEK_END is not supported. **********************************************************************/ void AVCRawBinFSeek(AVCRawBinFile *psFile, int nOffset, int nFrom) { int nTarget = 0; CPLAssert(nFrom == SEEK_SET || nFrom == SEEK_CUR); /* Supported only with read access for now */ CPLAssert(psFile && psFile->eAccess != AVCWrite); if (psFile == NULL || psFile->eAccess == AVCWrite) return; /* Compute destination relative to current memory buffer */ if (nFrom == SEEK_SET) nTarget = nOffset - psFile->nOffset; else if (nFrom == SEEK_CUR) nTarget = nOffset + psFile->nCurPos; /* Is the destination located inside the current buffer? */ if (nTarget > 0 && nTarget <= psFile->nCurSize) { /* Requested location is already in memory... just move the * read pointer */ psFile->nCurPos = nTarget; } else { /* Requested location is not part of the memory buffer... * move the FILE * to the right location and be ready to * read from there. */ VSIFSeek(psFile->fp, psFile->nOffset+nTarget, SEEK_SET); psFile->nCurPos = 0; psFile->nCurSize = 0; psFile->nOffset = psFile->nOffset+nTarget; } } /********************************************************************** * AVCRawBinEOF() * * Return TRUE if there is no more data to read from the file or * FALSE otherwise. **********************************************************************/ GBool AVCRawBinEOF(AVCRawBinFile *psFile) { if (psFile == NULL || psFile->fp == NULL) return TRUE; /* In write access mode, always return TRUE, since we always write * at EOF for now. */ if (psFile->eAccess != AVCRead && psFile->eAccess != AVCReadWrite) return TRUE; /* If file data size was specified, then check that we have not * passed that point yet... */ if (psFile->nFileDataSize > 0 && (psFile->nOffset+psFile->nCurPos) >= psFile->nFileDataSize) return TRUE; /* If the file pointer has been moved by AVCRawBinFSeek(), then * we may be at a position past EOF, but VSIFeof() would still * return FALSE. * To prevent this situation, if the memory buffer is empty, * we will try to read 1 byte from the file to force the next * chunk of data to be loaded (and we'll move the the read pointer * back by 1 char after of course!). * If we are at the end of the file, this will trigger the EOF flag. */ if (psFile->nCurPos == 0 && psFile->nCurSize == 0) { char c; /* Set bDisableReadBytesEOFError=TRUE to temporarily disable * the EOF error message from AVCRawBinReadBytes(). */ bDisableReadBytesEOFError = TRUE; AVCRawBinReadBytes(psFile, 1, &c); bDisableReadBytesEOFError = FALSE; if (psFile->nCurPos > 0) AVCRawBinFSeek(psFile, -1, SEEK_CUR); } return (psFile->nCurPos == psFile->nCurSize && VSIFEof(psFile->fp)); } /********************************************************************** * AVCRawBinRead() * * Arc/Info files are binary files with MSB first (Motorola) byte * ordering. The following functions will read from the input file * and return a value with the bytes ordered properly for the current * platform. **********************************************************************/ GInt16 AVCRawBinReadInt16(AVCRawBinFile *psFile) { GInt16 n16Value; AVCRawBinReadBytes(psFile, 2, (GByte*)(&n16Value)); if (psFile->eByteOrder != geSystemByteOrder) { return (GInt16)CPL_SWAP16(n16Value); } return n16Value; } GInt32 AVCRawBinReadInt32(AVCRawBinFile *psFile) { GInt32 n32Value; AVCRawBinReadBytes(psFile, 4, (GByte*)(&n32Value)); if (psFile->eByteOrder != geSystemByteOrder) { return (GInt32)CPL_SWAP32(n32Value); } return n32Value; } float AVCRawBinReadFloat(AVCRawBinFile *psFile) { float fValue; AVCRawBinReadBytes(psFile, 4, (GByte*)(&fValue)); if (psFile->eByteOrder != geSystemByteOrder) { CPL_SWAP32PTR( &fValue ); } return fValue; } double AVCRawBinReadDouble(AVCRawBinFile *psFile) { double dValue; AVCRawBinReadBytes(psFile, 8, (GByte*)(&dValue)); if (psFile->eByteOrder != geSystemByteOrder) { CPL_SWAPDOUBLE(&dValue); } return dValue; } /********************************************************************** * AVCRawBinWriteBytes() * * Write the number of bytes from the buffer to the file. * * If a problem happens, then CPLError() will be called and * CPLGetLastErrNo() can be used to test if a write operation was * succesful. **********************************************************************/ void AVCRawBinWriteBytes(AVCRawBinFile *psFile, int nBytesToWrite, GByte *pBuf) { /*---------------------------------------------------------------- * Make sure file is opened with Write access *---------------------------------------------------------------*/ if (psFile == NULL || (psFile->eAccess != AVCWrite && psFile->eAccess != AVCReadWrite)) { CPLError(CE_Failure, CPLE_FileIO, "AVCRawBinWriteBytes(): call not compatible with access mode."); return; } if (VSIFWrite(pBuf, nBytesToWrite, 1, psFile->fp) != 1) CPLError(CE_Failure, CPLE_FileIO, "Writing to %s failed.", psFile->pszFname); /*---------------------------------------------------------------- * In write mode, we keep track of current file position ( =nbr of * bytes written) through psFile->nCurPos *---------------------------------------------------------------*/ psFile->nCurPos += nBytesToWrite; } /********************************************************************** * AVCRawBinWrite() * * Arc/Info files are binary files with MSB first (Motorola) byte * ordering. The following functions will reorder the byte for the * value properly and write that to the output file. * * If a problem happens, then CPLError() will be called and * CPLGetLastErrNo() can be used to test if a write operation was * succesful. **********************************************************************/ void AVCRawBinWriteInt16(AVCRawBinFile *psFile, GInt16 n16Value) { if (psFile->eByteOrder != geSystemByteOrder) { n16Value = (GInt16)CPL_SWAP16(n16Value); } AVCRawBinWriteBytes(psFile, 2, (GByte*)&n16Value); } void AVCRawBinWriteInt32(AVCRawBinFile *psFile, GInt32 n32Value) { if (psFile->eByteOrder != geSystemByteOrder) { n32Value = (GInt32)CPL_SWAP32(n32Value); } AVCRawBinWriteBytes(psFile, 4, (GByte*)&n32Value); } void AVCRawBinWriteFloat(AVCRawBinFile *psFile, float fValue) { if (psFile->eByteOrder != geSystemByteOrder) { CPL_SWAP32PTR( &fValue ); } AVCRawBinWriteBytes(psFile, 4, (GByte*)&fValue); } void AVCRawBinWriteDouble(AVCRawBinFile *psFile, double dValue) { if (psFile->eByteOrder != geSystemByteOrder) { CPL_SWAPDOUBLE(&dValue); } AVCRawBinWriteBytes(psFile, 8, (GByte*)&dValue); } /********************************************************************** * AVCRawBinWriteZeros() * * Write a number of zeros (sepcified in bytes) at the current position * in the file. * * If a problem happens, then CPLError() will be called and * CPLGetLastErrNo() can be used to test if a write operation was * succesful. **********************************************************************/ void AVCRawBinWriteZeros(AVCRawBinFile *psFile, int nBytesToWrite) { char acZeros[8] = {0, 0, 0, 0, 0, 0, 0, 0}; int i; /* Write by 8 bytes chunks. The last chunk may be less than 8 bytes */ for(i=0; i< nBytesToWrite; i+=8) { AVCRawBinWriteBytes(psFile, MIN(8,(nBytesToWrite-i)), (GByte*)acZeros); } } /********************************************************************** * AVCRawBinWritePaddedString() * * Write a string and pad the end of the field (up to nFieldSize) with * spaces number of spaces at the current position in the file. * * If a problem happens, then CPLError() will be called and * CPLGetLastErrNo() can be used to test if a write operation was * succesful. **********************************************************************/ void AVCRawBinWritePaddedString(AVCRawBinFile *psFile, int nFieldSize, const char *pszString) { char acSpaces[8] = {' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '}; int i, nLen, numSpaces; /* If we're on a system with a multibyte codepage then we have to * convert strings to the proper multibyte encoding. */ pszString = AVCE00Convert2ArcDBCS(psFile->psDBCSInfo, pszString, nFieldSize); nLen = strlen(pszString); nLen = MIN(nLen, nFieldSize); numSpaces = nFieldSize - nLen; if (nLen > 0) AVCRawBinWriteBytes(psFile, nLen, (GByte*)pszString); /* Write spaces by 8 bytes chunks. The last chunk may be less than 8 bytes */ for(i=0; i< numSpaces; i+=8) { AVCRawBinWriteBytes(psFile, MIN(8,(numSpaces-i)), (GByte*)acSpaces); } } avce00-2.0.0/ex_avcwrite.c0100664000076400007640000000344707030617112014545 0ustar danieldaniel/********************************************************************** * ex_avcwrite.c * * This example program illustrates the use of the AVCE00WriteOpen() * and the functions to use to write a binary coverage from E00 input. **********************************************************************/ #include #include "avc.h" int main(int argc, char *argv[]) { FILE *fpIn; AVCE00WritePtr hWritePtr; const char *pszLine, *pszInFile, *pszOutCover; int nStatus = 0; if (argc < 3) { printf("Usage: ex_avcwrite \n"); return 1; } pszInFile = argv[1]; pszOutCover = argv[2]; /* Open input file */ fpIn = fopen(pszInFile, "rt"); if (fpIn) { /* Open output file */ hWritePtr = AVCE00WriteOpen(pszOutCover, AVCCoverV7, AVC_DEFAULT_PREC); if (hWritePtr) { /* Read lines from input until we reach EOF */ while((pszLine = CPLReadLine(fpIn)) != NULL) { if ((nStatus = CPLGetLastErrorNo()) == 0) nStatus = AVCE00WriteNextLine(hWritePtr, pszLine); if (nStatus != 0) { /* An error happened while converting the last * line... abort*/ break; } } /* Close output file. */ AVCE00WriteClose(hWritePtr); } else { /* ERROR ... failed to open output file */ nStatus = CPLGetLastErrorNo(); } /* Close input file. */ fclose(fpIn); } else { /* ERROR ... failed to open input file */ nStatus = CPLGetLastErrorNo(); } return nStatus; } avce00-2.0.0/dbfopen.c0100664000076400007640000012123507164202461013643 0ustar danieldaniel/****************************************************************************** * $Id: dbfopen.c,v 1.4 2000/09/26 20:21:05 daniel Exp $ * * Project: Shapelib * Purpose: Implementation of .dbf access API documented in dbf_api.html. * Author: Frank Warmerdam, warmerda@home.com * ****************************************************************************** * Copyright (c) 1999, Frank Warmerdam * * This software is available under the following "MIT Style" license, * or at the option of the licensee under the LGPL (see LICENSE.LGPL). This * option is discussed in more detail in shapelib.html. * * -- * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ****************************************************************************** * * $Log: dbfopen.c,v $ * Revision 1.4 2000/09/26 20:21:05 daniel * Added AVCCoverPC write * * Revision 1.3 2000/05/29 15:51:22 daniel * Ported to AIX * * Revision 1.2 1999/12/24 07:25:25 daniel * Fixed warnings * * Revision 1.1 1999/12/24 07:16:05 daniel * Checked into AVCE00 lib + Added DBFGetNativeFieldType() * * Revision 1.22 1999/12/15 13:47:24 warmerda * Added stdlib.h to ensure that atof() is prototyped. * * Revision 1.21 1999/12/13 17:25:46 warmerda * Added support for upper case .DBF extention. * * Revision 1.20 1999/11/30 16:32:11 warmerda * Use atof() instead of sscanf(). * * Revision 1.19 1999/11/05 14:12:04 warmerda * updated license terms * * Revision 1.18 1999/07/27 00:53:28 warmerda * ensure that whole old field value clear on write of string * * Revision 1.1 1999/07/05 18:58:07 warmerda * New * * Revision 1.17 1999/06/11 19:14:12 warmerda * Fixed some memory leaks. * * Revision 1.16 1999/06/11 19:04:11 warmerda * Remoted some unused variables. * * Revision 1.15 1999/05/11 03:19:28 warmerda * added new Tuple api, and improved extension handling - add from candrsn * * Revision 1.14 1999/05/04 15:01:48 warmerda * Added 'F' support. * * Revision 1.13 1999/03/23 17:38:59 warmerda * DBFAddField() now actually does return the new field number, or -1 if * it fails. * * Revision 1.12 1999/03/06 02:54:46 warmerda * Added logic to convert shapefile name to dbf filename in DBFOpen() * for convenience. * * Revision 1.11 1998/12/31 15:30:34 warmerda * Improved the interchangability of numeric and string attributes. Add * white space trimming option for attributes. * * Revision 1.10 1998/12/03 16:36:44 warmerda * Use r+b instead of rb+ for binary access. * * Revision 1.9 1998/12/03 15:34:23 warmerda * Updated copyright message. * * Revision 1.8 1997/12/04 15:40:15 warmerda * Added newline character after field definitions. * * Revision 1.7 1997/03/06 14:02:10 warmerda * Ensure bUpdated is initialized. * * Revision 1.6 1996/02/12 04:54:41 warmerda * Ensure that DBFWriteAttribute() returns TRUE if it succeeds. * * Revision 1.5 1995/10/21 03:15:12 warmerda * Changed to use binary file access, and ensure that the * field name field is zero filled, and limited to 10 chars. * * Revision 1.4 1995/08/24 18:10:42 warmerda * Added use of SfRealloc() to avoid pre-ANSI realloc() functions such * as on the Sun. * * Revision 1.3 1995/08/04 03:15:16 warmerda * Fixed up header. * * Revision 1.2 1995/08/04 03:14:43 warmerda * Added header. */ static char rcsid[] = "$Id: dbfopen.c,v 1.4 2000/09/26 20:21:05 daniel Exp $"; #include "dbfopen.h" #include #include #include #ifndef _AIX typedef unsigned char uchar; #endif #ifndef FALSE # define FALSE 0 # define TRUE 1 #endif static int nStringFieldLen = 0; static char * pszStringField = NULL; /************************************************************************/ /* SfRealloc() */ /* */ /* A realloc cover function that will access a NULL pointer as */ /* a valid input. */ /************************************************************************/ static void * SfRealloc( void * pMem, int nNewSize ) { if( pMem == NULL ) return( (void *) malloc(nNewSize) ); else return( (void *) realloc(pMem,nNewSize) ); } /************************************************************************/ /* DBFWriteHeader() */ /* */ /* This is called to write out the file header, and field */ /* descriptions before writing any actual data records. This */ /* also computes all the DBFDataSet field offset/size/decimals */ /* and so forth values. */ /************************************************************************/ static void DBFWriteHeader(DBFHandle psDBF) { uchar abyHeader[XBASE_FLDHDR_SZ]; int i; if( !psDBF->bNoHeader ) return; psDBF->bNoHeader = FALSE; /* -------------------------------------------------------------------- */ /* Initialize the file header information. */ /* -------------------------------------------------------------------- */ for( i = 0; i < XBASE_FLDHDR_SZ; i++ ) abyHeader[i] = 0; abyHeader[0] = 0x03; /* memo field? - just copying */ /* date updated on close, record count preset at zero */ abyHeader[8] = psDBF->nHeaderLength % 256; abyHeader[9] = psDBF->nHeaderLength / 256; abyHeader[10] = psDBF->nRecordLength % 256; abyHeader[11] = psDBF->nRecordLength / 256; /* -------------------------------------------------------------------- */ /* Write the initial 32 byte file header, and all the field */ /* descriptions. */ /* -------------------------------------------------------------------- */ fseek( psDBF->fp, 0, 0 ); fwrite( abyHeader, XBASE_FLDHDR_SZ, 1, psDBF->fp ); fwrite( psDBF->pszHeader, XBASE_FLDHDR_SZ, psDBF->nFields, psDBF->fp ); /* -------------------------------------------------------------------- */ /* Write out the newline character if there is room for it. */ /* -------------------------------------------------------------------- */ if( psDBF->nHeaderLength > 32*psDBF->nFields + 32 ) { char cNewline; cNewline = 0x0d; fwrite( &cNewline, 1, 1, psDBF->fp ); } } /************************************************************************/ /* DBFFlushRecord() */ /* */ /* Write out the current record if there is one. */ /************************************************************************/ static void DBFFlushRecord( DBFHandle psDBF ) { int nRecordOffset; if( psDBF->bCurrentRecordModified && psDBF->nCurrentRecord > -1 ) { psDBF->bCurrentRecordModified = FALSE; nRecordOffset = psDBF->nRecordLength * psDBF->nCurrentRecord + psDBF->nHeaderLength; fseek( psDBF->fp, nRecordOffset, 0 ); fwrite( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp ); } } /************************************************************************/ /* DBFOpen() */ /* */ /* Open a .dbf file. */ /************************************************************************/ DBFHandle DBFOpen( const char * pszFilename, const char * pszAccess ) { DBFHandle psDBF; uchar *pabyBuf; int nFields, nRecords, nHeadLen, nRecLen, iField, i; char *pszBasename, *pszFullname; /* -------------------------------------------------------------------- */ /* We only allow the access strings "rb" and "r+". */ /* -------------------------------------------------------------------- */ if( strcmp(pszAccess,"r") != 0 && strcmp(pszAccess,"r+") != 0 && strcmp(pszAccess,"rb") != 0 && strcmp(pszAccess,"rb+") != 0 && strcmp(pszAccess,"r+b") != 0 ) return( NULL ); /* -------------------------------------------------------------------- */ /* Compute the base (layer) name. If there is any extension */ /* on the passed in filename we will strip it off. */ /* -------------------------------------------------------------------- */ pszBasename = (char *) malloc(strlen(pszFilename)+5); strcpy( pszBasename, pszFilename ); for( i = strlen(pszBasename)-1; i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/' && pszBasename[i] != '\\'; i-- ) {} if( pszBasename[i] == '.' ) pszBasename[i] = '\0'; pszFullname = (char *) malloc(strlen(pszBasename) + 5); sprintf( pszFullname, "%s.dbf", pszBasename ); psDBF = (DBFHandle) calloc( 1, sizeof(DBFInfo) ); psDBF->fp = fopen( pszFullname, pszAccess ); if( psDBF->fp == NULL ) { sprintf( pszFullname, "%s.DBF", pszBasename ); psDBF->fp = fopen(pszFullname, pszAccess ); } free( pszBasename ); free( pszFullname ); if( psDBF->fp == NULL ) { free( psDBF ); return( NULL ); } psDBF->bNoHeader = FALSE; psDBF->nCurrentRecord = -1; psDBF->bCurrentRecordModified = FALSE; /* -------------------------------------------------------------------- */ /* Read Table Header info */ /* -------------------------------------------------------------------- */ pabyBuf = (uchar *) malloc(500); fread( pabyBuf, 32, 1, psDBF->fp ); psDBF->nRecords = nRecords = pabyBuf[4] + pabyBuf[5]*256 + pabyBuf[6]*256*256 + pabyBuf[7]*256*256*256; psDBF->nHeaderLength = nHeadLen = pabyBuf[8] + pabyBuf[9]*256; psDBF->nRecordLength = nRecLen = pabyBuf[10] + pabyBuf[11]*256; psDBF->nFields = nFields = (nHeadLen - 32) / 32; psDBF->pszCurrentRecord = (char *) malloc(nRecLen); /* -------------------------------------------------------------------- */ /* Read in Field Definitions */ /* -------------------------------------------------------------------- */ pabyBuf = (uchar *) SfRealloc(pabyBuf,nHeadLen); psDBF->pszHeader = (char *) pabyBuf; fseek( psDBF->fp, 32, 0 ); fread( pabyBuf, nHeadLen, 1, psDBF->fp ); psDBF->panFieldOffset = (int *) malloc(sizeof(int) * nFields); psDBF->panFieldSize = (int *) malloc(sizeof(int) * nFields); psDBF->panFieldDecimals = (int *) malloc(sizeof(int) * nFields); psDBF->pachFieldType = (char *) malloc(sizeof(char) * nFields); for( iField = 0; iField < nFields; iField++ ) { uchar *pabyFInfo; pabyFInfo = pabyBuf+iField*32; if( pabyFInfo[11] == 'N' || pabyFInfo[11] == 'F' ) { psDBF->panFieldSize[iField] = pabyFInfo[16]; psDBF->panFieldDecimals[iField] = pabyFInfo[17]; } else { psDBF->panFieldSize[iField] = pabyFInfo[16] + pabyFInfo[17]*256; psDBF->panFieldDecimals[iField] = 0; } psDBF->pachFieldType[iField] = (char) pabyFInfo[11]; if( iField == 0 ) psDBF->panFieldOffset[iField] = 1; else psDBF->panFieldOffset[iField] = psDBF->panFieldOffset[iField-1] + psDBF->panFieldSize[iField-1]; } return( psDBF ); } /************************************************************************/ /* DBFClose() */ /************************************************************************/ void DBFClose(DBFHandle psDBF) { /* -------------------------------------------------------------------- */ /* Write out header if not already written. */ /* -------------------------------------------------------------------- */ if( psDBF->bNoHeader ) DBFWriteHeader( psDBF ); DBFFlushRecord( psDBF ); /* -------------------------------------------------------------------- */ /* Update last access date, and number of records if we have */ /* write access. */ /* -------------------------------------------------------------------- */ if( psDBF->bUpdated ) { uchar abyFileHeader[32]; fseek( psDBF->fp, 0, 0 ); fread( abyFileHeader, 32, 1, psDBF->fp ); abyFileHeader[1] = 95; /* YY */ abyFileHeader[2] = 7; /* MM */ abyFileHeader[3] = 26; /* DD */ abyFileHeader[4] = psDBF->nRecords % 256; abyFileHeader[5] = (psDBF->nRecords/256) % 256; abyFileHeader[6] = (psDBF->nRecords/(256*256)) % 256; abyFileHeader[7] = (psDBF->nRecords/(256*256*256)) % 256; fseek( psDBF->fp, 0, 0 ); fwrite( abyFileHeader, 32, 1, psDBF->fp ); } /* -------------------------------------------------------------------- */ /* Close, and free resources. */ /* -------------------------------------------------------------------- */ fclose( psDBF->fp ); if( psDBF->panFieldOffset != NULL ) { free( psDBF->panFieldOffset ); free( psDBF->panFieldSize ); free( psDBF->panFieldDecimals ); free( psDBF->pachFieldType ); } free( psDBF->pszHeader ); free( psDBF->pszCurrentRecord ); free( psDBF ); if( pszStringField != NULL ) { free( pszStringField ); pszStringField = NULL; nStringFieldLen = 0; } } /************************************************************************/ /* DBFCreate() */ /* */ /* Create a new .dbf file. */ /************************************************************************/ DBFHandle DBFCreate( const char * pszFilename ) { DBFHandle psDBF; FILE *fp; char *pszFullname, *pszBasename; int i; /* -------------------------------------------------------------------- */ /* Compute the base (layer) name. If there is any extension */ /* on the passed in filename we will strip it off. */ /* -------------------------------------------------------------------- */ pszBasename = (char *) malloc(strlen(pszFilename)+5); strcpy( pszBasename, pszFilename ); for( i = strlen(pszBasename)-1; i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/' && pszBasename[i] != '\\'; i-- ) {} if( pszBasename[i] == '.' ) pszBasename[i] = '\0'; pszFullname = (char *) malloc(strlen(pszBasename) + 5); sprintf( pszFullname, "%s.dbf", pszBasename ); free( pszBasename ); /* -------------------------------------------------------------------- */ /* Create the file. */ /* -------------------------------------------------------------------- */ fp = fopen( pszFullname, "wb" ); if( fp == NULL ) return( NULL ); fputc( 0, fp ); fclose( fp ); fp = fopen( pszFullname, "rb+" ); if( fp == NULL ) return( NULL ); free( pszFullname ); /* -------------------------------------------------------------------- */ /* Create the info structure. */ /* -------------------------------------------------------------------- */ psDBF = (DBFHandle) malloc(sizeof(DBFInfo)); psDBF->fp = fp; psDBF->nRecords = 0; psDBF->nFields = 0; psDBF->nRecordLength = 1; psDBF->nHeaderLength = 33; psDBF->panFieldOffset = NULL; psDBF->panFieldSize = NULL; psDBF->panFieldDecimals = NULL; psDBF->pachFieldType = NULL; psDBF->pszHeader = NULL; psDBF->nCurrentRecord = -1; psDBF->bCurrentRecordModified = FALSE; psDBF->pszCurrentRecord = NULL; psDBF->bNoHeader = TRUE; return( psDBF ); } /************************************************************************/ /* DBFAddField() */ /* */ /* Add a field to a newly created .dbf file before any records */ /* are written. */ /************************************************************************/ int DBFAddField(DBFHandle psDBF, const char * pszFieldName, DBFFieldType eType, int nWidth, int nDecimals ) { char *pszFInfo; int i; /* -------------------------------------------------------------------- */ /* Do some checking to ensure we can add records to this file. */ /* -------------------------------------------------------------------- */ if( psDBF->nRecords > 0 ) return( -1 ); if( !psDBF->bNoHeader ) return( -1 ); if( eType != FTDouble && nDecimals != 0 ) return( -1 ); /* -------------------------------------------------------------------- */ /* SfRealloc all the arrays larger to hold the additional field */ /* information. */ /* -------------------------------------------------------------------- */ psDBF->nFields++; psDBF->panFieldOffset = (int *) SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields ); psDBF->panFieldSize = (int *) SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields ); psDBF->panFieldDecimals = (int *) SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields ); psDBF->pachFieldType = (char *) SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields ); /* -------------------------------------------------------------------- */ /* Assign the new field information fields. */ /* -------------------------------------------------------------------- */ psDBF->panFieldOffset[psDBF->nFields-1] = psDBF->nRecordLength; psDBF->nRecordLength += nWidth; psDBF->panFieldSize[psDBF->nFields-1] = nWidth; psDBF->panFieldDecimals[psDBF->nFields-1] = nDecimals; if( eType == FTString ) psDBF->pachFieldType[psDBF->nFields-1] = 'C'; else psDBF->pachFieldType[psDBF->nFields-1] = 'N'; /* -------------------------------------------------------------------- */ /* Extend the required header information. */ /* -------------------------------------------------------------------- */ psDBF->nHeaderLength += 32; psDBF->bUpdated = FALSE; psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,psDBF->nFields*32); pszFInfo = psDBF->pszHeader + 32 * (psDBF->nFields-1); for( i = 0; i < 32; i++ ) pszFInfo[i] = '\0'; if( strlen(pszFieldName) < 10 ) strncpy( pszFInfo, pszFieldName, strlen(pszFieldName)); else strncpy( pszFInfo, pszFieldName, 10); pszFInfo[11] = psDBF->pachFieldType[psDBF->nFields-1]; if( eType == FTString ) { pszFInfo[16] = nWidth % 256; pszFInfo[17] = nWidth / 256; } else { pszFInfo[16] = nWidth; pszFInfo[17] = nDecimals; } /* -------------------------------------------------------------------- */ /* Make the current record buffer appropriately larger. */ /* -------------------------------------------------------------------- */ psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord, psDBF->nRecordLength); return( psDBF->nFields-1 ); } /************************************************************************/ /* DBFReadAttribute() */ /* */ /* Read one of the attribute fields of a record. */ /************************************************************************/ static void *DBFReadAttribute(DBFHandle psDBF, int hEntity, int iField, char chReqType ) { int nRecordOffset; uchar *pabyRec; void *pReturnField = NULL; static double dDoubleField; /* -------------------------------------------------------------------- */ /* Have we read the record? */ /* -------------------------------------------------------------------- */ if( hEntity < 0 || hEntity >= psDBF->nRecords ) return( NULL ); if( psDBF->nCurrentRecord != hEntity ) { DBFFlushRecord( psDBF ); nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength; fseek( psDBF->fp, nRecordOffset, 0 ); fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp ); psDBF->nCurrentRecord = hEntity; } pabyRec = (uchar *) psDBF->pszCurrentRecord; /* -------------------------------------------------------------------- */ /* Ensure our field buffer is large enough to hold this buffer. */ /* -------------------------------------------------------------------- */ if( psDBF->panFieldSize[iField]+1 > nStringFieldLen ) { nStringFieldLen = psDBF->panFieldSize[iField]*2 + 10; pszStringField = (char *) SfRealloc(pszStringField,nStringFieldLen); } /* -------------------------------------------------------------------- */ /* Extract the requested field. */ /* -------------------------------------------------------------------- */ strncpy( pszStringField, (const char*)pabyRec+psDBF->panFieldOffset[iField], psDBF->panFieldSize[iField] ); pszStringField[psDBF->panFieldSize[iField]] = '\0'; pReturnField = pszStringField; /* -------------------------------------------------------------------- */ /* Decode the field. */ /* -------------------------------------------------------------------- */ if( chReqType == 'N' ) { dDoubleField = atof(pszStringField); pReturnField = &dDoubleField; } /* -------------------------------------------------------------------- */ /* Should we trim white space off the string attribute value? */ /* -------------------------------------------------------------------- */ #ifdef TRIM_DBF_WHITESPACE else { char *pchSrc, *pchDst; pchDst = pchSrc = pszStringField; while( *pchSrc == ' ' ) pchSrc++; while( *pchSrc != '\0' ) *(pchDst++) = *(pchSrc++); *pchDst = '\0'; while( *(--pchDst) == ' ' && pchDst != pszStringField ) *pchDst = '\0'; } #endif return( pReturnField ); } /************************************************************************/ /* DBFReadIntAttribute() */ /* */ /* Read an integer attribute. */ /************************************************************************/ int DBFReadIntegerAttribute( DBFHandle psDBF, int iRecord, int iField ) { double *pdValue; pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' ); return( (int) *pdValue ); } /************************************************************************/ /* DBFReadDoubleAttribute() */ /* */ /* Read a double attribute. */ /************************************************************************/ double DBFReadDoubleAttribute( DBFHandle psDBF, int iRecord, int iField ) { double *pdValue; pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' ); return( *pdValue ); } /************************************************************************/ /* DBFReadStringAttribute() */ /* */ /* Read a string attribute. */ /************************************************************************/ const char *DBFReadStringAttribute( DBFHandle psDBF, int iRecord, int iField ) { return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'C' ) ); } /************************************************************************/ /* DBFGetFieldCount() */ /* */ /* Return the number of fields in this table. */ /************************************************************************/ int DBFGetFieldCount( DBFHandle psDBF ) { return( psDBF->nFields ); } /************************************************************************/ /* DBFGetRecordCount() */ /* */ /* Return the number of records in this table. */ /************************************************************************/ int DBFGetRecordCount( DBFHandle psDBF ) { return( psDBF->nRecords ); } /************************************************************************/ /* DBFGetFieldInfo() */ /* */ /* Return any requested information about the field. */ /************************************************************************/ DBFFieldType DBFGetFieldInfo( DBFHandle psDBF, int iField, char * pszFieldName, int * pnWidth, int * pnDecimals ) { if( iField < 0 || iField >= psDBF->nFields ) return( FTInvalid ); if( pnWidth != NULL ) *pnWidth = psDBF->panFieldSize[iField]; if( pnDecimals != NULL ) *pnDecimals = psDBF->panFieldDecimals[iField]; if( pszFieldName != NULL ) { int i; strncpy( pszFieldName, (char *) psDBF->pszHeader+iField*32, 11 ); pszFieldName[11] = '\0'; for( i = 10; i > 0 && pszFieldName[i] == ' '; i-- ) pszFieldName[i] = '\0'; } if( psDBF->pachFieldType[iField] == 'N' || psDBF->pachFieldType[iField] == 'F' || psDBF->pachFieldType[iField] == 'D' ) { if( psDBF->panFieldDecimals[iField] > 0 ) return( FTDouble ); else return( FTInteger ); } else { return( FTString ); } } /************************************************************************/ /* DBFGetNativeFieldType() */ /* */ /* Return the DBase field type for the specified field. */ /* */ /* Value can be one of: 'C' (String), 'D' (Date), 'F' (Float), */ /* 'N' (Numeric, with or without decimal), */ /* 'L' (Logical), */ /* 'M' (Memo: 10 digits .DBT block ptr) */ /************************************************************************/ char DBFGetNativeFieldType( DBFHandle psDBF, int iField ) { if( iField >=0 && iField < psDBF->nFields ) return psDBF->pachFieldType[iField]; return ' '; } /************************************************************************/ /* DBFWriteAttribute() */ /* */ /* Write an attribute record to the file. */ /************************************************************************/ static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField, void * pValue ) { int nRecordOffset, i, j; uchar *pabyRec; char szSField[40], szFormat[12]; /* -------------------------------------------------------------------- */ /* Is this a valid record? */ /* -------------------------------------------------------------------- */ if( hEntity < 0 || hEntity > psDBF->nRecords ) return( FALSE ); if( psDBF->bNoHeader ) DBFWriteHeader(psDBF); /* -------------------------------------------------------------------- */ /* Is this a brand new record? */ /* -------------------------------------------------------------------- */ if( hEntity == psDBF->nRecords ) { DBFFlushRecord( psDBF ); psDBF->nRecords++; for( i = 0; i < psDBF->nRecordLength; i++ ) psDBF->pszCurrentRecord[i] = ' '; psDBF->nCurrentRecord = hEntity; } /* -------------------------------------------------------------------- */ /* Is this an existing record, but different than the last one */ /* we accessed? */ /* -------------------------------------------------------------------- */ if( psDBF->nCurrentRecord != hEntity ) { DBFFlushRecord( psDBF ); nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength; fseek( psDBF->fp, nRecordOffset, 0 ); fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp ); psDBF->nCurrentRecord = hEntity; } pabyRec = (uchar *) psDBF->pszCurrentRecord; /* -------------------------------------------------------------------- */ /* Assign all the record fields. */ /* -------------------------------------------------------------------- */ switch( psDBF->pachFieldType[iField] ) { case 'D': case 'N': case 'F': if( psDBF->panFieldDecimals[iField] == 0 ) { sprintf( szFormat, "%%%dd", psDBF->panFieldSize[iField] ); sprintf(szSField, szFormat, (int) *((double *) pValue) ); if( (int)strlen(szSField) > psDBF->panFieldSize[iField] ) szSField[psDBF->panFieldSize[iField]] = '\0'; strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]), szSField, strlen(szSField) ); } else { sprintf( szFormat, "%%%d.%df", psDBF->panFieldSize[iField], psDBF->panFieldDecimals[iField] ); sprintf(szSField, szFormat, *((double *) pValue) ); if( (int)strlen(szSField) > psDBF->panFieldSize[iField] ) szSField[psDBF->panFieldSize[iField]] = '\0'; strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]), szSField, strlen(szSField) ); } break; default: if( (int)strlen((char *) pValue) > psDBF->panFieldSize[iField] ) j = psDBF->panFieldSize[iField]; else { memset( pabyRec+psDBF->panFieldOffset[iField], ' ', psDBF->panFieldSize[iField] ); j = strlen((char *) pValue); } strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]), (char *) pValue, j ); break; } psDBF->bCurrentRecordModified = TRUE; psDBF->bUpdated = TRUE; return( TRUE ); } /************************************************************************/ /* DBFWriteAttributeDirectly() */ /* */ /* Write an attribute record to the file, but without any */ /* reformatting based on type. The provided buffer is written */ /* as is to the field position in the record. */ /************************************************************************/ int DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField, void * pValue ) { int nRecordOffset, i, j; uchar *pabyRec; /* -------------------------------------------------------------------- */ /* Is this a valid record? */ /* -------------------------------------------------------------------- */ if( hEntity < 0 || hEntity > psDBF->nRecords ) return( FALSE ); if( psDBF->bNoHeader ) DBFWriteHeader(psDBF); /* -------------------------------------------------------------------- */ /* Is this a brand new record? */ /* -------------------------------------------------------------------- */ if( hEntity == psDBF->nRecords ) { DBFFlushRecord( psDBF ); psDBF->nRecords++; for( i = 0; i < psDBF->nRecordLength; i++ ) psDBF->pszCurrentRecord[i] = ' '; psDBF->nCurrentRecord = hEntity; } /* -------------------------------------------------------------------- */ /* Is this an existing record, but different than the last one */ /* we accessed? */ /* -------------------------------------------------------------------- */ if( psDBF->nCurrentRecord != hEntity ) { DBFFlushRecord( psDBF ); nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength; fseek( psDBF->fp, nRecordOffset, 0 ); fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp ); psDBF->nCurrentRecord = hEntity; } pabyRec = (uchar *) psDBF->pszCurrentRecord; /* -------------------------------------------------------------------- */ /* Assign all the record fields. */ /* -------------------------------------------------------------------- */ if( (int)strlen((char *) pValue) > psDBF->panFieldSize[iField] ) j = psDBF->panFieldSize[iField]; else { memset( pabyRec+psDBF->panFieldOffset[iField], ' ', psDBF->panFieldSize[iField] ); j = strlen((char *) pValue); } strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]), (char *) pValue, j ); psDBF->bCurrentRecordModified = TRUE; psDBF->bUpdated = TRUE; return( TRUE ); } /************************************************************************/ /* DBFWriteDoubleAttribute() */ /* */ /* Write a double attribute. */ /************************************************************************/ int DBFWriteDoubleAttribute( DBFHandle psDBF, int iRecord, int iField, double dValue ) { return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) ); } /************************************************************************/ /* DBFWriteIntegerAttribute() */ /* */ /* Write a integer attribute. */ /************************************************************************/ int DBFWriteIntegerAttribute( DBFHandle psDBF, int iRecord, int iField, int nValue ) { double dValue = nValue; return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) ); } /************************************************************************/ /* DBFWriteStringAttribute() */ /* */ /* Write a string attribute. */ /************************************************************************/ int DBFWriteStringAttribute( DBFHandle psDBF, int iRecord, int iField, const char * pszValue ) { return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) pszValue ) ); } /************************************************************************/ /* DBFWriteTuple() */ /* */ /* Write an attribute record to the file. */ /************************************************************************/ int DBFWriteTuple(DBFHandle psDBF, int hEntity, void * pRawTuple ) { int nRecordOffset, i; uchar *pabyRec; /* -------------------------------------------------------------------- */ /* Is this a valid record? */ /* -------------------------------------------------------------------- */ if( hEntity < 0 || hEntity > psDBF->nRecords ) return( FALSE ); if( psDBF->bNoHeader ) DBFWriteHeader(psDBF); /* -------------------------------------------------------------------- */ /* Is this a brand new record? */ /* -------------------------------------------------------------------- */ if( hEntity == psDBF->nRecords ) { DBFFlushRecord( psDBF ); psDBF->nRecords++; for( i = 0; i < psDBF->nRecordLength; i++ ) psDBF->pszCurrentRecord[i] = ' '; psDBF->nCurrentRecord = hEntity; } /* -------------------------------------------------------------------- */ /* Is this an existing record, but different than the last one */ /* we accessed? */ /* -------------------------------------------------------------------- */ if( psDBF->nCurrentRecord != hEntity ) { DBFFlushRecord( psDBF ); nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength; fseek( psDBF->fp, nRecordOffset, 0 ); fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp ); psDBF->nCurrentRecord = hEntity; } pabyRec = (uchar *) psDBF->pszCurrentRecord; memcpy ( pabyRec, pRawTuple, psDBF->nRecordLength ); psDBF->bCurrentRecordModified = TRUE; psDBF->bUpdated = TRUE; return( TRUE ); } /************************************************************************/ /* DBFReadTuple() */ /* */ /* Read one of the attribute fields of a record. */ /************************************************************************/ const char *DBFReadTuple(DBFHandle psDBF, int hEntity ) { int nRecordOffset; uchar *pabyRec; static char *pReturnTuple = NULL; static int nTupleLen = 0; /* -------------------------------------------------------------------- */ /* Have we read the record? */ /* -------------------------------------------------------------------- */ if( hEntity < 0 || hEntity >= psDBF->nRecords ) return( NULL ); if( psDBF->nCurrentRecord != hEntity ) { DBFFlushRecord( psDBF ); nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength; fseek( psDBF->fp, nRecordOffset, 0 ); fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp ); psDBF->nCurrentRecord = hEntity; } pabyRec = (uchar *) psDBF->pszCurrentRecord; if ( nTupleLen < psDBF->nRecordLength) { nTupleLen = psDBF->nRecordLength; pReturnTuple = (char *) SfRealloc(pReturnTuple, psDBF->nRecordLength); } memcpy ( pReturnTuple, pabyRec, psDBF->nRecordLength ); return( pReturnTuple ); } /************************************************************************/ /* DBFCloneEmpty() */ /* */ /* Read one of the attribute fields of a record. */ /************************************************************************/ DBFHandle DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename ) { DBFHandle newDBF; newDBF = DBFCreate ( pszFilename ); if ( newDBF == NULL ) return ( NULL ); newDBF->pszHeader = (void *) malloc ( 32 * psDBF->nFields ); memcpy ( newDBF->pszHeader, psDBF->pszHeader, 32 * psDBF->nFields ); newDBF->nFields = psDBF->nFields; newDBF->nRecordLength = psDBF->nRecordLength; newDBF->nHeaderLength = psDBF->nHeaderLength; newDBF->panFieldOffset = (void *) malloc ( sizeof(int) * psDBF->nFields ); memcpy ( newDBF->panFieldOffset, psDBF->panFieldOffset, sizeof(int) * psDBF->nFields ); newDBF->panFieldSize = (void *) malloc ( sizeof(int) * psDBF->nFields ); memcpy ( newDBF->panFieldSize, psDBF->panFieldSize, sizeof(int) * psDBF->nFields ); newDBF->panFieldDecimals = (void *) malloc ( sizeof(int) * psDBF->nFields ); memcpy ( newDBF->panFieldDecimals, psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields ); newDBF->pachFieldType = (void *) malloc ( sizeof(int) * psDBF->nFields ); memcpy ( newDBF->pachFieldType, psDBF->pachFieldType, sizeof(int) * psDBF->nFields ); newDBF->bNoHeader = TRUE; newDBF->bUpdated = TRUE; DBFWriteHeader ( newDBF ); DBFClose ( newDBF ); newDBF = DBFOpen ( pszFilename, "rb+" ); return ( newDBF ); } avce00-2.0.0/avc.h0100664000076400007640000007616610471146411013015 0ustar danieldaniel/********************************************************************** * $Id: avc.h,v 1.24 2006/08/17 20:09:45 dmorissette Exp $ * * Name: avc.h * Project: Arc/Info Vector coverage (AVC) BIN<->E00 conversion library * Language: ANSI C * Purpose: Header file containing all definitions for the library. * Author: Daniel Morissette, dmorissette@dmsolutions.ca * ********************************************************************** * Copyright (c) 1999-2001, Daniel Morissette * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ********************************************************************** * * $Log: avc.h,v $ * Revision 1.24 2006/08/17 20:09:45 dmorissette * Update for 2.0.0 release * * Revision 1.23 2006/08/17 18:56:42 dmorissette * Support for reading standalone info tables (just tables, no coverage * data) by pointing AVCE00ReadOpen() to the info directory (bug 1549). * * Revision 1.22 2006/06/27 18:38:43 dmorissette * Cleaned up E00 reading (bug 1497, patch from James F.) * * Revision 1.21 2006/06/16 11:48:11 daniel * New functions to read E00 files directly as opposed to translating to * binary coverage. Used in the implementation of E00 read support in OGR. * Contributed by James E. Flemer. (bug 1497) * * Revision 1.20 2006/06/14 16:31:28 daniel * Added support for AVCCoverPC2 type (bug 1491) * * Revision 1.19 2005/06/03 03:49:58 daniel * Update email address, website url, and copyright dates * * Revision 1.18 2005/06/03 03:29:16 daniel * Ready for 1.3.0 release * * Revision 1.17 2004/02/11 05:49:44 daniel * Added support for deleted flag in arc.dir (bug 2332) * * Revision 1.16 2002/02/14 16:34:15 warmerda * fixed prototype name for AVCBinReadNextPrj * * Revision 1.15 2002/02/13 20:35:24 warmerda * added AVCBinReadObject * * Revision 1.14 2001/11/25 21:15:23 daniel * Added hack (AVC_MAP_TYPE40_TO_DOUBLE) to map type 40 fields bigger than 8 * digits to double precision as we generate E00 output (bug599) * * Revision 1.13 2001/02/20 15:24:11 daniel * Updated AVC_VERSION="1.2.0 (2000-10-17)" * * Revision 1.12 2000/09/26 21:38:44 daniel * Updated AVC_VERSION * * Revision 1.11 2000/09/26 20:21:04 daniel * Added AVCCoverPC write * * Revision 1.10 2000/09/22 19:45:20 daniel * Switch to MIT-style license * * Revision 1.9 2000/05/29 15:31:30 daniel * Added Japanese DBCS support * * Revision 1.8 2000/01/10 02:56:01 daniel * Added read support for "weird" coverages * * Revision 1.7 1999/12/24 07:18:34 daniel * Added PC Arc/Info coverages support * * Revision 1.6 1999/08/23 18:15:56 daniel * Added AVCE00DeleteCoverage() * * Revision 1.5 1999/06/08 22:07:28 daniel * Added AVCReadWrite in AVCAccess type * * Revision 1.4 1999/05/17 16:16:41 daniel * Added RXP + TXT/TX6/TX7 write support * * Revision 1.3 1999/05/11 02:15:04 daniel * Added coverage write support * * Revision 1.2 1999/02/25 03:39:39 daniel * Added TXT, TX6/TX7, RXP and RPL support * * Revision 1.1 1999/01/29 16:29:24 daniel * Initial revision * **********************************************************************/ #ifndef _AVC_H_INCLUDED_ #define _AVC_H_INCLUDED_ #include "cpl_conv.h" #include "cpl_string.h" #include "dbfopen.h" #include "avc_mbyte.h" CPL_C_START /*--------------------------------------------------------------------- * Current version of the AVCE00 library... always useful! *--------------------------------------------------------------------*/ #define AVC_VERSION "2.0.0 (2006-08-17)" /* Coverage precision */ #define AVC_DEFAULT_PREC 0 #define AVC_SINGLE_PREC 1 #define AVC_DOUBLE_PREC 2 /* AVC_FORMAT_DBF_FLOAT used as nPrecision value only for AVCPrintRealValue() */ #define AVC_FORMAT_DBF_FLOAT 42 /* Coverage file types */ typedef enum { AVCFileUnknown = 0, AVCFileARC, AVCFilePAL, AVCFileCNT, AVCFileLAB, AVCFilePRJ, AVCFileTOL, AVCFileLOG, AVCFileTXT, /* TXT and TX6 share the same binary format */ AVCFileTX6, AVCFileRXP, AVCFileRPL, /* RPL is a PAL for a region */ AVCFileTABLE }AVCFileType; /* Read or Write access flag */ typedef enum { AVCRead, AVCWrite, AVCReadWrite } AVCAccess; /* Coverage type: PC Arc/Info or Unix Arc/Info v7 */ typedef enum { AVCCoverTypeUnknown = 0, AVCCoverV7, AVCCoverPC, AVCCoverPC2, /* Unknown version... hybrid between V7 and PC !!! */ AVCCoverWeird, /* Unknown version... hybrid between V7 and PC !!! */ AVCCoverV7Tables /* Standalone tables, only an info directory */ } AVCCoverType; /* Enum for byte ordering */ typedef enum { AVCBigEndian, /* CPL_MSB, Motorola ordering */ AVCLittleEndian /* CPL_LSB, Intel ordering */ } AVCByteOrder; /* Macros to establish byte ordering for each coverage type * The rule until now: all coverage types use big endian (Motorola ordering) * except PC Arc/Info coverages variant 1 (AVCCoverPC). */ #define AVC_COVER_BYTE_ORDER(cover_type) \ (((cover_type) == AVCCoverPC ) ? AVCLittleEndian : AVCBigEndian ) /*===================================================================== Structures =====================================================================*/ /*--------------------------------------------------------------------- * Structures defining various Arc/Info objects types. * These are shared by the Binary and the E00 functions. *--------------------------------------------------------------------*/ typedef struct AVCVertex_t { double x; /* Even for single precision, we always */ double y; /* use doubles for the vertices in memory. */ }AVCVertex; /*--------------------------------------------------------------------- * AVCArc: Information about an ARC *--------------------------------------------------------------------*/ typedef struct AVCArc_t { GInt32 nArcId; GInt32 nUserId; GInt32 nFNode; GInt32 nTNode; GInt32 nLPoly; GInt32 nRPoly; GInt32 numVertices; AVCVertex *pasVertices; }AVCArc; /*--------------------------------------------------------------------- * AVCPal: A PAL (Polygon Arc List) references all the arcs that * constitute a polygon. *--------------------------------------------------------------------*/ typedef struct AVCPalArc_t { GInt32 nArcId; GInt32 nFNode; GInt32 nAdjPoly; }AVCPalArc; typedef struct AVCPal_t { GInt32 nPolyId; AVCVertex sMin; AVCVertex sMax; GInt32 numArcs; AVCPalArc *pasArcs; }AVCPal; /*--------------------------------------------------------------------- * AVCCnt: Information about a CNT (polygon centroid) *--------------------------------------------------------------------*/ typedef struct AVCCnt_t { GInt32 nPolyId; AVCVertex sCoord; GInt32 numLabels; /* 0 or 1 */ GInt32 *panLabelIds; }AVCCnt; /*--------------------------------------------------------------------- * AVCLab: Information about a LAB (polygon Label) *--------------------------------------------------------------------*/ typedef struct AVCLab_t { GInt32 nValue; GInt32 nPolyId; AVCVertex sCoord1; AVCVertex sCoord2; AVCVertex sCoord3; }AVCLab; /*--------------------------------------------------------------------- * AVCTol: Information about a TOL record (coverage tolerances) *--------------------------------------------------------------------*/ typedef struct AVCTol_t { GInt32 nIndex; GInt32 nFlag; double dValue; }AVCTol; /*--------------------------------------------------------------------- * AVCTxt: Information about a TXT/TX6/TX7 record (annotations) *--------------------------------------------------------------------*/ typedef struct AVCTxt_t { GInt32 nTxtId; GInt32 nUserId; GInt32 nLevel; float f_1e2; /* Always (float)-1e+20, even for double precision! */ GInt32 nSymbol; GInt32 numVerticesLine; GInt32 n28; /* Unknown value at byte 28 */ GInt32 numChars; GInt32 numVerticesArrow; GInt16 anJust1[20]; GInt16 anJust2[20]; double dHeight; double dV2; /* ??? */ double dV3; /* ??? */ char *pszText; AVCVertex *pasVertices; }AVCTxt; /*--------------------------------------------------------------------- * AVCRxp: Information about a RXP record (something related to regions...) *--------------------------------------------------------------------*/ typedef struct AVCRxp_t { GInt32 n1; GInt32 n2; }AVCRxp; /*--------------------------------------------------------------------- * AVCTableDef: Definition of an INFO table's structure. * This info is read from several files: * info/arc.dir * info/arc####.dat * info/arc####.nit * * And the data for the table itself is stored in a binary * file in the coverage directory. *--------------------------------------------------------------------*/ typedef struct AVCFieldInfo_t { char szName[17]; GInt16 nSize; GInt16 v2; GInt16 nOffset; GInt16 v4; GInt16 v5; GInt16 nFmtWidth; GInt16 nFmtPrec; GInt16 nType1; GInt16 nType2; GInt16 v10; GInt16 v11; GInt16 v12; GInt16 v13; char szAltName[17]; GInt16 nIndex; /* >0 if valid, or -1 if field is deleted */ }AVCFieldInfo; #define AVC_FT_DATE 10 #define AVC_FT_CHAR 20 #define AVC_FT_FIXINT 30 #define AVC_FT_FIXNUM 40 #define AVC_FT_BININT 50 #define AVC_FT_BINFLOAT 60 typedef struct AVCTableDef_t { /* Stuff read from the arc.dir file * (1 record, corresponding to this table, from the arc.dir file) */ char szTableName[33]; char szInfoFile[9]; GInt16 numFields; GInt16 nRecSize; GInt32 numRecords; char szExternal[3]; /* "XX" or " " */ GInt16 bDeletedFlag; /* 1 if deleted, 0 if table is active */ /* Data file path read from the arc####.dat file */ char szDataFile[81]; /* Field information read from the arc####.nit file */ AVCFieldInfo *pasFieldDef; }AVCTableDef; typedef struct AVCField_t { GInt16 nInt16; GInt32 nInt32; float fFloat; double dDouble; char *pszStr; }AVCField; /*--------------------------------------------------------------------- * Stuff related to buffered reading of raw binary files *--------------------------------------------------------------------*/ #define AVCRAWBIN_READBUFSIZE 1024 typedef struct AVCRawBinFile_t { FILE *fp; char *pszFname; AVCAccess eAccess; AVCByteOrder eByteOrder; GByte abyBuf[AVCRAWBIN_READBUFSIZE]; int nOffset; /* Location of current buffer in the file */ int nCurSize; /* Nbr of bytes currently loaded */ int nCurPos; /* Next byte to read from abyBuf[] */ int nFileDataSize; /* File Size as stated in the header */ /* EOF=TRUE passed this point in file */ /* Set to -1 if not specified. */ /* Handle on dataset's multibyte character encoding info. */ AVCDBCSInfo *psDBCSInfo; }AVCRawBinFile; /*--------------------------------------------------------------------- * Stuff related to reading and writing binary coverage files *--------------------------------------------------------------------*/ typedef struct AVCBinHeader_t { GUInt32 nSignature; GInt32 nPrecision; /* <0 for double prec., >0 for single prec. */ GInt32 nRecordSize; /* nbr of 2 byte words, 0 for var. length */ GInt32 nLength; /* Overall file length, in 2 byte words */ }AVCBinHeader; typedef struct AVCBinFile_t { AVCRawBinFile *psRawBinFile; char *pszFilename; AVCRawBinFile *psIndexFile; /* Index file, Write mode only */ DBFHandle hDBFFile; /* Used for AVCCoverPC/PC2 DBF TABLES only */ int nCurDBFRecord; /* 0-based record index in DBF file */ AVCCoverType eCoverType; AVCFileType eFileType; int nPrecision; /* AVC_SINGLE/DOUBLE_PREC */ union { AVCTableDef *psTableDef; }hdr; /* cur.* : temp. storage used to read one record (ARC, PAL, ... or * Table record) from the file. */ union { AVCArc *psArc; AVCPal *psPal; AVCCnt *psCnt; AVCLab *psLab; AVCTol *psTol; AVCTxt *psTxt; AVCRxp *psRxp; AVCField *pasFields; char **papszPrj; }cur; }AVCBinFile; /*--------------------------------------------------------------------- * Stuff related to the generation of E00 *--------------------------------------------------------------------*/ /*--------------------------------------------------------------------- * AVCE00GenInfo structure * This structure is used by the E00 generator functions to store * their buffer and their current state in case they need to be * called more than once for a given object type (i.e. ARC, PAL and IFO). *--------------------------------------------------------------------*/ typedef struct AVCE00GenInfo_t { char *pszBuf; int nBufSize; int nPrecision; /* AVC_SINGLE/DOUBLE_PREC */ int iCurItem; int numItems; }AVCE00GenInfo; /*--------------------------------------------------------------------- * Stuff related to the parsing of E00 *--------------------------------------------------------------------*/ /*--------------------------------------------------------------------- * AVCE00ParseInfo structure * This structure is used by the E00 parser functions to store * their buffer and their current state while parsing an object. *--------------------------------------------------------------------*/ typedef struct AVCE00ParseInfo_t { AVCFileType eFileType; int nPrecision; /* AVC_SINGLE/DOUBLE_PREC */ int iCurItem; int numItems; int nStartLineNum; int nCurLineNum; int nCurObjectId; GBool bForceEndOfSection; /* For sections that don't have an */ /* explicit end-of-section line. */ AVCFileType eSuperSectionType;/* For sections containing several files*/ char *pszSectionHdrLine; /* Used by supersection types */ union { AVCTableDef *psTableDef; }hdr; GBool bTableHdrComplete; /* FALSE until table header is */ /* finished parsing */ int nTableE00RecLength; /* cur.* : temp. storage used to store current object (ARC, PAL, ... or * Table record) from the file. */ union { AVCArc *psArc; AVCPal *psPal; AVCCnt *psCnt; AVCLab *psLab; AVCTol *psTol; AVCTxt *psTxt; AVCRxp *psRxp; AVCField *pasFields; char **papszPrj; }cur; char *pszBuf; /* Buffer used only for TABLEs */ int nBufSize; }AVCE00ParseInfo; /*--------------------------------------------------------------------- * Stuff related to the transparent binary -> E00 conversion *--------------------------------------------------------------------*/ typedef struct AVCE00Section_t { AVCFileType eType; /* File Type */ char *pszName; /* E00 section or Table Name */ char *pszFilename; /* Binary/E00 file filename */ int nLineNum; /* E00 line number */ int nFeatureCount; }AVCE00Section; typedef struct AVCE00ReadInfo_t { char *pszCoverPath; char *pszInfoPath; char *pszCoverName; AVCCoverType eCoverType; /* pasSections is built when the coverage is opened and describes * the squeleton of the E00 file. */ AVCE00Section *pasSections; int numSections; /* If bReadAllSections=TRUE then reading automatically continues to * the next section when a section finishes. (This is the default) * Otherwise, you can use AVCE00ReadGotoSection() to read one section * at a time... this will set bReadAllSections=FALSE. */ GBool bReadAllSections; /* Info about the file (or E00 section) currently being processed */ int iCurSection; AVCBinFile *hFile; int iCurStep; /* AVC_GEN_* values, see below */ AVCE00GenInfo *hGenInfo; /* Info related to multibyte character encoding */ AVCDBCSInfo *psDBCSInfo; } *AVCE00ReadPtr; typedef struct AVCE00ReadInfoE00_t { char *pszCoverPath; char *pszCoverName; AVCE00ParseInfo *hParseInfo; AVCFileType eCurFileType; /* pasSections is built when the coverage is opened and describes * the sections in the E00 file. */ AVCE00Section *pasSections; int numSections; /* If bReadAllSections=TRUE then reading automatically continues to * the next section when a section finishes. (This is the default) * Otherwise, you can use AVCE00ReadGotoSectionE00() to read one * section at a time. */ GBool bReadAllSections; /* File handle of the E00 file currently being processed */ FILE *hFile; } *AVCE00ReadE00Ptr; /* E00 generation steps... tells the AVCE00Read*() functions which * parts of the given E00 file are currently being processed. */ #define AVC_GEN_NOTSTARTED 0 #define AVC_GEN_DATA 1 #define AVC_GEN_ENDSECTION 2 #define AVC_GEN_TABLEHEADER 3 #define AVC_GEN_TABLEDATA 4 /*--------------------------------------------------------------------- * Stuff related to the transparent E00 -> binary conversion *--------------------------------------------------------------------*/ typedef struct AVCE00WriteInfo_t { char *pszCoverPath; char *pszInfoPath; char *pszCoverName; AVCCoverType eCoverType; /* Info about the file (or E00 section) currently being processed */ AVCFileType eCurFileType; AVCBinFile *hFile; /* Requested precision for the new coverage... may differ from the * precision of the E00 input lines. (AVC_SINGLE_PREC or AVC_DOUBLE_PREC) */ int nPrecision; AVCE00ParseInfo *hParseInfo; /* Info related to multibyte character encoding */ AVCDBCSInfo *psDBCSInfo; } *AVCE00WritePtr; /* Coverage generation steps... used to store the current state of the * AVCE00WriteNextLine() function. */ #define AVC_WR_TOPLEVEL 0 #define AVC_WR_READING_SECTION /*===================================================================== Function prototypes (lower-level lib. functions) =====================================================================*/ /*--------------------------------------------------------------------- * Functions related to buffered reading of raw binary files (and writing) *--------------------------------------------------------------------*/ AVCRawBinFile *AVCRawBinOpen(const char *pszFname, const char *pszAccess, AVCByteOrder eFileByteOrder, AVCDBCSInfo *psDBCSInfo); void AVCRawBinClose(AVCRawBinFile *psInfo); void AVCRawBinFSeek(AVCRawBinFile *psInfo, int nOffset, int nFrom); GBool AVCRawBinEOF(AVCRawBinFile *psInfo); void AVCRawBinSetFileDataSize(AVCRawBinFile *psInfo, int nDataSize); void AVCRawBinReadBytes(AVCRawBinFile *psInfo, int nBytesToRead, GByte *pBuf); GInt16 AVCRawBinReadInt16(AVCRawBinFile *psInfo); GInt32 AVCRawBinReadInt32(AVCRawBinFile *psInfo); float AVCRawBinReadFloat(AVCRawBinFile *psInfo); double AVCRawBinReadDouble(AVCRawBinFile *psInfo); void AVCRawBinReadString(AVCRawBinFile *psFile, int nBytesToRead, GByte *pBuf); void AVCRawBinWriteBytes(AVCRawBinFile *psFile, int nBytesToWrite, GByte *pBuf); void AVCRawBinWriteInt16(AVCRawBinFile *psFile, GInt16 n16Value); void AVCRawBinWriteInt32(AVCRawBinFile *psFile, GInt32 n32Value); void AVCRawBinWriteFloat(AVCRawBinFile *psFile, float fValue); void AVCRawBinWriteDouble(AVCRawBinFile *psFile, double dValue); void AVCRawBinWriteZeros(AVCRawBinFile *psFile, int nBytesToWrite); void AVCRawBinWritePaddedString(AVCRawBinFile *psFile, int nFieldSize, const char *pszString); /*--------------------------------------------------------------------- * Functions related to reading the binary coverage files *--------------------------------------------------------------------*/ AVCBinFile *AVCBinReadOpen(const char *pszPath, const char *pszName, AVCCoverType eCoverType, AVCFileType eType, AVCDBCSInfo *psDBCSInfo); void AVCBinReadClose(AVCBinFile *psFile); int AVCBinReadRewind(AVCBinFile *psFile); void *AVCBinReadObject(AVCBinFile *psFile, int iObjIndex ); void *AVCBinReadNextObject(AVCBinFile *psFile); AVCArc *AVCBinReadNextArc(AVCBinFile *psFile); AVCPal *AVCBinReadNextPal(AVCBinFile *psFile); AVCCnt *AVCBinReadNextCnt(AVCBinFile *psFile); AVCLab *AVCBinReadNextLab(AVCBinFile *psFile); AVCTol *AVCBinReadNextTol(AVCBinFile *psFile); AVCTxt *AVCBinReadNextTxt(AVCBinFile *psFile); AVCRxp *AVCBinReadNextRxp(AVCBinFile *psFile); AVCField *AVCBinReadNextTableRec(AVCBinFile *psFile); char **AVCBinReadNextPrj(AVCBinFile *psFile); char **AVCBinReadListTables(const char *pszInfoPath, const char *pszCoverName, char ***ppapszArcDatFiles, AVCCoverType eCoverType, AVCDBCSInfo *psDBCSInfo); /*--------------------------------------------------------------------- * Functions related to writing the binary coverage files *--------------------------------------------------------------------*/ AVCBinFile *AVCBinWriteCreate(const char *pszPath, const char *pszName, AVCCoverType eCoverType, AVCFileType eType, int nPrecision, AVCDBCSInfo *psDBCSInfo); AVCBinFile *AVCBinWriteCreateTable(const char *pszInfoPath, const char *pszCoverName, AVCTableDef *psSrcTableDef, AVCCoverType eCoverType, int nPrecision, AVCDBCSInfo *psDBCSInfo); void AVCBinWriteClose(AVCBinFile *psFile); int AVCBinWriteHeader(AVCBinFile *psFile); int AVCBinWriteObject(AVCBinFile *psFile, void *psObj); int AVCBinWriteArc(AVCBinFile *psFile, AVCArc *psArc); int AVCBinWritePal(AVCBinFile *psFile, AVCPal *psPal); int AVCBinWriteCnt(AVCBinFile *psFile, AVCCnt *psCnt); int AVCBinWriteLab(AVCBinFile *psFile, AVCLab *psLab); int AVCBinWriteTol(AVCBinFile *psFile, AVCTol *psTol); int AVCBinWritePrj(AVCBinFile *psFile, char **papszPrj); int AVCBinWriteTxt(AVCBinFile *psFile, AVCTxt *psTxt); int AVCBinWriteRxp(AVCBinFile *psFile, AVCRxp *psRxp); int AVCBinWriteTableRec(AVCBinFile *psFile, AVCField *pasFields); /*--------------------------------------------------------------------- * Functions related to the generation of E00 *--------------------------------------------------------------------*/ AVCE00GenInfo *AVCE00GenInfoAlloc(int nCoverPrecision); void AVCE00GenInfoFree(AVCE00GenInfo *psInfo); void AVCE00GenReset(AVCE00GenInfo *psInfo); const char *AVCE00GenStartSection(AVCE00GenInfo *psInfo, AVCFileType eType, const char *pszFilename); const char *AVCE00GenEndSection(AVCE00GenInfo *psInfo, AVCFileType eType, GBool bCont); const char *AVCE00GenObject(AVCE00GenInfo *psInfo, AVCFileType eType, void *psObj, GBool bCont); const char *AVCE00GenArc(AVCE00GenInfo *psInfo, AVCArc *psArc, GBool bCont); const char *AVCE00GenPal(AVCE00GenInfo *psInfo, AVCPal *psPal, GBool bCont); const char *AVCE00GenCnt(AVCE00GenInfo *psInfo, AVCCnt *psCnt, GBool bCont); const char *AVCE00GenLab(AVCE00GenInfo *psInfo, AVCLab *psLab, GBool bCont); const char *AVCE00GenTol(AVCE00GenInfo *psInfo, AVCTol *psTol, GBool bCont); const char *AVCE00GenTxt(AVCE00GenInfo *psInfo, AVCTxt *psTxt, GBool bCont); const char *AVCE00GenTx6(AVCE00GenInfo *psInfo, AVCTxt *psTxt, GBool bCont); const char *AVCE00GenPrj(AVCE00GenInfo *psInfo, char **papszPrj, GBool bCont); const char *AVCE00GenRxp(AVCE00GenInfo *psInfo, AVCRxp *psRxp, GBool bCont); const char *AVCE00GenTableHdr(AVCE00GenInfo *psInfo, AVCTableDef *psDef, GBool bCont); const char *AVCE00GenTableRec(AVCE00GenInfo *psInfo, int numFields, AVCFieldInfo *pasDef, AVCField *pasFields, GBool bCont); /*--------------------------------------------------------------------- * Functions related to parsing E00 lines *--------------------------------------------------------------------*/ AVCE00ParseInfo *AVCE00ParseInfoAlloc(); void AVCE00ParseInfoFree(AVCE00ParseInfo *psInfo); void AVCE00ParseReset(AVCE00ParseInfo *psInfo); AVCFileType AVCE00ParseSectionHeader(AVCE00ParseInfo *psInfo, const char *pszLine); GBool AVCE00ParseSectionEnd(AVCE00ParseInfo *psInfo, const char *pszLine, GBool bResetParseInfo); AVCFileType AVCE00ParseSuperSectionHeader(AVCE00ParseInfo *psInfo, const char *pszLine); GBool AVCE00ParseSuperSectionEnd(AVCE00ParseInfo *psInfo, const char *pszLine ); void *AVCE00ParseNextLine(AVCE00ParseInfo *psInfo, const char *pszLine); AVCArc *AVCE00ParseNextArcLine(AVCE00ParseInfo *psInfo, const char *pszLine); AVCPal *AVCE00ParseNextPalLine(AVCE00ParseInfo *psInfo, const char *pszLine); AVCCnt *AVCE00ParseNextCntLine(AVCE00ParseInfo *psInfo, const char *pszLine); AVCLab *AVCE00ParseNextLabLine(AVCE00ParseInfo *psInfo, const char *pszLine); AVCTol *AVCE00ParseNextTolLine(AVCE00ParseInfo *psInfo, const char *pszLine); AVCTxt *AVCE00ParseNextTxtLine(AVCE00ParseInfo *psInfo, const char *pszLine); AVCTxt *AVCE00ParseNextTx6Line(AVCE00ParseInfo *psInfo, const char *pszLine); char **AVCE00ParseNextPrjLine(AVCE00ParseInfo *psInfo, const char *pszLine); AVCRxp *AVCE00ParseNextRxpLine(AVCE00ParseInfo *psInfo, const char *pszLine); AVCTableDef *AVCE00ParseNextTableDefLine(AVCE00ParseInfo *psInfo, const char *pszLine); AVCField *AVCE00ParseNextTableRecLine(AVCE00ParseInfo *psInfo, const char *pszLine); /*--------------------------------------------------------------------- * Misc. functions shared by several parts of the lib. *--------------------------------------------------------------------*/ int _AVCE00ComputeRecSize(int numFields, AVCFieldInfo *pasDef, GBool bMapType40ToDouble); void _AVCDestroyTableFields(AVCTableDef *psTableDef, AVCField *pasFields); void _AVCDestroyTableDef(AVCTableDef *psTableDef); AVCTableDef *_AVCDupTableDef(AVCTableDef *psSrcDef); GBool AVCFileExists(const char *pszPath, const char *pszName); char *AVCAdjustCaseSensitiveFilename(char *pszFname); int AVCPrintRealValue(char *pszBuf, int nPrecision, AVCFileType eType, double dValue); /*===================================================================== Function prototypes (THE PUBLIC ONES) =====================================================================*/ /*--------------------------------------------------------------------- * Functions to read E00 *--------------------------------------------------------------------*/ AVCE00ReadE00Ptr AVCE00ReadOpenE00(const char *pszE00FileName); void AVCE00ReadCloseE00(AVCE00ReadE00Ptr psRead); int AVCE00ReadRewindE00(AVCE00ReadE00Ptr psRead); void *AVCE00ReadNextObjectE00(AVCE00ReadE00Ptr psRead); AVCE00Section *AVCE00ReadSectionsListE00(AVCE00ReadE00Ptr psRead, int *numSect); int AVCE00ReadGotoSectionE00(AVCE00ReadE00Ptr psRead, AVCE00Section *psSect, GBool bContinue); /*--------------------------------------------------------------------- * Functions to make a binary coverage appear as E00 *--------------------------------------------------------------------*/ AVCE00ReadPtr AVCE00ReadOpen(const char *pszCoverPath); void AVCE00ReadClose(AVCE00ReadPtr psInfo); const char *AVCE00ReadNextLine(AVCE00ReadPtr psInfo); int AVCE00ReadRewind(AVCE00ReadPtr psInfo); AVCE00Section *AVCE00ReadSectionsList(AVCE00ReadPtr psInfo, int *numSect); int AVCE00ReadGotoSection(AVCE00ReadPtr psInfo, AVCE00Section *psSect, GBool bContinue); /*--------------------------------------------------------------------- * Functions to write E00 lines to a binary coverage *--------------------------------------------------------------------*/ AVCE00WritePtr AVCE00WriteOpen(const char *pszCoverPath, AVCCoverType eNewCoverType, int nPrecision); void AVCE00WriteClose(AVCE00WritePtr psInfo); int AVCE00WriteNextLine(AVCE00WritePtr psInfo, const char *pszLine); int AVCE00DeleteCoverage(const char *pszCoverPath); CPL_C_END #endif /* _AVC_H_INCLUDED_ */ avce00-2.0.0/TODO.TXT0100664000076400007640000000277210471146411013231 0ustar danieldanielToDo list for the AVC Library: ----------------------------- - Docs: new member in squeleton struct... update example in docs. ==== Known issues ==== (For the list of currently open bugs, see: http://bugzilla.maptools.org/buglist.cgi?product=AVCE00&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED) - Windows-specific: 0 bytes allocation fails with arc with 0 vertices. - There are still a couple of values inside arc.dir for which I don't know the meaning. Setting them to zero seems to work... but these could be investigated a little more to try to find their meaning. - Potential collision problem if 2 processes try to add an info table to the ARC.DIR at the same time. Does Arc/Info have any way to lock the ARC.DIR??? - ??? Add support to explicitly specify the precision when creating a new coverage. For now AVCE00WriteOpen() only supports AVC_DEFAULT_PREC, but if we added some code to convert the INFO TABLE fields precision from single to double precision and vice-versa then we should be able to create a coverage using a precision different from the one in the source E00. - Interesting problem: sometimes tol.adf have missing tolerance index (ex: 2 and 3), and they appear to be replaced by index 11 and 12 at the end of the file. However, Arc/Info still exports a normal TOL section, with 10 values with indexes going from 1 to 10... (see single precision annotation.e00 coverage) ---------- $Id: TODO.TXT,v 1.2 2006/08/17 20:09:45 dmorissette Exp $ ---------- avce00-2.0.0/cpl_vsisimple.c0100664000076400007640000002351407457112427015107 0ustar danieldaniel/****************************************************************************** * Copyright (c) 1998, Frank Warmerdam * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ****************************************************************************** * * cpl_vsisimple.cpp * * This is a simple implementation (direct to Posix) of the Virtual System * Interface (VSI). See gdal_vsi.h. * * TODO: * - add some assertions to ensure that arguments are widely legal. For * instance validation of access strings to fopen(). * * $Log: cpl_vsisimple.c,v $ * Revision 1.3 2002/04/16 21:18:15 daniel * Added missing headers for rmdir() in WIN32 * * Revision 1.2 2002/03/18 18:59:26 daniel * Added VSIMkdir(), VSIRmdir() and VSIUnlink() * * Revision 1.1 1999/08/27 14:09:55 daniel * Update CPL files * * Revision 1.3 1998/12/14 04:50:33 warmerda * Avoid C++ comments so it will be C compilable as well. * * Revision 1.2 1998/12/04 21:42:57 danmo * Added #ifndef WIN32 arounf #include * * Revision 1.1 1998/12/03 18:26:03 warmerda * New * */ #include "cpl_vsi.h" /* for stat() */ #ifndef WIN32 # include #else # include # include # include #endif #include /************************************************************************/ /* VSIFOpen() */ /************************************************************************/ FILE *VSIFOpen( const char * pszFilename, const char * pszAccess ) { return( fopen( (char *) pszFilename, (char *) pszAccess ) ); } /************************************************************************/ /* VSIFClose() */ /************************************************************************/ int VSIFClose( FILE * fp ) { return( fclose(fp) ); } /************************************************************************/ /* VSIFSeek() */ /************************************************************************/ int VSIFSeek( FILE * fp, long nOffset, int nWhence ) { return( fseek( fp, nOffset, nWhence ) ); } /************************************************************************/ /* VSIFTell() */ /************************************************************************/ long VSIFTell( FILE * fp ) { return( ftell( fp ) ); } /************************************************************************/ /* VSIRewind() */ /************************************************************************/ void VSIRewind( FILE * fp ) { rewind( fp ); } /************************************************************************/ /* VSIFRead() */ /************************************************************************/ size_t VSIFRead( void * pBuffer, size_t nSize, size_t nCount, FILE * fp ) { return( fread( pBuffer, nSize, nCount, fp ) ); } /************************************************************************/ /* VSIFWrite() */ /************************************************************************/ size_t VSIFWrite( void * pBuffer, size_t nSize, size_t nCount, FILE * fp ) { return( fwrite( pBuffer, nSize, nCount, fp ) ); } /************************************************************************/ /* VSIFGets() */ /************************************************************************/ char *VSIFGets( char *pszBuffer, int nBufferSize, FILE * fp ) { return( fgets( pszBuffer, nBufferSize, fp ) ); } /************************************************************************/ /* VSIFGetc() */ /************************************************************************/ int VSIFGetc( FILE * fp ) { return( fgetc( fp ) ); } /************************************************************************/ /* VSIUngetc() */ /************************************************************************/ int VSIUngetc( int c, FILE * fp ) { return( ungetc( c, fp ) ); } /************************************************************************/ /* VSIFPrintf() */ /* */ /* This is a little more complicated than just calling */ /* fprintf() because of the variable arguments. Instead we */ /* have to use vfprintf(). */ /************************************************************************/ int VSIFPrintf( FILE * fp, const char * pszFormat, ... ) { va_list args; int nReturn; va_start( args, pszFormat ); nReturn = vfprintf( fp, pszFormat, args ); va_end( args ); return( nReturn ); } /************************************************************************/ /* VSIFEof() */ /************************************************************************/ int VSIFEof( FILE * fp ) { return( feof( fp ) ); } /************************************************************************/ /* VSIFPuts() */ /************************************************************************/ int VSIFPuts( const char * pszString, FILE * fp ) { return fputs( pszString, fp ); } /************************************************************************/ /* VSIFPutc() */ /************************************************************************/ int VSIFPutc( int nChar, FILE * fp ) { return( fputc( nChar, fp ) ); } /************************************************************************/ /* VSICalloc() */ /************************************************************************/ void *VSICalloc( size_t nCount, size_t nSize ) { return( calloc( nCount, nSize ) ); } /************************************************************************/ /* VSIMalloc() */ /************************************************************************/ void *VSIMalloc( size_t nSize ) { return( malloc( nSize ) ); } /************************************************************************/ /* VSIRealloc() */ /************************************************************************/ void * VSIRealloc( void * pData, size_t nNewSize ) { return( realloc( pData, nNewSize ) ); } /************************************************************************/ /* VSIFree() */ /************************************************************************/ void VSIFree( void * pData ) { if( pData != NULL ) free( pData ); } /************************************************************************/ /* VSIStrdup() */ /************************************************************************/ char *VSIStrdup( const char * pszString ) { return( strdup( pszString ) ); } /************************************************************************/ /* VSIStat() */ /************************************************************************/ int VSIStat( const char * pszFilename, VSIStatBuf * pStatBuf ) { return( stat( pszFilename, pStatBuf ) ); } /************************************************************************/ /* VSIMkdir() */ /************************************************************************/ int VSIMkdir( const char *pszPathname, long mode ) { #ifdef WIN32 return mkdir( pszPathname ); #elif defined(macos_pre10) return -1; #else return mkdir( pszPathname, mode ); #endif } /************************************************************************/ /* VSIUnlink() */ /*************************a***********************************************/ int VSIUnlink( const char * pszFilename ) { return unlink( pszFilename ); } /************************************************************************/ /* VSIRmdir() */ /************************************************************************/ int VSIRmdir( const char * pszFilename ) { return rmdir( pszFilename ); } avce00-2.0.0/GNUmakefile0100664000076400007640000000652010450275463014137 0ustar danieldaniel# Makefile for the Arc/Info Vector Coverage (AVC) reader # # $Id: GNUmakefile,v 1.8 2006/06/27 18:38:43 dmorissette Exp $ # # $Log: GNUmakefile,v $ # Revision 1.8 2006/06/27 18:38:43 dmorissette # Cleaned up E00 reading (bug 1497, patch from James F.) # # Revision 1.7 2001/11/25 21:15:22 daniel # Added hack (AVC_MAP_TYPE40_TO_DOUBLE) to map type 40 fields bigger than 8 # digits to double precision as we generate E00 output (bug599) # # Revision 1.6 2000/09/26 20:48:40 daniel # Added optional -DAVC_IGNORE_RMDIR_ERROR # # Revision 1.5 2000/05/29 17:12:56 daniel # Added avc_mbyte.* # # Revision 1.4 1999/12/24 07:18:34 daniel # Added PC Arc/Info coverages support # # Revision 1.3 1999/05/11 02:06:54 daniel # Added coverage write support (alpha version) # # Revision 1.2 1999/02/25 05:19:06 daniel # Added cpl_dir.c # # Revision 1.1 1999/01/29 16:29:55 daniel # Initial revision # # # # Default compiler is gcc, # CC = gcc # # Link with DBMALLOC when running in a test environment # #LIB_DBMALLOC= /home/daniel/proj/dbmalloc-14L2/libdbmalloc.a # # Byte ordering ... default is Intel ordering (CPL_LSB), # Select CPL_MSB for SUNs or other platforms with MSB first ordering. # # BYTE_ORDER_FL = -DCPL_MSB BYTE_ORDER_FL = -DCPL_LSB # # In some cases, AVCE00DeleteCoverage() fails because the coverage directory # could be locked by another application on the same system or somewhere on # the network. # Uncomment the following line to define AVC_IGNORE_RMDIR_ERROR at compile # time if you want this error to be ignored. # # OPTFLAGS := $(OPTFLAGS) -DAVC_IGNORE_RMDIR_ERROR # # Due to the odd way that fields of type 40 are handled in E00, you will # start to lose some digits of precision with fields bigger than 8 digits when # exporting to E00. Define AVC_MAP_TYPE40_TO_DOUBLE to ask the AVC lib to # automatically remap fields of type 40 bigger than 8 digits to double # precision floats while writing E00. Double precision floats can carry up # to 18 digits of precision. # OPTFLAGS := $(OPTFLAGS) -DAVC_MAP_TYPE40_TO_DOUBLE # # # CFLAGS= $(BYTE_ORDER_FL) $(OPTFLAGS) -g -Wall -DDEBUG LFLAGS= AR= ar LIB_OBJS= avc_e00read.o avc_e00write.o avc_rawbin.o avc_bin.o avc_binwr.o \ avc_e00gen.o avc_e00parse.o avc_misc.o \ cpl_error.o cpl_conv.o cpl_vsisimple.o cpl_string.o cpl_dir.o \ avc_mbyte.o dbfopen.o LIB= avc.a default: $(LIB) avcimport avcexport avcdelete avctest ex_avcwrite $(LIB_OBJS): avc.h avc_mbyte.h cpl_error.h cpl_port.h cpl_conv.h \ cpl_vsi.h cpl_string.h avcimport: avcimport.o $(LIB) avc.h $(CC) $(LFLAGS) -o avcimport avcimport.o $(LIB) avcexport: avcexport.o $(LIB) avc.h $(CC) $(LFLAGS) -o avcexport avcexport.o $(LIB) avcdelete: avcdelete.o $(LIB) avc.h $(CC) $(LFLAGS) -o avcdelete avcdelete.o $(LIB) avctest: avctest.o $(LIB) avc.h $(CC) $(LFLAGS) -o avctest avctest.o $(LIB) ex_avcwrite: ex_avcwrite.o $(LIB) avc.h $(CC) $(LFLAGS) -o ex_avcwrite ex_avcwrite.o $(LIB) $(LIB_DBMALLOC) testmulti: testmulti.o $(LIB) avc.h $(CC) $(LFLAGS) -o testmulti testmulti.o $(LIB) $(LIB_DBMALLOC) %.o: %.c $(CC) -c $(CFLAGS) $*.c -o $*.o %.o: %.cpp $(CC) -c $(CFLAGS) $*.cpp -o $*.o $(LIB): $(LIB_OBJS) rm -f $(LIB) $(AR) rc $(LIB) $(LIB_OBJS) clean: rm -f $(LIB) $(LIB_OBJS) rm -f avctest.o avctest avcexport.o avcexport avcimport.o avcimport \ ex_avcwrite ex_avcwrite.o avcdelete.o avcdelete avce00-2.0.0/dbf_api.html0100664000076400007640000003003007030616774014334 0ustar danieldaniel Attribute (.DBF) API

Attribute (.DBF) API

The Attribute (DBF) API uses DBFHandle to represent a handle for access to one .dbf file. The contents of the DBFHandle are visible (see shapefil.h) but should be ignored by the application. It is intended that all information be accessed by API functions. Note that there should be exactly one record in the .dbf file for each shape in the .shp/.shx files. This constraint must be maintained by the application.

DBFOpen()

DBFHandle DBFOpen( const char * pszDBFFile, const char * pszAccess );

  pszDBFFile:		The name of the xBase (.dbf) file to access.

  pszAccess:		The fopen() style access string.  At this time only
			"rb" (read-only binary) and "rb+" (read/write binary) 
		        should be used.
The DBFOpen() function should be used to establish access to an existing xBase format table file. The returned DBFHandle is passed to other access functions, and DBFClose() should be invoked to recover resources, and flush changes to disk when complete. The DBFCreate() function should called to create new xBase files. As a convenience, DBFOpen() can be called with the name of a .shp or .shx file, and it will figure out the name of the related .dbf file.

DBFCreate()

DBFHandle DBFCreate( const char * pszDBFFile );

  pszDBFFile:		The name of the xBase (.dbf) file to create.
The DBFCreate() function creates a new xBase format file with the given name, and returns an access handle that can be used with other DBF functions. The newly created file will have no fields, and no records. Fields should be added with DBFAddField() before any records add written.

DBFGetFieldCount()

int DBFGetFieldCount( DBFHandle hDBF );

  hDBF:		The access handle for the file to be queried, as returned
                by DBFOpen(), or DBFCreate().
The DBFGetFieldCount() function returns the number of fields currently defined for the indicated xBase file.

DBFGetRecordCount()

int DBFGetRecordCount( DBFHandle hDBF );

  hDBF:		The access handle for the file to be queried, as returned by
		DBFOpen(), or DBFCreate().
The DBFGetRecordCount() function returns the number of records that exist on the xBase file currently. Note that with shape files one xBase record exists for each shape in the .shp/.shx files.

DBFGetFieldInfo()

DBFFieldType DBFGetFieldInfo( DBFHandle hDBF, int iField, char * pszFieldName,
                              int * pnWidth, int * pnDecimals );

  hDBF:		The access handle for the file to be queried, as returned by
		DBFOpen(), or DBFCreate().

  iField:	The field to be queried.  This should be a number between 
                0 and n-1, where n is the number fields on the file, as
                returned by DBFGetFieldCount().

  pszFieldName:	If this pointer is not NULL the name of the requested field
		will be written to this location.  The pszFieldName buffer 
                should be at least 12 character is size in order to hold
		the longest possible field name of 11 characters plus a 
                terminating zero character.

  pnWidth:	If this pointer is not NULL, the width of the requested field
		will be returned in the int pointed to by pnWidth.  This is
                the width in characters.  

  pnDecimals:	If this pointer is not NULL, the number of decimal places
                precision defined for the field will be returned.  This is
                zero for integer fields, or non-numeric fields.
The DBFGetFieldInfo() returns the type of the requested field, which is one of the DBFFieldType enumerated values. As well, the field name, and field width information can optionally be returned. The field type returned does not correspond one to one with the xBase field types. For instance the xBase field type for Date will just be returned as being FTInteger.

    typedef enum {
      FTString,			/* fixed length string field 		*/
      FTInteger,		/* numeric field with no decimals 	*/
      FTDouble,			/* numeric field with decimals 		*/
      FTInvalid                 /* not a recognised field type 		*/
    } DBFFieldType;

DBFAddField()

int DBFAddField( DBFHandle hDBF, const char * pszFieldName, 
                 DBFFieldType eType, int nWidth, int nDecimals );

  hDBF:		The access handle for the file to be updated, as returned by
		DBFOpen(), or DBFCreate().

  pszFieldName:	The name of the new field.  At most 11 character will be used.
                In order to use the xBase file in some packages it may be
                necessary to avoid some special characters in the field names
                such as spaces, or arithmetic operators.

  eType:	One of FTString, FTInteger or FTDouble in order to establish
                the type of the new field.  Note that some valid xBase field
                types cannot be created such as date fields.

  nWidth:	The width of the field to be created.  For FTString fields this
                establishes the maximum length of string that can be stored.
                For FTInteger this establishes the largest number that can
                be represented.  For FTDouble fields this in combination
                with the nDecimals value establish the size, and precision
                of the created field.

  nDecimals:    The number of decimal places to reserve for FTDouble fields.
                For all other field types this should be zero.  For instance
                with nWidth=7, and nDecimals=3 numbers would be formatted
                similarly to `123.456'.
The DBFAddField() function is used to add new fields to an existing xBase file opened with DBFOpen(), or created with DBFCreate(). Note that fields can only be added to xBase files with no records, though this is limitation of this API, not of the file format.

The DBFAddField() return value is the field number of the new field, or -1 if the addition of the field failed.

DBFReadIntegerAttribute()

int DBFReadIntegerAttribute( DBFHandle hDBF, int iShape, int iField );
  
  hDBF:		The access handle for the file to be queried, as returned by
		DBFOpen(), or DBFCreate().

  iShape:	The record number (shape number) from which the field value
                should be read.

  iField:	The field within the selected record that should be read.
The DBFReadIntegerAttribute() will read the value of one field and return it as an integer. This can be used even with FTString fields, though the returned value will be zero if not interpretable as a number.

DBFReadDoubleAttribute()

double DBFReadDoubleAttribute( DBFHandle hDBF, int iShape, int iField );
  
  hDBF:		The access handle for the file to be queried, as returned by
		DBFOpen(), or DBFCreate().

  iShape:	The record number (shape number) from which the field value
                should be read.

  iField:	The field within the selected record that should be read.
The DBFReadDoubleAttribute() will read the value of one field and return it as a double. This can be used even with FTString fields, though the returned value will be zero if not interpretable as a number.

DBFReadStringAttribute()

const char *DBFReadStringAttribute( DBFHandle hDBF, int iShape, int iField );
  
  hDBF:		The access handle for the file to be queried, as returned by
		DBFOpen(), or DBFCreate().

  iShape:	The record number (shape number) from which the field value
                should be read.

  iField:	The field within the selected record that should be read.
The DBFReadStringAttribute() will read the value of one field and return it as a string. This function may be used on any field type (including FTInteger and FTDouble) and will return the string representation stored in the .dbf file. The returned pointer is to an internal buffer which is only valid untill the next DBF function call. It's contents may be copied with normal string functions such as strcpy(), or strdup(). If the TRIM_DBF_WHITESPACE macro is defined in shapefil.h (it is by default) then all leading and trailing space (ASCII 32) characters will be stripped before the string is returned.

DBFWriteIntegerAttribute

int DBFWriteIntegerAttribute( DBFHandle hDBF, int iShape, int iField,
                              int nFieldValue );

  hDBF:		The access handle for the file to be written, as returned by
		DBFOpen(), or DBFCreate().

  iShape:	The record number (shape number) to which the field value
                should be written.

  iField:	The field within the selected record that should be written.

  nFieldValue:	The integer value that should be written.
The DBFWriteIntegerAttribute() function is used to write a value to a numeric field (FTInteger, or FTDouble). If the write succeeds the value TRUE will be returned, otherwise FALSE will be returned. The value may be truncated without warning if written to a field to narrow to represent the value.

DBFWriteDoubleAttribute()

int DBFWriteDoubleAttribute( DBFHandle hDBF, int iShape, int iField,
                             double dFieldValue );

  hDBF:		The access handle for the file to be written, as returned by
		DBFOpen(), or DBFCreate().

  iShape:	The record number (shape number) to which the field value
                should be written.

  iField:	The field within the selected record that should be written.

  dFieldValue:	The floating point value that should be written.
The DBFWriteDoubleAttribute() function is used to write a value to a numeric field (FTInteger, or FTDouble). If the write succeeds the value TRUE will be returned, otherwise FALSE will be returned. The value may be truncated without warning if written to a field to narrow to represent the value.

DBFWriteStringAttribute()

int DBFWriteStringAttribute( DBFHandle hDBF, int iShape, int iField,
                             const char * pszFieldValue );

  hDBF:		The access handle for the file to be written, as returned by
		DBFOpen(), or DBFCreate().

  iShape:	The record number (shape number) to which the field value
                should be written.

  iField:	The field within the selected record that should be written.

  pszFieldValue: The string to be written to the field.
The DBFWriteStringAttribute() function is used to write a value to a string field (FString). If the write succeeds the value TRUE willbe returned, otherwise FALSE will be returned. The value may be truncated without warning if written to a field to narrow to hold the string.

DBFClose()

void DBFClose( DBFHandle hDBF );

  hDBF:		The access handle for the file to be closed.
The DBFClose() function will close the indicated xBase file (opened with DBFOpen(), or DBFCreate()), flushing out all information to the file on disk, and recovering any resources associated with having the file open. The file handle (hDBF) should not be used again with the DBF API after calling DBFClose().

avce00-2.0.0/avc_mbyte.c0100664000076400007640000004313110247751547014207 0ustar danieldaniel/* $Id: avc_mbyte.c,v 1.3 2005/06/03 03:49:59 daniel Exp $ * * Name: avc_mbyte.c * Project: Arc/Info vector coverage (AVC) E00->BIN conversion library * Language: ANSI C * Purpose: Functions to handle multibyte character conversions. * Author: Daniel Morissette, dmorissette@dmsolutions.ca * ********************************************************************** * Copyright (c) 1999-2005, Daniel Morissette * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ********************************************************************** * * $Log: avc_mbyte.c,v $ * Revision 1.3 2005/06/03 03:49:59 daniel * Update email address, website url, and copyright dates * * Revision 1.2 2000/09/22 19:45:21 daniel * Switch to MIT-style license * * Revision 1.1 2000/05/29 15:31:03 daniel * Initial revision - Japanese support * **********************************************************************/ #include "avc.h" #ifdef _WIN32 # include #endif static int _AVCDetectJapaneseEncoding(const unsigned char *pszLine); static const char *_AVCJapanese2ArcDBCS(AVCDBCSInfo *psDBCSInfo, const unsigned char *pszLine, int nMaxOutputLen); static const char *_AVCArcDBCS2JapaneseShiftJIS(AVCDBCSInfo *psDBCSInfo, const unsigned char *pszLine, int nMaxOutputLen); /*===================================================================== * Functions to handle multibyte char conversions *====================================================================*/ #define IS_ASCII(c) ((c) < 0x80) /********************************************************************** * AVCAllocDBCSInfo() * * Alloc and init a new AVCDBCSInfo structure. **********************************************************************/ AVCDBCSInfo *AVCAllocDBCSInfo() { AVCDBCSInfo *psInfo; psInfo = (AVCDBCSInfo*)CPLCalloc(1, sizeof(AVCDBCSInfo)); psInfo->nDBCSCodePage = AVCGetDBCSCodePage(); psInfo->nDBCSEncoding = AVC_CODE_UNKNOWN; psInfo->pszDBCSBuf = NULL; psInfo->nDBCSBufSize = 0; return psInfo; } /********************************************************************** * AVCFreeDBCSInfo() * * Release all memory associated with a AVCDBCSInfo structure. **********************************************************************/ void AVCFreeDBCSInfo(AVCDBCSInfo *psInfo) { if (psInfo) { CPLFree(psInfo->pszDBCSBuf); CPLFree(psInfo); } } /********************************************************************** * AVCGetDBCSCodePage() * * Fetch current multibyte codepage on the system. * Returns a valid codepage number, or 0 if the codepage is single byte or * unsupported. **********************************************************************/ int AVCGetDBCSCodePage() { #ifdef _WIN32 int nCP; nCP = _getmbcp(); /* Check if that's a supported codepage */ if (nCP == AVC_DBCS_JAPANESE) return nCP; #endif return 0; } /********************************************************************** * AVCE00DetectEncoding() * * Try to detect the encoding used in the current file by examining lines * of input. * * Returns TRUE once the encoding is established, or FALSE if more lines * of input are required to establish the encoding. **********************************************************************/ GBool AVCE00DetectEncoding(AVCDBCSInfo *psDBCSInfo, const char *pszLine) { if (psDBCSInfo == NULL || psDBCSInfo->nDBCSCodePage == 0 || psDBCSInfo->nDBCSEncoding != AVC_CODE_UNKNOWN) { /* Either single byte codepage, or encoding has already been detected */ return TRUE; } switch (psDBCSInfo->nDBCSCodePage) { case AVC_DBCS_JAPANESE: psDBCSInfo->nDBCSEncoding = _AVCDetectJapaneseEncoding((const unsigned char *)pszLine); break; default: psDBCSInfo->nDBCSEncoding = AVC_CODE_UNKNOWN; return TRUE; /* Codepage not supported... no need to scan more lines*/ } if (psDBCSInfo->nDBCSEncoding != AVC_CODE_UNKNOWN) return TRUE; /* We detected the encoding! */ return FALSE; } /********************************************************************** * AVCE00Convert2ArcDBCS() * * If encoding is still unknown, try to detect the encoding used in the * current file, and then convert the string to an encoding validfor output * to a coverage. * * Returns a reference to a const buffer that should not be freed by the * caller. It can be either the original string buffer or a ref. to an * internal buffer. **********************************************************************/ const char *AVCE00Convert2ArcDBCS(AVCDBCSInfo *psDBCSInfo, const char *pszLine, int nMaxOutputLen) { const char *pszOutBuf = NULL; unsigned char *pszTmp; GBool bAllAscii; if (psDBCSInfo == NULL || psDBCSInfo->nDBCSCodePage == 0 || pszLine == NULL) { /* Single byte codepage... nothing to do */ return pszLine; } /* If string is all ASCII then there is nothing to do... */ pszTmp = (unsigned char *)pszLine; for(bAllAscii = TRUE ; bAllAscii && pszTmp && *pszTmp; pszTmp++) { if ( !IS_ASCII(*pszTmp) ) bAllAscii = FALSE; } if (bAllAscii) return pszLine; /* Make sure output buffer is large enough. * We add 2 chars to buffer size to simplify processing... no need to * check if second byte of a pair would overflow buffer. */ if (psDBCSInfo->pszDBCSBuf == NULL || psDBCSInfo->nDBCSBufSize < nMaxOutputLen+2) { psDBCSInfo->nDBCSBufSize = nMaxOutputLen+2; psDBCSInfo->pszDBCSBuf = (unsigned char *)CPLRealloc(psDBCSInfo->pszDBCSBuf, psDBCSInfo->nDBCSBufSize* sizeof(unsigned char)); } /* Do the conversion according to current code page */ switch (psDBCSInfo->nDBCSCodePage) { case AVC_DBCS_JAPANESE: pszOutBuf = (char*)_AVCJapanese2ArcDBCS(psDBCSInfo, (const unsigned char *)pszLine, nMaxOutputLen); break; default: /* We should never get here anyways, but just in case return pszLine */ pszOutBuf = pszLine; } return pszOutBuf; } /********************************************************************** * AVCE00ConvertFromArcDBCS() * * Convert DBCS encoding in binary coverage files to E00 encoding. * * Returns a reference to a const buffer that should not be freed by the * caller. It can be either the original string buffer or a ref. to an * internal buffer. **********************************************************************/ const char *AVCE00ConvertFromArcDBCS(AVCDBCSInfo *psDBCSInfo, const char *pszLine, int nMaxOutputLen) { const char *pszOutBuf = NULL; unsigned char *pszTmp; GBool bAllAscii; if (psDBCSInfo == NULL || psDBCSInfo->nDBCSCodePage == 0 || pszLine == NULL) { /* Single byte codepage... nothing to do */ return pszLine; } /* If string is all ASCII then there is nothing to do... */ pszTmp = (unsigned char *)pszLine; for(bAllAscii = TRUE ; bAllAscii && pszTmp && *pszTmp; pszTmp++) { if ( !IS_ASCII(*pszTmp) ) bAllAscii = FALSE; } if (bAllAscii) return pszLine; /* Make sure output buffer is large enough. * We add 2 chars to buffer size to simplify processing... no need to * check if second byte of a pair would overflow buffer. */ if (psDBCSInfo->pszDBCSBuf == NULL || psDBCSInfo->nDBCSBufSize < nMaxOutputLen+2) { psDBCSInfo->nDBCSBufSize = nMaxOutputLen+2; psDBCSInfo->pszDBCSBuf = (unsigned char *)CPLRealloc(psDBCSInfo->pszDBCSBuf, psDBCSInfo->nDBCSBufSize* sizeof(unsigned char)); } /* Do the conversion according to current code page */ switch (psDBCSInfo->nDBCSCodePage) { case AVC_DBCS_JAPANESE: pszOutBuf = (char*)_AVCArcDBCS2JapaneseShiftJIS(psDBCSInfo, (const unsigned char *)pszLine, nMaxOutputLen); break; default: /* We should never get here anyways, but just in case return pszLine */ pszOutBuf = pszLine; } return pszOutBuf; } /*===================================================================== *===================================================================== * Functions Specific to Japanese encoding (CodePage 932). * * For now we assume that we can receive only Katakana, Shift-JIS, or EUC * encoding as input. Coverages use EUC encoding in most cases, except * for Katakana characters that are prefixed with a 0x8e byte. * * Most of the Japanese conversion functions are based on information and * algorithms found at: * http://www.mars.dti.ne.jp/~torao/program/appendix/japanese-en.html *===================================================================== *====================================================================*/ /********************************************************************** * _AVCDetectJapaneseEncoding() * * Scan a line of text to try to establish the type of japanese encoding * * Returns the encoding number (AVC_CODE_JAP_*), or AVC_CODE_UNKNOWN if no * specific encoding was detected. **********************************************************************/ #define IS_JAP_SHIFTJIS_1(c) ((c) >= 0x81 && (c) <= 0x9f) #define IS_JAP_SHIFTJIS_2(c) (((c) >= 0x40 && (c) <= 0x7e) || \ ((c) >= 0x80 && (c) <= 0xA0) ) #define IS_JAP_EUC_1(c) ((c) >= 0xF0 && (c) <= 0xFE) #define IS_JAP_EUC_2(c) ((c) >= 0xFD && (c) <= 0xFE) #define IS_JAP_KANA(c) ((c) >= 0xA1 && (c) <= 0xDF) static int _AVCDetectJapaneseEncoding(const unsigned char *pszLine) { int nEncoding = AVC_CODE_UNKNOWN; for( ; nEncoding == AVC_CODE_UNKNOWN && pszLine && *pszLine; pszLine++) { if (IS_ASCII(*pszLine)) continue; else if (IS_JAP_SHIFTJIS_1(*pszLine)) { nEncoding = AVC_CODE_JAP_SHIFTJIS; break; } else if (IS_JAP_KANA(*pszLine) && *(pszLine+1) && (IS_ASCII(*(pszLine+1)) || (*(pszLine+1)>=0x80 && *(pszLine+1)<=0xA0) ) ) { nEncoding = AVC_CODE_JAP_SHIFTJIS; /* SHIFT-JIS + Kana */ break; } else if (IS_JAP_EUC_1(*pszLine)) { nEncoding = AVC_CODE_JAP_EUC; break; } if (*(++pszLine) == '\0') break; if (IS_JAP_SHIFTJIS_2(*pszLine)) { nEncoding = AVC_CODE_JAP_SHIFTJIS; break; } else if (IS_JAP_EUC_2(*pszLine)) { nEncoding = AVC_CODE_JAP_EUC; break; } } return nEncoding; } /********************************************************************** * _AVCJapanese2ArcDBCS() * * Try to detect type of Japanese encoding if not done yet, and convert * string from Japanese to proper coverage DBCS encoding. **********************************************************************/ static const char *_AVCJapanese2ArcDBCS(AVCDBCSInfo *psDBCSInfo, const unsigned char *pszLine, int nMaxOutputLen) { unsigned char *pszOut; int iDst; pszOut = psDBCSInfo->pszDBCSBuf; if (psDBCSInfo->nDBCSEncoding == AVC_CODE_UNKNOWN) { /* Type of encoding (Shift-JIS or EUC) not known yet... try to * detect it now. */ psDBCSInfo->nDBCSEncoding = _AVCDetectJapaneseEncoding(pszLine); /* if (psDBCSInfo->nDBCSEncoding == AVC_CODE_JAP_SHIFTJIS) { printf("Found Japanese Shift-JIS encoding\n"); } else if (psDBCSInfo->nDBCSEncoding == AVC_CODE_JAP_EUC) { printf("Found Japanese EUC encoding\n"); } */ } for(iDst=0; *pszLine && iDst < nMaxOutputLen; pszLine++) { if (IS_ASCII(*pszLine)) { /* No transformation required for ASCII */ pszOut[iDst++] = *pszLine; } else if ( psDBCSInfo->nDBCSEncoding==AVC_CODE_JAP_EUC && *(pszLine+1) ) { /* This must be a pair of EUC chars and both should be in * the range 0xA1-0xFE */ pszOut[iDst++] = *(pszLine++); pszOut[iDst++] = *pszLine; } else if ( IS_JAP_KANA(*pszLine) ) { /* Katakana char. prefix it with 0x8e */ pszOut[iDst++] = 0x8e; pszOut[iDst++] = *pszLine; } else if ( *(pszLine+1) ) { /* This must be a pair of Shift-JIS chars... convert them to EUC * * If we haven't been able to establish the encoding for sure * yet, then it is possible that a pair of EUC chars could be * treated as shift-JIS here... but there is not much we can do * about that unless we scan the whole E00 input before we * start the conversion. */ unsigned char leader, trailer; leader = *(pszLine++); trailer = *pszLine; if(leader <= 0x9F) leader -= 0x71; else leader -= 0xB1; leader = (leader << 1) + 1; if(trailer > 0x7F) trailer --; if(trailer >= 0x9E) { trailer -= 0x7D; leader ++; } else { trailer -= 0x1F; } pszOut[iDst++] = leader | 0x80; pszOut[iDst++] = trailer | 0x80; } else { /* We should never get here unless a double-byte pair was * truncated... but just in case... */ pszOut[iDst++] = *pszLine; } } pszOut[iDst] = '\0'; return psDBCSInfo->pszDBCSBuf; } /********************************************************************** * _AVCArcDBCS2JapaneseShiftJIS() * * Convert string from coverage DBCS (EUC) to Japanese Shift-JIS. * * We know that binary coverages use a custom EUC encoding for japanese * which is EUC + all Katakana chars are prefixed with 0x8e. So this * function just does a simple conversion. **********************************************************************/ static const char *_AVCArcDBCS2JapaneseShiftJIS(AVCDBCSInfo *psDBCSInfo, const unsigned char *pszLine, int nMaxOutputLen) { unsigned char *pszOut; int iDst; pszOut = psDBCSInfo->pszDBCSBuf; for(iDst=0; *pszLine && iDst < nMaxOutputLen; pszLine++) { if (IS_ASCII(*pszLine)) { /* No transformation required for ASCII */ pszOut[iDst++] = *pszLine; } else if (*pszLine == 0x8e && *(pszLine+1)) { pszLine++; /* Flush the 0x8e */ pszOut[iDst++] = *pszLine; } else if (*(pszLine+1)) { /* This is a pair of EUC chars... convert them to Shift-JIS */ unsigned char leader, trailer; leader = *(pszLine++) & 0x7F; trailer = *pszLine & 0x7F; if((leader & 0x01) != 0) trailer += 0x1F; else trailer += 0x7D; if(trailer >= 0x7F) trailer ++; leader = ((leader - 0x21) >> 1) + 0x81; if(leader > 0x9F) leader += 0x40; pszOut[iDst++] = leader; pszOut[iDst++] = trailer; } else { /* We should never get here unless a double-byte pair was * truncated... but just in case... */ pszOut[iDst++] = *pszLine; } } pszOut[iDst] = '\0'; return psDBCSInfo->pszDBCSBuf; } avce00-2.0.0/avctest.c0100664000076400007640000007642710247751547013725 0ustar danieldaniel/********************************************************************** * $Id: avctest.c,v 1.13 2005/06/03 03:49:59 daniel Exp $ * * Name: avctest.c * Project: Arc/Info Vector coverage (AVC) BIN->E00 conversion library * Language: ANSI C * Purpose: Test various part of the lib., and generate binary dumps. * Author: Daniel Morissette, dmorissette@dmsolutions.ca * ********************************************************************** * Copyright (c) 1999-2005, Daniel Morissette * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ********************************************************************** * * $Log: avctest.c,v $ * Revision 1.13 2005/06/03 03:49:59 daniel * Update email address, website url, and copyright dates * * Revision 1.12 2000/10/17 19:46:49 daniel * Added DumpSqueleton() * * Revision 1.11 2000/09/26 20:21:05 daniel * Added AVCCoverPC write * * Revision 1.10 2000/09/22 19:45:21 daniel * Switch to MIT-style license * * Revision 1.9 2000/06/05 21:40:07 daniel * Use 1000 instead of 255 as threshold to mean double prec. in file header * * Revision 1.8 2000/06/05 21:36:12 daniel * Handle precision field > 255 in cover file header as meaning double prec. * * Revision 1.7 2000/05/29 15:31:31 daniel * Added Japanese DBCS support * * Revision 1.6 2000/01/10 03:00:15 daniel * Added support to dump "arcdr9" files * * Revision 1.5 1999/12/24 07:18:34 daniel * Added PC Arc/Info coverages support * * Revision 1.4 1999/05/17 16:25:44 daniel * Detect .pal (RPL) files and handle them as PAL files * * Revision 1.3 1999/05/11 02:13:49 daniel * Added tests for some write functions and made major changes to * command-line args. * * Revision 1.2 1999/02/25 03:38:36 daniel * Modified bin. dump to include doubles, and added TXT/TX6 test functions * **********************************************************************/ #include "avc.h" /* Prototypes for some internal functions not included in the lib * headers but that we want to test in this program. */ int _AVCBinReadHeader(AVCRawBinFile *psFile, AVCBinHeader *psHdr); int _AVCBinReadNextArc(AVCRawBinFile *psFile, AVCArc *psArc, int nPrecision); int _AVCBinReadNextPal(AVCRawBinFile *psFile, AVCPal *psPal, int nPrecision); int _AVCBinReadNextCnt(AVCRawBinFile *psFile, AVCCnt *psCnt, int nPrecision); int _AVCBinReadNextLab(AVCRawBinFile *psFile, AVCLab *psLab, int nPrecision); int _AVCBinReadNextTxt(AVCRawBinFile *psFile, AVCTxt *psTxt, int nPrecision); int _AVCBinReadNextArcDir(AVCRawBinFile *psInfo, AVCTableDef *psArcDir); int _AVCBinReadNextArcNit(AVCRawBinFile *psInfo, AVCFieldInfo *psField); #include static int DumpHeader(AVCRawBinFile *hFile); static void DumpArcFile(AVCRawBinFile *hFile); static void DumpPalFile(AVCRawBinFile *psFile); static void DumpCntFile(AVCRawBinFile *psFile); static void DumpLabFile(AVCRawBinFile *psFile); static void DumpTxtFile(AVCRawBinFile *psFile); static void DumpArcDirFile(AVCRawBinFile *psFile); static void DumpArcNitFile(AVCRawBinFile *psFile); static void DumpBytes(AVCRawBinFile *psFile); static void ConvertArcFile(AVCRawBinFile *psFile); static void ConvertPalFile(AVCRawBinFile *psFile); static void ConvertCntFile(AVCRawBinFile *psFile); static void ConvertLabFile(AVCRawBinFile *psFile); static void ConvertTxtFile(AVCRawBinFile *psFile, AVCFileType eType, const char *pszFilename); static void ConvertCover(const char *pszFname); static void ConvertAATOnly(const char *pszFname); static void DumpSqueleton(const char *pszFname); static void DupBinFile(const char *pszSrcFile, const char *pszDstFile); #define AVCTEST_USAGE "Usage: avctest -b|-bindump \n" \ "or avctest -e|-e00dump \n" \ "or avctest -c|-cov2e00 \n" \ "or avctest -a|-aatonly \n" \ "or avctest -s|-squeleton \n" \ "or avctest -d|-dupfile \n" /********************************************************************** * main() * * This program is used to dump binary files (default behavior), and to * test some parts of the lib. during the development process. **********************************************************************/ int main(int argc, char *argv[]) { const char *pszFname; AVCRawBinFile *hFile; /*--------------------------------------------------------------------- * Read program arguments. *--------------------------------------------------------------------*/ if (argc<2) { printf("%s", AVCTEST_USAGE); return 1; } else { pszFname = argv[2]; } if (EQUALN(argv[1], "-cov2e00", 2)) { /*--------------------------------------------------------------------- * With option -c ... * convert the whole coverage to E00 *--------------------------------------------------------------------*/ ConvertCover(pszFname); } else if (EQUALN(argv[1], "-aatonly", 2)) { /*--------------------------------------------------------------------- * With option -aatonly ... * use AVCE00ReadGotoSection() to read only the .AAT table if there * is one. *--------------------------------------------------------------------*/ ConvertAATOnly(pszFname); } else if (EQUALN(argv[1], "-squeleton", 2)) { /*--------------------------------------------------------------------- * With option -squeleton ... * Dump the squeleton of the coverage. *--------------------------------------------------------------------*/ DumpSqueleton(pszFname); } /*--------------------------------------------------------------------- * With option -bindump * Open file, and dump binary contents. *--------------------------------------------------------------------*/ else if (EQUALN(argv[1], "-bindump", 2) && (hFile = AVCRawBinOpen(pszFname, "r", AVC_COVER_BYTE_ORDER(AVCCoverV7), NULL ))!=NULL) { DumpBytes(hFile); AVCRawBinClose(hFile); } /*--------------------------------------------------------------------- * With option -e00dump * Open file, and dump its contents in E00 format. * If file name is not recognized, then the binary contents is returned. *--------------------------------------------------------------------*/ else if (EQUALN(argv[1], "-e00dump", 2) && (hFile = AVCRawBinOpen(pszFname, "r", AVC_COVER_BYTE_ORDER(AVCCoverV7), NULL ))!=NULL) { if (strstr(pszFname, "arc.adf") != NULL) ConvertArcFile(hFile); /* DumpArcFile(hFile);*/ else if (strstr(pszFname, "pal.adf") != NULL || strstr(pszFname, ".pal") != NULL ) ConvertPalFile(hFile); /* DumpPalFile(hFile);*/ else if (strstr(pszFname, "cnt.adf") != NULL) ConvertCntFile(hFile); /* DumpCntFile(hFile);*/ else if (strstr(pszFname, "lab.adf") != NULL) ConvertLabFile(hFile); /* DumpLabFile(hFile);*/ else if (strstr(pszFname, "txt.adf") != NULL) ConvertTxtFile(hFile, AVCFileTXT, pszFname); else if (strstr(pszFname, ".txt") != NULL ) ConvertTxtFile(hFile, AVCFileTX6, pszFname); else if (strstr(pszFname, "arc.dir") != NULL || strstr(pszFname, "ARCDR9") != NULL || strstr(pszFname, "arcdr9") != NULL) DumpArcDirFile(hFile); else if (strstr(pszFname, ".nit") != NULL) DumpArcNitFile(hFile); else DumpBytes(hFile); AVCRawBinClose(hFile); } /*--------------------------------------------------------------------- * avctest -dupfile * * Read specified binary file, and write it back to a new file. *--------------------------------------------------------------------*/ else if (argc==4 && EQUALN(argv[1], "-dupfile", 2)) { DupBinFile(argv[2], argv[3]); } else if (argc==3 && EQUALN(argv[1], "-testfname", 5)) { char *pszFname; pszFname = CPLStrdup(argv[2]); AVCAdjustCaseSensitiveFilename(pszFname); printf(" \"%s\"\n -> \"%s\"\n\n", argv[2], pszFname); CPLFree(pszFname); } else { printf("Cannot process file %s\n\n", pszFname); printf("%s", AVCTEST_USAGE); return 1; } return 0; } /********************************************************************** * DumpHeader() * * Read and dump the header contents. * * Returns the coverage precision: AVC_SINGLE/DOUBLE_PREC **********************************************************************/ static int DumpHeader(AVCRawBinFile *hFile) { AVCBinHeader sHdr; int nStatus; nStatus = _AVCBinReadHeader(hFile, &sHdr); if (nStatus == 0) { printf("\nFile Header:\n"); printf(" Signature: 0x%8.8x (%d)\n", sHdr.nSignature, sHdr.nSignature); printf(" Precision: 0x%8.8x (%d)\n", sHdr.nPrecision, sHdr.nPrecision); printf(" Length: 0x%8.8x (%d)\n", sHdr.nLength, sHdr.nLength); printf("\n"); } if (sHdr.nPrecision < 0 || sHdr.nPrecision > 1000) return AVC_DOUBLE_PREC; else return AVC_SINGLE_PREC; } /********************************************************************** * DumpArcFile() * * Read and dump the contents of an arc.adf file. **********************************************************************/ static void DumpArcFile(AVCRawBinFile *psFile) { AVCArc sArc; int i, nPrec; sArc.pasVertices = NULL; sArc.numVertices = 0; nPrec = DumpHeader(psFile); while(!AVCRawBinEOF(psFile)) { _AVCBinReadNextArc(psFile, &sArc, nPrec); printf("%d %d %d %d %d %d %d\n", sArc.nArcId, sArc.nUserId, sArc.nFNode, sArc.nTNode, sArc.nLPoly, sArc.nRPoly, sArc.numVertices); for(i=0; i 10) printf("..."); printf("\n"); } } /********************************************************************** * DumpLabFile() * * Read and dump the contents of an lab.adf file. **********************************************************************/ static void DumpLabFile(AVCRawBinFile *psFile) { AVCLab sLab; int nPrec; nPrec = DumpHeader(psFile); while(!AVCRawBinEOF(psFile)) { _AVCBinReadNextLab(psFile, &sLab, nPrec); printf("%d %d %e %e\n", sLab.nValue, sLab.nPolyId, sLab.sCoord1.x, sLab.sCoord1.y); printf("%e %e %e %e\n", sLab.sCoord2.x, sLab.sCoord2.y, sLab.sCoord3.x, sLab.sCoord3.y); } } /********************************************************************** * DumpTxtFile() * * Read and dump the contents of a txt.adf file. **********************************************************************/ static void DumpTxtFile(AVCRawBinFile *psFile) { AVCTxt sTxt; int i, nPrec, numVerticesTotal; sTxt.numVerticesLine = sTxt.numVerticesArrow = 0; sTxt.pasVertices = NULL; sTxt.numChars = 0; sTxt.pszText = NULL; nPrec = DumpHeader(psFile); while(!AVCRawBinEOF(psFile)) { _AVCBinReadNextTxt(psFile, &sTxt, nPrec); printf("(%d) %d %d %d %d %d %d %d (0!)\n", sTxt.nTxtId, sTxt.nUserId, sTxt.nLevel, sTxt.numVerticesLine, sTxt.numVerticesArrow, sTxt.nSymbol, sTxt.n28, sTxt.numChars ); printf("Just = %d / %d\n", sTxt.anJust2[0], sTxt.anJust1[0]); printf("%e\n", sTxt.f_1e2); printf("%e %e %e\n", sTxt.dHeight, sTxt.dV2, sTxt.dV3); numVerticesTotal = ABS(sTxt.numVerticesLine) + ABS(sTxt.numVerticesArrow); for(i=0; inPrecision, NULL)) == NULL) { AVCBinReadClose(psSrc); return; } /*----------------------------------------------------------------- * Copy objects *----------------------------------------------------------------*/ while((psObj = AVCBinReadNextObject(psSrc)) != NULL) { switch(eType) { case AVCFileARC: AVCBinWriteArc(psDst, (AVCArc*)psObj); break; case AVCFilePAL: AVCBinWritePal(psDst, (AVCPal*)psObj); break; case AVCFileCNT: AVCBinWriteCnt(psDst, (AVCCnt*)psObj); break; case AVCFileLAB: AVCBinWriteLab(psDst, (AVCLab*)psObj); break; case AVCFileTOL: AVCBinWriteTol(psDst, (AVCTol*)psObj); break; default: CPLError(CE_Failure, CPLE_NotSupported, "Support for this file type is not implemented yet."); AVCBinReadClose(psSrc); AVCBinWriteClose(psDst); return ; } } /*----------------------------------------------------------------- * Close files, cleanup and exit. *----------------------------------------------------------------*/ AVCBinReadClose(psSrc); AVCBinWriteClose(psDst); } /********************************************************************** * DumpSqueleton() * * Read and dump the coverage squeleton. **********************************************************************/ static void DumpSqueleton(const char *pszFname) { AVCE00ReadPtr psReadInfo; int i; psReadInfo = AVCE00ReadOpen(pszFname); if (psReadInfo) { for(i=0; inumSections; i++) { AVCE00Section *psSec; psSec = &(psReadInfo->pasSections[i]); printf(" %2d - (%s)\t%s\t%s\n", i, psSec->eType==AVCFileARC? "ARC": psSec->eType==AVCFilePAL? "PAL": psSec->eType==AVCFileCNT? "CNT": psSec->eType==AVCFileLAB? "LAB": psSec->eType==AVCFilePRJ? "PRJ": psSec->eType==AVCFileTOL? "TOL": psSec->eType==AVCFileLOG? "LOG": psSec->eType==AVCFileTXT? "TXT": psSec->eType==AVCFileTX6? "TX6": psSec->eType==AVCFileRXP? "RXP": psSec->eType==AVCFileRPL? "RPL": psSec->eType==AVCFileTABLE? "TABLE": "Unknown", psSec->pszName, psSec->pszFilename?psSec->pszFilename:"(null)"); } AVCE00ReadClose(psReadInfo); } } avce00-2.0.0/avcimport.c0100664000076400007640000001376310471150033014230 0ustar danieldaniel/********************************************************************** * $Id: avcimport.c,v 1.9 2006/08/17 20:21:51 dmorissette Exp $ * * Name: avcimport.c * Project: Arc/Info Vector coverage (AVC) BIN<->E00 conversion library * Language: ANSI C * Purpose: Convert an E00 file to an Arc/Info binary coverage. * Author: Daniel Morissette, dmorissette@dmsolutions.ca * ********************************************************************** * Copyright (c) 1999-2005, Daniel Morissette * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ********************************************************************** * * $Log: avcimport.c,v $ * Revision 1.9 2006/08/17 20:21:51 dmorissette * Updated email address * * Revision 1.8 2005/06/03 03:55:41 daniel * Update URL to website * * Revision 1.7 2005/06/03 03:49:59 daniel * Update email address, website url, and copyright dates * * Revision 1.6 2000/09/26 20:21:05 daniel * Added AVCCoverPC write * * Revision 1.5 2000/09/22 19:45:21 daniel * Switch to MIT-style license * * Revision 1.4 1999/12/24 07:18:34 daniel * Added PC Arc/Info coverages support * * Revision 1.3 1999/12/05 05:29:08 daniel * Updated usage info with build date * * Revision 1.2 1999/05/17 16:25:02 daniel * Use AVC_DEFAULT_PREC * * Revision 1.1 1999/05/11 02:11:49 daniel * Initial revision * **********************************************************************/ #include "avc.h" static void ConvertCover(FILE *fpIn, const char *pszCoverName, AVCCoverType eCoverType); /********************************************************************** * main() * * This program converts an Arc/Info vector coverage from the native * binary format to E00. **********************************************************************/ int main(int argc, char *argv[]) { const char *pszCoverPath, *pszInFile; FILE *fpIn; AVCCoverType eCoverType = AVCCoverV7; /*--------------------------------------------------------------------- * Read program arguments. *--------------------------------------------------------------------*/ if (argc >= 4) { if (EQUAL(argv[3], "V7")) eCoverType = AVCCoverV7; else if (EQUAL(argv[3], "PC")) eCoverType = AVCCoverPC; else { printf("\nERROR: Invalid coverage type '%s'\n\n", argv[3]); argc=0; /* Force display of usage information */ } } if (argc<3) { printf("\n"); printf("AVCIMPORT - Version %s\n", AVC_VERSION); printf(" Convert an Arc/Info vector coverage from E00 to binary.\n"); printf(" Copyright (c) 1999-2005, Daniel Morissette (dmorissette@mapgears.com)\n"); printf(" AVCE00 web page: http://avce00.maptools.org/\n"); printf("\n"); printf("Usage: avcimport []\n"); printf("\n"); printf(" is either 'V7' (the default) to write a Unix V7.x coverage,\n"); printf(" or 'PC' to write a PC/Arc coverage.\n"); printf("\n"); return 1; } pszInFile = argv[1]; pszCoverPath = argv[2]; /*--------------------------------------------------------------------- * Open output file... passing "-" will take input from stdin *-------------------------------------------------------------------*/ if (strcmp(pszInFile, "-") == 0) { fpIn = stdin; } else { fpIn = fopen(pszInFile, "rt"); if (fpIn == NULL) { perror(CPLSPrintf("avcimport: Cannot open %s", pszInFile)); return 1; } } /*--------------------------------------------------------------------- * Convert the whole E00 file to a binary coverage *-------------------------------------------------------------------*/ ConvertCover(fpIn, pszCoverPath, eCoverType); /*--------------------------------------------------------------------- * Close input file and exit. *-------------------------------------------------------------------*/ if (strcmp(pszInFile, "-") != 0) { fclose(fpIn); } return 0; } /********************************************************************** * ConvertCover() * * Create a binary coverage from an E00 file. * * It would be possible to have an option for the precision... coming soon! **********************************************************************/ static void ConvertCover(FILE *fpIn, const char *pszCoverName, AVCCoverType eCoverType) { AVCE00WritePtr hWriteInfo; const char *pszLine; hWriteInfo = AVCE00WriteOpen(pszCoverName, eCoverType, AVC_DEFAULT_PREC); if (hWriteInfo) { while (CPLGetLastErrorNo() == 0 && (pszLine = CPLReadLine(fpIn) ) != NULL ) { AVCE00WriteNextLine(hWriteInfo, pszLine); } AVCE00WriteClose(hWriteInfo); } } avce00-2.0.0/avcdelete.c0100664000076400007640000000666610471150033014164 0ustar danieldaniel/********************************************************************** * $Id: avcdelete.c,v 1.6 2006/08/17 20:21:51 dmorissette Exp $ * * Name: avcdelete.c * Project: Arc/Info Vector coverage (AVC) BIN<->E00 conversion library * Language: ANSI C * Purpose: Delete an Arc/Info binary coverage. * Author: Daniel Morissette, dmorissette@dmsolutions.ca * ********************************************************************** * Copyright (c) 1999-2005, Daniel Morissette * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ********************************************************************** * * $Log: avcdelete.c,v $ * Revision 1.6 2006/08/17 20:21:51 dmorissette * Updated email address * * Revision 1.5 2005/06/03 03:55:41 daniel * Update URL to website * * Revision 1.4 2005/06/03 03:49:59 daniel * Update email address, website url, and copyright dates * * Revision 1.3 2000/09/26 20:21:04 daniel * Added AVCCoverPC write * * Revision 1.2 1999/12/05 05:28:49 daniel * Updated usage info with build date * * Revision 1.1 1999/08/23 17:15:48 daniel * *** empty log message *** * **********************************************************************/ #include "avc.h" /********************************************************************** * main() * * This program properly deletes an Arc/Info vector coverage and * associated INFO tables. **********************************************************************/ int main(int argc, char *argv[]) { const char *pszCoverPath; /*--------------------------------------------------------------------- * Read program arguments. *--------------------------------------------------------------------*/ if (argc != 2) { printf("\n"); printf("AVCDELETE - Version %s\n", AVC_VERSION); printf(" Delete an Arc/Info vector coverage and associated INFO files\n"); printf(" Copyright (c) 1999-2005, Daniel Morissette (dmorissette@mapgears.com)\n"); printf(" AVCE00 web page: http://avce00.maptools.org/\n"); printf("\n"); printf("Usage: avcdelete \n"); printf("\n"); return 1; } pszCoverPath = argv[1]; /*--------------------------------------------------------------------- * Delete requested coverage *--------------------------------------------------------------------*/ return AVCE00DeleteCoverage(pszCoverPath); } avce00-2.0.0/avc_binwr.c0100664000076400007640000025012210444034740014174 0ustar danieldaniel/* $Id: avc_binwr.c,v 1.17 2006/06/14 16:31:28 daniel Exp $ * * Name: avc_binwr.c * Project: Arc/Info vector coverage (AVC) E00->BIN conversion library * Language: ANSI C * Purpose: Binary files access functions (write mode). * Author: Daniel Morissette, dmorissette@dmsolutions.ca * ********************************************************************** * Copyright (c) 1999-2001, Daniel Morissette * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ********************************************************************** * * $Log: avc_binwr.c,v $ * Revision 1.17 2006/06/14 16:31:28 daniel * Added support for AVCCoverPC2 type (bug 1491) * * Revision 1.16 2005/06/03 03:49:58 daniel * Update email address, website url, and copyright dates * * Revision 1.15 2001/07/06 05:09:33 daniel * Removed #ifdef around fseek to fix NT4 drive problem since ANSI-C requires * an fseek() between read and write operations so this applies to Unix too. * * Revision 1.14 2001/07/06 04:25:00 daniel * Fixed a problem writing arc.dir on NT4 networked drives in an empty dir. * * Revision 1.13 2000/10/16 16:13:29 daniel * Fixed sHeader.nPrecision when writing PC TXT files * * Revision 1.12 2000/09/26 21:40:18 daniel * Fixed writing of PC Coverage TXT... they're different from V7 TXT * * Revision 1.11 2000/09/26 20:21:04 daniel * Added AVCCoverPC write * * Revision 1.10 2000/09/22 19:45:20 daniel * Switch to MIT-style license * * Revision 1.9 2000/05/29 15:31:30 daniel * Added Japanese DBCS support * * Revision 1.8 2000/01/10 02:55:12 daniel * Added call to AVCAdjustCaseSensitiveFilename() when creating tables * * Revision 1.7 1999/12/24 07:18:34 daniel * Added PC Arc/Info coverages support * * Revision 1.6 1999/08/26 17:26:09 daniel * Removed printf() messages used in Windows tests * * Revision 1.5 1999/08/23 18:18:51 daniel * Fixed memory leak and some VC++ warnings * * Revision 1.4 1999/06/08 22:08:14 daniel * Modified CreateTable() to overwrite existing arc.dir entries if necessary * * Revision 1.3 1999/06/08 18:24:32 daniel * Fixed some problems with '/' vs '\\' on Windows * * Revision 1.2 1999/05/17 16:17:36 daniel * Added RXP + TXT/TX6/TX7 write support * * Revision 1.1 1999/05/11 02:34:46 daniel * Initial revision * **********************************************************************/ #include "avc.h" #include /* tolower() */ /*===================================================================== * Stuff related to writing the binary coverage files *====================================================================*/ static void _AVCBinWriteCloseTable(AVCBinFile *psFile); static AVCBinFile *_AVCBinWriteCreateDBFTable(const char *pszPath, const char *pszCoverName, AVCTableDef *psSrcTableDef, AVCCoverType eCoverType, int nPrecision, AVCDBCSInfo *psDBCSInfo); /********************************************************************** * AVCBinWriteCreate() * * Open a coverage file for writing, write a header if applicable, and * initialize the handle to be ready to write objects to the file. * * pszPath is the coverage (or info directory) path, terminated by * a '/' or a '\\' * pszName is the name of the file to create relative to this directory. * * Note: For most file types except tables, passing pszPath="" and * including the coverage path as part of pszName instead would work. * * Returns a valid AVCBinFile handle, or NULL if the file could * not be created. * * AVCBinClose() will eventually have to be called to release the * resources used by the AVCBinFile structure. **********************************************************************/ AVCBinFile *AVCBinWriteCreate(const char *pszPath, const char *pszName, AVCCoverType eCoverType, AVCFileType eType, int nPrecision, AVCDBCSInfo *psDBCSInfo) { AVCBinFile *psFile; char *pszFname = NULL, *pszExt; GBool bCreateIndex = FALSE; int nLen; /*----------------------------------------------------------------- * Make sure precision value is valid (AVC_DEFAULT_PREC is NOT valid) *----------------------------------------------------------------*/ if (nPrecision!=AVC_SINGLE_PREC && nPrecision!=AVC_DOUBLE_PREC) { CPLError(CE_Failure, CPLE_IllegalArg, "AVCBinWriteCreate(): Invalid precision parameter " "(value must be AVC_SINGLE_PREC or AVC_DOUBLE_PREC)"); return NULL; } /*----------------------------------------------------------------- * The case of INFO tables is a bit different... * tables have to be created through a separate function. *----------------------------------------------------------------*/ if (eType == AVCFileTABLE) { CPLError(CE_Failure, CPLE_AssertionFailed, "AVCBinWriteCreate(): TABLEs must be created using " "AVCBinWriteCreateTable()"); return NULL; } /*----------------------------------------------------------------- * Alloc and init the AVCBinFile struct. *----------------------------------------------------------------*/ psFile = (AVCBinFile*)CPLCalloc(1, sizeof(AVCBinFile)); psFile->eFileType = eType; psFile->nPrecision = nPrecision; psFile->pszFilename = (char*)CPLMalloc((strlen(pszPath)+strlen(pszName)+1)* sizeof(char)); sprintf(psFile->pszFilename, "%s%s", pszPath, pszName); psFile->eCoverType = eCoverType; /*----------------------------------------------------------------- * PRJ files are text files... we won't use the AVCRawBin*() * functions for them... the file will be created and closed * inside AVCBinWritePrj(). *----------------------------------------------------------------*/ if (eType == AVCFilePRJ) { return psFile; } /*----------------------------------------------------------------- * All other file types share a very similar creation method. *----------------------------------------------------------------*/ psFile->psRawBinFile = AVCRawBinOpen(psFile->pszFilename, "w", AVC_COVER_BYTE_ORDER(psFile->eCoverType), psDBCSInfo); if (psFile->psRawBinFile == NULL) { /* Failed to open file... just return NULL since an error message * has already been issued by AVCRawBinOpen() */ CPLFree(psFile->pszFilename); CPLFree(psFile); return NULL; } /*----------------------------------------------------------------- * Create an Index file if applicable for current file type. * Yep, we'll have a problem if filenames come in as uppercase, but * this should not happen in a normal situation. * For each type there is 3 possibilities, e.g. "pal", "pal.adf", "ttt.pal" *----------------------------------------------------------------*/ pszFname = CPLStrdup(psFile->pszFilename); nLen = strlen(pszFname); if (eType == AVCFileARC && ( (nLen>=3 && EQUALN((pszExt=pszFname+nLen-3), "arc", 3)) || (nLen>=7 && EQUALN((pszExt=pszFname+nLen-7), "arc.adf", 7)) ) ) { strncpy(pszExt, "arx", 3); bCreateIndex = TRUE; } else if ((eType == AVCFilePAL || eType == AVCFileRPL) && ( (nLen>=3 && EQUALN((pszExt=pszFname+nLen-3), "pal", 3)) || (nLen>=7 && EQUALN((pszExt=pszFname+nLen-7), "pal.adf", 7)) ) ) { strncpy(pszExt, "pax", 3); bCreateIndex = TRUE; } else if (eType == AVCFileCNT && ( (nLen>=3 && EQUALN((pszExt=pszFname+nLen-3), "cnt", 3)) || (nLen>=7 && EQUALN((pszExt=pszFname+nLen-7), "cnt.adf", 7)) ) ) { strncpy(pszExt, "cnx", 3); bCreateIndex = TRUE; } else if ((eType == AVCFileTXT || eType == AVCFileTX6) && ( (nLen>=3 && EQUALN((pszExt=pszFname+nLen-3), "txt", 3)) || (nLen>=7 && EQUALN((pszExt=pszFname+nLen-7), "txt.adf", 7)) ) ) { strncpy(pszExt, "txx", 3); bCreateIndex = TRUE; } if (bCreateIndex) { psFile->psIndexFile = AVCRawBinOpen(pszFname, "w", AVC_COVER_BYTE_ORDER(psFile->eCoverType), psDBCSInfo); } CPLFree(pszFname); /*----------------------------------------------------------------- * Generate the appropriate headers for the main file and its index * if one was created. *----------------------------------------------------------------*/ if (AVCBinWriteHeader(psFile) == -1) { /* Failed! Return NULL */ AVCBinWriteClose(psFile); psFile = NULL; } return psFile; } /********************************************************************** * _AVCBinWriteHeader() * * (This function is for internal library use... external calls should * go to AVCBinWriteHeader() instead) * * Generate a 100 bytes header using the info in psHeader. * * Note: PC Coverage files have an initial 256 bytes header followed by the * regular 100 bytes header. * * This function assumes that the file pointer is currently located at * the beginning of the file. * * Returns 0 on success or -1 on error. **********************************************************************/ int _AVCBinWriteHeader(AVCRawBinFile *psFile, AVCBinHeader *psHeader, AVCCoverType eCoverType) { int nStatus = 0; if (eCoverType == AVCCoverPC) { /* PC Coverage header starts with an initial 256 bytes header */ AVCRawBinWriteInt16(psFile, 0x0400); /* Signature??? */ AVCRawBinWriteInt32(psFile, psHeader->nLength); AVCRawBinWriteZeros(psFile, 250); } AVCRawBinWriteInt32(psFile, psHeader->nSignature); AVCRawBinWriteInt32(psFile, psHeader->nPrecision); AVCRawBinWriteInt32(psFile, psHeader->nRecordSize); AVCRawBinWriteZeros(psFile, 12); AVCRawBinWriteInt32(psFile, psHeader->nLength); /* Pad the rest of the header with zeros */ AVCRawBinWriteZeros(psFile, 72); if (CPLGetLastErrorNo() != 0) nStatus = -1; return nStatus; } /********************************************************************** * AVCBinWriteHeader() * * Write a header to the specified file using the values that apply to * this file's type. The function simply does nothing if it is called * for a file type that requires no header. * * Returns 0 on success or -1 on error. **********************************************************************/ int AVCBinWriteHeader(AVCBinFile *psFile) { AVCBinHeader sHeader; int nStatus=0; GBool bHeader = TRUE; /*----------------------------------------------------------------- * Set the appropriate header information for this file type. *----------------------------------------------------------------*/ sHeader.nPrecision = sHeader.nRecordSize = sHeader.nLength = 0; sHeader.nSignature = 9994; switch(psFile->eFileType) { case AVCFileARC: sHeader.nPrecision = (psFile->nPrecision == AVC_DOUBLE_PREC)? -1 : 1; break; case AVCFilePAL: case AVCFileRPL: sHeader.nPrecision = (psFile->nPrecision == AVC_DOUBLE_PREC)? -11 : 11; break; case AVCFileLAB: sHeader.nSignature = 9993; sHeader.nPrecision = (psFile->nPrecision == AVC_DOUBLE_PREC)? -2 : 2; sHeader.nRecordSize = (psFile->nPrecision == AVC_DOUBLE_PREC)? 28 : 16; break; case AVCFileCNT: sHeader.nPrecision = (psFile->nPrecision == AVC_DOUBLE_PREC)? -14 : 14; break; case AVCFileTOL: /* single prec: tol.adf has no header * double prec: par.adf has a header */ if (psFile->nPrecision == AVC_DOUBLE_PREC) { sHeader.nSignature = 9993; sHeader.nPrecision = 40; sHeader.nRecordSize = 8; } else { bHeader = FALSE; } break; case AVCFileTXT: case AVCFileTX6: if (psFile->eCoverType == AVCCoverPC) sHeader.nPrecision = 1; else sHeader.nPrecision = (psFile->nPrecision==AVC_DOUBLE_PREC)? -67:67; break; default: /* Other file types don't need a header */ bHeader = FALSE; } /*----------------------------------------------------------------- * Write a header only if applicable. *----------------------------------------------------------------*/ if (bHeader) nStatus = _AVCBinWriteHeader(psFile->psRawBinFile, &sHeader, psFile->eCoverType); /*----------------------------------------------------------------- * Write a header for the index file... it is identical to the main * file's header. *----------------------------------------------------------------*/ if (nStatus == 0 && bHeader && psFile->psIndexFile) nStatus = _AVCBinWriteHeader(psFile->psIndexFile, &sHeader, psFile->eCoverType); return nStatus; } /********************************************************************** * AVCBinWriteClose() * * Close a coverage file opened for wirting, and release all memory * (object strcut., buffers, etc.) associated with this file. **********************************************************************/ void AVCBinWriteClose(AVCBinFile *psFile) { if (psFile->eFileType == AVCFileTABLE) { _AVCBinWriteCloseTable(psFile); return; } /*----------------------------------------------------------------- * Write the file size (nbr of 2 byte words) in the header at * byte 24 in the 100 byte header (only if applicable) * (And write the same value at byte 2-5 in the first header of PC Cover) *----------------------------------------------------------------*/ if (psFile->psRawBinFile && (psFile->eFileType == AVCFileARC || psFile->eFileType == AVCFilePAL || psFile->eFileType == AVCFileRPL || psFile->eFileType == AVCFileLAB || psFile->eFileType == AVCFileCNT || psFile->eFileType == AVCFileTXT || psFile->eFileType == AVCFileTX6 || (psFile->eFileType == AVCFileTOL && psFile->nPrecision == AVC_DOUBLE_PREC) ) ) { GInt32 n32Size; n32Size = psFile->psRawBinFile->nCurPos/2; if (psFile->eCoverType == AVCCoverPC) { /* PC Cover... Pad to multiple of 512 bytes and write 2 headers * extra bytes at EOF are not included in the size written in * header. * The first 256 bytes header is not counted in the file size * written in both headers */ n32Size -= 128; /* minus 256 bytes */ if (psFile->psRawBinFile->nCurPos%512 != 0) AVCRawBinWriteZeros(psFile->psRawBinFile, 512 - psFile->psRawBinFile->nCurPos%512); VSIFSeek(psFile->psRawBinFile->fp, 2, SEEK_SET); AVCRawBinWriteInt32(psFile->psRawBinFile, n32Size); VSIFSeek(psFile->psRawBinFile->fp, 256+24, SEEK_SET); AVCRawBinWriteInt32(psFile->psRawBinFile, n32Size); } else { /* V7 Cover ... only 1 header */ VSIFSeek(psFile->psRawBinFile->fp, 24, SEEK_SET); AVCRawBinWriteInt32(psFile->psRawBinFile, n32Size); } } AVCRawBinClose(psFile->psRawBinFile); psFile->psRawBinFile = NULL; /*----------------------------------------------------------------- * Same for the index file if it exists. *----------------------------------------------------------------*/ if (psFile->psIndexFile) { GInt32 n32Size; n32Size = psFile->psIndexFile->nCurPos/2; if (psFile->eCoverType == AVCCoverPC) { /* PC Cover... Pad to multiple of 512 bytes and write 2 headers * extra bytes at EOF are not included in the size written in * header */ n32Size -= 128; /* minus 256 bytes */ if (psFile->psIndexFile->nCurPos%512 != 0) AVCRawBinWriteZeros(psFile->psIndexFile, 512 - psFile->psIndexFile->nCurPos%512); VSIFSeek(psFile->psIndexFile->fp, 2, SEEK_SET); AVCRawBinWriteInt32(psFile->psIndexFile, n32Size); VSIFSeek(psFile->psIndexFile->fp, 256+24, SEEK_SET); AVCRawBinWriteInt32(psFile->psIndexFile, n32Size); } else { /* V7 Cover ... only 1 header */ VSIFSeek(psFile->psIndexFile->fp, 24, SEEK_SET); AVCRawBinWriteInt32(psFile->psIndexFile, n32Size); } AVCRawBinClose(psFile->psIndexFile); psFile->psIndexFile = NULL; } CPLFree(psFile->pszFilename); CPLFree(psFile); } /********************************************************************** * _AVCBinWriteIndexEntry() * * (This function is for internal library use... the index entries * are automatically handled by the AVCBinWrite*() functions) * * Write an Index Entry at the current position in the file. * * Position is relative to the beginning of the file, including the header. * Both position and size are specified in number of 2 byte words. * * Returns 0 on success or -1 on error. **********************************************************************/ int _AVCBinWriteIndexEntry(AVCRawBinFile *psFile, int nPosition, int nSize) { AVCRawBinWriteInt32(psFile, nPosition); AVCRawBinWriteInt32(psFile, nSize); if (CPLGetLastErrorNo() != 0) return -1; return 0; } /********************************************************************** * AVCBinWriteObject() * * Write a CNT (Polygon Centroid) structure to the fin object to a * coverage file. * * Simply redirects the call to the right function based on the value * of psFile->eFileType. * * Returns 0 on success or -1 on error. * * If a problem happens, then CPLError() will be called by the lower-level * functions and CPLGetLastErrorNo() can be used to find out what happened. **********************************************************************/ int AVCBinWriteObject(AVCBinFile *psFile, void *psObj) { int nStatus = 0; switch(psFile->eFileType) { case AVCFileARC: nStatus = AVCBinWriteArc(psFile, (AVCArc *)psObj); break; case AVCFilePAL: case AVCFileRPL: nStatus = AVCBinWritePal(psFile, (AVCPal *)psObj); break; case AVCFileCNT: nStatus = AVCBinWriteCnt(psFile, (AVCCnt *)psObj); break; case AVCFileLAB: nStatus = AVCBinWriteLab(psFile, (AVCLab *)psObj); break; case AVCFileTOL: nStatus = AVCBinWriteTol(psFile, (AVCTol *)psObj); break; case AVCFilePRJ: nStatus = AVCBinWritePrj(psFile, (char **)psObj); break; case AVCFileTXT: case AVCFileTX6: nStatus = AVCBinWriteTxt(psFile, (AVCTxt *)psObj); break; case AVCFileRXP: nStatus = AVCBinWriteRxp(psFile, (AVCRxp *)psObj); break; case AVCFileTABLE: nStatus = AVCBinWriteTableRec(psFile, (AVCField *)psObj); break; default: CPLError(CE_Failure, CPLE_IllegalArg, "AVCBinWriteObject(): Unsupported file type!"); nStatus = -1; } return nStatus; } /*===================================================================== * ARC *====================================================================*/ /********************************************************************** * _AVCBinWriteArc() * * (This function is for internal library use... external calls should * go to AVCBinWriteNextArc() instead) * * Write an Arc structure to the file. * * The contents of the psArc structure is assumed to be valid... this * function performs no validation on the consistency of what it is * given as input. * * Returns 0 on success or -1 on error. **********************************************************************/ int _AVCBinWriteArc(AVCRawBinFile *psFile, AVCArc *psArc, int nPrecision, AVCRawBinFile *psIndexFile) { int i, nRecSize, nCurPos; nCurPos = psFile->nCurPos/2; /* Value in 2 byte words */ AVCRawBinWriteInt32(psFile, psArc->nArcId); if (CPLGetLastErrorNo() != 0) return -1; /*----------------------------------------------------------------- * Record size is expressed in 2 byte words, and does not count the * first 8 bytes of the ARC entry. *----------------------------------------------------------------*/ nRecSize = (6 * 4 + psArc->numVertices*2 * ((nPrecision == AVC_SINGLE_PREC)? 4 : 8)) / 2; AVCRawBinWriteInt32(psFile, nRecSize); AVCRawBinWriteInt32(psFile, psArc->nUserId); AVCRawBinWriteInt32(psFile, psArc->nFNode); AVCRawBinWriteInt32(psFile, psArc->nTNode); AVCRawBinWriteInt32(psFile, psArc->nLPoly); AVCRawBinWriteInt32(psFile, psArc->nRPoly); AVCRawBinWriteInt32(psFile, psArc->numVertices); if (nPrecision == AVC_SINGLE_PREC) { for(i=0; inumVertices; i++) { AVCRawBinWriteFloat(psFile, (float)psArc->pasVertices[i].x); AVCRawBinWriteFloat(psFile, (float)psArc->pasVertices[i].y); } } else { for(i=0; inumVertices; i++) { AVCRawBinWriteDouble(psFile, psArc->pasVertices[i].x); AVCRawBinWriteDouble(psFile, psArc->pasVertices[i].y); } } /*----------------------------------------------------------------- * Write index entry (arx.adf) *----------------------------------------------------------------*/ if (psIndexFile) { _AVCBinWriteIndexEntry(psIndexFile, nCurPos, nRecSize); } if (CPLGetLastErrorNo() != 0) return -1; return 0; } /********************************************************************** * AVCBinWriteArc() * * Write the next Arc structure to the file. * * The contents of the psArc structure is assumed to be valid... this * function performs no validation on the consistency of what it is * given as input. * * Returns 0 on success or -1 on error. * * If a problem happens, then CPLError() will be called by the lower-level * functions and CPLGetLastErrorNo() can be used to find out what happened. **********************************************************************/ int AVCBinWriteArc(AVCBinFile *psFile, AVCArc *psArc) { if (psFile->eFileType != AVCFileARC) return -1; return _AVCBinWriteArc(psFile->psRawBinFile, psArc, psFile->nPrecision, psFile->psIndexFile); } /*===================================================================== * PAL *====================================================================*/ /********************************************************************** * _AVCBinWritePal() * * (This function is for internal library use... external calls should * go to AVCBinWritePal() instead) * * Write a PAL (Polygon Arc List) structure to the file. * * The contents of the psPal structure is assumed to be valid... this * function performs no validation on the consistency of what it is * given as input. * * Returns 0 on success or -1 on error. **********************************************************************/ int _AVCBinWritePal(AVCRawBinFile *psFile, AVCPal *psPal, int nPrecision, AVCRawBinFile *psIndexFile) { int i, nRecSize, nCurPos; nCurPos = psFile->nCurPos/2; /* Value in 2 byte words */ AVCRawBinWriteInt32(psFile, psPal->nPolyId); if (CPLGetLastErrorNo() != 0) return -1; /*----------------------------------------------------------------- * Record size is expressed in 2 byte words, and does not count the * first 8 bytes of the PAL entry. *----------------------------------------------------------------*/ nRecSize = ( 4 + psPal->numArcs*3 * 4 + 4 * ((nPrecision == AVC_SINGLE_PREC)? 4 : 8)) / 2; AVCRawBinWriteInt32(psFile, nRecSize); if (nPrecision == AVC_SINGLE_PREC) { AVCRawBinWriteFloat(psFile, (float)psPal->sMin.x); AVCRawBinWriteFloat(psFile, (float)psPal->sMin.y); AVCRawBinWriteFloat(psFile, (float)psPal->sMax.x); AVCRawBinWriteFloat(psFile, (float)psPal->sMax.y); } else { AVCRawBinWriteDouble(psFile, psPal->sMin.x); AVCRawBinWriteDouble(psFile, psPal->sMin.y); AVCRawBinWriteDouble(psFile, psPal->sMax.x); AVCRawBinWriteDouble(psFile, psPal->sMax.y); } AVCRawBinWriteInt32(psFile, psPal->numArcs); for(i=0; inumArcs; i++) { AVCRawBinWriteInt32(psFile, psPal->pasArcs[i].nArcId); AVCRawBinWriteInt32(psFile, psPal->pasArcs[i].nFNode); AVCRawBinWriteInt32(psFile, psPal->pasArcs[i].nAdjPoly); } /*----------------------------------------------------------------- * Write index entry (pax.adf) *----------------------------------------------------------------*/ if (psIndexFile) { _AVCBinWriteIndexEntry(psIndexFile, nCurPos, nRecSize); } if (CPLGetLastErrorNo() != 0) return -1; return 0; } /********************************************************************** * AVCBinWritePal() * * Write a PAL (Polygon Arc List) structure to the file. * * The contents of the psPal structure is assumed to be valid... this * function performs no validation on the consistency of what it is * given as input. * * Returns 0 on success or -1 on error. * * If a problem happens, then CPLError() will be called by the lower-level * functions and CPLGetLastErrorNo() can be used to find out what happened. **********************************************************************/ int AVCBinWritePal(AVCBinFile *psFile, AVCPal *psPal) { if (psFile->eFileType != AVCFilePAL && psFile->eFileType != AVCFileRPL) return -1; return _AVCBinWritePal(psFile->psRawBinFile, psPal, psFile->nPrecision, psFile->psIndexFile); } /*===================================================================== * CNT *====================================================================*/ /********************************************************************** * _AVCBinWriteCnt() * * (This function is for internal library use... external calls should * go to AVCBinWriteCnt() instead) * * Write a CNT (Polygon Centroid) structure to the file. * * Returns 0 on success or -1 on error. **********************************************************************/ int _AVCBinWriteCnt(AVCRawBinFile *psFile, AVCCnt *psCnt, int nPrecision, AVCRawBinFile *psIndexFile) { int i, nRecSize, nCurPos; nCurPos = psFile->nCurPos/2; /* Value in 2 byte words */ AVCRawBinWriteInt32(psFile, psCnt->nPolyId); if (CPLGetLastErrorNo() != 0) return -1; /*----------------------------------------------------------------- * Record size is expressed in 2 byte words, and does not count the * first 8 bytes of the CNT entry. *----------------------------------------------------------------*/ nRecSize = ( 4 + psCnt->numLabels * 4 + 2 * ((nPrecision == AVC_SINGLE_PREC)? 4 : 8)) / 2; AVCRawBinWriteInt32(psFile, nRecSize); if (nPrecision == AVC_SINGLE_PREC) { AVCRawBinWriteFloat(psFile, (float)psCnt->sCoord.x); AVCRawBinWriteFloat(psFile, (float)psCnt->sCoord.y); } else { AVCRawBinWriteDouble(psFile, psCnt->sCoord.x); AVCRawBinWriteDouble(psFile, psCnt->sCoord.y); } AVCRawBinWriteInt32(psFile, psCnt->numLabels); for(i=0; inumLabels; i++) { AVCRawBinWriteInt32(psFile, psCnt->panLabelIds[i]); } /*----------------------------------------------------------------- * Write index entry (cnx.adf) *----------------------------------------------------------------*/ if (psIndexFile) { _AVCBinWriteIndexEntry(psIndexFile, nCurPos, nRecSize); } if (CPLGetLastErrorNo() != 0) return -1; return 0; } /********************************************************************** * AVCBinWriteCnt() * * Write a CNT (Polygon Centroid) structure to the file. * * The contents of the psCnt structure is assumed to be valid... this * function performs no validation on the consistency of what it is * given as input. * * Returns 0 on success or -1 on error. * * If a problem happens, then CPLError() will be called by the lower-level * functions and CPLGetLastErrorNo() can be used to find out what happened. **********************************************************************/ int AVCBinWriteCnt(AVCBinFile *psFile, AVCCnt *psCnt) { if (psFile->eFileType != AVCFileCNT) return -1; return _AVCBinWriteCnt(psFile->psRawBinFile, psCnt, psFile->nPrecision, psFile->psIndexFile); } /*===================================================================== * LAB *====================================================================*/ /********************************************************************** * _AVCBinWriteLab() * * (This function is for internal library use... external calls should * go to AVCBinWriteLab() instead) * * Write a LAB (Centroid Label) structure to the file. * * The contents of the psLab structure is assumed to be valid... this * function performs no validation on the consistency of what it is * given as input. * * Returns 0 on success or -1 on error. **********************************************************************/ int _AVCBinWriteLab(AVCRawBinFile *psFile, AVCLab *psLab, int nPrecision) { AVCRawBinWriteInt32(psFile, psLab->nValue); if (CPLGetLastErrorNo() != 0) return -1; AVCRawBinWriteInt32(psFile, psLab->nPolyId); if (nPrecision == AVC_SINGLE_PREC) { AVCRawBinWriteFloat(psFile, (float)psLab->sCoord1.x); AVCRawBinWriteFloat(psFile, (float)psLab->sCoord1.y); AVCRawBinWriteFloat(psFile, (float)psLab->sCoord2.x); AVCRawBinWriteFloat(psFile, (float)psLab->sCoord2.y); AVCRawBinWriteFloat(psFile, (float)psLab->sCoord3.x); AVCRawBinWriteFloat(psFile, (float)psLab->sCoord3.y); } else { AVCRawBinWriteDouble(psFile, psLab->sCoord1.x); AVCRawBinWriteDouble(psFile, psLab->sCoord1.y); AVCRawBinWriteDouble(psFile, psLab->sCoord2.x); AVCRawBinWriteDouble(psFile, psLab->sCoord2.y); AVCRawBinWriteDouble(psFile, psLab->sCoord3.x); AVCRawBinWriteDouble(psFile, psLab->sCoord3.y); } if (CPLGetLastErrorNo() != 0) return -1; return 0; } /********************************************************************** * AVCBinWriteLab() * * Write a LAB (Centroid Label) structure to the file. * * The contents of the psLab structure is assumed to be valid... this * function performs no validation on the consistency of what it is * given as input. * * Returns 0 on success or -1 on error. * * If a problem happens, then CPLError() will be called by the lower-level * functions and CPLGetLastErrorNo() can be used to find out what happened. **********************************************************************/ int AVCBinWriteLab(AVCBinFile *psFile, AVCLab *psLab) { if (psFile->eFileType != AVCFileLAB) return -1; return _AVCBinWriteLab(psFile->psRawBinFile, psLab, psFile->nPrecision); } /*===================================================================== * TOL *====================================================================*/ /********************************************************************** * _AVCBinWriteTol() * * (This function is for internal library use... external calls should * go to AVCBinWriteTol() instead) * * Write a TOL (tolerance) structure to the file. * * The contents of the psTol structure is assumed to be valid... this * function performs no validation on the consistency of what it is * given as input. * * Returns 0 on success or -1 on error. **********************************************************************/ int _AVCBinWriteTol(AVCRawBinFile *psFile, AVCTol *psTol, int nPrecision) { AVCRawBinWriteInt32(psFile, psTol->nIndex); if (CPLGetLastErrorNo() != 0) return -1; AVCRawBinWriteInt32(psFile, psTol->nFlag); if (nPrecision == AVC_SINGLE_PREC) { AVCRawBinWriteFloat(psFile, (float)psTol->dValue); } else { AVCRawBinWriteDouble(psFile, psTol->dValue); } if (CPLGetLastErrorNo() != 0) return -1; return 0; } /********************************************************************** * AVCBinWriteTol() * * Write a TOL (tolerance) structure to the file. * * The contents of the psTol structure is assumed to be valid... this * function performs no validation on the consistency of what it is * given as input. * * Returns 0 on success or -1 on error. * * If a problem happens, then CPLError() will be called by the lower-level * functions and CPLGetLastErrorNo() can be used to find out what happened. **********************************************************************/ int AVCBinWriteTol(AVCBinFile *psFile, AVCTol *psTol) { if (psFile->eFileType != AVCFileTOL) return -1; return _AVCBinWriteTol(psFile->psRawBinFile, psTol, psFile->nPrecision); } /*===================================================================== * PRJ *====================================================================*/ /********************************************************************** * AVCBinWritePrj() * * Write a PRJ (Projection info) to the file. * * Since a PRJ file is a simple text file and there is only ONE projection * info per prj.adf file, this function behaves differently from the * other ones... all the job is done here, including creating and closing * the output file. * * The contents of the papszPrj is assumed to be valid... this * function performs no validation on the consistency of what it is * given as input. * * Returns 0 on success or -1 on error. * * If a problem happens, then CPLError() will be called by the lower-level * functions and CPLGetLastErrorNo() can be used to find out what happened. **********************************************************************/ int AVCBinWritePrj(AVCBinFile *psFile, char **papszPrj) { if (psFile->eFileType != AVCFilePRJ) return -1; CSLSave(papszPrj, psFile->pszFilename); if (CPLGetLastErrorNo() != 0) return -1; return 0; } /*===================================================================== * TXT/TX6/TX7 *====================================================================*/ /********************************************************************** * _AVCBinWriteTxt() * * (This function is for internal library use... external calls should * go to AVCBinWriteTxt() instead) * * Write a TXT/TX6/TX7 (Annotation) structure to the file. * * The contents of the psTxt structure is assumed to be valid... this * function performs no validation on the consistency of what it is * given as input. * * Returns 0 on success or -1 on error. **********************************************************************/ int _AVCBinWriteTxt(AVCRawBinFile *psFile, AVCTxt *psTxt, int nPrecision, AVCRawBinFile *psIndexFile) { int i, nRecSize, nCurPos, nStrLen, numVertices; nCurPos = psFile->nCurPos/2; /* Value in 2 byte words */ AVCRawBinWriteInt32(psFile, psTxt->nTxtId); if (CPLGetLastErrorNo() != 0) return -1; /*----------------------------------------------------------------- * Record size is expressed in 2 byte words, and does not count the * first 8 bytes of the TXT entry. *----------------------------------------------------------------*/ /* String uses a multiple of 4 bytes of storage */ if (psTxt->pszText) nStrLen = ((strlen(psTxt->pszText) + 3)/4)*4; else nStrLen = 0; numVertices = ABS(psTxt->numVerticesLine) + ABS(psTxt->numVerticesArrow); nRecSize = (112 + 8 + nStrLen + (numVertices*2+3)* ((nPrecision == AVC_SINGLE_PREC)?4:8)) / 2; AVCRawBinWriteInt32(psFile, nRecSize); AVCRawBinWriteInt32(psFile, psTxt->nUserId ); AVCRawBinWriteInt32(psFile, psTxt->nLevel ); AVCRawBinWriteFloat(psFile, psTxt->f_1e2 ); AVCRawBinWriteInt32(psFile, psTxt->nSymbol ); AVCRawBinWriteInt32(psFile, psTxt->numVerticesLine ); AVCRawBinWriteInt32(psFile, psTxt->n28 ); AVCRawBinWriteInt32(psFile, psTxt->numChars ); AVCRawBinWriteInt32(psFile, psTxt->numVerticesArrow ); for(i=0; i<20; i++) { AVCRawBinWriteInt16(psFile, psTxt->anJust1[i] ); } for(i=0; i<20; i++) { AVCRawBinWriteInt16(psFile, psTxt->anJust2[i] ); } if (nPrecision == AVC_SINGLE_PREC) { AVCRawBinWriteFloat(psFile, (float)psTxt->dHeight); AVCRawBinWriteFloat(psFile, (float)psTxt->dV2); AVCRawBinWriteFloat(psFile, (float)psTxt->dV3); } else { AVCRawBinWriteDouble(psFile, psTxt->dHeight); AVCRawBinWriteDouble(psFile, psTxt->dV2); AVCRawBinWriteDouble(psFile, psTxt->dV3); } if (nStrLen > 0) AVCRawBinWritePaddedString(psFile, nStrLen, psTxt->pszText); if (nPrecision == AVC_SINGLE_PREC) { for(i=0; ipasVertices[i].x); AVCRawBinWriteFloat(psFile, (float)psTxt->pasVertices[i].y); } } else { for(i=0; ipasVertices[i].x); AVCRawBinWriteDouble(psFile, psTxt->pasVertices[i].y); } } AVCRawBinWriteZeros(psFile, 8); /*----------------------------------------------------------------- * Write index entry (cnx.adf) *----------------------------------------------------------------*/ if (psIndexFile) { _AVCBinWriteIndexEntry(psIndexFile, nCurPos, nRecSize); } if (CPLGetLastErrorNo() != 0) return -1; return 0; } /********************************************************************** * _AVCBinWritePCCoverageTxt() * * (This function is for internal library use... external calls should * go to AVCBinWriteTxt() instead) * * Write a TXT (Annotation) structure to a AVCCoverPC file. * * The contents of the psTxt structure is assumed to be valid... this * function performs no validation on the consistency of what it is * given as input. * * This function assumes that PC Coverages are always single precision. * * Returns 0 on success or -1 on error. **********************************************************************/ int _AVCBinWritePCCoverageTxt(AVCRawBinFile *psFile, AVCTxt *psTxt, int nPrecision, AVCRawBinFile *psIndexFile) { int i, nRecSize, nCurPos, nStrLen, numVertices; CPLAssert(nPrecision == AVC_SINGLE_PREC); nCurPos = psFile->nCurPos/2; /* Value in 2 byte words */ AVCRawBinWriteInt32(psFile, psTxt->nTxtId); if (CPLGetLastErrorNo() != 0) return -1; /*----------------------------------------------------------------- * Record size is expressed in 2 byte words, and does not count the * first 8 bytes of the TXT entry. *----------------------------------------------------------------*/ /* String uses a multiple of 4 bytes of storage, * And if text is already a multiple of 4 bytes then we include 4 extra * spaces anyways (was probably a bug in the software!). */ if (psTxt->pszText) nStrLen = ((strlen(psTxt->pszText) + 4)/4)*4; else nStrLen = 4; nRecSize = (92 - 8 + nStrLen) / 2; AVCRawBinWriteInt32(psFile, nRecSize); AVCRawBinWriteInt32(psFile, psTxt->nLevel ); /*----------------------------------------------------------------- * Number of vertices to write: * Note that because of the way V7 binary TXT files work, the rest of the * lib expects to receive duplicate coords for the first vertex, so * we will also receive an additional vertex for that but we won't write * it. We also ignore the arrow vertices if there is any. *----------------------------------------------------------------*/ numVertices = ABS(psTxt->numVerticesLine) -1; numVertices = MIN(4, numVertices); /* Maximum of 4 points */ AVCRawBinWriteInt32(psFile, numVertices ); for(i=0; ipasVertices[i+1].x); AVCRawBinWriteFloat(psFile, (float)psTxt->pasVertices[i+1].y); } AVCRawBinWriteZeros(psFile, (4-numVertices)*4*2 + 28); AVCRawBinWriteFloat(psFile, (float)psTxt->dHeight); AVCRawBinWriteFloat(psFile, psTxt->f_1e2 ); AVCRawBinWriteInt32(psFile, psTxt->nSymbol ); AVCRawBinWriteInt32(psFile, psTxt->numChars ); if (nStrLen > 0) AVCRawBinWritePaddedString(psFile, nStrLen, psTxt->pszText); /*----------------------------------------------------------------- * Write index entry (cnx.adf) *----------------------------------------------------------------*/ if (psIndexFile) { _AVCBinWriteIndexEntry(psIndexFile, nCurPos, nRecSize); } if (CPLGetLastErrorNo() != 0) return -1; return 0; } /********************************************************************** * AVCBinWriteTxt() * * Write a TXT/TX6/TX7 (Annotation) structure to the file. * * The contents of the psTxt structure is assumed to be valid... this * function performs no validation on the consistency of what it is * given as input. * * Returns 0 on success or -1 on error. * * If a problem happens, then CPLError() will be called by the lower-level * functions and CPLGetLastErrorNo() can be used to find out what happened. **********************************************************************/ int AVCBinWriteTxt(AVCBinFile *psFile, AVCTxt *psTxt) { if (psFile->eFileType != AVCFileTXT && psFile->eFileType != AVCFileTX6) return -1; /* AVCCoverPC and AVCCoverWeird have a different TXT format than AVCCoverV7 */ if (psFile->eCoverType == AVCCoverPC || psFile->eCoverType == AVCCoverWeird) { return _AVCBinWritePCCoverageTxt(psFile->psRawBinFile, psTxt, psFile->nPrecision, psFile->psIndexFile); } else { return _AVCBinWriteTxt(psFile->psRawBinFile, psTxt, psFile->nPrecision, psFile->psIndexFile); } } /*===================================================================== * RXP *====================================================================*/ /********************************************************************** * _AVCBinWriteRxp() * * (This function is for internal library use... external calls should * go to AVCBinWriteRxp() instead) * * Write a RXP (Region something...) structure to the file. * * The contents of the psRxp structure is assumed to be valid... this * function performs no validation on the consistency of what it is * given as input. * * Returns 0 on success or -1 on error. **********************************************************************/ int _AVCBinWriteRxp(AVCRawBinFile *psFile, AVCRxp *psRxp, int nPrecision) { AVCRawBinWriteInt32(psFile, psRxp->n1); if (CPLGetLastErrorNo() != 0) return -1; AVCRawBinWriteInt32(psFile, psRxp->n2); if (CPLGetLastErrorNo() != 0) return -1; return 0; } /********************************************************************** * AVCBinWriteRxp() * * Write a RXP (Region something...) structure to the file. * * The contents of the psRxp structure is assumed to be valid... this * function performs no validation on the consistency of what it is * given as input. * * Returns 0 on success or -1 on error. * * If a problem happens, then CPLError() will be called by the lower-level * functions and CPLGetLastErrorNo() can be used to find out what happened. **********************************************************************/ int AVCBinWriteRxp(AVCBinFile *psFile, AVCRxp *psRxp) { if (psFile->eFileType != AVCFileRXP) return -1; return _AVCBinWriteRxp(psFile->psRawBinFile, psRxp, psFile->nPrecision); } /*===================================================================== * TABLES *====================================================================*/ /********************************************************************** * _AVCBinWriteArcDir() * * (This function is for internal library use... external calls should * go to AVCBinWriteCreateTable() instead) * * Write an ARC.DIR entry at the current position in file. * * The contents of the psTableDef structure is assumed to be valid... this * function performs no validation on the consistency of what it is * given as input. * * Returns 0 on success or -1 on error. **********************************************************************/ int _AVCBinWriteArcDir(AVCRawBinFile *psFile, AVCTableDef *psTableDef) { /* STRING values MUST be padded with spaces. */ AVCRawBinWritePaddedString(psFile, 32, psTableDef->szTableName); if (CPLGetLastErrorNo() != 0) return -1; AVCRawBinWritePaddedString(psFile, 8, psTableDef->szInfoFile); AVCRawBinWriteInt16(psFile, psTableDef->numFields); /* Record size must be a multiple of 2 bytes */ AVCRawBinWriteInt16(psFile, (GInt16)(((psTableDef->nRecSize+1)/2)*2)); /* ??? Unknown values ??? */ AVCRawBinWritePaddedString(psFile, 16, " "); AVCRawBinWriteInt16(psFile, 132); AVCRawBinWriteInt16(psFile, 0); AVCRawBinWriteInt32(psFile, psTableDef->numRecords); AVCRawBinWriteZeros(psFile, 10); AVCRawBinWritePaddedString(psFile, 2, psTableDef->szExternal); AVCRawBinWriteZeros(psFile, 238); AVCRawBinWritePaddedString(psFile, 8, " "); AVCRawBinWriteZeros(psFile, 54); if (CPLGetLastErrorNo() != 0) return -1; return 0; } /********************************************************************** * _AVCBinWriteArcNit() * * (This function is for internal library use... external calls should * go to AVCBinWriteCreateTable() instead) * * Write an ARC####.NIT entry at the current position in file. * * The contents of the psTableDef structure is assumed to be valid... this * function performs no validation on the consistency of what it is * given as input. * * Returns 0 on success or -1 on error. **********************************************************************/ int _AVCBinWriteArcNit(AVCRawBinFile *psFile, AVCFieldInfo *psField) { /* STRING values MUST be padded with spaces. */ AVCRawBinWritePaddedString(psFile, 16, psField->szName); if (CPLGetLastErrorNo() != 0) return -1; AVCRawBinWriteInt16(psFile, psField->nSize); AVCRawBinWriteInt16(psFile, psField->v2); AVCRawBinWriteInt16(psFile, psField->nOffset); AVCRawBinWriteInt16(psFile, psField->v4); AVCRawBinWriteInt16(psFile, psField->v5); AVCRawBinWriteInt16(psFile, psField->nFmtWidth); AVCRawBinWriteInt16(psFile, psField->nFmtPrec); AVCRawBinWriteInt16(psFile, psField->nType1); AVCRawBinWriteInt16(psFile, psField->nType2); AVCRawBinWriteInt16(psFile, psField->v10); AVCRawBinWriteInt16(psFile, psField->v11); AVCRawBinWriteInt16(psFile, psField->v12); AVCRawBinWriteInt16(psFile, psField->v13); AVCRawBinWritePaddedString(psFile, 16, psField->szAltName); AVCRawBinWriteZeros(psFile, 56); AVCRawBinWriteInt16(psFile, psField->nIndex); AVCRawBinWriteZeros(psFile, 28); if (CPLGetLastErrorNo() != 0) return -1; return 0; } /********************************************************************** * _AVCBinWriteCreateArcDirEntry() * * Add an entry in the ARC.DIR for the table defined in psSrcTableDef. * * If an entry with the same table name already exists then this entry * will be reused and overwritten. * * Note: there could be a problem if 2 processes try to add an entry * at the exact same time... does Arc/Info do any locking on that file??? * * Returns an integer value corresponding to the new table index (ARC####) * or -1 if something failed. **********************************************************************/ /* Prototype for _AVCBinReadNextArcDir() from avc_bin.c */ int _AVCBinReadNextArcDir(AVCRawBinFile *psFile, AVCTableDef *psArcDir); int _AVCBinWriteCreateArcDirEntry(const char *pszArcDirFile, AVCTableDef *psTableDef, AVCDBCSInfo *psDBCSInfo) { int iEntry, numDirEntries=0, nTableIndex = 0; VSIStatBuf sStatBuf; AVCRawBinFile *hRawBinFile; GBool bFound; AVCTableDef sEntry; /*----------------------------------------------------------------- * Open and Scan the ARC.DIR to establish the table index (ARC####) *----------------------------------------------------------------*/ #ifdef _WIN32 /*----------------------------------------------------------------- * Note, DM, 20010507 - We used to use VSIFStat() to establish the * size of arc.dir, but when working on a WinNT4 networked drive, the * stat() information was not always right, and we sometimes ended * up overwriting arc.dir entries. The solution: open and scan arc.dir * until EOF to establish its size. * That trick also seems to fix another network buffer problem: when * writing a coverage in a new empty dir (with no info dir yet), we * would get an error in fwrite() while writing the 3rd arc.dir * entry of the coverage. That second problem could also have been * fixed by forcing a VSIFSeek() before the first fwrite()... we've * added it below. *----------------------------------------------------------------*/ FILE *fp; if ((fp = VSIFOpen(pszArcDirFile, "r")) != NULL) { char buf[380]; while (!VSIFEof(fp)) { if (VSIFRead(buf, 380, 1, fp) == 1) numDirEntries++; } VSIFClose(fp); hRawBinFile = AVCRawBinOpen(pszArcDirFile, "r+", AVC_COVER_BYTE_ORDER(AVCCoverV7), psDBCSInfo); } else #endif /* On Unix we can still use fstat() */ if ( VSIStat(pszArcDirFile, &sStatBuf) != -1 ) { numDirEntries = sStatBuf.st_size/380; hRawBinFile = AVCRawBinOpen(pszArcDirFile, "r+", AVC_COVER_BYTE_ORDER(AVCCoverV7), psDBCSInfo); } else { numDirEntries = 0; hRawBinFile = AVCRawBinOpen(pszArcDirFile, "w", AVC_COVER_BYTE_ORDER(AVCCoverV7), psDBCSInfo); } if (hRawBinFile == NULL) { /* Failed to open file... just return -1 since an error message * has already been issued by AVCRawBinOpen() */ return -1; } /* Init nTableIndex at -1 so that first table created should have * index 0 */ nTableIndex = -1; iEntry = 0; bFound = FALSE; while(!bFound && iEntryszTableName, sEntry.szTableName, strlen(psTableDef->szTableName))) { bFound = TRUE; break; } iEntry++; } /*----------------------------------------------------------------- * Reposition the file pointer and write the entry. * * We use VSIFSeek() directly since the AVCRawBin*() functions do * not support random access yet... it is OK to do so here since the * ARC.DIR does not have a header and we will close it right away. *----------------------------------------------------------------*/ if (bFound) VSIFSeek(hRawBinFile->fp, iEntry*380, SEEK_SET); else { /* Not found... Use the next logical table index */ nTableIndex++; /* We're already at EOF so we shouldn't need to fseek here, but * ANSI-C requires that a file positioning function be called * between read and writes... this had never been a problem before * on any system except with NT4 network drives. */ VSIFSeek(hRawBinFile->fp, numDirEntries*380, SEEK_SET); } sprintf(psTableDef->szInfoFile, "ARC%4.4d", nTableIndex); _AVCBinWriteArcDir(hRawBinFile, psTableDef); AVCRawBinClose(hRawBinFile); return nTableIndex; } /********************************************************************** * AVCBinWriteCreateTable() * * Open an INFO table for writing: * * - Add an entry for the new table in the info/arc.dir * - Write the attributes definitions to the info/arc####.nit * - Create the data file, ready to write data records to it * - If necessary, set the arc####.dat to point to the location of * the data file. * * pszInfoPath is the info directory path, terminated by a '/' or a '\\' * It is assumed that this 'info' directory already exists and is writable. * * psTableDef should contain a valid table definition for this coverage. * This function will create and maintain its own copy of the structure. * * The name of the file to create and its location will be based on the * table name and the external ("XX") flag values in the psTableDef * structure, so you have to make sure that these values are valid. * * If a table with the same name is already present in the arc.dir, then * the same arc.dir entry will be used and overwritten. This happens * when a coverage directory is deleted by hand. The behavior implemented * here correspond to Arc/Info's behavior. * * For internal tables, the data file goes directly in the info directory, so * there is not much to worry about. * * For external tables, the table name is composed of 3 parts: * * . * * - : * The first part of the table name (before the '.') is the * name of the coverage to which the table belongs, and the data file * will be created in this coverage's directory... so it is assumed that * the directory "../" already exists and is writable. * - : * The coverage name is followed by a 3 chars extension that will be * used to build the name of the external table to create. * - : * For some table types, the extension is followed by a subclass name. * * When is present, then the data file name will be: * "..//." * * e.g. The table named "TEST.PATCOUNTY" would be stored in the file * "../test/county.pat" (this path is realtive to the info directory) * * When the is not present, then the name of the data file * will be the "..//.adf" * * e.g. The table named "TEST.PAT" would be stored in the file * "../test/pat.adf" * * Of course, it would be too easy if there were no exceptions to these * rules! Single precision ".TIC" and ".BND" follow the above rules and * will be named "tic.adf" and "bnd.adf" but in double precision coverages, * they will be named "dbltic.adf" and "dblbnd.adf". * * Returns a valid AVCBinFile handle, or NULL if the table could * not be created. * * AVCBinClose() will eventually have to be called to release the * resources used by the AVCBinFile structure. **********************************************************************/ AVCBinFile *AVCBinWriteCreateTable(const char *pszInfoPath, const char *pszCoverName, AVCTableDef *psSrcTableDef, AVCCoverType eCoverType, int nPrecision, AVCDBCSInfo *psDBCSInfo) { AVCBinFile *psFile; AVCRawBinFile *hRawBinFile; AVCTableDef *psTableDef = NULL; char *pszFname = NULL, szInfoFile[8]=""; int i, nTableIndex = 0; if (eCoverType == AVCCoverPC || eCoverType == AVCCoverPC2) return _AVCBinWriteCreateDBFTable(pszInfoPath, pszCoverName, psSrcTableDef, eCoverType, nPrecision, psDBCSInfo); /*----------------------------------------------------------------- * Make sure precision value is valid (AVC_DEFAULT_PREC is NOT valid) *----------------------------------------------------------------*/ if (nPrecision!=AVC_SINGLE_PREC && nPrecision!=AVC_DOUBLE_PREC) { CPLError(CE_Failure, CPLE_IllegalArg, "AVCBinWriteCreateTable(): Invalid precision parameter " "(value must be AVC_SINGLE_PREC or AVC_DOUBLE_PREC)"); return NULL; } /* Alloc a buffer big enough for the longest possible filename... */ pszFname = (char*)CPLMalloc((strlen(pszInfoPath)+81)*sizeof(char)); /*----------------------------------------------------------------- * Alloc and init the AVCBinFile struct. *----------------------------------------------------------------*/ psFile = (AVCBinFile*)CPLCalloc(1, sizeof(AVCBinFile)); psFile->eFileType = AVCFileTABLE; /* Precision is not important for tables */ psFile->nPrecision = nPrecision; psFile->eCoverType = eCoverType; psFile->hdr.psTableDef = psTableDef = _AVCDupTableDef(psSrcTableDef); /*----------------------------------------------------------------- * Add a record for this table in the "arc.dir" * Note: there could be a problem if 2 processes try to add an entry * at the exact same time... does Arc/Info do any locking on that file??? *----------------------------------------------------------------*/ sprintf(pszFname, "%sarc.dir", pszInfoPath); nTableIndex = _AVCBinWriteCreateArcDirEntry(pszFname, psTableDef, psDBCSInfo); if (nTableIndex < 0) { /* Failed to add arc.dir entry... just return NULL since an error * message has already been issued by _AVCBinWriteCreateArcDirEntry() */ _AVCDestroyTableDef(psTableDef); CPLFree(psFile); CPLFree(pszFname); return NULL; } sprintf(szInfoFile, "arc%4.4d", nTableIndex); /*----------------------------------------------------------------- * Create the "arc####.nit" with the attribute definitions. *----------------------------------------------------------------*/ sprintf(pszFname, "%s%s.nit", pszInfoPath, szInfoFile); hRawBinFile = AVCRawBinOpen(pszFname, "w", AVC_COVER_BYTE_ORDER(AVCCoverV7), psDBCSInfo); if (hRawBinFile == NULL) { /* Failed to open file... just return NULL since an error message * has already been issued by AVCRawBinOpen() */ _AVCDestroyTableDef(psTableDef); CPLFree(psFile); CPLFree(pszFname); return NULL; } for(i=0; inumFields; i++) { _AVCBinWriteArcNit(hRawBinFile, &(psTableDef->pasFieldDef[i])); } AVCRawBinClose(hRawBinFile); hRawBinFile = NULL; /*----------------------------------------------------------------- * The location of the data file depends on the external flag. *----------------------------------------------------------------*/ if (EQUAL(psTableDef->szExternal, " ")) { /*------------------------------------------------------------- * Internal table: data goes directly in "arc####.dat" *------------------------------------------------------------*/ psTableDef->szDataFile[0] = '\0'; sprintf(pszFname, "%s%s.dat", pszInfoPath, szInfoFile); psFile->pszFilename = CPLStrdup(pszFname); } else { /*------------------------------------------------------------- * External table: data stored in the coverage directory, and * the path to the data file is written to "arc####.dat" *... start by extracting the info to build the data file name... *------------------------------------------------------------*/ char szCoverName[40]="", szExt[4]="", szSubclass[40]="", *pszPtr; int nLen; FILE *fpOut; nLen = strlen(psTableDef->szTableName); CPLAssert(nLen <= 32); if (nLen > 32) return NULL; pszPtr = psTableDef->szTableName; for(i=0; *pszPtr!='\0' && *pszPtr!='.' && *pszPtr!=' '; i++, pszPtr++) { szCoverName[i] = tolower(*pszPtr); } szCoverName[i] = '\0'; if (*pszPtr == '.') pszPtr++; for(i=0; i<3 && *pszPtr!='\0' && *pszPtr!=' '; i++, pszPtr++) { szExt[i] = tolower(*pszPtr); } szExt[i] = '\0'; for(i=0; *pszPtr!='\0' && *pszPtr!=' '; i++, pszPtr++) { szSubclass[i] = tolower(*pszPtr); } szSubclass[i] = '\0'; /*------------------------------------------------------------- * ... and build the data file name based on what we extracted *------------------------------------------------------------*/ if (strlen(szSubclass) == 0) { if (nPrecision == AVC_DOUBLE_PREC && (EQUAL(szExt, "TIC") || EQUAL(szExt, "BND")) ) { /* "..//dbl.adf" */ sprintf(psTableDef->szDataFile, "../%s/dbl%s.adf", szCoverName, szExt); } else { /* "..//.adf" */ sprintf(psTableDef->szDataFile, "../%s/%s.adf", szCoverName, szExt); } } else { /* "..//." */ sprintf(psTableDef->szDataFile, "../%s/%s.%s", szCoverName, szSubclass, szExt); } /*------------------------------------------------------------- * Write it to the arc####.dat * Note that the path that is written in the arc####.dat contains * '/' as a directory delimiter, even on Windows systems. *------------------------------------------------------------*/ sprintf(pszFname, "%s%s.dat", pszInfoPath, szInfoFile); fpOut = VSIFOpen(pszFname, "wt"); if (fpOut) { VSIFPrintf(fpOut, "%-80.80s", psTableDef->szDataFile); VSIFClose(fpOut); } else { CPLError(CE_Failure, CPLE_OpenFailed, "Failed creating file %s.", pszFname); CPLFree(pszFname); _AVCDestroyTableDef(psTableDef); CPLFree(psFile); return NULL; } sprintf(pszFname, "%s%s", pszInfoPath, psTableDef->szDataFile); psFile->pszFilename = CPLStrdup(pszFname); #ifdef WIN32 /*------------------------------------------------------------- * On a Windows system, we have to change the '/' to '\\' in the * data file path. *------------------------------------------------------------*/ for(i=0; psFile->pszFilename[i] != '\0'; i++) if (psFile->pszFilename[i] == '/') psFile->pszFilename[i] = '\\'; #endif /* WIN32 */ }/* if "XX" */ /*----------------------------------------------------------------- * OK, now we're ready to create the actual data file. *----------------------------------------------------------------*/ AVCAdjustCaseSensitiveFilename(psFile->pszFilename); psFile->psRawBinFile = AVCRawBinOpen(psFile->pszFilename, "w", AVC_COVER_BYTE_ORDER(AVCCoverV7), psDBCSInfo); if (psFile->psRawBinFile == NULL) { /* Failed to open file... just return NULL since an error message * has already been issued by AVCRawBinOpen() */ CPLFree(pszFname); CPLFree(psFile->pszFilename); _AVCDestroyTableDef(psTableDef); CPLFree(psFile); return NULL; } CPLFree(pszFname); return psFile; } /********************************************************************** * _AVCBinWriteCreateDBFTable() * * Create a table (DBF file) in a PC Coverage and write the attribute defns to * the file. The file will then be ready to write records to. * * In PC Coverages, only the following tables appear to be supported: * - TEST.AAT -> AAT.DBF * - TEST.PAT -> PAT.DBF * - TEST.BND -> BND.DBF * - TEST.TIC -> TIC.DBF * * However, this function will not fail if it is passed a table name not * supported by PC Arc/Info. * e.g. TEST.PATCOUNTY would be written as PATCOUNTY.DBF even if PC Arc/Info * would probably not recognize that name. * * Returns a valid AVCBinFile handle, or NULL if the table could * not be created. * * AVCBinClose() will eventually have to be called to release the * resources used by the AVCBinFile structure. **********************************************************************/ AVCBinFile *_AVCBinWriteCreateDBFTable(const char *pszPath, const char *pszCoverName, AVCTableDef *psSrcTableDef, AVCCoverType eCoverType, int nPrecision, AVCDBCSInfo *psDBCSInfo) { AVCBinFile *psFile; AVCTableDef *psTableDef = NULL; AVCFieldInfo *pasDef; char *pszDBFBasename, szFieldName[12]; int i, j, nType; /*----------------------------------------------------------------- * Alloc and init the AVCBinFile struct. *----------------------------------------------------------------*/ psFile = (AVCBinFile*)CPLCalloc(1, sizeof(AVCBinFile)); psFile->eFileType = AVCFileTABLE; /* Precision is not important for tables */ psFile->nPrecision = nPrecision; psFile->eCoverType = eCoverType; psFile->hdr.psTableDef = psTableDef = _AVCDupTableDef(psSrcTableDef); /* nCurDBFRecord is used to keep track of the 0-based index of the * last record we read from the DBF file... this is to emulate * sequential access which is assumed by the rest of the lib. * Since the first record (record 0) has not been written yet, then * we init the index at -1. */ psFile->nCurDBFRecord = -1; /*----------------------------------------------------------------- * Establish name of file to create. *----------------------------------------------------------------*/ psFile->pszFilename = (char*)CPLCalloc(strlen(psSrcTableDef->szTableName)+ strlen(pszPath)+10, sizeof(char)); if (EQUALN(psSrcTableDef->szTableName, pszCoverName, strlen(pszCoverName)) && psSrcTableDef->szTableName[strlen(pszCoverName)] == '.') { pszDBFBasename = psSrcTableDef->szTableName + strlen(pszCoverName)+1; } else { pszDBFBasename = psSrcTableDef->szTableName; } strcpy(psFile->pszFilename, pszPath); for(i=strlen(psFile->pszFilename); *pszDBFBasename; i++, pszDBFBasename++) { psFile->pszFilename[i] = tolower(*pszDBFBasename); } strcat(psFile->pszFilename, ".dbf"); /*----------------------------------------------------------------- * OK, let's try to create the DBF file. *----------------------------------------------------------------*/ AVCAdjustCaseSensitiveFilename(psFile->pszFilename); psFile->hDBFFile = DBFCreate(psFile->pszFilename); if (psFile->hDBFFile == NULL) { CPLError(CE_Failure, CPLE_OpenFailed, "Failed creating file %s.", psFile->pszFilename); CPLFree(psFile->pszFilename); _AVCDestroyTableDef(psTableDef); CPLFree(psFile); return NULL; } /*----------------------------------------------------------------- * Create fields. *----------------------------------------------------------------*/ pasDef = psTableDef->pasFieldDef; for(i=0; inumFields; i++) { nType = pasDef[i].nType1*10; /*------------------------------------------------------------- * Special characters '#' and '-' in field names have to be replaced * with '_'. PC Field names are limited to 10 chars. *------------------------------------------------------------*/ strncpy(szFieldName, pasDef[i].szName, 10); szFieldName[10] = '\0'; for(j=0; szFieldName[j]; j++) { if (szFieldName[j] == '#' || szFieldName[j] == '-') szFieldName[j] = '_'; } if (nType == AVC_FT_DATE || nType == AVC_FT_CHAR) { /*--------------------------------------------------------- * Values stored as strings *--------------------------------------------------------*/ DBFAddField(psFile->hDBFFile, szFieldName, FTString, pasDef[i].nSize, 0); } else if (nType == AVC_FT_FIXINT || nType == AVC_FT_FIXNUM) { /*--------------------------------------------------------- * Numerics (internally stored as strings) *--------------------------------------------------------*/ DBFAddField(psFile->hDBFFile, szFieldName, FTDouble, pasDef[i].nSize, pasDef[i].nFmtPrec); } else if (nType == AVC_FT_BININT) { /*--------------------------------------------------------- * Integers (16 and 32 bits) *--------------------------------------------------------*/ DBFAddField(psFile->hDBFFile, szFieldName, FTInteger, 11, 0); } else if (nType == AVC_FT_BINFLOAT) { /*--------------------------------------------------------- * Single + Double precision floats * Set them as width=13, prec=6 in the header like PC/Arc does *--------------------------------------------------------*/ DBFAddField(psFile->hDBFFile, szFieldName, FTDouble, 13, 6); } else { /*--------------------------------------------------------- * Hummm... unsupported field type... *--------------------------------------------------------*/ CPLError(CE_Failure, CPLE_NotSupported, "Unsupported field type: (field=%s, type=%d, size=%d)", szFieldName, nType, pasDef[i].nSize); _AVCBinWriteCloseTable(psFile); return NULL; } } return psFile; } /********************************************************************** * _AVCBinWriteCloseTable() * * (This function is for internal library use... external calls should * go to AVCBinWriteClose() instead) * * Close an info table opened for wirting, and release all memory * (object struct., buffers, etc.) associated with this file. **********************************************************************/ static void _AVCBinWriteCloseTable(AVCBinFile *psFile) { if (psFile->eFileType != AVCFileTABLE) return; /*----------------------------------------------------------------- * Close the data file *----------------------------------------------------------------*/ if (psFile->hDBFFile) { /*------------------------------------------------------------- * The case of DBF files is simple! *------------------------------------------------------------*/ DBFClose(psFile->hDBFFile); psFile->hDBFFile = NULL; } else if (psFile->psRawBinFile) { /*------------------------------------------------------------- * __TODO__ make sure ARC.DIR entry contains accurate info about the * number of records written, etc. *------------------------------------------------------------*/ AVCRawBinClose(psFile->psRawBinFile); psFile->psRawBinFile = NULL; } /*----------------------------------------------------------------- * Release other memory *----------------------------------------------------------------*/ _AVCDestroyTableDef(psFile->hdr.psTableDef); CPLFree(psFile->pszFilename); CPLFree(psFile); } /********************************************************************** * _AVCBinWriteTableRec() * * (This function is for internal library use... external calls should * go to AVCBinWriteTableRec() instead) * * Write a table data record at the current position in file. * * The contents of the pasDef and pasFields structures is assumed to * be valid... this function performs no validation on the consistency * of what it is given as input. * * Returns 0 on success or -1 on error. **********************************************************************/ int _AVCBinWriteTableRec(AVCRawBinFile *psFile, int nFields, AVCFieldInfo *pasDef, AVCField *pasFields, int nRecordSize, const char *pszFname) { int i, nType, nBytesWritten=0; if (psFile == NULL) return -1; for(i=0; ieFileType != AVCFileTABLE|| psFile->hdr.psTableDef->numRecords == 0) return -1; if (psFile->eCoverType == AVCCoverPC || psFile->eCoverType == AVCCoverPC2) return _AVCBinWriteDBFTableRec(psFile->hDBFFile, psFile->hdr.psTableDef->numFields, psFile->hdr.psTableDef->pasFieldDef, pasFields, &(psFile->nCurDBFRecord), psFile->pszFilename); else return _AVCBinWriteTableRec(psFile->psRawBinFile, psFile->hdr.psTableDef->numFields, psFile->hdr.psTableDef->pasFieldDef, pasFields, psFile->hdr.psTableDef->nRecSize, psFile->pszFilename); } avce00-2.0.0/avc_e00parse.c0100664000076400007640000024623210450271652014503 0ustar danieldaniel/********************************************************************** * $Id: avc_e00parse.c,v 1.18 2006/06/27 18:06:34 dmorissette Exp $ * * Name: avc_e00parse.c * Project: Arc/Info vector coverage (AVC) E00->BIN conversion library * Language: ANSI C * Purpose: Functions to parse ASCII E00 lines and fill binary structures. * Author: Daniel Morissette, dmorissette@dmsolutions.ca * ********************************************************************** * Copyright (c) 1999-2005, Daniel Morissette * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ********************************************************************** * * $Log: avc_e00parse.c,v $ * Revision 1.18 2006/06/27 18:06:34 dmorissette * Applied patch for EOP processing from James F. (bug 1497) * * Revision 1.17 2006/06/19 14:35:47 dmorissette * New patch from James F. for E00 read support in OGR (bug 1497) * * Revision 1.16 2006/06/16 11:48:11 daniel * New functions to read E00 files directly as opposed to translating to * binary coverage. Used in the implementation of E00 read support in OGR. * Contributed by James E. Flemer. (bug 1497) * * Revision 1.15 2006/03/02 22:46:26 daniel * Accept empty subclass names for TX6/TX7 sections (bug 1261) * * Revision 1.14 2005/06/03 03:49:58 daniel * Update email address, website url, and copyright dates * * Revision 1.13 2002/08/27 15:43:02 daniel * Small typo in type 40 fix (forgot to commit to CVS on 2002-08-05) * * Revision 1.12 2002/08/05 20:20:17 daniel * Fixed parsing type 40 fields to properly detect negative exp. (bug 1272) * * Revision 1.11 2001/11/25 21:15:23 daniel * Added hack (AVC_MAP_TYPE40_TO_DOUBLE) to map type 40 fields bigger than 8 * digits to double precision as we generate E00 output (bug599) * * Revision 1.10 2001/11/25 19:45:32 daniel * Fixed reading of type 40 when not in exponent format (bug599) * * Revision 1.9 2001/07/12 20:59:34 daniel * Properly handle PAL entries with 0 arcs * * Revision 1.8 2000/09/22 19:45:20 daniel * Switch to MIT-style license * * Revision 1.7 2000/03/16 03:48:00 daniel * Accept 0-length text strings in TX6/TX7 objects * * Revision 1.6 2000/02/03 07:21:40 daniel * TXT/TX6 with string longer than 80 chars: split string in 80 chars chunks * * Revision 1.5 1999/12/05 03:40:13 daniel * Fixed signed/unsigned mismatch compile warning * * Revision 1.4 1999/11/23 05:27:58 daniel * Added AVCE00Str2Int() to extract integer values in E00 lines * * Revision 1.3 1999/08/23 18:20:49 daniel * Fixed support for attribute fields type 40 * * Revision 1.2 1999/05/17 16:20:48 daniel * Added RXP + TXT/TX6/TX7 write support + some simple problems fixed * * Revision 1.1 1999/05/11 02:34:46 daniel * Initial revision * **********************************************************************/ #include "avc.h" #include /* toupper() */ /********************************************************************** * AVCE00Str2Int() * * Convert a portion of a string to an integer value. * The difference between this function and atoi() is that this version * takes only the specified number of characters... so it can handle the * case of 2 numbers that are part of the same string but are not separated * by a space. **********************************************************************/ int AVCE00Str2Int(const char *pszStr, int numChars) { int nValue = 0; if (pszStr && numChars >= (int)strlen(pszStr)) return atoi(pszStr); else if (pszStr) { char cNextDigit; char *pszTmp; /* Get rid of const */ pszTmp = (char*)pszStr; cNextDigit = pszTmp[numChars]; pszTmp[numChars] = '\0'; nValue = atoi(pszTmp); pszTmp[numChars] = cNextDigit; } return nValue; } /********************************************************************** * AVCE00ParseInfoAlloc() * * Allocate and initialize a new AVCE00ParseInfo structure. * * AVCE00ParseStartSection() will have to be called at least once * to specify the type of objects to parse. * * The structure will eventually have to be freed with AVCE00ParseInfoFree(). **********************************************************************/ AVCE00ParseInfo *AVCE00ParseInfoAlloc() { AVCE00ParseInfo *psInfo; psInfo = (AVCE00ParseInfo*)CPLCalloc(1,sizeof(AVCE00ParseInfo)); psInfo->eFileType = AVCFileUnknown; psInfo->eSuperSectionType = AVCFileUnknown; /* Allocate output buffer. * 2k should be enough... the biggest thing we'll need to store * in it will be 1 complete INFO table record. */ psInfo->nBufSize = 2048; psInfo->pszBuf = (char *)CPLMalloc(psInfo->nBufSize*sizeof(char)); /* Set a default precision, but this value will be set on a section * by section basis inside AVCE00ParseStartSection() */ psInfo->nPrecision = AVC_SINGLE_PREC; return psInfo; } /********************************************************************** * _AVCE00ParseDestroyCurObject() * * Release mem. associated with the psInfo->cur.* object we are * currently using. **********************************************************************/ void _AVCE00ParseDestroyCurObject(AVCE00ParseInfo *psInfo) { if (psInfo->eFileType == AVCFileUnknown) return; if (psInfo->eFileType == AVCFileARC) { CPLFree(psInfo->cur.psArc->pasVertices); CPLFree(psInfo->cur.psArc); } else if (psInfo->eFileType == AVCFilePAL || psInfo->eFileType == AVCFileRPL ) { CPLFree(psInfo->cur.psPal->pasArcs); CPLFree(psInfo->cur.psPal); } else if (psInfo->eFileType == AVCFileCNT) { CPLFree(psInfo->cur.psCnt->panLabelIds); CPLFree(psInfo->cur.psCnt); } else if (psInfo->eFileType == AVCFileLAB) { CPLFree(psInfo->cur.psLab); } else if (psInfo->eFileType == AVCFileTOL) { CPLFree(psInfo->cur.psTol); } else if (psInfo->eFileType == AVCFilePRJ) { CSLDestroy(psInfo->cur.papszPrj); } else if (psInfo->eFileType == AVCFileTXT || psInfo->eFileType == AVCFileTX6) { CPLFree(psInfo->cur.psTxt->pasVertices); CPLFree(psInfo->cur.psTxt->pszText); CPLFree(psInfo->cur.psTxt); } else if (psInfo->eFileType == AVCFileRXP) { CPLFree(psInfo->cur.psRxp); } else if (psInfo->eFileType == AVCFileTABLE) { _AVCDestroyTableFields(psInfo->hdr.psTableDef, psInfo->cur.pasFields); _AVCDestroyTableDef(psInfo->hdr.psTableDef); psInfo->bTableHdrComplete = FALSE; } else { CPLError(CE_Failure, CPLE_NotSupported, "_AVCE00ParseDestroyCurObject(): Unsupported file type!"); } psInfo->eFileType = AVCFileUnknown; psInfo->cur.psArc = NULL; } /********************************************************************** * AVCE00ParseInfoFree() * * Free any memory associated with a AVCE00ParseInfo structure. **********************************************************************/ void AVCE00ParseInfoFree(AVCE00ParseInfo *psInfo) { if (psInfo) { CPLFree(psInfo->pszSectionHdrLine); psInfo->pszSectionHdrLine = NULL; CPLFree(psInfo->pszBuf); _AVCE00ParseDestroyCurObject(psInfo); } CPLFree(psInfo); } /********************************************************************** * AVCE00ParseReset() * * Reset the fields in a AVCE00ParseInfo structure so that further calls * to the API will be ready to process a new object. **********************************************************************/ void AVCE00ParseReset(AVCE00ParseInfo *psInfo) { psInfo->iCurItem = psInfo->numItems = 0; psInfo->bForceEndOfSection = FALSE; } /********************************************************************** * AVCE00ParseSuperSectionHeader() * * Check if pszLine is a valid "supersection" header line, if it is one * then store the supersection type in the ParseInfo structure. * * What I call a "supersection" is a section that contains several * files, such as the TX6/TX7, RPL, RXP, ... and also the IFO (TABLEs). * * The ParseInfo structure won't be ready to read objects until * a call to AVCE00ParseSectionHeader() (see below) succesfully * recognizes the beginning of a subsection of this type. * * Returns the new supersection type, or AVCFileUnknown if the line is * not recognized. **********************************************************************/ AVCFileType AVCE00ParseSuperSectionHeader(AVCE00ParseInfo *psInfo, const char *pszLine) { /*----------------------------------------------------------------- * If we're already inside a supersection or a section, then * return AVCFileUnknown right away. *----------------------------------------------------------------*/ if (psInfo == NULL || psInfo->eSuperSectionType != AVCFileUnknown || psInfo->eFileType != AVCFileUnknown ) { return AVCFileUnknown; } /*----------------------------------------------------------------- * Check if pszLine is a valid supersection header line. *----------------------------------------------------------------*/ if (EQUALN(pszLine, "RPL ", 5)) psInfo->eSuperSectionType = AVCFileRPL; else if (EQUALN(pszLine, "TX6 ", 5) || EQUALN(pszLine, "TX7 ", 5)) psInfo->eSuperSectionType = AVCFileTX6; else if (EQUALN(pszLine, "RXP ", 5)) psInfo->eSuperSectionType = AVCFileRXP; else if (EQUALN(pszLine, "IFO ", 5)) psInfo->eSuperSectionType = AVCFileTABLE; else return AVCFileUnknown; /*----------------------------------------------------------------- * Record the start of the supersection (for faster seeking) *----------------------------------------------------------------*/ psInfo->nStartLineNum = psInfo->nCurLineNum; /*----------------------------------------------------------------- * OK, we have a valid new section header. Set the precision and * get ready to read objects from it. *----------------------------------------------------------------*/ if (atoi(pszLine+4) == 2) psInfo->nPrecision = AVC_SINGLE_PREC; else if (atoi(pszLine+4) == 3) psInfo->nPrecision = AVC_DOUBLE_PREC; else { CPLError(CE_Failure, CPLE_AppDefined, "Parse Error: Invalid section header line (\"%s\")!", pszLine); psInfo->eSuperSectionType = AVCFileUnknown; /* psInfo->nStartLineNum = -1; */ } return psInfo->eSuperSectionType; } /********************************************************************** * AVCE00ParseSuperSectionEnd() * * Check if pszLine marks the end of a supersection, and if it is the * case, then reset the supersection flag in the ParseInfo. * * Supersections always end with the line "JABBERWOCKY", except for * the IFO section. **********************************************************************/ GBool AVCE00ParseSuperSectionEnd(AVCE00ParseInfo *psInfo, const char *pszLine ) { if (psInfo->eFileType == AVCFileUnknown && psInfo->eSuperSectionType != AVCFileUnknown && (EQUALN(pszLine, "JABBERWOCKY", 11) || (psInfo->eSuperSectionType == AVCFileTABLE && EQUALN(pszLine, "EOI", 3) ) ) ) { psInfo->eSuperSectionType = AVCFileUnknown; /* psInfo->nStartLineNum = -1; */ return TRUE; } return FALSE; } /********************************************************************** * AVCE00ParseSectionHeader() * * Check if pszLine is a valid section header line, then initialize the * ParseInfo structure to be ready to parse of object from that section. * * Returns the new section type, or AVCFileUnknown if the line is * not recognized as a valid section header. * * Note: by section header lines, we mean the "ARC 2", "PAL 2", etc. **********************************************************************/ AVCFileType AVCE00ParseSectionHeader(AVCE00ParseInfo *psInfo, const char *pszLine) { AVCFileType eNewType = AVCFileUnknown; if (psInfo == NULL || psInfo->eFileType != AVCFileUnknown) { return AVCFileUnknown; } /*----------------------------------------------------------------- * Check if pszLine is a valid section header line. *----------------------------------------------------------------*/ if (psInfo->eSuperSectionType == AVCFileUnknown) { /*------------------------------------------------------------- * We're looking for a top-level section... *------------------------------------------------------------*/ if (EQUALN(pszLine, "ARC ", 5)) eNewType = AVCFileARC; else if (EQUALN(pszLine, "PAL ", 5)) eNewType = AVCFilePAL; else if (EQUALN(pszLine, "CNT ", 5)) eNewType = AVCFileCNT; else if (EQUALN(pszLine, "LAB ", 5)) eNewType = AVCFileLAB; else if (EQUALN(pszLine, "TOL ", 5)) eNewType = AVCFileTOL; else if (EQUALN(pszLine, "PRJ ", 5)) eNewType = AVCFilePRJ; else if (EQUALN(pszLine, "TXT ", 5)) eNewType = AVCFileTXT; else { eNewType = AVCFileUnknown; return AVCFileUnknown; } /*------------------------------------------------------------- * OK, we have a valid new section header. Set the precision and * get ready to read objects from it. *------------------------------------------------------------*/ if (atoi(pszLine+4) == 2) psInfo->nPrecision = AVC_SINGLE_PREC; else if (atoi(pszLine+4) == 3) psInfo->nPrecision = AVC_DOUBLE_PREC; else { CPLError(CE_Failure, CPLE_AppDefined, "Parse Error: Invalid section header line (\"%s\")!", pszLine); eNewType = AVCFileUnknown; return AVCFileUnknown; } } else { /*------------------------------------------------------------- * We're looking for a section inside a super-section... * in this case, the header line contains the subclass name, * so any non-empty line is acceptable! * Note: the precision is already set from the previous call to * AVCE00ParseSuperSectionHeader() * Note2: Inside a double precision RPL supersection, the end of * each sub-section is marked by 2 lines, just like what * happens with double precision PALs... we have to make * sure we don't catch that second line as the beginning * of a new RPL sub-section. *------------------------------------------------------------*/ if (psInfo->eSuperSectionType == AVCFileTX6 && strlen(pszLine)==0) { /* See bug 1261: It seems that empty subclass names are valid * for TX7. We don't know if that's valid for other supersection * types, so we'll handle this as a specific case just for TX7 */ eNewType = psInfo->eSuperSectionType; } else if (strlen(pszLine) > 0 && !isspace(pszLine[0]) && !EQUALN(pszLine, "JABBERWOCKY", 11) && !EQUALN(pszLine, "EOI", 3) && ! ( psInfo->eSuperSectionType == AVCFileRPL && EQUALN(pszLine, " 0.00000", 6) ) ) { eNewType = psInfo->eSuperSectionType; } else if (strlen(pszLine) == 0 && psInfo->eSuperSectionType == AVCFileTX6) { eNewType = psInfo->eSuperSectionType; } else { eNewType = AVCFileUnknown; return AVCFileUnknown; } } /*----------------------------------------------------------------- * nCurObjectId is used to keep track of sequential ids that are * not explicitly stored in E00. e.g. polygon Id in a PAL section. *----------------------------------------------------------------*/ psInfo->nCurObjectId = 0; /*----------------------------------------------------------------- * Allocate a temp. structure to use to store the objects we read * (Using Calloc() will automatically initialize the struct contents * to NULL... this is very important for ARCs and PALs) *----------------------------------------------------------------*/ _AVCE00ParseDestroyCurObject(psInfo); if (eNewType == AVCFileARC) { psInfo->cur.psArc = (AVCArc*)CPLCalloc(1, sizeof(AVCArc)); } else if (eNewType == AVCFilePAL || eNewType == AVCFileRPL ) { psInfo->cur.psPal = (AVCPal*)CPLCalloc(1, sizeof(AVCPal)); } else if (eNewType == AVCFileCNT) { psInfo->cur.psCnt = (AVCCnt*)CPLCalloc(1, sizeof(AVCCnt)); } else if (eNewType == AVCFileLAB) { psInfo->cur.psLab = (AVCLab*)CPLCalloc(1, sizeof(AVCLab)); } else if (eNewType == AVCFileTOL) { psInfo->cur.psTol = (AVCTol*)CPLCalloc(1, sizeof(AVCTol)); } else if (eNewType == AVCFilePRJ) { psInfo->cur.papszPrj = NULL; } else if (eNewType == AVCFileTXT || eNewType == AVCFileTX6) { psInfo->cur.psTxt = (AVCTxt*)CPLCalloc(1, sizeof(AVCTxt)); } else if (eNewType == AVCFileRXP) { psInfo->cur.psRxp = (AVCRxp*)CPLCalloc(1, sizeof(AVCRxp)); } else if (eNewType == AVCFileTABLE) { psInfo->cur.pasFields = NULL; psInfo->hdr.psTableDef = NULL; psInfo->bTableHdrComplete = FALSE; } else { CPLError(CE_Failure, CPLE_NotSupported, "AVCE00ParseSectionHeader(): Unsupported file type!"); eNewType = AVCFileUnknown; } if (eNewType != AVCFileUnknown) { /*----------------------------------------------------------------- * Record the start of the section (for faster seeking) *----------------------------------------------------------------*/ psInfo->nStartLineNum = psInfo->nCurLineNum; /*----------------------------------------------------------------- * Keep track of section header line... this is used for some file * types, specially the ones enclosed inside supersections. *----------------------------------------------------------------*/ CPLFree(psInfo->pszSectionHdrLine); psInfo->pszSectionHdrLine = CPLStrdup(pszLine); } psInfo->eFileType = eNewType; return psInfo->eFileType; } /********************************************************************** * AVCE00ParseSectionEnd() * * Check if pszLine marks the end of the current section. * * Passing bResetParseInfo=TRUE will reset the parser struct if an end of * section is found. Passing FALSE simply tests for the end of section * without affecting the parse info struct. * * Return TRUE if this is the end of the section (and reset the * ParseInfo structure) , or FALSE otherwise. **********************************************************************/ GBool AVCE00ParseSectionEnd(AVCE00ParseInfo *psInfo, const char *pszLine, GBool bResetParseInfo) { if ( psInfo->bForceEndOfSection || ((psInfo->eFileType == AVCFileARC || psInfo->eFileType == AVCFilePAL || psInfo->eFileType == AVCFileLAB || psInfo->eFileType == AVCFileRPL || psInfo->eFileType == AVCFileCNT || psInfo->eFileType == AVCFileTOL || psInfo->eFileType == AVCFileTXT || psInfo->eFileType == AVCFileTX6 || psInfo->eFileType == AVCFileRXP ) && EQUALN(pszLine, " -1 0", 20) ) ) { /* Reset ParseInfo only if explicitly requested. */ if (bResetParseInfo) { _AVCE00ParseDestroyCurObject(psInfo); AVCE00ParseReset(psInfo); psInfo->eFileType = AVCFileUnknown; CPLFree(psInfo->pszSectionHdrLine); psInfo->pszSectionHdrLine = NULL; psInfo->bForceEndOfSection = FALSE; } return TRUE; /* YES, we reached the end */ } return FALSE; /* NO, it's not the end of section line */ } /********************************************************************** * AVCE00ParseNextLine() * * Take the next line of E00 input and parse it. * * Returns NULL if the current object is not complete yet (expecting * more lines of input) or a reference to a complete object if it * is complete. * * The returned object is a reference to an internal data structure. * It should not be modified or freed by the caller. * * If the input is invalid or other problems happen, then a CPLError() * will be generated. CPLGetLastErrorNo() should be called to check * that the line was parsed succesfully. * * Note for TABLES: * When parsing input from info tables, the first valid object that * will be returned will be the AVCTableDef, and then the data records * will follow. When all the records have been read, then the * psInfo->bForceEndOfSection flag will be set to TRUE since there is * no explicit "end of table" line in E00. **********************************************************************/ void *AVCE00ParseNextLine(AVCE00ParseInfo *psInfo, const char *pszLine) { void *psObj = NULL; CPLAssert(psInfo); switch(psInfo->eFileType) { case AVCFileARC: psObj = (void*)AVCE00ParseNextArcLine(psInfo, pszLine); break; case AVCFilePAL: case AVCFileRPL: psObj = (void*)AVCE00ParseNextPalLine(psInfo, pszLine); break; case AVCFileCNT: psObj = (void*)AVCE00ParseNextCntLine(psInfo, pszLine); break; case AVCFileLAB: psObj = (void*)AVCE00ParseNextLabLine(psInfo, pszLine); break; case AVCFileTOL: psObj = (void*)AVCE00ParseNextTolLine(psInfo, pszLine); break; case AVCFilePRJ: psObj = (void*)AVCE00ParseNextPrjLine(psInfo, pszLine); break; case AVCFileTXT: psObj = (void*)AVCE00ParseNextTxtLine(psInfo, pszLine); break; case AVCFileTX6: psObj = (void*)AVCE00ParseNextTx6Line(psInfo, pszLine); break; case AVCFileRXP: psObj = (void*)AVCE00ParseNextRxpLine(psInfo, pszLine); break; case AVCFileTABLE: if ( ! psInfo->bTableHdrComplete ) psObj = (void*)AVCE00ParseNextTableDefLine(psInfo, pszLine); else psObj = (void*)AVCE00ParseNextTableRecLine(psInfo, pszLine); break; default: CPLError(CE_Failure, CPLE_NotSupported, "AVCE00ParseNextLine(): Unsupported file type!"); } return psObj; } /********************************************************************** * AVCE00ParseNextArcLine() * * Take the next line of E00 input for an ARC object and parse it. * * Returns NULL if the current object is not complete yet (expecting * more lines of input) or a reference to a complete object if it * is complete. * * The returned object is a reference to an internal data structure. * It should not be modified or freed by the caller. * * If the input is invalid or other problems happen, then a CPLError() * will be generated. CPLGetLastErrorNo() should be called to check * that the line was parsed succesfully. **********************************************************************/ AVCArc *AVCE00ParseNextArcLine(AVCE00ParseInfo *psInfo, const char *pszLine) { AVCArc *psArc; int nLen; CPLAssert(psInfo->eFileType == AVCFileARC); psArc = psInfo->cur.psArc; nLen = strlen(pszLine); if (psInfo->numItems == 0) { /*------------------------------------------------------------- * Begin processing a new object, read header line: * ArcId, UserId, FNode, TNode, LPoly, RPoly, numVertices *------------------------------------------------------------*/ if (nLen < 70) { CPLError(CE_Failure, CPLE_AppDefined, "Error parsing E00 ARC line: \"%s\"", pszLine); return NULL; } else { psArc->nArcId = AVCE00Str2Int(pszLine, 10); psArc->nUserId = AVCE00Str2Int(pszLine+10, 10); psArc->nFNode = AVCE00Str2Int(pszLine+20, 10); psArc->nTNode = AVCE00Str2Int(pszLine+30, 10); psArc->nLPoly = AVCE00Str2Int(pszLine+40, 10); psArc->nRPoly = AVCE00Str2Int(pszLine+50, 10); psArc->numVertices = AVCE00Str2Int(pszLine+60, 10); /* Realloc the array of vertices */ psArc->pasVertices = (AVCVertex*)CPLRealloc(psArc->pasVertices, psArc->numVertices* sizeof(AVCVertex)); /* psInfo->iCurItem is the last vertex that was read. * psInfo->numItems is the number of vertices to read. */ psInfo->iCurItem = 0; psInfo->numItems = psArc->numVertices; } } else if (psInfo->iCurItem < psInfo->numItems && psInfo->nPrecision == AVC_SINGLE_PREC && ( (psInfo->iCurItem==psInfo->numItems-1 && nLen >= 28) || nLen >= 56 ) ) { /*------------------------------------------------------------- * Single precision ARCs: 2 pairs of X,Y values per line * Except on the last line with an odd number of vertices) *------------------------------------------------------------*/ psArc->pasVertices[psInfo->iCurItem].x = atof(pszLine); psArc->pasVertices[psInfo->iCurItem++].y = atof(pszLine+14); if (psInfo->iCurItem < psInfo->numItems && nLen >= 56) { psArc->pasVertices[psInfo->iCurItem].x = atof(pszLine+28); psArc->pasVertices[psInfo->iCurItem++].y = atof(pszLine+42); } } else if (psInfo->iCurItem < psInfo->numItems && psInfo->nPrecision == AVC_DOUBLE_PREC && nLen >= 42) { /*------------------------------------------------------------- * Double precision ARCs: 1 pair of X,Y values per line *------------------------------------------------------------*/ psArc->pasVertices[psInfo->iCurItem].x = atof(pszLine); psArc->pasVertices[psInfo->iCurItem++].y = atof(pszLine+21); } else { CPLError(CE_Failure, CPLE_AppDefined, "Error parsing E00 ARC line: \"%s\"", pszLine); psInfo->numItems = psInfo->iCurItem = 0; return NULL; } /*----------------------------------------------------------------- * If we're done parsing this ARC, then reset the ParseInfo, * and return a reference to the ARC structure * Otherwise return NULL, which means that we are expecting more * more lines of input. *----------------------------------------------------------------*/ if (psInfo->iCurItem >= psInfo->numItems) { psInfo->numItems = psInfo->iCurItem = 0; return psArc; } return NULL; } /********************************************************************** * AVCE00ParseNextPalLine() * * Take the next line of E00 input for an PAL object and parse it. * * Returns NULL if the current object is not complete yet (expecting * more lines of input) or a reference to a complete object if it * is complete. * * The returned object is a reference to an internal data structure. * It should not be modified or freed by the caller. * * If the input is invalid or other problems happen, then a CPLError() * will be generated. CPLGetLastErrorNo() should be called to check * that the line was parsed succesfully. **********************************************************************/ AVCPal *AVCE00ParseNextPalLine(AVCE00ParseInfo *psInfo, const char *pszLine) { AVCPal *psPal; int nLen; CPLAssert(psInfo->eFileType == AVCFilePAL || psInfo->eFileType == AVCFileRPL ); psPal = psInfo->cur.psPal; nLen = strlen(pszLine); if (psInfo->numItems == 0) { /*------------------------------------------------------------- * Begin processing a new object, read header line: * numArcs, MinX, MinY, MaxX, MaxY * For Double precision, MaxX, MaxY are on a separate line. *------------------------------------------------------------*/ if (nLen < 52) { CPLError(CE_Failure, CPLE_AppDefined, "Error parsing E00 PAL line: \"%s\"", pszLine); return NULL; } else { /* Polygon Id is not stored in the E00 file. Polygons are * stored in increasing order, starting at 1... so we just * increment the previous value. */ psPal->nPolyId = ++psInfo->nCurObjectId; psPal->numArcs = AVCE00Str2Int(pszLine, 10); /* If a PAL record has 0 arcs, it really has a single "0 0 0" * triplet as its data. */ if ( psPal->numArcs == 0 ) { psPal->numArcs = 1; } /* Realloc the array of Arcs */ psPal->pasArcs = (AVCPalArc*)CPLRealloc(psPal->pasArcs, psPal->numArcs* sizeof(AVCPalArc)); /* psInfo->iCurItem is the index of the last arc that was read. * psInfo->numItems is the number of arcs to read. */ psInfo->iCurItem = 0; psInfo->numItems = psPal->numArcs; if (psInfo->nPrecision == AVC_SINGLE_PREC) { psPal->sMin.x = atof(pszLine + 10); psPal->sMin.y = atof(pszLine + 24); psPal->sMax.x = atof(pszLine + 38); psPal->sMax.y = atof(pszLine + 52); } else { psPal->sMin.x = atof(pszLine + 10); psPal->sMin.y = atof(pszLine + 31); /* Set psInfo->iCurItem = -1 since we still have 2 values * from the header to read on the next line. */ psInfo->iCurItem = -1; } } } else if (psInfo->iCurItem == -1 && nLen >= 42) { psPal->sMax.x = atof(pszLine); psPal->sMax.y = atof(pszLine + 21); psInfo->iCurItem++; } else if (psInfo->iCurItem < psPal->numArcs && (nLen >= 60 || (psInfo->iCurItem == psPal->numArcs-1 && nLen >= 30)) ) { /*------------------------------------------------------------- * 2 PAL entries (ArcId, FNode, AdjPoly) per line, * (Except on the last line with an odd number of vertices) *------------------------------------------------------------*/ psPal->pasArcs[psInfo->iCurItem].nArcId = AVCE00Str2Int(pszLine, 10); psPal->pasArcs[psInfo->iCurItem].nFNode = AVCE00Str2Int(pszLine+10,10); psPal->pasArcs[psInfo->iCurItem++].nAdjPoly = AVCE00Str2Int(pszLine+20, 10); if (psInfo->iCurItem < psInfo->numItems) { psPal->pasArcs[psInfo->iCurItem].nArcId = AVCE00Str2Int(pszLine+30, 10); psPal->pasArcs[psInfo->iCurItem].nFNode = AVCE00Str2Int(pszLine+40, 10); psPal->pasArcs[psInfo->iCurItem++].nAdjPoly = AVCE00Str2Int(pszLine+50, 10); } } else { CPLError(CE_Failure, CPLE_AppDefined, "Error parsing E00 PAL line: \"%s\"", pszLine); psInfo->numItems = psInfo->iCurItem = 0; return NULL; } /*----------------------------------------------------------------- * If we're done parsing this PAL, then reset the ParseInfo, * and return a reference to the PAL structure * Otherwise return NULL, which means that we are expecting more * more lines of input. *----------------------------------------------------------------*/ if (psInfo->iCurItem >= psInfo->numItems) { psInfo->numItems = psInfo->iCurItem = 0; return psPal; } return NULL; } /********************************************************************** * AVCE00ParseNextCntLine() * * Take the next line of E00 input for an CNT object and parse it. * * Returns NULL if the current object is not complete yet (expecting * more lines of input) or a reference to a complete object if it * is complete. * * The returned object is a reference to an internal data structure. * It should not be modified or freed by the caller. * * If the input is invalid or other problems happen, then a CPLError() * will be generated. CPLGetLastErrorNo() should be called to check * that the line was parsed succesfully. **********************************************************************/ AVCCnt *AVCE00ParseNextCntLine(AVCE00ParseInfo *psInfo, const char *pszLine) { AVCCnt *psCnt; int nLen; CPLAssert(psInfo->eFileType == AVCFileCNT); psCnt = psInfo->cur.psCnt; nLen = strlen(pszLine); if (psInfo->numItems == 0) { /*------------------------------------------------------------- * Begin processing a new object, read header line: * numLabels, X, Y *------------------------------------------------------------*/ if (nLen < 38) { CPLError(CE_Failure, CPLE_AppDefined, "Error parsing E00 CNT line: \"%s\"", pszLine); return NULL; } else { /* Polygon Id is not stored in the E00 file. Centroids are * stored in increasing order of Polygon Id, starting at 1... * so we just increment the previous value. */ psCnt->nPolyId = ++psInfo->nCurObjectId; psCnt->numLabels = AVCE00Str2Int(pszLine, 10); /* Realloc the array of Labels Ids * Avoid allocating a 0-length segment since centroids can have * 0 labels attached to them. */ if (psCnt->numLabels > 0) psCnt->panLabelIds = (GInt32 *)CPLRealloc(psCnt->panLabelIds, psCnt->numLabels* sizeof(GInt32)); if (psInfo->nPrecision == AVC_SINGLE_PREC) { psCnt->sCoord.x = atof(pszLine + 10); psCnt->sCoord.y = atof(pszLine + 24); } else { psCnt->sCoord.x = atof(pszLine + 10); psCnt->sCoord.y = atof(pszLine + 31); } /* psInfo->iCurItem is the index of the last label that was read. * psInfo->numItems is the number of label ids to read. */ psInfo->iCurItem = 0; psInfo->numItems = psCnt->numLabels; } } else if (psInfo->iCurItem < psInfo->numItems ) { /*------------------------------------------------------------- * Each line can contain up to 8 label ids (10 chars each) *------------------------------------------------------------*/ int i=0; while(psInfo->iCurItem < psInfo->numItems && nLen >= (i+1)*10) { psCnt->panLabelIds[psInfo->iCurItem++] = AVCE00Str2Int(pszLine + i*10, 10); i++; } } else { CPLError(CE_Failure, CPLE_AppDefined, "Error parsing E00 CNT line: \"%s\"", pszLine); psInfo->numItems = psInfo->iCurItem = 0; return NULL; } /*----------------------------------------------------------------- * If we're done parsing this CNT, then reset the ParseInfo, * and return a reference to the CNT structure * Otherwise return NULL, which means that we are expecting more * more lines of input. *----------------------------------------------------------------*/ if (psInfo->iCurItem >= psInfo->numItems) { psInfo->numItems = psInfo->iCurItem = 0; return psCnt; } return NULL; } /********************************************************************** * AVCE00ParseNextLabLine() * * Take the next line of E00 input for an LAB object and parse it. * * Returns NULL if the current object is not complete yet (expecting * more lines of input) or a reference to a complete object if it * is complete. * * The returned object is a reference to an internal data structure. * It should not be modified or freed by the caller. * * If the input is invalid or other problems happen, then a CPLError() * will be generated. CPLGetLastErrorNo() should be called to check * that the line was parsed succesfully. **********************************************************************/ AVCLab *AVCE00ParseNextLabLine(AVCE00ParseInfo *psInfo, const char *pszLine) { AVCLab *psLab; int nLen; CPLAssert(psInfo->eFileType == AVCFileLAB); psLab = psInfo->cur.psLab; nLen = strlen(pszLine); if (psInfo->numItems == 0) { /*------------------------------------------------------------- * Begin processing a new object, read header line: * LabelValue, PolyId, X1, Y1 *------------------------------------------------------------*/ if (nLen < 48) { CPLError(CE_Failure, CPLE_AppDefined, "Error parsing E00 LAB line: \"%s\"", pszLine); return NULL; } else { psLab->nValue = AVCE00Str2Int(pszLine, 10); psLab->nPolyId = AVCE00Str2Int(pszLine+10, 10); if (psInfo->nPrecision == AVC_SINGLE_PREC) { psLab->sCoord1.x = atof(pszLine + 20); psLab->sCoord1.y = atof(pszLine + 34); } else { psLab->sCoord1.x = atof(pszLine + 20); psLab->sCoord1.y = atof(pszLine + 41); } /* psInfo->iCurItem is the index of the last X,Y pair we read. * psInfo->numItems is the number of X,Y pairs to read. */ psInfo->iCurItem = 1; psInfo->numItems = 3; } } else if (psInfo->iCurItem == 1 && psInfo->nPrecision == AVC_SINGLE_PREC && nLen >= 56 ) { psLab->sCoord2.x = atof(pszLine); psLab->sCoord2.y = atof(pszLine + 14); psLab->sCoord3.x = atof(pszLine + 28); psLab->sCoord3.y = atof(pszLine + 42); psInfo->iCurItem += 2; } else if (psInfo->iCurItem == 1 && psInfo->nPrecision == AVC_DOUBLE_PREC && nLen >= 42 ) { psLab->sCoord2.x = atof(pszLine); psLab->sCoord2.y = atof(pszLine + 21); psInfo->iCurItem++; } else if (psInfo->iCurItem == 2 && psInfo->nPrecision == AVC_DOUBLE_PREC && nLen >= 42 ) { psLab->sCoord3.x = atof(pszLine); psLab->sCoord3.y = atof(pszLine + 21); psInfo->iCurItem++; } else { CPLError(CE_Failure, CPLE_AppDefined, "Error parsing E00 LAB line: \"%s\"", pszLine); psInfo->numItems = psInfo->iCurItem = 0; return NULL; } /*----------------------------------------------------------------- * If we're done parsing this LAB, then reset the ParseInfo, * and return a reference to the LAB structure * Otherwise return NULL, which means that we are expecting more * more lines of input. *----------------------------------------------------------------*/ if (psInfo->iCurItem >= psInfo->numItems) { psInfo->numItems = psInfo->iCurItem = 0; return psLab; } return NULL; } /********************************************************************** * AVCE00ParseNextTolLine() * * Take the next line of E00 input for an TOL object and parse it. * * Returns NULL if the current object is not complete yet (expecting * more lines of input) or a reference to a complete object if it * is complete. * * The returned object is a reference to an internal data structure. * It should not be modified or freed by the caller. * * If the input is invalid or other problems happen, then a CPLError() * will be generated. CPLGetLastErrorNo() should be called to check * that the line was parsed succesfully. **********************************************************************/ AVCTol *AVCE00ParseNextTolLine(AVCE00ParseInfo *psInfo, const char *pszLine) { AVCTol *psTol; int nLen; CPLAssert(psInfo->eFileType == AVCFileTOL); psTol = psInfo->cur.psTol; nLen = strlen(pszLine); if (nLen >= 34) { /*------------------------------------------------------------- * TOL Entries are only one line each: * TolIndex, TolFlag, TolValue *------------------------------------------------------------*/ psTol->nIndex = AVCE00Str2Int(pszLine, 10); psTol->nFlag = AVCE00Str2Int(pszLine + 10, 10); psTol->dValue = atof(pszLine + 20); } else { CPLError(CE_Failure, CPLE_AppDefined, "Error parsing E00 TOL line: \"%s\"", pszLine); psInfo->numItems = psInfo->iCurItem = 0; return NULL; } /*----------------------------------------------------------------- * If we're done parsing this TOL, then reset the ParseInfo, * and return a reference to the TOL structure * Otherwise return NULL, which means that we are expecting more * more lines of input. *----------------------------------------------------------------*/ if (psInfo->iCurItem >= psInfo->numItems) { psInfo->numItems = psInfo->iCurItem = 0; return psTol; } return NULL; } /********************************************************************** * AVCE00ParseNextPrjLine() * * Take the next line of E00 input for a PRJ object and parse it. * * Returns NULL if the current object is not complete yet (expecting * more lines of input) or a reference to a complete object if it * is complete. * * Since a PRJ section contains only ONE projection, the function will * always return NULL, until it reaches the end-of-section (EOP) line. * This is behavior is a bit different from the other section types that * will usually return a valid object immediately before the last line * of the section (the end-of-section line). * * The returned object is a reference to an internal data structure. * It should not be modified or freed by the caller. * * If the input is invalid or other problems happen, then a CPLError() * will be generated. CPLGetLastErrorNo() should be called to check * that the line was parsed succesfully. **********************************************************************/ char **AVCE00ParseNextPrjLine(AVCE00ParseInfo *psInfo, const char *pszLine) { CPLAssert(psInfo->eFileType == AVCFilePRJ); /*------------------------------------------------------------- * Since a PRJ section contains only ONE projection, this function will * always return NULL until it reaches the end-of-section (EOP) line. * This is behavior is a bit different from the other section types that * will usually return a valid object immediately before the last line * of the section (the end-of-section line). *------------------------------------------------------------*/ if (EQUALN(pszLine, "EOP", 3)) { /*------------------------------------------------------------- * We reached end of section... return the PRJ. *------------------------------------------------------------*/ psInfo->bForceEndOfSection = TRUE; return psInfo->cur.papszPrj; } if ( pszLine[0] != '~' ) { /*------------------------------------------------------------- * This is a new line... add it to the papszPrj stringlist. *------------------------------------------------------------*/ psInfo->cur.papszPrj = CSLAddString(psInfo->cur.papszPrj, pszLine); } else if ( strlen(pszLine) > 1 ) { /*------------------------------------------------------------- * '~' is a line continuation char. Append what follows the '~' * to the end of the previous line. *------------------------------------------------------------*/ int iLastLine, nNewLen; iLastLine = CSLCount(psInfo->cur.papszPrj) - 1; nNewLen = strlen(psInfo->cur.papszPrj[iLastLine])+strlen(pszLine)-1+1; if (iLastLine >= 0) { psInfo->cur.papszPrj[iLastLine] = (char*)CPLRealloc(psInfo->cur.papszPrj[iLastLine], nNewLen * sizeof(char)); strcat(psInfo->cur.papszPrj[iLastLine], pszLine+1); } } return NULL; } /********************************************************************** * AVCE00ParseNextTxtLine() * * Take the next line of E00 input for an TXT object and parse it. * * Returns NULL if the current object is not complete yet (expecting * more lines of input) or a reference to a complete object if it * is complete. * * The returned object is a reference to an internal data structure. * It should not be modified or freed by the caller. * * If the input is invalid or other problems happen, then a CPLError() * will be generated. CPLGetLastErrorNo() should be called to check * that the line was parsed succesfully. **********************************************************************/ AVCTxt *AVCE00ParseNextTxtLine(AVCE00ParseInfo *psInfo, const char *pszLine) { AVCTxt *psTxt; int i, nLen, numFixedLines; CPLAssert(psInfo->eFileType == AVCFileTXT); psTxt = psInfo->cur.psTxt; nLen = strlen(pszLine); /* numFixedLines is the number of lines to expect before the line(s) * with the text string */ if (psInfo->nPrecision == AVC_SINGLE_PREC) numFixedLines = 4; else numFixedLines = 6; if (psInfo->numItems == 0) { /*------------------------------------------------------------- * Begin processing a new object, read header line: *------------------------------------------------------------*/ if (nLen < 50) { CPLError(CE_Failure, CPLE_AppDefined, "Error parsing E00 TXT line: \"%s\"", pszLine); return NULL; } else { int numVertices; /*--------------------------------------------------------- * With TXT, there are several unused fields that have to be * set to default values... usually 0. *--------------------------------------------------------*/ psTxt->nUserId = 0; psTxt->n28 = 0; for(i=0; i<20; i++) psTxt->anJust1[i] = psTxt->anJust2[i] = 0; psTxt->dV2 = psTxt->dV3 = 0.0; /*--------------------------------------------------------- * System Id is not stored in the E00 file. Annotations are * stored in increasing order of System Id, starting at 1... * so we just increment the previous value. *--------------------------------------------------------*/ psTxt->nTxtId = ++psInfo->nCurObjectId; psTxt->nLevel = AVCE00Str2Int(pszLine, 10); /* Add 1 to numVerticesLine because the first vertex is * always duplicated in the TXT binary structure... */ psTxt->numVerticesLine = AVCE00Str2Int(pszLine+10, 10) + 1; psTxt->numVerticesArrow= AVCE00Str2Int(pszLine+20, 10); psTxt->nSymbol = AVCE00Str2Int(pszLine+30, 10); psTxt->numChars = AVCE00Str2Int(pszLine+40, 10); /*--------------------------------------------------------- * Realloc the string buffer and array of vertices *--------------------------------------------------------*/ psTxt->pszText = (char *)CPLRealloc(psTxt->pszText, (psTxt->numChars+1)* sizeof(char)); numVertices = ABS(psTxt->numVerticesLine) + ABS(psTxt->numVerticesArrow); if (numVertices > 0) psTxt->pasVertices = (AVCVertex*)CPLRealloc(psTxt->pasVertices, numVertices*sizeof(AVCVertex)); /*--------------------------------------------------------- * Fill the whole string buffer with spaces we'll just * paste lines in it using strncpy() *--------------------------------------------------------*/ memset(psTxt->pszText, ' ', psTxt->numChars); psTxt->pszText[psTxt->numChars] = '\0'; /*--------------------------------------------------------- * psInfo->iCurItem is the index of the last line that was read. * psInfo->numItems is the number of lines to read. *--------------------------------------------------------*/ psInfo->iCurItem = 0; psInfo->numItems = numFixedLines + ((psTxt->numChars-1)/80 + 1); } } else if (psInfo->iCurItem < psInfo->numItems && psInfo->iCurItem < numFixedLines-1 && nLen >=63) { /*------------------------------------------------------------- * Then we have a set of 15 coordinate values... unused ones * are present but are set to 0.00E+00 * * Vals 1 to 4 are X coords of line along which text is drawn * Vals 5 to 8 are the corresponding Y coords * Vals 9 to 11 are the X coords of the text arrow * Vals 12 to 14 are the corresponding Y coords * The 15th value is the height * * Note that the first vertex (values 1 and 5) is duplicated * in the TXT structure... go wonder why??? *------------------------------------------------------------*/ int iCurCoord=0, numCoordPerLine, nItemSize, iVertex; if (psInfo->nPrecision == AVC_SINGLE_PREC) { numCoordPerLine = 5; nItemSize = 14; /* Num of chars for single precision float*/ } else { numCoordPerLine = 3; nItemSize = 21; /* Num of chars for double precision float*/ } iCurCoord = psInfo->iCurItem * numCoordPerLine; for(i=0; inumVerticesLine-1) { psTxt->pasVertices[iVertex+1].x = atof(pszLine+i*nItemSize); /* The first vertex is always duplicated */ if (iVertex == 0) psTxt->pasVertices[0].x = psTxt->pasVertices[1].x; } else if (iCurCoord >= 4 && iCurCoord < 8 && (iVertex = iCurCoord % 4) < psTxt->numVerticesLine-1) { psTxt->pasVertices[iVertex+1].y = atof(pszLine+i*nItemSize); /* The first vertex is always duplicated */ if (iVertex == 0) psTxt->pasVertices[0].y = psTxt->pasVertices[1].y; } else if (iCurCoord >= 8 && iCurCoord < 11 && (iVertex = (iCurCoord-8) % 3) < psTxt->numVerticesArrow) { psTxt->pasVertices[iVertex+psTxt->numVerticesLine].x = atof(pszLine+i*nItemSize); } else if (iCurCoord >= 11 && iCurCoord < 14 && (iVertex = (iCurCoord-8) % 3) < psTxt->numVerticesArrow) { psTxt->pasVertices[iVertex+psTxt->numVerticesLine].y = atof(pszLine+i*nItemSize); } else if (iCurCoord == 14) { psTxt->dHeight = atof(pszLine+i*nItemSize); } } psInfo->iCurItem++; } else if (psInfo->iCurItem < psInfo->numItems && psInfo->iCurItem == numFixedLines-1 && nLen >=14) { /*------------------------------------------------------------- * Line with a -1.000E+02 value, ALWAYS SINGLE PRECISION !!! *------------------------------------------------------------*/ psTxt->f_1e2 = (float)atof(pszLine); psInfo->iCurItem++; } else if (psInfo->iCurItem < psInfo->numItems && psInfo->iCurItem >= numFixedLines) { /*------------------------------------------------------------- * Last line, contains the text string * Note that text can be split in 80 chars chunk and that buffer * has been previously initialized with spaces and '\0'-terminated *------------------------------------------------------------*/ int numLines, iLine; numLines = (psTxt->numChars-1)/80 + 1; iLine = numLines - (psInfo->numItems - psInfo->iCurItem); if (iLine == numLines-1) { strncpy(psTxt->pszText+(iLine*80), pszLine, MIN( nLen, (psTxt->numChars - (iLine*80)) ) ); } else { strncpy(psTxt->pszText+(iLine*80), pszLine, MIN(nLen, 80)); } psInfo->iCurItem++; } else { CPLError(CE_Failure, CPLE_AppDefined, "Error parsing E00 TXT line: \"%s\"", pszLine); psInfo->numItems = psInfo->iCurItem = 0; return NULL; } /*----------------------------------------------------------------- * If we're done parsing this TXT, then reset the ParseInfo, * and return a reference to the TXT structure * Otherwise return NULL, which means that we are expecting more * more lines of input. *----------------------------------------------------------------*/ if (psInfo->iCurItem >= psInfo->numItems) { psInfo->numItems = psInfo->iCurItem = 0; return psTxt; } return NULL; } /********************************************************************** * AVCE00ParseNextTx6Line() * * Take the next line of E00 input for an TX6/TX7 object and parse it. * * Returns NULL if the current object is not complete yet (expecting * more lines of input) or a reference to a complete object if it * is complete. * * The returned object is a reference to an internal data structure. * It should not be modified or freed by the caller. * * If the input is invalid or other problems happen, then a CPLError() * will be generated. CPLGetLastErrorNo() should be called to check * that the line was parsed succesfully. **********************************************************************/ AVCTxt *AVCE00ParseNextTx6Line(AVCE00ParseInfo *psInfo, const char *pszLine) { AVCTxt *psTxt; int i, nLen; CPLAssert(psInfo->eFileType == AVCFileTX6); psTxt = psInfo->cur.psTxt; nLen = strlen(pszLine); if (psInfo->numItems == 0) { /*------------------------------------------------------------- * Begin processing a new object, read header line: *------------------------------------------------------------*/ if (nLen < 70) { CPLError(CE_Failure, CPLE_AppDefined, "Error parsing E00 TX6/TX7 line: \"%s\"", pszLine); return NULL; } else { int numVertices; /*--------------------------------------------------------- * System Id is not stored in the E00 file. Annotations are * stored in increasing order of System Id, starting at 1... * so we just increment the previous value. *--------------------------------------------------------*/ psTxt->nTxtId = ++psInfo->nCurObjectId; psTxt->nUserId = AVCE00Str2Int(pszLine, 10); psTxt->nLevel = AVCE00Str2Int(pszLine+10, 10); psTxt->numVerticesLine = AVCE00Str2Int(pszLine+20, 10); psTxt->numVerticesArrow= AVCE00Str2Int(pszLine+30, 10); psTxt->nSymbol = AVCE00Str2Int(pszLine+40, 10); psTxt->n28 = AVCE00Str2Int(pszLine+50, 10); psTxt->numChars = AVCE00Str2Int(pszLine+60, 10); /*--------------------------------------------------------- * Realloc the string buffer and array of vertices *--------------------------------------------------------*/ psTxt->pszText = (char *)CPLRealloc(psTxt->pszText, (psTxt->numChars+1)* sizeof(char)); numVertices = ABS(psTxt->numVerticesLine) + ABS(psTxt->numVerticesArrow); if (numVertices > 0) psTxt->pasVertices = (AVCVertex*)CPLRealloc(psTxt->pasVertices, numVertices*sizeof(AVCVertex)); /*--------------------------------------------------------- * Fill the whole string buffer with spaces we'll just * paste lines in it using strncpy() *--------------------------------------------------------*/ memset(psTxt->pszText, ' ', psTxt->numChars); psTxt->pszText[psTxt->numChars] = '\0'; /*--------------------------------------------------------- * psInfo->iCurItem is the index of the last line that was read. * psInfo->numItems is the number of lines to read. *--------------------------------------------------------*/ psInfo->iCurItem = 0; psInfo->numItems = 8 + numVertices + ((psTxt->numChars-1)/80 + 1); } } else if (psInfo->iCurItem < psInfo->numItems && psInfo->iCurItem < 6 && nLen >=60) { /*------------------------------------------------------------- * Text Justification stuff... 2 sets of 20 int16 values. *------------------------------------------------------------*/ GInt16 *pValue; int numValPerLine=7; if (psInfo->iCurItem < 3) pValue = psTxt->anJust2 + psInfo->iCurItem * 7; else pValue = psTxt->anJust1 + (psInfo->iCurItem-3) * 7; /* Last line of each set contains only 6 values instead of 7 */ if (psInfo->iCurItem == 2 || psInfo->iCurItem == 5) numValPerLine = 6; for(i=0; iiCurItem++; } else if (psInfo->iCurItem < psInfo->numItems && psInfo->iCurItem == 6 && nLen >=14) { /*------------------------------------------------------------- * Line with a -1.000E+02 value, ALWAYS SINGLE PRECISION !!! *------------------------------------------------------------*/ psTxt->f_1e2 = (float)atof(pszLine); psInfo->iCurItem++; } else if (psInfo->iCurItem < psInfo->numItems && psInfo->iCurItem == 7 && nLen >=42) { /*------------------------------------------------------------- * Line with 3 values, 1st value is text height. *------------------------------------------------------------*/ psTxt->dHeight = atof(pszLine); if (psInfo->nPrecision == AVC_SINGLE_PREC) { psTxt->dV2 = atof(pszLine+14); psTxt->dV3 = atof(pszLine+28); } else { psTxt->dV2 = atof(pszLine+21); psTxt->dV3 = atof(pszLine+42); } psInfo->iCurItem++; } else if (psInfo->iCurItem < (8 + ABS(psTxt->numVerticesLine) + ABS(psTxt->numVerticesArrow)) && nLen >= 28) { /*------------------------------------------------------------- * One line for each pair of X,Y coordinates * (Lines 8 to 8+numVertices-1) *------------------------------------------------------------*/ psTxt->pasVertices[ psInfo->iCurItem-8 ].x = atof(pszLine); if (psInfo->nPrecision == AVC_SINGLE_PREC) psTxt->pasVertices[ psInfo->iCurItem-8 ].y = atof(pszLine+14); else psTxt->pasVertices[ psInfo->iCurItem-8 ].y = atof(pszLine+21); psInfo->iCurItem++; } else if (psInfo->iCurItem < psInfo->numItems) { /*------------------------------------------------------------- * Last line, contains the text string * Note that text can be split in 80 chars chunk and that buffer * has been previously initialized with spaces and '\0'-terminated *------------------------------------------------------------*/ int numLines, iLine; numLines = (psTxt->numChars-1)/80 + 1; iLine = numLines - (psInfo->numItems - psInfo->iCurItem); if (iLine == numLines-1) { strncpy(psTxt->pszText+(iLine*80), pszLine, MIN( nLen, (psTxt->numChars - (iLine*80)) ) ); } else { strncpy(psTxt->pszText+(iLine*80), pszLine, MIN(nLen, 80)); } psInfo->iCurItem++; } else { CPLError(CE_Failure, CPLE_AppDefined, "Error parsing E00 TX6/TX7 line: \"%s\"", pszLine); psInfo->numItems = psInfo->iCurItem = 0; return NULL; } /*----------------------------------------------------------------- * If we're done parsing this TX6/TX7, then reset the ParseInfo, * and return a reference to the TXT structure * Otherwise return NULL, which means that we are expecting more * more lines of input. *----------------------------------------------------------------*/ if (psInfo->iCurItem >= psInfo->numItems) { psInfo->numItems = psInfo->iCurItem = 0; return psTxt; } return NULL; } /********************************************************************** * AVCE00ParseNextRxpLine() * * Take the next line of E00 input for an RXP object and parse it. * * Returns NULL if the current object is not complete yet (expecting * more lines of input) or a reference to a complete object if it * is complete. * * The returned object is a reference to an internal data structure. * It should not be modified or freed by the caller. * * If the input is invalid or other problems happen, then a CPLError() * will be generated. CPLGetLastErrorNo() should be called to check * that the line was parsed succesfully. **********************************************************************/ AVCRxp *AVCE00ParseNextRxpLine(AVCE00ParseInfo *psInfo, const char *pszLine) { AVCRxp *psRxp; int nLen; CPLAssert(psInfo->eFileType == AVCFileRXP); psRxp = psInfo->cur.psRxp; nLen = strlen(pszLine); if (nLen >= 20) { /*------------------------------------------------------------- * RXP Entries are only one line each: * Value1, Value2 (meaning of the value??? Don't know!!!) *------------------------------------------------------------*/ psRxp->n1 = AVCE00Str2Int(pszLine, 10); psRxp->n2 = AVCE00Str2Int(pszLine + 10, 10); } else { CPLError(CE_Failure, CPLE_AppDefined, "Error parsing E00 RXP line: \"%s\"", pszLine); psInfo->numItems = psInfo->iCurItem = 0; return NULL; } /*----------------------------------------------------------------- * If we're done parsing this RXP, then reset the ParseInfo, * and return a reference to the RXP structure * Otherwise return NULL, which means that we are expecting more * more lines of input. *----------------------------------------------------------------*/ if (psInfo->iCurItem >= psInfo->numItems) { psInfo->numItems = psInfo->iCurItem = 0; return psRxp; } return NULL; } /*===================================================================== TABLE stuff =====================================================================*/ /********************************************************************** * AVCE00ParseNextTableDefLine() * * Take the next line of E00 input for an TableDef object and parse it. * * Returns NULL if the current object is not complete yet (expecting * more lines of input) or a reference to a complete object if it * is complete. * * The returned object is a reference to an internal data structure. * It should not be modified or freed by the caller. * * If the input is invalid or other problems happen, then a CPLError() * will be generated. CPLGetLastErrorNo() should be called to check * that the line was parsed succesfully. **********************************************************************/ AVCTableDef *AVCE00ParseNextTableDefLine(AVCE00ParseInfo *psInfo, const char *pszLine) { AVCTableDef *psTableDef; int nLen; CPLAssert(psInfo->eFileType == AVCFileTABLE); psTableDef = psInfo->hdr.psTableDef; /* May be NULL on first call */ nLen = strlen(pszLine); if (psInfo->numItems == 0) { /*------------------------------------------------------------- * Begin processing a new TableDef. Read header line: * TableName, extFlag, numFields, RecSize, numRecords *------------------------------------------------------------*/ if (nLen < 56) { CPLError(CE_Failure, CPLE_AppDefined, "Error parsing E00 Table Definition line: \"%s\"", pszLine); return NULL; } else { /*--------------------------------------------------------- * Parse header line and alloc and init. a new psTableDef struct *--------------------------------------------------------*/ psTableDef = psInfo->hdr.psTableDef = (AVCTableDef*)CPLCalloc(1, sizeof(AVCTableDef)); psInfo->bTableHdrComplete = FALSE; strncpy(psTableDef->szTableName, pszLine, 32); psTableDef->szTableName[32] = '\0'; strncpy(psTableDef->szExternal, pszLine+32, 2); psTableDef->szExternal[2] = '\0'; psTableDef->numFields = AVCE00Str2Int(pszLine+34, 4); psTableDef->nRecSize = AVCE00Str2Int(pszLine+42, 4); psTableDef->numRecords = AVCE00Str2Int(pszLine+46, 10); /*--------------------------------------------------------- * Alloc array of fields defs, will be filled in further calls *--------------------------------------------------------*/ psTableDef->pasFieldDef = (AVCFieldInfo*)CPLCalloc(psTableDef->numFields, sizeof(AVCFieldInfo)); /*--------------------------------------------------------- * psInfo->iCurItem is the index of the last field def we read. * psInfo->numItems is the number of field defs to read, * including deleted ones. *--------------------------------------------------------*/ psInfo->numItems = AVCE00Str2Int(pszLine+38, 4); psInfo->iCurItem = 0; psInfo->nCurObjectId = 0; /* We'll use it as a field index */ } } else if (psInfo->iCurItem < psInfo->numItems && nLen >= 69 ) { /*------------------------------------------------------------- * Read an attribute field definition * If field index is -1, then we ignore this line... we do not * even count it in psInfo->iCurItem. *------------------------------------------------------------*/ int nIndex; nIndex = AVCE00Str2Int(pszLine + 65, 4); if (nIndex > 0 && psInfo->nCurObjectId >= psTableDef->numFields) { CPLError(CE_Failure, CPLE_AppDefined, "Error parsing E00 INFO Table Header: " "number of fields is invalid " "(expected %d, got at least %d)", psTableDef->numFields, psInfo->nCurObjectId+1); psInfo->numItems = psInfo->iCurItem = psInfo->nCurObjectId; return NULL; } if (nIndex > 0) { AVCFieldInfo *psDef; psDef = &(psTableDef->pasFieldDef[psInfo->iCurItem]); psDef->nIndex = nIndex; strncpy(psDef->szName, pszLine, 16); psDef->szName[16] = '\0'; psDef->nSize = AVCE00Str2Int(pszLine + 16, 3); psDef->v2 = AVCE00Str2Int(pszLine + 19, 2); psDef->nOffset = AVCE00Str2Int(pszLine + 21, 4); psDef->v4 = AVCE00Str2Int(pszLine + 25, 1); psDef->v5 = AVCE00Str2Int(pszLine + 26, 2); psDef->nFmtWidth= AVCE00Str2Int(pszLine + 28, 4); psDef->nFmtPrec = AVCE00Str2Int(pszLine + 32, 2); psDef->nType1 = AVCE00Str2Int(pszLine + 34, 3)/10; psDef->nType2 = AVCE00Str2Int(pszLine + 34, 3)%10; psDef->v10 = AVCE00Str2Int(pszLine + 37, 2); psDef->v11 = AVCE00Str2Int(pszLine + 39, 4); psDef->v12 = AVCE00Str2Int(pszLine + 43, 4); psDef->v13 = AVCE00Str2Int(pszLine + 47, 2); strncpy(psDef->szAltName, pszLine+49, 16); psDef->szAltName[16] = '\0'; psInfo->nCurObjectId++; } psInfo->iCurItem++; } else { CPLError(CE_Failure, CPLE_AppDefined, "Error parsing E00 Table Definition line: \"%s\"", pszLine); psInfo->numItems = psInfo->iCurItem = 0; return NULL; } /*----------------------------------------------------------------- * If we're done parsing this TableDef, then reset the ParseInfo, * and return a reference to the TableDef structure. * Next calls should go to AVCE00ParseNextTableRecLine() to * read data records. * Otherwise return NULL, which means that we are expecting more * more lines of input. *----------------------------------------------------------------*/ if (psInfo->iCurItem >= psInfo->numItems) { psInfo->numItems = psInfo->iCurItem = 0; psInfo->nCurObjectId = 0; psInfo->bTableHdrComplete = TRUE; /*--------------------------------------------------------- * It is possible to have a table with 0 records... in this * case we are already at the end of the section for that table. *--------------------------------------------------------*/ if (psTableDef->numRecords == 0) psInfo->bForceEndOfSection = TRUE; return psTableDef; } return NULL; } /********************************************************************** * _AVCE00ParseTableRecord() * * Parse the record data present inside psInfo->pszBuf and fill and * return the psInfo->cur.pasFields[]. * * This function should not be called directly... it is used by * AVCE00ParseNextTableRecLine(). **********************************************************************/ static AVCField *_AVCE00ParseTableRecord(AVCE00ParseInfo *psInfo) { AVCField *pasFields; AVCFieldInfo *pasDef; AVCTableDef *psTableDef; int i, nType, nSize; char *pszBuf, szTmp[30]; pasFields = psInfo->cur.pasFields; psTableDef = psInfo->hdr.psTableDef; pasDef = psTableDef->pasFieldDef; pszBuf = psInfo->pszBuf; for(i=0; inumFields; i++) { nType = pasDef[i].nType1*10; nSize = pasDef[i].nSize; if (nType == AVC_FT_DATE || nType == AVC_FT_CHAR || nType == AVC_FT_FIXINT ) { strncpy(pasFields[i].pszStr, pszBuf, nSize); pasFields[i].pszStr[nSize] = '\0'; pszBuf += nSize; } else if (nType == AVC_FT_FIXNUM) { /* TYPE 40 attributes are stored with 1 byte per digit * in binary format, and as single precision floats in * E00 tables, even in double precision coverages. */ const char *pszTmpStr; strncpy(szTmp, pszBuf, 14); szTmp[14] = '\0'; pszBuf += 14; /* Compensate for a very odd behavior observed in some E00 files. * A type 40 field can be written in decimal format instead of * exponent format, but in this case the decimal point is shifted * one position to the right, resulting in a value 10 times bigger * than expected. So if the value is not in exponent format then * we should shift the decimal point to the left before we * interpret it. (bug 599) */ if (!strchr(szTmp, 'E') && !strchr(szTmp, 'e')) { char *pszTmp; if ( (pszTmp=strchr(szTmp, '.')) != NULL && pszTmp != szTmp ) { *pszTmp = *(pszTmp-1); *(pszTmp-1) = '.'; } } /* We use nSize and nFmtPrec for the format because nFmtWidth can * be different from nSize, but nSize has priority since it * is the actual size of the field in memory. */ pszTmpStr = CPLSPrintf("%*.*f", nSize, pasDef[i].nFmtPrec, atof(szTmp)); /* If value is bigger than size, then it's too bad... we * truncate it... but this should never happen in clean datasets. */ if ((int)strlen(pszTmpStr) > nSize) pszTmpStr = pszTmpStr + strlen(pszTmpStr) - nSize; strncpy(pasFields[i].pszStr, pszTmpStr, nSize); pasFields[i].pszStr[nSize] = '\0'; } else if (nType == AVC_FT_BININT && nSize == 4) { pasFields[i].nInt32 = AVCE00Str2Int(pszBuf, 11); pszBuf += 11; } else if (nType == AVC_FT_BININT && nSize == 2) { pasFields[i].nInt16 = AVCE00Str2Int(pszBuf, 6); pszBuf += 6; } else if (nType == AVC_FT_BINFLOAT && pasDef[i].nSize == 4) { /* NOTE: The E00 representation for a binary float is * defined by its binary size, not by the coverage's * precision. */ strncpy(szTmp, pszBuf, 14); szTmp[14] = '\0'; pasFields[i].fFloat = (float)atof(szTmp); pszBuf += 14; } else if (nType == AVC_FT_BINFLOAT && pasDef[i].nSize == 8) { /* NOTE: The E00 representation for a binary float is * defined by its binary size, not by the coverage's * precision. */ strncpy(szTmp, pszBuf, 24); szTmp[24] = '\0'; pasFields[i].dDouble = atof(szTmp); pszBuf += 24; } else { /*----------------------------------------------------- * Hummm... unsupported field type... *----------------------------------------------------*/ CPLError(CE_Failure, CPLE_NotSupported, "_AVCE00ParseTableRecord(): Unsupported field type " "(type=%d, size=%d)", nType, pasDef[i].nSize); return NULL; } } CPLAssert(pszBuf == psInfo->pszBuf + psInfo->nTableE00RecLength); return pasFields; } /********************************************************************** * AVCE00ParseNextTableRecLine() * * Take the next line of E00 input for an Table data record and parse it. * * Returns NULL if the current record is not complete yet (expecting * more lines of input) or a reference to a complete record if it * is complete. * * The returned record is a reference to an internal data structure. * It should not be modified or freed by the caller. * * If the input is invalid or other problems happen, then a CPLError() * will be generated. CPLGetLastErrorNo() should be called to check * that the line was parsed succesfully. **********************************************************************/ AVCField *AVCE00ParseNextTableRecLine(AVCE00ParseInfo *psInfo, const char *pszLine) { AVCField *pasFields = NULL; AVCTableDef *psTableDef; int i; CPLAssert(psInfo->eFileType == AVCFileTABLE); psTableDef = psInfo->hdr.psTableDef; if (psInfo->bForceEndOfSection || psTableDef->numFields == 0 || psTableDef->numRecords == 0) { psInfo->bForceEndOfSection = TRUE; return NULL; } /*----------------------------------------------------------------- * On the first call for a new table, we have some allocations to * do: * - make sure the psInfo->szBuf is big enough to hold one complete * E00 data record. * - Alloc the array of Field values (psInfo->cur.pasFields[]) * for the number of fields in this table. *----------------------------------------------------------------*/ if (psInfo->numItems == 0 && psInfo->nCurObjectId == 0) { /*------------------------------------------------------------- * Realloc E00 buffer *------------------------------------------------------------*/ psInfo->nTableE00RecLength = _AVCE00ComputeRecSize(psTableDef->numFields, psTableDef->pasFieldDef, FALSE); if (psInfo->nBufSize < psInfo->nTableE00RecLength + 1) { psInfo->nBufSize = psInfo->nTableE00RecLength + 1; psInfo->pszBuf = (char*)CPLRealloc(psInfo->pszBuf, psInfo->nBufSize); } /*--------------------------------------------------------- * Alloc psInfo->cur.pasFields[] * Also alloc buffers for string attributes. *--------------------------------------------------------*/ psInfo->cur.pasFields = (AVCField*)CPLCalloc(psTableDef->numFields, sizeof(AVCField)); for(i=0; inumFields; i++) { if (psTableDef->pasFieldDef[i].nType1*10 == AVC_FT_DATE || psTableDef->pasFieldDef[i].nType1*10 == AVC_FT_CHAR || psTableDef->pasFieldDef[i].nType1*10 == AVC_FT_FIXINT || psTableDef->pasFieldDef[i].nType1*10 == AVC_FT_FIXNUM ) { psInfo->cur.pasFields[i].pszStr = (char*)CPLCalloc(psTableDef->pasFieldDef[i].nSize+1, sizeof(char)); } } } if (psInfo->numItems == 0) { /*----------------------------------------------------------------- * Begin processing a new record... we'll accumulate the 80 * chars lines until we have the whole record in our buffer * and parse it only at the end. * Lines shorter than 80 chars are legal, and in this case * they will be padded with spaces up to 80 chars. *----------------------------------------------------------------*/ /*--------------------------------------------------------- * First fill the whole record buffer with spaces we'll just * paste lines in it using strncpy() *--------------------------------------------------------*/ memset(psInfo->pszBuf, ' ', psInfo->nTableE00RecLength); psInfo->pszBuf[psInfo->nTableE00RecLength] = '\0'; /*--------------------------------------------------------- * psInfo->iCurItem is the number of chars buffered so far. * psInfo->numItems is the number of chars to expect in one record. *--------------------------------------------------------*/ psInfo->numItems = psInfo->nTableE00RecLength; psInfo->iCurItem = 0; } if (psInfo->iCurItem < psInfo->numItems) { /*------------------------------------------------------------- * Continue to accumulate the 80 chars lines until we have * the whole record in our buffer. We'll parse it only at the end. * Lines shorter than 80 chars are legal, and in this case * they padded with spaces up to 80 chars. *------------------------------------------------------------*/ int nSrcLen, nLenToCopy; nSrcLen = strlen(pszLine); nLenToCopy = MIN(80, MIN(nSrcLen,(psInfo->numItems-psInfo->iCurItem))); strncpy(psInfo->pszBuf+psInfo->iCurItem, pszLine, nLenToCopy); psInfo->iCurItem+=80; } if (psInfo->iCurItem >= psInfo->numItems) { /*------------------------------------------------------------- * OK, we've got one full record in the buffer... parse it and * return the pasFields[] *------------------------------------------------------------*/ pasFields = _AVCE00ParseTableRecord(psInfo); if (pasFields == NULL) { CPLError(CE_Failure, CPLE_AppDefined, "Error parsing E00 Table Record: \"%s\"", psInfo->pszBuf); return NULL; } psInfo->numItems = psInfo->iCurItem = 0; psInfo->nCurObjectId++; } /*----------------------------------------------------------------- * Since there is no explicit "end of table" line, we set the * bForceEndOfSection flag when the last record is read. *----------------------------------------------------------------*/ if (psInfo->nCurObjectId >= psTableDef->numRecords) { psInfo->bForceEndOfSection = TRUE; } return pasFields; } avce00-2.0.0/cpl_string.c0100664000076400007640000006215210247751547014406 0ustar danieldaniel/********************************************************************** * $Id: cpl_string.c,v 1.3 2005/06/03 03:49:59 daniel Exp $ * * Name: cpl_string.cpp * Project: CPL - Common Portability Library * Purpose: String and Stringlist manipulation functions. * Author: Daniel Morissette, dmorissette@dmsolutions.ca * ********************************************************************** * Copyright (c) 1998, Daniel Morissette * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ********************************************************************** * * $Log: cpl_string.c,v $ * Revision 1.3 2005/06/03 03:49:59 daniel * Update email address, website url, and copyright dates * * Revision 1.2 1999/10/29 06:10:29 daniel * Updated cpl_string.* * * Revision 1.10 1999/06/26 14:05:10 warmerda * Added CSLFindString(). * * Revision 1.9 1999/04/28 02:33:02 danmo * CSLInsertStrings(): make sure papszStrList is NULL-terminated properly * * Revision 1.8 1999/03/12 21:19:49 danmo * Fixed TokenizeStringComplex() vs strings ending with empty token, * and fixed a problem with CSLAdd/SetNameValue() vs empty string list. * * Revision 1.7 1999/03/09 21:29:57 warmerda * Added backslash escaping within string constants for tokenize function. * * Revision 1.6 1999/02/25 04:40:46 danmo * Modif. CSLLoad() to use CPLReadLine() (better handling of newlines) * * Revision 1.5 1999/02/17 01:41:58 warmerda * Added CSLGetField * * Revision 1.4 1998/12/15 19:01:40 warmerda * *** empty log message *** * * Revision 1.3 1998/12/05 23:04:21 warmerda * Use EQUALN() instead of strincmp() which doesn't exist on Linux. * * Revision 1.2 1998/12/04 21:40:42 danmo * Added more Name=Value manipulation fuctions * * Revision 1.1 1998/12/03 18:26:02 warmerda * New * **********************************************************************/ #include "cpl_string.h" #include "cpl_vsi.h" /*===================================================================== StringList manipulation functions. =====================================================================*/ /********************************************************************** * CSLAddString() * * Append a string to a StringList and return a pointer to the modified * StringList. * If the input StringList is NULL, then a new StringList is created. **********************************************************************/ char **CSLAddString(char **papszStrList, const char *pszNewString) { int nItems=0; if (pszNewString == NULL) return papszStrList; /* Nothing to do!*/ /* Allocate room for the new string */ if (papszStrList == NULL) papszStrList = (char**) CPLCalloc(2,sizeof(char*)); else { nItems = CSLCount(papszStrList); papszStrList = (char**)CPLRealloc(papszStrList, (nItems+2)*sizeof(char*)); } /* Copy the string in the list */ papszStrList[nItems] = CPLStrdup(pszNewString); papszStrList[nItems+1] = NULL; return papszStrList; } /********************************************************************** * CSLCount() * * Return the number of lines in a Stringlist. **********************************************************************/ int CSLCount(char **papszStrList) { int nItems=0; if (papszStrList) { while(*papszStrList != NULL) { nItems++; papszStrList++; } } return nItems; } /************************************************************************/ /* CSLGetField() */ /* */ /* Fetches the indicated field, being careful not to crash if */ /* the field doesn't exist within this string list. The */ /* returned pointer should not be freed, and doesn't */ /* necessarily last long. */ /************************************************************************/ const char * CSLGetField( char ** papszStrList, int iField ) { int i; if( papszStrList == NULL || iField < 0 ) return( "" ); for( i = 0; i < iField+1; i++ ) { if( papszStrList[i] == NULL ) return ""; } return( papszStrList[iField] ); } /********************************************************************** * CSLDestroy() * * Free all memory used by a StringList. **********************************************************************/ void CSLDestroy(char **papszStrList) { char **papszPtr; if (papszStrList) { papszPtr = papszStrList; while(*papszPtr != NULL) { CPLFree(*papszPtr); papszPtr++; } CPLFree(papszStrList); } } /********************************************************************** * CSLDuplicate() * * Allocate and return a copy of a StringList. **********************************************************************/ char **CSLDuplicate(char **papszStrList) { char **papszNewList, **papszSrc, **papszDst; int nLines; nLines = CSLCount(papszStrList); if (nLines == 0) return NULL; papszNewList = (char **)CPLMalloc((nLines+1)*sizeof(char*)); papszSrc = papszStrList; papszDst = papszNewList; while(*papszSrc != NULL) { *papszDst = CPLStrdup(*papszSrc); papszSrc++; papszDst++; } *papszDst = NULL; return papszNewList; } /********************************************************************** * CSLLoad() * * Load a test file into a stringlist. * * Lines are limited in length by the size fo the CPLReadLine() buffer. **********************************************************************/ char **CSLLoad(const char *pszFname) { FILE *fp; const char *pszLine; char **papszStrList=NULL; fp = VSIFOpen(pszFname, "rt"); if (fp) { while(!VSIFEof(fp)) { if ( (pszLine = CPLReadLine(fp)) != NULL ) { papszStrList = CSLAddString(papszStrList, pszLine); } } VSIFClose(fp); } else { /* Unable to open file */ CPLError(CE_Failure, CPLE_OpenFailed, "CSLLoad(%s): %s", pszFname, strerror(errno)); } return papszStrList; } /********************************************************************** * CSLSave() * * Write a stringlist to a text file. * * Returns the number of lines written, or 0 if the file could not * be written. **********************************************************************/ int CSLSave(char **papszStrList, const char *pszFname) { FILE *fp; int nLines=0; if (papszStrList) { if ((fp = VSIFOpen(pszFname, "wt")) != NULL) { while(*papszStrList != NULL) { if (VSIFPuts(*papszStrList, fp) == EOF || VSIFPutc('\n', fp) == EOF) { CPLError(CE_Failure, CPLE_FileIO, "CSLSave(%s): %s", pszFname, strerror(errno)); break; /* A Problem happened... abort */ } nLines++; papszStrList++; } VSIFClose(fp); } else { /* Unable to open file */ CPLError(CE_Failure, CPLE_OpenFailed, "CSLSave(%s): %s", pszFname, strerror(errno)); } } return nLines; } /********************************************************************** * CSLPrint() * * Print a StringList to fpOut. If fpOut==NULL, then output is sent * to stdout. * * Returns the number of lines printed. **********************************************************************/ int CSLPrint(char **papszStrList, FILE *fpOut) { int nLines=0; if (fpOut == NULL) fpOut = stdout; if (papszStrList) { while(*papszStrList != NULL) { VSIFPrintf(fpOut, "%s\n", *papszStrList); nLines++; papszStrList++; } } return nLines; } /********************************************************************** * CSLInsertStrings() * * Copies the contents of a StringList inside another StringList * before the specified line. * * nInsertAtLineNo is a 0-based line index before which the new strings * should be inserted. If this value is -1 or is larger than the actual * number of strings in the list then the strings are added at the end * of the source StringList. * * Returns the modified StringList. **********************************************************************/ char **CSLInsertStrings(char **papszStrList, int nInsertAtLineNo, char **papszNewLines) { int i, nSrcLines, nDstLines, nToInsert; char **ppszSrc, **ppszDst; if (papszNewLines == NULL || ( nToInsert = CSLCount(papszNewLines) ) == 0) return papszStrList; /* Nothing to do!*/ nSrcLines = CSLCount(papszStrList); nDstLines = nSrcLines + nToInsert; /* Allocate room for the new strings */ papszStrList = (char**)CPLRealloc(papszStrList, (nDstLines+1)*sizeof(char*)); /* Make sure the array is NULL-terminated... it may not be if * papszStrList was NULL before Realloc() */ papszStrList[nSrcLines] = NULL; /* Make some room in the original list at the specified location * Note that we also have to move the NULL pointer at the end of * the source StringList. */ if (nInsertAtLineNo == -1 || nInsertAtLineNo > nSrcLines) nInsertAtLineNo = nSrcLines; ppszSrc = papszStrList + nSrcLines; ppszDst = papszStrList + nDstLines; for (i=nSrcLines; i>=nInsertAtLineNo; i--) { *ppszDst = *ppszSrc; ppszDst--; ppszSrc--; } /* Copy the strings to the list */ ppszSrc = papszNewLines; ppszDst = papszStrList + nInsertAtLineNo; for (; *ppszSrc != NULL; ppszSrc++, ppszDst++) { *ppszDst = CPLStrdup(*ppszSrc); } return papszStrList; } /********************************************************************** * CSLInsertString() * * Insert a string at a given line number inside a StringList * * nInsertAtLineNo is a 0-based line index before which the new string * should be inserted. If this value is -1 or is larger than the actual * number of strings in the list then the string is added at the end * of the source StringList. * * Returns the modified StringList. **********************************************************************/ char **CSLInsertString(char **papszStrList, int nInsertAtLineNo, char *pszNewLine) { char *apszList[2]; /* Create a temporary StringList and call CSLInsertStrings() */ apszList[0] = pszNewLine; apszList[1] = NULL; return CSLInsertStrings(papszStrList, nInsertAtLineNo, apszList); } /********************************************************************** * CSLRemoveStrings() * * Remove strings inside a StringList * * nFirstLineToDelete is the 0-based line index of the first line to * remove. If this value is -1 or is larger than the actual * number of strings in list then the nNumToRemove last strings are * removed. * * If ppapszRetStrings != NULL then the deleted strings won't be * free'd, they will be stored in a new StringList and the pointer to * this new list will be returned in *ppapszRetStrings. * * Returns the modified StringList. **********************************************************************/ char **CSLRemoveStrings(char **papszStrList, int nFirstLineToDelete, int nNumToRemove, char ***ppapszRetStrings) { int i, nSrcLines, nDstLines; char **ppszSrc, **ppszDst; nSrcLines = CSLCount(papszStrList); nDstLines = nSrcLines - nNumToRemove; if (nNumToRemove < 1 || nSrcLines == 0) return papszStrList; /* Nothing to do!*/ /* If operation will result in an empty StringList then don't waste * time here! */ if (nDstLines < 1) { CSLDestroy(papszStrList); return NULL; } /* Remove lines from the source StringList... * Either free() each line or store them to a new StringList depending on * the caller's choice. */ ppszDst = papszStrList + nFirstLineToDelete; if (ppapszRetStrings == NULL) { /* free() all the strings that will be removed. */ for (i=0; i < nNumToRemove; i++) { CPLFree(*ppszDst); *ppszDst = NULL; } } else { /* Store the strings to remove in a new StringList */ *ppapszRetStrings = (char **)CPLCalloc(nNumToRemove+1, sizeof(char*)); for (i=0; i < nNumToRemove; i++) { (*ppapszRetStrings)[i] = *ppszDst; *ppszDst = NULL; ppszDst++; } } /* Shift down all the lines that follow the lines to remove. */ if (nFirstLineToDelete == -1 || nFirstLineToDelete > nSrcLines) nFirstLineToDelete = nDstLines; ppszSrc = papszStrList + nFirstLineToDelete + nNumToRemove; ppszDst = papszStrList + nFirstLineToDelete; for ( ; *ppszSrc != NULL; ppszSrc++, ppszDst++) { *ppszDst = *ppszSrc; } /* Move the NULL pointer at the end of the StringList */ *ppszDst = *ppszSrc; /* At this point, we could realloc() papszStrList to a smaller size, but * since this array will likely grow again in further operations on the * StringList we'll leave it as it is. */ return papszStrList; } /************************************************************************/ /* CSLFindString() */ /* */ /* Find a string within a string list. The string must match */ /* the full length, but the comparison is case insensitive. */ /* Return -1 on failure. */ /************************************************************************/ int CSLFindString( char ** papszList, const char * pszTarget ) { int i; if( papszList == NULL ) return -1; for( i = 0; papszList[i] != NULL; i++ ) { if( EQUAL(papszList[i],pszTarget) ) return i; } return -1; } /********************************************************************** * CSLTokenizeString() * * Tokenizes a string and returns a StringList with one string for * each token. **********************************************************************/ char **CSLTokenizeString( const char *pszString ) { return CSLTokenizeStringComplex( pszString, " ", TRUE, FALSE ); } /************************************************************************/ /* CSLTokenizeStringComplex() */ /* */ /* The ultimate tokenizer? */ /************************************************************************/ char ** CSLTokenizeStringComplex( const char * pszString, const char * pszDelimiters, int bHonourStrings, int bAllowEmptyTokens ) { char **papszRetList = NULL; char *pszToken; int nTokenMax, nTokenLen; pszToken = (char *) CPLCalloc(10,1); nTokenMax = 10; while( pszString != NULL && *pszString != '\0' ) { int bInString = FALSE; nTokenLen = 0; /* Try to find the next delimeter, marking end of token */ for( ; *pszString != '\0'; pszString++ ) { /* End if this is a delimeter skip it and break. */ if( !bInString && strchr(pszDelimiters, *pszString) != NULL ) { pszString++; break; } /* If this is a quote, and we are honouring constant strings, then process the constant strings, with out delim but don't copy over the quotes */ if( bHonourStrings && *pszString == '"' ) { if( bInString ) { bInString = FALSE; continue; } else { bInString = TRUE; continue; } } /* Within string constants we allow for escaped quotes, but in processing them we will unescape the quotes */ if( bInString && pszString[0] == '\\' && pszString[1] == '"' ) { pszString++; } /* Within string constants a \\ sequence reduces to \ */ else if( bInString && pszString[0] == '\\' && pszString[1] == '\\' ) { pszString++; } if( nTokenLen >= nTokenMax-1 ) { nTokenMax = nTokenMax * 2 + 10; pszToken = (char *) CPLRealloc( pszToken, nTokenMax ); } pszToken[nTokenLen] = *pszString; nTokenLen++; } pszToken[nTokenLen] = '\0'; if( pszToken[0] != '\0' || bAllowEmptyTokens ) { papszRetList = CSLAddString( papszRetList, pszToken ); } /* If the last token is an empty token, then we have to catch * it now, otherwise we won't reenter the loop and it will be lost. */ if ( *pszString == '\0' && bAllowEmptyTokens && strchr(pszDelimiters, *(pszString-1)) ) { papszRetList = CSLAddString( papszRetList, "" ); } } if( papszRetList == NULL ) papszRetList = (char **) CPLCalloc(sizeof(char *),1); CPLFree( pszToken ); return papszRetList; } /********************************************************************** * CPLSPrintf() * * My own version of CPLSPrintf() that works with a static buffer. * * It returns a ref. to a static buffer that should not be freed and * is valid only until the next call to CPLSPrintf(). * * NOTE: This function should move to cpl_conv.cpp. **********************************************************************/ /* For now, assume that a 8000 chars buffer will be enough. */ #define CPLSPrintf_BUF_SIZE 8000 static char gszCPLSPrintfBuffer[CPLSPrintf_BUF_SIZE]; const char *CPLSPrintf(char *fmt, ...) { va_list args; va_start(args, fmt); vsprintf(gszCPLSPrintfBuffer, fmt, args); va_end(args); return gszCPLSPrintfBuffer; } /********************************************************************** * CSLAppendPrintf() * * Use CPLSPrintf() to append a new line at the end of a StringList. * * Returns the modified StringList. **********************************************************************/ char **CSLAppendPrintf(char **papszStrList, char *fmt, ...) { va_list args; va_start(args, fmt); vsprintf(gszCPLSPrintfBuffer, fmt, args); va_end(args); return CSLAddString(papszStrList, gszCPLSPrintfBuffer); } /********************************************************************** * CSLFetchNameValue() * * In a StringList of "Name=Value" pairs, look for the * first value associated with the specified name. The search is not * case sensitive. * ("Name:Value" pairs are also supported for backward compatibility * with older stuff.) * * Returns a reference to the value in the StringList that the caller * should not attempt to free. * * Returns NULL if the name is not found. **********************************************************************/ const char *CSLFetchNameValue(char **papszStrList, const char *pszName) { int nLen; if (papszStrList == NULL || pszName == NULL) return NULL; nLen = strlen(pszName); while(*papszStrList != NULL) { if (EQUALN(*papszStrList, pszName, nLen) && ( (*papszStrList)[nLen] == '=' || (*papszStrList)[nLen] == ':' ) ) { return (*papszStrList)+nLen+1; } papszStrList++; } return NULL; } /********************************************************************** * CSLFetchNameValueMultiple() * * In a StringList of "Name=Value" pairs, look for all the * values with the specified name. The search is not case * sensitive. * ("Name:Value" pairs are also supported for backward compatibility * with older stuff.) * * Returns stringlist with one entry for each occurence of the * specified name. The stringlist should eventually be destroyed * by calling CSLDestroy(). * * Returns NULL if the name is not found. **********************************************************************/ char **CSLFetchNameValueMultiple(char **papszStrList, const char *pszName) { int nLen; char **papszValues = NULL; if (papszStrList == NULL || pszName == NULL) return NULL; nLen = strlen(pszName); while(*papszStrList != NULL) { if (EQUALN(*papszStrList, pszName, nLen) && ( (*papszStrList)[nLen] == '=' || (*papszStrList)[nLen] == ':' ) ) { papszValues = CSLAddString(papszValues, (*papszStrList)+nLen+1); } papszStrList++; } return papszValues; } /********************************************************************** * CSLAddNameValue() * * Add a new entry to a StringList of "Name=Value" pairs, * ("Name:Value" pairs are also supported for backward compatibility * with older stuff.) * * This function does not check if a "Name=Value" pair already exists * for that name and can generate multiple entryes for the same name. * Use CSLSetNameValue() if you want each name to have only one value. * * Returns the modified stringlist. **********************************************************************/ char **CSLAddNameValue(char **papszStrList, const char *pszName, const char *pszValue) { const char *pszLine; if (pszName == NULL || pszValue==NULL) return papszStrList; pszLine = CPLSPrintf("%s=%s", pszName, pszValue); return CSLAddString(papszStrList, pszLine); } /********************************************************************** * CSLSetNameValue() * * Set the value for a given name in a StringList of "Name=Value" pairs * ("Name:Value" pairs are also supported for backward compatibility * with older stuff.) * * If there is already a value for that name in the list then the value * is changed, otherwise a new "Name=Value" pair is added. * * Returns the modified stringlist. **********************************************************************/ char **CSLSetNameValue(char **papszList, const char *pszName, const char *pszValue) { char **papszPtr; int nLen; if (pszName == NULL || pszValue==NULL) return papszList; nLen = strlen(pszName); papszPtr = papszList; while(papszPtr && *papszPtr != NULL) { if (EQUALN(*papszPtr, pszName, nLen) && ( (*papszPtr)[nLen] == '=' || (*papszPtr)[nLen] == ':' ) ) { /* Found it! * Change the value... make sure to keep the ':' or '=' */ char cSep; cSep = (*papszPtr)[nLen]; free(*papszPtr); *papszPtr = CPLStrdup(CPLSPrintf("%s%c%s", pszName, cSep, pszValue)); return papszList; } papszPtr++; } /* The name does not exist yet... create a new entry */ return CSLAddString(papszList, CPLSPrintf("%s=%s", pszName, pszValue)); } avce00-2.0.0/dbfopen.h0100664000076400007640000001434307164202461013651 0ustar danieldaniel#ifndef _SHAPEFILE_H_INCLUDED #define _SHAPEFILE_H_INCLUDED /* NOTE: This file (dbfopen.h) is a copy of shapefil.h (described below) * in which only the DBF-related stuff was kept to include it in * the AVCE00 library. */ /****************************************************************************** * $Id: dbfopen.h,v 1.2 2000/09/26 20:21:05 daniel Exp $ * * Project: Shapelib * Purpose: Primary include file for Shapelib. * Author: Frank Warmerdam, warmerda@home.com * ****************************************************************************** * Copyright (c) 1999, Frank Warmerdam * * This software is available under the following "MIT Style" license, * or at the option of the licensee under the LGPL (see LICENSE.LGPL). This * option is discussed in more detail in shapelib.html. * * -- * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ****************************************************************************** * * $Log: dbfopen.h,v $ * Revision 1.2 2000/09/26 20:21:05 daniel * Added AVCCoverPC write * * Revision 1.1 1999/12/24 07:16:41 daniel * Checked into AVCE00 lib + Added DBFGetNativeFieldType() * * Revision 1.14 1999/11/05 14:12:05 warmerda * updated license terms * * Revision 1.13 1999/06/02 18:24:21 warmerda * added trimming code * * Revision 1.12 1999/06/02 17:56:12 warmerda * added quad'' subnode support for trees * * Revision 1.11 1999/05/18 19:11:11 warmerda * Added example searching capability * * Revision 1.10 1999/05/18 17:49:38 warmerda * added initial quadtree support * * Revision 1.9 1999/05/11 03:19:28 warmerda * added new Tuple api, and improved extension handling - add from candrsn * * Revision 1.8 1999/03/23 17:22:27 warmerda * Added extern "C" protection for C++ users of shapefil.h. * * Revision 1.7 1998/12/31 15:31:07 warmerda * Added the TRIM_DBF_WHITESPACE and DISABLE_MULTIPATCH_MEASURE options. * * Revision 1.6 1998/12/03 15:48:15 warmerda * Added SHPCalculateExtents(). * * Revision 1.5 1998/11/09 20:57:16 warmerda * Altered SHPGetInfo() call. * * Revision 1.4 1998/11/09 20:19:33 warmerda * Added 3D support, and use of SHPObject. * * Revision 1.3 1995/08/23 02:24:05 warmerda * Added support for reading bounds. * * Revision 1.2 1995/08/04 03:17:39 warmerda * Added header. * */ #include #ifdef USE_DBMALLOC #include #endif #ifdef __cplusplus extern "C" { #endif /************************************************************************/ /* Configuration options. */ /************************************************************************/ /* -------------------------------------------------------------------- */ /* Should the DBFReadStringAttribute() strip leading and */ /* trailing white space? */ /* -------------------------------------------------------------------- */ /* Note: For AVCE00 purposes, we do not want the spaces to be stripped. * * #define TRIM_DBF_WHITESPACE */ /************************************************************************/ /* DBF Support. */ /************************************************************************/ typedef struct { FILE *fp; int nRecords; int nRecordLength; int nHeaderLength; int nFields; int *panFieldOffset; int *panFieldSize; int *panFieldDecimals; char *pachFieldType; char *pszHeader; int nCurrentRecord; int bCurrentRecordModified; char *pszCurrentRecord; int bNoHeader; int bUpdated; } DBFInfo; typedef DBFInfo * DBFHandle; typedef enum { FTString, FTInteger, FTDouble, FTInvalid } DBFFieldType; #define XBASE_FLDHDR_SZ 32 DBFHandle DBFOpen( const char * pszDBFFile, const char * pszAccess ); DBFHandle DBFCreate( const char * pszDBFFile ); int DBFGetFieldCount( DBFHandle psDBF ); int DBFGetRecordCount( DBFHandle psDBF ); int DBFAddField( DBFHandle hDBF, const char * pszFieldName, DBFFieldType eType, int nWidth, int nDecimals ); DBFFieldType DBFGetFieldInfo( DBFHandle psDBF, int iField, char * pszFieldName, int * pnWidth, int * pnDecimals ); char DBFGetNativeFieldType( DBFHandle psDBF, int iField ); int DBFReadIntegerAttribute( DBFHandle hDBF, int iShape, int iField ); double DBFReadDoubleAttribute( DBFHandle hDBF, int iShape, int iField ); const char *DBFReadStringAttribute( DBFHandle hDBF, int iShape, int iField ); int DBFWriteIntegerAttribute( DBFHandle hDBF, int iShape, int iField, int nFieldValue ); int DBFWriteDoubleAttribute( DBFHandle hDBF, int iShape, int iField, double dFieldValue ); int DBFWriteStringAttribute( DBFHandle hDBF, int iShape, int iField, const char * pszFieldValue ); int DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField, void * pValue ); const char *DBFReadTuple(DBFHandle psDBF, int hEntity ); int DBFWriteTuple(DBFHandle psDBF, int hEntity, void * pRawTuple ); DBFHandle DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename ); void DBFClose( DBFHandle hDBF ); #ifdef __cplusplus } #endif #endif /* ndef _SHAPEFILE_H_INCLUDED */ avce00-2.0.0/cpl_error.h0100775000076400007640000001007310247751547014234 0ustar danieldaniel/********************************************************************** * $Id: cpl_error.h,v 1.2 2005/06/03 03:49:59 daniel Exp $ * * Name: cpl_error.h * Project: CPL - Common Portability Library * Purpose: CPL Error handling * Author: Daniel Morissette, dmorissette@dmsolutions.ca * ********************************************************************** * Copyright (c) 1998, Daniel Morissette * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ********************************************************************** * * $Log: cpl_error.h,v $ * Revision 1.2 2005/06/03 03:49:59 daniel * Update email address, website url, and copyright dates * * Revision 1.1 1999/08/27 14:09:55 daniel * Update CPL files * * Revision 1.9 1999/07/23 14:27:47 warmerda * CPLSetErrorHandler returns old handler * * Revision 1.8 1999/05/20 14:59:05 warmerda * added CPLDebug() * * Revision 1.7 1999/05/20 02:54:38 warmerda * Added API documentation * * Revision 1.6 1999/02/17 05:40:47 danmo * Fixed CPLAssert() macro to work with EGCS. * * Revision 1.5 1999/01/11 15:34:29 warmerda * added reserved range comment * * Revision 1.4 1998/12/15 19:02:27 warmerda * Avoid use of errno as a variable * * Revision 1.3 1998/12/06 22:20:42 warmerda * Added error code. * * Revision 1.2 1998/12/06 02:52:52 warmerda * Implement assert support * * Revision 1.1 1998/12/03 18:26:02 warmerda * New * **********************************************************************/ #ifndef _CPL_ERROR_H_INCLUDED_ #define _CPL_ERROR_H_INCLUDED_ #include "cpl_port.h" /*===================================================================== Error handling functions (cpl_error.c) =====================================================================*/ /** * \file cpl_error.h * * CPL error handling services. */ CPL_C_START typedef enum { CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4 } CPLErr; void CPL_DLL CPLError(CPLErr eErrClass, int err_no, const char *fmt, ...); void CPL_DLL CPLErrorReset(); int CPL_DLL CPLGetLastErrorNo(); const char CPL_DLL * CPLGetLastErrorMsg(); typedef void (*CPLErrorHandler)(CPLErr, int, const char*); CPLErrorHandler CPL_DLL CPLSetErrorHandler(CPLErrorHandler); void CPL_DLL CPLDebug( const char *, const char *, ... ); void CPL_DLL _CPLAssert( const char *, const char *, int ); #ifdef DEBUG # define CPLAssert(expr) ((expr) ? (void)(0) : _CPLAssert(#expr,__FILE__,__LINE__)) #else # define CPLAssert(expr) #endif CPL_C_END /* ==================================================================== */ /* Well known error codes. */ /* ==================================================================== */ #define CPLE_None 0 #define CPLE_AppDefined 1 #define CPLE_OutOfMemory 2 #define CPLE_FileIO 3 #define CPLE_OpenFailed 4 #define CPLE_IllegalArg 5 #define CPLE_NotSupported 6 #define CPLE_AssertionFailed 7 #define CPLE_NoWriteAccess 8 /* 100 - 299 reserved for GDAL */ #endif /* _CPL_ERROR_H_INCLUDED_ */ avce00-2.0.0/makefile.vc0100664000076400007640000000543207400265437014176 0ustar danieldaniel# # makefile.vc - AVCE00 library makefile # # This VC++ makefile will build AVCE00.LIB and CPL.LIB, and also build the # "AVCIMPORT", "AVCEXPORT", and "AVCDELETE" programs. # # To use the makefile: # - Open a DOS prompt window # - Run the VCVARS32.BAT script to initialize the VC++ environment variables # - Start the build with: nmake /f makefile.vc # # $Id: makefile.vc,v 1.7 2001/11/25 22:05:19 daniel Exp $ # INC = OPTFLAGS= /Zi /nologo /W3 # # In some cases, AVCE00DeleteCoverage() fails because the coverage directory # could be locked by another application on the same system or somewhere on # the network. # Uncomment the following line to define AVC_IGNORE_RMDIR_ERROR at compile # time if you want this error to be ignored. # # OPTFLAGS = $(OPTFLAGS) -DAVC_IGNORE_RMDIR_ERROR # # Due to the odd way that fields of type 40 are handled in E00, you will # start to lose some digits of precision with fields bugger than 8 digits when # exporting to E00. Define AVC_MAP_TYPE40_TO_DOUBLE to ask the AVC lib to # automatically remap fields of type 40 bigger than 8 digits to double # precision floats while writing E00. Double precision floats can carry up # to 18 digits of precision. # #OPTFLAGS = $(OPTFLAGS) -DAVC_MAP_TYPE40_TO_DOUBLE CFLAGS = -DWIN32 $(OPTFLAGS) $(INC) $(EXTRAFLAGS) MAKE = nmake /nologo CC = cl # # Define 2 libraries: # $(AVCLIB) contains all the stuff specific to reading/writing coverages # $(CPLLIB) contains utility functions shared by several libraries # AVCLIB = avce00.lib AVC_OBJS= avc_e00read.obj avc_e00write.obj avc_rawbin.obj avc_bin.obj \ avc_binwr.obj avc_e00gen.obj avc_e00parse.obj avc_misc.obj \ avc_mbyte.obj dbfopen.obj AVC_HDRS= avc.h avc_mbyte.h dbfopen.h CPLLIB = cpl.lib CPL_OBJS= cpl_error.obj cpl_conv.obj cpl_vsisimple.obj cpl_string.obj \ cpl_dir.obj CPL_HDRS= cpl_conv.h cpl_port.h cpl_error.h cpl_string.h cpl_vsi.h LIBS = $(AVCLIB) $(CPLLIB) default: $(LIBS) avcimport.exe avcexport.exe avctest.exe avcdelete.exe \ ex_avcwrite.exe $(AVC_OBJS): $(AVC_HDRS) $(CPL_HDRS) $(AVCLIB): $(AVC_OBJS) lib /out:$(AVCLIB) $(AVC_OBJS) $(CPL_OBJS): $(CPL_HDRS) $(CPLLIB): $(CPL_OBJS) lib /out:$(CPLLIB) $(CPL_OBJS) avcimport.exe: avcimport.c $(LIBS) $(CC) $(CFLAGS) avcimport.c $(LIBS) avcexport.exe: avcexport.c $(LIBS) $(CC) $(CFLAGS) avcexport.c $(LIBS) avcdelete.exe: avcdelete.c $(LIBS) $(CC) $(CFLAGS) avcdelete.c $(LIBS) avctest.exe: avctest.c $(LIBS) $(CC) $(CFLAGS) avctest.c $(LIBS) ex_avcwrite.exe: ex_avcwrite.c $(LIBS) $(CC) $(CFLAGS) ex_avcwrite.c $(LIBS) testmulti.exe: testmulti.c $(LIBS) $(CC) $(CFLAGS) testmulti.c commode.obj $(LIBS) clean: del *.obj del $(AVCLIB) del $(CPLLIB) del *.exe del *.pdb del *.exp del *.ilk .c.obj: $(CC) $(CFLAGS) /c $*.c .cpp.obj: $(CC) $(CFLAGS) /c $*.cpp avce00-2.0.0/avce00.html0100664000076400007640000011123210471146411014017 0ustar danieldaniel

AVCE00 - Arc/Info Vector Coverage <-> E00 Library

AVCE00 - 2.0.0

Arc/Info Vector Coverage <-> E00 Library

By Daniel Morissette, dmorissette@mapgears.com


The latest version of this documentation and of the whole package can be obtained from http://avce00.maptools.org/

Table of Contents

Copyright and License terms

Copyright (c) 1999-2005, Daniel Morissette

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

What is AVCE00?

AVCE00 is an ANSI C library that makes Arc/Info binary coverages appear as ASCII E00. It can be used to read existing binary coverages or create new ones. The library has been designed in a way that it can be easily plugged into an existing E00 translator that you want to extend to support binary coverages.

In read mode, AVCE00 reads an Arc/Info binary coverage and makes it appear as an ASCII E00 files. In other words, you use the library to open a binary coverage for reading, and you read from it one line at a time just like if you had opened the ASCII E00 file corresponding to this coverage.

In write mode AVCE00 takes E00 lines as input and writes the result to a binary coverage. When you use the library for writing you create a new binary coverage and write E00 lines to it... the library takes care of converting the E00 to binary coverage format and to create all the necessary coverage and info files.

Note: Writing to existing coverages (i.e. update) is not supported. You can only read existing coverages, or create new ones using the current version of the library.

This package contains 4 major components:

For the GIS users:

  • The 'avcexport' command-line program reads a binary coverage and converts it to a file in E00 format.

  • The 'avcimport' command-line program takes a E00 file as input and creates a binary coverage from it.

For the GIS developers:

  • A simple set of C library functions that make a binary coverage appear as an ASCII E00 file. These functions read a binary coverage and return a stream of E00 lines, making the coverage appear as an E00 file.

  • Another set of C functions that can create a binary coverage from an E00 input. You write E00 lines (one line at a time) using these functions, and the E00 input is written as a binary coverage.

And for those who are really looking for trouble: ;-)
The read and write library can also be divided into sub-components that are not documented here but could be used as standalone components in other translators:

  • A set of library functions that read binary coverage files directly into structures in memory. This part could eventually be used as a base for a translator that converts binary coverage files to another format, or even to allow random access to the files in a coverage.

  • A set of library functions that write to binary coverage files directly from structures in memory.

  • A set of library functions that generate E00 lines from these same structures in memory. These functions could be used as a base for a translator that generates E00 files from another format.

  • A set of library functions that parse E00 lines and generate the appropriate structures in memory. These functions could be used as a base for a translator that converts E00 files to another format.

Supported Coverage Features

Since the coverage file's format is not documented by ESRI, this library is based on the analysis of binary dumps of the files... this implies that support for some features may be incomplete (or even inaccurate!) in some cases. Of course, it is expected that the lib. will evolve as we (the whole GIS community) learn more about the format.

The following Arc/Info features are expected to be properly converted from binary to E00 format, for both single and double precision coverages:

  • ARC (arc.adf) - Arcs
  • CNT (cnt.adf) - Polygon Centroids
  • LAB (lab.adf) - Polygon Labels
  • PAL (pal.adf) - Polygon Arc Lists
  • TOL (tol.adf, par.adf) - Coverage Tolerances
  • TXT/TX6/TX7 (txt.adf, *.txt) - Annotations
  • PRJ (prj.adf) - Projection
  • RXP/RPL (*.rxp, *.pal) - Files specific to region coverages
  • INFO Tables (info directory) - Attribute tables of any type (.AAT, .PAT, .NAT, .TIC, .BND, .TAT, .SEC, .RAT, etc... as well as internal tables)

If you use the library and encounter unsupported features, then please report the problem and I'll try to add support for that new case... this will just make the whole library better!

Using the 'avcexport' Conversion Program

'avcexport' is a command-line executable that takes an Arc/Info binary coverage as input and converts it to E00.

    avcexport <input_cover> <output_file>

    • input_cover is the path to the Arc/Info coverage to read from.

    • output_file is the name of the E00 file to create. If the file already exists then it is overwritten.
      Passing "-" as output_file will send the output to standard output (stdout).

Using the 'avcimport' Conversion Program

'avcimport' is a command-line executable that takes an Arc/Info E00 file as input and converts it to a binary coverage.

    avcimport <input_file> <output_cover>

    • input_file is the name of the E00 file to read from.
      Passing "-" as input_file will take the input from standard input (stdin).

    • output_cover is the path to the Arc/Info coverage to create. The program cannot write to (or overwrite) an existing coverage, so you have to make sure that the coverage name does not already exist.

Building the package

The library has already been succesfully built on Windows (with MSVC++), and on Linux (with gcc).

Windows users:

    Note: Precompiled executables for WIN32 are available on the library's web page at http://avce00.maptools.org/. So if all you need is the AVCIMPORT and AVCEXPORT programs then you should get them from there.

    For the developers using MSVC++, a NMAKE makefile (makefile.vc) to build the library and the 'avcexport.exe' and 'avcimport.exe' command-line programs is included with the distribution.

    To build the package using the makefile and NMAKE: open a DOS prompt window, run the VCVARS32.BAT script to initialize the VC++ environment variables, and start the build with the command: nmake /f makefile.vc

    Another option is to build a project in your development environment. Include the following files in your project for the library:

      avc.h
      cpl_error.h
      cpl_conv.h
      cpl_port.h
      cpl_string.h
      cpl_vsi.h

      avc_e00read.c
      avc_bin.c
      avc_rawbin.c
      avc_e00gen.c
      avc_e00write.c
      avc_binwr.c
      avc_e00parse.c
      avc_misc.c
      cpl_error.c
      cpl_conv.c
      cpl_string.c
      cpl_vsisimple.c
      cpl_dir.c

    And the main() function for the AVCEXPORT and AVCIMPORT programs are located in the files:

      avcexport.c
      avcimport.c

Unix users:

    A GNUmakefile is included with the distribution. Its default target will build the 'e00export' and 'e00import' executables using gcc. Take a look at the definitions at the top of the Makefile to see if you need to modify it to build in your own environment.

    An important flag to set in the Makefile is the byte ordering flag. The Makefile's default behavior is to build for systems with LSB first (Intel ordering). If you are building the library on a platform with MSB first (on a SUN for instance) then you will need to define the CPL_MSB flag in the Makefile.

    In most cases, building the package should be as simple as extracting the distribution files to a empty directory, and then going to this directory and typing make.

    If you encounter problems with the Makefile, then make sure that it contains Unix line breaks. The line breaks are sometimes altered when the distribution is copied between PCs and Unix systems, and make doesn't seem to like Makefiles that contain DOS CR-LF line breaks.

How to use the library in your programs


Note: If you are not planning to use the library in your programs,
then you can stop reading here...
the rest of this document won't be of any use to you!

To use the library in your programs, include the file "avc.h", and link with the "avc.a" library produced by the Unix Makefile.

If you are working in a Windows development environment (i.e. with projects, no Makefiles!) then include the C files from the library in your project. See the section about building the library for Windows above for the list of files to include.

Library functions to read a coverage as if it was an E00 file

Information about the file currently being read is stored inside an internal structure. You do not need to understand the contents of this structure to use the library.

All you need is to declare a AVCE00ReadPtr variable which will serve as a handle on the input file for all the other functions.

You use the following functions to read a coverage as a ASCII E00 file:

    AVCE00ReadPtr  AVCE00ReadOpen(const char *pszCoveragePath);
    void           AVCE00ReadClose(AVCE00ReadPtr hInfo);

    const char    *AVCE00ReadNextLine(AVCE00ReadPtr hInfo);
    void           AVCE00ReadRewind(AVCE00ReadPtr hInfo);

You can also optionally use the 2 following functions to go directly to the files that are of interest for you in the coverage:

    AVCE00Section  *AVCE00ReadSectionsList(AVCE00ReadPtr hInfo, 
                                           int *numSect);
    int             AVCE00ReadGotoSection(AVCE00ReadPtr hInfo, 
                                          AVCE00Section *psSect,
                                          GBool bContinue);

Each function is described after the example below.

Example:

    This short example uses the library to read the coverage in "data/cover1/" and convert it to E00 on stdout.

    /**********************************************************************
     * This example program illustrates the use of the AVCE00ReadOpen()
     * and associated AVC -> E00 read functions.
     **********************************************************************/
    
    #include <stdio.h>
    
    #include "avc.h"
    
    int main(int argc, char *argv[])
    {
        AVCE00ReadPtr hReadInfo;
        const char    *pszLine;
    
        /* Open input */
        hReadInfo = AVCE00ReadOpen("data/cover1/");
    
        if (hReadInfo)
        {
            /* Read lines from input until we reach EOF */
            while ((pszLine = AVCE00ReadNextLine(hReadInfo)) != NULL)
            {
                if (CPLGetLastErrorNo() == 0)
                    printf("%s\n", pszLine);
                else
                {
                    /* An error happened while reading this line... */
                    break;
                }
            }
    
            /* Close input file */
            AVCE00ReadClose(hReadInfo);
        }
        else
        {
            /* ERROR ... failed to open input file */
        }
    
        return 0;
    }
      

AVCE00ReadPtr data type

    A variable of type AVCE00ReadPtr serves as a handle on the current input file.

    The handle is allocated by AVCE00ReadOpen(), and you must call AVCE00ReadClose() to properly release the memory associated with it.

AVCE00ReadOpen()

    AVCE00ReadPtr  AVCE00ReadOpen(const char *pszCoverPath);

    Open a Arc/Info coverage to read it as if it was an E00 file.

    You can either pass the name of the coverage directory, or the path to one of the files in the coverage directory. The name of the coverage MUST be included in pszCoverPath... this means that passing "." is invalid.

    Since version 1.4.0 it is also possible to pass the path to the info directory to AVCE00ReadOpen(). In this case, a E00 stream with all the info tables (and no coverage data) will be returned.

    The following are all valid values for pszCoverPath:

                    /home/data/country
                    /home/data/country/
                    /home/data/country/arc.adf
                    /home/data/info
                    /home/data/info/arc.dir
    
    (Of course you should replace the '/' with '\\' on DOS systems!)

    Returns a new AVCE00ReadPtr handle or NULL if the coverage could not be opened or if it does not appear to be a valid Arc/Info coverage.

    The handle will eventually have to be released with AVCE00ReadClose().

AVCE00ReadClose()

    void           AVCE00ReadClose(AVCE00ReadPtr hInfo);

    Closes the coverage and releases any memory associated with the AVCE00ReadPtr handle.

AVCE00ReadNextLine()

    const char    *AVCE00ReadNextLine(AVCE00ReadPtr hInfo);

    Returns the next line of the E00 representation of the coverage or NULL when there are no more lines to generate, or if an error happened. The returned line is a null-terminated string, and it does not include a newline character.

    Call CPLGetLastErrorNo() after calling AVCE00ReadNextLine() to make sure that the line was generated succesfully.

    Note that AVCE00ReadNextLine() returns a reference to an internal buffer whose contents will be valid only until the next call to this function. The caller should not attempt to free() the returned pointer.

AVCE00ReadRewind()

    int            AVCE00ReadRewind(AVCE00ReadPtr hInfo);

    Rewinds the AVCE00ReadPtr just like the stdio rewind() function would do if you were reading an ASCII E00 file. Useful when you have to do multiple read passes on the same coverage.

    Returns 0 on success, or -1 on error.

AVCE00ReadSectionsList()

    AVCE00Section  *AVCE00ReadSectionsList(AVCE00ReadPtr hInfo, 
                                           int *numSect);
    

    Returns an array of AVCE00Section structures that describe the squeleton of the whole coverage, with each E00 section corresponding to one file from the coverage. The value of *numSect will be set to the number of items in the array.

    The AVCE00Section structure is defined in "avc.h" as:

        typedef struct AVCE00Section_t 
        {
            AVCFileType eType;     /* File Type          */
            char        *pszName;  /* File or Table Name */
        }AVCE00Section;
    
    And AVCFileType defines the type of the file associated with a given E00 section:
        typedef enum
        {
            AVCFileUnknown = 0,
            AVCFileARC,
            AVCFilePAL,
            AVCFileCNT,
            AVCFileLAB,
            AVCFilePRJ,
            AVCFileTOL,
            AVCFileLOG,
            AVCFileTABLE
        }AVCFileType;
    

    You can scan the returned array and use AVCE00ReadGotoSection() to move the read pointer directly to the beginning of a given section of the file.

    Sections of type AVCFileUnknown correspond to lines in the E00 output that are not directly linked to any file, like the "EXP 0" line, the "IFO X", "SIN X", etc.

    THE RETURNED ARRAY IS AN INTERNAL STRUCTURE AND SHOULD NOT BE MODIFIED OR FREED BY THE CALLER... its contents will be valid for as long as the coverage will remain open.

    Example: The array of sections returned for a coverage with valid polygon topology could take the following form:

    numSections = 17
    Sect[0]:  eType = AVCFileUnknown  pszName = "EXP  0"
    Sect[1]:  eType = AVCFileARC      pszName = "arc.adf"
    Sect[2]:  eType = AVCFilePAL      pszName = "pal.adf"
    Sect[3]:  eType = AVCFileCNT      pszName = "cnt.adf"
    Sect[4]:  eType = AVCFileLAB      pszName = "lab.adf"
    Sect[5]:  eType = AVCFileTOL      pszName = "tol.adf"
    Sect[6]:  eType = AVCFileUnknown  pszName = "SIN  2"
    Sect[7]:  eType = AVCFileUnknown  pszName = "EOX"
    Sect[8]:  eType = AVCFilePRJ      pszName = "prj.adf"
    Sect[9]:  eType = AVCFileUnknown  pszName = "IFO  2"
    Sect[10]: eType = AVCFileTABLE    pszName = "TEST.AAT                        "
    Sect[11]: eType = AVCFileTABLE    pszName = "TEST.PAT                        "
    Sect[12]: eType = AVCFileTABLE    pszName = "TEST.NAT                        "
    Sect[13]: eType = AVCFileTABLE    pszName = "TEST.BND                        "
    Sect[14]: eType = AVCFileTABLE    pszName = "TEST.TIC                        "
    Sect[15]: eType = AVCFileUnknown  pszName = "EOI"
    Sect[16]: eType = AVCFileUnknown  pszName = "EOS"
    

AVCE00ReadGotoSection()

    int             AVCE00ReadGotoSection(AVCE00ReadPtr hInfo, 
                                          AVCE00Section *psSect,
                                          GBool bContinue);
    

    Moves the read pointer to the beginning of the E00 section (coverage file) described in the psSect structure. Call AVCE00ReadListSections() to get the list of sections for the current coverage.

    If bContinue=TRUE, then reading will automatically continue with the next sections of the file once the requested section is finished. Otherwise, if bContinue=FALSE then reading will stop at the end of this section (i.e. AVCE00ReadNextLine() will return NULL when it reaches the end of this section)

    Sections of type AVCFileUnknown returned by AVCE00ReadListSections() correspond to lines in the E00 output that are not directly linked to any coverage file, like the "EXP 0" line, the "IFO X", "SIN X", etc. You can jump to these sections or any other one without problems.

    This function returns 0 on success or -1 on error.

    Example: The following function would look for a .AAT table in a coverage and convert it to E00.

    /**********************************************************************
     *                          ConvertAATonly()
     *
     * Look for a .AAT table in the coverage, and if we find one then 
     * convert it to E00 on stdout.
     **********************************************************************/
    static void ConvertAATOnly(const char *pszFname)
    {
        AVCE00ReadPtr   hReadInfo;
        AVCE00Section  *pasSect;
        const char     *pszLine;
        int             i, numSect;
        GBool           bFound;
    
        hReadInfo = AVCE00ReadOpen(pszFname);
    
        if (hReadInfo)
        {
            /* Fetch the list of E00 sections for the coverage, and 
             * try to find a .AAT table in it.
             */
            pasSect = AVCE00ReadSectionsList(hReadInfo, &numSect);
            bFound = FALSE;
            for(i=0; i<numSect; i++)
            {
                if (pasSect[i].eType == AVCFileTABLE &&
                    strstr(pasSect[i].pszName, ".AAT") != NULL)
                {
                    /* Found it!  Move the read pointer to the beginning 
                     * of the .AAT table, and tell the lib to stop reading
                     * at the end of table (3rd argument=FALSE)
                     */
                    bFound = TRUE;
                    AVCE00ReadGotoSection(hReadInfo, &(pasSect[i]), FALSE);
    		break;
                }
            }
    
            if (bFound)
            {
                /* Convert the .AAT table to E00.  AVCE00ReadNextLine()
                 * will return NULL at the end of the table.
                 */
                while ((pszLine = AVCE00ReadNextLine(hReadInfo)) != NULL)
                {
                    printf("%s\n", pszLine);
                }
            }
            else
            {
                printf("No .AAT table found in this coverage!\n");
            }
    
            AVCE00ReadClose(hReadInfo);
        }
    }
    
    

Library functions to create a coverage from an E00 source

Information about the coverage currently being written is stored inside an internal structure. You do not need to understand the contents of this structure to use the library.

All you need is to declare a AVCE00WritePtr variable which will serve as a handle on the input file for all the other functions.

You use the following functions to create a coverage from an E00 input:

    AVCE00WritePtr  AVCE00WriteOpen(const char *pszCoverPath,
                                    AVCCoverType eNewCoverType,  
				    int nPrecision);
    void            AVCE00WriteClose(AVCE00WritePtr psInfo);
    int             AVCE00WriteNextLine(AVCE00WritePtr psInfo, 
                                        const char *pszLine);

To overwrite an existing coverage, it should first be properly destroyed using AVCE00DeleteCoverage():

    int             AVCE00DeleteCoverage(const char *pszCoverPath);

Each function is described after the example below.

Example:

    This short example uses the library to create a coverage in "data/cover2/" from the contents of the ASCII E00 file "data/test2.e00".

    /**********************************************************************
     * This example program illustrates the use of the AVCE00WriteOpen()
     * and the functions to use to write a binary coverage from E00 input.
     **********************************************************************/
    
    #include <stdio.h>
    
    #include "avc.h"
    
    int main()
    {
        FILE           *fpIn;
        AVCE00WritePtr hWritePtr;
        const char     *pszLine;
        int            nStatus = 0;
    
        /* Open input file */
        fpIn = fopen("data/test2.e00", "rt");
    
        if (fpIn)
        {
            /* Open output file */
            hWritePtr = AVCE00WriteOpen("data/cover2", AVCCoverV7,
                                        AVC_DEFAULT_PREC);
    
            if (hWritePtr)
            {
                /* Read lines from input until we reach EOF */
                while((pszLine = CPLReadLine(fpIn)) != NULL)
                {
                    if ((nStatus = CPLGetLastErrorNo()) == 0)
                        nStatus = AVCE00WriteNextLine(hWritePtr, pszLine);
    
                    if (nStatus != 0)
                    {
                        /* An error happened while converting the last 
                         * line... abort*/
                        break;
                    }
                }
                /* Close output file. */
                AVCE00WriteClose(hWritePtr);
            }
            else
            {
                /* ERROR ... failed to open output file */
                nStatus = -1;
            }
    
            /* Close input file. */
            fclose(fpIn);
        }
        else
        {
            /* ERROR ... failed to open input file */
            nStatus = -1;
        }
    
        return nStatus;
    }
    
    

AVCE00WritePtr data type

    A variable of type AVCE00WritePtr serves as a handle on the current output coverage.

    The handle is allocated by AVCE00WriteOpen(), and you must call AVCE00writeClose() to properly release the memory associated with it.

AVCE00WriteOpen()

    AVCE00WritePtr  AVCE00WriteOpen(const char *pszCoverPath, AVCCoverType eNewCoverType, int nPrecision);

    Open (create) an Arc/Info coverage, ready to receive a stream of ASCII E00 lines and convert that to the binary coverage format.

    Directly overwriting or updating existing coverages is not supported (and may quite well never be!)... you can only create new coverages. However, AVCE00DeleteCoverage() can be used to cleanly destroy an existing coverage, allowing you to eventually overwrite it.

    IMPORTANT NOTE: The E00 source lines are assumed to be valid... the library performs no validation on the consistency of what it is given as input (i.e. topology, polygons consistency, etc.). So the coverage that will be created will be only as good as the E00 input that was used to generate it.

    pszCoverPath MUST be the name of the coverage directory, including the path to it. (Contrary to AVCE00ReadOpen(), you cannot pass the name of one of the files in the coverage directory). The name of the coverage MUST be included in pszCoverPath... this means that passing "." is invalid.

    Also note that to be valid, a coverage name cannot be longer than 13 characters and can contain only alphanumerical characters and '_' (underscore). Spaces and '.' (dots) should be specially avoided inside coverage names.

    eNewCoverType is the type of coverage to create. Either AVCCoverV7 to create an Arc/Info V7 (Unix) coverage or AVCCoverPC to create a PC Arc/Info coverage.

    nPrecision SHOULD ALWAYS BE AVC_DEFAULT_PREC to automagically detect the source coverage's precision and use that same precision for the new coverage.

    IMPORTANT NOTE: The nPrecision parameter is there only to allow future enhancements of the library. It should eventually be possible to create coverages with a precision different from the one of the source E00.
    Given the way the lib is built, it should be possible to also pass AVC_SINGLE_PREC or AVC_DOUBLE_PREC to explicitly request the creation of a coverage with that precision, but the library does not (not yet!) properly convert the TABLE attributes' precision, and the resulting coverage may be invalid in some cases. This improvement is on the ToDo list!

    Returns a new AVCE00WritePtr handle or NULL if the coverage could not be created or if a coverage with that name already exists.

    The handle will eventually have to be released with AVCE00ReadClose().

AVCE00WriteClose()

    void  AVCE00WriteClose(AVCE00writePtr hInfo);

    Closes the coverage and releases any memory associated with the AVCE00writePtr handle.

AVCE00WriteNextLine()

    int   AVCE00WriteNextLine(AVCE00WritePtr psInfo,  const char *pszLine);

    Take the next line of E00 input for this coverage, parse it and write the result to the coverage.

    pszLine should be a null-terminated string and should not be terminated by a newline character.

    Important Note: The E00 source lines are assumed to be valid... the library performs no validation on the consistency of what it is given as input (i.e. topology, polygons consistency, etc.). So the coverage that will be created will be only as good as the E00 input that was used to generate it.

    Returns 0 on success or -1 on error. If an error happens, then CPLGetLastErrorNo() can be used to find out what went wrong.

AVCE00DeleteCoverage()

    int   AVCE00DeleteCoverage(const char *pszCoverPath);

    Delete a coverage directory, its contents, and the associated info tables.

    Note:
    When deleting tables, only the ../info/arc????.nit and arc????.dat will be deleted; the entries in the arc.dir will not be updated. This is apparently what Arc/Info's KILL command does.

    Returns 0 on success or -1 on error. If an error happens, then CPLGetLastErrorNo() can be used to find out what went wrong.

Trapping errors reported by the library

When errors happen, the library's default behavior is to report an error message on stderr, and to fail nicely, usually by simulating a EOF situation. Errors are reported through the function CPLError() defined in "cpl_error.c".

While this is sufficient for the purposes of the 'avcexport' and 'avcimport' command-line programs, you may want to trap and handle errors yourself if you use the library in a bigger application (a GUI application for instance).

CPLSetErrorHandler()

    void  CPLSetErrorHandler(void (*pfnErrorHandler)(CPLErr, int, const char *));
    

    You can use CPLSetErrorHandler() to override the default error handler function. Your new error handler should be a C function with the following prototype:

      void MyErrorHandler(CPLErr eErrClass, int err_no, const char *msg);

    And you register it with the following call at the beginning of your program:

      CPLSetErrorHandler( MyErrorHandler );

CPLError()

    void CPLError(CPLErr eErrClass, int err_no, const char *fmt, ...);

    The library reports errors through this function. It's default behavior is to display the error messages to stderr, but it can be overridden using CPLSetErrorHandler().

    You can call CPLGetLastErrorNo() or CPLGetLastErrorMsg() to get the last error number and string.

    eErrClass defines the severity of the error:

        typedef enum
        {
            CE_None = 0,
            CE_Log = 1,
            CE_Warning = 2,
            CE_Failure = 3,
            CE_Fatal = 4
        } CPLErr;
    

    Error class CE_Fatal will abort the execution of the program, it is mainly used for out of memory errors, or unrecoverable situations of that kind. All the other error classes return control to the calling function.

CPLGetLastErrorNo()

    int         CPLGetLastErrorNo();

    Returns the number of the last error that was produced. Returns 0 if the last library function that was called completed without any error. See the list of possible error numbers below.

    Note: This function works even if you redefined your own error handler using CPLSetErrorHandler() .

CPLGetLastErrorMsg()

    const char *CPLGetLastErrorMsg();

    Returns a reference to a static buffer containing the last error message that was produced. The caller should not attempt to free this buffer. Returns an empty string ("") if the last library function that was called completed without any error.

    Note: This function works even if you redefined your own error handler using CPLSetErrorHandler() .

Errors generated by the library and their meaning:

The values for the error codes returned by the library are defined in the file cpl_error.h.

    #define CPLE_OutOfMemory		2
    #define CPLE_FileIO			3
    #define CPLE_OpenFailed			4
    #define CPLE_IllegalArg			5
    #define CPLE_NotSupported		6
    

The following errors codes can be returned:

Error CodeDescription
0 Success, no error.
CPLE_OutOfMemory Memory allocation failed. This is a fatal error, it will abort the program execution. There is currently no proper way to recover from it.
CPLE_FileIO Unexpected error reading to a file. This is more likely to happen if one of the files is corrupt which could result in an attempt to read past EOF.
CPLE_OpenFailed Failed to open the coverage, or failed to open one of the files that was expected to be present in the coverage.
CPLE_IllegalArg Illegal argument passed to one of the library's functions. This is a kind of internal error that should not happen unless the lib is modified or is not used as it is expected.
CPLE_NotSupported One of the functions encountered an unsupported/unexpected case in one of the coverage files. This error can also be a sign that the file is corrupt.


Last Update: $Date: 2006/08/17 20:09:45 $
Daniel Morissette, dmorissette@mapgears.com
avce00-2.0.0/cpl_string.h0100775000076400007640000000776310247751547014425 0ustar danieldaniel/********************************************************************** * $Id: cpl_string.h,v 1.3 2005/06/03 03:49:59 daniel Exp $ * * Name: cpl_string.h * Project: CPL - Common Portability Library * Purpose: String and StringList functions. * Author: Daniel Morissette, dmorissette@dmsolutions.ca * ********************************************************************** * Copyright (c) 1998, Daniel Morissette * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ********************************************************************** * * $Log: cpl_string.h,v $ * Revision 1.3 2005/06/03 03:49:59 daniel * Update email address, website url, and copyright dates * * Revision 1.2 1999/10/29 06:10:12 daniel * Updated cpl_string.* * * Revision 1.4 1999/06/26 14:05:19 warmerda * Added CSLFindString(). * * Revision 1.3 1999/02/17 01:41:58 warmerda * Added CSLGetField * * Revision 1.2 1998/12/04 21:40:42 danmo * Added more Name=Value manipulation fuctions * * Revision 1.1 1998/12/03 18:26:02 warmerda * New * **********************************************************************/ #ifndef _CPL_STRING_H_INCLUDED #define _CPL_STRING_H_INCLUDED #include "cpl_vsi.h" #include "cpl_error.h" #include "cpl_conv.h" /*===================================================================== Stringlist functions (strlist.c) =====================================================================*/ CPL_C_START char **CSLAddString(char **papszStrList, const char *pszNewString); int CSLCount(char **papszStrList); const char *CSLGetField( char **, int ); void CSLDestroy(char **papszStrList); char **CSLDuplicate(char **papszStrList); char **CSLTokenizeString(const char *pszString ); char **CSLTokenizeStringComplex(const char *pszString, const char *pszDelimiter, int bHonourStrings, int bAllowEmptyTokens ); int CSLPrint(char **papszStrList, FILE *fpOut); char **CSLLoad(const char *pszFname); int CSLSave(char **papszStrList, const char *pszFname); char **CSLInsertStrings(char **papszStrList, int nInsertAtLineNo, char **papszNewLines); char **CSLInsertString(char **papszStrList, int nInsertAtLineNo, char *pszNewLine); char **CSLRemoveStrings(char **papszStrList, int nFirstLineToDelete, int nNumToRemove, char ***ppapszRetStrings); int CSLFindString( char **, const char * ); const char *CPLSPrintf(char *fmt, ...); char **CSLAppendPrintf(char **papszStrList, char *fmt, ...); const char *CSLFetchNameValue(char **papszStrList, const char *pszName); char **CSLFetchNameValueMultiple(char **papszStrList, const char *pszName); char **CSLAddNameValue(char **papszStrList, const char *pszName, const char *pszValue); char **CSLSetNameValue(char **papszStrList, const char *pszName, const char *pszValue); CPL_C_END #endif /* _CPL_STRING_H_INCLUDED */ avce00-2.0.0/avc_misc.c0100664000076400007640000004155110247751547014026 0ustar danieldaniel/********************************************************************** * $Id: avc_misc.c,v 1.9 2005/06/03 03:49:59 daniel Exp $ * * Name: avc_misc.c * Project: Arc/Info vector coverage (AVC) BIN<->E00 conversion library * Language: ANSI C * Purpose: Misc. functions used by several parts of the library * Author: Daniel Morissette, dmorissette@dmsolutions.ca * ********************************************************************** * Copyright (c) 1999-2005, Daniel Morissette * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ********************************************************************** * * $Log: avc_misc.c,v $ * Revision 1.9 2005/06/03 03:49:59 daniel * Update email address, website url, and copyright dates * * Revision 1.8 2004/08/31 21:00:20 warmerda * Applied Carl Anderson's patch to reduce the amount of stating while * trying to discover filename "case" on Unix in AVCAdjustCaseSensitiveFilename. * http://bugzilla.remotesensing.org/show_bug.cgi?id=314 * * Revision 1.7 2001/11/25 21:38:01 daniel * Remap '\\' to '/' in AVCAdjustCaseSensitiveFilename() on Unix. * * Revision 1.6 2001/11/25 21:15:23 daniel * Added hack (AVC_MAP_TYPE40_TO_DOUBLE) to map type 40 fields bigger than 8 * digits to double precision as we generate E00 output (bug599) * * Revision 1.5 2000/09/26 20:21:04 daniel * Added AVCCoverPC write * * Revision 1.4 2000/09/22 19:45:21 daniel * Switch to MIT-style license * * Revision 1.3 2000/01/10 02:53:21 daniel * Added AVCAdjustCaseSensitiveFilename() and AVCFileExists() * * Revision 1.2 1999/08/23 18:24:27 daniel * Fixed support for attribute fields of type 40 * * Revision 1.1 1999/05/11 02:34:46 daniel * Initial revision * **********************************************************************/ #include "avc.h" /********************************************************************** * AVCE00ComputeRecSize() * * Computes the number of chars required to generate a E00 attribute * table record. * * Returns -1 on error, i.e. if it encounters an unsupported field type. **********************************************************************/ int _AVCE00ComputeRecSize(int numFields, AVCFieldInfo *pasDef, GBool bMapType40ToDouble) { int i, nType, nBufSize=0; /*------------------------------------------------------------- * Add up the nbr of chars used by each field *------------------------------------------------------------*/ for(i=0; i < numFields; i++) { nType = pasDef[i].nType1*10; if (nType == AVC_FT_DATE || nType == AVC_FT_CHAR || nType == AVC_FT_FIXINT ) { nBufSize += pasDef[i].nSize; } else if (nType == AVC_FT_BININT && pasDef[i].nSize == 4) nBufSize += 11; else if (nType == AVC_FT_BININT && pasDef[i].nSize == 2) nBufSize += 6; else if (bMapType40ToDouble && nType == AVC_FT_FIXNUM && pasDef[i].nSize > 8) { /* See explanation in AVCE00GenTableHdr() about this hack to remap * type 40 fields to double precision floats. */ nBufSize += 24; /* Remap to double float */ } else if ((nType == AVC_FT_BINFLOAT && pasDef[i].nSize == 4) || nType == AVC_FT_FIXNUM ) nBufSize += 14; else if (nType == AVC_FT_BINFLOAT && pasDef[i].nSize == 8) nBufSize += 24; else { /*----------------------------------------------------- * Hummm... unsupported field type... *----------------------------------------------------*/ CPLError(CE_Failure, CPLE_NotSupported, "_AVCE00ComputeRecSize(): Unsupported field type: " "(type=%d, size=%d)", nType, pasDef[i].nSize); return -1; } } return nBufSize; } /********************************************************************** * _AVCDestroyTableFields() * * Release all memory associated with an array of AVCField structures. **********************************************************************/ void _AVCDestroyTableFields(AVCTableDef *psTableDef, AVCField *pasFields) { int i, nFieldType; if (pasFields) { for(i=0; inumFields; i++) { nFieldType = psTableDef->pasFieldDef[i].nType1*10; if (nFieldType == AVC_FT_DATE || nFieldType == AVC_FT_CHAR || nFieldType == AVC_FT_FIXINT || nFieldType == AVC_FT_FIXNUM) { CPLFree(pasFields[i].pszStr); } } CPLFree(pasFields); } } /********************************************************************** * _AVCDestroyTableDef() * * Release all memory associated with a AVCTableDef structure. * **********************************************************************/ void _AVCDestroyTableDef(AVCTableDef *psTableDef) { if (psTableDef) { CPLFree(psTableDef->pasFieldDef); CPLFree(psTableDef); } } /********************************************************************** * _AVCDupTableDef() * * Create a new copy of a AVCTableDef structure. **********************************************************************/ AVCTableDef *_AVCDupTableDef(AVCTableDef *psSrcDef) { AVCTableDef *psNewDef; if (psSrcDef == NULL) return NULL; psNewDef = (AVCTableDef*)CPLMalloc(1*sizeof(AVCTableDef)); memcpy(psNewDef, psSrcDef, sizeof(AVCTableDef)); psNewDef->pasFieldDef = (AVCFieldInfo*)CPLMalloc(psSrcDef->numFields* sizeof(AVCFieldInfo)); memcpy(psNewDef->pasFieldDef, psSrcDef->pasFieldDef, psSrcDef->numFields*sizeof(AVCFieldInfo)); return psNewDef; } /********************************************************************** * AVCFileExists() * * Returns TRUE if a file with the specified name exists in the * specified directory. * * For now I simply try to fopen() the file ... would it be more * efficient to use stat() ??? **********************************************************************/ GBool AVCFileExists(const char *pszPath, const char *pszName) { char *pszBuf; GBool bFileExists = FALSE; FILE *fp; pszBuf = (char*)CPLMalloc((strlen(pszPath)+strlen(pszName)+1)* sizeof(char)); sprintf(pszBuf, "%s%s", pszPath, pszName); AVCAdjustCaseSensitiveFilename(pszBuf); if ((fp = VSIFOpen(pszBuf, "rb")) != NULL) { bFileExists = TRUE; VSIFClose(fp); } CPLFree(pszBuf); return bFileExists; } /********************************************************************** * AVCAdjustCaseSensitiveFilename() * * Scan a filename and its path, adjust uppercase/lowercases if * necessary, and return a reference to that filename. * * This function works on the original buffer and returns a reference to it. * It does nothing on Windows systems where filenames are not case sensitive. * * NFW: It seems like this could be made somewhat more efficient by * getting a directory listing and doing a case insensitive search in * that list rather than all this stating that can be very expensive * in some circumstances. However, at least with Carl's fix this is * somewhat faster. * see: http://buzilla.remotesensing.org/show_bug.cgi?id=314 **********************************************************************/ char *AVCAdjustCaseSensitiveFilename(char *pszFname) { #ifdef _WIN32 /*----------------------------------------------------------------- * Nothing to do on Windows *----------------------------------------------------------------*/ return pszFname; #else /*----------------------------------------------------------------- * Unix case. *----------------------------------------------------------------*/ VSIStatBuf sStatBuf; char *pszTmpPath = NULL; int nTotalLen, iTmpPtr; GBool bValidPath; /*----------------------------------------------------------------- * Remap '\\' to '/' *----------------------------------------------------------------*/ for(pszTmpPath = pszFname; *pszTmpPath != '\0'; pszTmpPath++) { if (*pszTmpPath == '\\') *pszTmpPath = '/'; } /*----------------------------------------------------------------- * First check if the filename is OK as is. *----------------------------------------------------------------*/ if (VSIStat(pszFname, &sStatBuf) == 0) { return pszFname; } pszTmpPath = CPLStrdup(pszFname); nTotalLen = strlen(pszTmpPath); /*----------------------------------------------------------------- * Try all lower case, check if the filename is OK as that. *----------------------------------------------------------------*/ for (iTmpPtr=0; iTmpPtr< nTotalLen; iTmpPtr++) { if ( pszTmpPath[iTmpPtr] >= 0x41 && pszTmpPath[iTmpPtr] <= 0x5a ) pszTmpPath[iTmpPtr] += 32; } if (VSIStat(pszTmpPath, &sStatBuf) == 0) { strcpy(pszFname, pszTmpPath); CPLFree(pszTmpPath); return pszFname; } /*----------------------------------------------------------------- * Try all upper case, check if the filename is OK as that. *----------------------------------------------------------------*/ for (iTmpPtr=0; iTmpPtr< nTotalLen; iTmpPtr++) { if ( pszTmpPath[iTmpPtr] >= 0x61 && pszTmpPath[iTmpPtr] <= 0x7a ) pszTmpPath[iTmpPtr] -= 32; } if (VSIStat(pszTmpPath, &sStatBuf) == 0) { strcpy(pszFname, pszTmpPath); CPLFree(pszTmpPath); return pszFname; } /*----------------------------------------------------------------- * OK, file either does not exist or has the wrong cases... we'll * go backwards until we find a portion of the path that is valid. *----------------------------------------------------------------*/ iTmpPtr = nTotalLen; bValidPath = FALSE; while(iTmpPtr > 0 && !bValidPath) { /*------------------------------------------------------------- * Move back to the previous '/' separator *------------------------------------------------------------*/ pszTmpPath[--iTmpPtr] = '\0'; while( iTmpPtr > 0 && pszTmpPath[iTmpPtr-1] != '/' ) { pszTmpPath[--iTmpPtr] = '\0'; } if (iTmpPtr > 0 && VSIStat(pszTmpPath, &sStatBuf) == 0) bValidPath = TRUE; } CPLAssert(iTmpPtr >= 0); /*----------------------------------------------------------------- * Assume that CWD is valid... so an empty path is a valid path *----------------------------------------------------------------*/ if (iTmpPtr == 0) bValidPath = TRUE; /*----------------------------------------------------------------- * OK, now that we have a valid base, reconstruct the whole path * by scanning all the sub-directories. * If we get to a point where a path component does not exist then * we simply return the rest of the path as is. *----------------------------------------------------------------*/ while(bValidPath && strlen(pszTmpPath) < nTotalLen) { char **papszDir=NULL; int iEntry, iLastPartStart; iLastPartStart = iTmpPtr; papszDir = CPLReadDir(pszTmpPath); /*------------------------------------------------------------- * Add one component to the current path *------------------------------------------------------------*/ pszTmpPath[iTmpPtr] = pszFname[iTmpPtr]; iTmpPtr++; for( ; pszFname[iTmpPtr] != '\0' && pszFname[iTmpPtr]!='/'; iTmpPtr++) { pszTmpPath[iTmpPtr] = pszFname[iTmpPtr]; } while(iLastPartStart < iTmpPtr && pszTmpPath[iLastPartStart] == '/') iLastPartStart++; /*------------------------------------------------------------- * And do a case insensitive search in the current dir... *------------------------------------------------------------*/ for(iEntry=0; papszDir && papszDir[iEntry]; iEntry++) { if (EQUAL(pszTmpPath+iLastPartStart, papszDir[iEntry])) { /* Fount it! */ strcpy(pszTmpPath+iLastPartStart, papszDir[iEntry]); break; } } if (iTmpPtr > 0 && VSIStat(pszTmpPath, &sStatBuf) != 0) bValidPath = FALSE; CSLDestroy(papszDir); } /*----------------------------------------------------------------- * We reached the last valid path component... just copy the rest * of the path as is. *----------------------------------------------------------------*/ if (iTmpPtr < nTotalLen-1) { strncpy(pszTmpPath+iTmpPtr, pszFname+iTmpPtr, nTotalLen-iTmpPtr); } /*----------------------------------------------------------------- * Update the source buffer and return. *----------------------------------------------------------------*/ strcpy(pszFname, pszTmpPath); CPLFree(pszTmpPath); return pszFname; #endif } /********************************************************************** * AVCPrintRealValue() * * Format a floating point value according to the specified coverage * precision (AVC_SINGLE/DOUBLE_PREC), and append the formatted value * to the end of the pszBuf buffer. * * The function returns the number of characters added to the buffer. **********************************************************************/ int AVCPrintRealValue(char *pszBuf, int nPrecision, AVCFileType eType, double dValue) { static int numExpDigits=-1; int nLen = 0; /* WIN32 systems' printf for floating point output generates 3 * digits exponents (ex: 1.23E+012), but E00 files must have 2 digits * exponents (ex: 1.23E+12). * Run a test (only once per prg execution) to establish the number * of exponent digits on the current platform. */ if (numExpDigits == -1) { char szBuf[50]; int i; sprintf(szBuf, "%10.7E", 123.45); numExpDigits = 0; for(i=strlen(szBuf)-1; i>0; i--) { if (szBuf[i] == '+' || szBuf[i] == '-') break; numExpDigits++; } } /* We will append the value at the end of the current buffer contents. */ pszBuf = pszBuf+strlen(pszBuf); if (dValue < 0.0) { *pszBuf = '-'; dValue = -1.0*dValue; } else *pszBuf = ' '; /* Just to make things more complicated, double values are * output in a different format in attribute tables than in * the other files! */ if (nPrecision == AVC_FORMAT_DBF_FLOAT) { /* Float stored in DBF table in PC coverages */ sprintf(pszBuf+1, "%9.6E", dValue); nLen = 13; } else if (nPrecision == AVC_DOUBLE_PREC && eType == AVCFileTABLE) { sprintf(pszBuf+1, "%20.17E", dValue); nLen = 24; } else if (nPrecision == AVC_DOUBLE_PREC) { sprintf(pszBuf+1, "%17.14E", dValue); nLen = 21; } else { sprintf(pszBuf+1, "%10.7E", dValue); nLen = 14; } /* Adjust number of exponent digits if necessary */ if (numExpDigits > 2) { int n; n = strlen(pszBuf); pszBuf[n - numExpDigits] = pszBuf[n-2]; pszBuf[n - numExpDigits +1] = pszBuf[n-1]; pszBuf[n - numExpDigits +2] = '\0'; } /* Just make sure that the actual output length is what we expected. */ CPLAssert(strlen(pszBuf) == nLen); return nLen; } avce00-2.0.0/avcexport.c0100664000076400007640000001211610471150033014226 0ustar danieldaniel/********************************************************************** * $Id: avcexport.c,v 1.9 2006/08/17 20:21:51 dmorissette Exp $ * * Name: avcexport.c * Project: Arc/Info Vector coverage (AVC) BIN->E00 conversion library * Language: ANSI C * Purpose: Convert an Arc/Info binary coverage to E00. * Author: Daniel Morissette, dmorissette@dmsolutions.ca * ********************************************************************** * Copyright (c) 1999-2005, Daniel Morissette * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ********************************************************************** * * $Log: avcexport.c,v $ * Revision 1.9 2006/08/17 20:21:51 dmorissette * Updated email address * * Revision 1.8 2005/06/03 03:55:41 daniel * Update URL to website * * Revision 1.7 2005/06/03 03:49:59 daniel * Update email address, website url, and copyright dates * * Revision 1.6 2000/09/26 20:21:04 daniel * Added AVCCoverPC write * * Revision 1.5 1999/12/05 05:28:59 daniel * Updated usage info with build date * * Revision 1.4 1999/05/11 02:11:35 daniel * Renamed from avcconv.c to avcexport.c * * Revision 1.3 1999/02/25 03:34:48 daniel * Fixed the Revsion field in the "usage" output * * Revision 1.2 1999/02/25 03:32:25 daniel * Added support for output_file arg. * **********************************************************************/ #include "avc.h" static void ConvertCover(const char *pszFname, FILE *fpOut); /********************************************************************** * main() * * This program converts an Arc/Info vector coverage from the native * binary format to E00. **********************************************************************/ int main(int argc, char *argv[]) { const char *pszCoverPath, *pszOutFile; FILE *fpOut; /*--------------------------------------------------------------------- * Read program arguments. *--------------------------------------------------------------------*/ if (argc<3) { printf("\n"); printf("AVCEXPORT - Version %s\n", AVC_VERSION); printf(" Convert an Arc/Info vector coverage from binary to E00.\n"); printf(" Copyright (c) 1999-2005, Daniel Morissette (dmorissette@mapgears.com)\n"); printf(" AVCE00 web page: http://avce00.maptools.org/\n"); printf("\n"); printf("Usage: avcexport \n"); printf("\n"); return 1; } pszCoverPath = argv[1]; pszOutFile = argv[2]; /*--------------------------------------------------------------------- * Open output file... passing "-" will send output to stdout *-------------------------------------------------------------------*/ if (strcmp(pszOutFile, "-") == 0) { fpOut = stdout; } else { fpOut = fopen(pszOutFile, "wt"); if (fpOut == NULL) { perror(CPLSPrintf("avcexport: Cannot create %s", pszOutFile)); return 1; } } /*--------------------------------------------------------------------- * Convert the whole coverage to E00 *-------------------------------------------------------------------*/ ConvertCover(pszCoverPath, fpOut); /*--------------------------------------------------------------------- * Close output file and exit. *-------------------------------------------------------------------*/ if (strcmp(pszOutFile, "-") != 0) { fclose(fpOut); } return 0; } /********************************************************************** * ConvertCover() * * Convert a complete coverage to E00. **********************************************************************/ static void ConvertCover(const char *pszFname, FILE *fpOut) { AVCE00ReadPtr hReadInfo; const char *pszLine; hReadInfo = AVCE00ReadOpen(pszFname); if (hReadInfo) { while ((pszLine = AVCE00ReadNextLine(hReadInfo)) != NULL) { fprintf(fpOut, "%s\n", pszLine); } AVCE00ReadClose(hReadInfo); } } avce00-2.0.0/cpl_vsi.h0100775000076400007640000001363507445434416013712 0ustar danieldaniel/****************************************************************************** * Copyright (c) 1998, Frank Warmerdam * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ****************************************************************************** * * cpl_vsi.h * * Include file defining the Virtual System Interface (VSI) functions. This * should normally be included by all translators using VSI functions for * accessing system services. It is also used by the GDAL core, and can be * used by higher level applications which adhere to VSI use. * * Most VSI functions are direct analogs of Posix C library functions. * VSI exists to allow ``hooking'' these functions to provide application * specific checking, io redirection and so on. * * $Log: cpl_vsi.h,v $ * Revision 1.2 2002/03/18 18:59:26 daniel * Added VSIMkdir(), VSIRmdir() and VSIUnlink() * * Revision 1.1 1999/08/27 14:09:55 daniel * Update CPL files * * Revision 1.5 1999/05/23 02:43:57 warmerda * Added documentation block. * * Revision 1.4 1999/02/25 04:48:11 danmo * Added VSIStat() macros specific to _WIN32 (for MSVC++) * * Revision 1.3 1999/01/28 18:31:25 warmerda * Test on _WIN32 rather than WIN32. It seems to be more reliably defined. * * Revision 1.2 1998/12/04 21:42:57 danmo * Added #ifndef WIN32 arounf #include * * Revision 1.1 1998/12/03 18:26:02 warmerda * New * */ #ifndef CPL_VSI_H_INCLUDED #define CPL_VSI_H_INCLUDED #include "cpl_port.h" /** * \file cpl_vsi.h * * Standard C Covers * * The VSI functions are intended to be hookable aliases for Standard C * I/O, memory allocation and other system functions. They are intended * to allow virtualization of disk I/O so that non file data sources * can be made to appear as files, and so that additional error trapping * and reporting can be interested. The memory access API is aliased * so that special application memory management services can be used. * * Is is intended that each of these functions retains exactly the same * calling pattern as the original Standard C functions they relate to. * This means we don't have to provide custom documentation, and also means * that the default implementation is very simple. */ /* -------------------------------------------------------------------- */ /* We need access to ``struct stat''. */ /* -------------------------------------------------------------------- */ #ifndef _WIN32 # include #endif #include CPL_C_START /* ==================================================================== */ /* stdio file access functions. */ /* ==================================================================== */ FILE CPL_DLL * VSIFOpen( const char *, const char * ); int CPL_DLL VSIFClose( FILE * ); int CPL_DLL VSIFSeek( FILE *, long, int ); long CPL_DLL VSIFTell( FILE * ); void CPL_DLL VSIRewind( FILE * ); size_t CPL_DLL VSIFRead( void *, size_t, size_t, FILE * ); size_t CPL_DLL VSIFWrite( void *, size_t, size_t, FILE * ); char CPL_DLL *VSIFGets( char *, int, FILE * ); int CPL_DLL VSIFPuts( const char *, FILE * ); int CPL_DLL VSIFPrintf( FILE *, const char *, ... ); int CPL_DLL VSIFGetc( FILE * ); int CPL_DLL VSIFPutc( int, FILE * ); int CPL_DLL VSIUngetc( int, FILE * ); int CPL_DLL VSIFEof( FILE * ); /* ==================================================================== */ /* VSIStat() related. */ /* ==================================================================== */ typedef struct stat VSIStatBuf; int CPL_DLL VSIStat( const char *, VSIStatBuf * ); #ifdef _WIN32 # define VSI_ISLNK(x) ( 0 ) /* N/A on Windows */ # define VSI_ISREG(x) ((x) & S_IFREG) # define VSI_ISDIR(x) ((x) & S_IFDIR) # define VSI_ISCHR(x) ((x) & S_IFCHR) # define VSI_ISBLK(x) ( 0 ) /* N/A on Windows */ #else # define VSI_ISLNK(x) S_ISLNK(x) # define VSI_ISREG(x) S_ISREG(x) # define VSI_ISDIR(x) S_ISDIR(x) # define VSI_ISCHR(x) S_ISCHR(x) # define VSI_ISBLK(x) S_ISBLK(x) #endif /* ==================================================================== */ /* Memory allocation */ /* ==================================================================== */ void CPL_DLL *VSICalloc( size_t, size_t ); void CPL_DLL *VSIMalloc( size_t ); void CPL_DLL VSIFree( void * ); void CPL_DLL *VSIRealloc( void *, size_t ); char CPL_DLL *VSIStrdup( const char * ); /* ==================================================================== */ /* Other... */ /* ==================================================================== */ int CPL_DLL VSIMkdir( const char * pathname, long mode ); int CPL_DLL VSIRmdir( const char * pathname ); int CPL_DLL VSIUnlink( const char * pathname ); CPL_C_END #endif /* ndef CPL_VSI_H_INCLUDED */ avce00-2.0.0/cpl_conv.h0100775000076400007640000000577506761516063014063 0ustar danieldaniel/****************************************************************************** * Copyright (c) 1998, Frank Warmerdam * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ****************************************************************************** * * cpl_conv.h * * Prototypes, and stuff for various convenience functions. This is intended * to remain light weight. * * $Log: * Revision 1.1 1998/10/18 06:15:11 warmerda * Initial implementation. * */ #ifndef CPL_CONV_H_INCLUDED #define CPL_CONV_H_INCLUDED #include "cpl_port.h" #include "cpl_vsi.h" #include "cpl_error.h" /** * \file cpl_conv.h * * Various convenience functions for CPL. * */ /* -------------------------------------------------------------------- */ /* Safe malloc() API. Thin cover over VSI functions with fatal */ /* error reporting if memory allocation fails. */ /* -------------------------------------------------------------------- */ CPL_C_START void CPL_DLL *CPLMalloc( size_t ); void CPL_DLL *CPLCalloc( size_t, size_t ); void CPL_DLL *CPLRealloc( void *, size_t ); char CPL_DLL *CPLStrdup( const char * ); #define CPLFree VSIFree /* -------------------------------------------------------------------- */ /* Read a line from a text file, and strip of CR/LF. */ /* -------------------------------------------------------------------- */ const char *CPLReadLine( FILE * ); /* -------------------------------------------------------------------- */ /* Fetch a function from DLL / so. */ /* -------------------------------------------------------------------- */ void CPL_DLL *CPLGetSymbol( const char *, const char * ); /* -------------------------------------------------------------------- */ /* Read a directory (cpl_dir.c) */ /* -------------------------------------------------------------------- */ char CPL_DLL **CPLReadDir( const char *pszPath ); CPL_C_END #endif /* ndef CPL_CONV_H_INCLUDED */ avce00-2.0.0/avc_mbyte.h0100664000076400007640000000730310247751547014215 0ustar danieldaniel/********************************************************************** * $Id: avc_mbyte.h,v 1.3 2005/06/03 03:49:59 daniel Exp $ * * Name: avc.h * Project: Arc/Info Vector coverage (AVC) BIN<->E00 conversion library * Language: ANSI C * Purpose: Header file containing all definitions for the library. * Author: Daniel Morissette, dmorissette@dmsolutions.ca * ********************************************************************** * Copyright (c) 1999-2005, Daniel Morissette * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ********************************************************************** * * $Log: avc_mbyte.h,v $ * Revision 1.3 2005/06/03 03:49:59 daniel * Update email address, website url, and copyright dates * * Revision 1.2 2000/09/22 19:45:21 daniel * Switch to MIT-style license * * Revision 1.1 2000/05/29 15:31:03 daniel * Initial revision - Japanese support * **********************************************************************/ #ifndef _AVC_MBYTE_H_INCLUDED_ #define _AVC_MBYTE_H_INCLUDED_ CPL_C_START /*--------------------------------------------------------------------- * Supported multibyte codepage numbers *--------------------------------------------------------------------*/ #define AVC_DBCS_JAPANESE 932 #define AVC_CODE_UNKNOWN 0 /*--------------------------------------------------------------------- * Definitions for Japanese encodings (AVC_DBCS_JAPANESE) *--------------------------------------------------------------------*/ #define AVC_CODE_JAP_UNKNOWN 0 #define AVC_CODE_JAP_SHIFTJIS 1 #define AVC_CODE_JAP_EUC 2 /*--------------------------------------------------------------------- * We use the following structure to keep track of DBCS info. *--------------------------------------------------------------------*/ typedef struct AVCDBCSInfo_t { int nDBCSCodePage; int nDBCSEncoding; unsigned char *pszDBCSBuf; int nDBCSBufSize; } AVCDBCSInfo; /*--------------------------------------------------------------------- * Functions prototypes *--------------------------------------------------------------------*/ AVCDBCSInfo *AVCAllocDBCSInfo(); void AVCFreeDBCSInfo(AVCDBCSInfo *psInfo); int AVCGetDBCSCodePage(); GBool AVCE00DetectEncoding(AVCDBCSInfo *psDBCSInfo, const char *pszLine); const char *AVCE00Convert2ArcDBCS(AVCDBCSInfo *psDBCSInfo, const char *pszLine, int nMaxOutputLen); const char *AVCE00ConvertFromArcDBCS(AVCDBCSInfo *psDBCSInfo, const char *pszLine, int nMaxOutputLen); CPL_C_END #endif /* _AVC_MBYTE_H_INCLUDED_ */ avce00-2.0.0/cpl_config.h0100664000076400007640000000000006761516063014330 0ustar danieldaniel