Subversion Repositories gelsvn

Rev

Rev 371 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
371 jab 1
/* ----------------------------------------------------------------------
2
 * RPly library, read/write PLY files
3
 * Diego Nehab, Princeton University
4
 * http://www.cs.princeton.edu/~diego/professional/rply
5
 *
6
 * This library is distributed under the MIT License. See notice
7
 * at the end of this file.
8
 * ---------------------------------------------------------------------- */
9
#include <stdio.h>
10
#include <ctype.h>
11
#include <assert.h>
12
#include <string.h>
13
#include <limits.h>
14
#include <float.h>
15
#include <stdarg.h>
16
#include <stdlib.h>
17
#include <stddef.h>
18
 
19
#include "rply.h"
20
 
21
/* ----------------------------------------------------------------------
22
 * Constants 
23
 * ---------------------------------------------------------------------- */
24
#define WORDSIZE 256
25
#define LINESIZE 1024
26
#define BUFFERSIZE (8*1024)
27
 
28
typedef enum e_ply_io_mode_ {
29
    PLY_READ, 
30
    PLY_WRITE
31
} e_ply_io_mode;
32
 
33
static const char *const ply_storage_mode_list[] = {
34
    "binary_big_endian", "binary_little_endian", "ascii", NULL
35
};     /* order matches e_ply_storage_mode enum */
36
 
37
static const char *const ply_type_list[] = {
38
    "int8", "uint8", "int16", "uint16", 
39
    "int32", "uint32", "float32", "float64",
40
    "char", "uchar", "short", "ushort", 
41
    "int", "uint", "float", "double",
42
    "list", NULL
43
};     /* order matches e_ply_type enum */
44
 
45
/* ----------------------------------------------------------------------
46
 * Property reading callback argument
47
 *
48
 * element: name of element being processed
49
 * property: name of property being processed
50
 * nelements: number of elements of this kind in file
51
 * instance_index: index current element of this kind being processed
52
 * length: number of values in current list (or 1 for scalars)
53
 * value_index: index of current value int this list (or 0 for scalars)
54
 * value: value of property
55
 * pdata/idata: user data defined with ply_set_cb
56
 *
57
 * Returns handle to ply file if succesful, NULL otherwise.
58
 * ---------------------------------------------------------------------- */
59
typedef struct t_ply_argument_ {
60
    p_ply_element element;
595 jab 61
    int instance_index;
371 jab 62
    p_ply_property property;
595 jab 63
    int length, value_index;
371 jab 64
    double value;
65
    void *pdata;
595 jab 66
    int idata;
371 jab 67
} t_ply_argument;
68
 
69
/* ----------------------------------------------------------------------
70
 * Property information
71
 *
72
 * name: name of this property
73
 * type: type of this property (list or type of scalar value)
74
 * length_type, value_type: type of list property count and values
75
 * read_cb: function to be called when this property is called
76
 *
77
 * Returns 1 if should continue processing file, 0 if should abort.
78
 * ---------------------------------------------------------------------- */
79
typedef struct t_ply_property_ {
80
    char name[WORDSIZE];
81
    e_ply_type type, value_type, length_type;
82
    p_ply_read_cb read_cb;
83
    void *pdata;
595 jab 84
    int idata;
371 jab 85
} t_ply_property; 
86
 
87
/* ----------------------------------------------------------------------
88
 * Element information
89
 *
90
 * name: name of this property
91
 * ninstances: number of elements of this type in file
92
 * property: property descriptions for this element
93
 * nproperty: number of properties in this element
94
 *
95
 * Returns 1 if should continue processing file, 0 if should abort.
96
 * ---------------------------------------------------------------------- */
97
typedef struct t_ply_element_ {
98
    char name[WORDSIZE];
595 jab 99
    int ninstances;
371 jab 100
    p_ply_property property;
595 jab 101
    int nproperties;
371 jab 102
} t_ply_element;
103
 
104
/* ----------------------------------------------------------------------
105
 * Input/output driver
106
 *
107
 * Depending on file mode, different functions are used to read/write 
108
 * property fields. The drivers make it transparent to read/write in ascii, 
109
 * big endian or little endian cases.
110
 * ---------------------------------------------------------------------- */
111
typedef int (*p_ply_ihandler)(p_ply ply, double *value);
112
typedef int (*p_ply_ichunk)(p_ply ply, void *anydata, size_t size);
113
typedef struct t_ply_idriver_ {
114
    p_ply_ihandler ihandler[16];
115
    p_ply_ichunk ichunk;
116
    const char *name;
117
} t_ply_idriver;
118
typedef t_ply_idriver *p_ply_idriver;
119
 
120
typedef int (*p_ply_ohandler)(p_ply ply, double value);
121
typedef int (*p_ply_ochunk)(p_ply ply, void *anydata, size_t size);
122
typedef struct t_ply_odriver_ {
123
    p_ply_ohandler ohandler[16];
124
    p_ply_ochunk ochunk;
125
    const char *name;
126
} t_ply_odriver;
127
typedef t_ply_odriver *p_ply_odriver;
128
 
129
/* ----------------------------------------------------------------------
130
 * Ply file handle. 
131
 *
132
 * io_mode: read or write (from e_ply_io_mode)
133
 * storage_mode: mode of file associated with handle (from e_ply_storage_mode)
134
 * element: elements description for this file
135
 * nelement: number of different elements in file
136
 * comment: comments for this file
137
 * ncomments: number of comments in file
138
 * obj_info: obj_info items for this file
139
 * nobj_infos: number of obj_info items in file
140
 * fp: file pointer associated with ply file
141
 * c: last character read from ply file
142
 * buffer: last word/chunck of data read from ply file
143
 * buffer_first, buffer_last: interval of untouched good data in buffer
144
 * buffer_token: start of parsed token (line or word) in buffer
145
 * idriver, odriver: input driver used to get property fields from file 
146
 * argument: storage space for callback arguments
147
 * welement, wproperty: element/property type being written
148
 * winstance_index: index of instance of current element being written
149
 * wvalue_index: index of list property value being written 
150
 * wlength: number of values in list property being written
151
 * error_cb: callback for error messages
152
 * ---------------------------------------------------------------------- */
153
typedef struct t_ply_ {
154
    e_ply_io_mode io_mode;
155
    e_ply_storage_mode storage_mode;
156
    p_ply_element element;
595 jab 157
    int nelements;
371 jab 158
    char *comment;
595 jab 159
    int ncomments;
371 jab 160
    char *obj_info;
595 jab 161
    int nobj_infos;
371 jab 162
    FILE *fp;
163
    int c;
164
    char buffer[BUFFERSIZE];
165
    size_t buffer_first, buffer_token, buffer_last;
166
    p_ply_idriver idriver;
167
    p_ply_odriver odriver;
168
    t_ply_argument argument;
595 jab 169
    int welement, wproperty;
170
    int winstance_index, wvalue_index, wlength;
371 jab 171
    p_ply_error_cb error_cb;
172
} t_ply;
173
 
174
/* ----------------------------------------------------------------------
175
 * I/O functions and drivers
176
 * ---------------------------------------------------------------------- */
177
static t_ply_idriver ply_idriver_ascii;
178
static t_ply_idriver ply_idriver_binary;
179
static t_ply_idriver ply_idriver_binary_reverse;
180
static t_ply_odriver ply_odriver_ascii;
181
static t_ply_odriver ply_odriver_binary;
182
static t_ply_odriver ply_odriver_binary_reverse;
183
 
184
static int ply_read_word(p_ply ply);
185
static int ply_check_word(p_ply ply);
186
static int ply_read_line(p_ply ply);
187
static int ply_check_line(p_ply ply);
188
static int ply_read_chunk(p_ply ply, void *anybuffer, size_t size);
189
static int ply_read_chunk_reverse(p_ply ply, void *anybuffer, size_t size);
190
static int ply_write_chunk(p_ply ply, void *anybuffer, size_t size);
191
static int ply_write_chunk_reverse(p_ply ply, void *anybuffer, size_t size);
192
static void ply_reverse(void *anydata, size_t size);
193
 
194
/* ----------------------------------------------------------------------
195
 * String functions
196
 * ---------------------------------------------------------------------- */
197
static int ply_find_string(const char *item, const char* const list[]);
198
static p_ply_element ply_find_element(p_ply ply, const char *name);
199
static p_ply_property ply_find_property(p_ply_element element, 
200
        const char *name);
201
 
202
/* ----------------------------------------------------------------------
203
 * Header parsing
204
 * ---------------------------------------------------------------------- */
205
static int ply_read_header_format(p_ply ply);
206
static int ply_read_header_comment(p_ply ply);
207
static int ply_read_header_obj_info(p_ply ply);
208
static int ply_read_header_property(p_ply ply);
209
static int ply_read_header_element(p_ply ply);
210
 
211
/* ----------------------------------------------------------------------
212
 * Error handling
213
 * ---------------------------------------------------------------------- */
214
static void ply_error_cb(const char *message);
215
static void ply_error(p_ply ply, const char *fmt, ...);
216
 
217
/* ----------------------------------------------------------------------
218
 * Memory allocation and initialization
219
 * ---------------------------------------------------------------------- */
220
static void ply_init(p_ply ply);
221
static void ply_element_init(p_ply_element element);
222
static void ply_property_init(p_ply_property property);
223
static p_ply ply_alloc(void);
224
static p_ply_element ply_grow_element(p_ply ply);
225
static p_ply_property ply_grow_property(p_ply ply, p_ply_element element);
595 jab 226
static void *ply_grow_array(p_ply ply, void **pointer, int *nmemb, int size);
371 jab 227
 
228
/* ----------------------------------------------------------------------
229
 * Special functions
230
 * ---------------------------------------------------------------------- */
231
static e_ply_storage_mode ply_arch_endian(void);
232
static int ply_type_check(void); 
233
 
234
/* ----------------------------------------------------------------------
235
 * Auxiliary read functions
236
 * ---------------------------------------------------------------------- */
237
static int ply_read_element(p_ply ply, p_ply_element element, 
238
        p_ply_argument argument);
239
static int ply_read_property(p_ply ply, p_ply_element element, 
240
        p_ply_property property, p_ply_argument argument);
241
static int ply_read_list_property(p_ply ply, p_ply_element element, 
242
        p_ply_property property, p_ply_argument argument);
243
static int ply_read_scalar_property(p_ply ply, p_ply_element element, 
244
        p_ply_property property, p_ply_argument argument);
245
 
246
 
247
/* ----------------------------------------------------------------------
248
 * Buffer support functions
249
 * ---------------------------------------------------------------------- */
250
/* pointers to tokenized word and line in buffer */
251
#define BWORD(p) (p->buffer + p->buffer_token)
252
#define BLINE(p) (p->buffer + p->buffer_token)
253
 
254
/* pointer to start of untouched bytes in buffer */
255
#define BFIRST(p) (p->buffer + p->buffer_first) 
256
 
257
/* number of bytes untouched in buffer */
258
#define BSIZE(p) (p->buffer_last - p->buffer_first) 
259
 
260
/* consumes data from buffer */
261
#define BSKIP(p, s) (p->buffer_first += s)
262
 
263
/* refills the buffer */
264
static int BREFILL(p_ply ply) {
265
    /* move untouched data to beginning of buffer */
266
    size_t size = BSIZE(ply);
267
    memmove(ply->buffer, BFIRST(ply), size);
268
    ply->buffer_last = size;
269
    ply->buffer_first = ply->buffer_token = 0;
270
    /* fill remaining with new data */
271
    size = fread(ply->buffer+size, 1, BUFFERSIZE-size-1, ply->fp);
272
    /* place sentinel so we can use str* functions with buffer */
273
    ply->buffer[BUFFERSIZE-1] = '\0';
274
    /* check if read failed */
275
    if (size <= 0) return 0;
276
    /* increase size to account for new data */
277
    ply->buffer_last += size;
278
    return 1;
279
}
280
 
281
/* ----------------------------------------------------------------------
282
 * Exported functions
283
 * ---------------------------------------------------------------------- */
284
/* ----------------------------------------------------------------------
285
 * Read support functions
286
 * ---------------------------------------------------------------------- */
287
p_ply ply_open(const char *name, p_ply_error_cb error_cb) {
288
    char magic[5] = "    ";
289
    FILE *fp = NULL; 
290
    p_ply ply = NULL;
291
    if (error_cb == NULL) error_cb = ply_error_cb;
292
    if (!ply_type_check()) {
293
        error_cb("Incompatible type system");
294
        return NULL;
295
    }
296
    assert(name);
297
    fp = fopen(name, "rb");
298
    if (!fp) {
299
        error_cb("Unable to open file");
300
        return NULL;
301
    }
302
    if (fread(magic, 1, 4, fp) < 4) {
303
        error_cb("Error reading from file");
304
        fclose(fp);
305
        return NULL;
306
    }
307
    if (strcmp(magic, "ply\n")) {
308
        fclose(fp);
309
        error_cb("Not a PLY file. Expected magic number 'ply\\n'");
310
        return NULL;
311
    }
312
    ply = ply_alloc();
313
    if (!ply) {
314
        error_cb("Out of memory");
315
        fclose(fp);
316
        return NULL;
317
    }
318
    ply->fp = fp;
319
    ply->io_mode = PLY_READ;
320
    ply->error_cb = error_cb;
321
    return ply;
322
}
323
 
324
int ply_read_header(p_ply ply) {
325
    assert(ply && ply->fp && ply->io_mode == PLY_READ);
326
    if (!ply_read_word(ply)) return 0;
327
    /* parse file format */
328
    if (!ply_read_header_format(ply)) {
329
        ply_error(ply, "Invalid file format");
330
        return 0;
331
    }
332
    /* parse elements, comments or obj_infos until the end of header */
333
    while (strcmp(BWORD(ply), "end_header")) {
334
        if (!ply_read_header_comment(ply) && 
335
                !ply_read_header_element(ply) && 
336
                !ply_read_header_obj_info(ply)) {
337
            ply_error(ply, "Unexpected token '%s'", BWORD(ply));
338
            return 0;
339
        }
340
    }
341
    return 1;
342
}
343
 
595 jab 344
int ply_set_read_cb(p_ply ply, const char *element_name, 
371 jab 345
        const char* property_name, p_ply_read_cb read_cb, 
595 jab 346
        void *pdata, int idata) {
371 jab 347
    p_ply_element element = NULL; 
348
    p_ply_property property = NULL;
349
    assert(ply && element_name && property_name);
350
    element = ply_find_element(ply, element_name);
351
    if (!element) return 0;
352
    property = ply_find_property(element, property_name);
353
    if (!property) return 0;
354
    property->read_cb = read_cb;
355
    property->pdata = pdata;
356
    property->idata = idata;
357
    return (int) element->ninstances;
358
}
359
 
360
int ply_read(p_ply ply) {
595 jab 361
    int i;
371 jab 362
    p_ply_argument argument;
363
    assert(ply && ply->fp && ply->io_mode == PLY_READ);
364
    argument = &ply->argument;
365
    /* for each element type */
366
    for (i = 0; i < ply->nelements; i++) {
367
        p_ply_element element = &ply->element[i];
368
        argument->element = element;
369
        if (!ply_read_element(ply, element, argument))
370
            return 0;
371
    }
372
    return 1;
373
}
374
 
375
/* ----------------------------------------------------------------------
376
 * Write support functions
377
 * ---------------------------------------------------------------------- */
