diff --git a/libpc/Makefile b/libpc/Makefile index c6a2461..d572228 100644 --- a/libpc/Makefile +++ b/libpc/Makefile @@ -24,6 +24,9 @@ clean: @rm -f $(OBJS) $(LIBPC_A) $(MAKE) -C cunit $@ +install: + @echo "No install target in libpc" + check: $(MAKE) -C cunit $@ diff --git a/libpc/cunit/cu_pc_patch.c b/libpc/cunit/cu_pc_patch.c index 122b9ed..5604b22 100644 --- a/libpc/cunit/cu_pc_patch.c +++ b/libpc/cunit/cu_pc_patch.c @@ -20,8 +20,9 @@ static int init_suite(void) { char *xmlstr = file_to_str(xmlfile); - schema = pc_schema_from_xml(xmlstr); + int rv = pc_schema_from_xml(xmlstr, &schema); pcfree(xmlstr); + if ( rv == PC_FAILURE ) return 1; return 0; } diff --git a/libpc/cunit/cu_pc_schema.c b/libpc/cunit/cu_pc_schema.c index a74169b..c4c494d 100644 --- a/libpc/cunit/cu_pc_schema.c +++ b/libpc/cunit/cu_pc_schema.c @@ -37,7 +37,7 @@ static void test_schema_from_xml() { char *xmlstr = file_to_str(xmlfile); - schema = pc_schema_from_xml(xmlstr); + int rv = pc_schema_from_xml(xmlstr, &schema); pcfree(xmlstr); // char *schemastr = pc_schema_to_json(schema); diff --git a/libpc/pc_api.h b/libpc/pc_api.h index 833ad23..15c30c6 100644 --- a/libpc/pc_api.h +++ b/libpc/pc_api.h @@ -188,7 +188,7 @@ void pc_install_default_handlers(void); /** Release the memory in a schema structure */ void pc_schema_free(PCSCHEMA *pcs); /** Build a schema structure from the XML serialisation */ -PCSCHEMA* pc_schema_from_xml(const char *xmlstr); +int pc_schema_from_xml(const char *xmlstr, PCSCHEMA **schema); /** Print out JSON readable format of schema */ char* pc_schema_to_json(const PCSCHEMA *pcs); /** Extract dimension information by position */ diff --git a/libpc/pc_schema.c b/libpc/pc_schema.c index 1f2344e..75f4ddb 100644 --- a/libpc/pc_schema.c +++ b/libpc/pc_schema.c @@ -198,7 +198,8 @@ pc_schema_calculate_byteoffsets(const PCSCHEMA *pcs) } /** Population a PCSCHEMA struct from the XML representation */ -PCSCHEMA* pc_schema_from_xml(const char *xml_str) +int +pc_schema_from_xml(const char *xml_str, PCSCHEMA **schema) { xmlDocPtr xml_doc = NULL; xmlNodePtr xml_root = NULL; @@ -206,18 +207,27 @@ PCSCHEMA* pc_schema_from_xml(const char *xml_str) xmlXPathContextPtr xpath_ctx; xmlXPathObjectPtr xpath_obj; xmlNodeSetPtr nodes; - PCSCHEMA *s = NULL; + PCSCHEMA *s; + const char *xml_ptr = xml_str; - size_t xml_size = strlen(xml_str); + /* Roll forward to start of XML string */ + while( (*xml_ptr != '\0') && (*xml_ptr != '<') ) + { + xml_ptr++; + } + + size_t xml_size = strlen(xml_ptr); static xmlChar *xpath_str = "/pc:PointCloudSchema/pc:dimension"; /* Parse XML doc */ + *schema = NULL; xmlInitParser(); - xml_doc = xmlReadMemory(xml_str, xml_size, NULL, NULL, 0); + xml_doc = xmlReadMemory(xml_ptr, xml_size, NULL, NULL, 0); if ( ! xml_doc ) { xmlCleanupParser(); - pcerror("unable to parse schema XML"); + pcwarn("unable to parse schema XML"); + return PC_FAILURE; } /* Capture the namespace */ @@ -231,7 +241,8 @@ PCSCHEMA* pc_schema_from_xml(const char *xml_str) { xmlFreeDoc(xml_doc); xmlCleanupParser(); - pcerror("unable to create new XPath context to read schema XML"); + pcwarn("unable to create new XPath context to read schema XML"); + return PC_FAILURE; } /* Register the root namespace if there is one */ @@ -245,7 +256,8 @@ PCSCHEMA* pc_schema_from_xml(const char *xml_str) xmlXPathFreeContext(xpath_ctx); xmlFreeDoc(xml_doc); xmlCleanupParser(); - pcerror("unable to evaluate xpath expression \"%s\" against schema XML", xpath_str); + pcwarn("unable to evaluate xpath expression \"%s\" against schema XML", xpath_str); + return PC_FAILURE; } /* Iterate on the dimensions we found */ @@ -254,6 +266,7 @@ PCSCHEMA* pc_schema_from_xml(const char *xml_str) int ndims = nodes->nodeNr; int i; s = pc_schema_new(ndims); + *schema = s; for ( i = 0; i < ndims; i++ ) { @@ -312,7 +325,9 @@ PCSCHEMA* pc_schema_from_xml(const char *xml_str) xmlXPathFreeContext(xpath_ctx); xmlFreeDoc(xml_doc); xmlCleanupParser(); - pcerror("schema dimension at position \"%d\" is declared twice", d->position + 1, ndims); + pc_schema_free(s); + pcwarn("schema dimension at position \"%d\" is declared twice", d->position + 1, ndims); + return PC_FAILURE; } s->dims[d->position] = d; d->size = pc_interpretation_size(d->interpretation); @@ -323,7 +338,13 @@ PCSCHEMA* pc_schema_from_xml(const char *xml_str) } else { + xmlXPathFreeObject(xpath_obj); + xmlXPathFreeContext(xpath_ctx); + xmlFreeDoc(xml_doc); + xmlCleanupParser(); + pc_schema_free(s); pcwarn("schema dimension states position \"%d\", but number of XML dimensions is \"%d\"", d->position + 1, ndims); + return PC_FAILURE; } } } @@ -338,7 +359,7 @@ PCSCHEMA* pc_schema_from_xml(const char *xml_str) xmlFreeDoc(xml_doc); xmlCleanupParser(); - return s; + return PC_SUCCESS; } uint32_t diff --git a/pgsql/pc_inout.c b/pgsql/pc_inout.c index f3022d6..d1034c7 100644 --- a/pgsql/pc_inout.c +++ b/pgsql/pc_inout.c @@ -48,15 +48,15 @@ Datum PC_SchemaIsValid(PG_FUNCTION_ARGS) bool valid; text *xml = PG_GETARG_TEXT_P(0); char *xmlstr = text_to_cstring(xml); - PCSCHEMA *schema = pc_schema_from_xml(xmlstr); + PCSCHEMA *schema; + int err = pc_schema_from_xml(xmlstr, &schema); pfree(xmlstr); - if ( ! schema ) + if ( ! err ) { - elog(NOTICE, "pc_schema_from_xml returned NULL"); PG_RETURN_BOOL(FALSE); } - + valid = pc_schema_is_valid(schema); PG_RETURN_BOOL(valid); } diff --git a/pgsql/pc_pgsql.c b/pgsql/pc_pgsql.c index 91e32e2..b773a01 100644 --- a/pgsql/pc_pgsql.c +++ b/pgsql/pc_pgsql.c @@ -136,11 +136,12 @@ pc_get_schema_by_id(uint32_t pcid) SPI_finish(); /* Build the schema object */ - schema = pc_schema_from_xml(xml); + err = pc_schema_from_xml(xml, &schema); - if ( ! schema ) + if ( ! err ) { elog(ERROR, "unable to parse XML representation of schema"); + return NULL; } return schema; diff --git a/pgsql/pointcloud--1.0.sql b/pgsql/pointcloud--1.0.sql index 381dffb..7b3e1c1 100644 --- a/pgsql/pointcloud--1.0.sql +++ b/pgsql/pointcloud--1.0.sql @@ -17,4 +17,54 @@ CREATE TABLE pointcloud_formats ( ); -- Register pointcloud_formats table so the contents are included in pg_dump output -SELECT pg_catalog.pg_extension_config_dump('pointcloud_formats', ''); \ No newline at end of file +SELECT pg_catalog.pg_extension_config_dump('pointcloud_formats', ''); + + + +-- Sample data +INSERT INTO pointcloud_formats (pcid, srid, schema) VALUES (1, 4326, ' + + + 1 + 4 + X coordinate as a long integer. You must use the scale and offset information of the header to determine the double value. + X + int32_t + 0.01 + + + 2 + 4 + Y coordinate as a long integer. You must use the scale and offset information of the header to determine the double value. + Y + int32_t + 0.01 + + + 3 + 4 + Z coordinate as a long integer. You must use the scale and offset information of the header to determine the double value. + Z + int32_t + 0.01 + + + 4 + 2 + The intensity value is the integer representation of the pulse return magnitude. This value is optional and system specific. However, it should always be included if available. + Intensity + uint16_t + 1 + + + + + + + + + + 4326 + + +'); \ No newline at end of file