geo_coder 0.1.0
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.
- data/Gemfile +12 -0
- data/Gemfile.lock +32 -0
- data/History.txt +6 -0
- data/Makefile +13 -0
- data/Manifest.txt +18 -0
- data/README.rdoc +197 -0
- data/Rakefile +53 -0
- data/TODO.txt +8 -0
- data/VERSION +1 -0
- data/bin/build_indexes +8 -0
- data/bin/rebuild_cluster +22 -0
- data/bin/rebuild_metaphones +23 -0
- data/bin/tiger_import +59 -0
- data/demos/demo/app/ext/geocodewrap.rb +84 -0
- data/demos/demo/app/views/index.builder +13 -0
- data/demos/demo/app/views/index.erb +71 -0
- data/demos/demo/config.ru +12 -0
- data/demos/demo/config/bootstraps.rb +130 -0
- data/demos/demo/config/geoenvironment.rb +25 -0
- data/demos/demo/geocoder_helper.rb +12 -0
- data/demos/demo/geocom_geocode.rb +10 -0
- data/demos/demo/main.rb +3 -0
- data/demos/demo/rakefile.rb +17 -0
- data/demos/demo/tmp/restart.txt +0 -0
- data/demos/simpledemo/views/index.builder +13 -0
- data/demos/simpledemo/views/index.erb +69 -0
- data/demos/simpledemo/ws.rb +83 -0
- data/doc/Makefile +7 -0
- data/doc/html4css1.css +279 -0
- data/doc/lookup.rst +193 -0
- data/doc/parsing.rst +125 -0
- data/doc/voidspace.css +147 -0
- data/geo_coder.gemspec +172 -0
- data/lib/geocoder/us.rb +21 -0
- data/lib/geocoder/us/address.rb +290 -0
- data/lib/geocoder/us/constants.rb +670 -0
- data/lib/geocoder/us/database.rb +745 -0
- data/lib/geocoder/us/import.rb +181 -0
- data/lib/geocoder/us/import/tiger.rb +13 -0
- data/lib/geocoder/us/numbers.rb +58 -0
- data/navteq/README +4 -0
- data/navteq/convert.sql +37 -0
- data/navteq/navteq_import +39 -0
- data/navteq/prepare.sql +92 -0
- data/sql/cluster.sql +16 -0
- data/sql/convert.sql +80 -0
- data/sql/create.sql +37 -0
- data/sql/index.sql +12 -0
- data/sql/place.csv +104944 -0
- data/sql/place.sql +104948 -0
- data/sql/setup.sql +78 -0
- data/src/Makefile +13 -0
- data/src/README +14 -0
- data/src/liblwgeom/Makefile +75 -0
- data/src/liblwgeom/box2d.c +54 -0
- data/src/liblwgeom/lex.yy.c +4799 -0
- data/src/liblwgeom/liblwgeom.h +1405 -0
- data/src/liblwgeom/lwalgorithm.c +946 -0
- data/src/liblwgeom/lwalgorithm.h +52 -0
- data/src/liblwgeom/lwcircstring.c +759 -0
- data/src/liblwgeom/lwcollection.c +541 -0
- data/src/liblwgeom/lwcompound.c +118 -0
- data/src/liblwgeom/lwcurvepoly.c +86 -0
- data/src/liblwgeom/lwgeom.c +886 -0
- data/src/liblwgeom/lwgeom_api.c +2201 -0
- data/src/liblwgeom/lwgparse.c +1219 -0
- data/src/liblwgeom/lwgunparse.c +1054 -0
- data/src/liblwgeom/lwline.c +525 -0
- data/src/liblwgeom/lwmcurve.c +125 -0
- data/src/liblwgeom/lwmline.c +137 -0
- data/src/liblwgeom/lwmpoint.c +138 -0
- data/src/liblwgeom/lwmpoly.c +141 -0
- data/src/liblwgeom/lwmsurface.c +129 -0
- data/src/liblwgeom/lwpoint.c +439 -0
- data/src/liblwgeom/lwpoly.c +579 -0
- data/src/liblwgeom/lwsegmentize.c +1047 -0
- data/src/liblwgeom/lwutil.c +369 -0
- data/src/liblwgeom/measures.c +861 -0
- data/src/liblwgeom/postgis_config.h +93 -0
- data/src/liblwgeom/ptarray.c +847 -0
- data/src/liblwgeom/vsprintf.c +179 -0
- data/src/liblwgeom/wktparse.h +126 -0
- data/src/liblwgeom/wktparse.lex +74 -0
- data/src/liblwgeom/wktparse.tab.c +2353 -0
- data/src/liblwgeom/wktparse.tab.h +145 -0
- data/src/liblwgeom/wktparse.y +385 -0
- data/src/libsqlite3_geocoder/Makefile +22 -0
- data/src/libsqlite3_geocoder/Makefile.nix +15 -0
- data/src/libsqlite3_geocoder/Makefile.redhat +15 -0
- data/src/libsqlite3_geocoder/extension.c +121 -0
- data/src/libsqlite3_geocoder/extension.h +13 -0
- data/src/libsqlite3_geocoder/levenshtein.c +42 -0
- data/src/libsqlite3_geocoder/metaphon.c +278 -0
- data/src/libsqlite3_geocoder/util.c +37 -0
- data/src/libsqlite3_geocoder/wkb_compress.c +54 -0
- data/src/metaphone/Makefile +7 -0
- data/src/metaphone/README +49 -0
- data/src/metaphone/extension.c +37 -0
- data/src/metaphone/metaphon.c +251 -0
- data/src/shp2sqlite/Makefile +37 -0
- data/src/shp2sqlite/Makefile.nix +36 -0
- data/src/shp2sqlite/Makefile.redhat +35 -0
- data/src/shp2sqlite/dbfopen.c +1595 -0
- data/src/shp2sqlite/getopt.c +695 -0
- data/src/shp2sqlite/getopt.h +127 -0
- data/src/shp2sqlite/shapefil.h +500 -0
- data/src/shp2sqlite/shp2sqlite.c +1974 -0
- data/src/shp2sqlite/shpopen.c +1894 -0
- data/tests/address.rb +236 -0
- data/tests/benchmark.rb +20 -0
- data/tests/constants.rb +57 -0
- data/tests/data/address-sample.csv +52 -0
- data/tests/data/db-test.csv +57 -0
- data/tests/data/locations.csv +4 -0
- data/tests/database.rb +137 -0
- data/tests/generate.rb +34 -0
- data/tests/numbers.rb +46 -0
- data/tests/run.rb +11 -0
- metadata +237 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# **********************************************************************
|
|
2
|
+
# * $Id: Makefile.in
|
|
3
|
+
# *
|
|
4
|
+
# * PostGIS - Spatial Types for PostgreSQL
|
|
5
|
+
# * http://postgis.refractions.net
|
|
6
|
+
# * Copyright 2008 Mark Cave-Ayland
|
|
7
|
+
# *
|
|
8
|
+
# * This is free software; you can redistribute and/or modify it under
|
|
9
|
+
# * the terms of the GNU General Public Licence. See the COPYING file.
|
|
10
|
+
# *
|
|
11
|
+
# **********************************************************************
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
CFLAGS=-g -O2 -fPIC -DPIC -Wall -Wmissing-prototypes
|
|
15
|
+
|
|
16
|
+
# Filenames with extension as determined by the OS
|
|
17
|
+
SHP2SQLITE=shp2sqlite
|
|
18
|
+
LIBLWGEOM=../liblwgeom/liblwgeom.a
|
|
19
|
+
|
|
20
|
+
# iconv flags
|
|
21
|
+
ICONV_LDFLAGS=-lc
|
|
22
|
+
|
|
23
|
+
all: $(SHP2SQLITE)
|
|
24
|
+
|
|
25
|
+
$(LIBLWGEOM):
|
|
26
|
+
make -C ../liblwgeom
|
|
27
|
+
|
|
28
|
+
$(SHP2SQLITE): shpopen.o dbfopen.o getopt.o shp2sqlite.o $(LIBLWGEOM)
|
|
29
|
+
$(CC) $(CFLAGS) $^ $(ICONV_LDFLAGS) -lm -o $@
|
|
30
|
+
|
|
31
|
+
install: all
|
|
32
|
+
@cp $(SHP2SQLITE) ../../bin
|
|
33
|
+
|
|
34
|
+
clean:
|
|
35
|
+
@rm -f *.o $(SHP2SQLITE)
|
|
36
|
+
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# **********************************************************************
|
|
2
|
+
# * $Id: Makefile.in
|
|
3
|
+
# *
|
|
4
|
+
# * PostGIS - Spatial Types for PostgreSQL
|
|
5
|
+
# * http://postgis.refractions.net
|
|
6
|
+
# * Copyright 2008 Mark Cave-Ayland
|
|
7
|
+
# *
|
|
8
|
+
# * This is free software; you can redistribute and/or modify it under
|
|
9
|
+
# * the terms of the GNU General Public Licence. See the COPYING file.
|
|
10
|
+
# *
|
|
11
|
+
# **********************************************************************
|
|
12
|
+
CC=gcc
|
|
13
|
+
CFLAGS=-g -O2 -fPIC -DPIC -Wall -Wmissing-prototypes
|
|
14
|
+
|
|
15
|
+
# Filenames with extension as determined by the OS
|
|
16
|
+
SHP2SQLITE=shp2sqlite
|
|
17
|
+
LIBLWGEOM=../liblwgeom/liblwgeom.a
|
|
18
|
+
|
|
19
|
+
# iconv flags
|
|
20
|
+
ICONV_LDFLAGS=-lc
|
|
21
|
+
|
|
22
|
+
all: $(SHP2SQLITE)
|
|
23
|
+
|
|
24
|
+
$(LIBLWGEOM):
|
|
25
|
+
make -C ../liblwgeom
|
|
26
|
+
|
|
27
|
+
$(SHP2SQLITE): shpopen.o dbfopen.o getopt.o shp2sqlite.o $(LIBLWGEOM)
|
|
28
|
+
$(CC) $(CFLAGS) $^ $(ICONV_LDFLAGS) -lm -o $@
|
|
29
|
+
|
|
30
|
+
install: all
|
|
31
|
+
@cp $(SHP2SQLITE) ../../bin
|
|
32
|
+
|
|
33
|
+
clean:
|
|
34
|
+
@rm -f *.o $(SHP2SQLITE)
|
|
35
|
+
|
|
@@ -0,0 +1,1595 @@
|
|
|
1
|
+
/******************************************************************************
|
|
2
|
+
* $Id: dbfopen.c 3750 2009-02-19 21:12:22Z pramsey $
|
|
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$
|
|
37
|
+
* Revision 1.8 2006/01/16 10:42:57 strk
|
|
38
|
+
* Added support for Bool and Date DBF<=>PGIS mapping
|
|
39
|
+
*
|
|
40
|
+
* Revision 1.7 2006/01/09 16:40:16 strk
|
|
41
|
+
* ISO C90 comments, signedness mismatch fixes
|
|
42
|
+
*
|
|
43
|
+
* Revision 1.6 2003/12/01 20:52:00 strk
|
|
44
|
+
* shapelib put in sync with gdal cvs
|
|
45
|
+
*
|
|
46
|
+
* Revision 1.52 2003/07/08 15:20:03 warmerda
|
|
47
|
+
* avoid warnings about downcasting to unsigned char
|
|
48
|
+
*
|
|
49
|
+
* Revision 1.51 2003/07/08 13:50:15 warmerda
|
|
50
|
+
* DBFIsAttributeNULL check for pszValue==NULL - bug 360
|
|
51
|
+
*
|
|
52
|
+
* Revision 1.50 2003/04/21 18:58:25 warmerda
|
|
53
|
+
* ensure current record is flushed at same time as header is updated
|
|
54
|
+
*
|
|
55
|
+
* Revision 1.49 2003/04/21 18:30:37 warmerda
|
|
56
|
+
* added header write/update public methods
|
|
57
|
+
*
|
|
58
|
+
* Revision 1.48 2003/03/10 14:51:27 warmerda
|
|
59
|
+
* DBFWrite* calls now return FALSE if they have to truncate
|
|
60
|
+
*
|
|
61
|
+
* Revision 1.47 2002/11/20 03:32:22 warmerda
|
|
62
|
+
* Ensure field name in DBFGetFieldIndex() is properly terminated.
|
|
63
|
+
*
|
|
64
|
+
* Revision 1.46 2002/10/09 13:10:21 warmerda
|
|
65
|
+
* Added check that width is positive.
|
|
66
|
+
*
|
|
67
|
+
* Revision 1.45 2002/09/29 00:00:08 warmerda
|
|
68
|
+
* added FTLogical and logical attribute read/write calls
|
|
69
|
+
*
|
|
70
|
+
* Revision 1.44 2002/05/07 13:46:11 warmerda
|
|
71
|
+
* Added DBFWriteAttributeDirectly().
|
|
72
|
+
*
|
|
73
|
+
* Revision 1.43 2002/02/13 19:39:21 warmerda
|
|
74
|
+
* Fix casting issues in DBFCloneEmpty().
|
|
75
|
+
*
|
|
76
|
+
* Revision 1.42 2002/01/15 14:36:07 warmerda
|
|
77
|
+
* updated email address
|
|
78
|
+
*
|
|
79
|
+
* Revision 1.41 2002/01/15 14:31:49 warmerda
|
|
80
|
+
* compute rather than copying nHeaderLength in DBFCloneEmpty()
|
|
81
|
+
*
|
|
82
|
+
* Revision 1.40 2002/01/09 04:32:35 warmerda
|
|
83
|
+
* fixed to read correct amount of header
|
|
84
|
+
*
|
|
85
|
+
* Revision 1.39 2001/12/11 22:41:03 warmerda
|
|
86
|
+
* improve io related error checking when reading header
|
|
87
|
+
*
|
|
88
|
+
* Revision 1.38 2001/11/28 16:07:31 warmerda
|
|
89
|
+
* Cleanup to avoid compiler warnings as suggested by Richard Hash.
|
|
90
|
+
*
|
|
91
|
+
* Revision 1.37 2001/07/04 05:18:09 warmerda
|
|
92
|
+
* do last fix properly
|
|
93
|
+
*
|
|
94
|
+
* Revision 1.36 2001/07/04 05:16:09 warmerda
|
|
95
|
+
* fixed fieldname comparison in DBFGetFieldIndex
|
|
96
|
+
*
|
|
97
|
+
* Revision 1.35 2001/06/22 02:10:06 warmerda
|
|
98
|
+
* fixed NULL shape support with help from Jim Matthews
|
|
99
|
+
*
|
|
100
|
+
* Revision 1.33 2001/05/31 19:20:13 warmerda
|
|
101
|
+
* added DBFGetFieldIndex()
|
|
102
|
+
*
|
|
103
|
+
* Revision 1.32 2001/05/31 18:15:40 warmerda
|
|
104
|
+
* Added support for NULL fields in DBF files
|
|
105
|
+
*
|
|
106
|
+
* Revision 1.31 2001/05/23 13:36:52 warmerda
|
|
107
|
+
* added use of SHPAPI_CALL
|
|
108
|
+
*
|
|
109
|
+
* Revision 1.30 2000/12/05 14:43:38 warmerda
|
|
110
|
+
* DBReadAttribute() white space trimming bug fix
|
|
111
|
+
*
|
|
112
|
+
* Revision 1.29 2000/10/05 14:36:44 warmerda
|
|
113
|
+
* fix bug with writing very wide numeric fields
|
|
114
|
+
*
|
|
115
|
+
* Revision 1.28 2000/09/25 14:18:07 warmerda
|
|
116
|
+
* Added some casts of strlen() return result to fix warnings on some
|
|
117
|
+
* systems, as submitted by Daniel.
|
|
118
|
+
*
|
|
119
|
+
* Revision 1.27 2000/09/25 14:15:51 warmerda
|
|
120
|
+
* added DBFGetNativeFieldType()
|
|
121
|
+
*
|
|
122
|
+
* Revision 1.26 2000/07/07 13:39:45 warmerda
|
|
123
|
+
* removed unused variables, and added system include files
|
|
124
|
+
*
|
|
125
|
+
* Revision 1.25 2000/05/29 18:19:13 warmerda
|
|
126
|
+
* avoid use of uchar, and adding casting fix
|
|
127
|
+
*
|
|
128
|
+
* Revision 1.24 2000/05/23 13:38:27 warmerda
|
|
129
|
+
* Added error checks on return results of fread() and fseek().
|
|
130
|
+
*
|
|
131
|
+
* Revision 1.23 2000/05/23 13:25:49 warmerda
|
|
132
|
+
* Avoid crashing if field or record are out of range in dbfread*attribute().
|
|
133
|
+
*
|
|
134
|
+
* Revision 1.22 1999/12/15 13:47:24 warmerda
|
|
135
|
+
* Added stdlib.h to ensure that atof() is prototyped.
|
|
136
|
+
*
|
|
137
|
+
* Revision 1.21 1999/12/13 17:25:46 warmerda
|
|
138
|
+
* Added support for upper case .DBF extention.
|
|
139
|
+
*
|
|
140
|
+
* Revision 1.20 1999/11/30 16:32:11 warmerda
|
|
141
|
+
* Use atof() instead of sscanf().
|
|
142
|
+
*
|
|
143
|
+
* Revision 1.19 1999/11/05 14:12:04 warmerda
|
|
144
|
+
* updated license terms
|
|
145
|
+
*
|
|
146
|
+
* Revision 1.18 1999/07/27 00:53:28 warmerda
|
|
147
|
+
* ensure that whole old field value clear on write of string
|
|
148
|
+
*
|
|
149
|
+
* Revision 1.1 1999/07/05 18:58:07 warmerda
|
|
150
|
+
* New
|
|
151
|
+
*
|
|
152
|
+
* Revision 1.17 1999/06/11 19:14:12 warmerda
|
|
153
|
+
* Fixed some memory leaks.
|
|
154
|
+
*
|
|
155
|
+
* Revision 1.16 1999/06/11 19:04:11 warmerda
|
|
156
|
+
* Remoted some unused variables.
|
|
157
|
+
*
|
|
158
|
+
* Revision 1.15 1999/05/11 03:19:28 warmerda
|
|
159
|
+
* added new Tuple api, and improved extension handling - add from candrsn
|
|
160
|
+
*
|
|
161
|
+
* Revision 1.14 1999/05/04 15:01:48 warmerda
|
|
162
|
+
* Added 'F' support.
|
|
163
|
+
*
|
|
164
|
+
* Revision 1.13 1999/03/23 17:38:59 warmerda
|
|
165
|
+
* DBFAddField() now actually does return the new field number, or -1 if
|
|
166
|
+
* it fails.
|
|
167
|
+
*
|
|
168
|
+
* Revision 1.12 1999/03/06 02:54:46 warmerda
|
|
169
|
+
* Added logic to convert shapefile name to dbf filename in DBFOpen()
|
|
170
|
+
* for convenience.
|
|
171
|
+
*
|
|
172
|
+
* Revision 1.11 1998/12/31 15:30:34 warmerda
|
|
173
|
+
* Improved the interchangability of numeric and string attributes. Add
|
|
174
|
+
* white space trimming option for attributes.
|
|
175
|
+
*
|
|
176
|
+
* Revision 1.10 1998/12/03 16:36:44 warmerda
|
|
177
|
+
* Use r+b instead of rb+ for binary access.
|
|
178
|
+
*
|
|
179
|
+
* Revision 1.9 1998/12/03 15:34:23 warmerda
|
|
180
|
+
* Updated copyright message.
|
|
181
|
+
*
|
|
182
|
+
* Revision 1.8 1997/12/04 15:40:15 warmerda
|
|
183
|
+
* Added newline character after field definitions.
|
|
184
|
+
*
|
|
185
|
+
* Revision 1.7 1997/03/06 14:02:10 warmerda
|
|
186
|
+
* Ensure bUpdated is initialized.
|
|
187
|
+
*
|
|
188
|
+
* Revision 1.6 1996/02/12 04:54:41 warmerda
|
|
189
|
+
* Ensure that DBFWriteAttribute() returns TRUE if it succeeds.
|
|
190
|
+
*
|
|
191
|
+
* Revision 1.5 1995/10/21 03:15:12 warmerda
|
|
192
|
+
* Changed to use binary file access, and ensure that the
|
|
193
|
+
* field name field is zero filled, and limited to 10 chars.
|
|
194
|
+
*
|
|
195
|
+
* Revision 1.4 1995/08/24 18:10:42 warmerda
|
|
196
|
+
* Added use of SfRealloc() to avoid pre-ANSI realloc() functions such
|
|
197
|
+
* as on the Sun.
|
|
198
|
+
*
|
|
199
|
+
* Revision 1.3 1995/08/04 03:15:16 warmerda
|
|
200
|
+
* Fixed up header.
|
|
201
|
+
*
|
|
202
|
+
* Revision 1.2 1995/08/04 03:14:43 warmerda
|
|
203
|
+
* Added header.
|
|
204
|
+
*/
|
|
205
|
+
|
|
206
|
+
#include "shapefil.h"
|
|
207
|
+
|
|
208
|
+
#include <math.h>
|
|
209
|
+
#include <stdlib.h>
|
|
210
|
+
#include <ctype.h>
|
|
211
|
+
#include <string.h>
|
|
212
|
+
|
|
213
|
+
#ifndef FALSE
|
|
214
|
+
# define FALSE 0
|
|
215
|
+
# define TRUE 1
|
|
216
|
+
#endif
|
|
217
|
+
|
|
218
|
+
static int nStringFieldLen = 0;
|
|
219
|
+
static char * pszStringField = NULL;
|
|
220
|
+
|
|
221
|
+
/************************************************************************/
|
|
222
|
+
/* SfRealloc() */
|
|
223
|
+
/* */
|
|
224
|
+
/* A realloc cover function that will access a NULL pointer as */
|
|
225
|
+
/* a valid input. */
|
|
226
|
+
/************************************************************************/
|
|
227
|
+
|
|
228
|
+
static void * SfRealloc( void * pMem, int nNewSize )
|
|
229
|
+
|
|
230
|
+
{
|
|
231
|
+
if( pMem == NULL )
|
|
232
|
+
return( (void *) malloc(nNewSize) );
|
|
233
|
+
else
|
|
234
|
+
return( (void *) realloc(pMem,nNewSize) );
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/************************************************************************/
|
|
238
|
+
/* DBFWriteHeader() */
|
|
239
|
+
/* */
|
|
240
|
+
/* This is called to write out the file header, and field */
|
|
241
|
+
/* descriptions before writing any actual data records. This */
|
|
242
|
+
/* also computes all the DBFDataSet field offset/size/decimals */
|
|
243
|
+
/* and so forth values. */
|
|
244
|
+
/************************************************************************/
|
|
245
|
+
|
|
246
|
+
static void DBFWriteHeader(DBFHandle psDBF)
|
|
247
|
+
|
|
248
|
+
{
|
|
249
|
+
unsigned char abyHeader[XBASE_FLDHDR_SZ];
|
|
250
|
+
int i;
|
|
251
|
+
|
|
252
|
+
if( !psDBF->bNoHeader )
|
|
253
|
+
return;
|
|
254
|
+
|
|
255
|
+
psDBF->bNoHeader = FALSE;
|
|
256
|
+
|
|
257
|
+
/* -------------------------------------------------------------------- */
|
|
258
|
+
/* Initialize the file header information. */
|
|
259
|
+
/* -------------------------------------------------------------------- */
|
|
260
|
+
for( i = 0; i < XBASE_FLDHDR_SZ; i++ )
|
|
261
|
+
abyHeader[i] = 0;
|
|
262
|
+
|
|
263
|
+
abyHeader[0] = 0x03; /* memo field? - just copying */
|
|
264
|
+
|
|
265
|
+
/* write out a dummy date */
|
|
266
|
+
abyHeader[1] = 95; /* YY */
|
|
267
|
+
abyHeader[2] = 7; /* MM */
|
|
268
|
+
abyHeader[3] = 26; /* DD */
|
|
269
|
+
|
|
270
|
+
/* record count preset at zero */
|
|
271
|
+
|
|
272
|
+
abyHeader[8] = (unsigned char) (psDBF->nHeaderLength % 256);
|
|
273
|
+
abyHeader[9] = (unsigned char) (psDBF->nHeaderLength / 256);
|
|
274
|
+
|
|
275
|
+
abyHeader[10] = (unsigned char) (psDBF->nRecordLength % 256);
|
|
276
|
+
abyHeader[11] = (unsigned char) (psDBF->nRecordLength / 256);
|
|
277
|
+
|
|
278
|
+
/* -------------------------------------------------------------------- */
|
|
279
|
+
/* Write the initial 32 byte file header, and all the field */
|
|
280
|
+
/* descriptions. */
|
|
281
|
+
/* -------------------------------------------------------------------- */
|
|
282
|
+
fseek( psDBF->fp, 0, 0 );
|
|
283
|
+
fwrite( abyHeader, XBASE_FLDHDR_SZ, 1, psDBF->fp );
|
|
284
|
+
fwrite( psDBF->pszHeader, XBASE_FLDHDR_SZ, psDBF->nFields, psDBF->fp );
|
|
285
|
+
|
|
286
|
+
/* -------------------------------------------------------------------- */
|
|
287
|
+
/* Write out the newline character if there is room for it. */
|
|
288
|
+
/* -------------------------------------------------------------------- */
|
|
289
|
+
if( psDBF->nHeaderLength > 32*psDBF->nFields + 32 )
|
|
290
|
+
{
|
|
291
|
+
char cNewline;
|
|
292
|
+
|
|
293
|
+
cNewline = 0x0d;
|
|
294
|
+
fwrite( &cNewline, 1, 1, psDBF->fp );
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/************************************************************************/
|
|
299
|
+
/* DBFFlushRecord() */
|
|
300
|
+
/* */
|
|
301
|
+
/* Write out the current record if there is one. */
|
|
302
|
+
/************************************************************************/
|
|
303
|
+
|
|
304
|
+
static void DBFFlushRecord( DBFHandle psDBF )
|
|
305
|
+
|
|
306
|
+
{
|
|
307
|
+
int nRecordOffset;
|
|
308
|
+
|
|
309
|
+
if( psDBF->bCurrentRecordModified && psDBF->nCurrentRecord > -1 )
|
|
310
|
+
{
|
|
311
|
+
psDBF->bCurrentRecordModified = FALSE;
|
|
312
|
+
|
|
313
|
+
nRecordOffset = psDBF->nRecordLength * psDBF->nCurrentRecord
|
|
314
|
+
+ psDBF->nHeaderLength;
|
|
315
|
+
|
|
316
|
+
fseek( psDBF->fp, nRecordOffset, 0 );
|
|
317
|
+
fwrite( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/************************************************************************/
|
|
322
|
+
/* DBFUpdateHeader() */
|
|
323
|
+
/************************************************************************/
|
|
324
|
+
|
|
325
|
+
void SHPAPI_CALL
|
|
326
|
+
DBFUpdateHeader( DBFHandle psDBF )
|
|
327
|
+
|
|
328
|
+
{
|
|
329
|
+
unsigned char abyFileHeader[32];
|
|
330
|
+
|
|
331
|
+
if( psDBF->bNoHeader )
|
|
332
|
+
DBFWriteHeader( psDBF );
|
|
333
|
+
|
|
334
|
+
DBFFlushRecord( psDBF );
|
|
335
|
+
|
|
336
|
+
fseek( psDBF->fp, 0, 0 );
|
|
337
|
+
fread( abyFileHeader, 32, 1, psDBF->fp );
|
|
338
|
+
|
|
339
|
+
abyFileHeader[4] = (unsigned char) (psDBF->nRecords % 256);
|
|
340
|
+
abyFileHeader[5] = (unsigned char) ((psDBF->nRecords/256) % 256);
|
|
341
|
+
abyFileHeader[6] = (unsigned char) ((psDBF->nRecords/(256*256)) % 256);
|
|
342
|
+
abyFileHeader[7] = (unsigned char) ((psDBF->nRecords/(256*256*256)) % 256);
|
|
343
|
+
|
|
344
|
+
fseek( psDBF->fp, 0, 0 );
|
|
345
|
+
fwrite( abyFileHeader, 32, 1, psDBF->fp );
|
|
346
|
+
|
|
347
|
+
fflush( psDBF->fp );
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/************************************************************************/
|
|
351
|
+
/* DBFOpen() */
|
|
352
|
+
/* */
|
|
353
|
+
/* Open a .dbf file. */
|
|
354
|
+
/************************************************************************/
|
|
355
|
+
|
|
356
|
+
DBFHandle SHPAPI_CALL
|
|
357
|
+
DBFOpen( const char * pszFilename, const char * pszAccess )
|
|
358
|
+
|
|
359
|
+
{
|
|
360
|
+
DBFHandle psDBF;
|
|
361
|
+
unsigned char *pabyBuf;
|
|
362
|
+
int nFields, nHeadLen, nRecLen, iField, i;
|
|
363
|
+
char *pszBasename, *pszFullname;
|
|
364
|
+
|
|
365
|
+
/* -------------------------------------------------------------------- */
|
|
366
|
+
/* We only allow the access strings "rb" and "r+". */
|
|
367
|
+
/* -------------------------------------------------------------------- */
|
|
368
|
+
if( strcmp(pszAccess,"r") != 0 && strcmp(pszAccess,"r+") != 0
|
|
369
|
+
&& strcmp(pszAccess,"rb") != 0 && strcmp(pszAccess,"rb+") != 0
|
|
370
|
+
&& strcmp(pszAccess,"r+b") != 0 )
|
|
371
|
+
return( NULL );
|
|
372
|
+
|
|
373
|
+
if( strcmp(pszAccess,"r") == 0 )
|
|
374
|
+
pszAccess = "rb";
|
|
375
|
+
|
|
376
|
+
if( strcmp(pszAccess,"r+") == 0 )
|
|
377
|
+
pszAccess = "rb+";
|
|
378
|
+
|
|
379
|
+
/* -------------------------------------------------------------------- */
|
|
380
|
+
/* Compute the base (layer) name. If there is any extension */
|
|
381
|
+
/* on the passed in filename we will strip it off. */
|
|
382
|
+
/* -------------------------------------------------------------------- */
|
|
383
|
+
pszBasename = (char *) malloc(strlen(pszFilename)+5);
|
|
384
|
+
strcpy( pszBasename, pszFilename );
|
|
385
|
+
for( i = strlen(pszBasename)-1;
|
|
386
|
+
i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
|
|
387
|
+
&& pszBasename[i] != '\\';
|
|
388
|
+
i-- ) {}
|
|
389
|
+
|
|
390
|
+
if( pszBasename[i] == '.' )
|
|
391
|
+
pszBasename[i] = '\0';
|
|
392
|
+
|
|
393
|
+
pszFullname = (char *) malloc(strlen(pszBasename) + 5);
|
|
394
|
+
sprintf( pszFullname, "%s.dbf", pszBasename );
|
|
395
|
+
|
|
396
|
+
psDBF = (DBFHandle) calloc( 1, sizeof(DBFInfo) );
|
|
397
|
+
psDBF->fp = fopen( pszFullname, pszAccess );
|
|
398
|
+
|
|
399
|
+
if( psDBF->fp == NULL )
|
|
400
|
+
{
|
|
401
|
+
sprintf( pszFullname, "%s.DBF", pszBasename );
|
|
402
|
+
psDBF->fp = fopen(pszFullname, pszAccess );
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
free( pszBasename );
|
|
406
|
+
free( pszFullname );
|
|
407
|
+
|
|
408
|
+
if( psDBF->fp == NULL )
|
|
409
|
+
{
|
|
410
|
+
free( psDBF );
|
|
411
|
+
return( NULL );
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
psDBF->bNoHeader = FALSE;
|
|
415
|
+
psDBF->nCurrentRecord = -1;
|
|
416
|
+
psDBF->bCurrentRecordModified = FALSE;
|
|
417
|
+
|
|
418
|
+
/* -------------------------------------------------------------------- */
|
|
419
|
+
/* Read Table Header info */
|
|
420
|
+
/* -------------------------------------------------------------------- */
|
|
421
|
+
pabyBuf = (unsigned char *) malloc(500);
|
|
422
|
+
if( fread( pabyBuf, 32, 1, psDBF->fp ) != 1 )
|
|
423
|
+
{
|
|
424
|
+
fclose( psDBF->fp );
|
|
425
|
+
free( pabyBuf );
|
|
426
|
+
free( psDBF );
|
|
427
|
+
return NULL;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
psDBF->nRecords =
|
|
431
|
+
pabyBuf[4] + pabyBuf[5]*256 + pabyBuf[6]*256*256 + pabyBuf[7]*256*256*256;
|
|
432
|
+
|
|
433
|
+
psDBF->nHeaderLength = nHeadLen = pabyBuf[8] + pabyBuf[9]*256;
|
|
434
|
+
psDBF->nRecordLength = nRecLen = pabyBuf[10] + pabyBuf[11]*256;
|
|
435
|
+
|
|
436
|
+
psDBF->nFields = nFields = (nHeadLen - 32) / 32;
|
|
437
|
+
|
|
438
|
+
psDBF->pszCurrentRecord = (char *) malloc(nRecLen);
|
|
439
|
+
|
|
440
|
+
/* -------------------------------------------------------------------- */
|
|
441
|
+
/* Read in Field Definitions */
|
|
442
|
+
/* -------------------------------------------------------------------- */
|
|
443
|
+
|
|
444
|
+
pabyBuf = (unsigned char *) SfRealloc(pabyBuf,nHeadLen);
|
|
445
|
+
psDBF->pszHeader = (char *) pabyBuf;
|
|
446
|
+
|
|
447
|
+
fseek( psDBF->fp, 32, 0 );
|
|
448
|
+
if( fread( pabyBuf, nHeadLen-32, 1, psDBF->fp ) != 1 )
|
|
449
|
+
{
|
|
450
|
+
fclose( psDBF->fp );
|
|
451
|
+
free( pabyBuf );
|
|
452
|
+
free( psDBF );
|
|
453
|
+
return NULL;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
psDBF->panFieldOffset = (int *) malloc(sizeof(int) * nFields);
|
|
457
|
+
psDBF->panFieldSize = (int *) malloc(sizeof(int) * nFields);
|
|
458
|
+
psDBF->panFieldDecimals = (int *) malloc(sizeof(int) * nFields);
|
|
459
|
+
psDBF->pachFieldType = (char *) malloc(sizeof(char) * nFields);
|
|
460
|
+
|
|
461
|
+
for( iField = 0; iField < nFields; iField++ )
|
|
462
|
+
{
|
|
463
|
+
unsigned char *pabyFInfo;
|
|
464
|
+
|
|
465
|
+
pabyFInfo = pabyBuf+iField*32;
|
|
466
|
+
|
|
467
|
+
if( pabyFInfo[11] == 'N' || pabyFInfo[11] == 'F' )
|
|
468
|
+
{
|
|
469
|
+
psDBF->panFieldSize[iField] = pabyFInfo[16];
|
|
470
|
+
psDBF->panFieldDecimals[iField] = pabyFInfo[17];
|
|
471
|
+
}
|
|
472
|
+
else
|
|
473
|
+
{
|
|
474
|
+
psDBF->panFieldSize[iField] = pabyFInfo[16] + pabyFInfo[17]*256;
|
|
475
|
+
psDBF->panFieldDecimals[iField] = 0;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
psDBF->pachFieldType[iField] = (char) pabyFInfo[11];
|
|
479
|
+
if( iField == 0 )
|
|
480
|
+
psDBF->panFieldOffset[iField] = 1;
|
|
481
|
+
else
|
|
482
|
+
psDBF->panFieldOffset[iField] =
|
|
483
|
+
psDBF->panFieldOffset[iField-1] + psDBF->panFieldSize[iField-1];
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
return( psDBF );
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/************************************************************************/
|
|
490
|
+
/* DBFClose() */
|
|
491
|
+
/************************************************************************/
|
|
492
|
+
|
|
493
|
+
void SHPAPI_CALL
|
|
494
|
+
DBFClose(DBFHandle psDBF)
|
|
495
|
+
{
|
|
496
|
+
static char eof = 0x1a;
|
|
497
|
+
char eof_test;
|
|
498
|
+
|
|
499
|
+
/* -------------------------------------------------------------------- */
|
|
500
|
+
/* Write out header if not already written. */
|
|
501
|
+
/* -------------------------------------------------------------------- */
|
|
502
|
+
if( psDBF->bNoHeader )
|
|
503
|
+
DBFWriteHeader( psDBF );
|
|
504
|
+
|
|
505
|
+
DBFFlushRecord( psDBF );
|
|
506
|
+
|
|
507
|
+
/* -------------------------------------------------------------------- */
|
|
508
|
+
/* Update last access date, and number of records if we have */
|
|
509
|
+
/* write access. */
|
|
510
|
+
/* -------------------------------------------------------------------- */
|
|
511
|
+
if( psDBF->bUpdated )
|
|
512
|
+
DBFUpdateHeader( psDBF );
|
|
513
|
+
|
|
514
|
+
/* -------------------------------------------------------------------- */
|
|
515
|
+
/* Add the DBF end-of-file marker after the last record. */
|
|
516
|
+
/* -------------------------------------------------------------------- */
|
|
517
|
+
|
|
518
|
+
fseek(psDBF->fp, -1, SEEK_END);
|
|
519
|
+
fread(&eof_test, 1, 1, psDBF->fp);
|
|
520
|
+
if( eof_test != 0x1a ) /* no EOF exists, so write one */
|
|
521
|
+
{
|
|
522
|
+
fseek(psDBF->fp, 0, SEEK_END);
|
|
523
|
+
fwrite(&eof, 1, 1, psDBF->fp);
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
/* -------------------------------------------------------------------- */
|
|
527
|
+
/* Close, and free resources. */
|
|
528
|
+
/* -------------------------------------------------------------------- */
|
|
529
|
+
fclose( psDBF->fp );
|
|
530
|
+
|
|
531
|
+
if( psDBF->panFieldOffset != NULL )
|
|
532
|
+
{
|
|
533
|
+
free( psDBF->panFieldOffset );
|
|
534
|
+
free( psDBF->panFieldSize );
|
|
535
|
+
free( psDBF->panFieldDecimals );
|
|
536
|
+
free( psDBF->pachFieldType );
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
free( psDBF->pszHeader );
|
|
540
|
+
free( psDBF->pszCurrentRecord );
|
|
541
|
+
|
|
542
|
+
free( psDBF );
|
|
543
|
+
|
|
544
|
+
if( pszStringField != NULL )
|
|
545
|
+
{
|
|
546
|
+
free( pszStringField );
|
|
547
|
+
pszStringField = NULL;
|
|
548
|
+
nStringFieldLen = 0;
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
/************************************************************************/
|
|
553
|
+
/* DBFCreate() */
|
|
554
|
+
/* */
|
|
555
|
+
/* Create a new .dbf file. */
|
|
556
|
+
/************************************************************************/
|
|
557
|
+
|
|
558
|
+
DBFHandle SHPAPI_CALL
|
|
559
|
+
DBFCreate( const char * pszFilename )
|
|
560
|
+
|
|
561
|
+
{
|
|
562
|
+
DBFHandle psDBF;
|
|
563
|
+
FILE *fp;
|
|
564
|
+
char *pszFullname, *pszBasename;
|
|
565
|
+
int i;
|
|
566
|
+
|
|
567
|
+
/* -------------------------------------------------------------------- */
|
|
568
|
+
/* Compute the base (layer) name. If there is any extension */
|
|
569
|
+
/* on the passed in filename we will strip it off. */
|
|
570
|
+
/* -------------------------------------------------------------------- */
|
|
571
|
+
pszBasename = (char *) malloc(strlen(pszFilename)+5);
|
|
572
|
+
strcpy( pszBasename, pszFilename );
|
|
573
|
+
for( i = strlen(pszBasename)-1;
|
|
574
|
+
i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
|
|
575
|
+
&& pszBasename[i] != '\\';
|
|
576
|
+
i-- ) {}
|
|
577
|
+
|
|
578
|
+
if( pszBasename[i] == '.' )
|
|
579
|
+
pszBasename[i] = '\0';
|
|
580
|
+
|
|
581
|
+
pszFullname = (char *) malloc(strlen(pszBasename) + 5);
|
|
582
|
+
sprintf( pszFullname, "%s.dbf", pszBasename );
|
|
583
|
+
free( pszBasename );
|
|
584
|
+
|
|
585
|
+
/* -------------------------------------------------------------------- */
|
|
586
|
+
/* Create the file. */
|
|
587
|
+
/* -------------------------------------------------------------------- */
|
|
588
|
+
fp = fopen( pszFullname, "wb" );
|
|
589
|
+
if( fp == NULL )
|
|
590
|
+
return( NULL );
|
|
591
|
+
|
|
592
|
+
fputc( 0, fp );
|
|
593
|
+
fclose( fp );
|
|
594
|
+
|
|
595
|
+
fp = fopen( pszFullname, "rb+" );
|
|
596
|
+
if( fp == NULL )
|
|
597
|
+
return( NULL );
|
|
598
|
+
|
|
599
|
+
free( pszFullname );
|
|
600
|
+
|
|
601
|
+
/* -------------------------------------------------------------------- */
|
|
602
|
+
/* Create the info structure. */
|
|
603
|
+
/* -------------------------------------------------------------------- */
|
|
604
|
+
psDBF = (DBFHandle) malloc(sizeof(DBFInfo));
|
|
605
|
+
|
|
606
|
+
psDBF->fp = fp;
|
|
607
|
+
psDBF->nRecords = 0;
|
|
608
|
+
psDBF->nFields = 0;
|
|
609
|
+
psDBF->nRecordLength = 1;
|
|
610
|
+
psDBF->nHeaderLength = 33;
|
|
611
|
+
psDBF->bUpdated = FALSE;
|
|
612
|
+
|
|
613
|
+
psDBF->panFieldOffset = NULL;
|
|
614
|
+
psDBF->panFieldSize = NULL;
|
|
615
|
+
psDBF->panFieldDecimals = NULL;
|
|
616
|
+
psDBF->pachFieldType = NULL;
|
|
617
|
+
psDBF->pszHeader = NULL;
|
|
618
|
+
|
|
619
|
+
psDBF->nCurrentRecord = -1;
|
|
620
|
+
psDBF->bCurrentRecordModified = FALSE;
|
|
621
|
+
psDBF->pszCurrentRecord = NULL;
|
|
622
|
+
|
|
623
|
+
psDBF->bNoHeader = TRUE;
|
|
624
|
+
|
|
625
|
+
return( psDBF );
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
/************************************************************************/
|
|
629
|
+
/* DBFAddField() */
|
|
630
|
+
/* */
|
|
631
|
+
/* Add a field to a newly created .dbf file before any records */
|
|
632
|
+
/* are written. */
|
|
633
|
+
/************************************************************************/
|
|
634
|
+
|
|
635
|
+
int SHPAPI_CALL
|
|
636
|
+
DBFAddField(DBFHandle psDBF, const char * pszFieldName,
|
|
637
|
+
DBFFieldType eType, int nWidth, int nDecimals )
|
|
638
|
+
|
|
639
|
+
{
|
|
640
|
+
char *pszFInfo;
|
|
641
|
+
int i;
|
|
642
|
+
|
|
643
|
+
/* -------------------------------------------------------------------- */
|
|
644
|
+
/* Do some checking to ensure we can add records to this file. */
|
|
645
|
+
/* -------------------------------------------------------------------- */
|
|
646
|
+
if( psDBF->nRecords > 0 )
|
|
647
|
+
return( -1 );
|
|
648
|
+
|
|
649
|
+
if( !psDBF->bNoHeader )
|
|
650
|
+
return( -1 );
|
|
651
|
+
|
|
652
|
+
if( eType != FTDouble && nDecimals != 0 )
|
|
653
|
+
return( -1 );
|
|
654
|
+
|
|
655
|
+
if( nWidth < 1 )
|
|
656
|
+
return -1;
|
|
657
|
+
|
|
658
|
+
/* -------------------------------------------------------------------- */
|
|
659
|
+
/* SfRealloc all the arrays larger to hold the additional field */
|
|
660
|
+
/* information. */
|
|
661
|
+
/* -------------------------------------------------------------------- */
|
|
662
|
+
psDBF->nFields++;
|
|
663
|
+
|
|
664
|
+
psDBF->panFieldOffset = (int *)
|
|
665
|
+
SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
|
|
666
|
+
|
|
667
|
+
psDBF->panFieldSize = (int *)
|
|
668
|
+
SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
|
|
669
|
+
|
|
670
|
+
psDBF->panFieldDecimals = (int *)
|
|
671
|
+
SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
|
|
672
|
+
|
|
673
|
+
psDBF->pachFieldType = (char *)
|
|
674
|
+
SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields );
|
|
675
|
+
|
|
676
|
+
/* -------------------------------------------------------------------- */
|
|
677
|
+
/* Assign the new field information fields. */
|
|
678
|
+
/* -------------------------------------------------------------------- */
|
|
679
|
+
psDBF->panFieldOffset[psDBF->nFields-1] = psDBF->nRecordLength;
|
|
680
|
+
psDBF->nRecordLength += nWidth;
|
|
681
|
+
psDBF->panFieldSize[psDBF->nFields-1] = nWidth;
|
|
682
|
+
psDBF->panFieldDecimals[psDBF->nFields-1] = nDecimals;
|
|
683
|
+
|
|
684
|
+
if( eType == FTLogical )
|
|
685
|
+
psDBF->pachFieldType[psDBF->nFields-1] = 'L';
|
|
686
|
+
else if( eType == FTString )
|
|
687
|
+
psDBF->pachFieldType[psDBF->nFields-1] = 'C';
|
|
688
|
+
else if( eType == FTDate )
|
|
689
|
+
psDBF->pachFieldType[psDBF->nFields-1] = 'D';
|
|
690
|
+
else
|
|
691
|
+
psDBF->pachFieldType[psDBF->nFields-1] = 'N';
|
|
692
|
+
|
|
693
|
+
/* -------------------------------------------------------------------- */
|
|
694
|
+
/* Extend the required header information. */
|
|
695
|
+
/* -------------------------------------------------------------------- */
|
|
696
|
+
psDBF->nHeaderLength += 32;
|
|
697
|
+
psDBF->bUpdated = FALSE;
|
|
698
|
+
|
|
699
|
+
psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,psDBF->nFields*32);
|
|
700
|
+
|
|
701
|
+
pszFInfo = psDBF->pszHeader + 32 * (psDBF->nFields-1);
|
|
702
|
+
|
|
703
|
+
for( i = 0; i < 32; i++ )
|
|
704
|
+
pszFInfo[i] = '\0';
|
|
705
|
+
|
|
706
|
+
if( (int) strlen(pszFieldName) < 10 )
|
|
707
|
+
strncpy( pszFInfo, pszFieldName, strlen(pszFieldName));
|
|
708
|
+
else
|
|
709
|
+
strncpy( pszFInfo, pszFieldName, 10);
|
|
710
|
+
|
|
711
|
+
pszFInfo[11] = psDBF->pachFieldType[psDBF->nFields-1];
|
|
712
|
+
|
|
713
|
+
if( eType == FTString )
|
|
714
|
+
{
|
|
715
|
+
pszFInfo[16] = (unsigned char) (nWidth % 256);
|
|
716
|
+
pszFInfo[17] = (unsigned char) (nWidth / 256);
|
|
717
|
+
}
|
|
718
|
+
else
|
|
719
|
+
{
|
|
720
|
+
pszFInfo[16] = (unsigned char) nWidth;
|
|
721
|
+
pszFInfo[17] = (unsigned char) nDecimals;
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
/* -------------------------------------------------------------------- */
|
|
725
|
+
/* Make the current record buffer appropriately larger. */
|
|
726
|
+
/* -------------------------------------------------------------------- */
|
|
727
|
+
psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord,
|
|
728
|
+
psDBF->nRecordLength);
|
|
729
|
+
|
|
730
|
+
return( psDBF->nFields-1 );
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
|
|
734
|
+
/************************************************************************/
|
|
735
|
+
/* DBFReadSetup() */
|
|
736
|
+
/* */
|
|
737
|
+
/* Prep a record for reading. */
|
|
738
|
+
/************************************************************************/
|
|
739
|
+
|
|
740
|
+
int DBFReadSetup(DBFHandle psDBF, int hEntity)
|
|
741
|
+
{
|
|
742
|
+
int nRecordOffset;
|
|
743
|
+
|
|
744
|
+
/* -------------------------------------------------------------------- */
|
|
745
|
+
/* Verify selection. */
|
|
746
|
+
/* -------------------------------------------------------------------- */
|
|
747
|
+
if( hEntity < 0 || hEntity >= psDBF->nRecords )
|
|
748
|
+
return( 0 );
|
|
749
|
+
|
|
750
|
+
/* -------------------------------------------------------------------- */
|
|
751
|
+
/* Have we read the record? */
|
|
752
|
+
/* -------------------------------------------------------------------- */
|
|
753
|
+
if( psDBF->nCurrentRecord != hEntity )
|
|
754
|
+
{
|
|
755
|
+
DBFFlushRecord( psDBF );
|
|
756
|
+
|
|
757
|
+
nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
|
|
758
|
+
|
|
759
|
+
if( fseek( psDBF->fp, nRecordOffset, 0 ) != 0 )
|
|
760
|
+
{
|
|
761
|
+
fprintf( stderr, "fseek(%d) failed on DBF file.\n",
|
|
762
|
+
nRecordOffset );
|
|
763
|
+
return 0;
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
if( fread( psDBF->pszCurrentRecord, psDBF->nRecordLength,
|
|
767
|
+
1, psDBF->fp ) != 1 )
|
|
768
|
+
{
|
|
769
|
+
fprintf( stderr, "fread(%d) failed on DBF file.\n",
|
|
770
|
+
psDBF->nRecordLength );
|
|
771
|
+
return 0;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
psDBF->nCurrentRecord = hEntity;
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
return 1;
|
|
778
|
+
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
|
|
782
|
+
/************************************************************************/
|
|
783
|
+
/* DBFReadDeleted() */
|
|
784
|
+
/* */
|
|
785
|
+
/* Read whether a record is deleted. */
|
|
786
|
+
/************************************************************************/
|
|
787
|
+
|
|
788
|
+
int DBFReadDeleted(DBFHandle psDBF, int hEntity)
|
|
789
|
+
{
|
|
790
|
+
unsigned char *pabyRec;
|
|
791
|
+
|
|
792
|
+
if( ! DBFReadSetup( psDBF, hEntity) )
|
|
793
|
+
return 0;
|
|
794
|
+
|
|
795
|
+
/* get reference to current record */
|
|
796
|
+
pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
|
|
797
|
+
|
|
798
|
+
/* 0x20 => not deleted, 0x24 => deleted */
|
|
799
|
+
return *pabyRec == 0x20 ? 0 : 1;
|
|
800
|
+
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
/************************************************************************/
|
|
804
|
+
/* DBFReadAttribute() */
|
|
805
|
+
/* */
|
|
806
|
+
/* Read one of the attribute fields of a record. */
|
|
807
|
+
/************************************************************************/
|
|
808
|
+
|
|
809
|
+
static void *DBFReadAttribute(DBFHandle psDBF, int hEntity, int iField,
|
|
810
|
+
char chReqType )
|
|
811
|
+
|
|
812
|
+
{
|
|
813
|
+
unsigned char *pabyRec;
|
|
814
|
+
void *pReturnField = NULL;
|
|
815
|
+
|
|
816
|
+
static double dDoubleField;
|
|
817
|
+
|
|
818
|
+
/* -------------------------------------------------------------------- */
|
|
819
|
+
/* Verify selection. */
|
|
820
|
+
/* -------------------------------------------------------------------- */
|
|
821
|
+
if( iField < 0 || iField >= psDBF->nFields )
|
|
822
|
+
return( NULL );
|
|
823
|
+
|
|
824
|
+
if( ! DBFReadSetup( psDBF, hEntity) )
|
|
825
|
+
return( NULL );
|
|
826
|
+
|
|
827
|
+
/* get reference to current record */
|
|
828
|
+
pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
|
|
829
|
+
|
|
830
|
+
/* -------------------------------------------------------------------- */
|
|
831
|
+
/* Ensure our field buffer is large enough to hold this buffer. */
|
|
832
|
+
/* -------------------------------------------------------------------- */
|
|
833
|
+
if( psDBF->panFieldSize[iField]+1 > nStringFieldLen )
|
|
834
|
+
{
|
|
835
|
+
nStringFieldLen = psDBF->panFieldSize[iField]*2 + 10;
|
|
836
|
+
pszStringField = (char *) SfRealloc(pszStringField,nStringFieldLen);
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
/* -------------------------------------------------------------------- */
|
|
840
|
+
/* Extract the requested field. */
|
|
841
|
+
/* -------------------------------------------------------------------- */
|
|
842
|
+
strncpy( pszStringField,
|
|
843
|
+
((const char *) pabyRec) + psDBF->panFieldOffset[iField],
|
|
844
|
+
psDBF->panFieldSize[iField] );
|
|
845
|
+
pszStringField[psDBF->panFieldSize[iField]] = '\0';
|
|
846
|
+
|
|
847
|
+
pReturnField = pszStringField;
|
|
848
|
+
|
|
849
|
+
/* -------------------------------------------------------------------- */
|
|
850
|
+
/* Decode the field. */
|
|
851
|
+
/* -------------------------------------------------------------------- */
|
|
852
|
+
if( chReqType == 'N' )
|
|
853
|
+
{
|
|
854
|
+
dDoubleField = atof(pszStringField);
|
|
855
|
+
pReturnField = &dDoubleField;
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
/* -------------------------------------------------------------------- */
|
|
859
|
+
/* Should we trim white space off the string attribute value? */
|
|
860
|
+
/* -------------------------------------------------------------------- */
|
|
861
|
+
#ifdef TRIM_DBF_WHITESPACE
|
|
862
|
+
else
|
|
863
|
+
{
|
|
864
|
+
char *pchSrc, *pchDst;
|
|
865
|
+
|
|
866
|
+
pchDst = pchSrc = pszStringField;
|
|
867
|
+
while( *pchSrc == ' ' )
|
|
868
|
+
pchSrc++;
|
|
869
|
+
|
|
870
|
+
while( *pchSrc != '\0' )
|
|
871
|
+
*(pchDst++) = *(pchSrc++);
|
|
872
|
+
*pchDst = '\0';
|
|
873
|
+
|
|
874
|
+
while( pchDst != pszStringField && *(--pchDst) == ' ' )
|
|
875
|
+
*pchDst = '\0';
|
|
876
|
+
}
|
|
877
|
+
#endif
|
|
878
|
+
|
|
879
|
+
return( pReturnField );
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
/************************************************************************/
|
|
883
|
+
/* DBFReadIntAttribute() */
|
|
884
|
+
/* */
|
|
885
|
+
/* Read an integer attribute. */
|
|
886
|
+
/************************************************************************/
|
|
887
|
+
|
|
888
|
+
int SHPAPI_CALL
|
|
889
|
+
DBFReadIntegerAttribute( DBFHandle psDBF, int iRecord, int iField )
|
|
890
|
+
|
|
891
|
+
{
|
|
892
|
+
double *pdValue;
|
|
893
|
+
|
|
894
|
+
pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' );
|
|
895
|
+
|
|
896
|
+
if( pdValue == NULL )
|
|
897
|
+
return 0;
|
|
898
|
+
else
|
|
899
|
+
return( (int) *pdValue );
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
/************************************************************************/
|
|
903
|
+
/* DBFReadDoubleAttribute() */
|
|
904
|
+
/* */
|
|
905
|
+
/* Read a double attribute. */
|
|
906
|
+
/************************************************************************/
|
|
907
|
+
|
|
908
|
+
double SHPAPI_CALL
|
|
909
|
+
DBFReadDoubleAttribute( DBFHandle psDBF, int iRecord, int iField )
|
|
910
|
+
|
|
911
|
+
{
|
|
912
|
+
double *pdValue;
|
|
913
|
+
|
|
914
|
+
pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' );
|
|
915
|
+
|
|
916
|
+
if( pdValue == NULL )
|
|
917
|
+
return 0.0;
|
|
918
|
+
else
|
|
919
|
+
return( *pdValue );
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
/************************************************************************/
|
|
923
|
+
/* DBFReadStringAttribute() */
|
|
924
|
+
/* */
|
|
925
|
+
/* Read a string attribute. */
|
|
926
|
+
/************************************************************************/
|
|
927
|
+
|
|
928
|
+
const char SHPAPI_CALL1(*)
|
|
929
|
+
DBFReadStringAttribute( DBFHandle psDBF, int iRecord, int iField )
|
|
930
|
+
|
|
931
|
+
{
|
|
932
|
+
return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'C' ) );
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
/************************************************************************/
|
|
936
|
+
/* DBFReadLogicalAttribute() */
|
|
937
|
+
/* */
|
|
938
|
+
/* Read a logical attribute. */
|
|
939
|
+
/************************************************************************/
|
|
940
|
+
|
|
941
|
+
const char SHPAPI_CALL1(*)
|
|
942
|
+
DBFReadLogicalAttribute( DBFHandle psDBF, int iRecord, int iField )
|
|
943
|
+
|
|
944
|
+
{
|
|
945
|
+
return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'L' ) );
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
/************************************************************************/
|
|
949
|
+
/* DBFIsAttributeNULL() */
|
|
950
|
+
/* */
|
|
951
|
+
/* Return TRUE if value for field is NULL. */
|
|
952
|
+
/* */
|
|
953
|
+
/* Contributed by Jim Matthews. */
|
|
954
|
+
/************************************************************************/
|
|
955
|
+
|
|
956
|
+
int SHPAPI_CALL
|
|
957
|
+
DBFIsAttributeNULL( DBFHandle psDBF, int iRecord, int iField )
|
|
958
|
+
|
|
959
|
+
{
|
|
960
|
+
const char *pszValue;
|
|
961
|
+
|
|
962
|
+
pszValue = DBFReadStringAttribute( psDBF, iRecord, iField );
|
|
963
|
+
|
|
964
|
+
if( pszValue == NULL )
|
|
965
|
+
return TRUE;
|
|
966
|
+
|
|
967
|
+
switch(psDBF->pachFieldType[iField])
|
|
968
|
+
{
|
|
969
|
+
case 'N':
|
|
970
|
+
case 'F':
|
|
971
|
+
/* NULL numeric fields have value "****************" */
|
|
972
|
+
return pszValue[0] == '*';
|
|
973
|
+
|
|
974
|
+
case 'D':
|
|
975
|
+
/* NULL date fields have value "00000000" */
|
|
976
|
+
return (strncmp(pszValue,"00000000",8) == 0 || strlen(pszValue) == 0);
|
|
977
|
+
|
|
978
|
+
case 'L':
|
|
979
|
+
/* NULL boolean fields have value "?" */
|
|
980
|
+
return pszValue[0] == '?';
|
|
981
|
+
|
|
982
|
+
default:
|
|
983
|
+
/* empty string fields are considered NULL */
|
|
984
|
+
return strlen(pszValue) == 0;
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
/************************************************************************/
|
|
989
|
+
/* DBFGetFieldCount() */
|
|
990
|
+
/* */
|
|
991
|
+
/* Return the number of fields in this table. */
|
|
992
|
+
/************************************************************************/
|
|
993
|
+
|
|
994
|
+
int SHPAPI_CALL
|
|
995
|
+
DBFGetFieldCount( DBFHandle psDBF )
|
|
996
|
+
|
|
997
|
+
{
|
|
998
|
+
return( psDBF->nFields );
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
/************************************************************************/
|
|
1002
|
+
/* DBFGetRecordCount() */
|
|
1003
|
+
/* */
|
|
1004
|
+
/* Return the number of records in this table. */
|
|
1005
|
+
/************************************************************************/
|
|
1006
|
+
|
|
1007
|
+
int SHPAPI_CALL
|
|
1008
|
+
DBFGetRecordCount( DBFHandle psDBF )
|
|
1009
|
+
|
|
1010
|
+
{
|
|
1011
|
+
return( psDBF->nRecords );
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
/************************************************************************/
|
|
1015
|
+
/* DBFGetFieldInfo() */
|
|
1016
|
+
/* */
|
|
1017
|
+
/* Return any requested information about the field. */
|
|
1018
|
+
/************************************************************************/
|
|
1019
|
+
|
|
1020
|
+
DBFFieldType SHPAPI_CALL
|
|
1021
|
+
DBFGetFieldInfo( DBFHandle psDBF, int iField, char * pszFieldName,
|
|
1022
|
+
int * pnWidth, int * pnDecimals )
|
|
1023
|
+
|
|
1024
|
+
{
|
|
1025
|
+
if( iField < 0 || iField >= psDBF->nFields )
|
|
1026
|
+
return( FTInvalid );
|
|
1027
|
+
|
|
1028
|
+
if( pnWidth != NULL )
|
|
1029
|
+
*pnWidth = psDBF->panFieldSize[iField];
|
|
1030
|
+
|
|
1031
|
+
if( pnDecimals != NULL )
|
|
1032
|
+
*pnDecimals = psDBF->panFieldDecimals[iField];
|
|
1033
|
+
|
|
1034
|
+
if( pszFieldName != NULL )
|
|
1035
|
+
{
|
|
1036
|
+
int i;
|
|
1037
|
+
|
|
1038
|
+
strncpy( pszFieldName, (char *) psDBF->pszHeader+iField*32, 11 );
|
|
1039
|
+
pszFieldName[11] = '\0';
|
|
1040
|
+
for( i = 10; i > 0 && pszFieldName[i] == ' '; i-- )
|
|
1041
|
+
pszFieldName[i] = '\0';
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
if ( psDBF->pachFieldType[iField] == 'L' )
|
|
1045
|
+
return( FTLogical);
|
|
1046
|
+
|
|
1047
|
+
else if( psDBF->pachFieldType[iField] == 'D' )
|
|
1048
|
+
return ( FTDate );
|
|
1049
|
+
|
|
1050
|
+
else if( psDBF->pachFieldType[iField] == 'N'
|
|
1051
|
+
|| psDBF->pachFieldType[iField] == 'F' )
|
|
1052
|
+
{
|
|
1053
|
+
if( psDBF->panFieldDecimals[iField] > 0 )
|
|
1054
|
+
return( FTDouble );
|
|
1055
|
+
else
|
|
1056
|
+
return( FTInteger );
|
|
1057
|
+
}
|
|
1058
|
+
else
|
|
1059
|
+
{
|
|
1060
|
+
return( FTString );
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
/************************************************************************/
|
|
1065
|
+
/* DBFWriteAttribute() */
|
|
1066
|
+
/* */
|
|
1067
|
+
/* Write an attribute record to the file. */
|
|
1068
|
+
/************************************************************************/
|
|
1069
|
+
|
|
1070
|
+
static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField,
|
|
1071
|
+
void * pValue )
|
|
1072
|
+
|
|
1073
|
+
{
|
|
1074
|
+
int nRecordOffset, i, j, nRetResult = TRUE;
|
|
1075
|
+
unsigned char *pabyRec;
|
|
1076
|
+
char szSField[400], szFormat[20];
|
|
1077
|
+
|
|
1078
|
+
/* -------------------------------------------------------------------- */
|
|
1079
|
+
/* Is this a valid record? */
|
|
1080
|
+
/* -------------------------------------------------------------------- */
|
|
1081
|
+
if( hEntity < 0 || hEntity > psDBF->nRecords )
|
|
1082
|
+
return( FALSE );
|
|
1083
|
+
|
|
1084
|
+
if( psDBF->bNoHeader )
|
|
1085
|
+
DBFWriteHeader(psDBF);
|
|
1086
|
+
|
|
1087
|
+
/* -------------------------------------------------------------------- */
|
|
1088
|
+
/* Is this a brand new record? */
|
|
1089
|
+
/* -------------------------------------------------------------------- */
|
|
1090
|
+
if( hEntity == psDBF->nRecords )
|
|
1091
|
+
{
|
|
1092
|
+
DBFFlushRecord( psDBF );
|
|
1093
|
+
|
|
1094
|
+
psDBF->nRecords++;
|
|
1095
|
+
for( i = 0; i < psDBF->nRecordLength; i++ )
|
|
1096
|
+
psDBF->pszCurrentRecord[i] = ' ';
|
|
1097
|
+
|
|
1098
|
+
psDBF->nCurrentRecord = hEntity;
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
/* -------------------------------------------------------------------- */
|
|
1102
|
+
/* Is this an existing record, but different than the last one */
|
|
1103
|
+
/* we accessed? */
|
|
1104
|
+
/* -------------------------------------------------------------------- */
|
|
1105
|
+
if( psDBF->nCurrentRecord != hEntity )
|
|
1106
|
+
{
|
|
1107
|
+
DBFFlushRecord( psDBF );
|
|
1108
|
+
|
|
1109
|
+
nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
|
|
1110
|
+
|
|
1111
|
+
fseek( psDBF->fp, nRecordOffset, 0 );
|
|
1112
|
+
fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
|
|
1113
|
+
|
|
1114
|
+
psDBF->nCurrentRecord = hEntity;
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
|
|
1118
|
+
|
|
1119
|
+
psDBF->bCurrentRecordModified = TRUE;
|
|
1120
|
+
psDBF->bUpdated = TRUE;
|
|
1121
|
+
|
|
1122
|
+
/* -------------------------------------------------------------------- */
|
|
1123
|
+
/* Translate NULL value to valid DBF file representation. */
|
|
1124
|
+
/* */
|
|
1125
|
+
/* Contributed by Jim Matthews. */
|
|
1126
|
+
/* -------------------------------------------------------------------- */
|
|
1127
|
+
if( pValue == NULL )
|
|
1128
|
+
{
|
|
1129
|
+
switch(psDBF->pachFieldType[iField])
|
|
1130
|
+
{
|
|
1131
|
+
case 'N':
|
|
1132
|
+
case 'F':
|
|
1133
|
+
/* NULL numeric fields have value "****************" */
|
|
1134
|
+
memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '*',
|
|
1135
|
+
psDBF->panFieldSize[iField] );
|
|
1136
|
+
break;
|
|
1137
|
+
|
|
1138
|
+
case 'D':
|
|
1139
|
+
/* NULL date fields have value "00000000" */
|
|
1140
|
+
memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '0',
|
|
1141
|
+
psDBF->panFieldSize[iField] );
|
|
1142
|
+
break;
|
|
1143
|
+
|
|
1144
|
+
case 'L':
|
|
1145
|
+
/* NULL boolean fields have value "?" */
|
|
1146
|
+
memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '?',
|
|
1147
|
+
psDBF->panFieldSize[iField] );
|
|
1148
|
+
break;
|
|
1149
|
+
|
|
1150
|
+
default:
|
|
1151
|
+
/* empty string fields are considered NULL */
|
|
1152
|
+
memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), '\0',
|
|
1153
|
+
psDBF->panFieldSize[iField] );
|
|
1154
|
+
break;
|
|
1155
|
+
}
|
|
1156
|
+
return TRUE;
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
/* -------------------------------------------------------------------- */
|
|
1160
|
+
/* Assign all the record fields. */
|
|
1161
|
+
/* -------------------------------------------------------------------- */
|
|
1162
|
+
switch( psDBF->pachFieldType[iField] )
|
|
1163
|
+
{
|
|
1164
|
+
case 'D':
|
|
1165
|
+
case 'N':
|
|
1166
|
+
case 'F':
|
|
1167
|
+
if( psDBF->panFieldDecimals[iField] == 0 )
|
|
1168
|
+
{
|
|
1169
|
+
int nWidth = psDBF->panFieldSize[iField];
|
|
1170
|
+
|
|
1171
|
+
if( sizeof(szSField)-2 < nWidth )
|
|
1172
|
+
nWidth = sizeof(szSField)-2;
|
|
1173
|
+
|
|
1174
|
+
sprintf( szFormat, "%%%dd", nWidth );
|
|
1175
|
+
sprintf(szSField, szFormat, (int) *((double *) pValue) );
|
|
1176
|
+
if( (int)strlen(szSField) > psDBF->panFieldSize[iField] )
|
|
1177
|
+
{
|
|
1178
|
+
szSField[psDBF->panFieldSize[iField]] = '\0';
|
|
1179
|
+
nRetResult = FALSE;
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
|
|
1183
|
+
szSField, strlen(szSField) );
|
|
1184
|
+
}
|
|
1185
|
+
else
|
|
1186
|
+
{
|
|
1187
|
+
int nWidth = psDBF->panFieldSize[iField];
|
|
1188
|
+
|
|
1189
|
+
if( sizeof(szSField)-2 < nWidth )
|
|
1190
|
+
nWidth = sizeof(szSField)-2;
|
|
1191
|
+
|
|
1192
|
+
sprintf( szFormat, "%%%d.%df",
|
|
1193
|
+
nWidth, psDBF->panFieldDecimals[iField] );
|
|
1194
|
+
sprintf(szSField, szFormat, *((double *) pValue) );
|
|
1195
|
+
if( (int) strlen(szSField) > psDBF->panFieldSize[iField] )
|
|
1196
|
+
{
|
|
1197
|
+
szSField[psDBF->panFieldSize[iField]] = '\0';
|
|
1198
|
+
nRetResult = FALSE;
|
|
1199
|
+
}
|
|
1200
|
+
strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
|
|
1201
|
+
szSField, strlen(szSField) );
|
|
1202
|
+
}
|
|
1203
|
+
break;
|
|
1204
|
+
|
|
1205
|
+
case 'L':
|
|
1206
|
+
if (psDBF->panFieldSize[iField] >= 1 &&
|
|
1207
|
+
(*(char*)pValue == 'F' || *(char*)pValue == 'T'))
|
|
1208
|
+
*(pabyRec+psDBF->panFieldOffset[iField]) = *(char*)pValue;
|
|
1209
|
+
break;
|
|
1210
|
+
|
|
1211
|
+
default:
|
|
1212
|
+
if( (int) strlen((char *) pValue) > psDBF->panFieldSize[iField] )
|
|
1213
|
+
{
|
|
1214
|
+
j = psDBF->panFieldSize[iField];
|
|
1215
|
+
nRetResult = FALSE;
|
|
1216
|
+
}
|
|
1217
|
+
else
|
|
1218
|
+
{
|
|
1219
|
+
memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
|
|
1220
|
+
psDBF->panFieldSize[iField] );
|
|
1221
|
+
j = strlen((char *) pValue);
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
|
|
1225
|
+
(char *) pValue, j );
|
|
1226
|
+
break;
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
return( nRetResult );
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
/************************************************************************/
|
|
1233
|
+
/* DBFWriteAttributeDirectly() */
|
|
1234
|
+
/* */
|
|
1235
|
+
/* Write an attribute record to the file, but without any */
|
|
1236
|
+
/* reformatting based on type. The provided buffer is written */
|
|
1237
|
+
/* as is to the field position in the record. */
|
|
1238
|
+
/************************************************************************/
|
|
1239
|
+
|
|
1240
|
+
int DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField,
|
|
1241
|
+
const void * pValue )
|
|
1242
|
+
|
|
1243
|
+
{
|
|
1244
|
+
int nRecordOffset, i, j;
|
|
1245
|
+
unsigned char *pabyRec;
|
|
1246
|
+
|
|
1247
|
+
/* -------------------------------------------------------------------- */
|
|
1248
|
+
/* Is this a valid record? */
|
|
1249
|
+
/* -------------------------------------------------------------------- */
|
|
1250
|
+
if( hEntity < 0 || hEntity > psDBF->nRecords )
|
|
1251
|
+
return( FALSE );
|
|
1252
|
+
|
|
1253
|
+
if( psDBF->bNoHeader )
|
|
1254
|
+
DBFWriteHeader(psDBF);
|
|
1255
|
+
|
|
1256
|
+
/* -------------------------------------------------------------------- */
|
|
1257
|
+
/* Is this a brand new record? */
|
|
1258
|
+
/* -------------------------------------------------------------------- */
|
|
1259
|
+
if( hEntity == psDBF->nRecords )
|
|
1260
|
+
{
|
|
1261
|
+
DBFFlushRecord( psDBF );
|
|
1262
|
+
|
|
1263
|
+
psDBF->nRecords++;
|
|
1264
|
+
for( i = 0; i < psDBF->nRecordLength; i++ )
|
|
1265
|
+
psDBF->pszCurrentRecord[i] = ' ';
|
|
1266
|
+
|
|
1267
|
+
psDBF->nCurrentRecord = hEntity;
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
/* -------------------------------------------------------------------- */
|
|
1271
|
+
/* Is this an existing record, but different than the last one */
|
|
1272
|
+
/* we accessed? */
|
|
1273
|
+
/* -------------------------------------------------------------------- */
|
|
1274
|
+
if( psDBF->nCurrentRecord != hEntity )
|
|
1275
|
+
{
|
|
1276
|
+
DBFFlushRecord( psDBF );
|
|
1277
|
+
|
|
1278
|
+
nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
|
|
1279
|
+
|
|
1280
|
+
fseek( psDBF->fp, nRecordOffset, 0 );
|
|
1281
|
+
fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
|
|
1282
|
+
|
|
1283
|
+
psDBF->nCurrentRecord = hEntity;
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
|
|
1287
|
+
|
|
1288
|
+
/* -------------------------------------------------------------------- */
|
|
1289
|
+
/* Assign all the record fields. */
|
|
1290
|
+
/* -------------------------------------------------------------------- */
|
|
1291
|
+
if( (int)strlen((char *) pValue) > psDBF->panFieldSize[iField] )
|
|
1292
|
+
j = psDBF->panFieldSize[iField];
|
|
1293
|
+
else
|
|
1294
|
+
{
|
|
1295
|
+
memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
|
|
1296
|
+
psDBF->panFieldSize[iField] );
|
|
1297
|
+
j = strlen((char *) pValue);
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
|
|
1301
|
+
(char *) pValue, j );
|
|
1302
|
+
|
|
1303
|
+
psDBF->bCurrentRecordModified = TRUE;
|
|
1304
|
+
psDBF->bUpdated = TRUE;
|
|
1305
|
+
|
|
1306
|
+
return( TRUE );
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
/************************************************************************/
|
|
1310
|
+
/* DBFWriteDoubleAttribute() */
|
|
1311
|
+
/* */
|
|
1312
|
+
/* Write a double attribute. */
|
|
1313
|
+
/************************************************************************/
|
|
1314
|
+
|
|
1315
|
+
int SHPAPI_CALL
|
|
1316
|
+
DBFWriteDoubleAttribute( DBFHandle psDBF, int iRecord, int iField,
|
|
1317
|
+
double dValue )
|
|
1318
|
+
|
|
1319
|
+
{
|
|
1320
|
+
return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) );
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
/************************************************************************/
|
|
1324
|
+
/* DBFWriteIntegerAttribute() */
|
|
1325
|
+
/* */
|
|
1326
|
+
/* Write a integer attribute. */
|
|
1327
|
+
/************************************************************************/
|
|
1328
|
+
|
|
1329
|
+
int SHPAPI_CALL
|
|
1330
|
+
DBFWriteIntegerAttribute( DBFHandle psDBF, int iRecord, int iField,
|
|
1331
|
+
int nValue )
|
|
1332
|
+
|
|
1333
|
+
{
|
|
1334
|
+
double dValue = nValue;
|
|
1335
|
+
|
|
1336
|
+
return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) );
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
/************************************************************************/
|
|
1340
|
+
/* DBFWriteStringAttribute() */
|
|
1341
|
+
/* */
|
|
1342
|
+
/* Write a string attribute. */
|
|
1343
|
+
/************************************************************************/
|
|
1344
|
+
|
|
1345
|
+
int SHPAPI_CALL
|
|
1346
|
+
DBFWriteStringAttribute( DBFHandle psDBF, int iRecord, int iField,
|
|
1347
|
+
const char * pszValue )
|
|
1348
|
+
|
|
1349
|
+
{
|
|
1350
|
+
return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) pszValue ) );
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1353
|
+
/************************************************************************/
|
|
1354
|
+
/* DBFWriteNULLAttribute() */
|
|
1355
|
+
/* */
|
|
1356
|
+
/* Write a string attribute. */
|
|
1357
|
+
/************************************************************************/
|
|
1358
|
+
|
|
1359
|
+
int SHPAPI_CALL
|
|
1360
|
+
DBFWriteNULLAttribute( DBFHandle psDBF, int iRecord, int iField )
|
|
1361
|
+
|
|
1362
|
+
{
|
|
1363
|
+
return( DBFWriteAttribute( psDBF, iRecord, iField, NULL ) );
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
/************************************************************************/
|
|
1367
|
+
/* DBFWriteLogicalAttribute() */
|
|
1368
|
+
/* */
|
|
1369
|
+
/* Write a logical attribute. */
|
|
1370
|
+
/************************************************************************/
|
|
1371
|
+
|
|
1372
|
+
int SHPAPI_CALL
|
|
1373
|
+
DBFWriteLogicalAttribute( DBFHandle psDBF, int iRecord, int iField,
|
|
1374
|
+
const char lValue)
|
|
1375
|
+
|
|
1376
|
+
{
|
|
1377
|
+
return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) (&lValue) ) );
|
|
1378
|
+
}
|
|
1379
|
+
|
|
1380
|
+
/************************************************************************/
|
|
1381
|
+
/* DBFWriteTuple() */
|
|
1382
|
+
/* */
|
|
1383
|
+
/* Write an attribute record to the file. */
|
|
1384
|
+
/************************************************************************/
|
|
1385
|
+
|
|
1386
|
+
int SHPAPI_CALL
|
|
1387
|
+
DBFWriteTuple(DBFHandle psDBF, int hEntity, void * pRawTuple )
|
|
1388
|
+
|
|
1389
|
+
{
|
|
1390
|
+
int nRecordOffset, i;
|
|
1391
|
+
unsigned char *pabyRec;
|
|
1392
|
+
|
|
1393
|
+
/* -------------------------------------------------------------------- */
|
|
1394
|
+
/* Is this a valid record? */
|
|
1395
|
+
/* -------------------------------------------------------------------- */
|
|
1396
|
+
if( hEntity < 0 || hEntity > psDBF->nRecords )
|
|
1397
|
+
return( FALSE );
|
|
1398
|
+
|
|
1399
|
+
if( psDBF->bNoHeader )
|
|
1400
|
+
DBFWriteHeader(psDBF);
|
|
1401
|
+
|
|
1402
|
+
/* -------------------------------------------------------------------- */
|
|
1403
|
+
/* Is this a brand new record? */
|
|
1404
|
+
/* -------------------------------------------------------------------- */
|
|
1405
|
+
if( hEntity == psDBF->nRecords )
|
|
1406
|
+
{
|
|
1407
|
+
DBFFlushRecord( psDBF );
|
|
1408
|
+
|
|
1409
|
+
psDBF->nRecords++;
|
|
1410
|
+
for( i = 0; i < psDBF->nRecordLength; i++ )
|
|
1411
|
+
psDBF->pszCurrentRecord[i] = ' ';
|
|
1412
|
+
|
|
1413
|
+
psDBF->nCurrentRecord = hEntity;
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
/* -------------------------------------------------------------------- */
|
|
1417
|
+
/* Is this an existing record, but different than the last one */
|
|
1418
|
+
/* we accessed? */
|
|
1419
|
+
/* -------------------------------------------------------------------- */
|
|
1420
|
+
if( psDBF->nCurrentRecord != hEntity )
|
|
1421
|
+
{
|
|
1422
|
+
DBFFlushRecord( psDBF );
|
|
1423
|
+
|
|
1424
|
+
nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
|
|
1425
|
+
|
|
1426
|
+
fseek( psDBF->fp, nRecordOffset, 0 );
|
|
1427
|
+
fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
|
|
1428
|
+
|
|
1429
|
+
psDBF->nCurrentRecord = hEntity;
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
|
|
1433
|
+
|
|
1434
|
+
memcpy ( pabyRec, pRawTuple, psDBF->nRecordLength );
|
|
1435
|
+
|
|
1436
|
+
psDBF->bCurrentRecordModified = TRUE;
|
|
1437
|
+
psDBF->bUpdated = TRUE;
|
|
1438
|
+
|
|
1439
|
+
return( TRUE );
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1442
|
+
/************************************************************************/
|
|
1443
|
+
/* DBFReadTuple() */
|
|
1444
|
+
/* */
|
|
1445
|
+
/* Read one of the attribute fields of a record. */
|
|
1446
|
+
/************************************************************************/
|
|
1447
|
+
|
|
1448
|
+
const char SHPAPI_CALL1(*)
|
|
1449
|
+
DBFReadTuple(DBFHandle psDBF, int hEntity )
|
|
1450
|
+
|
|
1451
|
+
{
|
|
1452
|
+
int nRecordOffset;
|
|
1453
|
+
unsigned char *pabyRec;
|
|
1454
|
+
static char *pReturnTuple = NULL;
|
|
1455
|
+
|
|
1456
|
+
static int nTupleLen = 0;
|
|
1457
|
+
|
|
1458
|
+
/* -------------------------------------------------------------------- */
|
|
1459
|
+
/* Have we read the record? */
|
|
1460
|
+
/* -------------------------------------------------------------------- */
|
|
1461
|
+
if( hEntity < 0 || hEntity >= psDBF->nRecords )
|
|
1462
|
+
return( NULL );
|
|
1463
|
+
|
|
1464
|
+
if( psDBF->nCurrentRecord != hEntity )
|
|
1465
|
+
{
|
|
1466
|
+
DBFFlushRecord( psDBF );
|
|
1467
|
+
|
|
1468
|
+
nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength;
|
|
1469
|
+
|
|
1470
|
+
fseek( psDBF->fp, nRecordOffset, 0 );
|
|
1471
|
+
fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp );
|
|
1472
|
+
|
|
1473
|
+
psDBF->nCurrentRecord = hEntity;
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1476
|
+
pabyRec = (unsigned char *) psDBF->pszCurrentRecord;
|
|
1477
|
+
|
|
1478
|
+
if ( nTupleLen < psDBF->nRecordLength) {
|
|
1479
|
+
nTupleLen = psDBF->nRecordLength;
|
|
1480
|
+
pReturnTuple = (char *) SfRealloc(pReturnTuple, psDBF->nRecordLength);
|
|
1481
|
+
}
|
|
1482
|
+
|
|
1483
|
+
memcpy ( pReturnTuple, pabyRec, psDBF->nRecordLength );
|
|
1484
|
+
|
|
1485
|
+
return( pReturnTuple );
|
|
1486
|
+
}
|
|
1487
|
+
|
|
1488
|
+
/************************************************************************/
|
|
1489
|
+
/* DBFCloneEmpty() */
|
|
1490
|
+
/* */
|
|
1491
|
+
/* Read one of the attribute fields of a record. */
|
|
1492
|
+
/************************************************************************/
|
|
1493
|
+
|
|
1494
|
+
DBFHandle SHPAPI_CALL
|
|
1495
|
+
DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename )
|
|
1496
|
+
{
|
|
1497
|
+
DBFHandle newDBF;
|
|
1498
|
+
|
|
1499
|
+
newDBF = DBFCreate ( pszFilename );
|
|
1500
|
+
if ( newDBF == NULL ) return ( NULL );
|
|
1501
|
+
|
|
1502
|
+
newDBF->pszHeader = (char *) malloc ( 32 * psDBF->nFields );
|
|
1503
|
+
memcpy ( newDBF->pszHeader, psDBF->pszHeader, 32 * psDBF->nFields );
|
|
1504
|
+
|
|
1505
|
+
newDBF->nFields = psDBF->nFields;
|
|
1506
|
+
newDBF->nRecordLength = psDBF->nRecordLength;
|
|
1507
|
+
newDBF->nHeaderLength = 32 * (psDBF->nFields+1);
|
|
1508
|
+
|
|
1509
|
+
newDBF->panFieldOffset = (int *) malloc ( sizeof(int) * psDBF->nFields );
|
|
1510
|
+
memcpy ( newDBF->panFieldOffset, psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
|
|
1511
|
+
newDBF->panFieldSize = (int *) malloc ( sizeof(int) * psDBF->nFields );
|
|
1512
|
+
memcpy ( newDBF->panFieldSize, psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
|
|
1513
|
+
newDBF->panFieldDecimals = (int *) malloc ( sizeof(int) * psDBF->nFields );
|
|
1514
|
+
memcpy ( newDBF->panFieldDecimals, psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
|
|
1515
|
+
newDBF->pachFieldType = (char *) malloc ( sizeof(int) * psDBF->nFields );
|
|
1516
|
+
memcpy ( newDBF->pachFieldType, psDBF->pachFieldType, sizeof(int) * psDBF->nFields );
|
|
1517
|
+
|
|
1518
|
+
newDBF->bNoHeader = TRUE;
|
|
1519
|
+
newDBF->bUpdated = TRUE;
|
|
1520
|
+
|
|
1521
|
+
DBFWriteHeader ( newDBF );
|
|
1522
|
+
DBFClose ( newDBF );
|
|
1523
|
+
|
|
1524
|
+
newDBF = DBFOpen ( pszFilename, "rb+" );
|
|
1525
|
+
|
|
1526
|
+
return ( newDBF );
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1529
|
+
/************************************************************************/
|
|
1530
|
+
/* DBFGetNativeFieldType() */
|
|
1531
|
+
/* */
|
|
1532
|
+
/* Return the DBase field type for the specified field. */
|
|
1533
|
+
/* */
|
|
1534
|
+
/* Value can be one of: 'C' (String), 'D' (Date), 'F' (Float), */
|
|
1535
|
+
/* 'N' (Numeric, with or without decimal), */
|
|
1536
|
+
/* 'L' (Logical), */
|
|
1537
|
+
/* 'M' (Memo: 10 digits .DBT block ptr) */
|
|
1538
|
+
/************************************************************************/
|
|
1539
|
+
|
|
1540
|
+
char SHPAPI_CALL
|
|
1541
|
+
DBFGetNativeFieldType( DBFHandle psDBF, int iField )
|
|
1542
|
+
|
|
1543
|
+
{
|
|
1544
|
+
if( iField >=0 && iField < psDBF->nFields )
|
|
1545
|
+
return psDBF->pachFieldType[iField];
|
|
1546
|
+
|
|
1547
|
+
return ' ';
|
|
1548
|
+
}
|
|
1549
|
+
|
|
1550
|
+
/************************************************************************/
|
|
1551
|
+
/* str_to_upper() */
|
|
1552
|
+
/************************************************************************/
|
|
1553
|
+
|
|
1554
|
+
static void str_to_upper (char *string)
|
|
1555
|
+
{
|
|
1556
|
+
int len;
|
|
1557
|
+
short i = -1;
|
|
1558
|
+
|
|
1559
|
+
len = strlen (string);
|
|
1560
|
+
|
|
1561
|
+
while (++i < len)
|
|
1562
|
+
if (isalpha(string[i]) && islower(string[i]))
|
|
1563
|
+
string[i] = (char) toupper ((int)string[i]);
|
|
1564
|
+
}
|
|
1565
|
+
|
|
1566
|
+
/************************************************************************/
|
|
1567
|
+
/* DBFGetFieldIndex() */
|
|
1568
|
+
/* */
|
|
1569
|
+
/* Get the index number for a field in a .dbf file. */
|
|
1570
|
+
/* */
|
|
1571
|
+
/* Contributed by Jim Matthews. */
|
|
1572
|
+
/************************************************************************/
|
|
1573
|
+
|
|
1574
|
+
int SHPAPI_CALL
|
|
1575
|
+
DBFGetFieldIndex(DBFHandle psDBF, const char *pszFieldName)
|
|
1576
|
+
|
|
1577
|
+
{
|
|
1578
|
+
char name[12], name1[12], name2[12];
|
|
1579
|
+
int i;
|
|
1580
|
+
|
|
1581
|
+
strncpy(name1, pszFieldName,11);
|
|
1582
|
+
name1[11] = '\0';
|
|
1583
|
+
str_to_upper(name1);
|
|
1584
|
+
|
|
1585
|
+
for( i = 0; i < DBFGetFieldCount(psDBF); i++ )
|
|
1586
|
+
{
|
|
1587
|
+
DBFGetFieldInfo( psDBF, i, name, NULL, NULL );
|
|
1588
|
+
strncpy(name2,name,11);
|
|
1589
|
+
str_to_upper(name2);
|
|
1590
|
+
|
|
1591
|
+
if(!strncmp(name1,name2,10))
|
|
1592
|
+
return(i);
|
|
1593
|
+
}
|
|
1594
|
+
return(-1);
|
|
1595
|
+
}
|