378
p_ply ply_create(const char *name, e_ply_storage_mode storage_mode, 
379
        p_ply_error_cb error_cb) {
380
    FILE *fp = NULL;
381
    p_ply ply = NULL;
382
    if (error_cb == NULL) error_cb = ply_error_cb;
383
    if (!ply_type_check()) {
384
        error_cb("Incompatible type system");
385
        return NULL;
386
    }
387
    assert(name && storage_mode <= PLY_DEFAULT);
388
    fp = fopen(name, "wb");
389
    if (!fp) {
390
        error_cb("Unable to create file");
391
        return NULL;
392
    }
393
    ply = ply_alloc();
394
    if (!ply) {
395
        fclose(fp);
396
        error_cb("Out of memory");
397
        return NULL;
398
    }
399
    ply->io_mode = PLY_WRITE;
400
    if (storage_mode == PLY_DEFAULT) storage_mode = ply_arch_endian();
401
    if (storage_mode == PLY_ASCII) ply->odriver = &ply_odriver_ascii;
402
    else if (storage_mode == ply_arch_endian()) 
403
        ply->odriver = &ply_odriver_binary;
404
    else ply->odriver = &ply_odriver_binary_reverse;
405
    ply->storage_mode = storage_mode;
406
    ply->fp = fp;
407
    ply->error_cb = error_cb;
408
    return ply;
409
}
410
 
595 jab 411
int ply_add_element(p_ply ply, const char *name, int ninstances) {
371 jab 412
    p_ply_element element = NULL;
413
    assert(ply && ply->fp && ply->io_mode == PLY_WRITE);
414
    assert(name && strlen(name) < WORDSIZE && ninstances >= 0);
415
    if (strlen(name) >= WORDSIZE || ninstances < 0) {
416
        ply_error(ply, "Invalid arguments");
417
        return 0;
418
    }
419
    element = ply_grow_element(ply);
420
    if (!element) return 0;
421
    strcpy(element->name, name);
422
    element->ninstances = ninstances;
423
    return 1;
424
}
425
 
426
int ply_add_scalar_property(p_ply ply, const char *name, e_ply_type type) {
427
    p_ply_element element = NULL;
428
    p_ply_property property = NULL;
429
    assert(ply && ply->fp && ply->io_mode == PLY_WRITE);
430
    assert(name && strlen(name) < WORDSIZE);
431
    assert(type < PLY_LIST);
432
    if (strlen(name) >= WORDSIZE || type >= PLY_LIST) {
433
        ply_error(ply, "Invalid arguments");
434
        return 0;
435
    }
436
    element = &ply->element[ply->nelements-1];
437
    property = ply_grow_property(ply, element);
438
    if (!property) return 0;
439
    strcpy(property->name, name);
440
    property->type = type;
441
    return 1;
442
}
443
 
444
int ply_add_list_property(p_ply ply, const char *name, 
445
        e_ply_type length_type, e_ply_type value_type) {
446
    p_ply_element element = NULL;
447
    p_ply_property property = NULL;
448
    assert(ply && ply->fp && ply->io_mode == PLY_WRITE);
449
    assert(name && strlen(name) < WORDSIZE);
450
    if (strlen(name) >= WORDSIZE) {
451
        ply_error(ply, "Invalid arguments");
452
        return 0;
453
    }
454
    assert(length_type < PLY_LIST);
455
    assert(value_type < PLY_LIST);
456
    if (length_type >= PLY_LIST || value_type >= PLY_LIST) {
457
        ply_error(ply, "Invalid arguments");
458
        return 0;
459
    }
460
    element = &ply->element[ply->nelements-1];
461
    property = ply_grow_property(ply, element);
462
    if (!property) return 0;
463
    strcpy(property->name, name);
464
    property->type = PLY_LIST;
465
    property->length_type = length_type;
466
    property->value_type = value_type;
467
    return 1;
468
}
469
 
470
int ply_add_property(p_ply ply, const char *name, e_ply_type type,
471
        e_ply_type length_type, e_ply_type value_type) {
472
    if (type == PLY_LIST) 
473
        return ply_add_list_property(ply, name, length_type, value_type);
474
    else 
475
        return ply_add_scalar_property(ply, name, type);
476
}
477
 
478
int ply_add_comment(p_ply ply, const char *comment) {
479
    char *new_comment = NULL;
480
    assert(ply && comment && strlen(comment) < LINESIZE);
481
    if (!comment || strlen(comment) >= LINESIZE) {
482
        ply_error(ply, "Invalid arguments");
483
        return 0;
484
    }
485
    new_comment = (char *) ply_grow_array(ply, (void **) &ply->comment,
486
            &ply->ncomments, LINESIZE);
487
    if (!new_comment) return 0;
488
    strcpy(new_comment, comment);
489
    return 1;
490
}
491
 
492
int ply_add_obj_info(p_ply ply, const char *obj_info) {
493
    char *new_obj_info = NULL;
494
    assert(ply && obj_info && strlen(obj_info) < LINESIZE);
495
    if (!obj_info || strlen(obj_info) >= LINESIZE) {
496
        ply_error(ply, "Invalid arguments");
497
        return 0;
498
    }
499
    new_obj_info = (char *) ply_grow_array(ply, (void **) &ply->obj_info,
500
            &ply->nobj_infos, LINESIZE);
501
    if (!new_obj_info) return 0;
502
    strcpy(new_obj_info, obj_info);
503
    return 1;
504
}
505
 
506
int ply_write_header(p_ply ply) {
595 jab 507
    int i, j;
371 jab 508
    assert(ply && ply->fp && ply->io_mode == PLY_WRITE);
509
    assert(ply->element || ply->nelements == 0); 
510
    assert(!ply->element || ply->nelements > 0); 
511
    if (fprintf(ply->fp, "ply\nformat %s 1.0\n", 
512
                ply_storage_mode_list[ply->storage_mode]) <= 0) goto error;
513
    for (i = 0; i < ply->ncomments; i++)
514
        if (fprintf(ply->fp, "comment %s\n", ply->comment + LINESIZE*i) <= 0)
515
            goto error;
516
    for (i = 0; i < ply->nobj_infos; i++)
517
        if (fprintf(ply->fp, "obj_info %s\n", ply->obj_info + LINESIZE*i) <= 0)
518
            goto error;
519
    for (i = 0; i < ply->nelements; i++) {
520
        p_ply_element element = &ply->element[i];
521
        assert(element->property || element->nproperties == 0); 
522
        assert(!element->property || element->nproperties > 0); 
523
        if (fprintf(ply->fp, "element %s %ld\n", element->name, 
524
                    element->ninstances) <= 0) goto error;
525
        for (j = 0; j < element->nproperties; j++) {
526
            p_ply_property property = &element->property[j];
527
            if (property->type == PLY_LIST) {
528
                if (fprintf(ply->fp, "property list %s %s %s\n", 
529
                            ply_type_list[property->length_type],
530
                            ply_type_list[property->value_type],
531
                            property->name) <= 0) goto error;
532
            } else {
533
                if (fprintf(ply->fp, "property %s %s\n", 
534
                            ply_type_list[property->type],
535
                            property->name) <= 0) goto error;
536
            }
537
        }
538
    }
539
    return fprintf(ply->fp, "end_header\n") > 0;
540
error:
541
    ply_error(ply, "Error writing to file");
542
    return 0;
543
}
544
 
