source: GTP/trunk/App/Demos/Vis/FriendlyCulling/Converter/rply.c @ 3357

Revision 3357, 50.2 KB checked in by mattausch, 15 years ago (diff)
Line 
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
28typedef enum e_ply_io_mode_ {
29    PLY_READ,
30    PLY_WRITE
31} e_ply_io_mode;
32
33static 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
37static 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 * ---------------------------------------------------------------------- */
59typedef struct t_ply_argument_ {
60    p_ply_element element;
61    long instance_index;
62    p_ply_property property;
63    long length, value_index;
64    double value;
65    void *pdata;
66    long idata;
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 * ---------------------------------------------------------------------- */
79typedef 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;
84    long idata;
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 * ---------------------------------------------------------------------- */
97typedef struct t_ply_element_ {
98    char name[WORDSIZE];
99    long ninstances;
100    p_ply_property property;
101    long nproperties;
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 * ---------------------------------------------------------------------- */
111typedef int (*p_ply_ihandler)(p_ply ply, double *value);
112typedef int (*p_ply_ichunk)(p_ply ply, void *anydata, size_t size);
113typedef struct t_ply_idriver_ {
114    p_ply_ihandler ihandler[16];
115    p_ply_ichunk ichunk;
116    const char *name;
117} t_ply_idriver;
118typedef t_ply_idriver *p_ply_idriver;
119
120typedef int (*p_ply_ohandler)(p_ply ply, double value);
121typedef int (*p_ply_ochunk)(p_ply ply, void *anydata, size_t size);
122typedef struct t_ply_odriver_ {
123    p_ply_ohandler ohandler[16];
124    p_ply_ochunk ochunk;
125    const char *name;
126} t_ply_odriver;
127typedef 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 * ---------------------------------------------------------------------- */
153typedef struct t_ply_ {
154    e_ply_io_mode io_mode;
155    e_ply_storage_mode storage_mode;
156    p_ply_element element;
157    long nelements;
158    char *comment;
159    long ncomments;
160    char *obj_info;
161    long nobj_infos;
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;
169    long welement, wproperty;
170    long winstance_index, wvalue_index, wlength;
171    p_ply_error_cb error_cb;
172} t_ply;
173
174/* ----------------------------------------------------------------------
175 * I/O functions and drivers
176 * ---------------------------------------------------------------------- */
177static t_ply_idriver ply_idriver_ascii;
178static t_ply_idriver ply_idriver_binary;
179static t_ply_idriver ply_idriver_binary_reverse;
180static t_ply_odriver ply_odriver_ascii;
181static t_ply_odriver ply_odriver_binary;
182static t_ply_odriver ply_odriver_binary_reverse;
183
184static int ply_read_word(p_ply ply);
185static int ply_check_word(p_ply ply);
186static int ply_read_line(p_ply ply);
187static int ply_check_line(p_ply ply);
188static int ply_read_chunk(p_ply ply, void *anybuffer, size_t size);
189static int ply_read_chunk_reverse(p_ply ply, void *anybuffer, size_t size);
190static int ply_write_chunk(p_ply ply, void *anybuffer, size_t size);
191static int ply_write_chunk_reverse(p_ply ply, void *anybuffer, size_t size);
192static void ply_reverse(void *anydata, size_t size);
193
194/* ----------------------------------------------------------------------
195 * String functions
196 * ---------------------------------------------------------------------- */
197static int ply_find_string(const char *item, const char* const list[]);
198static p_ply_element ply_find_element(p_ply ply, const char *name);
199static p_ply_property ply_find_property(p_ply_element element,
200        const char *name);
201
202/* ----------------------------------------------------------------------
203 * Header parsing
204 * ---------------------------------------------------------------------- */
205static int ply_read_header_format(p_ply ply);
206static int ply_read_header_comment(p_ply ply);
207static int ply_read_header_obj_info(p_ply ply);
208static int ply_read_header_property(p_ply ply);
209static int ply_read_header_element(p_ply ply);
210
211/* ----------------------------------------------------------------------
212 * Error handling
213 * ---------------------------------------------------------------------- */
214static void ply_error_cb(const char *message);
215static void ply_error(p_ply ply, const char *fmt, ...);
216
217/* ----------------------------------------------------------------------
218 * Memory allocation and initialization
219 * ---------------------------------------------------------------------- */
220static void ply_init(p_ply ply);
221static void ply_element_init(p_ply_element element);
222static void ply_property_init(p_ply_property property);
223static p_ply ply_alloc(void);
224static p_ply_element ply_grow_element(p_ply ply);
225static p_ply_property ply_grow_property(p_ply ply, p_ply_element element);
226static void *ply_grow_array(p_ply ply, void **pointer, long *nmemb, long size);
227
228/* ----------------------------------------------------------------------
229 * Special functions
230 * ---------------------------------------------------------------------- */
231static e_ply_storage_mode ply_arch_endian(void);
232static int ply_type_check(void);
233
234/* ----------------------------------------------------------------------
235 * Auxiliary read functions
236 * ---------------------------------------------------------------------- */
237static int ply_read_element(p_ply ply, p_ply_element element,
238        p_ply_argument argument);
239static int ply_read_property(p_ply ply, p_ply_element element,
240        p_ply_property property, p_ply_argument argument);
241static int ply_read_list_property(p_ply ply, p_ply_element element,
242        p_ply_property property, p_ply_argument argument);
243static 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 */
264static 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 * ---------------------------------------------------------------------- */
287p_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
324int 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
344long ply_set_read_cb(p_ply ply, const char *element_name,
345        const char* property_name, p_ply_read_cb read_cb,
346        void *pdata, long idata) {
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
360int ply_read(p_ply ply) {
361    long i;
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 * ---------------------------------------------------------------------- */
378p_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
411int ply_add_element(p_ply ply, const char *name, long ninstances) {
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
426int 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
444int 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
470int 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
478int 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
492int 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
506int ply_write_header(p_ply ply) {
507    long i, j;
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;
540error:
541    ply_error(ply, "Error writing to file");
542    return 0;
543}
544
545int 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;
557            ply->wlength = (long) value;
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
587int ply_close(p_ply ply) {
588    long i;
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 * ---------------------------------------------------------------------- */
616p_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
625int ply_get_element_info(p_ply_element element, const char** name,
626        long *ninstances) {
627    assert(element);
628    if (name) *name = element->name;
629    if (ninstances) *ninstances = (long) element->ninstances;
630    return 1;
631}
632
633p_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
642int 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
653const 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
661const 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 * ---------------------------------------------------------------------- */
672int ply_get_argument_element(p_ply_argument argument,
673        p_ply_element *element, long *instance_index) {
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
681int ply_get_argument_property(p_ply_argument argument,
682        p_ply_property *property, long *length, long *value_index) {
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
691int ply_get_argument_user_data(p_ply_argument argument, void **pdata,
692        long *idata) {
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
700double 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 * ---------------------------------------------------------------------- */
709static 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 */
723    argument->length = (long) length;
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 */
733    for (l = 0; l < (long) length; l++) {
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
751static 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
770static 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
778static int ply_read_element(p_ply ply, p_ply_element element,
779        p_ply_argument argument) {
780    long j, k;
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
797static 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
805static 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
818static 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
832static int ply_check_word(p_ply ply) {
833    if (strlen(BLINE(ply)) >= WORDSIZE) {
834        ply_error(ply, "Word too long");
835        return 0;
836    }
837    return 1;
838}
839
840static 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
885static int ply_check_line(p_ply ply) {
886    if (strlen(BLINE(ply)) >= LINESIZE) {
887        ply_error(ply, "Line too long");
888        return 0;
889    }
890    return 1;
891}
892
893static 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
928static 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
947static 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
966static 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
974static 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
980static 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
991static 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
1010static 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
1017static 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
1027static 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
1034static void *ply_grow_array(p_ply ply, void **pointer,
1035        long *nmemb, long size) {
1036    void *temp = *pointer;
1037    long count = *nmemb + 1;
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
1049static 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
1061static 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
1075static 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
1091static 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
1100static 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
1109static 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
1137static int ply_read_header_element(p_ply ply) {
1138    p_ply_element element = NULL;
1139    long dummy;
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;
1150    if (sscanf(BWORD(ply), "%ld", &dummy) != 1) {
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
1163static void ply_error_cb(const char *message) {
1164    fprintf(stderr, "RPly: %s\n", message);
1165}
1166
1167static 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
1176static e_ply_storage_mode ply_arch_endian(void) {
1177    unsigned long i = 1;
1178    unsigned char *s = (unsigned char *) &i;
1179    if (*s == 1) return PLY_LITTLE_ENDIAN;
1180    else return PLY_BIG_ENDIAN;
1181}
1182
1183static 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);
1188    assert(sizeof(long) == 4);
1189    assert(sizeof(unsigned long) == 4);
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;
1196    if (sizeof(long) != 4) return 0;
1197    if (sizeof(unsigned long) != 4) return 0;
1198    if (sizeof(float) != 4) return 0;
1199    if (sizeof(double) != 8) return 0;
1200    return 1;
1201}
1202
1203/* ----------------------------------------------------------------------
1204 * Output handlers
1205 * ---------------------------------------------------------------------- */
1206static 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
1211static 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
1216static 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
1221static 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
1226static 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
1231static 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
1236static 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
1241static 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
1246static 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
1252static 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
1258static 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
1264static 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
1270static int obinary_int32(p_ply ply, double value) {
1271    long int32 = (long) value;
1272    if (value > LONG_MAX || value < LONG_MIN) return 0;
1273    return ply->odriver->ochunk(ply, &int32, sizeof(int32));
1274}
1275
1276static int obinary_uint32(p_ply ply, double value) {
1277    unsigned long uint32 = (unsigned long) value;
1278    if (value > ULONG_MAX || value < 0) return 0;
1279    return ply->odriver->ochunk(ply, &uint32, sizeof(uint32));
1280}
1281
1282static 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
1288static int obinary_float64(p_ply ply, double value) {
1289    return ply->odriver->ochunk(ply, &value, sizeof(value));
1290}
1291
1292/* ----------------------------------------------------------------------
1293 * Input  handlers
1294 * ---------------------------------------------------------------------- */
1295static 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
1303static 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
1311static 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
1319static 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
1327static 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
1335static 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
1343static 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
1351static 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
1359static 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
1366static 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
1373static 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
1380static 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
1387static int ibinary_int32(p_ply ply, double *value) {
1388    long int32;
1389    if (!ply->idriver->ichunk(ply, &int32, sizeof(int32))) return 0;
1390    *value = int32;
1391    return 1;
1392}
1393
1394static int ibinary_uint32(p_ply ply, double *value) {
1395    unsigned long uint32;
1396    if (!ply->idriver->ichunk(ply, &uint32, sizeof(uint32))) return 0;
1397    *value = uint32;
1398    return 1;
1399}
1400
1401static 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
1409static int ibinary_float64(p_ply ply, double *value) {
1410    return ply->idriver->ichunk(ply, value, sizeof(double));
1411}
1412
1413/* ----------------------------------------------------------------------
1414 * Constants
1415 * ---------------------------------------------------------------------- */
1416static 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
1426static 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
1436static 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
1446static 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
1456static 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
1466static 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 * ---------------------------------------------------------------------- */
Note: See TracBrowser for help on using the repository browser.