/** Complete the byte offsets of dimensions from the ordered sizes */ static void pc_schema_calculate_byteoffsets(PCSCHEMA *pcs) { int i; size_t byteoffset = 0; for ( i = 0; i < pcs->ndims; i++ ) { if ( pcs->dims[i] ) { pcs->dims[i]->byteoffset = byteoffset; pcs->dims[i]->size = pc_interpretation_size(pcs->dims[i]->interpretation); byteoffset += pcs->dims[i]->size; } } pcs->size = byteoffset; }
static void test_dimension_byteoffsets() { PCDIMENSION *d; int i; int prev_byteoffset; int prev_size; int pc_size; for ( i = 0; i < schema->ndims; i++ ) { d = pc_schema_get_dimension(schema, i); // printf("d=%d name='%s' size=%d byteoffset=%d\n", i, d->name, d->size, d->byteoffset); if ( i > 0 ) { CU_ASSERT_EQUAL(prev_size, pc_size); CU_ASSERT_EQUAL(prev_size, d->byteoffset - prev_byteoffset); } prev_byteoffset = d->byteoffset; prev_size = d->size; pc_size = pc_interpretation_size(d->interpretation); } }
/** Population a PCSCHEMA struct from the XML representation */ int pc_schema_from_xml(const char *xml_str, PCSCHEMA **schema) { xmlDocPtr xml_doc = NULL; xmlNodePtr xml_root = NULL; xmlNsPtr xml_ns = NULL; xmlXPathContextPtr xpath_ctx; xmlXPathObjectPtr xpath_obj; xmlNodeSetPtr nodes; PCSCHEMA *s; const char *xml_ptr = 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"; static xmlChar *xpath_metadata_str = "/pc:PointCloudSchema/pc:metadata/Metadata"; /* Parse XML doc */ *schema = NULL; xmlInitParser(); xml_doc = xmlReadMemory(xml_ptr, xml_size, NULL, NULL, 0); if ( ! xml_doc ) { xmlCleanupParser(); pcwarn("unable to parse schema XML"); return PC_FAILURE; } /* Capture the namespace */ xml_root = xmlDocGetRootElement(xml_doc); if ( xml_root->ns ) xml_ns = xml_root->ns; /* Create xpath evaluation context */ xpath_ctx = xmlXPathNewContext(xml_doc); if( ! xpath_ctx ) { xmlFreeDoc(xml_doc); xmlCleanupParser(); pcwarn("unable to create new XPath context to read schema XML"); return PC_FAILURE; } /* Register the root namespace if there is one */ if ( xml_ns ) xmlXPathRegisterNs(xpath_ctx, "pc", xml_ns->href); /* Evaluate xpath expression */ xpath_obj = xmlXPathEvalExpression(xpath_str, xpath_ctx); if( ! xpath_obj ) { xmlXPathFreeContext(xpath_ctx); xmlFreeDoc(xml_doc); xmlCleanupParser(); pcwarn("unable to evaluate xpath expression \"%s\" against schema XML", xpath_str); return PC_FAILURE; } /* Iterate on the dimensions we found */ if ( nodes = xpath_obj->nodesetval ) { int ndims = nodes->nodeNr; int i; s = pc_schema_new(ndims); *schema = s; for ( i = 0; i < ndims; i++ ) { /* This is a "dimension" */ if( nodes->nodeTab[i]->type == XML_ELEMENT_NODE ) { xmlNodePtr cur = nodes->nodeTab[i]; xmlNodePtr child; PCDIMENSION *d = pc_dimension_new(); char xydim = 0; /* These are the values of the dimension */ for ( child = cur->children; child; child = child->next ) { if( child->type == XML_ELEMENT_NODE ) { if ( strcmp(child->name, "name") == 0 ) { if ( strcasecmp(child->children->content, "X") == 0 || strcasecmp(child->children->content, "Longitude") == 0 || strcasecmp(child->children->content, "Lon") == 0 ) { xydim = 'x'; } if ( strcasecmp(child->children->content, "Y") == 0 || strcasecmp(child->children->content, "Latitude") == 0 || strcasecmp(child->children->content, "Lat") == 0 ) { xydim = 'y'; } d->name = pcstrdup(child->children->content); } else if ( strcmp(child->name, "description") == 0 ) d->description = pcstrdup(child->children->content); else if ( strcmp(child->name, "size") == 0 ) d->size = atoi(child->children->content); else if ( strcmp(child->name, "active") == 0 ) d->active = atoi(child->children->content); else if ( strcmp(child->name, "position") == 0 ) d->position = atoi(child->children->content) - 1; else if ( strcmp(child->name, "interpretation") == 0 ) d->interpretation = pc_interpretation_number(child->children->content); else if ( strcmp(child->name, "scale") == 0 ) d->scale = atof(child->children->content); else if ( strcmp(child->name, "offset") == 0 ) d->offset = atof(child->children->content); else if ( strcmp(child->name, "uuid") == 0 ) /* Ignore this tag for now */ 1; else if ( strcmp(child->name, "parent_uuid") == 0 ) /* Ignore this tag for now */ 1; else pcinfo("unhandled schema type element \"%s\" encountered", child->name); } } /* Convert interprestation to size */ d->size = pc_interpretation_size(d->interpretation); /* Store the dimension in the schema */ if ( d->position >= 0 && d->position < ndims ) { if ( s->dims[d->position] ) { xmlXPathFreeObject(xpath_obj); xmlXPathFreeContext(xpath_ctx); xmlFreeDoc(xml_doc); xmlCleanupParser(); pc_schema_free(s); pcwarn("schema dimension at position \"%d\" is declared twice", d->position + 1, ndims); return PC_FAILURE; } if ( xydim == 'x' ) { s->x_position = d->position; } if ( xydim == 'y' ) { s->y_position = d->position; } pc_schema_set_dimension(s, d); } 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; } } } /* Complete the byte offsets of dimensions from the ordered sizes */ pc_schema_calculate_byteoffsets(s); /* Check X/Y positions */ pc_schema_check_xy(s); } xmlXPathFreeObject(xpath_obj); /* SEARCH FOR METADATA ENTRIES */ xpath_obj = xmlXPathEvalExpression(xpath_metadata_str, xpath_ctx); if( ! xpath_obj ) { xmlXPathFreeContext(xpath_ctx); xmlFreeDoc(xml_doc); xmlCleanupParser(); pcwarn("unable to evaluate xpath expression \"%s\" against schema XML", xpath_metadata_str); return PC_FAILURE; } /* Iterate on the <Metadata> we find */ if ( nodes = xpath_obj->nodesetval ) { int i; for ( i = 0; i < nodes->nodeNr; i++ ) { char *metadata_name = ""; char *metadata_value = ""; /* Read the metadata name and value from the node */ /* <Metadata name="somename">somevalue</Metadata> */ xmlNodePtr cur = nodes->nodeTab[i]; if( cur->type == XML_ELEMENT_NODE && strcmp(cur->name, "Metadata") == 0 ) { metadata_name = xmlGetProp(cur, "name"); metadata_value = xml_node_get_content(cur); } /* Store the compression type on the schema */ if ( strcmp(metadata_name, "compression") == 0 ) { int compression = pc_compression_number(metadata_value); if ( compression >= 0 ) { s->compression = compression; } } xmlFree(metadata_name); } } xmlXPathFreeObject(xpath_obj); xmlXPathFreeContext(xpath_ctx); xmlFreeDoc(xml_doc); xmlCleanupParser(); return PC_SUCCESS; }