545
int ply_write(p_ply ply, double value) {
546
    p_ply_element element = NULL;
547
    p_ply_property property = NULL;
548
    int type = -1;
549
    int breakafter = 0;
550
    if (ply->welement > ply->nelements) return 0;
551
    element = &ply->element[ply->welement];
552
    if (ply->wproperty > element->nproperties) return 0;
553
    property = &element->property[ply->wproperty];
554
    if (property->type == PLY_LIST) {
555
        if (ply->wvalue_index == 0) {
556
            type = property->length_type;
595 jab 557
            ply->wlength = (int) value;
371 jab 558
        } else type = property->value_type;
559
    } else {
560
        type = property->type;
561
        ply->wlength = 0;
562
    }
563
    if (!ply->odriver->ohandler[type](ply, value)) {
564
        ply_error(ply, "Failed writing %s of %s %d (%s: %s)", 
565
                    property->name, element->name, 
566
                    ply->winstance_index, 
567
                    ply->odriver->name, ply_type_list[type]);
568
        return 0;
569
    }
570
    ply->wvalue_index++;
571
    if (ply->wvalue_index > ply->wlength) {
572
        ply->wvalue_index = 0;
573
        ply->wproperty++;
574
    }
575
    if (ply->wproperty >= element->nproperties) {
576
        ply->wproperty = 0;
577
        ply->winstance_index++;
578
        if (ply->storage_mode == PLY_ASCII) breakafter = 1;
579
    }
580
    if (ply->winstance_index >= element->ninstances) {
581
        ply->winstance_index = 0;
582
        ply->welement++;
583
    }
584
    return !breakafter || putc('\n', ply->fp) > 0;
585
}
586
 
587
int ply_close(p_ply ply) {
595 jab 588
    int i;
371 jab 589
    assert(ply && ply->fp);
590
    assert(ply->element || ply->nelements == 0);
591
    assert(!ply->element || ply->nelements > 0);
592
    /* write last chunk to file */
593
    if (ply->io_mode == PLY_WRITE && 
594
      fwrite(ply->buffer, 1, ply->buffer_last, ply->fp) < ply->buffer_last) {
595
        ply_error(ply, "Error closing up");
596
        return 0;
597
    }
598
    fclose(ply->fp);
599
    /* free all memory used by handle */
600
    if (ply->element) {
601
        for (i = 0; i < ply->nelements; i++) {
602
            p_ply_element element = &ply->element[i];
603
            if (element->property) free(element->property);
604
        }
605
        free(ply->element);
606
    }
607
    if (ply->obj_info) free(ply->obj_info);
608
    if (ply->comment) free(ply->comment);
609
    free(ply);
610
    return 1;
611
}
612
 
613
/* ----------------------------------------------------------------------
614
 * Query support functions
615
 * ---------------------------------------------------------------------- */
616
p_ply_element ply_get_next_element(p_ply ply, 
617
        p_ply_element last) {
618
    assert(ply);
619
    if (!last) return ply->element;
620
    last++;
621
    if (last < ply->element + ply->nelements) return last;
622
    else return NULL;
623
}
624
 
625
int ply_get_element_info(p_ply_element element, const char** name,
595 jab 626
        int *ninstances) {
371 jab 627
    assert(element);
628
    if (name) *name = element->name;
595 jab 629
    if (ninstances) *ninstances = (int) element->ninstances;
371 jab 630
    return 1;
631
}
632
 
633
p_ply_property ply_get_next_property(p_ply_element element, 
634
        p_ply_property last) {
635
    assert(element);
636
    if (!last) return element->property;
637
    last++;
638
    if (last < element->property + element->nproperties) return last;
639
    else return NULL;
640
}
641
 
642
int ply_get_property_info(p_ply_property property, const char** name,
643
        e_ply_type *type, e_ply_type *length_type, e_ply_type *value_type) {
644
    assert(property);
645
    if (name) *name = property->name;
646
    if (type) *type = property->type;
647
    if (length_type) *length_type = property->length_type;
648
    if (value_type) *value_type = property->value_type;
649
    return 1;
650
 
651
}
652
 
653
const char *ply_get_next_comment(p_ply ply, const char *last) {
654
    assert(ply);
655
    if (!last) return ply->comment; 
656
    last += LINESIZE;
657
    if (last < ply->comment + LINESIZE*ply->ncomments) return last;
658
    else return NULL;
659
}
660
 
661
const char *ply_get_next_obj_info(p_ply ply, const char *last) {
662
    assert(ply);
663
    if (!last) return ply->obj_info; 
664
    last += LINESIZE;
665
    if (last < ply->obj_info + LINESIZE*ply->nobj_infos) return last;
666
    else return NULL;
667
}
668
 
669
/* ----------------------------------------------------------------------
670
 * Callback argument support functions 
671
 * ---------------------------------------------------------------------- */
672
int ply_get_argument_element(p_ply_argument argument, 
595 jab 673
        p_ply_element *element, int *instance_index) {
371 jab 674
    assert(argument);
675
    if (!argument) return 0;
676
    if (element) *element = argument->element;
677
    if (instance_index) *instance_index = argument->instance_index;
678
    return 1;
679
}
680
 
681
int ply_get_argument_property(p_ply_argument argument, 
595 jab 682
        p_ply_property *property, int *length, int *value_index) {
371 jab 683
    assert(argument);
684
    if (!argument) return 0;
685
    if (property) *property = argument->property;
686
    if (length) *length = argument->length;
687
    if (value_index) *value_index = argument->value_index;
688
    return 1;
689
}
690
 
691
int ply_get_argument_user_data(p_ply_argument argument, void **pdata, 
595 jab 692
        int *idata) {
371 jab 693
    assert(argument);
694
    if (!argument) return 0;
695
    if (pdata) *pdata = argument->pdata;
696
    if (idata) *idata = argument->idata;
697
    return 1;
698
}
699
 
700
double ply_get_argument_value(p_ply_argument argument) {
701
    assert(argument);
702
    if (!argument) return 0.0;
703
    return argument->value;
704
}
705
 
706
/* ----------------------------------------------------------------------
707
 * Internal functions
708
 * ---------------------------------------------------------------------- */
709
static int ply_read_list_property(p_ply ply, p_ply_element element, 
710
        p_ply_property property, p_ply_argument argument) {
711
    int l;
712
    p_ply_read_cb read_cb = property->read_cb;
713
    p_ply_ihandler *driver = ply->idriver->ihandler; 
714
    /* get list length */
715
    p_ply_ihandler handler = driver[property->length_type];
716
    double length;
717
    if (!handler(ply, &length)) {
718
        ply_error(ply, "Error reading '%s' of '%s' number %d",
719
                property->name, element->name, argument->instance_index);
720
        return 0;
721
    }
722
    /* invoke callback to pass length in value field */
595 jab 723
    argument->length = (int) length;
371 jab 724
    argument->value_index = -1;
725
    argument->value = length;
726
    if (read_cb && !read_cb(argument)) {
727
        ply_error(ply, "Aborted by user");
728
        return 0;
729
    }
730
    /* read list values */
731
    handler = driver[property->value_type];
732
    /* for each value in list */
595 jab 733
    for (l = 0; l < (int) length; l++) {
371 jab 734
        /* read value from file */
735
        argument->value_index = l;
736
        if (!handler(ply, &argument->value)) {
737
            ply_error(ply, "Error reading value number %d of '%s' of "
738
                    "'%s' number %d", l+1, property->name, 
739
                    element->name, argument->instance_index);
740
            return 0;
741
        }
742
        /* invoke callback to pass value */
743
        if (read_cb && !read_cb(argument)) {
744
            ply_error(ply, "Aborted by user");
745
            return 0;
746
        }
747
    }
748
    return 1;
749
}
750
 
751
static int ply_read_scalar_property(p_ply ply, p_ply_element element, 
752
        p_ply_property property, p_ply_argument argument) {
753
    p_ply_read_cb read_cb = property->read_cb;
754
    p_ply_ihandler *driver = ply->idriver->ihandler; 
755
    p_ply_ihandler handler = driver[property->type];
756
    argument->length = 1;
757
    argument->value_index = 0;
758
    if (!handler(ply, &argument->value)) {
759
        ply_error(ply, "Error reading '%s' of '%s' number %d",
760
                property->name, element->name, argument->instance_index);
761
        return 0;
762
    }
763
    if (read_cb && !read_cb(argument)) {
764
        ply_error(ply, "Aborted by user");
765
        return 0;
766
    }
767
    return 1;
768
}
769
 
770
static int ply_read_property(p_ply ply, p_ply_element element, 
771
        p_ply_property property, p_ply_argument argument) {
772
    if (property->type == PLY_LIST) 
773
        return ply_read_list_property(ply, element, property, argument);
774
    else 
775
        return ply_read_scalar_property(ply, element, property, argument);
776
}
777
 
778
static int ply_read_element(p_ply ply, p_ply_element element, 
779
        p_ply_argument argument) {
595 jab 780
    int j, k;
371 jab 781
    /* for each element of this type */
782
    for (j = 0; j < element->ninstances; j++) {
783
        argument->instance_index = j;
784
        /* for each property */
785
        for (k = 0; k < element->nproperties; k++) {
786
            p_ply_property property = &element->property[k];
787
            argument->property = property;
788
            argument->pdata = property->pdata;
789
            argument->idata = property->idata;
790
            if (!ply_read_property(ply, element, property, argument))
791
                return 0;
792
        }
793
    }
794
    return 1;
795
}
796
 
797
static int ply_find_string(const char *item, const char* const list[]) {
798
    int i;
799
    assert(item && list);
800
    for (i = 0; list[i]; i++) 
801
        if (!strcmp(list[i], item)) return i;
802
    return -1;
803
}
804
 
805
static p_ply_element ply_find_element(p_ply ply, const char *name) {
806
    p_ply_element element;
807
    int i, nelements;
808
    assert(ply && name); 
809
    element = ply->element;
810
    nelements = ply->nelements;
811
    assert(element || nelements == 0); 
812
    assert(!element || nelements > 0); 
813
    for (i = 0; i < nelements; i++) 
814
        if (!strcmp(element[i].name, name)) return &element[i];
815
    return NULL;
816
}
817
 
818
static p_ply_property ply_find_property(p_ply_element element, 
819
        const char *name) {
820
    p_ply_property property;
821
    int i, nproperties;
822
    assert(element && name); 
823
    property = element->property;
824
    nproperties = element->nproperties;
825
    assert(property || nproperties == 0); 
826
    assert(!property || nproperties > 0); 
827
    for (i = 0; i < nproperties; i++) 
828
        if (!strcmp(property[i].name, name)) return &property[i];
829
    return NULL;
830
}
831
 
832
static int ply_check_word(p_ply ply) {
833
    if (strlen(BLINE(ply)) >= WORDSIZE) {
595 jab 834
        ply_error(ply, "Word too int");
371 jab 835
        return 0;
836
    }
837
    return 1;
838
}
839
 
840
static int ply_read_word(p_ply ply) {
841
    size_t t = 0;
842
    assert(ply && ply->fp && ply->io_mode == PLY_READ);
843
    /* skip leading blanks */
844
    while (1) {
845
        t = strspn(BFIRST(ply), " \n\r\t");
846
        /* check if all buffer was made of blanks */
847
        if (t >= BSIZE(ply)) {
848
            if (!BREFILL(ply)) {
849
                ply_error(ply, "Unexpected end of file");
850
                return 0;
851
            }
852
        } else break; 
853
    } 
854
    BSKIP(ply, t); 
855
    /* look for a space after the current word */
856
    t = strcspn(BFIRST(ply), " \n\r\t");
857
    /* if we didn't reach the end of the buffer, we are done */
858
    if (t < BSIZE(ply)) {
859
        ply->buffer_token = ply->buffer_first;
860
        BSKIP(ply, t);
861
        *BFIRST(ply) = '\0';
862
        BSKIP(ply, 1);
863
        return ply_check_word(ply);
864
    }
865
    /* otherwise, try to refill buffer */
866
    if (!BREFILL(ply)) {
867
        ply_error(ply, "Unexpected end of file");
868
        return 0;
869
    }
870
    /* keep looking from where we left */
871
    t += strcspn(BFIRST(ply) + t, " \n\r\t");
872
    /* check if the token is too large for our buffer */
873
    if (t >= BSIZE(ply)) {
874
        ply_error(ply, "Token too large");
875
        return 0;
876
    }
877
    /* we are done */
878
    ply->buffer_token = ply->buffer_first;
879
    BSKIP(ply, t);
880
    *BFIRST(ply) = '\0';
881
    BSKIP(ply, 1);
882
    return ply_check_word(ply);
883
}
884
 
885
static int ply_check_line(p_ply ply) {
886
    if (strlen(BLINE(ply)) >= LINESIZE) {
595 jab 887
        ply_error(ply, "Line too int");
371 jab 888
        return 0;
889
    }
890
    return 1;
891
}
892
 
893
static int ply_read_line(p_ply ply) {
894
    const char *end = NULL;
895
    assert(ply && ply->fp && ply->io_mode == PLY_READ);
896
    /* look for a end of line */
897
    end = strchr(BFIRST(ply), '\n');
898
    /* if we didn't reach the end of the buffer, we are done */
899
    if (end) {
900
        ply->buffer_token = ply->buffer_first;
901
        BSKIP(ply, end - BFIRST(ply));
902
        *BFIRST(ply) = '\0';
903
        BSKIP(ply, 1);
904
        return ply_check_line(ply);
905
    } else {
906
        end = ply->buffer + BSIZE(ply); 
907
        /* otherwise, try to refill buffer */
908
        if (!BREFILL(ply)) {
909
            ply_error(ply, "Unexpected end of file");
910
            return 0;
911
        }
912
    }
913
    /* keep looking from where we left */
914
    end = strchr(end, '\n');
915
    /* check if the token is too large for our buffer */
916
    if (!end) {
917
        ply_error(ply, "Token too large");
918
        return 0;
919
    }
920
    /* we are done */
921
    ply->buffer_token = ply->buffer_first;
922
    BSKIP(ply, end - BFIRST(ply));
923
    *BFIRST(ply) = '\0';
924
    BSKIP(ply, 1);
925
    return ply_check_line(ply);
926
}
927
 
928
static int ply_read_chunk(p_ply ply, void *anybuffer, size_t size) {
929
    char *buffer = (char *) anybuffer;
930
    size_t i = 0;
931
    assert(ply && ply->fp && ply->io_mode == PLY_READ);
932
    assert(ply->buffer_first <= ply->buffer_last);
933
    while (i < size) {
934
        if (ply->buffer_first < ply->buffer_last) {
935
            buffer[i] = ply->buffer[ply->buffer_first];
936
            ply->buffer_first++;
937
            i++;
938
        } else {
939
            ply->buffer_first = 0;
940
            ply->buffer_last = fread(ply->buffer, 1, BUFFERSIZE, ply->fp);
941
            if (ply->buffer_last <= 0) return 0;
942
        }
943
    }
944
    return 1;
945
}
946
 
947
static int ply_write_chunk(p_ply ply, void *anybuffer, size_t size) {
948
    char *buffer = (char *) anybuffer;
949
    size_t i = 0;
950
    assert(ply && ply->fp && ply->io_mode == PLY_WRITE);
951
    assert(ply->buffer_last <= BUFFERSIZE);
952
    while (i < size) {
953
        if (ply->buffer_last < BUFFERSIZE) {
954
            ply->buffer[ply->buffer_last] = buffer[i];
955
            ply->buffer_last++;
956
            i++;
957
        } else {
958
            ply->buffer_last = 0;
959
            if (fwrite(ply->buffer, 1, BUFFERSIZE, ply->fp) < BUFFERSIZE)
960
                return 0;
961
        }
962
    }
963
    return 1;
964
}
965
 
966
static int ply_write_chunk_reverse(p_ply ply, void *anybuffer, size_t size) {
967
    int ret = 0;
968
    ply_reverse(anybuffer, size);
969
    ret = ply_write_chunk(ply, anybuffer, size);
970
    ply_reverse(anybuffer, size);
971
    return ret;
972
}
973
 
974
static int ply_read_chunk_reverse(p_ply ply, void *anybuffer, size_t size) {
975
    if (!ply_read_chunk(ply, anybuffer, size)) return 0;
976
    ply_reverse(anybuffer, size);
977
    return 1;
978
}
979
 
