shapelib 0.7.2 → 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 = TypedData_Wrap_Struct(qlass, &shape_data_type, 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 TypedData_Wrap_Struct(klass, &shape_data_type, 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 TypedData_Wrap_Struct(klass, &shape_data_type, 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 = TypedData_Wrap_Struct(klass, &shape_data_type, 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 = TypedData_Wrap_Struct(klass, &shape_data_type, 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 = TypedData_Wrap_Struct(klass, &shape_data_type, 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
  }
@@ -467,7 +567,7 @@ static VALUE sp_field_get(VALUE obj, VALUE name)
467
567
  int ofs;
468
568
 
469
569
  TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
470
- cname = StringValuePtr(name);
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
601
  TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
498
- cname = StringValuePtr(name);
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
 
@@ -613,7 +723,12 @@ static VALUE sp_rewind(VALUE obj)
613
723
  {
614
724
  shape_t *self;
615
725
  TypedData_Get_Struct(obj, shape_t, &shape_data_type, self);
616
- return SHPRewindObject(NULL, self->obj) ? Qtrue : Qfalse;
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)
@@ -649,6 +764,7 @@ static VALUE pt_x(VALUE obj)
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);
@@ -664,6 +780,7 @@ static VALUE pt_y(VALUE obj)
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);
@@ -678,6 +795,7 @@ static VALUE pt_m(VALUE obj)
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;
@@ -693,7 +811,8 @@ static VALUE pt_z(VALUE obj)
693
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;
@@ -22,32 +22,32 @@ static VALUE sp_to_h(VALUE obj)
22
22
  }
23
23
 
24
24
  static method_table_entry sp_methods[] = {
25
- { "[]", sp_field_get, 1 },
26
- { "[]=", sp_field_set, 2 },
27
- { "maxbound", sp_maxbound, 0 },
28
- { "minbound", sp_minbound, 0 },
29
- { "mvals", sp_mvals, 0 },
30
- { "n_parts", sp_n_parts, 0 },
31
- { "n_vertices", sp_n_vertices, 0 },
32
- { "part_start", sp_part_start, 0 },
33
- { "part_type", sp_part_type, 0 },
34
- { "shape_type", sp_shape_type, 0 },
35
- { "shape_id", sp_shape_id, 0 },
36
- { "to_h", sp_to_h, 0 },
37
- { "to_s", sp_wkt, 0 },
38
- { "rewind_polygon", sp_rewind, 0 },
39
- { "wkt", sp_wkt, 0 },
40
- { "xvals", sp_xvals, 0 },
41
- { "yvals", sp_yvals, 0 },
42
- { "zvals", sp_zvals, 0 },
25
+ { "[]", RUBY_METHOD_FUNC(sp_field_get), 1 },
26
+ { "[]=", RUBY_METHOD_FUNC(sp_field_set), 2 },
27
+ { "maxbound", RUBY_METHOD_FUNC(sp_maxbound), 0 },
28
+ { "minbound", RUBY_METHOD_FUNC(sp_minbound), 0 },
29
+ { "mvals", RUBY_METHOD_FUNC(sp_mvals), 0 },
30
+ { "n_parts", RUBY_METHOD_FUNC(sp_n_parts), 0 },
31
+ { "n_vertices", RUBY_METHOD_FUNC(sp_n_vertices), 0 },
32
+ { "part_start", RUBY_METHOD_FUNC(sp_part_start), 0 },
33
+ { "part_type", RUBY_METHOD_FUNC(sp_part_type), 0 },
34
+ { "shape_type", RUBY_METHOD_FUNC(sp_shape_type), 0 },
35
+ { "shape_id", RUBY_METHOD_FUNC(sp_shape_id), 0 },
36
+ { "to_h", RUBY_METHOD_FUNC(sp_to_h), 0 },
37
+ { "to_s", RUBY_METHOD_FUNC(sp_wkt), 0 },
38
+ { "rewind_polygon", RUBY_METHOD_FUNC(sp_rewind), 0 },
39
+ { "wkt", RUBY_METHOD_FUNC(sp_wkt), 0 },
40
+ { "xvals", RUBY_METHOD_FUNC(sp_xvals), 0 },
41
+ { "yvals", RUBY_METHOD_FUNC(sp_yvals), 0 },
42
+ { "zvals", RUBY_METHOD_FUNC(sp_zvals), 0 },
43
43
  { NULL, NULL, 0 }
44
44
  };
45
45
 
46
46
  static method_table_entry pt_methods[] = {
47
- { "m", pt_m, 0 },
48
- { "wkt", pt_wkt, 0 },
49
- { "x", pt_x, 0 },
50
- { "y", pt_y, 0 },
51
- { "z", pt_z, 0 },
47
+ { "m", RUBY_METHOD_FUNC(pt_m), 0 },
48
+ { "wkt", RUBY_METHOD_FUNC(pt_wkt), 0 },
49
+ { "x", RUBY_METHOD_FUNC(pt_x), 0 },
50
+ { "y", RUBY_METHOD_FUNC(pt_y), 0 },
51
+ { "z", RUBY_METHOD_FUNC(pt_z), 0 },
52
52
  { NULL, NULL, 0 }
53
53
  };