shapelib 0.7.0 → 0.8.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.
@@ -3,35 +3,72 @@
3
3
  */
4
4
  #define NUM2DBLo(val) (NIL_P((val)) ? 0.0 : NUM2DBL((val)))
5
5
 
6
- static int *IntPack(VALUE array, int decode_p)
6
+ struct shape_wrap_args {
7
+ VALUE klass;
8
+ shape_t *shape;
9
+ };
10
+
11
+ static VALUE WrapShapeProtected(VALUE ptr)
12
+ {
13
+ struct shape_wrap_args *args = (struct shape_wrap_args *)ptr;
14
+ return TypedData_Wrap_Struct(args->klass, &shape_data_type, args->shape);
15
+ }
16
+
17
+ static VALUE WrapShape(VALUE klass, shape_t *shape)
18
+ {
19
+ struct shape_wrap_args args = { klass, shape };
20
+ int state;
21
+ VALUE obj;
22
+ if (shape == NULL)
23
+ rb_raise(rb_eRuntimeError, "SHPCreateObject fails");
24
+ obj = rb_protect(WrapShapeProtected, (VALUE)&args, &state);
25
+ if (state) {
26
+ shape_close(shape);
27
+ rb_jump_tag(state);
28
+ }
29
+ return obj;
30
+ }
31
+
32
+ static void CheckPartStarts(SHPObject *obj)
7
33
  {
8
- int *buf;
9
34
  int i;
35
+ for (i = 0; i < obj->nParts; i++) {
36
+ if (obj->panPartStart[i] < 0 || obj->panPartStart[i] > obj->nVertices)
37
+ rb_raise(rb_eArgError, "part_start[%d] must be between 0 and %d", i, obj->nVertices);
38
+ }
39
+ }
40
+
41
+ static void CheckPointVertices(SHPObject *obj)
42
+ {
43
+ if (obj->nVertices < 1)
44
+ rb_raise(rb_eArgError, "point has no vertices");
45
+ }
46
+
47
+ static void IntPack(VALUE array, int decode_p, int *buf)
48
+ {
49
+ long i, length;
10
50
  Check_Type(array, T_ARRAY);
11
- buf = xmalloc(sizeof(int) * RARRAY_LEN(array));
12
- for (i = 0; i < RARRAY_LEN(array); i++) {
51
+ length = RARRAY_LEN(array);
52
+ for (i = 0; i < length; i++) {
13
53
  if (decode_p)
14
54
  buf[i] = Ruby2PartType(RARRAY_PTR(array)[i]);
15
55
  else
16
56
  buf[i] = NUM2INT(RARRAY_PTR(array)[i]);
17
57
  }
18
- return buf;
19
58
  }
20
59
 
21
- static double *DoublePack(VALUE array, double nilval)
60
+ static void DoublePack(VALUE array, double nilval, double *buf)
22
61
  {
23
- double *buf;
24
- int i;
62
+ long i, length;
25
63
  if (NIL_P(array))
26
- return NULL;
64
+ return;
27
65
  Check_Type(array, T_ARRAY);
28
- buf = xmalloc(sizeof(double) * RARRAY_LEN(array));
29
- for (i = 0; i < RARRAY_LEN(array); i++) {
66
+ length = RARRAY_LEN(array);
67
+ for (i = 0; i < length; i++) {
30
68
  VALUE v;
31
69
  v = RARRAY_PTR(array)[i];
32
70
  buf[i] = (NIL_P(v) ? nilval : NUM2DBL(RARRAY_PTR(array)[i]));
33
71
  }
34
- return buf;
35
72
  }
36
73
 
37
74
  static VALUE HashDeref(VALUE hash, const char *key)
@@ -42,12 +79,19 @@ static VALUE HashDeref(VALUE hash, const char *key)
42
79
  static ID op = 0;
43
80
  if (op == 0)
44
81
  op = rb_intern("[]");
45
- return rb_funcall(hash, op, CSTR2SYM(key));
82
+ return rb_funcall(hash, op, 1, CSTR2SYM(key));
46
83
  }
47
84
  }
48
85
 
49
86
  static VALUE sp_field_set(VALUE obj, VALUE name, VALUE val);
50
87
 
88
+ static void CheckArrayLength(VALUE array, int count, const char *name)
89
+ {
90
+ Check_Type(array, T_ARRAY);
91
+ if (RARRAY_LEN(array) < count)
92
+ rb_raise(rb_eArgError, "%s must contain at least %d entries", name, count);
93
+ }
94
+
51
95
  static void HashLoadAttrib(VALUE vshape, VALUE hash)
52
96
  {
53
97
  VALUE ary, *argv;
@@ -79,6 +123,10 @@ static VALUE sp_s_new(VALUE klass, VALUE hash)
79
123
  {
80
124
  shape_t *shape;
81
125
  VALUE qlass, vshape;
126
+ VALUE arrays[6];
127
+ VALUE storage[6] = { 0 };
128
+ static const char *array_names[] = { "part_type", "part_start", "xvals", "yvals", "zvals", "mvals" };
129
+ int i;
82
130
  int shape_type, shape_id, n_parts, n_vertices;
83
131
  int *part_type, *part_start;
84
132
  double *xvals, *yvals, *zvals, *mvals;
@@ -87,43 +135,72 @@ static VALUE sp_s_new(VALUE klass, VALUE hash)
87
135
  shape_id = NUM2INT_nil(HashDeref(hash, "shape_id"));
88
136
  n_parts = NUM2INT(HashDeref(hash, "n_parts"));
89
137
  n_vertices = NUM2INT(HashDeref(hash, "n_vertices"));
90
- part_type = IntPack(HashDeref(hash, "part_type"), 1);
91
- part_start = IntPack(HashDeref(hash, "part_start"), 0);
92
- xvals = DoublePack(HashDeref(hash, "xvals"), 0.0);
93
- yvals = DoublePack(HashDeref(hash, "yvals"), 0.0);
94
- zvals = DoublePack(HashDeref(hash, "zvals"), 0.0);
95
- mvals = DoublePack(HashDeref(hash, "mvals"), SHP_NODATA);
96
- if (zvals == NULL) rb_raise(rb_eRuntimeError, "missing zvals");
97
- if (mvals == NULL) rb_raise(rb_eRuntimeError, "missing mvals");
98
- shape = shape_new(shape_type, shape_id,
99
- n_parts, part_type, part_start, n_vertices,
100
- xvals, yvals, zvals, mvals);
101
- if (shape == NULL) rb_raise(rb_eRuntimeError, "SHPCreateObject fails");
102
- free(part_type);
103
- free(part_start);
104
- if (xvals) free(xvals);
105
- if (yvals) free(yvals);
106
- if (zvals) free(zvals);
107
- if (mvals) free(mvals);
108
- vshape = Data_Wrap_Struct(qlass, 0, shape_close, shape);
138
+ if (n_parts < 0) rb_raise(rb_eArgError, "n_parts must be nonnegative");
139
+ if (n_vertices < 0) rb_raise(rb_eArgError, "n_vertices must be nonnegative");
140
+ for (i = 0; i < 6; i++)
141
+ arrays[i] = HashDeref(hash, array_names[i]);
142
+ /* Numeric conversion can mutate any of the caller's arrays. */
143
+ for (i = 0; i < 6; i++) {
144
+ if (i < 2 && n_parts == 0 && NIL_P(arrays[i]))
145
+ arrays[i] = rb_ary_new();
146
+ if (!NIL_P(arrays[i])) {
147
+ Check_Type(arrays[i], T_ARRAY);
148
+ arrays[i] = rb_ary_dup(arrays[i]);
149
+ }
150
+ }
151
+ for (i = 0; i < 6; i++) {
152
+ if (i < 2 || !NIL_P(arrays[i]))
153
+ CheckArrayLength(arrays[i], i < 2 ? n_parts : n_vertices, array_names[i]);
154
+ }
155
+ if (NIL_P(arrays[4])) rb_raise(rb_eRuntimeError, "missing zvals");
156
+ if (NIL_P(arrays[5])) rb_raise(rb_eRuntimeError, "missing mvals");
157
+ /* Allocate here: ALLOCV_N may use this constructor's stack frame. */
158
+ part_type = ALLOCV_N(int, storage[0], RARRAY_LEN(arrays[0]));
159
+ IntPack(arrays[0], 1, part_type);
160
+ part_start = ALLOCV_N(int, storage[1], RARRAY_LEN(arrays[1]));
161
+ IntPack(arrays[1], 0, part_start);
162
+ xvals = NIL_P(arrays[2]) ? NULL : ALLOCV_N(double, storage[2], RARRAY_LEN(arrays[2]));
163
+ DoublePack(arrays[2], 0.0, xvals);
164
+ yvals = NIL_P(arrays[3]) ? NULL : ALLOCV_N(double, storage[3], RARRAY_LEN(arrays[3]));
165
+ DoublePack(arrays[3], 0.0, yvals);
166
+ zvals = ALLOCV_N(double, storage[4], RARRAY_LEN(arrays[4]));
167
+ DoublePack(arrays[4], 0.0, zvals);
168
+ mvals = ALLOCV_N(double, storage[5], RARRAY_LEN(arrays[5]));
169
+ DoublePack(arrays[5], SHP_NODATA, mvals);
170
+ shape = shape_new(shape_type, shape_id, n_parts, part_type, part_start, n_vertices, xvals, yvals, zvals, mvals);
171
+ for (i = 0; i < 6; i++) {
172
+ ALLOCV_END(storage[i]);
173
+ RB_GC_GUARD(arrays[i]);
174
+ }
175
+ vshape = WrapShape(qlass, shape);
176
+ CheckPartStarts(shape->obj);
109
177
  HashLoadAttrib(vshape, hash);
110
178
  return vshape;
111
179
  }
112
180
 
113
- static int CheckPartSize(int argc, VALUE *argv, int *part_start,
114
- int *part_type)
181
+ /* Snapshot all coordinate arrays before any numeric conversion can mutate them. */
182
+ static VALUE SnapshotPoints(VALUE points)
183
+ {
184
+ VALUE snapshot = rb_ary_dup(points);
185
+ long i;
186
+ for (i = 0; i < RARRAY_LEN(snapshot); i++) {
187
+ VALUE point = rb_ary_entry(snapshot, i);
188
+ if (T_ARRAY == TYPE(point))
189
+ rb_ary_store(snapshot, i, rb_ary_dup(point));
190
+ }
191
+ return snapshot;
192
+ }
193
+
194
+ static int CheckPartSize(VALUE parts, int *part_start, int *part_type)
115
195
  {
116
196
  int pstart = 0;
117
197
  int i;
118
- for (i = 0; i < argc; i++) {
198
+ for (i = 0; i < RARRAY_LEN(parts); i++) {
199
+ VALUE part = rb_ary_entry(parts, i);
119
200
  VALUE first;
120
201
  int partlen;
121
- if (T_ARRAY != TYPE(argv[i])) {
122
- rb_raise(rb_eArgError, "arg %d must be Array", i);
123
- return -1;
124
- }
125
- partlen = RARRAY_LEN(argv[i]);
126
- first = RARRAY_PTR(argv[i])[0];
202
+ partlen = RARRAY_LEN(part);
203
+ first = rb_ary_entry(part, 0);
127
204
  switch (TYPE(first)) {
128
205
  case T_SYMBOL: case T_STRING:
129
206
  part_type[i] = Ruby2PartType(first);
@@ -140,8 +217,7 @@ static int CheckPartSize(int argc, VALUE *argv, int *part_start,
140
217
  return pstart;
141
218
  }
142
219
 
143
- static void ExtractXYMZ(VALUE v,
144
- double *x, double *y, double *m, double *z)
220
+ static void ExtractXYMZ(VALUE v, double *x, double *y, double *m, double *z)
145
221
  {
146
222
  static int idx = 0, idy, idz, idm;
147
223
  if (idx == 0) {
@@ -150,11 +226,10 @@ static void ExtractXYMZ(VALUE v,
150
226
  }
151
227
  if (T_ARRAY == TYPE(v)) {
152
228
  int argc = RARRAY_LEN(v);
153
- VALUE *argv = RARRAY_PTR(v);
154
- *x = (argc > 0) ? NUM2DBLo(argv[0]) : 0.0;
155
- *y = (argc > 1) ? NUM2DBLo(argv[1]) : 0.0;
156
- *m = SHP_NUM2DBL((argc > 2) ? argv[2] : Qnil);
157
- *z = (argc > 3) ? NUM2DBL(argv[3]) : 0.0;
229
+ *x = (argc > 0) ? NUM2DBLo(rb_ary_entry(v, 0)) : 0.0;
230
+ *y = (argc > 1) ? NUM2DBLo(rb_ary_entry(v, 1)) : 0.0;
231
+ *m = SHP_NUM2DBL((argc > 2) ? rb_ary_entry(v, 2) : Qnil);
232
+ *z = (argc > 3) ? NUM2DBL(rb_ary_entry(v, 3)) : 0.0;
158
233
  } else {
159
234
  *x = NUM2DBLo(rb_funcall(v, idx, 0));
160
235
  *y = NUM2DBLo(rb_funcall(v, idy, 0));
@@ -171,78 +246,92 @@ static void ExtractXYMZ(VALUE v,
171
246
  }
172
247
  }
173
248
 
174
- static void CollectPoints(int argc, const VALUE *argv,
175
- double *x, double *y, double *m, double *z)
249
+ static void CollectPoints(VALUE points, double *x, double *y, double *m, double *z)
176
250
  {
177
251
  int i, ofs;
252
+ int argc = RARRAY_LEN(points);
178
253
  ofs = 0;
179
254
  if (argc > 0) {
180
- switch (TYPE(argv[0])) {
255
+ switch (TYPE(rb_ary_entry(points, 0))) {
181
256
  case T_SYMBOL: case T_STRING:
182
257
  ofs++;
183
258
  }
184
259
  }
185
260
  for (i = 0; i < argc - ofs; i++) {
186
- ExtractXYMZ(argv[i + ofs], x + i, y + i, m + i, z + i);
261
+ ExtractXYMZ(rb_ary_entry(points, i + ofs), x + i, y + i, m + i, z + i);
187
262
  }
188
263
  }
189
264
 
190
265
  static shape_t *NewMultiPart(int argc, VALUE *argv, VALUE klass, int shapetype)
191
266
  {
192
267
  shape_t *shape;
268
+ VALUE parts = rb_ary_new4(argc, argv);
269
+ VALUE part_start_storage = 0, part_type_storage = 0, dblock_storage = 0;
193
270
  double *dblock, *x, *y, *m, *z;
194
271
  int *part_start, *part_type;
195
272
  int n_parts, n_vert;
196
273
  int ipart;
197
274
 
275
+ for (ipart = 0; ipart < argc; ipart++) {
276
+ VALUE part = rb_ary_entry(parts, ipart);
277
+ if (T_ARRAY != TYPE(part))
278
+ rb_raise(rb_eArgError, "arg %d must be Array", ipart);
279
+ if (RARRAY_LEN(part) == 0)
280
+ rb_raise(rb_eArgError, "part %d must not be empty", ipart);
281
+ rb_ary_store(parts, ipart, SnapshotPoints(part));
282
+ }
198
283
  n_parts = argc;
199
- part_start = xmalloc(sizeof(int) * n_parts);
200
- part_type = xmalloc(sizeof(int) * n_parts);
201
- n_vert = CheckPartSize(argc, argv, part_start, part_type);
202
- dblock = xmalloc(sizeof(double) * n_vert * 4);
284
+ part_start = ALLOCV_N(int, part_start_storage, n_parts);
285
+ part_type = ALLOCV_N(int, part_type_storage, n_parts);
286
+ n_vert = CheckPartSize(parts, part_start, part_type);
287
+ dblock = ALLOCV_N(double, dblock_storage, (size_t)n_vert * 4);
203
288
  x = dblock;
204
289
  y = dblock + n_vert;
205
290
  m = dblock + n_vert * 2;
206
291
  z = dblock + n_vert * 3;
207
292
  for (ipart = 0; ipart < argc; ipart++) {
208
293
  CollectPoints(
209
- RARRAY_LEN(argv[ipart]), RARRAY_PTR(argv[ipart]),
294
+ rb_ary_entry(parts, ipart),
210
295
  x + part_start[ipart], y + part_start[ipart],
211
296
  m + part_start[ipart], z + part_start[ipart]);
212
297
  }
213
298
  shape = shape_new_obj(shapetype,
214
299
  n_parts, part_start, part_type, n_vert,
215
300
  x, y, m, z);
216
- free(dblock);
217
- free(part_start);
218
- free(part_type);
301
+ ALLOCV_END(dblock_storage);
302
+ ALLOCV_END(part_start_storage);
303
+ ALLOCV_END(part_type_storage);
304
+ RB_GC_GUARD(parts);
219
305
  return shape;
220
306
  }
221
307
 
222
308
  static shape_t *NewSinglePart(int argc, VALUE *argv, VALUE klass, int shapetype)
223
309
  {
224
310
  shape_t *shape;
311
+ VALUE points = SnapshotPoints(rb_ary_new4(argc, argv));
312
+ VALUE storage = 0;
225
313
  double *dblock, *x, *y, *m, *z;
226
314
  int n_vert, part_type_buf;
227
315
  int part_start_buf = 0;
228
316
  n_vert = argc;
229
- switch (TYPE(argv[0])) {
317
+ switch (TYPE(rb_ary_entry(points, 0))) {
230
318
  case T_STRING: case T_SYMBOL:
231
- part_type_buf = Ruby2PartType(argv[0]);
319
+ part_type_buf = Ruby2PartType(rb_ary_entry(points, 0));
232
320
  n_vert--;
233
321
  break;
234
322
  default:
235
323
  part_type_buf = SHPP_RING;
236
324
  }
237
- dblock = xmalloc(sizeof(double) * n_vert * 4);
325
+ dblock = ALLOCV_N(double, storage, (size_t)n_vert * 4);
238
326
  x = dblock;
239
327
  y = dblock + n_vert;
240
328
  m = dblock + n_vert * 2;
241
329
  z = dblock + n_vert * 3;
242
- CollectPoints(argc, argv, x, y, m, z);
330
+ CollectPoints(points, x, y, m, z);
243
331
  shape = shape_new_obj(shapetype,
244
332
  1, &part_start_buf, &part_type_buf, n_vert, x, y, m, z);
245
- free(dblock);
333
+ ALLOCV_END(storage);
334
+ RB_GC_GUARD(points);
246
335
  return shape;
247
336
  }
248
337
 
@@ -262,16 +351,13 @@ static VALUE NewShape(int argc, VALUE *argv, VALUE klass, int shapetype)
262
351
  shape_t *shape;
263
352
  int multipart;
264
353
  monitor(("NewShape"));
354
+ if (argc == 0)
355
+ rb_raise(rb_eArgError, "at least one point is required");
265
356
  if (T_ARRAY == TYPE(argv[0])) {
266
- switch (TYPE( RARRAY_PTR(argv[0])[0] )) {
267
- case T_FIXNUM:
268
- case T_FLOAT:
269
- multipart = 0;
270
- break;
271
- default:
272
- multipart = 1;
273
- break;
274
- }
357
+ VALUE first = rb_ary_entry(argv[0], 0);
358
+ if (RARRAY_LEN(argv[0]) == 0)
359
+ rb_raise(rb_eArgError, "first geometry array must not be empty");
360
+ multipart = !(RB_INTEGER_TYPE_P(first) || RB_TYPE_P(first, T_FLOAT));
275
361
  } else {
276
362
  multipart = 0;
277
363
  }
@@ -280,27 +366,42 @@ static VALUE NewShape(int argc, VALUE *argv, VALUE klass, int shapetype)
280
366
  } else {
281
367
  shape = NewSinglePart(argc, argv, klass, shapetype);
282
368
  }
283
- return Data_Wrap_Struct(klass, 0, shape_close, shape);
369
+ return WrapShape(klass, shape);
284
370
  }
285
371
 
286
372
  static VALUE MultiPointNew(int argc, VALUE *argv, VALUE klass, int shapetype)
287
373
  {
288
374
  shape_t *shape;
375
+ VALUE points = SnapshotPoints(rb_ary_new4(argc, argv));
376
+ VALUE storage = 0;
289
377
  double *dblock, *x, *y, *m, *z;
290
378
  int *part_start;
291
379
  int n_vert;
292
380
  int part_start_buf = 0;
381
+ if (argc == 1 && TYPE(rb_ary_entry(points, 0)) == T_ARRAY) {
382
+ /* Snapshot nested coordinates before point detection can invoke Ruby. */
383
+ VALUE candidate = SnapshotPoints(rb_ary_entry(points, 0));
384
+ VALUE first = rb_ary_entry(candidate, 0);
385
+ if (RARRAY_LEN(candidate) > 0 &&
386
+ (TYPE(first) == T_ARRAY ||
387
+ (rb_respond_to(first, rb_intern("x")) && rb_respond_to(first, rb_intern("y")))))
388
+ points = candidate;
389
+ RB_GC_GUARD(candidate);
390
+ }
391
+ if (TYPE(rb_ary_entry(points, 0)) == T_STRING || TYPE(rb_ary_entry(points, 0)) == T_SYMBOL)
392
+ rb_raise(rb_eArgError, "MultiPoint does not accept part type labels");
293
393
  part_start = &part_start_buf;
294
- n_vert = argc;
295
- dblock = malloc(sizeof(double) * n_vert * 4);
394
+ n_vert = RARRAY_LEN(points);
395
+ dblock = ALLOCV_N(double, storage, (size_t)n_vert * 4);
296
396
  x = dblock;
297
397
  y = dblock + n_vert;
298
398
  m = dblock + n_vert * 2;
299
399
  z = dblock + n_vert * 3;
300
- CollectPoints(argc, argv, x, y, m, z);
400
+ CollectPoints(points, x, y, m, z);
301
401
  shape = shape_new_obj(shapetype, 1, part_start, NULL, n_vert, x, y, m, z);
302
- free(dblock);
303
- return Data_Wrap_Struct(klass, 0, shape_close, shape);
402
+ ALLOCV_END(storage);
403
+ RB_GC_GUARD(points);
404
+ return WrapShape(klass, shape);
304
405
  }
305
406
 
306
407
  static VALUE arc_s_new(int argc, VALUE *argv, VALUE klass) {
@@ -346,22 +447,21 @@ static VALUE mpz_s_new(int argc, VALUE *argv, VALUE klass) {
346
447
 
347
448
  static void PointAddAttr(VALUE pt, VALUE attrs)
348
449
  {
349
- VALUE *argv;
350
450
  VALUE ary;
351
451
  int i, argc;
352
452
  Check_Type(attrs, T_HASH);
353
453
  ary = rb_funcall(attrs, rb_intern("to_a"), 0);
354
454
  Check_Type(ary, T_ARRAY);
355
- argv = RARRAY_PTR(ary);
455
+ ary = SnapshotPoints(ary);
356
456
  argc = RARRAY_LEN(ary);
357
457
  for (i = 0; i < argc; i++) {
358
- VALUE *pair;
359
- Check_Type(argv[i], T_ARRAY);
360
- if (RARRAY_LEN(argv[i]) != 2)
361
- rb_bug("hash.to_a member has weird size");
362
- pair = RARRAY_PTR(argv[i]);
363
- sp_field_set(pt, pair[0], pair[1]);
458
+ VALUE pair = rb_ary_entry(ary, i);
459
+ Check_Type(pair, T_ARRAY);
460
+ if (RARRAY_LEN(pair) != 2)
461
+ rb_raise(rb_eArgError, "attribute pair must contain exactly two entries");
462
+ sp_field_set(pt, rb_ary_entry(pair, 0), rb_ary_entry(pair, 1));
364
463
  }
464
+ RB_GC_GUARD(ary);
365
465
  }
366
466
 
367
467
 
@@ -372,7 +472,7 @@ static VALUE pt_s_new(int argc, VALUE *argv, VALUE klass)
372
472
  rb_scan_args(argc, argv, "21", &vx, &vy, &attrs);
373
473
  shape = shape_new_point(SHPT_POINT,
374
474
  NUM2DBLo(vx), NUM2DBLo(vy), 0.0, 0.0);
375
- pt = Data_Wrap_Struct(klass, 0, shape_close, shape);
475
+ pt = WrapShape(klass, shape);
376
476
  if (!NIL_P(attrs)) {
377
477
  PointAddAttr(pt, attrs);
378
478
  }
@@ -386,7 +486,7 @@ static VALUE ptm_s_new(int argc, VALUE *argv, VALUE klass)
386
486
  rb_scan_args(argc, argv, "31", &vx, &vy, &vm, &attrs);
387
487
  shape = shape_new_point(SHPT_POINTM,
388
488
  NUM2DBLo(vx), NUM2DBLo(vy), SHP_NUM2DBL(vm), 0.0);
389
- pt = Data_Wrap_Struct(klass, 0, shape_close, shape);
489
+ pt = WrapShape(klass, shape);
390
490
  if (!NIL_P(attrs)) {
391
491
  PointAddAttr(pt, attrs);
392
492
  }
@@ -400,25 +500,25 @@ static VALUE ptz_s_new(int argc, VALUE *argv, VALUE klass)
400
500
  rb_scan_args(argc, argv, "41", &vx, &vy, &vm, &vz, &attrs);
401
501
  shape = shape_new_point(SHPT_POINTZ,
402
502
  NUM2DBLo(vx), NUM2DBLo(vy), SHP_NUM2DBL(vm), NUM2DBLo(vz));
403
- pt = Data_Wrap_Struct(klass, 0, shape_close, shape);
503
+ pt = WrapShape(klass, shape);
404
504
  if (!NIL_P(attrs)) {
405
505
  PointAddAttr(pt, attrs);
406
506
  }
407
507
  return pt;
408
508
  }
409
509
 
410
- /* ShapeLib.new_point */
510
+ /* Shapelib.new_point */
411
511
  static VALUE sl_m_new_point(int argc, VALUE *argv, VALUE klass)
412
512
  {
413
513
  if (2 == argc || (3 == argc && T_HASH == TYPE(argv[2]))) {
414
514
  return pt_s_new(argc, argv, cPoint);
415
- } else if (3 == argc || (4 == argc && T_HASH != TYPE(argv[3]))) {
515
+ } else if (3 == argc || (4 == argc && (T_HASH == TYPE(argv[3]) || NIL_P(argv[3])))) {
416
516
  return ptm_s_new(argc, argv, cPointM);
417
- } else if (4 == argc || (5 == argc && T_HASH != TYPE(argv[4]))) {
517
+ } else if (4 == argc || 5 == argc) {
418
518
  return ptz_s_new(argc, argv, cPointZ);
419
519
  } else {
420
520
  rb_raise(rb_eArgError,
421
- "usage: ShapeLib::Shape.new_point x, y, m, z, attr_array");
521
+ "usage: Shapelib.new_point x, y, m, z, attr_array");
422
522
  return Qnil;
423
523
  }
424
524
  }
@@ -431,7 +531,7 @@ static void Attr_to_Hash(VALUE h, VALUE obj)
431
531
  {
432
532
  shape_t *self;
433
533
  int i;
434
- Data_Get_Struct(obj, shape_t, self);
534
+ TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
435
535
  if (self->nattr <= 0)
436
536
  return;
437
537
  for (i = 0; i < self->nattr; i++) {
@@ -466,8 +566,8 @@ static VALUE sp_field_get(VALUE obj, VALUE name)
466
566
  char *cname;
467
567
  int ofs;
468
568
 
469
- Data_Get_Struct(obj, shape_t, self);
470
- cname = StringValuePtr(name);
569
+ TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
570
+ cname = StringValueCStr(name);
471
571
  ofs = shape_attrib_index(self, cname, 0);
472
572
  if (ofs < 0) {
473
573
  return Qnil;
@@ -481,6 +581,9 @@ static VALUE sp_field_get(VALUE obj, VALUE name)
481
581
  return rb_float_new(self->attr[ofs].val.fval);
482
582
  case FTString:
483
583
  case FTLogical:
584
+ #ifdef HAVE_CONST_FTDATE
585
+ case FTDate:
586
+ #endif
484
587
  return rb_str_new2(self->attr[ofs].val.sval);
485
588
  default:
486
589
  rb_raise(rb_eTypeError, "unacceptable field type");
@@ -491,35 +594,42 @@ static VALUE sp_field_get(VALUE obj, VALUE name)
491
594
  static VALUE sp_field_set(VALUE obj, VALUE name, VALUE val)
492
595
  {
493
596
  shape_t *self;
597
+ attrib_t replacement;
494
598
  char *cname;
495
599
  int ofs;
496
600
 
497
- Data_Get_Struct(obj, shape_t, self);
498
- cname = StringValuePtr(name);
601
+ TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
602
+ rb_check_frozen(obj);
603
+ cname = StringValueCStr(name);
604
+ rb_check_frozen(obj);
499
605
  ofs = shape_attrib_index(self, cname, 1);
500
606
  if (ofs < 0) {
501
607
  return Qnil;
502
608
  }
609
+ memset(&replacement.val, 0, sizeof(replacement.val));
503
610
  switch (TYPE(val)) {
504
611
  case T_STRING:
505
- self->attr[ofs].type = FTString;
506
- self->attr[ofs].val.sval = StringDup(StringValuePtr(val));
612
+ replacement.type = FTString;
613
+ replacement.val.sval = StringDup(StringValueCStr(val));
507
614
  break;
508
615
  case T_FIXNUM:
509
- self->attr[ofs].type = FTInteger;
510
- self->attr[ofs].val.ival = FIX2INT(val);
616
+ replacement.type = FTInteger;
617
+ replacement.val.ival = FIX2INT(val);
511
618
  break;
512
619
  case T_FLOAT:
513
- self->attr[ofs].type = FTDouble;
514
- self->attr[ofs].val.fval = RFLOAT_VALUE(val);
620
+ replacement.type = FTDouble;
621
+ replacement.val.fval = RFLOAT_VALUE(val);
515
622
  break;
516
623
  case T_NIL:
517
- self->attr[ofs].type = -1;
624
+ replacement.type = -1;
518
625
  break;
519
626
  default:
520
627
  rb_raise(rb_eTypeError,
521
628
  "give me String, Integer, or Float");
522
629
  }
630
+ shape_attrib_clear_value(&self->attr[ofs]);
631
+ self->attr[ofs].type = replacement.type;
632
+ self->attr[ofs].val = replacement.val;
523
633
  return obj;
524
634
  }
525
635
 
@@ -527,7 +637,7 @@ static VALUE sp_maxbound(VALUE obj)
527
637
  {
528
638
  shape_t *self;
529
639
  double buf[4];
530
- Data_Get_Struct(obj, shape_t, self);
640
+ TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
531
641
  buf[0] = self->obj->dfXMax;
532
642
  buf[1] = self->obj->dfYMax;
533
643
  buf[2] = self->obj->dfMMax;
@@ -539,7 +649,7 @@ static VALUE sp_minbound(VALUE obj)
539
649
  {
540
650
  shape_t *self;
541
651
  double buf[4];
542
- Data_Get_Struct(obj, shape_t, self);
652
+ TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
543
653
  buf[0] = self->obj->dfXMin;
544
654
  buf[1] = self->obj->dfYMin;
545
655
  buf[2] = self->obj->dfMMin;
@@ -550,28 +660,28 @@ static VALUE sp_minbound(VALUE obj)
550
660
  static VALUE sp_mvals(VALUE obj)
551
661
  {
552
662
  shape_t *self;
553
- Data_Get_Struct(obj, shape_t, self);
663
+ TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
554
664
  return DoubleUnpackM(self->obj->padfM, self->obj->nVertices, -1);
555
665
  }
556
666
 
557
667
  static VALUE sp_n_parts(VALUE obj)
558
668
  {
559
669
  shape_t *self;
560
- Data_Get_Struct(obj, shape_t, self);
670
+ TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
561
671
  return INT2NUM(self->obj->nParts);
562
672
  }
563
673
 
564
674
  static VALUE sp_n_vertices(VALUE obj)
565
675
  {
566
676
  shape_t *self;
567
- Data_Get_Struct(obj, shape_t, self);
677
+ TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
568
678
  return INT2NUM(self->obj->nVertices);
569
679
  }
570
680
 
571
681
  static VALUE sp_part_start(VALUE obj)
572
682
  {
573
683
  shape_t *self;
574
- Data_Get_Struct(obj, shape_t, self);
684
+ TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
575
685
  if (self->obj->nParts == 0)
576
686
  return Qnil;
577
687
  return IntUnpack(self->obj->panPartStart, self->obj->nParts);
@@ -582,7 +692,7 @@ static VALUE sp_part_type(VALUE obj)
582
692
  shape_t *self;
583
693
  VALUE ary;
584
694
  int i;
585
- Data_Get_Struct(obj, shape_t, self);
695
+ TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
586
696
  if (self->obj->nParts == 0)
587
697
  return Qnil;
588
698
  #if 0
@@ -598,42 +708,47 @@ static VALUE sp_part_type(VALUE obj)
598
708
  static VALUE sp_shape_id(VALUE obj)
599
709
  {
600
710
  shape_t *self;
601
- Data_Get_Struct(obj, shape_t, self);
711
+ TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
602
712
  return (self->obj->nShapeId < 0) ? Qnil : INT2NUM(self->obj->nShapeId);
603
713
  }
604
714
 
605
715
  static VALUE sp_shape_type(VALUE obj)
606
716
  {
607
717
  shape_t *self;
608
- Data_Get_Struct(obj, shape_t, self);
718
+ TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
609
719
  return ShapeType2Ruby(self->obj->nSHPType);
610
720
  }
611
721
 
612
722
  static VALUE sp_rewind(VALUE obj)
613
723
  {
614
724
  shape_t *self;
615
- Data_Get_Struct(obj, shape_t, self);
616
- return SHPRewindObject(NULL, self->obj) ? Qtrue : Qfalse;
725
+ TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
726
+ rb_check_frozen(obj);
727
+ if (SHPRewindObject(NULL, self->obj)) {
728
+ rb_iv_set(obj, "@latlngs", Qnil);
729
+ return Qtrue;
730
+ }
731
+ return Qfalse;
617
732
  }
618
733
 
619
734
  static VALUE sp_xvals(VALUE obj)
620
735
  {
621
736
  shape_t *self;
622
- Data_Get_Struct(obj, shape_t, self);
737
+ TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
623
738
  return DoubleUnpack(self->obj->padfX, self->obj->nVertices);
624
739
  }
625
740
 
626
741
  static VALUE sp_yvals(VALUE obj)
627
742
  {
628
743
  shape_t *self;
629
- Data_Get_Struct(obj, shape_t, self);
744
+ TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
630
745
  return DoubleUnpack(self->obj->padfY, self->obj->nVertices);
631
746
  }
632
747
 
633
748
  static VALUE sp_zvals(VALUE obj)
634
749
  {
635
750
  shape_t *self;
636
- Data_Get_Struct(obj, shape_t, self);
751
+ TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
637
752
  return DoubleUnpack(self->obj->padfZ, self->obj->nVertices);
638
753
  }
639
754
 
@@ -644,11 +759,12 @@ static VALUE sp_zvals(VALUE obj)
644
759
  static VALUE pt_x(VALUE obj)
645
760
  {
646
761
  shape_t *self;
647
- Data_Get_Struct(obj, shape_t, self);
762
+ TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
648
763
  switch (self->obj->nSHPType) {
649
764
  case SHPT_POINT:
650
765
  case SHPT_POINTM:
651
766
  case SHPT_POINTZ:
767
+ CheckPointVertices(self->obj);
652
768
  return rb_float_new(self->obj->padfX[0]);
653
769
  default:
654
770
  rb_bug("shape type %d is not Point", self->obj->nSHPType);
@@ -659,11 +775,12 @@ static VALUE pt_x(VALUE obj)
659
775
  static VALUE pt_y(VALUE obj)
660
776
  {
661
777
  shape_t *self;
662
- Data_Get_Struct(obj, shape_t, self);
778
+ TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
663
779
  switch (self->obj->nSHPType) {
664
780
  case SHPT_POINT:
665
781
  case SHPT_POINTM:
666
782
  case SHPT_POINTZ:
783
+ CheckPointVertices(self->obj);
667
784
  return rb_float_new(self->obj->padfY[0]);
668
785
  default:
669
786
  rb_bug("shape type %d is not Point", self->obj->nSHPType);
@@ -674,10 +791,11 @@ static VALUE pt_y(VALUE obj)
674
791
  static VALUE pt_m(VALUE obj)
675
792
  {
676
793
  shape_t *self;
677
- Data_Get_Struct(obj, shape_t, self);
794
+ TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
678
795
  switch (self->obj->nSHPType) {
679
796
  case SHPT_POINTM:
680
797
  case SHPT_POINTZ:
798
+ CheckPointVertices(self->obj);
681
799
  return SHP_FLOAT_NEW(self->obj->padfM[0]);
682
800
  case SHPT_POINT:
683
801
  return Qnil;
@@ -690,10 +808,11 @@ static VALUE pt_m(VALUE obj)
690
808
  static VALUE pt_z(VALUE obj)
691
809
  {
692
810
  shape_t *self;
693
- Data_Get_Struct(obj, shape_t, self);
811
+ TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
694
812
  switch (self->obj->nSHPType) {
695
813
  case SHPT_POINTZ:
696
- return rb_float_new(self->obj->padfM[0]);
814
+ CheckPointVertices(self->obj);
815
+ return rb_float_new(self->obj->padfZ[0]);
697
816
  case SHPT_POINTM:
698
817
  case SHPT_POINT:
699
818
  return Qnil;