980
static void ply_reverse(void *anydata, size_t size) {
981
    char *data = (char *) anydata;
982
    char temp;
983
    size_t i;
984
    for (i = 0; i < size/2; i++) {
985
        temp = data[i];
986
        data[i] = data[size-i-1];
987
        data[size-i-1] = temp;
988
    }
989
}
990
 
991
static void ply_init(p_ply ply) {
992
    ply->c = ' ';
993
    ply->element = NULL;
994
    ply->nelements = 0;
995
    ply->comment = NULL;
996
    ply->ncomments = 0;
997
    ply->obj_info = NULL;
998
    ply->nobj_infos = 0;
999
    ply->idriver = NULL;
1000
    ply->odriver = NULL;
1001
    ply->buffer[0] = '\0';
1002
    ply->buffer_first = ply->buffer_last = ply->buffer_token = 0;
1003
    ply->welement = 0;
1004
    ply->wproperty = 0;
1005
    ply->winstance_index = 0;
1006
    ply->wlength = 0;
1007
    ply->wvalue_index = 0;
1008
}
1009
 
1010
static void ply_element_init(p_ply_element element) {
1011
    element->name[0] = '\0';
1012
    element->ninstances = 0;
1013
    element->property = NULL;
1014
    element->nproperties = 0; 
1015
}
1016
 
1017
static void ply_property_init(p_ply_property property) {
1018
    property->name[0] = '\0';
1019
    property->type = -1;
1020
    property->length_type = -1;
1021
    property->value_type = -1;
1022
    property->read_cb = (p_ply_read_cb) NULL;
1023
    property->pdata = NULL;
1024
    property->idata = 0;
1025
}
1026
 
1027
static p_ply ply_alloc(void) {
1028
    p_ply ply = (p_ply) malloc(sizeof(t_ply));
1029
    if (!ply) return NULL;
1030
    ply_init(ply);
1031
    return ply;
1032
}
1033
 
1034
static void *ply_grow_array(p_ply ply, void **pointer, 
595 jab 1035
        int *nmemb, int size) {
371 jab 1036
    void *temp = *pointer;
595 jab 1037
    int count = *nmemb + 1;
371 jab 1038
    if (!temp) temp = malloc(count*size);
1039
    else temp = realloc(temp, count*size);
1040
    if (!temp) {
1041
        ply_error(ply, "Out of memory");
1042
        return NULL;
1043
    }
1044
    *pointer = temp;
1045
    *nmemb = count;
1046
    return (char *) temp + (count-1) * size;
1047
}
1048
 
1049
static p_ply_element ply_grow_element(p_ply ply) {
1050
    p_ply_element element = NULL;
1051
    assert(ply); 
1052
    assert(ply->element || ply->nelements == 0); 
1053
    assert(!ply->element || ply->nelements > 0); 
1054
    element = (p_ply_element) ply_grow_array(ply, (void **) &ply->element, 
1055
            &ply->nelements, sizeof(t_ply_element));
1056
    if (!element) return NULL;
1057
    ply_element_init(element);
1058
    return element; 
1059
}
1060
 
1061
static p_ply_property ply_grow_property(p_ply ply, p_ply_element element) {
1062
    p_ply_property property = NULL;
1063
    assert(ply);
1064
    assert(element);
1065
    assert(element->property || element->nproperties == 0);
1066
    assert(!element->property || element->nproperties > 0);
1067
    property = (p_ply_property) ply_grow_array(ply, 
1068
            (void **) &element->property, 
1069
            &element->nproperties, sizeof(t_ply_property));
1070
    if (!property) return NULL;
1071
    ply_property_init(property);
1072
    return property;
1073
}
1074
 
1075
static int ply_read_header_format(p_ply ply) {
1076
    assert(ply && ply->fp && ply->io_mode == PLY_READ);
1077
    if (strcmp(BWORD(ply), "format")) return 0;
1078
    if (!ply_read_word(ply)) return 0;
1079
    ply->storage_mode = ply_find_string(BWORD(ply), ply_storage_mode_list);
1080
    if (ply->storage_mode == (e_ply_storage_mode) (-1)) return 0;
1081
    if (ply->storage_mode == PLY_ASCII) ply->idriver = &ply_idriver_ascii;
1082
    else if (ply->storage_mode == ply_arch_endian()) 
1083
        ply->idriver = &ply_idriver_binary;
1084
    else ply->idriver = &ply_idriver_binary_reverse;
1085
    if (!ply_read_word(ply)) return 0;
1086
    if (strcmp(BWORD(ply), "1.0")) return 0;
1087
    if (!ply_read_word(ply)) return 0;
1088
    return 1;
1089
}
1090
 
1091
static int ply_read_header_comment(p_ply ply) {
1092
    assert(ply && ply->fp && ply->io_mode == PLY_READ);
1093
    if (strcmp(BWORD(ply), "comment")) return 0;
1094
    if (!ply_read_line(ply)) return 0;
1095
    if (!ply_add_comment(ply, BLINE(ply))) return 0;
1096
    if (!ply_read_word(ply)) return 0;
1097
    return 1;
1098
}
1099
 
1100
static int ply_read_header_obj_info(p_ply ply) {
1101
    assert(ply && ply->fp && ply->io_mode == PLY_READ);
1102
    if (strcmp(BWORD(ply), "obj_info")) return 0;
1103
    if (!ply_read_line(ply)) return 0;
1104
    if (!ply_add_obj_info(ply, BLINE(ply))) return 0;
1105
    if (!ply_read_word(ply)) return 0;
1106
    return 1;
1107
}
1108
 
1109
static int ply_read_header_property(p_ply ply) {
1110
    p_ply_element element = NULL;
1111
    p_ply_property property = NULL;
1112
    /* make sure it is a property */
1113
    if (strcmp(BWORD(ply), "property")) return 0;
1114
    element = &ply->element[ply->nelements-1];
1115
    property = ply_grow_property(ply, element);
1116
    if (!property) return 0;
1117
    /* get property type */
1118
    if (!ply_read_word(ply)) return 0;
1119
    property->type = ply_find_string(BWORD(ply), ply_type_list);
1120
    if (property->type == (e_ply_type) (-1)) return 0;
1121
    if (property->type == PLY_LIST) {
1122
        /* if it's a list, we need the base types */
1123
        if (!ply_read_word(ply)) return 0;
1124
        property->length_type = ply_find_string(BWORD(ply), ply_type_list);
1125
        if (property->length_type == (e_ply_type) (-1)) return 0;
1126
        if (!ply_read_word(ply)) return 0;
1127
        property->value_type = ply_find_string(BWORD(ply), ply_type_list);
1128
        if (property->value_type == (e_ply_type) (-1)) return 0;
1129
    }
1130
    /* get property name */
1131
    if (!ply_read_word(ply)) return 0;
1132
    strcpy(property->name, BWORD(ply));
1133
    if (!ply_read_word(ply)) return 0;
1134
    return 1;
1135
}
1136
 
1137
static int ply_read_header_element(p_ply ply) {
1138
    p_ply_element element = NULL;
595 jab 1139
    int dummy;
371 jab 1140
    assert(ply && ply->fp && ply->io_mode == PLY_READ);
1141
    if (strcmp(BWORD(ply), "element")) return 0;
1142
    /* allocate room for new element */
1143
    element = ply_grow_element(ply);
1144
    if (!element) return 0;
1145
    /* get element name */
1146
    if (!ply_read_word(ply)) return 0;
1147
    strcpy(element->name, BWORD(ply));
1148
    /* get number of elements of this type */
1149
    if (!ply_read_word(ply)) return 0;
595 jab 1150
    if (sscanf(BWORD(ply), "%d", &dummy) != 1) {
371 jab 1151
        ply_error(ply, "Expected number got '%s'", BWORD(ply));
1152
        return 0;
1153
    }
1154
    element->ninstances = dummy;
1155
    /* get all properties for this element */
1156
    if (!ply_read_word(ply)) return 0;
1157
    while (ply_read_header_property(ply) || 
1158
        ply_read_header_comment(ply) || ply_read_header_obj_info(ply))
1159
        /* do nothing */;
1160
    return 1;
1161
}
1162
 
