📄 rply.c
字号:
/* ---------------------------------------------------------------------- * RPly library, read/write PLY files * Diego Nehab, Princeton University * http://www.cs.princeton.edu/~diego/professional/rply * * This library is distributed under the MIT License. See notice * at the end of this file. * ---------------------------------------------------------------------- */#include <stdio.h>#include <ctype.h>#include <assert.h>#include <string.h>#include <limits.h>#include <float.h>#include <stdarg.h>#include <stdlib.h>#include <stddef.h>#include "rply.h"/* ---------------------------------------------------------------------- * Constants * ---------------------------------------------------------------------- */#define WORDSIZE 256#define LINESIZE 1024#define BUFFERSIZE (8*1024)typedef enum e_ply_io_mode_ { PLY_READ, PLY_WRITE} e_ply_io_mode;static const char *const ply_storage_mode_list[] = { "binary_big_endian", "binary_little_endian", "ascii", NULL}; /* order matches e_ply_storage_mode enum */static const char *const ply_type_list[] = { "int8", "uint8", "int16", "uint16", "int32", "uint32", "float32", "float64", "char", "uchar", "short", "ushort", "int", "uint", "float", "double", "list", NULL}; /* order matches e_ply_type enum *//* ---------------------------------------------------------------------- * Property reading callback argument * * element: name of element being processed * property: name of property being processed * nelements: number of elements of this kind in file * instance_index: index current element of this kind being processed * length: number of values in current list (or 1 for scalars) * value_index: index of current value int this list (or 0 for scalars) * value: value of property * pdata/idata: user data defined with ply_set_cb * * Returns handle to ply file if succesful, NULL otherwise. * ---------------------------------------------------------------------- */typedef struct t_ply_argument_ { p_ply_element element; long instance_index; p_ply_property property; long length, value_index; double value; void *pdata; long idata;} t_ply_argument;/* ---------------------------------------------------------------------- * Property information * * name: name of this property * type: type of this property (list or type of scalar value) * length_type, value_type: type of list property count and values * read_cb: function to be called when this property is called * * Returns 1 if should continue processing file, 0 if should abort. * ---------------------------------------------------------------------- */typedef struct t_ply_property_ { char name[WORDSIZE]; e_ply_type type, value_type, length_type; p_ply_read_cb read_cb; void *pdata; long idata;} t_ply_property; /* ---------------------------------------------------------------------- * Element information * * name: name of this property * ninstances: number of elements of this type in file * property: property descriptions for this element * nproperty: number of properties in this element * * Returns 1 if should continue processing file, 0 if should abort. * ---------------------------------------------------------------------- */typedef struct t_ply_element_ { char name[WORDSIZE]; long ninstances; p_ply_property property; long nproperties;} t_ply_element;/* ---------------------------------------------------------------------- * Input/output driver * * Depending on file mode, different functions are used to read/write * property fields. The drivers make it transparent to read/write in ascii, * big endian or little endian cases. * ---------------------------------------------------------------------- */typedef int (*p_ply_ihandler)(p_ply ply, double *value);typedef int (*p_ply_ichunk)(p_ply ply, void *anydata, size_t size);typedef struct t_ply_idriver_ { p_ply_ihandler ihandler[16]; p_ply_ichunk ichunk; const char *name;} t_ply_idriver;typedef t_ply_idriver *p_ply_idriver;typedef int (*p_ply_ohandler)(p_ply ply, double value);typedef int (*p_ply_ochunk)(p_ply ply, void *anydata, size_t size);typedef struct t_ply_odriver_ { p_ply_ohandler ohandler[16]; p_ply_ochunk ochunk; const char *name;} t_ply_odriver;typedef t_ply_odriver *p_ply_odriver;/* ---------------------------------------------------------------------- * Ply file handle. * * io_mode: read or write (from e_ply_io_mode) * storage_mode: mode of file associated with handle (from e_ply_storage_mode) * element: elements description for this file * nelement: number of different elements in file * comment: comments for this file * ncomments: number of comments in file * obj_info: obj_info items for this file * nobj_infos: number of obj_info items in file * fp: file pointer associated with ply file * c: last character read from ply file * buffer: last word/chunck of data read from ply file * buffer_first, buffer_last: interval of untouched good data in buffer * buffer_token: start of parsed token (line or word) in buffer * idriver, odriver: input driver used to get property fields from file * argument: storage space for callback arguments * welement, wproperty: element/property type being written * winstance_index: index of instance of current element being written * wvalue_index: index of list property value being written * wlength: number of values in list property being written * error_cb: callback for error messages * ---------------------------------------------------------------------- */typedef struct t_ply_ { e_ply_io_mode io_mode; e_ply_storage_mode storage_mode; p_ply_element element; long nelements; char *comment; long ncomments; char *obj_info; long nobj_infos; FILE *fp; int c; char buffer[BUFFERSIZE]; size_t buffer_first, buffer_token, buffer_last; p_ply_idriver idriver; p_ply_odriver odriver; t_ply_argument argument; long welement, wproperty; long winstance_index, wvalue_index, wlength; p_ply_error_cb error_cb;} t_ply;/* ---------------------------------------------------------------------- * I/O functions and drivers * ---------------------------------------------------------------------- */static t_ply_idriver ply_idriver_ascii;static t_ply_idriver ply_idriver_binary;static t_ply_idriver ply_idriver_binary_reverse;static t_ply_odriver ply_odriver_ascii;static t_ply_odriver ply_odriver_binary;static t_ply_odriver ply_odriver_binary_reverse;static int ply_read_word(p_ply ply);static int ply_check_word(p_ply ply);static int ply_read_line(p_ply ply);static int ply_check_line(p_ply ply);static int ply_read_chunk(p_ply ply, void *anybuffer, size_t size);static int ply_read_chunk_reverse(p_ply ply, void *anybuffer, size_t size);static int ply_write_chunk(p_ply ply, void *anybuffer, size_t size);static int ply_write_chunk_reverse(p_ply ply, void *anybuffer, size_t size);static void ply_reverse(void *anydata, size_t size);/* ---------------------------------------------------------------------- * String functions * ---------------------------------------------------------------------- */static int ply_find_string(const char *item, const char* const list[]);static p_ply_element ply_find_element(p_ply ply, const char *name);static p_ply_property ply_find_property(p_ply_element element, const char *name);/* ---------------------------------------------------------------------- * Header parsing * ---------------------------------------------------------------------- */static int ply_read_header_format(p_ply ply);static int ply_read_header_comment(p_ply ply);static int ply_read_header_obj_info(p_ply ply);static int ply_read_header_property(p_ply ply);static int ply_read_header_element(p_ply ply);/* ---------------------------------------------------------------------- * Error handling * ---------------------------------------------------------------------- */static void ply_error_cb(const char *message);static void ply_error(p_ply ply, const char *fmt, ...);/* ---------------------------------------------------------------------- * Memory allocation and initialization * ---------------------------------------------------------------------- */static void ply_init(p_ply ply);static void ply_element_init(p_ply_element element);static void ply_property_init(p_ply_property property);static p_ply ply_alloc(void);static p_ply_element ply_grow_element(p_ply ply);static p_ply_property ply_grow_property(p_ply ply, p_ply_element element);static void *ply_grow_array(p_ply ply, void **pointer, long *nmemb, long size);/* ---------------------------------------------------------------------- * Special functions * ---------------------------------------------------------------------- */static e_ply_storage_mode ply_arch_endian(void);static int ply_type_check(void); /* ---------------------------------------------------------------------- * Auxiliary read functions * ---------------------------------------------------------------------- */static int ply_read_element(p_ply ply, p_ply_element element, p_ply_argument argument);static int ply_read_property(p_ply ply, p_ply_element element, p_ply_property property, p_ply_argument argument);static int ply_read_list_property(p_ply ply, p_ply_element element, p_ply_property property, p_ply_argument argument);static int ply_read_scalar_property(p_ply ply, p_ply_element element, p_ply_property property, p_ply_argument argument);/* ---------------------------------------------------------------------- * Buffer support functions * ---------------------------------------------------------------------- *//* pointers to tokenized word and line in buffer */#define BWORD(p) (p->buffer + p->buffer_token)#define BLINE(p) (p->buffer + p->buffer_token)/* pointer to start of untouched bytes in buffer */#define BFIRST(p) (p->buffer + p->buffer_first) /* number of bytes untouched in buffer */#define BSIZE(p) (p->buffer_last - p->buffer_first) /* consumes data from buffer */#define BSKIP(p, s) (p->buffer_first += s)/* refills the buffer */static int BREFILL(p_ply ply) { /* move untouched data to beginning of buffer */ size_t size = BSIZE(ply); memmove(ply->buffer, BFIRST(ply), size); ply->buffer_last = size; ply->buffer_first = ply->buffer_token = 0; /* fill remaining with new data */ size = fread(ply->buffer+size, 1, BUFFERSIZE-size-1, ply->fp); /* place sentinel so we can use str* functions with buffer */ ply->buffer[BUFFERSIZE-1] = '\0'; /* check if read failed */ if (size <= 0) return 0; /* increase size to account for new data */ ply->buffer_last += size; return 1;}/* ---------------------------------------------------------------------- * Exported functions * ---------------------------------------------------------------------- *//* ---------------------------------------------------------------------- * Read support functions * ---------------------------------------------------------------------- */p_ply ply_open(const char *name, p_ply_error_cb error_cb) { char magic[5] = " "; FILE *fp = NULL; p_ply ply = NULL; if (error_cb == NULL) error_cb = ply_error_cb; if (!ply_type_check()) { error_cb("Incompatible type system"); return NULL; } assert(name); fp = fopen(name, "rb"); if (!fp) { error_cb("Unable to open file"); return NULL; } if (fread(magic, 1, 4, fp) < 4) { error_cb("Error reading from file"); fclose(fp); return NULL; } if (strcmp(magic, "ply\n")) { fclose(fp); error_cb("Not a PLY file. Expected magic number 'ply\\n'"); return NULL; } ply = ply_alloc(); if (!ply) { error_cb("Out of memory"); fclose(fp); return NULL; } ply->fp = fp; ply->io_mode = PLY_READ; ply->error_cb = error_cb; return ply;}int ply_read_header(p_ply ply) { assert(ply && ply->fp && ply->io_mode == PLY_READ); if (!ply_read_word(ply)) return 0; /* parse file format */ if (!ply_read_header_format(ply)) { ply_error(ply, "Invalid file format"); return 0; } /* parse elements, comments or obj_infos until the end of header */ while (strcmp(BWORD(ply), "end_header")) { if (!ply_read_header_comment(ply) && !ply_read_header_element(ply) && !ply_read_header_obj_info(ply)) { ply_error(ply, "Unexpected token '%s'", BWORD(ply)); return 0; } } return 1;}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) { p_ply_element element = NULL; p_ply_property property = NULL; assert(ply && element_name && property_name); element = ply_find_element(ply, element_name); if (!element) return 0; property = ply_find_property(element, property_name); if (!property) return 0; property->read_cb = read_cb; property->pdata = pdata; property->idata = idata; return (int) element->ninstances;}int ply_read(p_ply ply) { long i; p_ply_argument argument; assert(ply && ply->fp && ply->io_mode == PLY_READ); argument = &ply->argument; /* for each element type */ for (i = 0; i < ply->nelements; i++) { p_ply_element element = &ply->element[i]; argument->element = element; if (!ply_read_element(ply, element, argument)) return 0; } return 1;}/* ----------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -