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


lvr2
Author(s): Thomas Wiemann , Sebastian Pütz , Alexander Mock , Lars Kiesow , Lukas Kalbertodt , Tristan Igelbrink , Johan M. von Behren , Dominik Feldschnieders , Alexander Löhr
autogenerated on Mon Feb 28 2022 22:46:09