shp 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +15 -0
- data/.gitignore +34 -0
- data/.travis.yml +4 -0
- data/Gemfile +3 -0
- data/LICENSE +28 -0
- data/README.md +30 -0
- data/Rakefile +23 -0
- data/ext/shp/base.hpp +113 -0
- data/ext/shp/dbf.cpp +381 -0
- data/ext/shp/dbf.hpp +44 -0
- data/ext/shp/extconf.rb +13 -0
- data/ext/shp/shape_object.cpp +58 -0
- data/ext/shp/shape_object.hpp +27 -0
- data/ext/shp/shapefile.cpp +299 -0
- data/ext/shp/shapefile.hpp +35 -0
- data/ext/shp/shapelib/.cvsignore +15 -0
- data/ext/shp/shapelib/ChangeLog +450 -0
- data/ext/shp/shapelib/HOWTO-RELEASE +16 -0
- data/ext/shp/shapelib/LICENSE.LGPL +483 -0
- data/ext/shp/shapelib/Makefile +113 -0
- data/ext/shp/shapelib/README +41 -0
- data/ext/shp/shapelib/README.tree +172 -0
- data/ext/shp/shapelib/contrib/.cvsignore +12 -0
- data/ext/shp/shapelib/contrib/Makefile +66 -0
- data/ext/shp/shapelib/contrib/ShapeFileII.pas +234 -0
- data/ext/shp/shapelib/contrib/Shape_PointInPoly.cpp +238 -0
- data/ext/shp/shapelib/contrib/Shape_PointInPoly_README.txt +59 -0
- data/ext/shp/shapelib/contrib/csv2shp.c +558 -0
- data/ext/shp/shapelib/contrib/dbfcat.c +166 -0
- data/ext/shp/shapelib/contrib/dbfinfo.c +106 -0
- data/ext/shp/shapelib/contrib/makefile.vc +34 -0
- data/ext/shp/shapelib/contrib/my_nan.h +46 -0
- data/ext/shp/shapelib/contrib/shpcat.c +100 -0
- data/ext/shp/shapelib/contrib/shpcentrd.c +159 -0
- data/ext/shp/shapelib/contrib/shpdata.c +129 -0
- data/ext/shp/shapelib/contrib/shpdxf.c +340 -0
- data/ext/shp/shapelib/contrib/shpfix.c +110 -0
- data/ext/shp/shapelib/contrib/shpgeo.c +1595 -0
- data/ext/shp/shapelib/contrib/shpgeo.h +154 -0
- data/ext/shp/shapelib/contrib/shpinfo.c +113 -0
- data/ext/shp/shapelib/contrib/shpproj.c +260 -0
- data/ext/shp/shapelib/contrib/shpsort.c +605 -0
- data/ext/shp/shapelib/contrib/shpsort.txt +44 -0
- data/ext/shp/shapelib/contrib/shpwkb.c +123 -0
- data/ext/shp/shapelib/contrib/tests/shpproj.sh +38 -0
- data/ext/shp/shapelib/dbfopen.c +2221 -0
- data/ext/shp/shapelib/makefile.vc +86 -0
- data/ext/shp/shapelib/makeshape.sh +21 -0
- data/ext/shp/shapelib/mkdist.sh +37 -0
- data/ext/shp/shapelib/mkinstalldirs +38 -0
- data/ext/shp/shapelib/mkrelease.sh +55 -0
- data/ext/shp/shapelib/safileio.c +286 -0
- data/ext/shp/shapelib/shapefil.h +647 -0
- data/ext/shp/shapelib/shapelib.def +46 -0
- data/ext/shp/shapelib/shpopen.c +2388 -0
- data/ext/shp/shapelib/shptree.c +1187 -0
- data/ext/shp/shapelib/shputils.c +1072 -0
- data/ext/shp/shapelib/stream1.out +1465 -0
- data/ext/shp/shapelib/stream1.sh +28 -0
- data/ext/shp/shapelib/stream2.out +530 -0
- data/ext/shp/shapelib/stream2.sh +11 -0
- data/ext/shp/shapelib/stream3.out +37 -0
- data/ext/shp/shapelib/web/.cvsignore +2 -0
- data/ext/shp/shapelib/web/codepage.html +403 -0
- data/ext/shp/shapelib/web/dbf_api.html +436 -0
- data/ext/shp/shapelib/web/index.html +235 -0
- data/ext/shp/shapelib/web/license.html +78 -0
- data/ext/shp/shapelib/web/manifest.html +87 -0
- data/ext/shp/shapelib/web/release.html +80 -0
- data/ext/shp/shapelib/web/shapelib-tools.html +352 -0
- data/ext/shp/shapelib/web/shp_api.html +376 -0
- data/ext/shp/shp.cpp +19 -0
- data/ext/shp/shp.hpp +47 -0
- data/lib/shp.rb +35 -0
- data/lib/shp/version.rb +3 -0
- data/shp.gemspec +23 -0
- data/spec/shp_spec.rb +127 -0
- metadata +176 -0
@@ -0,0 +1,44 @@
|
|
1
|
+
============================= ABOUT ===========================================
|
2
|
+
|
3
|
+
The program "shpsort" is a standalone program for sorting shapefiles
|
4
|
+
on one or more fields (including the pseudofield "SHAPE") and outputing
|
5
|
+
the results. People may find it useful for forcing drawing order.
|
6
|
+
|
7
|
+
============================= AUTHOR ==========================================
|
8
|
+
|
9
|
+
Eric G. Miller
|
10
|
+
California Department of Fish and Game
|
11
|
+
2004-06-30
|
12
|
+
|
13
|
+
============================= USAGE ===========================================
|
14
|
+
|
15
|
+
shpsort <INFILE> <OUTFILE> <SORT_FIELD;SORT_FIELD...> {SORT_ORDER;SORT_ORDER...}
|
16
|
+
|
17
|
+
============================= DETAILS =========================================
|
18
|
+
|
19
|
+
INFILE The input shapefile
|
20
|
+
|
21
|
+
OUTFILE The output shapefile
|
22
|
+
|
23
|
+
SORT_FIELD Any attribute field of the shapefile, including "SHAPE"
|
24
|
+
|
25
|
+
SORT_ORDER Specify "ASCENDING" or "DESCENDING" for each SORT_FIELD.
|
26
|
+
This field is optional, and is assumed to be ASCENDING
|
27
|
+
unless the exact word "DESCENDING" is specified (case
|
28
|
+
matters).
|
29
|
+
|
30
|
+
When sorting on the "SHAPE" the records are sorted as follows:
|
31
|
+
|
32
|
+
* Null shapes are treated as any other null field and will
|
33
|
+
sort to the top in ASCENDING mode. A warning is issued
|
34
|
+
for each null shape encountered.
|
35
|
+
* POINT, POINTM, POINTZ, MULTIPOINT, MULTIPOINTM, MULTIPOINTZ
|
36
|
+
and MULTIPATCH are all sorted by the maximum "Y" value of
|
37
|
+
their envelopes (not particularly useful).
|
38
|
+
* POLYLINE, POLYLINEZ and POLYLINEM are sorted by total 2d
|
39
|
+
shape length.
|
40
|
+
* POLYGON, POLYGONZ and POLYGONM are sorted by the 2d shape
|
41
|
+
area. Shapes are assumed to be in canonical ordering, so that
|
42
|
+
the area of interior rings (if any) is subtracted from the
|
43
|
+
area of exterior rings.
|
44
|
+
|
@@ -0,0 +1,123 @@
|
|
1
|
+
/******************************************************************************
|
2
|
+
* Copyright (c) 1999, Carl Anderson
|
3
|
+
*
|
4
|
+
* this code is based in part on the earlier work of Frank Warmerdam
|
5
|
+
*
|
6
|
+
* Permission is hereby granted, free of charge, to any person obtaining a
|
7
|
+
* copy of this software and associated documentation files (the "Software"),
|
8
|
+
* to deal in the Software without restriction, including without limitation
|
9
|
+
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
10
|
+
* and/or sell copies of the Software, and to permit persons to whom the
|
11
|
+
* Software is furnished to do so, subject to the following conditions:
|
12
|
+
*
|
13
|
+
* The above copyright notice and this permission notice shall be included
|
14
|
+
* in all copies or substantial portions of the Software.
|
15
|
+
*
|
16
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
17
|
+
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
19
|
+
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
22
|
+
* DEALINGS IN THE SOFTWARE.
|
23
|
+
******************************************************************************
|
24
|
+
*
|
25
|
+
* shpwkb.c - test WKB binary Input / Output
|
26
|
+
*
|
27
|
+
*
|
28
|
+
* $Log: shpwkb.c,v $
|
29
|
+
* Revision 1.1 1999-05-26 02:29:36 candrsn
|
30
|
+
* OGis Well Known Binary test program (output only)
|
31
|
+
*
|
32
|
+
*
|
33
|
+
*
|
34
|
+
*/
|
35
|
+
|
36
|
+
#include "shapefil.h"
|
37
|
+
#include "shpgeo.h"
|
38
|
+
|
39
|
+
int main( int argc, char ** argv )
|
40
|
+
{
|
41
|
+
SHPHandle old_SHP, new_SHP;
|
42
|
+
DBFHandle old_DBF, new_DBF;
|
43
|
+
int nShapeType, nEntities, nVertices, nParts, *panParts, i, iPart;
|
44
|
+
double *padVertices, adBounds[4];
|
45
|
+
const char *pszPlus;
|
46
|
+
DBFFieldType idfld_type;
|
47
|
+
int idfld, nflds;
|
48
|
+
char kv[257] = "";
|
49
|
+
char idfldName[120] = "";
|
50
|
+
char fldName[120] = "";
|
51
|
+
char shpFileName[120] = "";
|
52
|
+
char dbfFileName[120] = "";
|
53
|
+
char *DBFRow = NULL;
|
54
|
+
int Cpan[2] = { 0,0 };
|
55
|
+
int byRing = 0;
|
56
|
+
PT oCentrd, ringCentrd;
|
57
|
+
SHPObject *psCShape, *cent_pt;
|
58
|
+
double oArea = 0.0, oLen = 0.0;
|
59
|
+
WKBStreamObj *wkbObj = NULL;
|
60
|
+
FILE *wkb_file = NULL;
|
61
|
+
|
62
|
+
if( argc < 3 )
|
63
|
+
{
|
64
|
+
printf( "shpwkb shp_file wkb_file\n" );
|
65
|
+
exit( 1 );
|
66
|
+
}
|
67
|
+
|
68
|
+
old_SHP = SHPOpen (argv[1], "rb" );
|
69
|
+
old_DBF = DBFOpen (argv[1], "rb");
|
70
|
+
if( old_SHP == NULL || old_DBF == NULL )
|
71
|
+
{
|
72
|
+
printf( "Unable to open old files:%s\n", argv[1] );
|
73
|
+
exit( 1 );
|
74
|
+
}
|
75
|
+
|
76
|
+
wkb_file = fopen ( argv[2], "wb");
|
77
|
+
wkbObj = calloc ( 3, sizeof (int) );
|
78
|
+
|
79
|
+
SHPGetInfo( old_SHP, &nEntities, &nShapeType, NULL, NULL );
|
80
|
+
for( i = 0; i < nEntities; i++ )
|
81
|
+
{
|
82
|
+
int res ;
|
83
|
+
|
84
|
+
psCShape = SHPReadObject( old_SHP, i );
|
85
|
+
|
86
|
+
if ( byRing == 1 ) {
|
87
|
+
int ring, prevStart, ringDir;
|
88
|
+
double ringArea;
|
89
|
+
|
90
|
+
prevStart = psCShape->nVertices;
|
91
|
+
for ( ring = (psCShape->nParts - 1); ring >= 0; ring-- ) {
|
92
|
+
SHPObject *psO;
|
93
|
+
int j, numVtx, rStart;
|
94
|
+
|
95
|
+
rStart = psCShape->panPartStart[ring];
|
96
|
+
if ( ring == (psCShape->nParts -1) )
|
97
|
+
{ numVtx = psCShape->nVertices - rStart; }
|
98
|
+
else
|
99
|
+
{ numVtx = psCShape->panPartStart[ring+1] - rStart; }
|
100
|
+
|
101
|
+
printf ("(shpdata) Ring(%d) (%d for %d) \n", ring, rStart, numVtx);
|
102
|
+
psO = SHPClone ( psCShape, ring, ring + 1 );
|
103
|
+
|
104
|
+
SHPDestroyObject ( psO );
|
105
|
+
printf ("(shpdata) End Ring \n");
|
106
|
+
} /* (ring) [0,nParts */
|
107
|
+
|
108
|
+
} /* by ring */
|
109
|
+
|
110
|
+
printf ("gonna build a wkb \n");
|
111
|
+
res = SHPWriteOGisWKB ( wkbObj, psCShape );
|
112
|
+
printf ("gonna write a wkb that is %d bytes long \n", wkbObj->StreamPos );
|
113
|
+
fwrite ( (void*) wkbObj->wStream, 1, wkbObj->StreamPos, wkb_file );
|
114
|
+
}
|
115
|
+
|
116
|
+
|
117
|
+
free ( wkbObj );
|
118
|
+
SHPClose( old_SHP );
|
119
|
+
DBFClose( old_DBF );
|
120
|
+
if ( wkb_file ) fclose ( wkb_file );
|
121
|
+
|
122
|
+
printf ("\n");
|
123
|
+
}
|
@@ -0,0 +1,38 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
|
3
|
+
cd tests
|
4
|
+
|
5
|
+
rm test*
|
6
|
+
shpcreate test point
|
7
|
+
|
8
|
+
shpadd test -83.54949956 34.992401
|
9
|
+
shpadd test -83.52162155 34.99276748
|
10
|
+
shpadd test -84.01681518 34.67275985
|
11
|
+
shpadd test -84.15596023 34.64862437
|
12
|
+
shpadd test -83.61951463 34.54927047
|
13
|
+
|
14
|
+
dbfcreate test -s fd 30
|
15
|
+
dbfadd test "1"
|
16
|
+
dbfadd test "2"
|
17
|
+
dbfadd test "3"
|
18
|
+
dbfadd test "4"
|
19
|
+
dbfadd test "5"
|
20
|
+
|
21
|
+
../shpproj test test_1 -i=geographic -o="init=nad83:1002 units=us-ft"
|
22
|
+
../shpproj test_1 test_2 -o="proj=utm zone=16 units=m"
|
23
|
+
../shpproj test_2 test_3 -o=geographic
|
24
|
+
|
25
|
+
shpdump test > test.out
|
26
|
+
shpdump test_3 > test_3.out
|
27
|
+
result=`diff test.out test_3.out`
|
28
|
+
|
29
|
+
if [ -z "${result}" ]; then
|
30
|
+
echo success...
|
31
|
+
else
|
32
|
+
echo failure...
|
33
|
+
fi
|
34
|
+
|
35
|
+
rm test*
|
36
|
+
|
37
|
+
|
38
|
+
cd ..
|
@@ -0,0 +1,2221 @@
|
|
1
|
+
/******************************************************************************
|
2
|
+
* $Id: dbfopen.c,v 1.89 2011-07-24 05:59:25 fwarmerdam Exp $
|
3
|
+
*
|
4
|
+
* Project: Shapelib
|
5
|
+
* Purpose: Implementation of .dbf access API documented in dbf_api.html.
|
6
|
+
* Author: Frank Warmerdam, warmerdam@pobox.com
|
7
|
+
*
|
8
|
+
******************************************************************************
|
9
|
+
* Copyright (c) 1999, Frank Warmerdam
|
10
|
+
*
|
11
|
+
* This software is available under the following "MIT Style" license,
|
12
|
+
* or at the option of the licensee under the LGPL (see LICENSE.LGPL). This
|
13
|
+
* option is discussed in more detail in shapelib.html.
|
14
|
+
*
|
15
|
+
* --
|
16
|
+
*
|
17
|
+
* Permission is hereby granted, free of charge, to any person obtaining a
|
18
|
+
* copy of this software and associated documentation files (the "Software"),
|
19
|
+
* to deal in the Software without restriction, including without limitation
|
20
|
+
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
21
|
+
* and/or sell copies of the Software, and to permit persons to whom the
|
22
|
+
* Software is furnished to do so, subject to the following conditions:
|
23
|
+
*
|
24
|
+
* The above copyright notice and this permission notice shall be included
|
25
|
+
* in all copies or substantial portions of the Software.
|
26
|
+
*
|
27
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
28
|
+
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
29
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
30
|
+
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
31
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
32
|
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
33
|
+
* DEALINGS IN THE SOFTWARE.
|
34
|
+
******************************************************************************
|
35
|
+
*
|
36
|
+
* $Log: dbfopen.c,v $
|
37
|
+
* Revision 1.89 2011-07-24 05:59:25 fwarmerdam
|
38
|
+
* minimize use of CPLError in favor of SAHooks.Error()
|
39
|
+
*
|
40
|
+
* Revision 1.88 2011-05-13 17:35:17 fwarmerdam
|
41
|
+
* added DBFReorderFields() and DBFAlterFields() functions (from Even)
|
42
|
+
*
|
43
|
+
* Revision 1.87 2011-05-07 22:41:02 fwarmerdam
|
44
|
+
* ensure pending record is flushed when adding a native field (GDAL #4073)
|
45
|
+
*
|
46
|
+
* Revision 1.86 2011-04-17 15:15:29 fwarmerdam
|
47
|
+
* Removed unused variable.
|
48
|
+
*
|
49
|
+
* Revision 1.85 2010-12-06 16:09:34 fwarmerdam
|
50
|
+
* fix buffer read overrun fetching code page (bug 2276)
|
51
|
+
*
|
52
|
+
* Revision 1.84 2009-10-29 19:59:48 fwarmerdam
|
53
|
+
* avoid crash on truncated header (gdal #3093)
|
54
|
+
*
|
55
|
+
* Revision 1.83 2008/11/12 14:28:15 fwarmerdam
|
56
|
+
* DBFCreateField() now works on files with records
|
57
|
+
*
|
58
|
+
* Revision 1.82 2008/11/11 17:47:09 fwarmerdam
|
59
|
+
* added DBFDeleteField() function
|
60
|
+
*
|
61
|
+
* Revision 1.81 2008/01/03 17:48:13 bram
|
62
|
+
* in DBFCreate, use default code page LDID/87 (= 0x57, ANSI)
|
63
|
+
* instead of LDID/3. This seems to be the same as what ESRI
|
64
|
+
* would be doing by default.
|
65
|
+
*
|
66
|
+
* Revision 1.80 2007/12/30 14:36:39 fwarmerdam
|
67
|
+
* avoid syntax issue with last comment.
|
68
|
+
*
|
69
|
+
* Revision 1.79 2007/12/30 14:35:48 fwarmerdam
|
70
|
+
* Avoid char* / unsigned char* warnings.
|
71
|
+
*
|
72
|
+
* Revision 1.78 2007/12/18 18:28:07 bram
|
73
|
+
* - create hook for client specific atof (bugzilla ticket 1615)
|
74
|
+
* - check for NULL handle before closing cpCPG file, and close after reading.
|
75
|
+
*
|
76
|
+
* Revision 1.77 2007/12/15 20:25:21 bram
|
77
|
+
* dbfopen.c now reads the Code Page information from the DBF file, and exports
|
78
|
+
* this information as a string through the DBFGetCodePage function. This is
|
79
|
+
* either the number from the LDID header field ("LDID/<number>") or as the
|
80
|
+
* content of an accompanying .CPG file. When creating a DBF file, the code can
|
81
|
+
* be set using DBFCreateEx.
|
82
|
+
*
|
83
|
+
* Revision 1.76 2007/12/12 22:21:32 bram
|
84
|
+
* DBFClose: check for NULL psDBF handle before trying to close it.
|
85
|
+
*
|
86
|
+
* Revision 1.75 2007/12/06 13:58:19 fwarmerdam
|
87
|
+
* make sure file offset calculations are done in as SAOffset
|
88
|
+
*
|
89
|
+
* Revision 1.74 2007/12/06 07:00:25 fwarmerdam
|
90
|
+
* dbfopen now using SAHooks for fileio
|
91
|
+
*
|
92
|
+
* Revision 1.73 2007/09/03 19:48:11 fwarmerdam
|
93
|
+
* move DBFReadAttribute() static dDoubleField into dbfinfo
|
94
|
+
*
|
95
|
+
* Revision 1.72 2007/09/03 19:34:06 fwarmerdam
|
96
|
+
* Avoid use of static tuple buffer in DBFReadTuple()
|
97
|
+
*
|
98
|
+
* Revision 1.71 2006/06/22 14:37:18 fwarmerdam
|
99
|
+
* avoid memory leak if dbfopen fread fails
|
100
|
+
*
|
101
|
+
* Revision 1.70 2006/06/17 17:47:05 fwarmerdam
|
102
|
+
* use calloc() for dbfinfo in DBFCreate
|
103
|
+
*
|
104
|
+
* Revision 1.69 2006/06/17 15:34:32 fwarmerdam
|
105
|
+
* disallow creating fields wider than 255
|
106
|
+
*
|
107
|
+
* Revision 1.68 2006/06/17 15:12:40 fwarmerdam
|
108
|
+
* Fixed C++ style comments.
|
109
|
+
*
|
110
|
+
* Revision 1.67 2006/06/17 00:24:53 fwarmerdam
|
111
|
+
* Don't treat non-zero decimals values as high order byte for length
|
112
|
+
* for strings. It causes serious corruption for some files.
|
113
|
+
* http://bugzilla.remotesensing.org/show_bug.cgi?id=1202
|
114
|
+
*
|
115
|
+
* Revision 1.66 2006/03/29 18:26:20 fwarmerdam
|
116
|
+
* fixed bug with size of pachfieldtype in dbfcloneempty
|
117
|
+
*
|
118
|
+
* Revision 1.65 2006/02/15 01:14:30 fwarmerdam
|
119
|
+
* added DBFAddNativeFieldType
|
120
|
+
*
|
121
|
+
* Revision 1.64 2006/02/09 00:29:04 fwarmerdam
|
122
|
+
* Changed to put spaces into string fields that are NULL as
|
123
|
+
* per http://bugzilla.maptools.org/show_bug.cgi?id=316.
|
124
|
+
*
|
125
|
+
* Revision 1.63 2006/01/25 15:35:43 fwarmerdam
|
126
|
+
* check success on DBFFlushRecord
|
127
|
+
*
|
128
|
+
* Revision 1.62 2006/01/10 16:28:03 fwarmerdam
|
129
|
+
* Fixed typo in CPLError.
|
130
|
+
*
|
131
|
+
* Revision 1.61 2006/01/10 16:26:29 fwarmerdam
|
132
|
+
* Push loading record buffer into DBFLoadRecord.
|
133
|
+
* Implement CPL error reporting if USE_CPL defined.
|
134
|
+
*
|
135
|
+
* Revision 1.60 2006/01/05 01:27:27 fwarmerdam
|
136
|
+
* added dbf deletion mark/fetch
|
137
|
+
*
|
138
|
+
* Revision 1.59 2005/03/14 15:20:28 fwarmerdam
|
139
|
+
* Fixed last change.
|
140
|
+
*
|
141
|
+
* Revision 1.58 2005/03/14 15:18:54 fwarmerdam
|
142
|
+
* Treat very wide fields with no decimals as double. This is
|
143
|
+
* more than 32bit integer fields.
|
144
|
+
*
|
145
|
+
* Revision 1.57 2005/02/10 20:16:54 fwarmerdam
|
146
|
+
* Make the pszStringField buffer for DBFReadAttribute() static char [256]
|
147
|
+
* as per bug 306.
|
148
|
+
*
|
149
|
+
* Revision 1.56 2005/02/10 20:07:56 fwarmerdam
|
150
|
+
* Fixed bug 305 in DBFCloneEmpty() - header length problem.
|
151
|
+
*
|
152
|
+
* Revision 1.55 2004/09/26 20:23:46 fwarmerdam
|
153
|
+
* avoid warnings with rcsid and signed/unsigned stuff
|
154
|
+
*
|
155
|
+
* Revision 1.54 2004/09/15 16:26:10 fwarmerdam
|
156
|
+
* Treat all blank numeric fields as null too.
|
157
|
+
*/
|
158
|
+
|
159
|
+
#include "shapefil.h"
|
160
|
+
|
161
|
+
#include <math.h>
|
162
|
+
#include <stdlib.h>
|
163
|
+
#include <ctype.h>
|
164
|
+
#include <string.h>
|
165
|
+
|
166
|
+
SHP_CVSID("$Id: dbfopen.c,v 1.89 2011-07-24 05:59:25 fwarmerdam Exp $")
|
167
|
+
|
168
|
+
#ifndef FALSE
|
169
|
+
# define FALSE 0
|
170
|
+
# define TRUE 1
|
171
|
+
#endif
|
172
|
+
|
173
|
+
/************************************************************************/
|
174
|
+
/* SfRealloc() */
|
175
|
+
/* */
|
176
|
+
/* A realloc cover function that will access a NULL pointer as */
|
177
|
+
/* a valid input. */
|
178
|
+
/************************************************************************/
|
179
|
+
|
180
|
+
static void * SfRealloc( void * pMem, int nNewSize )
|
181
|
+
|
182
|
+
{
|
183
|
+
if( pMem == NULL )
|
184
|
+
return( (void *) malloc(nNewSize) );
|
185
|
+
else
|
186
|
+
return( (void *) realloc(pMem,nNewSize) );
|
187
|
+
}
|
188
|
+
|
189
|
+
/************************************************************************/
|
190
|
+
/* DBFWriteHeader() */
|
191
|
+
/* */
|
192
|
+
/* This is called to write out the file header, and field */
|
193
|
+
/* descriptions before writing any actual data records. This */
|
194
|
+
/* also computes all the DBFDataSet field offset/size/decimals */
|
195
|
+
/* and so forth values. */
|
196
|
+
/************************************************************************/
|
197
|
+
|
198
|
+
static void DBFWriteHeader(DBFHandle psDBF)
|
199
|
+
|
200
|
+
{
|
201
|
+
unsigned char abyHeader[XBASE_FLDHDR_SZ];
|
202
|
+
int i;
|
203
|
+
|
204
|
+
if( !psDBF->bNoHeader )
|
205
|
+
return;
|
206
|
+
|
207
|
+
psDBF->bNoHeader = FALSE;
|
208
|
+
|
209
|
+
/* -------------------------------------------------------------------- */
|
210
|
+
/* Initialize the file header information. */
|
211
|
+
/* -------------------------------------------------------------------- */
|
212
|
+
for( i = 0; i < XBASE_FLDHDR_SZ; i++ )
|
213
|
+
abyHeader[i] = 0;
|
214
|
+
|
215
|
+
abyHeader[0] = 0x03; /* memo field? - just copying */
|
216
|
+
|
217
|
+
/* write out a dummy date */
|
218
|
+
abyHeader[1] = 95; /* YY */
|
219
|
+
abyHeader[2] = 7; /* MM */
|
220
|
+
abyHeader[3] = 26; /* DD */
|
221
|
+
|
222
|
+
/* record count preset at zero */
|
223
|
+
|
224
|
+
abyHeader[8] = (unsigned char) (psDBF->nHeaderLength % 256);
|
225
|
+
abyHeader[9] = (unsigned char) (psDBF->nHeaderLength / 256);
|
226
|
+
|
227
|
+
abyHeader[10] = (unsigned char) (psDBF->nRecordLength % 256);
|
228
|
+
abyHeader[11] = (unsigned char) (psDBF->nRecordLength / 256);
|
229
|
+
|
230
|
+
abyHeader[29] = (unsigned char) (psDBF->iLanguageDriver);
|
231
|
+
|
232
|
+
/* -------------------------------------------------------------------- */
|
233
|
+
/* Write the initial 32 byte file header, and all the field */
|
234
|
+
/* descriptions. */
|
235
|
+
/* -------------------------------------------------------------------- */
|
236
|
+
psDBF->sHooks.FSeek( psDBF->fp, 0, 0 );
|
237
|
+
psDBF->sHooks.FWrite( abyHeader, XBASE_FLDHDR_SZ, 1, psDBF->fp );
|
238
|
+
psDBF->sHooks.FWrite( psDBF->pszHeader, XBASE_FLDHDR_SZ, psDBF->nFields,
|
239
|
+
psDBF->fp );
|
240
|
+
|
241
|
+
/* -------------------------------------------------------------------- */
|
242
|
+
/* Write out the newline character if there is room for it. */
|
243
|
+
/* -------------------------------------------------------------------- */
|
244
|
+
if( psDBF->nHeaderLength > 32*psDBF->nFields + 32 )
|
245
|
+
{
|
246
|
+
char cNewline;
|
247
|
+
|
248
|
+
cNewline = 0x0d;
|
249
|
+
psDBF->sHooks.FWrite( &cNewline, 1, 1, psDBF->fp );
|
250
|
+
}
|
251
|
+
}
|
252
|
+
|
253
|
+
/************************************************************************/
|
254
|
+
/* DBFFlushRecord() */
|
255
|
+
/* */
|
256
|
+
/* Write out the current record if there is one. */
|
257
|
+
/************************************************************************/
|
258
|
+
|
259
|
+
static int DBFFlushRecord( DBFHandle psDBF )
|
260
|
+
|
261
|
+
{
|
262
|
+
SAOffset nRecordOffset;
|
263
|
+
|
264
|
+
if( psDBF->bCurrentRecordModified && psDBF->nCurrentRecord > -1 )
|
265
|
+
{
|
266
|
+
psDBF->bCurrentRecordModified = FALSE;
|
267
|
+
|
268
|
+
nRecordOffset =
|
269
|
+
psDBF->nRecordLength * (SAOffset) psDBF->nCurrentRecord
|
270
|
+
+ psDBF->nHeaderLength;
|
271
|
+
|
272
|
+
if( psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 ) != 0
|
273
|
+
|| psDBF->sHooks.FWrite( psDBF->pszCurrentRecord,
|
274
|
+
psDBF->nRecordLength,
|
275
|
+
1, psDBF->fp ) != 1 )
|
276
|
+
{
|
277
|
+
char szMessage[128];
|
278
|
+
sprintf( szMessage, "Failure writing DBF record %d.",
|
279
|
+
psDBF->nCurrentRecord );
|
280
|
+
psDBF->sHooks.Error( szMessage );
|
281
|
+
return FALSE;
|
282
|
+
}
|
283
|
+
}
|
284
|
+
|
285
|
+
return TRUE;
|
286
|
+
}
|
287
|
+
|
288
|
+
/************************************************************************/
|
289
|
+
/* DBFLoadRecord() */
|
290
|
+
/************************************************************************/
|
291
|
+
|
292
|
+
static int DBFLoadRecord( DBFHandle psDBF, int iRecord )
|
293
|
+
|
294
|
+
{
|
295
|
+
if( psDBF->nCurrentRecord != iRecord )
|
296
|
+
{
|
297
|
+
SAOffset nRecordOffset;
|
298
|
+
|
299
|
+
if( !DBFFlushRecord( psDBF ) )
|
300
|
+
return FALSE;
|
301
|
+
|
302
|
+
nRecordOffset =
|
303
|
+
psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
|
304
|
+
|
305
|
+
if( psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, SEEK_SET ) != 0 )
|
306
|
+
{
|
307
|
+
char szMessage[128];
|
308
|
+
sprintf( szMessage, "fseek(%ld) failed on DBF file.\n",
|
309
|
+
(long) nRecordOffset );
|
310
|
+
psDBF->sHooks.Error( szMessage );
|
311
|
+
return FALSE;
|
312
|
+
}
|
313
|
+
|
314
|
+
if( psDBF->sHooks.FRead( psDBF->pszCurrentRecord,
|
315
|
+
psDBF->nRecordLength, 1, psDBF->fp ) != 1 )
|
316
|
+
{
|
317
|
+
char szMessage[128];
|
318
|
+
sprintf( szMessage, "fread(%d) failed on DBF file.\n",
|
319
|
+
psDBF->nRecordLength );
|
320
|
+
psDBF->sHooks.Error( szMessage );
|
321
|
+
return FALSE;
|
322
|
+
}
|
323
|
+
|
324
|
+
psDBF->nCurrentRecord = iRecord;
|
325
|
+
}
|
326
|
+
|
327
|
+
return TRUE;
|
328
|
+
}
|
329
|
+
|
330
|
+
/************************************************************************/
|
331
|
+
/* DBFUpdateHeader() */
|
332
|
+
/************************************************************************/
|
333
|
+
|
334
|
+
void SHPAPI_CALL
|
335
|
+
DBFUpdateHeader( DBFHandle psDBF )
|
336
|
+
|
337
|
+
{
|
338
|
+
unsigned char abyFileHeader[32];
|
339
|
+
|
340
|
+
if( psDBF->bNoHeader )
|
341
|
+
DBFWriteHeader( psDBF );
|
342
|
+
|
343
|
+
DBFFlushRecord( psDBF );
|
344
|
+
|
345
|
+
psDBF->sHooks.FSeek( psDBF->fp, 0, 0 );
|
346
|
+
psDBF->sHooks.FRead( abyFileHeader, 32, 1, psDBF->fp );
|
347
|
+
|
348
|
+
abyFileHeader[4] = (unsigned char) (psDBF->nRecords % 256);
|
349
|
+
abyFileHeader[5] = (unsigned char) ((psDBF->nRecords/256) % 256);
|
350
|
+
abyFileHeader[6] = (unsigned char) ((psDBF->nRecords/(256*256)) % 256);
|
351
|
+
abyFileHeader[7] = (unsigned char) ((psDBF->nRecords/(256*256*256)) % 256);
|
352
|
+
|
353
|
+
psDBF->sHooks.FSeek( psDBF->fp, 0, 0 );
|
354
|
+
psDBF->sHooks.FWrite( abyFileHeader, 32, 1, psDBF->fp );
|
355
|
+
|
356
|
+
psDBF->sHooks.FFlush( psDBF->fp );
|
357
|
+
}
|
358
|
+
|
359
|
+
/************************************************************************/
|
360
|
+
/* DBFOpen() */
|
361
|
+
/* */
|
362
|
+
/* Open a .dbf file. */
|
363
|
+
/************************************************************************/
|
364
|
+
|
365
|
+
DBFHandle SHPAPI_CALL
|
366
|
+
DBFOpen( const char * pszFilename, const char * pszAccess )
|
367
|
+
|
368
|
+
{
|
369
|
+
SAHooks sHooks;
|
370
|
+
|
371
|
+
SASetupDefaultHooks( &sHooks );
|
372
|
+
|
373
|
+
return DBFOpenLL( pszFilename, pszAccess, &sHooks );
|
374
|
+
}
|
375
|
+
|
376
|
+
/************************************************************************/
|
377
|
+
/* DBFOpen() */
|
378
|
+
/* */
|
379
|
+
/* Open a .dbf file. */
|
380
|
+
/************************************************************************/
|
381
|
+
|
382
|
+
DBFHandle SHPAPI_CALL
|
383
|
+
DBFOpenLL( const char * pszFilename, const char * pszAccess, SAHooks *psHooks )
|
384
|
+
|
385
|
+
{
|
386
|
+
DBFHandle psDBF;
|
387
|
+
SAFile pfCPG;
|
388
|
+
unsigned char *pabyBuf;
|
389
|
+
int nFields, nHeadLen, iField, i;
|
390
|
+
char *pszBasename, *pszFullname;
|
391
|
+
int nBufSize = 500;
|
392
|
+
|
393
|
+
/* -------------------------------------------------------------------- */
|
394
|
+
/* We only allow the access strings "rb" and "r+". */
|
395
|
+
/* -------------------------------------------------------------------- */
|
396
|
+
if( strcmp(pszAccess,"r") != 0 && strcmp(pszAccess,"r+") != 0
|
397
|
+
&& strcmp(pszAccess,"rb") != 0 && strcmp(pszAccess,"rb+") != 0
|
398
|
+
&& strcmp(pszAccess,"r+b") != 0 )
|
399
|
+
return( NULL );
|
400
|
+
|
401
|
+
if( strcmp(pszAccess,"r") == 0 )
|
402
|
+
pszAccess = "rb";
|
403
|
+
|
404
|
+
if( strcmp(pszAccess,"r+") == 0 )
|
405
|
+
pszAccess = "rb+";
|
406
|
+
|
407
|
+
/* -------------------------------------------------------------------- */
|
408
|
+
/* Compute the base (layer) name. If there is any extension */
|
409
|
+
/* on the passed in filename we will strip it off. */
|
410
|
+
/* -------------------------------------------------------------------- */
|
411
|
+
pszBasename = (char *) malloc(strlen(pszFilename)+5);
|
412
|
+
strcpy( pszBasename, pszFilename );
|
413
|
+
for( i = strlen(pszBasename)-1;
|
414
|
+
i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
|
415
|
+
&& pszBasename[i] != '\\';
|
416
|
+
i-- ) {}
|
417
|
+
|
418
|
+
if( pszBasename[i] == '.' )
|
419
|
+
pszBasename[i] = '\0';
|
420
|
+
|
421
|
+
pszFullname = (char *) malloc(strlen(pszBasename) + 5);
|
422
|
+
sprintf( pszFullname, "%s.dbf", pszBasename );
|
423
|
+
|
424
|
+
psDBF = (DBFHandle) calloc( 1, sizeof(DBFInfo) );
|
425
|
+
psDBF->fp = psHooks->FOpen( pszFullname, pszAccess );
|
426
|
+
memcpy( &(psDBF->sHooks), psHooks, sizeof(SAHooks) );
|
427
|
+
|
428
|
+
if( psDBF->fp == NULL )
|
429
|
+
{
|
430
|
+
sprintf( pszFullname, "%s.DBF", pszBasename );
|
431
|
+
psDBF->fp = psDBF->sHooks.FOpen(pszFullname, pszAccess );
|
432
|
+
}
|
433
|
+
|
434
|
+
sprintf( pszFullname, "%s.cpg", pszBasename );
|
435
|
+
pfCPG = psHooks->FOpen( pszFullname, "r" );
|
436
|
+
if( pfCPG == NULL )
|
437
|
+
{
|
438
|
+
sprintf( pszFullname, "%s.CPG", pszBasename );
|
439
|
+
pfCPG = psHooks->FOpen( pszFullname, "r" );
|
440
|
+
}
|
441
|
+
|
442
|
+
free( pszBasename );
|
443
|
+
free( pszFullname );
|
444
|
+
|
445
|
+
if( psDBF->fp == NULL )
|
446
|
+
{
|
447
|
+
free( psDBF );
|
448
|
+
if( pfCPG ) psHooks->FClose( pfCPG );
|
449
|
+
return( NULL );
|
450
|
+
}
|
451
|
+
|
452
|
+
psDBF->bNoHeader = FALSE;
|
453
|
+
psDBF->nCurrentRecord = -1;
|
454
|
+
psDBF->bCurrentRecordModified = FALSE;
|
455
|
+
|
456
|
+
/* -------------------------------------------------------------------- */
|
457
|
+
/* Read Table Header info */
|
458
|
+
/* -------------------------------------------------------------------- */
|
459
|
+
pabyBuf = (unsigned char *) malloc(nBufSize);
|
460
|
+
if( psDBF->sHooks.FRead( pabyBuf, 32, 1, psDBF->fp ) != 1 )
|
461
|
+
{
|
462
|
+
psDBF->sHooks.FClose( psDBF->fp );
|
463
|
+
if( pfCPG ) psDBF->sHooks.FClose( pfCPG );
|
464
|
+
free( pabyBuf );
|
465
|
+
free( psDBF );
|
466
|
+
return NULL;
|
467
|
+
}
|
468
|
+
|
469
|
+
psDBF->nRecords =
|
470
|
+
pabyBuf[4] + pabyBuf[5]*256 + pabyBuf[6]*256*256 + pabyBuf[7]*256*256*256;
|
471
|
+
|
472
|
+
psDBF->nHeaderLength = nHeadLen = pabyBuf[8] + pabyBuf[9]*256;
|
473
|
+
psDBF->nRecordLength = pabyBuf[10] + pabyBuf[11]*256;
|
474
|
+
psDBF->iLanguageDriver = pabyBuf[29];
|
475
|
+
|
476
|
+
if (nHeadLen < 32)
|
477
|
+
{
|
478
|
+
psDBF->sHooks.FClose( psDBF->fp );
|
479
|
+
if( pfCPG ) psDBF->sHooks.FClose( pfCPG );
|
480
|
+
free( pabyBuf );
|
481
|
+
free( psDBF );
|
482
|
+
return NULL;
|
483
|
+
}
|
484
|
+
|
485
|
+
psDBF->nFields = nFields = (nHeadLen - 32) / 32;
|
486
|
+
|
487
|
+
psDBF->pszCurrentRecord = (char *) malloc(psDBF->nRecordLength);
|
488
|
+
|
489
|
+
/* -------------------------------------------------------------------- */
|
490
|
+
/* Figure out the code page from the LDID and CPG */
|
491
|
+
/* -------------------------------------------------------------------- */
|
492
|
+
|
493
|
+
psDBF->pszCodePage = NULL;
|
494
|
+
if( pfCPG )
|
495
|
+
{
|
496
|
+
size_t n;
|
497
|
+
memset( pabyBuf, 0, nBufSize);
|
498
|
+
psDBF->sHooks.FRead( pabyBuf, nBufSize - 1, 1, pfCPG );
|
499
|
+
n = strcspn( (char *) pabyBuf, "\n\r" );
|
500
|
+
if( n > 0 )
|
501
|
+
{
|
502
|
+
pabyBuf[n] = '\0';
|
503
|
+
psDBF->pszCodePage = (char *) malloc(n + 1);
|
504
|
+
memcpy( psDBF->pszCodePage, pabyBuf, n + 1 );
|
505
|
+
}
|
506
|
+
psDBF->sHooks.FClose( pfCPG );
|
507
|
+
}
|
508
|
+
if( psDBF->pszCodePage == NULL && pabyBuf[29] != 0 )
|
509
|
+
{
|
510
|
+
sprintf( (char *) pabyBuf, "LDID/%d", psDBF->iLanguageDriver );
|
511
|
+
psDBF->pszCodePage = (char *) malloc(strlen((char*)pabyBuf) + 1);
|
512
|
+
strcpy( psDBF->pszCodePage, (char *) pabyBuf );
|
513
|
+
}
|
514
|
+
|
515
|
+
/* -------------------------------------------------------------------- */
|
516
|
+
/* Read in Field Definitions */
|
517
|
+
/* -------------------------------------------------------------------- */
|
518
|
+
|
519
|
+
pabyBuf = (unsigned char *) SfRealloc(pabyBuf,nHeadLen);
|
520
|
+
psDBF->pszHeader = (char *) pabyBuf;
|
521
|
+
|
522
|
+
psDBF->sHooks.FSeek( psDBF->fp, 32, 0 );
|
523
|
+
if( psDBF->sHooks.FRead( pabyBuf, nHeadLen-32, 1, psDBF->fp ) != 1 )
|
524
|
+
{
|
525
|
+
psDBF->sHooks.FClose( psDBF->fp );
|
526
|
+
free( pabyBuf );
|
527
|
+
free( psDBF->pszCurrentRecord );
|
528
|
+
free( psDBF );
|
529
|
+
return NULL;
|
530
|
+
}
|
531
|
+
|
532
|
+
psDBF->panFieldOffset = (int *) malloc(sizeof(int) * nFields);
|
533
|
+
psDBF->panFieldSize = (int *) malloc(sizeof(int) * nFields);
|
534
|
+
psDBF->panFieldDecimals = (int *) malloc(sizeof(int) * nFields);
|
535
|
+
psDBF->pachFieldType = (char *) malloc(sizeof(char) * nFields);
|
536
|
+
|
537
|
+
for( iField = 0; iField < nFields; iField++ )
|
538
|
+
{
|
539
|
+
unsigned char *pabyFInfo;
|
540
|
+
|
541
|
+
pabyFInfo = pabyBuf+iField*32;
|
542
|
+
|
543
|
+
if( pabyFInfo[11] == 'N' || pabyFInfo[11] == 'F' )
|
544
|
+
{
|
545
|
+
psDBF->panFieldSize[iField] = pabyFInfo[16];
|
546
|
+
psDBF->panFieldDecimals[iField] = pabyFInfo[17];
|
547
|
+
}
|
548
|
+
else
|
549
|
+
{
|
550
|
+
psDBF->panFieldSize[iField] = pabyFInfo[16];
|
551
|
+
psDBF->panFieldDecimals[iField] = 0;
|
552
|
+
|
553
|
+
/*
|
554
|
+
** The following seemed to be used sometimes to handle files with long
|
555
|
+
** string fields, but in other cases (such as bug 1202) the decimals field
|
556
|
+
** just seems to indicate some sort of preferred formatting, not very
|
557
|
+
** wide fields. So I have disabled this code. FrankW.
|
558
|
+
psDBF->panFieldSize[iField] = pabyFInfo[16] + pabyFInfo[17]*256;
|
559
|
+
psDBF->panFieldDecimals[iField] = 0;
|
560
|
+
*/
|
561
|
+
}
|
562
|
+
|
563
|
+
psDBF->pachFieldType[iField] = (char) pabyFInfo[11];
|
564
|
+
if( iField == 0 )
|
565
|
+
psDBF->panFieldOffset[iField] = 1;
|
566
|
+
else
|
567
|
+
psDBF->panFieldOffset[iField] =
|
568
|
+
psDBF->panFieldOffset[iField-1] + psDBF->panFieldSize[iField-1];
|
569
|
+
}
|
570
|
+
|
571
|
+
return( psDBF );
|
572
|
+
}
|
573
|
+
|
574
|
+
/************************************************************************/
|
575
|
+
/* DBFClose() */
|
576
|
+
/************************************************************************/
|
577
|
+
|
578
|
+
void SHPAPI_CALL
|
579
|
+
DBFClose(DBFHandle psDBF)
|
580
|
+
{
|
581
|
+
if( psDBF == NULL )
|
582
|
+
return;
|
583
|
+
|
584
|
+
/* -------------------------------------------------------------------- */
|
585
|
+
/* Write out header if not already written. */
|
586
|
+
/* -------------------------------------------------------------------- */
|
587
|
+
if( psDBF->bNoHeader )
|
588
|
+
DBFWriteHeader( psDBF );
|
589
|
+
|
590
|
+
DBFFlushRecord( psDBF );
|
591
|
+
|
592
|
+
/* -------------------------------------------------------------------- */
|
593
|
+
/* Update last access date, and number of records if we have */
|
594
|
+
/* write access. */
|
595
|
+
/* -------------------------------------------------------------------- */
|
596
|
+
if( psDBF->bUpdated )
|
597
|
+
DBFUpdateHeader( psDBF );
|
598
|
+
|
599
|
+
/* -------------------------------------------------------------------- */
|
600
|
+
/* Close, and free resources. */
|
601
|
+
/* -------------------------------------------------------------------- */
|
602
|
+
psDBF->sHooks.FClose( psDBF->fp );
|
603
|
+
|
604
|
+
if( psDBF->panFieldOffset != NULL )
|
605
|
+
{
|
606
|
+
free( psDBF->panFieldOffset );
|
607
|
+
free( psDBF->panFieldSize );
|
608
|
+
free( psDBF->panFieldDecimals );
|
609
|
+
free( psDBF->pachFieldType );
|
610
|
+
}
|
611
|
+
|
612
|
+
if( psDBF->pszWorkField != NULL )
|
613
|
+
free( psDBF->pszWorkField );
|
614
|
+
|
615
|
+
free( psDBF->pszHeader );
|
616
|
+
free( psDBF->pszCurrentRecord );
|
617
|
+
free( psDBF->pszCodePage );
|
618
|
+
|
619
|
+
free( psDBF );
|
620
|
+
}
|
621
|
+
|
622
|
+
/************************************************************************/
|
623
|
+
/* DBFCreate() */
|
624
|
+
/* */
|
625
|
+
/* Create a new .dbf file with default code page LDID/87 (0x57) */
|
626
|
+
/************************************************************************/
|
627
|
+
|
628
|
+
DBFHandle SHPAPI_CALL
|
629
|
+
DBFCreate( const char * pszFilename )
|
630
|
+
|
631
|
+
{
|
632
|
+
return DBFCreateEx( pszFilename, "LDID/87" ); // 0x57
|
633
|
+
}
|
634
|
+
|
635
|
+
/************************************************************************/
|
636
|
+
/* DBFCreateEx() */
|
637
|
+
/* */
|
638
|
+
/* Create a new .dbf file. */
|
639
|
+
/************************************************************************/
|
640
|
+
|
641
|
+
DBFHandle SHPAPI_CALL
|
642
|
+
DBFCreateEx( const char * pszFilename, const char* pszCodePage )
|
643
|
+
|
644
|
+
{
|
645
|
+
SAHooks sHooks;
|
646
|
+
|
647
|
+
SASetupDefaultHooks( &sHooks );
|
648
|
+
|
649
|
+
return DBFCreateLL( pszFilename, pszCodePage , &sHooks );
|
650
|
+
}
|
651
|
+
|
652
|
+
/************************************************************************/
|
653
|
+
/* DBFCreate() */
|
654
|
+
/* */
|
655
|
+
/* Create a new .dbf file. */
|
656
|
+
/************************************************************************/
|
657
|
+
|
658
|
+
DBFHandle SHPAPI_CALL
|
659
|
+
DBFCreateLL( const char * pszFilename, const char * pszCodePage, SAHooks *psHooks )
|
660
|
+
|
661
|
+
{
|
662
|
+
DBFHandle psDBF;
|
663
|
+
SAFile fp;
|
664
|
+
char *pszFullname, *pszBasename;
|
665
|
+
int i, ldid = -1;
|
666
|
+
char chZero = '\0';
|
667
|
+
|
668
|
+
/* -------------------------------------------------------------------- */
|
669
|
+
/* Compute the base (layer) name. If there is any extension */
|
670
|
+
/* on the passed in filename we will strip it off. */
|
671
|
+
/* -------------------------------------------------------------------- */
|
672
|
+
pszBasename = (char *) malloc(strlen(pszFilename)+5);
|
673
|
+
strcpy( pszBasename, pszFilename );
|
674
|
+
for( i = strlen(pszBasename)-1;
|
675
|
+
i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
|
676
|
+
&& pszBasename[i] != '\\';
|
677
|
+
i-- ) {}
|
678
|
+
|
679
|
+
if( pszBasename[i] == '.' )
|
680
|
+
pszBasename[i] = '\0';
|
681
|
+
|
682
|
+
pszFullname = (char *) malloc(strlen(pszBasename) + 5);
|
683
|
+
sprintf( pszFullname, "%s.dbf", pszBasename );
|
684
|
+
|
685
|
+
/* -------------------------------------------------------------------- */
|
686
|
+
/* Create the file. */
|
687
|
+
/* -------------------------------------------------------------------- */
|
688
|
+
fp = psHooks->FOpen( pszFullname, "wb" );
|
689
|
+
if( fp == NULL )
|
690
|
+
return( NULL );
|
691
|
+
|
692
|
+
psHooks->FWrite( &chZero, 1, 1, fp );
|
693
|
+
psHooks->FClose( fp );
|
694
|
+
|
695
|
+
fp = psHooks->FOpen( pszFullname, "rb+" );
|
696
|
+
if( fp == NULL )
|
697
|
+
return( NULL );
|
698
|
+
|
699
|
+
|
700
|
+
sprintf( pszFullname, "%s.cpg", pszBasename );
|
701
|
+
if( pszCodePage != NULL )
|
702
|
+
{
|
703
|
+
if( strncmp( pszCodePage, "LDID/", 5 ) == 0 )
|
704
|
+
{
|
705
|
+
ldid = atoi( pszCodePage + 5 );
|
706
|
+
if( ldid > 255 )
|
707
|
+
ldid = -1; // don't use 0 to indicate out of range as LDID/0 is a valid one
|
708
|
+
}
|
709
|
+
if( ldid < 0 )
|
710
|
+
{
|
711
|
+
SAFile fpCPG = psHooks->FOpen( pszFullname, "w" );
|
712
|
+
psHooks->FWrite( (char*) pszCodePage, strlen(pszCodePage), 1, fpCPG );
|
713
|
+
psHooks->FClose( fpCPG );
|
714
|
+
}
|
715
|
+
}
|
716
|
+
if( pszCodePage == NULL || ldid >= 0 )
|
717
|
+
{
|
718
|
+
psHooks->Remove( pszFullname );
|
719
|
+
}
|
720
|
+
|
721
|
+
free( pszBasename );
|
722
|
+
free( pszFullname );
|
723
|
+
|
724
|
+
/* -------------------------------------------------------------------- */
|
725
|
+
/* Create the info structure. */
|
726
|
+
/* -------------------------------------------------------------------- */
|
727
|
+
psDBF = (DBFHandle) calloc(1,sizeof(DBFInfo));
|
728
|
+
|
729
|
+
memcpy( &(psDBF->sHooks), psHooks, sizeof(SAHooks) );
|
730
|
+
psDBF->fp = fp;
|
731
|
+
psDBF->nRecords = 0;
|
732
|
+
psDBF->nFields = 0;
|
733
|
+
psDBF->nRecordLength = 1;
|
734
|
+
psDBF->nHeaderLength = 33;
|
735
|
+
|
736
|
+
psDBF->panFieldOffset = NULL;
|
737
|
+
psDBF->panFieldSize = NULL;
|
738
|
+
psDBF->panFieldDecimals = NULL;
|
739
|
+
psDBF->pachFieldType = NULL;
|
740
|
+
psDBF->pszHeader = NULL;
|
741
|
+
|
742
|
+
psDBF->nCurrentRecord = -1;
|
743
|
+
psDBF->bCurrentRecordModified = FALSE;
|
744
|
+
psDBF->pszCurrentRecord = NULL;
|
745
|
+
|
746
|
+
psDBF->bNoHeader = TRUE;
|
747
|
+
|
748
|
+
psDBF->iLanguageDriver = ldid > 0 ? ldid : 0;
|
749
|
+
psDBF->pszCodePage = NULL;
|
750
|
+
if( pszCodePage )
|
751
|
+
{
|
752
|
+
psDBF->pszCodePage = (char * ) malloc( strlen(pszCodePage) + 1 );
|
753
|
+
strcpy( psDBF->pszCodePage, pszCodePage );
|
754
|
+
}
|
755
|
+
|
756
|
+
return( psDBF );
|
757
|
+
}
|
758
|
+
|
759
|
+
/************************************************************************/
|
760
|
+
/* DBFAddField() */
|
761
|
+
/* */
|
762
|
+
/* Add a field to a newly created .dbf or to an existing one */
|
763
|
+
/************************************************************************/
|
764
|
+
|
765
|
+
int SHPAPI_CALL
|
766
|
+
DBFAddField(DBFHandle psDBF, const char * pszFieldName,
|
767
|
+
DBFFieldType eType, int nWidth, int nDecimals )
|
768
|
+
|
769
|
+
{
|
770
|
+
char chNativeType = 'C';
|
771
|
+
|
772
|
+
if( eType == FTLogical )
|
773
|
+
chNativeType = 'L';
|
774
|
+
else if( eType == FTString )
|
775
|
+
chNativeType = 'C';
|
776
|
+
else
|
777
|
+
chNativeType = 'N';
|
778
|
+
|
779
|
+
return DBFAddNativeFieldType( psDBF, pszFieldName, chNativeType,
|
780
|
+
nWidth, nDecimals );
|
781
|
+
}
|
782
|
+
|
783
|
+
/************************************************************************/
|
784
|
+
/* DBFGetNullCharacter() */
|
785
|
+
/************************************************************************/
|
786
|
+
|
787
|
+
static char DBFGetNullCharacter(char chType)
|
788
|
+
{
|
789
|
+
switch (chType)
|
790
|
+
{
|
791
|
+
case 'N':
|
792
|
+
case 'F':
|
793
|
+
return '*';
|
794
|
+
case 'D':
|
795
|
+
return '0';
|
796
|
+
case 'L':
|
797
|
+
return '?';
|
798
|
+
default:
|
799
|
+
return ' ';
|
800
|
+
}
|
801
|
+
}
|
802
|
+
|
803
|
+
/************************************************************************/
|
804
|
+
/* DBFAddField() */
|
805
|
+
/* */
|
806
|
+
/* Add a field to a newly created .dbf file before any records */
|
807
|
+
/* are written. */
|
808
|
+
/************************************************************************/
|
809
|
+
|
810
|
+
int SHPAPI_CALL
|
811
|
+
DBFAddNativeFieldType(DBFHandle psDBF, const char * pszFieldName,
|
812
|
+
char chType, int nWidth, int nDecimals )
|
813
|
+
|
814
|
+
{
|
815
|
+
char *pszFInfo;
|
816
|
+
int i;
|
817
|
+
int nOldRecordLength, nOldHeaderLength;
|
818
|
+
char *pszRecord;
|
819
|
+
char chFieldFill;
|
820
|
+
SAOffset nRecordOffset;
|
821
|
+
|
822
|
+
/* make sure that everything is written in .dbf */
|
823
|
+
if( !DBFFlushRecord( psDBF ) )
|
824
|
+
return -1;
|
825
|
+
|
826
|
+
/* -------------------------------------------------------------------- */
|
827
|
+
/* Do some checking to ensure we can add records to this file. */
|
828
|
+
/* -------------------------------------------------------------------- */
|
829
|
+
if( nWidth < 1 )
|
830
|
+
return -1;
|
831
|
+
|
832
|
+
if( nWidth > 255 )
|
833
|
+
nWidth = 255;
|
834
|
+
|
835
|
+
nOldRecordLength = psDBF->nRecordLength;
|
836
|
+
nOldHeaderLength = psDBF->nHeaderLength;
|
837
|
+
|
838
|
+
/* -------------------------------------------------------------------- */
|
839
|
+
/* SfRealloc all the arrays larger to hold the additional field */
|
840
|
+
/* information. */
|
841
|
+
/* -------------------------------------------------------------------- */
|
842
|
+
psDBF->nFields++;
|
843
|
+
|
844
|
+
psDBF->panFieldOffset = (int *)
|
845
|
+
SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
|
846
|
+
|
847
|
+
psDBF->panFieldSize = (int *)
|
848
|
+
SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
|
849
|
+
|
850
|
+
psDBF->panFieldDecimals = (int *)
|
851
|
+
SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
|
852
|
+
|
853
|
+
psDBF->pachFieldType = (char *)
|
854
|
+
SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields );
|
855
|
+
|
856
|
+
/* -------------------------------------------------------------------- */
|
857
|
+
/* Assign the new field information fields. */
|
858
|
+
/* -------------------------------------------------------------------- */
|
859
|
+
psDBF->panFieldOffset[psDBF->nFields-1] = psDBF->nRecordLength;
|
860
|
+
psDBF->nRecordLength += nWidth;
|
861
|
+
psDBF->panFieldSize[psDBF->nFields-1] = nWidth;
|
862
|
+
psDBF->panFieldDecimals[psDBF->nFields-1] = nDecimals;
|
863
|
+
psDBF->pachFieldType[psDBF->nFields-1] = chType;
|
864
|
+
|
865
|
+
/* -------------------------------------------------------------------- */
|
866
|
+
/* Extend the required header information. */
|
867
|
+
/* -------------------------------------------------------------------- */
|
868
|
+
psDBF->nHeaderLength += 32;
|
869
|
+
psDBF->bUpdated = FALSE;
|
870
|
+
|
871
|
+
psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,psDBF->nFields*32);
|
872
|
+
|
873
|
+
pszFInfo = psDBF->pszHeader + 32 * (psDBF->nFields-1);
|
874
|
+
|
875
|
+
for( i = 0; i < 32; i++ )
|
876
|
+
pszFInfo[i] = '\0';
|
877
|
+
|
878
|
+
if( (int) strlen(pszFieldName) < 10 )
|
879
|
+
strncpy( pszFInfo, pszFieldName, strlen(pszFieldName));
|
880
|
+
else
|
881
|
+
strncpy( pszFInfo, pszFieldName, 10);
|
882
|
+
|
883
|
+
pszFInfo[11] = psDBF->pachFieldType[psDBF->nFields-1];
|
884
|
+
|
885
|
+
if( chType == 'C' )
|
886
|
+
{
|
887
|
+
pszFInfo[16] = (unsigned char) (nWidth % 256);
|
888
|
+
pszFInfo[17] = (unsigned char) (nWidth / 256);
|
889
|
+
}
|
890
|
+
else
|
891
|
+
{
|
892
|
+
pszFInfo[16] = (unsigned char) nWidth;
|
893
|
+
pszFInfo[17] = (unsigned char) nDecimals;
|
894
|
+
}
|
895
|
+
|
896
|
+
/* -------------------------------------------------------------------- */
|
897
|
+
/* Make the current record buffer appropriately larger. */
|
898
|
+
/* -------------------------------------------------------------------- */
|
899
|
+
psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord,
|
900
|
+
psDBF->nRecordLength);
|
901
|
+
|
902
|
+
/* we're done if dealing with new .dbf */
|
903
|
+
if( psDBF->bNoHeader )
|
904
|
+
return( psDBF->nFields - 1 );
|
905
|
+
|
906
|
+
/* -------------------------------------------------------------------- */
|
907
|
+
/* For existing .dbf file, shift records */
|
908
|
+
/* -------------------------------------------------------------------- */
|
909
|
+
|
910
|
+
/* alloc record */
|
911
|
+
pszRecord = (char *) malloc(sizeof(char) * psDBF->nRecordLength);
|
912
|
+
|
913
|
+
chFieldFill = DBFGetNullCharacter(chType);
|
914
|
+
|
915
|
+
for (i = psDBF->nRecords-1; i >= 0; --i)
|
916
|
+
{
|
917
|
+
nRecordOffset = nOldRecordLength * (SAOffset) i + nOldHeaderLength;
|
918
|
+
|
919
|
+
/* load record */
|
920
|
+
psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
|
921
|
+
psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp );
|
922
|
+
|
923
|
+
/* set new field's value to NULL */
|
924
|
+
memset(pszRecord + nOldRecordLength, chFieldFill, nWidth);
|
925
|
+
|
926
|
+
nRecordOffset = psDBF->nRecordLength * (SAOffset) i + psDBF->nHeaderLength;
|
927
|
+
|
928
|
+
/* move record to the new place*/
|
929
|
+
psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
|
930
|
+
psDBF->sHooks.FWrite( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
|
931
|
+
}
|
932
|
+
|
933
|
+
/* free record */
|
934
|
+
free(pszRecord);
|
935
|
+
|
936
|
+
/* force update of header with new header, record length and new field */
|
937
|
+
psDBF->bNoHeader = TRUE;
|
938
|
+
DBFUpdateHeader( psDBF );
|
939
|
+
|
940
|
+
psDBF->nCurrentRecord = -1;
|
941
|
+
psDBF->bCurrentRecordModified = FALSE;
|
942
|
+
|
943
|
+
return( psDBF->nFields-1 );
|
944
|
+
}
|
945
|
+
|
946
|
+
/************************************************************************/
|
947
|
+
/* DBFReadAttribute() */
|
948
|
+
/* */
|
949
|
+
/* Read one of the attribute fields of a record. */
|
950
|
+
/************************************************************************/
|
951
|
+
|
952
|
+
static void *DBFReadAttribute(DBFHandle psDBF, int hEntity, int iField,
|
953
|
+
char chReqType )
|
954
|
+
|
955
|
+
{
|
956
|
+
unsigned char *pabyRec;
|
957
|
+
void *pReturnField = NULL;
|
958
|
+
|
959
|
+
/* -------------------------------------------------------------------- */
|
960
|
+
/* Verify selection. */
|
961
|
+
/* -------------------------------------------------------------------- */
|
962
|
+
if( hEntity < 0 || hEntity >= psDBF->nRecords )
|
963
|
+
return( NULL );
|
964
|
+
|
965
|
+
if( iField < 0 || iField >= psDBF->nFields )
|
966
|
+
return( NULL );
|
967
|
+
|
968
|
+
/* -------------------------------------------------------------------- */
|
969
|
+
/* Have we read the record? */
|
970
|
+
/* -------------------------------------------------------------------- */
|
971
|
+
if( !DBFLoadRecord( psDBF, hEntity ) )
|
972
|
+
return NULL;
|
973
|
+
|
974
|
+
pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
|
975
|
+
|
976
|
+
/* -------------------------------------------------------------------- */
|
977
|
+
/* Ensure we have room to extract the target field. */
|
978
|
+
/* -------------------------------------------------------------------- */
|
979
|
+
if( psDBF->panFieldSize[iField] >= psDBF->nWorkFieldLength )
|
980
|
+
{
|
981
|
+
psDBF->nWorkFieldLength = psDBF->panFieldSize[iField] + 100;
|
982
|
+
if( psDBF->pszWorkField == NULL )
|
983
|
+
psDBF->pszWorkField = (char *) malloc(psDBF->nWorkFieldLength);
|
984
|
+
else
|
985
|
+
psDBF->pszWorkField = (char *) realloc(psDBF->pszWorkField,
|
986
|
+
psDBF->nWorkFieldLength);
|
987
|
+
}
|
988
|
+
|
989
|
+
/* -------------------------------------------------------------------- */
|
990
|
+
/* Extract the requested field. */
|
991
|
+
/* -------------------------------------------------------------------- */
|
992
|
+
strncpy( psDBF->pszWorkField,
|
993
|
+
((const char *) pabyRec) + psDBF->panFieldOffset[iField],
|
994
|
+
psDBF->panFieldSize[iField] );
|
995
|
+
psDBF->pszWorkField[psDBF->panFieldSize[iField]] = '\0';
|
996
|
+
|
997
|
+
pReturnField = psDBF->pszWorkField;
|
998
|
+
|
999
|
+
/* -------------------------------------------------------------------- */
|
1000
|
+
/* Decode the field. */
|
1001
|
+
/* -------------------------------------------------------------------- */
|
1002
|
+
if( chReqType == 'N' )
|
1003
|
+
{
|
1004
|
+
psDBF->dfDoubleField = psDBF->sHooks.Atof(psDBF->pszWorkField);
|
1005
|
+
|
1006
|
+
pReturnField = &(psDBF->dfDoubleField);
|
1007
|
+
}
|
1008
|
+
|
1009
|
+
/* -------------------------------------------------------------------- */
|
1010
|
+
/* Should we trim white space off the string attribute value? */
|
1011
|
+
/* -------------------------------------------------------------------- */
|
1012
|
+
#ifdef TRIM_DBF_WHITESPACE
|
1013
|
+
else
|
1014
|
+
{
|
1015
|
+
char *pchSrc, *pchDst;
|
1016
|
+
|
1017
|
+
pchDst = pchSrc = psDBF->pszWorkField;
|
1018
|
+
while( *pchSrc == ' ' )
|
1019
|
+
pchSrc++;
|
1020
|
+
|
1021
|
+
while( *pchSrc != '\0' )
|
1022
|
+
*(pchDst++) = *(pchSrc++);
|
1023
|
+
*pchDst = '\0';
|
1024
|
+
|
1025
|
+
while( pchDst != psDBF->pszWorkField && *(--pchDst) == ' ' )
|
1026
|
+
*pchDst = '\0';
|
1027
|
+
}
|
1028
|
+
#endif
|
1029
|
+
|
1030
|
+
return( pReturnField );
|
1031
|
+
}
|
1032
|
+
|
1033
|
+
/************************************************************************/
|
1034
|
+
/* DBFReadIntAttribute() */
|
1035
|
+
/* */
|
1036
|
+
/* Read an integer attribute. */
|
1037
|
+
/************************************************************************/
|
1038
|
+
|
1039
|
+
int SHPAPI_CALL
|
1040
|
+
DBFReadIntegerAttribute( DBFHandle psDBF, int iRecord, int iField )
|
1041
|
+
|
1042
|
+
{
|
1043
|
+
double *pdValue;
|
1044
|
+
|
1045
|
+
pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' );
|
1046
|
+
|
1047
|
+
if( pdValue == NULL )
|
1048
|
+
return 0;
|
1049
|
+
else
|
1050
|
+
return( (int) *pdValue );
|
1051
|
+
}
|
1052
|
+
|
1053
|
+
/************************************************************************/
|
1054
|
+
/* DBFReadDoubleAttribute() */
|
1055
|
+
/* */
|
1056
|
+
/* Read a double attribute. */
|
1057
|
+
/************************************************************************/
|
1058
|
+
|
1059
|
+
double SHPAPI_CALL
|
1060
|
+
DBFReadDoubleAttribute( DBFHandle psDBF, int iRecord, int iField )
|
1061
|
+
|
1062
|
+
{
|
1063
|
+
double *pdValue;
|
1064
|
+
|
1065
|
+
pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' );
|
1066
|
+
|
1067
|
+
if( pdValue == NULL )
|
1068
|
+
return 0.0;
|
1069
|
+
else
|
1070
|
+
return( *pdValue );
|
1071
|
+
}
|
1072
|
+
|
1073
|
+
/************************************************************************/
|
1074
|
+
/* DBFReadStringAttribute() */
|
1075
|
+
/* */
|
1076
|
+
/* Read a string attribute. */
|
1077
|
+
/************************************************************************/
|
1078
|
+
|
1079
|
+
const char SHPAPI_CALL1(*)
|
1080
|
+
DBFReadStringAttribute( DBFHandle psDBF, int iRecord, int iField )
|
1081
|
+
|
1082
|
+
{
|
1083
|
+
return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'C' ) );
|
1084
|
+
}
|
1085
|
+
|
1086
|
+
/************************************************************************/
|
1087
|
+
/* DBFReadLogicalAttribute() */
|
1088
|
+
/* */
|
1089
|
+
/* Read a logical attribute. */
|
1090
|
+
/************************************************************************/
|
1091
|
+
|
1092
|
+
const char SHPAPI_CALL1(*)
|
1093
|
+
DBFReadLogicalAttribute( DBFHandle psDBF, int iRecord, int iField )
|
1094
|
+
|
1095
|
+
{
|
1096
|
+
return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'L' ) );
|
1097
|
+
}
|
1098
|
+
|
1099
|
+
|
1100
|
+
/************************************************************************/
|
1101
|
+
/* DBFIsValueNULL() */
|
1102
|
+
/* */
|
1103
|
+
/* Return TRUE if the passed string is NULL. */
|
1104
|
+
/************************************************************************/
|
1105
|
+
|
1106
|
+
static int DBFIsValueNULL( char chType, const char* pszValue )
|
1107
|
+
{
|
1108
|
+
int i;
|
1109
|
+
|
1110
|
+
if( pszValue == NULL )
|
1111
|
+
return TRUE;
|
1112
|
+
|
1113
|
+
switch(chType)
|
1114
|
+
{
|
1115
|
+
case 'N':
|
1116
|
+
case 'F':
|
1117
|
+
/*
|
1118
|
+
** We accept all asterisks or all blanks as NULL
|
1119
|
+
** though according to the spec I think it should be all
|
1120
|
+
** asterisks.
|
1121
|
+
*/
|
1122
|
+
if( pszValue[0] == '*' )
|
1123
|
+
return TRUE;
|
1124
|
+
|
1125
|
+
for( i = 0; pszValue[i] != '\0'; i++ )
|
1126
|
+
{
|
1127
|
+
if( pszValue[i] != ' ' )
|
1128
|
+
return FALSE;
|
1129
|
+
}
|
1130
|
+
return TRUE;
|
1131
|
+
|
1132
|
+
case 'D':
|
1133
|
+
/* NULL date fields have value "00000000" */
|
1134
|
+
return strncmp(pszValue,"00000000",8) == 0;
|
1135
|
+
|
1136
|
+
case 'L':
|
1137
|
+
/* NULL boolean fields have value "?" */
|
1138
|
+
return pszValue[0] == '?';
|
1139
|
+
|
1140
|
+
default:
|
1141
|
+
/* empty string fields are considered NULL */
|
1142
|
+
return strlen(pszValue) == 0;
|
1143
|
+
}
|
1144
|
+
}
|
1145
|
+
|
1146
|
+
/************************************************************************/
|
1147
|
+
/* DBFIsAttributeNULL() */
|
1148
|
+
/* */
|
1149
|
+
/* Return TRUE if value for field is NULL. */
|
1150
|
+
/* */
|
1151
|
+
/* Contributed by Jim Matthews. */
|
1152
|
+
/************************************************************************/
|
1153
|
+
|
1154
|
+
int SHPAPI_CALL
|
1155
|
+
DBFIsAttributeNULL( DBFHandle psDBF, int iRecord, int iField )
|
1156
|
+
|
1157
|
+
{
|
1158
|
+
const char *pszValue;
|
1159
|
+
|
1160
|
+
pszValue = DBFReadStringAttribute( psDBF, iRecord, iField );
|
1161
|
+
|
1162
|
+
if( pszValue == NULL )
|
1163
|
+
return TRUE;
|
1164
|
+
|
1165
|
+
return DBFIsValueNULL( psDBF->pachFieldType[iField], pszValue );
|
1166
|
+
}
|
1167
|
+
|
1168
|
+
/************************************************************************/
|
1169
|
+
/* DBFGetFieldCount() */
|
1170
|
+
/* */
|
1171
|
+
/* Return the number of fields in this table. */
|
1172
|
+
/************************************************************************/
|
1173
|
+
|
1174
|
+
int SHPAPI_CALL
|
1175
|
+
DBFGetFieldCount( DBFHandle psDBF )
|
1176
|
+
|
1177
|
+
{
|
1178
|
+
return( psDBF->nFields );
|
1179
|
+
}
|
1180
|
+
|
1181
|
+
/************************************************************************/
|
1182
|
+
/* DBFGetRecordCount() */
|
1183
|
+
/* */
|
1184
|
+
/* Return the number of records in this table. */
|
1185
|
+
/************************************************************************/
|
1186
|
+
|
1187
|
+
int SHPAPI_CALL
|
1188
|
+
DBFGetRecordCount( DBFHandle psDBF )
|
1189
|
+
|
1190
|
+
{
|
1191
|
+
return( psDBF->nRecords );
|
1192
|
+
}
|
1193
|
+
|
1194
|
+
/************************************************************************/
|
1195
|
+
/* DBFGetFieldInfo() */
|
1196
|
+
/* */
|
1197
|
+
/* Return any requested information about the field. */
|
1198
|
+
/************************************************************************/
|
1199
|
+
|
1200
|
+
DBFFieldType SHPAPI_CALL
|
1201
|
+
DBFGetFieldInfo( DBFHandle psDBF, int iField, char * pszFieldName,
|
1202
|
+
int * pnWidth, int * pnDecimals )
|
1203
|
+
|
1204
|
+
{
|
1205
|
+
if( iField < 0 || iField >= psDBF->nFields )
|
1206
|
+
return( FTInvalid );
|
1207
|
+
|
1208
|
+
if( pnWidth != NULL )
|
1209
|
+
*pnWidth = psDBF->panFieldSize[iField];
|
1210
|
+
|
1211
|
+
if( pnDecimals != NULL )
|
1212
|
+
*pnDecimals = psDBF->panFieldDecimals[iField];
|
1213
|
+
|
1214
|
+
if( pszFieldName != NULL )
|
1215
|
+
{
|
1216
|
+
int i;
|
1217
|
+
|
1218
|
+
strncpy( pszFieldName, (char *) psDBF->pszHeader+iField*32, 11 );
|
1219
|
+
pszFieldName[11] = '\0';
|
1220
|
+
for( i = 10; i > 0 && pszFieldName[i] == ' '; i-- )
|
1221
|
+
pszFieldName[i] = '\0';
|
1222
|
+
}
|
1223
|
+
|
1224
|
+
if ( psDBF->pachFieldType[iField] == 'L' )
|
1225
|
+
return( FTLogical);
|
1226
|
+
|
1227
|
+
else if( psDBF->pachFieldType[iField] == 'N'
|
1228
|
+
|| psDBF->pachFieldType[iField] == 'F' )
|
1229
|
+
{
|
1230
|
+
if( psDBF->panFieldDecimals[iField] > 0
|
1231
|
+
|| psDBF->panFieldSize[iField] > 10 )
|
1232
|
+
return( FTDouble );
|
1233
|
+
else
|
1234
|
+
return( FTInteger );
|
1235
|
+
}
|
1236
|
+
else
|
1237
|
+
{
|
1238
|
+
return( FTString );
|
1239
|
+
}
|
1240
|
+
}
|
1241
|
+
|
1242
|
+
/************************************************************************/
|
1243
|
+
/* DBFWriteAttribute() */
|
1244
|
+
/* */
|
1245
|
+
/* Write an attribute record to the file. */
|
1246
|
+
/************************************************************************/
|
1247
|
+
|
1248
|
+
static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField,
|
1249
|
+
void * pValue )
|
1250
|
+
|
1251
|
+
{
|
1252
|
+
int i, j, nRetResult = TRUE;
|
1253
|
+
unsigned char *pabyRec;
|
1254
|
+
char szSField[400], szFormat[20];
|
1255
|
+
|
1256
|
+
/* -------------------------------------------------------------------- */
|
1257
|
+
/* Is this a valid record? */
|
1258
|
+
/* -------------------------------------------------------------------- */
|
1259
|
+
if( hEntity < 0 || hEntity > psDBF->nRecords )
|
1260
|
+
return( FALSE );
|
1261
|
+
|
1262
|
+
if( psDBF->bNoHeader )
|
1263
|
+
DBFWriteHeader(psDBF);
|
1264
|
+
|
1265
|
+
/* -------------------------------------------------------------------- */
|
1266
|
+
/* Is this a brand new record? */
|
1267
|
+
/* -------------------------------------------------------------------- */
|
1268
|
+
if( hEntity == psDBF->nRecords )
|
1269
|
+
{
|
1270
|
+
if( !DBFFlushRecord( psDBF ) )
|
1271
|
+
return FALSE;
|
1272
|
+
|
1273
|
+
psDBF->nRecords++;
|
1274
|
+
for( i = 0; i < psDBF->nRecordLength; i++ )
|
1275
|
+
psDBF->pszCurrentRecord[i] = ' ';
|
1276
|
+
|
1277
|
+
psDBF->nCurrentRecord = hEntity;
|
1278
|
+
}
|
1279
|
+
|
1280
|
+
/* -------------------------------------------------------------------- */
|
1281
|
+
/* Is this an existing record, but different than the last one */
|
1282
|
+
/* we accessed? */
|
1283
|
+
/* -------------------------------------------------------------------- */
|
1284
|
+
if( !DBFLoadRecord( psDBF, hEntity ) )
|
1285
|
+
return FALSE;
|
1286
|
+
|
1287
|
+
pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
|
1288
|
+
|
1289
|
+
psDBF->bCurrentRecordModified = TRUE;
|
1290
|
+
psDBF->bUpdated = TRUE;
|
1291
|
+
|
1292
|
+
/* -------------------------------------------------------------------- */
|
1293
|
+
/* Translate NULL value to valid DBF file representation. */
|
1294
|
+
/* */
|
1295
|
+
/* Contributed by Jim Matthews. */
|
1296
|
+
/* -------------------------------------------------------------------- */
|
1297
|
+
if( pValue == NULL )
|
1298
|
+
{
|
1299
|
+
memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]),
|
1300
|
+
DBFGetNullCharacter(psDBF->pachFieldType[iField]),
|
1301
|
+
psDBF->panFieldSize[iField] );
|
1302
|
+
return TRUE;
|
1303
|
+
}
|
1304
|
+
|
1305
|
+
/* -------------------------------------------------------------------- */
|
1306
|
+
/* Assign all the record fields. */
|
1307
|
+
/* -------------------------------------------------------------------- */
|
1308
|
+
switch( psDBF->pachFieldType[iField] )
|
1309
|
+
{
|
1310
|
+
case 'D':
|
1311
|
+
case 'N':
|
1312
|
+
case 'F':
|
1313
|
+
if( psDBF->panFieldDecimals[iField] == 0 )
|
1314
|
+
{
|
1315
|
+
int nWidth = psDBF->panFieldSize[iField];
|
1316
|
+
|
1317
|
+
if( (int) sizeof(szSField)-2 < nWidth )
|
1318
|
+
nWidth = sizeof(szSField)-2;
|
1319
|
+
|
1320
|
+
sprintf( szFormat, "%%%dd", nWidth );
|
1321
|
+
sprintf(szSField, szFormat, (int) *((double *) pValue) );
|
1322
|
+
if( (int)strlen(szSField) > psDBF->panFieldSize[iField] )
|
1323
|
+
{
|
1324
|
+
szSField[psDBF->panFieldSize[iField]] = '\0';
|
1325
|
+
nRetResult = FALSE;
|
1326
|
+
}
|
1327
|
+
|
1328
|
+
strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
|
1329
|
+
szSField, strlen(szSField) );
|
1330
|
+
}
|
1331
|
+
else
|
1332
|
+
{
|
1333
|
+
int nWidth = psDBF->panFieldSize[iField];
|
1334
|
+
|
1335
|
+
if( (int) sizeof(szSField)-2 < nWidth )
|
1336
|
+
nWidth = sizeof(szSField)-2;
|
1337
|
+
|
1338
|
+
sprintf( szFormat, "%%%d.%df",
|
1339
|
+
nWidth, psDBF->panFieldDecimals[iField] );
|
1340
|
+
sprintf(szSField, szFormat, *((double *) pValue) );
|
1341
|
+
if( (int) strlen(szSField) > psDBF->panFieldSize[iField] )
|
1342
|
+
{
|
1343
|
+
szSField[psDBF->panFieldSize[iField]] = '\0';
|
1344
|
+
nRetResult = FALSE;
|
1345
|
+
}
|
1346
|
+
strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
|
1347
|
+
szSField, strlen(szSField) );
|
1348
|
+
}
|
1349
|
+
break;
|
1350
|
+
|
1351
|
+
case 'L':
|
1352
|
+
if (psDBF->panFieldSize[iField] >= 1 &&
|
1353
|
+
(*(char*)pValue == 'F' || *(char*)pValue == 'T'))
|
1354
|
+
*(pabyRec+psDBF->panFieldOffset[iField]) = *(char*)pValue;
|
1355
|
+
break;
|
1356
|
+
|
1357
|
+
default:
|
1358
|
+
if( (int) strlen((char *) pValue) > psDBF->panFieldSize[iField] )
|
1359
|
+
{
|
1360
|
+
j = psDBF->panFieldSize[iField];
|
1361
|
+
nRetResult = FALSE;
|
1362
|
+
}
|
1363
|
+
else
|
1364
|
+
{
|
1365
|
+
memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
|
1366
|
+
psDBF->panFieldSize[iField] );
|
1367
|
+
j = strlen((char *) pValue);
|
1368
|
+
}
|
1369
|
+
|
1370
|
+
strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
|
1371
|
+
(char *) pValue, j );
|
1372
|
+
break;
|
1373
|
+
}
|
1374
|
+
|
1375
|
+
return( nRetResult );
|
1376
|
+
}
|
1377
|
+
|
1378
|
+
/************************************************************************/
|
1379
|
+
/* DBFWriteAttributeDirectly() */
|
1380
|
+
/* */
|
1381
|
+
/* Write an attribute record to the file, but without any */
|
1382
|
+
/* reformatting based on type. The provided buffer is written */
|
1383
|
+
/* as is to the field position in the record. */
|
1384
|
+
/************************************************************************/
|
1385
|
+
|
1386
|
+
int SHPAPI_CALL
|
1387
|
+
DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField,
|
1388
|
+
void * pValue )
|
1389
|
+
|
1390
|
+
{
|
1391
|
+
int i, j;
|
1392
|
+
unsigned char *pabyRec;
|
1393
|
+
|
1394
|
+
/* -------------------------------------------------------------------- */
|
1395
|
+
/* Is this a valid record? */
|
1396
|
+
/* -------------------------------------------------------------------- */
|
1397
|
+
if( hEntity < 0 || hEntity > psDBF->nRecords )
|
1398
|
+
return( FALSE );
|
1399
|
+
|
1400
|
+
if( psDBF->bNoHeader )
|
1401
|
+
DBFWriteHeader(psDBF);
|
1402
|
+
|
1403
|
+
/* -------------------------------------------------------------------- */
|
1404
|
+
/* Is this a brand new record? */
|
1405
|
+
/* -------------------------------------------------------------------- */
|
1406
|
+
if( hEntity == psDBF->nRecords )
|
1407
|
+
{
|
1408
|
+
if( !DBFFlushRecord( psDBF ) )
|
1409
|
+
return FALSE;
|
1410
|
+
|
1411
|
+
psDBF->nRecords++;
|
1412
|
+
for( i = 0; i < psDBF->nRecordLength; i++ )
|
1413
|
+
psDBF->pszCurrentRecord[i] = ' ';
|
1414
|
+
|
1415
|
+
psDBF->nCurrentRecord = hEntity;
|
1416
|
+
}
|
1417
|
+
|
1418
|
+
/* -------------------------------------------------------------------- */
|
1419
|
+
/* Is this an existing record, but different than the last one */
|
1420
|
+
/* we accessed? */
|
1421
|
+
/* -------------------------------------------------------------------- */
|
1422
|
+
if( !DBFLoadRecord( psDBF, hEntity ) )
|
1423
|
+
return FALSE;
|
1424
|
+
|
1425
|
+
pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
|
1426
|
+
|
1427
|
+
/* -------------------------------------------------------------------- */
|
1428
|
+
/* Assign all the record fields. */
|
1429
|
+
/* -------------------------------------------------------------------- */
|
1430
|
+
if( (int)strlen((char *) pValue) > psDBF->panFieldSize[iField] )
|
1431
|
+
j = psDBF->panFieldSize[iField];
|
1432
|
+
else
|
1433
|
+
{
|
1434
|
+
memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
|
1435
|
+
psDBF->panFieldSize[iField] );
|
1436
|
+
j = strlen((char *) pValue);
|
1437
|
+
}
|
1438
|
+
|
1439
|
+
strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
|
1440
|
+
(char *) pValue, j );
|
1441
|
+
|
1442
|
+
psDBF->bCurrentRecordModified = TRUE;
|
1443
|
+
psDBF->bUpdated = TRUE;
|
1444
|
+
|
1445
|
+
return( TRUE );
|
1446
|
+
}
|
1447
|
+
|
1448
|
+
/************************************************************************/
|
1449
|
+
/* DBFWriteDoubleAttribute() */
|
1450
|
+
/* */
|
1451
|
+
/* Write a double attribute. */
|
1452
|
+
/************************************************************************/
|
1453
|
+
|
1454
|
+
int SHPAPI_CALL
|
1455
|
+
DBFWriteDoubleAttribute( DBFHandle psDBF, int iRecord, int iField,
|
1456
|
+
double dValue )
|
1457
|
+
|
1458
|
+
{
|
1459
|
+
return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) );
|
1460
|
+
}
|
1461
|
+
|
1462
|
+
/************************************************************************/
|
1463
|
+
/* DBFWriteIntegerAttribute() */
|
1464
|
+
/* */
|
1465
|
+
/* Write a integer attribute. */
|
1466
|
+
/************************************************************************/
|
1467
|
+
|
1468
|
+
int SHPAPI_CALL
|
1469
|
+
DBFWriteIntegerAttribute( DBFHandle psDBF, int iRecord, int iField,
|
1470
|
+
int nValue )
|
1471
|
+
|
1472
|
+
{
|
1473
|
+
double dValue = nValue;
|
1474
|
+
|
1475
|
+
return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) );
|
1476
|
+
}
|
1477
|
+
|
1478
|
+
/************************************************************************/
|
1479
|
+
/* DBFWriteStringAttribute() */
|
1480
|
+
/* */
|
1481
|
+
/* Write a string attribute. */
|
1482
|
+
/************************************************************************/
|
1483
|
+
|
1484
|
+
int SHPAPI_CALL
|
1485
|
+
DBFWriteStringAttribute( DBFHandle psDBF, int iRecord, int iField,
|
1486
|
+
const char * pszValue )
|
1487
|
+
|
1488
|
+
{
|
1489
|
+
return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) pszValue ) );
|
1490
|
+
}
|
1491
|
+
|
1492
|
+
/************************************************************************/
|
1493
|
+
/* DBFWriteNULLAttribute() */
|
1494
|
+
/* */
|
1495
|
+
/* Write a string attribute. */
|
1496
|
+
/************************************************************************/
|
1497
|
+
|
1498
|
+
int SHPAPI_CALL
|
1499
|
+
DBFWriteNULLAttribute( DBFHandle psDBF, int iRecord, int iField )
|
1500
|
+
|
1501
|
+
{
|
1502
|
+
return( DBFWriteAttribute( psDBF, iRecord, iField, NULL ) );
|
1503
|
+
}
|
1504
|
+
|
1505
|
+
/************************************************************************/
|
1506
|
+
/* DBFWriteLogicalAttribute() */
|
1507
|
+
/* */
|
1508
|
+
/* Write a logical attribute. */
|
1509
|
+
/************************************************************************/
|
1510
|
+
|
1511
|
+
int SHPAPI_CALL
|
1512
|
+
DBFWriteLogicalAttribute( DBFHandle psDBF, int iRecord, int iField,
|
1513
|
+
const char lValue)
|
1514
|
+
|
1515
|
+
{
|
1516
|
+
return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) (&lValue) ) );
|
1517
|
+
}
|
1518
|
+
|
1519
|
+
/************************************************************************/
|
1520
|
+
/* DBFWriteTuple() */
|
1521
|
+
/* */
|
1522
|
+
/* Write an attribute record to the file. */
|
1523
|
+
/************************************************************************/
|
1524
|
+
|
1525
|
+
int SHPAPI_CALL
|
1526
|
+
DBFWriteTuple(DBFHandle psDBF, int hEntity, void * pRawTuple )
|
1527
|
+
|
1528
|
+
{
|
1529
|
+
int i;
|
1530
|
+
unsigned char *pabyRec;
|
1531
|
+
|
1532
|
+
/* -------------------------------------------------------------------- */
|
1533
|
+
/* Is this a valid record? */
|
1534
|
+
/* -------------------------------------------------------------------- */
|
1535
|
+
if( hEntity < 0 || hEntity > psDBF->nRecords )
|
1536
|
+
return( FALSE );
|
1537
|
+
|
1538
|
+
if( psDBF->bNoHeader )
|
1539
|
+
DBFWriteHeader(psDBF);
|
1540
|
+
|
1541
|
+
/* -------------------------------------------------------------------- */
|
1542
|
+
/* Is this a brand new record? */
|
1543
|
+
/* -------------------------------------------------------------------- */
|
1544
|
+
if( hEntity == psDBF->nRecords )
|
1545
|
+
{
|
1546
|
+
if( !DBFFlushRecord( psDBF ) )
|
1547
|
+
return FALSE;
|
1548
|
+
|
1549
|
+
psDBF->nRecords++;
|
1550
|
+
for( i = 0; i < psDBF->nRecordLength; i++ )
|
1551
|
+
psDBF->pszCurrentRecord[i] = ' ';
|
1552
|
+
|
1553
|
+
psDBF->nCurrentRecord = hEntity;
|
1554
|
+
}
|
1555
|
+
|
1556
|
+
/* -------------------------------------------------------------------- */
|
1557
|
+
/* Is this an existing record, but different than the last one */
|
1558
|
+
/* we accessed? */
|
1559
|
+
/* -------------------------------------------------------------------- */
|
1560
|
+
if( !DBFLoadRecord( psDBF, hEntity ) )
|
1561
|
+
return FALSE;
|
1562
|
+
|
1563
|
+
pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
|
1564
|
+
|
1565
|
+
memcpy ( pabyRec, pRawTuple, psDBF->nRecordLength );
|
1566
|
+
|
1567
|
+
psDBF->bCurrentRecordModified = TRUE;
|
1568
|
+
psDBF->bUpdated = TRUE;
|
1569
|
+
|
1570
|
+
return( TRUE );
|
1571
|
+
}
|
1572
|
+
|
1573
|
+
/************************************************************************/
|
1574
|
+
/* DBFReadTuple() */
|
1575
|
+
/* */
|
1576
|
+
/* Read a complete record. Note that the result is only valid */
|
1577
|
+
/* till the next record read for any reason. */
|
1578
|
+
/************************************************************************/
|
1579
|
+
|
1580
|
+
const char SHPAPI_CALL1(*)
|
1581
|
+
DBFReadTuple(DBFHandle psDBF, int hEntity )
|
1582
|
+
|
1583
|
+
{
|
1584
|
+
if( hEntity < 0 || hEntity >= psDBF->nRecords )
|
1585
|
+
return( NULL );
|
1586
|
+
|
1587
|
+
if( !DBFLoadRecord( psDBF, hEntity ) )
|
1588
|
+
return NULL;
|
1589
|
+
|
1590
|
+
return (const char *) psDBF->pszCurrentRecord;
|
1591
|
+
}
|
1592
|
+
|
1593
|
+
/************************************************************************/
|
1594
|
+
/* DBFCloneEmpty() */
|
1595
|
+
/* */
|
1596
|
+
/* Read one of the attribute fields of a record. */
|
1597
|
+
/************************************************************************/
|
1598
|
+
|
1599
|
+
DBFHandle SHPAPI_CALL
|
1600
|
+
DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename )
|
1601
|
+
{
|
1602
|
+
DBFHandle newDBF;
|
1603
|
+
|
1604
|
+
newDBF = DBFCreateEx ( pszFilename, psDBF->pszCodePage );
|
1605
|
+
if ( newDBF == NULL ) return ( NULL );
|
1606
|
+
|
1607
|
+
newDBF->nFields = psDBF->nFields;
|
1608
|
+
newDBF->nRecordLength = psDBF->nRecordLength;
|
1609
|
+
newDBF->nHeaderLength = psDBF->nHeaderLength;
|
1610
|
+
|
1611
|
+
newDBF->pszHeader = (char *) malloc ( newDBF->nHeaderLength );
|
1612
|
+
memcpy ( newDBF->pszHeader, psDBF->pszHeader, newDBF->nHeaderLength );
|
1613
|
+
|
1614
|
+
newDBF->panFieldOffset = (int *) malloc ( sizeof(int) * psDBF->nFields );
|
1615
|
+
memcpy ( newDBF->panFieldOffset, psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
|
1616
|
+
newDBF->panFieldSize = (int *) malloc ( sizeof(int) * psDBF->nFields );
|
1617
|
+
memcpy ( newDBF->panFieldSize, psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
|
1618
|
+
newDBF->panFieldDecimals = (int *) malloc ( sizeof(int) * psDBF->nFields );
|
1619
|
+
memcpy ( newDBF->panFieldDecimals, psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
|
1620
|
+
newDBF->pachFieldType = (char *) malloc ( sizeof(char) * psDBF->nFields );
|
1621
|
+
memcpy ( newDBF->pachFieldType, psDBF->pachFieldType, sizeof(char)*psDBF->nFields );
|
1622
|
+
|
1623
|
+
newDBF->bNoHeader = TRUE;
|
1624
|
+
newDBF->bUpdated = TRUE;
|
1625
|
+
|
1626
|
+
DBFWriteHeader ( newDBF );
|
1627
|
+
DBFClose ( newDBF );
|
1628
|
+
|
1629
|
+
newDBF = DBFOpen ( pszFilename, "rb+" );
|
1630
|
+
|
1631
|
+
return ( newDBF );
|
1632
|
+
}
|
1633
|
+
|
1634
|
+
/************************************************************************/
|
1635
|
+
/* DBFGetNativeFieldType() */
|
1636
|
+
/* */
|
1637
|
+
/* Return the DBase field type for the specified field. */
|
1638
|
+
/* */
|
1639
|
+
/* Value can be one of: 'C' (String), 'D' (Date), 'F' (Float), */
|
1640
|
+
/* 'N' (Numeric, with or without decimal), */
|
1641
|
+
/* 'L' (Logical), */
|
1642
|
+
/* 'M' (Memo: 10 digits .DBT block ptr) */
|
1643
|
+
/************************************************************************/
|
1644
|
+
|
1645
|
+
char SHPAPI_CALL
|
1646
|
+
DBFGetNativeFieldType( DBFHandle psDBF, int iField )
|
1647
|
+
|
1648
|
+
{
|
1649
|
+
if( iField >=0 && iField < psDBF->nFields )
|
1650
|
+
return psDBF->pachFieldType[iField];
|
1651
|
+
|
1652
|
+
return ' ';
|
1653
|
+
}
|
1654
|
+
|
1655
|
+
/************************************************************************/
|
1656
|
+
/* str_to_upper() */
|
1657
|
+
/************************************************************************/
|
1658
|
+
|
1659
|
+
static void str_to_upper (char *string)
|
1660
|
+
{
|
1661
|
+
int len;
|
1662
|
+
short i = -1;
|
1663
|
+
|
1664
|
+
len = strlen (string);
|
1665
|
+
|
1666
|
+
while (++i < len)
|
1667
|
+
if (isalpha(string[i]) && islower(string[i]))
|
1668
|
+
string[i] = (char) toupper ((int)string[i]);
|
1669
|
+
}
|
1670
|
+
|
1671
|
+
/************************************************************************/
|
1672
|
+
/* DBFGetFieldIndex() */
|
1673
|
+
/* */
|
1674
|
+
/* Get the index number for a field in a .dbf file. */
|
1675
|
+
/* */
|
1676
|
+
/* Contributed by Jim Matthews. */
|
1677
|
+
/************************************************************************/
|
1678
|
+
|
1679
|
+
int SHPAPI_CALL
|
1680
|
+
DBFGetFieldIndex(DBFHandle psDBF, const char *pszFieldName)
|
1681
|
+
|
1682
|
+
{
|
1683
|
+
char name[12], name1[12], name2[12];
|
1684
|
+
int i;
|
1685
|
+
|
1686
|
+
strncpy(name1, pszFieldName,11);
|
1687
|
+
name1[11] = '\0';
|
1688
|
+
str_to_upper(name1);
|
1689
|
+
|
1690
|
+
for( i = 0; i < DBFGetFieldCount(psDBF); i++ )
|
1691
|
+
{
|
1692
|
+
DBFGetFieldInfo( psDBF, i, name, NULL, NULL );
|
1693
|
+
strncpy(name2,name,11);
|
1694
|
+
str_to_upper(name2);
|
1695
|
+
|
1696
|
+
if(!strncmp(name1,name2,10))
|
1697
|
+
return(i);
|
1698
|
+
}
|
1699
|
+
return(-1);
|
1700
|
+
}
|
1701
|
+
|
1702
|
+
/************************************************************************/
|
1703
|
+
/* DBFIsRecordDeleted() */
|
1704
|
+
/* */
|
1705
|
+
/* Returns TRUE if the indicated record is deleted, otherwise */
|
1706
|
+
/* it returns FALSE. */
|
1707
|
+
/************************************************************************/
|
1708
|
+
|
1709
|
+
int SHPAPI_CALL DBFIsRecordDeleted( DBFHandle psDBF, int iShape )
|
1710
|
+
|
1711
|
+
{
|
1712
|
+
/* -------------------------------------------------------------------- */
|
1713
|
+
/* Verify selection. */
|
1714
|
+
/* -------------------------------------------------------------------- */
|
1715
|
+
if( iShape < 0 || iShape >= psDBF->nRecords )
|
1716
|
+
return TRUE;
|
1717
|
+
|
1718
|
+
/* -------------------------------------------------------------------- */
|
1719
|
+
/* Have we read the record? */
|
1720
|
+
/* -------------------------------------------------------------------- */
|
1721
|
+
if( !DBFLoadRecord( psDBF, iShape ) )
|
1722
|
+
return FALSE;
|
1723
|
+
|
1724
|
+
/* -------------------------------------------------------------------- */
|
1725
|
+
/* '*' means deleted. */
|
1726
|
+
/* -------------------------------------------------------------------- */
|
1727
|
+
return psDBF->pszCurrentRecord[0] == '*';
|
1728
|
+
}
|
1729
|
+
|
1730
|
+
/************************************************************************/
|
1731
|
+
/* DBFMarkRecordDeleted() */
|
1732
|
+
/************************************************************************/
|
1733
|
+
|
1734
|
+
int SHPAPI_CALL DBFMarkRecordDeleted( DBFHandle psDBF, int iShape,
|
1735
|
+
int bIsDeleted )
|
1736
|
+
|
1737
|
+
{
|
1738
|
+
char chNewFlag;
|
1739
|
+
|
1740
|
+
/* -------------------------------------------------------------------- */
|
1741
|
+
/* Verify selection. */
|
1742
|
+
/* -------------------------------------------------------------------- */
|
1743
|
+
if( iShape < 0 || iShape >= psDBF->nRecords )
|
1744
|
+
return FALSE;
|
1745
|
+
|
1746
|
+
/* -------------------------------------------------------------------- */
|
1747
|
+
/* Is this an existing record, but different than the last one */
|
1748
|
+
/* we accessed? */
|
1749
|
+
/* -------------------------------------------------------------------- */
|
1750
|
+
if( !DBFLoadRecord( psDBF, iShape ) )
|
1751
|
+
return FALSE;
|
1752
|
+
|
1753
|
+
/* -------------------------------------------------------------------- */
|
1754
|
+
/* Assign value, marking record as dirty if it changes. */
|
1755
|
+
/* -------------------------------------------------------------------- */
|
1756
|
+
if( bIsDeleted )
|
1757
|
+
chNewFlag = '*';
|
1758
|
+
else
|
1759
|
+
chNewFlag = ' ';
|
1760
|
+
|
1761
|
+
if( psDBF->pszCurrentRecord[0] != chNewFlag )
|
1762
|
+
{
|
1763
|
+
psDBF->bCurrentRecordModified = TRUE;
|
1764
|
+
psDBF->bUpdated = TRUE;
|
1765
|
+
psDBF->pszCurrentRecord[0] = chNewFlag;
|
1766
|
+
}
|
1767
|
+
|
1768
|
+
return TRUE;
|
1769
|
+
}
|
1770
|
+
|
1771
|
+
/************************************************************************/
|
1772
|
+
/* DBFGetCodePage */
|
1773
|
+
/************************************************************************/
|
1774
|
+
|
1775
|
+
const char SHPAPI_CALL1(*)
|
1776
|
+
DBFGetCodePage(DBFHandle psDBF )
|
1777
|
+
{
|
1778
|
+
if( psDBF == NULL )
|
1779
|
+
return NULL;
|
1780
|
+
return psDBF->pszCodePage;
|
1781
|
+
}
|
1782
|
+
|
1783
|
+
/************************************************************************/
|
1784
|
+
/* DBFDeleteField() */
|
1785
|
+
/* */
|
1786
|
+
/* Remove a field from a .dbf file */
|
1787
|
+
/************************************************************************/
|
1788
|
+
|
1789
|
+
int SHPAPI_CALL
|
1790
|
+
DBFDeleteField(DBFHandle psDBF, int iField)
|
1791
|
+
{
|
1792
|
+
int nOldRecordLength, nOldHeaderLength;
|
1793
|
+
int nDeletedFieldOffset, nDeletedFieldSize;
|
1794
|
+
SAOffset nRecordOffset;
|
1795
|
+
char* pszRecord;
|
1796
|
+
int i, iRecord;
|
1797
|
+
|
1798
|
+
if (iField < 0 || iField >= psDBF->nFields)
|
1799
|
+
return FALSE;
|
1800
|
+
|
1801
|
+
/* make sure that everything is written in .dbf */
|
1802
|
+
if( !DBFFlushRecord( psDBF ) )
|
1803
|
+
return FALSE;
|
1804
|
+
|
1805
|
+
/* get information about field to be deleted */
|
1806
|
+
nOldRecordLength = psDBF->nRecordLength;
|
1807
|
+
nOldHeaderLength = psDBF->nHeaderLength;
|
1808
|
+
nDeletedFieldOffset = psDBF->panFieldOffset[iField];
|
1809
|
+
nDeletedFieldSize = psDBF->panFieldSize[iField];
|
1810
|
+
|
1811
|
+
/* update fields info */
|
1812
|
+
for (i = iField + 1; i < psDBF->nFields; i++)
|
1813
|
+
{
|
1814
|
+
psDBF->panFieldOffset[i-1] = psDBF->panFieldOffset[i] - nDeletedFieldSize;
|
1815
|
+
psDBF->panFieldSize[i-1] = psDBF->panFieldSize[i];
|
1816
|
+
psDBF->panFieldDecimals[i-1] = psDBF->panFieldDecimals[i];
|
1817
|
+
psDBF->pachFieldType[i-1] = psDBF->pachFieldType[i];
|
1818
|
+
}
|
1819
|
+
|
1820
|
+
/* resize fields arrays */
|
1821
|
+
psDBF->nFields--;
|
1822
|
+
|
1823
|
+
psDBF->panFieldOffset = (int *)
|
1824
|
+
SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
|
1825
|
+
|
1826
|
+
psDBF->panFieldSize = (int *)
|
1827
|
+
SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
|
1828
|
+
|
1829
|
+
psDBF->panFieldDecimals = (int *)
|
1830
|
+
SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
|
1831
|
+
|
1832
|
+
psDBF->pachFieldType = (char *)
|
1833
|
+
SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields );
|
1834
|
+
|
1835
|
+
/* update header information */
|
1836
|
+
psDBF->nHeaderLength -= 32;
|
1837
|
+
psDBF->nRecordLength -= nDeletedFieldSize;
|
1838
|
+
|
1839
|
+
/* overwrite field information in header */
|
1840
|
+
memmove(psDBF->pszHeader + iField*32,
|
1841
|
+
psDBF->pszHeader + (iField+1)*32,
|
1842
|
+
sizeof(char) * (psDBF->nFields - iField)*32);
|
1843
|
+
|
1844
|
+
psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,psDBF->nFields*32);
|
1845
|
+
|
1846
|
+
/* update size of current record appropriately */
|
1847
|
+
psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord,
|
1848
|
+
psDBF->nRecordLength);
|
1849
|
+
|
1850
|
+
/* we're done if we're dealing with not yet created .dbf */
|
1851
|
+
if ( psDBF->bNoHeader && psDBF->nRecords == 0 )
|
1852
|
+
return TRUE;
|
1853
|
+
|
1854
|
+
/* force update of header with new header and record length */
|
1855
|
+
psDBF->bNoHeader = TRUE;
|
1856
|
+
DBFUpdateHeader( psDBF );
|
1857
|
+
|
1858
|
+
/* alloc record */
|
1859
|
+
pszRecord = (char *) malloc(sizeof(char) * nOldRecordLength);
|
1860
|
+
|
1861
|
+
/* shift records to their new positions */
|
1862
|
+
for (iRecord = 0; iRecord < psDBF->nRecords; iRecord++)
|
1863
|
+
{
|
1864
|
+
nRecordOffset =
|
1865
|
+
nOldRecordLength * (SAOffset) iRecord + nOldHeaderLength;
|
1866
|
+
|
1867
|
+
/* load record */
|
1868
|
+
psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
|
1869
|
+
psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp );
|
1870
|
+
|
1871
|
+
nRecordOffset =
|
1872
|
+
psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
|
1873
|
+
|
1874
|
+
/* move record in two steps */
|
1875
|
+
psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
|
1876
|
+
psDBF->sHooks.FWrite( pszRecord, nDeletedFieldOffset, 1, psDBF->fp );
|
1877
|
+
psDBF->sHooks.FWrite( pszRecord + nDeletedFieldOffset + nDeletedFieldSize,
|
1878
|
+
nOldRecordLength - nDeletedFieldOffset - nDeletedFieldSize,
|
1879
|
+
1, psDBF->fp );
|
1880
|
+
|
1881
|
+
}
|
1882
|
+
|
1883
|
+
/* TODO: truncate file */
|
1884
|
+
|
1885
|
+
/* free record */
|
1886
|
+
free(pszRecord);
|
1887
|
+
|
1888
|
+
psDBF->nCurrentRecord = -1;
|
1889
|
+
psDBF->bCurrentRecordModified = FALSE;
|
1890
|
+
|
1891
|
+
return TRUE;
|
1892
|
+
}
|
1893
|
+
|
1894
|
+
/************************************************************************/
|
1895
|
+
/* DBFReorderFields() */
|
1896
|
+
/* */
|
1897
|
+
/* Reorder the fields of a .dbf file */
|
1898
|
+
/* */
|
1899
|
+
/* panMap must be exactly psDBF->nFields long and be a permutation */
|
1900
|
+
/* of [0, psDBF->nFields-1]. This assumption will not be asserted in the*/
|
1901
|
+
/* code of DBFReorderFields. */
|
1902
|
+
/************************************************************************/
|
1903
|
+
|
1904
|
+
int SHPAPI_CALL
|
1905
|
+
DBFReorderFields( DBFHandle psDBF, int* panMap )
|
1906
|
+
{
|
1907
|
+
SAOffset nRecordOffset;
|
1908
|
+
int i, iRecord;
|
1909
|
+
int *panFieldOffsetNew;
|
1910
|
+
int *panFieldSizeNew;
|
1911
|
+
int *panFieldDecimalsNew;
|
1912
|
+
char *pachFieldTypeNew;
|
1913
|
+
char *pszHeaderNew;
|
1914
|
+
char *pszRecord;
|
1915
|
+
char *pszRecordNew;
|
1916
|
+
|
1917
|
+
if ( psDBF->nFields == 0 )
|
1918
|
+
return TRUE;
|
1919
|
+
|
1920
|
+
/* make sure that everything is written in .dbf */
|
1921
|
+
if( !DBFFlushRecord( psDBF ) )
|
1922
|
+
return FALSE;
|
1923
|
+
|
1924
|
+
panFieldOffsetNew = (int *) malloc(sizeof(int) * psDBF->nFields);
|
1925
|
+
panFieldSizeNew = (int *) malloc(sizeof(int) * psDBF->nFields);
|
1926
|
+
panFieldDecimalsNew = (int *) malloc(sizeof(int) * psDBF->nFields);
|
1927
|
+
pachFieldTypeNew = (char *) malloc(sizeof(char) * psDBF->nFields);
|
1928
|
+
pszHeaderNew = (char*) malloc(sizeof(char) * 32 * psDBF->nFields);
|
1929
|
+
|
1930
|
+
/* shuffle fields definitions */
|
1931
|
+
for(i=0; i < psDBF->nFields; i++)
|
1932
|
+
{
|
1933
|
+
panFieldSizeNew[i] = psDBF->panFieldSize[panMap[i]];
|
1934
|
+
panFieldDecimalsNew[i] = psDBF->panFieldDecimals[panMap[i]];
|
1935
|
+
pachFieldTypeNew[i] = psDBF->pachFieldType[panMap[i]];
|
1936
|
+
memcpy(pszHeaderNew + i * 32,
|
1937
|
+
psDBF->pszHeader + panMap[i] * 32, 32);
|
1938
|
+
}
|
1939
|
+
panFieldOffsetNew[0] = 1;
|
1940
|
+
for(i=1; i < psDBF->nFields; i++)
|
1941
|
+
{
|
1942
|
+
panFieldOffsetNew[i] = panFieldOffsetNew[i - 1] + panFieldSizeNew[i - 1];
|
1943
|
+
}
|
1944
|
+
|
1945
|
+
free(psDBF->pszHeader);
|
1946
|
+
psDBF->pszHeader = pszHeaderNew;
|
1947
|
+
|
1948
|
+
/* we're done if we're dealing with not yet created .dbf */
|
1949
|
+
if ( !(psDBF->bNoHeader && psDBF->nRecords == 0) )
|
1950
|
+
{
|
1951
|
+
/* force update of header with new header and record length */
|
1952
|
+
psDBF->bNoHeader = TRUE;
|
1953
|
+
DBFUpdateHeader( psDBF );
|
1954
|
+
|
1955
|
+
/* alloc record */
|
1956
|
+
pszRecord = (char *) malloc(sizeof(char) * psDBF->nRecordLength);
|
1957
|
+
pszRecordNew = (char *) malloc(sizeof(char) * psDBF->nRecordLength);
|
1958
|
+
|
1959
|
+
/* shuffle fields in records */
|
1960
|
+
for (iRecord = 0; iRecord < psDBF->nRecords; iRecord++)
|
1961
|
+
{
|
1962
|
+
nRecordOffset =
|
1963
|
+
psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
|
1964
|
+
|
1965
|
+
/* load record */
|
1966
|
+
psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
|
1967
|
+
psDBF->sHooks.FRead( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
|
1968
|
+
|
1969
|
+
pszRecordNew[0] = pszRecord[0];
|
1970
|
+
|
1971
|
+
for(i=0; i < psDBF->nFields; i++)
|
1972
|
+
{
|
1973
|
+
memcpy(pszRecordNew + panFieldOffsetNew[i],
|
1974
|
+
pszRecord + psDBF->panFieldOffset[panMap[i]],
|
1975
|
+
psDBF->panFieldSize[panMap[i]]);
|
1976
|
+
}
|
1977
|
+
|
1978
|
+
/* write record */
|
1979
|
+
psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
|
1980
|
+
psDBF->sHooks.FWrite( pszRecordNew, psDBF->nRecordLength, 1, psDBF->fp );
|
1981
|
+
}
|
1982
|
+
|
1983
|
+
/* free record */
|
1984
|
+
free(pszRecord);
|
1985
|
+
free(pszRecordNew);
|
1986
|
+
}
|
1987
|
+
|
1988
|
+
free(psDBF->panFieldOffset);
|
1989
|
+
free(psDBF->panFieldSize);
|
1990
|
+
free(psDBF->panFieldDecimals);
|
1991
|
+
free(psDBF->pachFieldType);
|
1992
|
+
|
1993
|
+
psDBF->panFieldOffset = panFieldOffsetNew;
|
1994
|
+
psDBF->panFieldSize = panFieldSizeNew;
|
1995
|
+
psDBF->panFieldDecimals =panFieldDecimalsNew;
|
1996
|
+
psDBF->pachFieldType = pachFieldTypeNew;
|
1997
|
+
|
1998
|
+
psDBF->nCurrentRecord = -1;
|
1999
|
+
psDBF->bCurrentRecordModified = FALSE;
|
2000
|
+
|
2001
|
+
return TRUE;
|
2002
|
+
}
|
2003
|
+
|
2004
|
+
|
2005
|
+
/************************************************************************/
|
2006
|
+
/* DBFAlterFieldDefn() */
|
2007
|
+
/* */
|
2008
|
+
/* Alter a field definition in a .dbf file */
|
2009
|
+
/************************************************************************/
|
2010
|
+
|
2011
|
+
int SHPAPI_CALL
|
2012
|
+
DBFAlterFieldDefn( DBFHandle psDBF, int iField, const char * pszFieldName,
|
2013
|
+
char chType, int nWidth, int nDecimals )
|
2014
|
+
{
|
2015
|
+
int i;
|
2016
|
+
int iRecord;
|
2017
|
+
int nOffset;
|
2018
|
+
int nOldWidth;
|
2019
|
+
int nOldRecordLength;
|
2020
|
+
int nRecordOffset;
|
2021
|
+
char* pszFInfo;
|
2022
|
+
char chOldType;
|
2023
|
+
int bIsNULL;
|
2024
|
+
char chFieldFill;
|
2025
|
+
|
2026
|
+
if (iField < 0 || iField >= psDBF->nFields)
|
2027
|
+
return FALSE;
|
2028
|
+
|
2029
|
+
/* make sure that everything is written in .dbf */
|
2030
|
+
if( !DBFFlushRecord( psDBF ) )
|
2031
|
+
return FALSE;
|
2032
|
+
|
2033
|
+
chFieldFill = DBFGetNullCharacter(chType);
|
2034
|
+
|
2035
|
+
chOldType = psDBF->pachFieldType[iField];
|
2036
|
+
nOffset = psDBF->panFieldOffset[iField];
|
2037
|
+
nOldWidth = psDBF->panFieldSize[iField];
|
2038
|
+
nOldRecordLength = psDBF->nRecordLength;
|
2039
|
+
|
2040
|
+
/* -------------------------------------------------------------------- */
|
2041
|
+
/* Do some checking to ensure we can add records to this file. */
|
2042
|
+
/* -------------------------------------------------------------------- */
|
2043
|
+
if( nWidth < 1 )
|
2044
|
+
return -1;
|
2045
|
+
|
2046
|
+
if( nWidth > 255 )
|
2047
|
+
nWidth = 255;
|
2048
|
+
|
2049
|
+
/* -------------------------------------------------------------------- */
|
2050
|
+
/* Assign the new field information fields. */
|
2051
|
+
/* -------------------------------------------------------------------- */
|
2052
|
+
psDBF->panFieldSize[iField] = nWidth;
|
2053
|
+
psDBF->panFieldDecimals[iField] = nDecimals;
|
2054
|
+
psDBF->pachFieldType[iField] = chType;
|
2055
|
+
|
2056
|
+
/* -------------------------------------------------------------------- */
|
2057
|
+
/* Update the header information. */
|
2058
|
+
/* -------------------------------------------------------------------- */
|
2059
|
+
pszFInfo = psDBF->pszHeader + 32 * iField;
|
2060
|
+
|
2061
|
+
for( i = 0; i < 32; i++ )
|
2062
|
+
pszFInfo[i] = '\0';
|
2063
|
+
|
2064
|
+
if( (int) strlen(pszFieldName) < 10 )
|
2065
|
+
strncpy( pszFInfo, pszFieldName, strlen(pszFieldName));
|
2066
|
+
else
|
2067
|
+
strncpy( pszFInfo, pszFieldName, 10);
|
2068
|
+
|
2069
|
+
pszFInfo[11] = psDBF->pachFieldType[iField];
|
2070
|
+
|
2071
|
+
if( chType == 'C' )
|
2072
|
+
{
|
2073
|
+
pszFInfo[16] = (unsigned char) (nWidth % 256);
|
2074
|
+
pszFInfo[17] = (unsigned char) (nWidth / 256);
|
2075
|
+
}
|
2076
|
+
else
|
2077
|
+
{
|
2078
|
+
pszFInfo[16] = (unsigned char) nWidth;
|
2079
|
+
pszFInfo[17] = (unsigned char) nDecimals;
|
2080
|
+
}
|
2081
|
+
|
2082
|
+
/* -------------------------------------------------------------------- */
|
2083
|
+
/* Update offsets */
|
2084
|
+
/* -------------------------------------------------------------------- */
|
2085
|
+
if (nWidth != nOldWidth)
|
2086
|
+
{
|
2087
|
+
for (i = iField + 1; i < psDBF->nFields; i++)
|
2088
|
+
psDBF->panFieldOffset[i] += nWidth - nOldWidth;
|
2089
|
+
psDBF->nRecordLength += nWidth - nOldWidth;
|
2090
|
+
|
2091
|
+
psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord,
|
2092
|
+
psDBF->nRecordLength);
|
2093
|
+
}
|
2094
|
+
|
2095
|
+
/* we're done if we're dealing with not yet created .dbf */
|
2096
|
+
if ( psDBF->bNoHeader && psDBF->nRecords == 0 )
|
2097
|
+
return TRUE;
|
2098
|
+
|
2099
|
+
/* force update of header with new header and record length */
|
2100
|
+
psDBF->bNoHeader = TRUE;
|
2101
|
+
DBFUpdateHeader( psDBF );
|
2102
|
+
|
2103
|
+
if (nWidth < nOldWidth || (nWidth == nOldWidth && chType != chOldType))
|
2104
|
+
{
|
2105
|
+
char* pszRecord = (char *) malloc(sizeof(char) * nOldRecordLength);
|
2106
|
+
char* pszOldField = (char *) malloc(sizeof(char) * (nOldWidth + 1));
|
2107
|
+
|
2108
|
+
pszOldField[nOldWidth] = 0;
|
2109
|
+
|
2110
|
+
/* move records to their new positions */
|
2111
|
+
for (iRecord = 0; iRecord < psDBF->nRecords; iRecord++)
|
2112
|
+
{
|
2113
|
+
nRecordOffset =
|
2114
|
+
nOldRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
|
2115
|
+
|
2116
|
+
/* load record */
|
2117
|
+
psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
|
2118
|
+
psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp );
|
2119
|
+
|
2120
|
+
memcpy(pszOldField, pszRecord + nOffset, nOldWidth);
|
2121
|
+
bIsNULL = DBFIsValueNULL( chOldType, pszOldField );
|
2122
|
+
|
2123
|
+
if (nWidth != nOldWidth)
|
2124
|
+
{
|
2125
|
+
if ((chOldType == 'N' || chOldType == 'F') && pszOldField[0] == ' ')
|
2126
|
+
{
|
2127
|
+
/* Strip leading spaces when truncating a numeric field */
|
2128
|
+
memmove( pszRecord + nOffset,
|
2129
|
+
pszRecord + nOffset + nOldWidth - nWidth,
|
2130
|
+
nWidth );
|
2131
|
+
}
|
2132
|
+
if (nOffset + nOldWidth < nOldRecordLength)
|
2133
|
+
{
|
2134
|
+
memmove( pszRecord + nOffset + nWidth,
|
2135
|
+
pszRecord + nOffset + nOldWidth,
|
2136
|
+
nOldRecordLength - (nOffset + nOldWidth));
|
2137
|
+
}
|
2138
|
+
}
|
2139
|
+
|
2140
|
+
/* Convert null value to the appropriate value of the new type */
|
2141
|
+
if (bIsNULL)
|
2142
|
+
{
|
2143
|
+
memset( pszRecord + nOffset, chFieldFill, nWidth);
|
2144
|
+
}
|
2145
|
+
|
2146
|
+
nRecordOffset =
|
2147
|
+
psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
|
2148
|
+
|
2149
|
+
/* write record */
|
2150
|
+
psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
|
2151
|
+
psDBF->sHooks.FWrite( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
|
2152
|
+
}
|
2153
|
+
|
2154
|
+
free(pszRecord);
|
2155
|
+
free(pszOldField);
|
2156
|
+
}
|
2157
|
+
else if (nWidth > nOldWidth)
|
2158
|
+
{
|
2159
|
+
char* pszRecord = (char *) malloc(sizeof(char) * psDBF->nRecordLength);
|
2160
|
+
char* pszOldField = (char *) malloc(sizeof(char) * (nOldWidth + 1));
|
2161
|
+
|
2162
|
+
pszOldField[nOldWidth] = 0;
|
2163
|
+
|
2164
|
+
/* move records to their new positions */
|
2165
|
+
for (iRecord = psDBF->nRecords - 1; iRecord >= 0; iRecord--)
|
2166
|
+
{
|
2167
|
+
nRecordOffset =
|
2168
|
+
nOldRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
|
2169
|
+
|
2170
|
+
/* load record */
|
2171
|
+
psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
|
2172
|
+
psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp );
|
2173
|
+
|
2174
|
+
memcpy(pszOldField, pszRecord + nOffset, nOldWidth);
|
2175
|
+
bIsNULL = DBFIsValueNULL( chOldType, pszOldField );
|
2176
|
+
|
2177
|
+
if (nOffset + nOldWidth < nOldRecordLength)
|
2178
|
+
{
|
2179
|
+
memmove( pszRecord + nOffset + nWidth,
|
2180
|
+
pszRecord + nOffset + nOldWidth,
|
2181
|
+
nOldRecordLength - (nOffset + nOldWidth));
|
2182
|
+
}
|
2183
|
+
|
2184
|
+
/* Convert null value to the appropriate value of the new type */
|
2185
|
+
if (bIsNULL)
|
2186
|
+
{
|
2187
|
+
memset( pszRecord + nOffset, chFieldFill, nWidth);
|
2188
|
+
}
|
2189
|
+
else
|
2190
|
+
{
|
2191
|
+
if ((chOldType == 'N' || chOldType == 'F'))
|
2192
|
+
{
|
2193
|
+
/* Add leading spaces when expanding a numeric field */
|
2194
|
+
memmove( pszRecord + nOffset + nWidth - nOldWidth,
|
2195
|
+
pszRecord + nOffset, nOldWidth );
|
2196
|
+
memset( pszRecord + nOffset, ' ', nWidth - nOldWidth );
|
2197
|
+
}
|
2198
|
+
else
|
2199
|
+
{
|
2200
|
+
/* Add trailing spaces */
|
2201
|
+
memset(pszRecord + nOffset + nOldWidth, ' ', nWidth - nOldWidth);
|
2202
|
+
}
|
2203
|
+
}
|
2204
|
+
|
2205
|
+
nRecordOffset =
|
2206
|
+
psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
|
2207
|
+
|
2208
|
+
/* write record */
|
2209
|
+
psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
|
2210
|
+
psDBF->sHooks.FWrite( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
|
2211
|
+
}
|
2212
|
+
|
2213
|
+
free(pszRecord);
|
2214
|
+
free(pszOldField);
|
2215
|
+
}
|
2216
|
+
|
2217
|
+
psDBF->nCurrentRecord = -1;
|
2218
|
+
psDBF->bCurrentRecordModified = FALSE;
|
2219
|
+
|
2220
|
+
return TRUE;
|
2221
|
+
}
|