22 #include "utils/builtins.h"
24 #include "../postgis_config.h"
26 #include "lwgeom_transform.h"
31 #define MARC21_NS ((char *) "http://www.loc.gov/MARC21/slim")
58 text *format_text_input = PG_GETARG_TEXT_P(1);
59 const char *format = text_to_cstring(format_text_input);
65 PG_FREE_IF_COPY(gs, 0);
66 lwpgerror(
"ST_AsMARC21: Input geometry has unknown (%d) SRID", srid);
71 if (lwproj_lookup(srid, srid, &lwproj) ==
LW_FAILURE) {
73 PG_FREE_IF_COPY(gs, 0);
74 lwpgerror(
"ST_AsMARC21: Failure reading projections from spatial_ref_sys.");
79 if (!lwproj_is_latlong(lwproj)) {
81 PG_FREE_IF_COPY(gs, 0);
82 lwpgerror(
"ST_AsMARC21: Unsupported SRID (%d). Only lon/lat coordinate systems are supported in MARC21/XML Documents.", srid);
90 if (marc21) PG_RETURN_TEXT_P(marc21);
107 POSTGIS_DEBUG(3,
"creating stringbuffer");
126 for (uint32_t i = 0; i < coll->
ngeoms; i++) {
166 POSTGIS_DEBUG(3,
" closing MARC21/XML record");
184 const char *dec_part = strchr(format,
'.');
185 if(!dec_part) dec_part = strchr(format,
',');
189 if (strcmp(format,
"hdddmmss") && strcmp(format,
"dddmmss")) {
197 const size_t dec_part_len = strlen(dec_part);
198 const size_t int_part_len = (size_t)(dec_part - format);
199 if(int_part_len == 0 || dec_part_len<2)
return LW_FALSE;
201 int_part = palloc(int_part_len + 1);
202 memcpy(int_part, &format[0], int_part_len);
203 int_part[int_part_len]=
'\0';
205 if (strcmp(int_part,
"hddd") && strcmp(int_part,
"ddd") &&
206 strcmp(int_part,
"hdddmm") && strcmp(int_part,
"dddmm") &&
207 strcmp(int_part,
"hdddmmss") && strcmp(int_part,
"dddmmss")) {
214 for (
size_t i = 1; i < dec_part_len; i++) {
216 if(dec_part[i]!=int_part[int_part_len-1]) {
233 char cardinal_direction;
234 char decimal_separator;
236 int degrees = (int) decimal_degrees;
237 double minutes = fabs((decimal_degrees-degrees)*60);
238 double seconds = fabs((minutes-(
int)minutes) *60);
240 int has_cardinal_direction = 0;
241 int num_decimals = 0;
242 char*
res = palloc(
sizeof(
char)*strlen(format)+2);
254 POSTGIS_DEBUGF(2,
"corner_to_subfield_sb called with coordinates: %f and format: %s",decimal_degrees,format);
256 if((
int)(seconds + 0.5)>=60) {
258 seconds = seconds-60;
259 minutes = minutes +1;
264 if(strchr(format,
'.')) {
265 num_decimals = strlen(strchr(format,
'.'))-1;
266 decimal_separator =
'.';
269 if(strchr(format,
',')) {
270 num_decimals = strlen(strchr(format,
','))-1;
271 decimal_separator =
',';
276 has_cardinal_direction = 1;
278 if(subfield==
'd'||subfield==
'e'){
280 if(decimal_degrees>0){
282 cardinal_direction=
'E';
286 cardinal_direction=
'W';
287 degrees=abs(degrees);
288 decimal_degrees= fabs(decimal_degrees);
293 if(subfield==
'f'||subfield==
'g'){
295 if(decimal_degrees>0){
297 cardinal_direction=
'N';
301 cardinal_direction=
'S';
302 degrees=abs(degrees);
303 decimal_degrees= fabs(decimal_degrees);
311 if(format[3+has_cardinal_direction]==
'.' || format[3+has_cardinal_direction]==
',' ) {
317 int pad_degrees = (int)strlen(format);
319 if(decimal_degrees <0 && decimal_degrees>-100) pad_degrees=strlen(format)+1;
321 if(has_cardinal_direction) pad_degrees=pad_degrees-1;
323 snprintf(
res,
buffer_size,
"%0*.*f",pad_degrees,num_decimals,decimal_degrees);
326 }
else if(format[5+has_cardinal_direction]==
'.' || format[5+has_cardinal_direction]==
',' ) {
333 if(minutes<10) pad_minutes = (int)strlen(format)-has_cardinal_direction-3;
335 snprintf(
res,
buffer_size,
"%.3d%0*.*f",degrees,pad_minutes,num_decimals,fabs(minutes));
339 else if(format[7+has_cardinal_direction]==
'.' || format[7+has_cardinal_direction]==
',') {
347 if(seconds<10) pad_seconds = (int) strlen(format)-has_cardinal_direction-5;
349 snprintf(
res,
buffer_size,
"%.3d%.2d%0*.*f",degrees,(
int)minutes,pad_seconds,num_decimals,fabs(seconds));
357 snprintf(
res,
buffer_size,
"%.3d%.2d%.2d",degrees,(
int)minutes,(
int)(seconds + 0.5));
362 if(decimal_separator==
','){
364 res[strlen(
res)-num_decimals-1] =
',';
368 if(has_cardinal_direction){
388 POSTGIS_DEBUG(2,
"gbox_to_marc21_sb called");
398 POSTGIS_DEBUG(2,
"=> gbox_to_marc21_sb returns LW_SUCCESS");
int32_t gserialized_get_srid(const GSERIALIZED *g)
Extract the SRID from the serialized form (it is packed into three bytes so this is a handy function)...
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
int lwgeom_is_collection(const LWGEOM *lwgeom)
Determine whether a LWGEOM contains sub-geometries or not This basically just checks that the struct ...
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
int lwgeom_calculate_gbox(const LWGEOM *lwgeom, GBOX *gbox)
Calculate bounding box of a geometry, automatically taking into account whether it is cartesian or ge...
#define LW_TRUE
Return types for functions with status returns.
#define SRID_UNKNOWN
Unknown SRID value.
This library is the generic geometry handling section of PostGIS.
void void lwerror(const char *fmt,...) __attribute__((format(printf
Write a notice out to the error handler.
lwvarlena_t * lwgeom_to_marc21(const LWGEOM *geom, const char *format)
static int corner_to_subfield_sb(stringbuffer_t *sb, double decimal_degrees, const char *format, char subfield)
static int gbox_to_marc21_sb(const GBOX box, const char *format, stringbuffer_t *sb)
PG_FUNCTION_INFO_V1(ST_AsMARC21)
static int is_format_valid(const char *format)
Datum ST_AsMARC21(PG_FUNCTION_ARGS)
static uint32_t lwgeom_get_type(const LWGEOM *geom)
Return LWTYPE number.
static int lwgeom_is_empty(const LWGEOM *geom)
Return true or false depending on whether a geometry is an "empty" geometry (no vertices members)
int stringbuffer_aprintf(stringbuffer_t *s, const char *fmt,...)
Appends a formatted string to the current string buffer, using the format and argument list provided.
lwvarlena_t * stringbuffer_getvarlenacopy(stringbuffer_t *s)
stringbuffer_t * stringbuffer_create(void)
Allocate a new stringbuffer_t.
void stringbuffer_destroy(stringbuffer_t *s)
Free the stringbuffer_t and all memory managed within it.