/* Test functions */
void test_ShpDumperCreate(void);
-void test_ShpDumperGeoMapRead(void);
-void test_ShpDumperFieldnameLimit(void);
+void test_ShpDumperDestroy(void);
+
+SHPDUMPERCONFIG *config;
+SHPDUMPERSTATE *state;
/*
** Called from test harness to register the tests in this file.
if (
(NULL == CU_add_test(pSuite, "test_ShpDumperCreate()", test_ShpDumperCreate)) ||
- (NULL == CU_add_test(pSuite, "test_ShpDumperGeoMapRead()", test_ShpDumperGeoMapRead)) ||
- (NULL == CU_add_test(pSuite, "test_ShpDumperFieldnameLimit()", test_ShpDumperFieldnameLimit))
+ (NULL == CU_add_test(pSuite, "test_ShpDumperDestroy()", test_ShpDumperDestroy))
)
{
CU_cleanup_registry();
}
void test_ShpDumperCreate(void)
-{
- SHPDUMPERCONFIG *config;
- SHPDUMPERSTATE *state;
-
+{
config = (SHPDUMPERCONFIG*)calloc(1, sizeof(SHPDUMPERCONFIG));
state = ShpDumperCreate(config);
CU_ASSERT_PTR_NOT_NULL(state);
CU_ASSERT_EQUAL(state->outtype, 's');
- free(state);
- free(config);
-}
-
-void ShpDumperGeoMapRead(char* filename, SHPDUMPERSTATE *state);
-
-void test_ShpDumperGeoMapRead(void)
-{
- SHPDUMPERSTATE *state;
-
- state = malloc(sizeof(SHPDUMPERSTATE));
- ShpDumperGeoMapRead("map.txt", state);
- CU_ASSERT_PTR_NOT_NULL(state->geo_map);
- CU_ASSERT_EQUAL(state->geo_map_size, 3);
- CU_ASSERT_STRING_EQUAL(state->geo_map[0], "0123456789toolong0");
- CU_ASSERT_STRING_EQUAL(state->geo_map[0] + strlen(state->geo_map[0]) + 1, "0123456780");
- CU_ASSERT_STRING_EQUAL(state->geo_map[1], "0123456789toolong1");
- CU_ASSERT_STRING_EQUAL(state->geo_map[1] + strlen(state->geo_map[1]) + 1, "0123456781");
- CU_ASSERT_STRING_EQUAL(state->geo_map[2], "0123456789toolong2");
- CU_ASSERT_STRING_EQUAL(state->geo_map[2] + strlen(state->geo_map[2]) + 1, "0123456782");
- free(*state->geo_map);
- free(state->geo_map);
- free(state);
}
-char* ShpDumperFieldnameLimit(char* ptr, SHPDUMPERSTATE *state);
-
-void test_ShpDumperFieldnameLimit(void)
+void test_ShpDumperDestroy(void)
{
- SHPDUMPERSTATE *state;
-
- state = malloc(sizeof(SHPDUMPERSTATE));
- ShpDumperGeoMapRead("map.txt", state);
- {
- char* from = "UNTOUCHED";
- char* to = ShpDumperFieldnameLimit(from, state);
- CU_ASSERT_STRING_EQUAL(from, to);
- free(to);
- }
- {
- char* from = "0123456789toolong1";
- char* to = ShpDumperFieldnameLimit(from, state);
- CU_ASSERT_STRING_EQUAL(to, "0123456781");
- free(to);
- }
- free(*state->geo_map);
- free(state->geo_map);
- free(state);
+ ShpDumperDestroy(state);
}
/* Prototypes */
-int reverse_points(int num_points, double *x, double *y, double *z, double *m);
-int is_clockwise(int num_points,double *x,double *y,double *z);
-int is_bigendian(void);
-SHPObject *create_point(SHPDUMPERSTATE *state, LWPOINT *lwpoint);
-SHPObject *create_multipoint(SHPDUMPERSTATE *state, LWMPOINT *lwmultipoint);
-SHPObject *create_polygon(SHPDUMPERSTATE *state, LWPOLY *lwpolygon);
-SHPObject *create_multipolygon(SHPDUMPERSTATE *state, LWMPOLY *lwmultipolygon);
-SHPObject *create_linestring(SHPDUMPERSTATE *state, LWLINE *lwlinestring);
-SHPObject *create_multilinestring(SHPDUMPERSTATE *state, LWMLINE *lwmultilinestring);
+static int reverse_points(int num_points, double *x, double *y, double *z, double *m);
+static int is_clockwise(int num_points,double *x,double *y,double *z);
+static int is_bigendian(void);
+static SHPObject *create_point(SHPDUMPERSTATE *state, LWPOINT *lwpoint);
+static SHPObject *create_multipoint(SHPDUMPERSTATE *state, LWMPOINT *lwmultipoint);
+static SHPObject *create_polygon(SHPDUMPERSTATE *state, LWPOLY *lwpolygon);
+static SHPObject *create_multipolygon(SHPDUMPERSTATE *state, LWMPOLY *lwmultipolygon);
+static SHPObject *create_linestring(SHPDUMPERSTATE *state, LWLINE *lwlinestring);
+static SHPObject *create_multilinestring(SHPDUMPERSTATE *state, LWMLINE *lwmultilinestring);
static const char *nullDBFValue(char fieldType);
-int getMaxFieldSize(PGconn *conn, char *schema, char *table, char *fname);
-int getTableInfo(SHPDUMPERSTATE *state);
-int projFileCreate(SHPDUMPERSTATE *state);
+static int getMaxFieldSize(PGconn *conn, char *schema, char *table, char *fname);
+static int getTableInfo(SHPDUMPERSTATE *state);
+static int projFileCreate(SHPDUMPERSTATE *state);
/**
* @brief Make appropriate formatting of a DBF value based on type.
}
-SHPObject *
+static SHPObject *
create_point(SHPDUMPERSTATE *state, LWPOINT *lwpoint)
{
SHPObject *obj;
return obj;
}
-SHPObject *
+static SHPObject *
create_multipoint(SHPDUMPERSTATE *state, LWMPOINT *lwmultipoint)
{
SHPObject *obj;
return obj;
}
-SHPObject *
+static SHPObject *
create_polygon(SHPDUMPERSTATE *state, LWPOLY *lwpolygon)
{
SHPObject *obj;
return obj;
}
-SHPObject *
+static SHPObject *
create_multipolygon(SHPDUMPERSTATE *state, LWMPOLY *lwmultipolygon)
{
SHPObject *obj;
return obj;
}
-SHPObject *
+static SHPObject *
create_linestring(SHPDUMPERSTATE *state, LWLINE *lwlinestring)
{
SHPObject *obj;
return obj;
}
-SHPObject *
+static SHPObject *
create_multilinestring(SHPDUMPERSTATE *state, LWMLINE *lwmultilinestring)
{
SHPObject *obj;
/*Reverse the clockwise-ness of the point list... */
-int
+static int
reverse_points(int num_points, double *x, double *y, double *z, double *m)
{
}
/* Return 1 if the points are in clockwise order */
-int
+static int
is_clockwise(int num_points, double *x, double *y, double *z)
{
int i;
* Return the maximum octet_length from given table.
* Return -1 on error.
*/
-int
+static int
getMaxFieldSize(PGconn *conn, char *schema, char *table, char *fname)
{
int size;
return size;
}
-int
+static int
is_bigendian(void)
{
int test = 1;
* If data is a table will use geometry_columns, if a query or view will read SRID from query output.
* @warning Will give warning and not output a .prj file if SRID is -1, Unknown, mixed SRIDS or not found in spatial_ref_sys. The dbf and shp will still be output.
*/
-int projFileCreate(SHPDUMPERSTATE *state)
+static int
+projFileCreate(SHPDUMPERSTATE *state)
{
FILE *fp;
char *pszFullname, *pszBasename;
{
snprintf(state->message, SHPDUMPERMSGLEN, _("WARNING: Could not execute prj query: %s"), PQresultErrorMessage(res));
PQclear(res);
+ free(query);
return SHPDUMPERWARN;
}
{
snprintf(state->message, SHPDUMPERMSGLEN, _("WARNING: Mixed set of spatial references. No prj file will be generated"));
PQclear(res);
+ free(query);
return SHPDUMPERWARN;
}
else
{
snprintf(state->message, SHPDUMPERMSGLEN, _("WARNING: Cannot determine spatial reference (empty table or unknown spatial ref). No prj file will be generated."));
PQclear(res);
+ free(query);
return SHPDUMPERWARN;
}
else
}
-int getTableInfo(SHPDUMPERSTATE *state)
+static int
+getTableInfo(SHPDUMPERSTATE *state)
{
/* Get some more information from the table:
config->geo_col_name = NULL;
config->keep_fieldname_case = 0;
config->fetchsize = 100;
- config->geo_map_filename = 0;
+ config->column_map_filename = NULL;
}
/**
* Read the content of filename into a symbol map stored
- * at state->geo_map.
+ * at state->column_map_filename.
*
- * The content of the file is lines of two symbols separated by
- * a single white space and no trailing or leading space:
+ * The content of the file is lines of two names separated by
+ * white space and no trailing or leading space:
*
- * VERYLONGSYMBOL SHORTONE\n
- * ANOTHERVERYLONGSYMBOL SHORTER\n
+ * COLUMNNAME DBFFIELD1
+ * AVERYLONGCOLUMNNAME DBFFIELD2
*
* etc.
*
- * The file is read in core (one large malloc'd area), each
- * space and newline is replaced by a null character. A pointer
- * to the start of each line is stored in the state->geo_map
- * table.
- *
* It is the reponsibility of the caller to reclaim the allocated space
* as follows:
*
- * free(*state->geo_map) to free the file content
- * free(state->geo_map) to free the pointer list
+ * free(state->column_map_pgfieldnames[]) to free the column names
+ * free(state->column_map_dbffieldnames[]) to free the dbf field names
*
- * @param filename : path to a readable map file in the format
- * described above.
- * @param state : container of state->geo_map where the malloc'd
+ * @param state : container of state->column_map where the malloc'd
* symbol map will be stored.
- *
- * @return state->geo_map : NULL on error, symbol map pointer on
- * success.
*/
-void
-ShpDumperGeoMapRead(char* filename, SHPDUMPERSTATE *state)
+static int
+read_column_map(SHPDUMPERSTATE *state)
{
- struct stat stat_buf;
- static char* content = 0;
+ FILE *fptr;
+ char linebuffer[1024];
+ char *tmpstr, *tmpptr;
+ int curmapsize, fieldnamesize;
+
+ /* Read column map file and load the column_map_dbffieldnames and column_map_pgfieldnames
+ arrays */
+ fptr = fopen(state->config->column_map_filename, "r");
+ if (!fptr)
{
- FILE* fp = 0;
- if(stat(filename, &stat_buf) < 0)
- {
- perror(filename);
- return;
- }
- content = malloc(stat_buf.st_size);
- fp = fopen(filename, "r");
- if(stat_buf.st_size != fread(content, 1, stat_buf.st_size, fp))
- {
- free(content);
- fprintf(stderr, "fread did not return the expected amount of chars");
- fclose(fp);
- return;
- }
- fclose(fp);
+ /* Return an error */
+ snprintf(state->message, SHPDUMPERMSGLEN, _("ERROR: Unable to open column map file %s"), state->config->column_map_filename);
+ return SHPDUMPERERR;
}
- {
- int i;
- state->geo_map_size = 0;
-
- for(i = 0; i < stat_buf.st_size; i++)
- {
- if(content[i] == '\n')
- {
- state->geo_map_size++;
- }
- }
- state->geo_map = (char**)malloc(sizeof(char*)*state->geo_map_size);
+
+ /* First count how many columns we have... */
+ while (fgets(linebuffer, 1024, fptr) != NULL)
+ state->column_map_size++;
+
+ /* Now we know the final size, allocate the arrays and load the data */
+ fseek(fptr, 0, SEEK_SET);
+ state->column_map_pgfieldnames = (char **)malloc(sizeof(char *) * state->column_map_size);
+ state->column_map_dbffieldnames = (char **)malloc(sizeof(char *) * state->column_map_size);
+
+ /* Read in a line at a time... */
+ curmapsize = 0;
+ while (fgets(linebuffer, 1024, fptr) != NULL)
+ {
+ /* Split into two separate strings - pgfieldname followed by dbffieldname */
+
+ /* First locate end of first column (pgfieldname) */
+ for (tmpptr = tmpstr = linebuffer; *tmpptr != '\t' && *tmpptr != '\n' && *tmpptr != ' ' && *tmpptr != '\0'; tmpptr++);
+ fieldnamesize = tmpptr - tmpstr;
+
+ /* Allocate memory and copy the string ensuring it is terminated */
+ state->column_map_pgfieldnames[curmapsize] = malloc(fieldnamesize + 1);
+ strncpy(state->column_map_pgfieldnames[curmapsize], tmpstr, fieldnamesize);
+ state->column_map_pgfieldnames[curmapsize][fieldnamesize] = '\0';
+
+ /* Now swallow up any whitespace */
+ for (tmpstr = tmpptr; *tmpptr == '\t' || *tmpptr == '\n' || *tmpptr == ' '; tmpptr++);
+
+ /* Finally locate end of second column (dbffieldname) */
+ for (tmpstr = tmpptr; *tmpptr != '\t' && *tmpptr != '\n' && *tmpptr != ' ' && *tmpptr != '\0'; tmpptr++);
+ fieldnamesize = tmpptr - tmpstr;
+
+ /* Allocate memory and copy the string ensuring it is terminated */
+ state->column_map_dbffieldnames[curmapsize] = malloc(fieldnamesize + 1);
+ strncpy(state->column_map_dbffieldnames[curmapsize], tmpstr, fieldnamesize);
+ state->column_map_dbffieldnames[curmapsize][fieldnamesize] = '\0';
+
+ /* Error out if the dbffieldname is > 10 chars */
+ if (strlen(state->column_map_dbffieldnames[curmapsize]) > 10)
{
- char** map = state->geo_map;
- *map = content;
- map++;
- for(i = 0; i < stat_buf.st_size; i++)
- {
- if(content[i] == '\n' && i + 1 < stat_buf.st_size)
- {
- *map = content + i + 1;
- map++;
- }
- if(content[i] == '\n' || content[i] == ' ')
- content[i] = '\0';
- }
+ snprintf(state->message, SHPDUMPERMSGLEN, _("ERROR: column map file specifies a DBF field name \"%s\" which is longer than 10 characters"), state->column_map_dbffieldnames[curmapsize]);
+ return SHPDUMPERERR;
}
+
+ curmapsize++;
}
+
+ fclose(fptr);
+
+ /* Done; return success */
+ return SHPDUMPEROK;
}
+
/* Create a new shapefile state object */
SHPDUMPERSTATE *
ShpDumperCreate(SHPDUMPERCONFIG *config)
state->schema = NULL;
state->table = NULL;
state->geo_col_name = NULL;
-
- if(config->geo_map_filename)
- {
- ShpDumperGeoMapRead(config->geo_map_filename, state);
- }
- else
- {
- state->geo_map = NULL;
- state->geo_map_size = 0;
- }
+ state->column_map_pgfieldnames = NULL;
+ state->column_map_dbffieldnames = NULL;
+ state->column_map_size = 0;
+
return state;
}
return SHPDUMPEROK;
}
-/**
- * Map a symbol into its 10 chars equivalent according to a map.
- * The map is found in state->geo_map and loaded with the -m option.
- *
- * @param ptr : null terminated string containing the symbol to
- * be mapped
- * @param state : non null state->geo_map container
- *
- * @return a malloc'd 10 chars symbol that is either the corresponding
- * symbol found in the state->geo_map or the symbol truncated
- * to its first 10 chars. The string is null terminated.
- */
-char*
-ShpDumperFieldnameLimit(char* ptr, SHPDUMPERSTATE *state)
-{
- /* Limit dbf field name to 10-digits */
- char* dbffieldname = malloc(11);
- if(state->geo_map)
- {
- int i;
- for(i=0; i<state->geo_map_size; i++)
- {
- if(!strcasecmp(state->geo_map[i], ptr))
- {
- /* the replacement follows the terminating null */
- ptr = state->geo_map[i] + strlen(state->geo_map[i]) + 1;
- break;
- }
- }
- }
- strncpy(dbffieldname, ptr, 10);
- dbffieldname[10] = '\0';
- return dbffieldname;
-}
/* Open the specified table in preparation for extracting rows */
int
int gidfound = 0, i, j, ret, status;
+ /* Open the column map if one was specified */
+ if (state->config->column_map_filename)
+ {
+ ret = read_column_map(state);
+ if (ret != SHPDUMPEROK)
+ return SHPDUMPERERR;
+ }
+
/* If a user-defined query has been specified, create and point the state to our new table */
if (state->config->usrquery)
{
*/
/* Limit dbf field name to 10-digits */
- dbffieldname = ShpDumperFieldnameLimit(ptr, state);
+ dbffieldname = malloc(11);
+ strncpy(dbffieldname, ptr, 10);
+ dbffieldname[10] = '\0';
+ /* If a column map file has been passed in, use this to create the dbf field name from
+ the PostgreSQL column name */
+ if (state->column_map_size > 0)
+ {
+ for (j = 0; j < state->column_map_size; j++)
+ {
+ if (!strcasecmp(state->column_map_pgfieldnames[j], dbffieldname))
+ {
+ strncpy(dbffieldname, state->column_map_dbffieldnames[j], 10);
+ dbffieldname[10] = '\0';
+ }
+ }
+ }
+
/*
* make sure the fields all have unique names,
*/
free(state->dbffieldtypes);
free(state->pgfieldnames);
+ /* Free any column map fieldnames if specified */
+ if (state->column_map_size > 0)
+ {
+ for (i = 0; i < state->column_map_size; i++)
+ {
+ if (state->column_map_pgfieldnames[i])
+ free(state->column_map_pgfieldnames[i]);
+
+ if (state->column_map_dbffieldnames[i])
+ free(state->column_map_dbffieldnames[i]);
+ }
+
+ free(state->column_map_pgfieldnames);
+ free(state->column_map_dbffieldnames);
+ }
+
/* Free other names */
if (state->table)
free(state->table);
if (state->schema)
free(state->schema);
+ if (state->geo_col_name)
+ free(state->geo_col_name);
/* Free the state itself */
free(state);