1163
static void ply_error_cb(const char *message) {
1164
    fprintf(stderr, "RPly: %s\n", message);
1165
}
1166
 
1167
static void ply_error(p_ply ply, const char *fmt, ...) {
1168
    char buffer[1024];
1169
    va_list ap;
1170
    va_start(ap, fmt);
1171
    vsprintf(buffer, fmt, ap);
1172
    va_end(ap);
1173
    ply->error_cb(buffer);
1174
}
1175
 
1176
static e_ply_storage_mode ply_arch_endian(void) {
595 jab 1177
    unsigned int i = 1;
371 jab 1178
    unsigned char *s = (unsigned char *) &i;
1179
    if (*s == 1) return PLY_LITTLE_ENDIAN;
1180
    else return PLY_BIG_ENDIAN;
1181
}
1182
 
1183
static int ply_type_check(void) {
1184
    assert(sizeof(char) == 1);
1185
    assert(sizeof(unsigned char) == 1);
1186
    assert(sizeof(short) == 2);
1187
    assert(sizeof(unsigned short) == 2);
595 jab 1188
    assert(sizeof(int) == 4);
1189
    assert(sizeof(unsigned int) == 4);
371 jab 1190
    assert(sizeof(float) == 4);
1191
    assert(sizeof(double) == 8);
1192
    if (sizeof(char) != 1) return 0;
1193
    if (sizeof(unsigned char) != 1) return 0;
1194
    if (sizeof(short) != 2) return 0;
1195
    if (sizeof(unsigned short) != 2) return 0;
595 jab 1196
    if (sizeof(int) != 4) return 0;
1197
    if (sizeof(unsigned int) != 4) return 0;
371 jab 1198
    if (sizeof(float) != 4) return 0;
1199
    if (sizeof(double) != 8) return 0;
1200
    return 1;
1201
}
1202
 
1203
/* ----------------------------------------------------------------------
1204
 * Output handlers
1205
 * ---------------------------------------------------------------------- */
1206
static int oascii_int8(p_ply ply, double value) {
1207
    if (value > CHAR_MAX || value < CHAR_MIN) return 0;
1208
    return fprintf(ply->fp, "%d ", (char) value) > 0;
1209
}
1210
 
1211
static int oascii_uint8(p_ply ply, double value) {
1212
    if (value > UCHAR_MAX || value < 0) return 0;
1213
    return fprintf(ply->fp, "%d ", (unsigned char) value) > 0;
1214
}
1215
 
1216
static int oascii_int16(p_ply ply, double value) {
1217
    if (value > SHRT_MAX || value < SHRT_MIN) return 0;
1218
    return fprintf(ply->fp, "%d ", (short) value) > 0;
1219
}
1220
 
1221
static int oascii_uint16(p_ply ply, double value) {
1222
    if (value > USHRT_MAX || value < 0) return 0;
1223
    return fprintf(ply->fp, "%d ", (unsigned short) value) > 0;
1224
}
1225
 
1226
static int oascii_int32(p_ply ply, double value) {
1227
    if (value > LONG_MAX || value < LONG_MIN) return 0;
1228
    return fprintf(ply->fp, "%d ", (int) value) > 0;
1229
}
1230
 
1231
static int oascii_uint32(p_ply ply, double value) {
1232
    if (value > ULONG_MAX || value < 0) return 0;
1233
    return fprintf(ply->fp, "%d ", (unsigned int) value) > 0;
1234
}
1235
 
1236
static int oascii_float32(p_ply ply, double value) {
1237
    if (value < -FLT_MAX || value > FLT_MAX) return 0;
1238
    return fprintf(ply->fp, "%g ", (float) value) > 0;
1239
}
1240
 
1241
static int oascii_float64(p_ply ply, double value) {
1242
    if (value < -DBL_MAX || value > DBL_MAX) return 0;
1243
    return fprintf(ply->fp, "%g ", value) > 0;
1244
}
1245
 
1246
static int obinary_int8(p_ply ply, double value) {
1247
    char int8 = (char) value;
1248
    if (value > CHAR_MAX || value < CHAR_MIN) return 0;
1249
    return ply->odriver->ochunk(ply, &int8, sizeof(int8));
1250
}
1251
 
1252
static int obinary_uint8(p_ply ply, double value) {
1253
    unsigned char uint8 = (unsigned char) value;
1254
    if (value > UCHAR_MAX || value < 0) return 0;
1255
    return ply->odriver->ochunk(ply, &uint8, sizeof(uint8)); 
1256
}
1257
 
1258
static int obinary_int16(p_ply ply, double value) {
1259
    short int16 = (short) value;
1260
    if (value > SHRT_MAX || value < SHRT_MIN) return 0;
1261
    return ply->odriver->ochunk(ply, &int16, sizeof(int16));
1262
}
1263
 
1264
static int obinary_uint16(p_ply ply, double value) {
1265
    unsigned short uint16 = (unsigned short) value;
1266
    if (value > USHRT_MAX || value < 0) return 0;
1267
    return ply->odriver->ochunk(ply, &uint16, sizeof(uint16)); 
1268
}
1269
 
1270
static int obinary_int32(p_ply ply, double value) {
595 jab 1271
    int int32 = (int) value;
371 jab 1272
    if (value > LONG_MAX || value < LONG_MIN) return 0;
1273
    return ply->odriver->ochunk(ply, &int32, sizeof(int32));
1274
}
1275
 
1276
static int obinary_uint32(p_ply ply, double value) {
595 jab 1277
    unsigned int uint32 = (unsigned int) value;
371 jab 1278
    if (value > ULONG_MAX || value < 0) return 0;
1279
    return ply->odriver->ochunk(ply, &uint32, sizeof(uint32));
1280
}
1281
 
1282
static int obinary_float32(p_ply ply, double value) {
1283
    float float32 = (float) value;
1284
    if (value > FLT_MAX || value < -FLT_MAX) return 0;
1285
    return ply->odriver->ochunk(ply, &float32, sizeof(float32));
1286
}
1287
 
1288
static int obinary_float64(p_ply ply, double value) {
1289
    return ply->odriver->ochunk(ply, &value, sizeof(value)); 
1290
}
1291
 
1292
/* ----------------------------------------------------------------------
1293
 * Input  handlers
1294
 * ---------------------------------------------------------------------- */
1295
static int iascii_int8(p_ply ply, double *value) {
1296
    char *end;
1297
    if (!ply_read_word(ply)) return 0;
1298
    *value = strtol(BWORD(ply), &end, 10);
1299
    if (*end || *value > CHAR_MAX || *value < CHAR_MIN) return 0;
1300
    return 1;
1301
}
1302
 
1303
static int iascii_uint8(p_ply ply, double *value) {
1304
    char *end;
1305
    if (!ply_read_word(ply)) return 0;
1306
    *value = strtol(BWORD(ply), &end, 10);
1307
    if (*end || *value > UCHAR_MAX || *value < 0) return 0;
1308
    return 1;
1309
}
1310
 
1311
static int iascii_int16(p_ply ply, double *value) {
1312
    char *end;
1313
    if (!ply_read_word(ply)) return 0;
1314
    *value = strtol(BWORD(ply), &end, 10);
1315
    if (*end || *value > SHRT_MAX || *value < SHRT_MIN) return 0;
1316
    return 1;
1317
}
1318
 
1319
static int iascii_uint16(p_ply ply, double *value) {
1320
    char *end;
1321
    if (!ply_read_word(ply)) return 0;
1322
    *value = strtol(BWORD(ply), &end, 10);
1323
    if (*end || *value > USHRT_MAX || *value < 0) return 0;
1324
    return 1;
1325
}
1326
 
1327
static int iascii_int32(p_ply ply, double *value) {
1328
    char *end;
1329
    if (!ply_read_word(ply)) return 0;
1330
    *value = strtol(BWORD(ply), &end, 10);
1331
    if (*end || *value > LONG_MAX || *value < LONG_MIN) return 0;
1332
    return 1;
1333
}
1334
 
1335
static int iascii_uint32(p_ply ply, double *value) {
1336
    char *end;
1337
    if (!ply_read_word(ply)) return 0;
1338
    *value = strtol(BWORD(ply), &end, 10);
1339
    if (*end || *value < 0) return 0;
1340
    return 1;
1341
}
1342
 
1343
static int iascii_float32(p_ply ply, double *value) {
1344
    char *end;
1345
    if (!ply_read_word(ply)) return 0;
1346
    *value = strtod(BWORD(ply), &end);
1347
    if (*end || *value < -FLT_MAX || *value > FLT_MAX) return 0;
1348
    return 1;
1349
}
1350
 
1351
static int iascii_float64(p_ply ply, double *value) {
1352
    char *end;
1353
    if (!ply_read_word(ply)) return 0;
1354
    *value = strtod(BWORD(ply), &end);
1355
    if (*end || *value < -DBL_MAX || *value > DBL_MAX) return 0;
1356
    return 1;
1357
}
1358
 
1359
static int ibinary_int8(p_ply ply, double *value) {
1360
    char int8;
1361
    if (!ply->idriver->ichunk(ply, &int8, 1)) return 0;
1362
    *value = int8;
1363
    return 1;
1364
}
1365
 
1366
static int ibinary_uint8(p_ply ply, double *value) {
1367
    unsigned char uint8;
1368
    if (!ply->idriver->ichunk(ply, &uint8, 1)) return 0;
1369
    *value = uint8;
1370
    return 1;
1371
}
1372
 
1373
static int ibinary_int16(p_ply ply, double *value) {
1374
    short int16;
1375
    if (!ply->idriver->ichunk(ply, &int16, sizeof(int16))) return 0;
1376
    *value = int16;
1377
    return 1;
1378
}
1379
 
1380
static int ibinary_uint16(p_ply ply, double *value) {
1381
    unsigned short uint16;
1382
    if (!ply->idriver->ichunk(ply, &uint16, sizeof(uint16))) return 0;
1383
    *value = uint16;
1384
    return 1;
1385
}
1386
 
1387
static int ibinary_int32(p_ply ply, double *value) {
595 jab 1388
    int int32;
371 jab 1389
    if (!ply->idriver->ichunk(ply, &int32, sizeof(int32))) return 0;
1390
    *value = int32;
1391
    return 1;
1392
}
1393
 
1394
static int ibinary_uint32(p_ply ply, double *value) {
595 jab 1395
    unsigned int uint32;
371 jab 1396
    if (!ply->idriver->ichunk(ply, &uint32, sizeof(uint32))) return 0;
1397
    *value = uint32;
1398
    return 1;
1399
}
1400
 
1401
static int ibinary_float32(p_ply ply, double *value) {
1402
    float float32;
1403
    if (!ply->idriver->ichunk(ply, &float32, sizeof(float32))) return 0;
1404
    *value = float32;
1405
    ply_reverse(&float32, sizeof(float32));
1406
    return 1;
1407
}
1408
 
1409
static int ibinary_float64(p_ply ply, double *value) {
1410
    return ply->idriver->ichunk(ply, value, sizeof(double));
1411
}
1412
 
1413
/* ----------------------------------------------------------------------
1414
 * Constants
1415
 * ---------------------------------------------------------------------- */
1416
static t_ply_idriver ply_idriver_ascii = {
1417
    {   iascii_int8, iascii_uint8, iascii_int16, iascii_uint16,
1418
        iascii_int32, iascii_uint32, iascii_float32, iascii_float64,
1419
        iascii_int8, iascii_uint8, iascii_int16, iascii_uint16,
1420
        iascii_int32, iascii_uint32, iascii_float32, iascii_float64
1421
    }, /* order matches e_ply_type enum */
1422
    NULL,
1423
    "ascii input"
1424
};
1425
 
1426
static t_ply_idriver ply_idriver_binary = {
1427
    {   ibinary_int8, ibinary_uint8, ibinary_int16, ibinary_uint16,
1428
        ibinary_int32, ibinary_uint32, ibinary_float32, ibinary_float64,
1429
        ibinary_int8, ibinary_uint8, ibinary_int16, ibinary_uint16,
1430
        ibinary_int32, ibinary_uint32, ibinary_float32, ibinary_float64
1431
    }, /* order matches e_ply_type enum */
1432
    ply_read_chunk,
1433
    "binary input"
1434
};
1435
 
1436
static t_ply_idriver ply_idriver_binary_reverse = {
1437
    {   ibinary_int8, ibinary_uint8, ibinary_int16, ibinary_uint16,
1438
        ibinary_int32, ibinary_uint32, ibinary_float32, ibinary_float64,
1439
        ibinary_int8, ibinary_uint8, ibinary_int16, ibinary_uint16,
1440
        ibinary_int32, ibinary_uint32, ibinary_float32, ibinary_float64
1441
    }, /* order matches e_ply_type enum */
1442
    ply_read_chunk_reverse,
1443
    "reverse binary input"
1444
};
1445
 
1446
static t_ply_odriver ply_odriver_ascii = {
1447
    {   oascii_int8, oascii_uint8, oascii_int16, oascii_uint16,
1448
        oascii_int32, oascii_uint32, oascii_float32, oascii_float64,
1449
        oascii_int8, oascii_uint8, oascii_int16, oascii_uint16,
1450
        oascii_int32, oascii_uint32, oascii_float32, oascii_float64
1451
    }, /* order matches e_ply_type enum */
1452
    NULL,
1453
    "ascii output"
1454
};
1455
 
1456
static t_ply_odriver ply_odriver_binary = {
1457
    {   obinary_int8, obinary_uint8, obinary_int16, obinary_uint16,
1458
        obinary_int32, obinary_uint32, obinary_float32, obinary_float64,
1459
        obinary_int8, obinary_uint8, obinary_int16, obinary_uint16,
1460
        obinary_int32, obinary_uint32, obinary_float32, obinary_float64
1461
    }, /* order matches e_ply_type enum */
1462
    ply_write_chunk,
1463
    "binary output"
1464
};
1465
 
1466
static t_ply_odriver ply_odriver_binary_reverse = {
1467
    {   obinary_int8, obinary_uint8, obinary_int16, obinary_uint16,
1468
        obinary_int32, obinary_uint32, obinary_float32, obinary_float64,
1469
        obinary_int8, obinary_uint8, obinary_int16, obinary_uint16,
1470
        obinary_int32, obinary_uint32, obinary_float32, obinary_float64
1471
    }, /* order matches e_ply_type enum */
1472
    ply_write_chunk_reverse,
1473
    "reverse binary output"
1474
};
1475
 
1476
/* ----------------------------------------------------------------------
1477
 * Copyright (C) 2003 Diego Nehab.  All rights reserved.
1478
 *
1479
 * Permission is hereby granted, free of charge, to any person obtaining
1480
 * a copy of this software and associated documentation files (the
1481
 * "Software"), to deal in the Software without restriction, including
1482
 * without limitation the rights to use, copy, modify, merge, publish,
1483
 * distribute, sublicense, and/or sell copies of the Software, and to
1484
 * permit persons to whom the Software is furnished to do so, subject to
1485
 * the following conditions:
1486
 *
1487
 * The above copyright notice and this permission notice shall be
1488
 * included in all copies or substantial portions of the Software.
1489
 *
1490
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1491
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1492
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
1493
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
1494
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
1495
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
1496
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1497
 * ---------------------------------------------------------------------- */