/** * Writes a uint8_t value to the buffer */ void bytebuffer_append_bytebuffer(bytebuffer_t *write_to,bytebuffer_t *write_from ) { LWDEBUG(2,"bytebuffer_append_bytebuffer"); size_t size = bytebuffer_getlength(write_from); bytebuffer_makeroom(write_to, size); memcpy(write_to->writecursor, write_from->buf_start, size); write_to->writecursor += size; return; }
/** * Returns a new bytebuffer were both ingoing bytebuffers is merged. * Caller is responsible for freeing both incoming bytefyffers and resulting bytebuffer */ bytebuffer_t* bytebuffer_merge(bytebuffer_t **buff_array, int nbuffers) { size_t total_size = 0, current_size, acc_size = 0; int i; for ( i = 0; i < nbuffers; i++ ) { total_size += bytebuffer_getlength(buff_array[i]); } bytebuffer_t *res = bytebuffer_create_with_size(total_size); for ( i = 0; i < nbuffers; i++) { current_size = bytebuffer_getlength(buff_array[i]); memcpy(res->buf_start+acc_size, buff_array[i]->buf_start, current_size); acc_size += current_size; } res->writecursor = res->buf_start + total_size; res->readcursor = res->buf_start; return res; }
/** * Convert LWGEOM to a char* in TWKB format. Caller is responsible for freeing * the returned array. */ uint8_t* lwgeom_to_twkb_with_idlist(const LWGEOM *geom, int64_t *idlist, uint8_t variant, int8_t precision_xy, int8_t precision_z, int8_t precision_m, size_t *twkb_size) { LWDEBUGF(2, "Entered %s", __func__); LWDEBUGF(2, "variant value %x", variant); TWKB_GLOBALS tg; TWKB_STATE ts; uint8_t *twkb; memset(&ts, 0, sizeof(TWKB_STATE)); memset(&tg, 0, sizeof(TWKB_GLOBALS)); tg.variant = variant; tg.prec_xy = precision_xy; tg.prec_z = precision_z; tg.prec_m = precision_m; if ( idlist && ! lwgeom_is_collection(geom) ) { lwerror("Only collections can support ID lists"); return NULL; } if ( ! geom ) { LWDEBUG(4,"Cannot convert NULL into TWKB."); lwerror("Cannot convert NULL into TWKB"); return NULL; } ts.idlist = idlist; ts.header_buf = NULL; ts.geom_buf = bytebuffer_create(); lwgeom_write_to_buffer(geom, &tg, &ts); if ( twkb_size ) *twkb_size = bytebuffer_getlength(ts.geom_buf); twkb = ts.geom_buf->buf_start; lwfree(ts.geom_buf); return twkb; }
/** * Free the bytebuffer_t and all memory managed within it. */ void bytebuffer_destroy(bytebuffer_t *s) { LWDEBUG(2,"Entered bytebuffer_destroy"); LWDEBUGF(4,"The buffer has used %d bytes",bytebuffer_getlength(s)); if ( s->buf_start ) { LWDEBUGF(4,"let's free buf_start %p",s->buf_start); lwfree(s->buf_start); LWDEBUG(4,"buf_start is freed"); } if ( s ) { lwfree(s); LWDEBUG(4,"bytebuffer_t is freed"); } return; }
static int lwgeom_write_to_buffer(const LWGEOM *geom, TWKB_GLOBALS *globals, TWKB_STATE *parent_state) { int i, is_empty, has_z, has_m, ndims; size_t bbox_size = 0, optional_precision_byte = 0; uint8_t flag = 0, type_prec = 0; TWKB_STATE child_state; memset(&child_state, 0, sizeof(TWKB_STATE)); child_state.header_buf = bytebuffer_create_with_size(16); child_state.geom_buf = bytebuffer_create_with_size(64); child_state.idlist = parent_state->idlist; /* Read dimensionality from input */ has_z = lwgeom_has_z(geom); has_m = lwgeom_has_m(geom); ndims = lwgeom_ndims(geom); is_empty = lwgeom_is_empty(geom); /* Do we need extended precision? If we have a Z or M we do. */ optional_precision_byte = (has_z || has_m); /* Both X and Y dimension use the same precision */ globals->factor[0] = pow(10, globals->prec_xy); globals->factor[1] = globals->factor[0]; /* Z and M dimensions have their own precisions */ if ( has_z ) globals->factor[2] = pow(10, globals->prec_z); if ( has_m ) globals->factor[2 + has_z] = pow(10, globals->prec_m); /* Reset stats */ for ( i = 0; i < MAX_N_DIMS; i++ ) { /* Reset bbox calculation */ child_state.bbox_max[i] = INT64_MIN; child_state.bbox_min[i] = INT64_MAX; /* Reset acumulated delta values to get absolute values on next point */ child_state.accum_rels[i] = 0; } /* TYPE/PRECISION BYTE */ if ( abs(globals->prec_xy) > 7 ) lwerror("%s: X/Z precision cannot be greater than 7 or less than -7", __func__); /* Read the TWKB type number from the geometry */ TYPE_PREC_SET_TYPE(type_prec, lwgeom_twkb_type(geom)); /* Zig-zag the precision value before encoding it since it is a signed value */ TYPE_PREC_SET_PREC(type_prec, zigzag8(globals->prec_xy)); /* Write the type and precision byte */ bytebuffer_append_byte(child_state.header_buf, type_prec); /* METADATA BYTE */ /* Set first bit if we are going to store bboxes */ FIRST_BYTE_SET_BBOXES(flag, (globals->variant & TWKB_BBOX) && ! is_empty); /* Set second bit if we are going to store resulting size */ FIRST_BYTE_SET_SIZES(flag, globals->variant & TWKB_SIZE); /* There will be no ID-list (for now) */ FIRST_BYTE_SET_IDLIST(flag, parent_state->idlist && ! is_empty); /* Are there higher dimensions */ FIRST_BYTE_SET_EXTENDED(flag, optional_precision_byte); /* Empty? */ FIRST_BYTE_SET_EMPTY(flag, is_empty); /* Write the header byte */ bytebuffer_append_byte(child_state.header_buf, flag); /* EXTENDED PRECISION BYTE (OPTIONAL) */ /* If needed, write the extended dim byte */ if( optional_precision_byte ) { uint8_t flag = 0; if ( has_z && ( globals->prec_z > 7 || globals->prec_z < 0 ) ) lwerror("%s: Z precision cannot be negative or greater than 7", __func__); if ( has_m && ( globals->prec_m > 7 || globals->prec_m < 0 ) ) lwerror("%s: M precision cannot be negative or greater than 7", __func__); HIGHER_DIM_SET_HASZ(flag, has_z); HIGHER_DIM_SET_HASM(flag, has_m); HIGHER_DIM_SET_PRECZ(flag, globals->prec_z); HIGHER_DIM_SET_PRECM(flag, globals->prec_m); bytebuffer_append_byte(child_state.header_buf, flag); } /* It the geometry is empty, we're almost done */ if ( is_empty ) { /* If this output is sized, write the size of */ /* all following content, which is zero because */ /* there is none */ if ( globals->variant & TWKB_SIZE ) bytebuffer_append_byte(child_state.header_buf, 0); bytebuffer_append_bytebuffer(parent_state->geom_buf, child_state.header_buf); bytebuffer_destroy(child_state.header_buf); bytebuffer_destroy(child_state.geom_buf); return 0; } /* Write the TWKB into the output buffer */ lwgeom_to_twkb_buf(geom, globals, &child_state); /*If we have a header_buf, we know that this function is called inside a collection*/ /*and then we have to merge the bboxes of the included geometries*/ /*and put the result to the parent (the collection)*/ if( (globals->variant & TWKB_BBOX) && parent_state->header_buf ) { LWDEBUG(4,"Merge bboxes"); for ( i = 0; i < ndims; i++ ) { if(child_state.bbox_min[i]<parent_state->bbox_min[i]) parent_state->bbox_min[i] = child_state.bbox_min[i]; if(child_state.bbox_max[i]>parent_state->bbox_max[i]) parent_state->bbox_max[i] = child_state.bbox_max[i]; } } /* Did we have a box? If so, how big? */ bbox_size = 0; if( globals->variant & TWKB_BBOX ) { LWDEBUG(4,"We want boxes and will calculate required size"); bbox_size = sizeof_bbox(&child_state, ndims); } /* Write the size if wanted */ if( globals->variant & TWKB_SIZE ) { /* Here we have to add what we know will be written to header */ /* buffer after size value is written */ size_t size_to_register = bytebuffer_getlength(child_state.geom_buf); size_to_register += bbox_size; bytebuffer_append_uvarint(child_state.header_buf, size_to_register); } if( globals->variant & TWKB_BBOX ) write_bbox(&child_state, ndims); bytebuffer_append_bytebuffer(parent_state->geom_buf,child_state.header_buf); bytebuffer_append_bytebuffer(parent_state->geom_buf,child_state.geom_buf); bytebuffer_destroy(child_state.header_buf); bytebuffer_destroy(child_state.geom_buf); return 0; }