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.
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
+ }