shp 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +34 -0
  3. data/.travis.yml +4 -0
  4. data/Gemfile +3 -0
  5. data/LICENSE +28 -0
  6. data/README.md +30 -0
  7. data/Rakefile +23 -0
  8. data/ext/shp/base.hpp +113 -0
  9. data/ext/shp/dbf.cpp +381 -0
  10. data/ext/shp/dbf.hpp +44 -0
  11. data/ext/shp/extconf.rb +13 -0
  12. data/ext/shp/shape_object.cpp +58 -0
  13. data/ext/shp/shape_object.hpp +27 -0
  14. data/ext/shp/shapefile.cpp +299 -0
  15. data/ext/shp/shapefile.hpp +35 -0
  16. data/ext/shp/shapelib/.cvsignore +15 -0
  17. data/ext/shp/shapelib/ChangeLog +450 -0
  18. data/ext/shp/shapelib/HOWTO-RELEASE +16 -0
  19. data/ext/shp/shapelib/LICENSE.LGPL +483 -0
  20. data/ext/shp/shapelib/Makefile +113 -0
  21. data/ext/shp/shapelib/README +41 -0
  22. data/ext/shp/shapelib/README.tree +172 -0
  23. data/ext/shp/shapelib/contrib/.cvsignore +12 -0
  24. data/ext/shp/shapelib/contrib/Makefile +66 -0
  25. data/ext/shp/shapelib/contrib/ShapeFileII.pas +234 -0
  26. data/ext/shp/shapelib/contrib/Shape_PointInPoly.cpp +238 -0
  27. data/ext/shp/shapelib/contrib/Shape_PointInPoly_README.txt +59 -0
  28. data/ext/shp/shapelib/contrib/csv2shp.c +558 -0
  29. data/ext/shp/shapelib/contrib/dbfcat.c +166 -0
  30. data/ext/shp/shapelib/contrib/dbfinfo.c +106 -0
  31. data/ext/shp/shapelib/contrib/makefile.vc +34 -0
  32. data/ext/shp/shapelib/contrib/my_nan.h +46 -0
  33. data/ext/shp/shapelib/contrib/shpcat.c +100 -0
  34. data/ext/shp/shapelib/contrib/shpcentrd.c +159 -0
  35. data/ext/shp/shapelib/contrib/shpdata.c +129 -0
  36. data/ext/shp/shapelib/contrib/shpdxf.c +340 -0
  37. data/ext/shp/shapelib/contrib/shpfix.c +110 -0
  38. data/ext/shp/shapelib/contrib/shpgeo.c +1595 -0
  39. data/ext/shp/shapelib/contrib/shpgeo.h +154 -0
  40. data/ext/shp/shapelib/contrib/shpinfo.c +113 -0
  41. data/ext/shp/shapelib/contrib/shpproj.c +260 -0
  42. data/ext/shp/shapelib/contrib/shpsort.c +605 -0
  43. data/ext/shp/shapelib/contrib/shpsort.txt +44 -0
  44. data/ext/shp/shapelib/contrib/shpwkb.c +123 -0
  45. data/ext/shp/shapelib/contrib/tests/shpproj.sh +38 -0
  46. data/ext/shp/shapelib/dbfopen.c +2221 -0
  47. data/ext/shp/shapelib/makefile.vc +86 -0
  48. data/ext/shp/shapelib/makeshape.sh +21 -0
  49. data/ext/shp/shapelib/mkdist.sh +37 -0
  50. data/ext/shp/shapelib/mkinstalldirs +38 -0
  51. data/ext/shp/shapelib/mkrelease.sh +55 -0
  52. data/ext/shp/shapelib/safileio.c +286 -0
  53. data/ext/shp/shapelib/shapefil.h +647 -0
  54. data/ext/shp/shapelib/shapelib.def +46 -0
  55. data/ext/shp/shapelib/shpopen.c +2388 -0
  56. data/ext/shp/shapelib/shptree.c +1187 -0
  57. data/ext/shp/shapelib/shputils.c +1072 -0
  58. data/ext/shp/shapelib/stream1.out +1465 -0
  59. data/ext/shp/shapelib/stream1.sh +28 -0
  60. data/ext/shp/shapelib/stream2.out +530 -0
  61. data/ext/shp/shapelib/stream2.sh +11 -0
  62. data/ext/shp/shapelib/stream3.out +37 -0
  63. data/ext/shp/shapelib/web/.cvsignore +2 -0
  64. data/ext/shp/shapelib/web/codepage.html +403 -0
  65. data/ext/shp/shapelib/web/dbf_api.html +436 -0
  66. data/ext/shp/shapelib/web/index.html +235 -0
  67. data/ext/shp/shapelib/web/license.html +78 -0
  68. data/ext/shp/shapelib/web/manifest.html +87 -0
  69. data/ext/shp/shapelib/web/release.html +80 -0
  70. data/ext/shp/shapelib/web/shapelib-tools.html +352 -0
  71. data/ext/shp/shapelib/web/shp_api.html +376 -0
  72. data/ext/shp/shp.cpp +19 -0
  73. data/ext/shp/shp.hpp +47 -0
  74. data/lib/shp.rb +35 -0
  75. data/lib/shp/version.rb +3 -0
  76. data/shp.gemspec +23 -0
  77. data/spec/shp_spec.rb +127 -0
  78. 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
+ }