/* Copyright (C) 2004 HSA Systems, Sven Dowideit This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA */ #include "defs.h" #include "cet_util.h" #if HAVE_LIBEXPAT #include static XML_Parser psr; #endif static char *cdatastr; static int in_Route = 0; static int in_ChartWork = 0; static int in_Object = 0; static waypoint *wpt_tmp; static char *routeName = "ROUTENAME"; #define REPLACEMENT_SIRIUS_ATTR_SEPARATOR ';' #define ATTR_USRMRK "usrmrk" #define ATTR_OBJECTNAME "OBJNAM" #define ATTR_SHIPNAME "shpnam" static void readVersion4(gbfile* pFile); static void getAttr(const char *data, const char *attr, char **val, char seperator); static gbfile *fd; static gbfile *ofd; static arglist_t hsa_ndv_args[] = { ARG_TERMINATOR }; #define MYNAME "HsaNdv" #define MY_CBUF 4096 #define TRUE 1 #define FALSE 0 #if ! HAVE_LIBEXPAT static void hsa_ndv_rd_init(const char *fname) { fatal(MYNAME ": This build excluded HSA Endeavour support because expat was not installed.\n"); } static void hsa_ndv_read(void) { } #else static void hsa_ndv_start(void *data, const XML_Char *xml_el, const XML_Char **attr) { const char *el = xml_convert_to_char_string(xml_el); // printf("<%s>\n", el); if (strcmp(el, "Export") == 0) {//should only be one } else if (strcmp(el, "Route") == 0) { in_Route++; } else if (strcmp(el, "Chartwork") == 0) { in_ChartWork++; } else if (strcmp(el, "Object") == 0) { wpt_tmp = xcalloc(sizeof(*wpt_tmp), 1); wpt_tmp->altitude = unknown_alt; in_Object++; } //reset data :) memset(cdatastr,0, MY_CBUF); xml_free_converted_string(el); } static void hsa_ndv_end(void *data, const XML_Char *xml_el) { const char *el = xml_convert_to_char_string(xml_el); if (in_Route) { if (strcmp(el, "Version") == 0) {//don't really care } else if (strcmp(el, "Name") == 0) { routeName = xstrdup(cdatastr); } else if (strcmp(el, "LastModified") == 0) {//don't really care } if (in_Object) { if (strcmp(el, "ClassName") == 0) { } else if (strcmp(el, "Attr") == 0) { getAttr(cdatastr, ATTR_OBJECTNAME, &wpt_tmp->shortname, REPLACEMENT_SIRIUS_ATTR_SEPARATOR); getAttr(cdatastr, ATTR_USRMRK, &wpt_tmp->description, REPLACEMENT_SIRIUS_ATTR_SEPARATOR); } else if (strcmp(el, "LegAttr") == 0) { } else if (strcmp(el, "NumberOfVertexs") == 0) { } else if (strcmp(el, "Latitude") == 0) { wpt_tmp->latitude = atof(cdatastr); } else if (strcmp(el, "Longitude") == 0) { wpt_tmp->longitude = atof(cdatastr); } } } if (in_ChartWork) { if (strcmp(el, "Version") == 0) {//don't really care } if (in_Object) { if (strcmp(el, "ClassName") == 0) { // className = xstrdup(cdatastr); } else if (strcmp(el, "Attr") == 0) { //getAttr(cdatastr, ATTR_OBJECTNAME, &wpt_tmp->shortname, REPLACEMENT_SIRIUS_ATTR_SEPARATOR); //getAttr(cdatastr, ATTR_SHIPNAME, &wpt_tmp->description, REPLACEMENT_SIRIUS_ATTR_SEPARATOR); } else if (strcmp(el, "NumberOfVertexs") == 0) { } else if (strcmp(el, "Latitude") == 0) { wpt_tmp->latitude = atof(cdatastr); } else if (strcmp(el, "Longitude") == 0) { wpt_tmp->longitude = atof(cdatastr); } else if (strcmp(el, "Time") == 0) { wpt_tmp->creation_time = atoi(cdatastr); } } } //ignore everything else for now.. memset(cdatastr,0, MY_CBUF); if (strcmp(el, "Object") == 0) { if (in_Route) { waypt_add(wpt_tmp); } else if (in_ChartWork) { //TODO: not sure how i want to handle this.. } in_Object--; } else if (strcmp(el, "Route") == 0) { in_Route--; } else if (strcmp(el, "Chartwork") == 0) { in_ChartWork--; } xml_free_converted_string(el); } static void hsa_ndv_cdata(void *dta, const XML_Char *s, int len) { char *estr; estr = cdatastr + strlen(cdatastr); memcpy(estr, s, len); } static void hsa_ndv_rd_init(const char *fname) { fd = gbfopen(fname, "r", MYNAME); psr = XML_ParserCreate(NULL); if (!psr) { fatal(MYNAME ":Cannot create XML parser\n"); } XML_SetUnknownEncodingHandler(psr, cet_lib_expat_UnknownEncodingHandler, NULL); XML_SetElementHandler(psr, hsa_ndv_start, hsa_ndv_end); cdatastr = xcalloc(MY_CBUF,1); XML_SetCharacterDataHandler(psr, hsa_ndv_cdata); } static void hsa_ndv_read(void) { int len; char buf[MY_CBUF + 1]; while ((len = gbfread(buf, 1, sizeof(buf) - 1, fd))) { char *bad; buf[len] = '\0'; if (NULL != strstr(buf, "nver=1")) {//its the older format, not xml gbfseek(fd, 0, SEEK_SET); readVersion4(fd); break; } //grumble - have to remove \x1f's from sirius attributes bad = buf; while (NULL != (bad = strchr(bad, '\x1f'))) { *bad = REPLACEMENT_SIRIUS_ATTR_SEPARATOR; } if (!XML_Parse(psr, buf, len, gbfeof(fd))) { fatal(MYNAME ":Parse error at %d: %s\n", (int) XML_GetCurrentLineNumber(psr), XML_ErrorString(XML_GetErrorCode(psr))); } } XML_ParserFree(psr); } #endif static void getAttr(const char *data, const char *attr, char **val, char seperator) { char *start; if ((start = strstr(data, attr)) != NULL) { char *end; int len; end = strchr(start, seperator); if (end == NULL) { end = start + strlen(start);//assume we are teh last attr } len = end-start - strlen(attr); *val = xcalloc(len+1, 1); memcpy(*val, start+strlen(attr), len); (*val)[len] = '\0'; } else { *val = xcalloc(1, 1); (*val)[0] = '\0'; } } static void hsa_ndv_rd_deinit(void) { if ( cdatastr ) { xfree(cdatastr); } gbfclose(fd); } static void hsa_ndv_wr_init(const char *fname) { ofd = gbfopen(fname, "w", MYNAME); } static void hsa_ndv_wr_deinit(void) { gbfclose(ofd); } static int legNum = 0; static void hsa_ndv_waypt_pr(const waypoint *waypointp) { gbfprintf(ofd, "\t\t\n"); gbfprintf(ofd, "\t\t\twaypnt\n"); //ignore these for now, they are s57 specific // fprintf(ofd, "\t\t\t0\n"); // fprintf(ofd, "\t\t\t1\n"); // fprintf(ofd, "\t\t\t1089009023\n"); gbfprintf(ofd, "\t\t\t\n", routeName, waypointp->shortname, legNum, waypointp->description); gbfprintf(ofd, "\t\t\t\n", routeName); gbfprintf(ofd, "\t\t\t1\n"); gbfprintf(ofd, "\t\t\t%lf\n", waypointp->latitude); gbfprintf(ofd, "\t\t\t%lf\n", waypointp->longitude); gbfprintf(ofd, "\t\t\n"); legNum++; } static void hsa_ndv_write(void) { gbfprintf(ofd, "\n"); gbfprintf(ofd, "\n"); gbfprintf(ofd, "\t\n"); gbfprintf(ofd, "\t\t1.0000000\n"); gbfprintf(ofd, "\t\tROUTENAME\n"); /*TODO: used filename? */ gbfprintf(ofd, "\t\t0\n"); waypt_disp_all(hsa_ndv_waypt_pr); gbfprintf(ofd, "\t\n"); //later we'll import past tracks and chart objects? // fprintf(ofd, "\t\n"); // fprintf(ofd, "\t\t1.0000000\n"); // track_disp_all(hsa_ndv_track_pr); // fprintf(ofd, "\t\n"); gbfprintf(ofd, "\n"); } ff_vecs_t HsaEndeavourNavigator_vecs = { ff_type_file, FF_CAP_RW_WPT, hsa_ndv_rd_init, hsa_ndv_wr_init, hsa_ndv_rd_deinit, hsa_ndv_wr_deinit, hsa_ndv_read, hsa_ndv_write, NULL, hsa_ndv_args, CET_CHARSET_ASCII, 0 /* CET-REVIEW */ }; ////////////////////////////////////////////////////////////////////////// // older style Endeavour route export file //read DEC2000 NDV export files #define EF_RECORD_DELIMTER 0 #define ED_REC_NAME_SIZE 5 #define EF_NVER_REC "nver=" #define EF_LAT_REC "lati=" #define EF_LONG_REC "long=" #define EF_TIME_REC "time=" #define EF_ATTR_REC "attr=" #define EF_CLNM_REC "clnm=" #define INVALID_TIME -1L #define SOUNDARRAY_CHAR 'S' static int readRecord(gbfile* pFile, const char* pRecName, char *recData); static int readPositionRecord(gbfile* pFile, double* lat, double* lng, long* timeStamp); static void readVersion4(gbfile* pFile) { while( TRUE ) { char recData[256] = {0}; // get the position double lat2, lng2 = 0; // set the pointer to the time stamp depending // on whether we have a sounding array or not long ts1, ts2; long* pts1 = 0; long* pts2 = 0; int soundArray = FALSE; int numberOfVerticies = 0; char className[256]; char attr[1024]; int Vertex; memset(attr, 0, sizeof(attr)); wpt_tmp = xcalloc(sizeof(*wpt_tmp), 1); wpt_tmp->altitude = unknown_alt; // read the first record if( !readRecord( pFile, EF_NVER_REC, recData) ) // no first record then finished break; // get the type sscanf( (const char*)recData, "%d", &numberOfVerticies); // do we have a sounding array if( *((const char *)recData + strlen(recData) - 1) == SOUNDARRAY_CHAR ) { soundArray = TRUE; } if( soundArray ) { pts1 = &ts1; pts2 = &ts2; } // go through the vertices for( Vertex = 0; Vertex < numberOfVerticies; Vertex++) { // read vertex position if( !readPositionRecord( pFile, &lat2, &lng2, pts2) ) { xfree(wpt_tmp); return; } wpt_tmp->longitude = lng2; wpt_tmp->latitude = lat2; break;//TODO: ignore more points for now } // read the class name if( !readRecord( pFile, EF_CLNM_REC, className) ) { xfree( wpt_tmp ); return; } // read the attributes name if( !readRecord( pFile, EF_ATTR_REC, attr) ) { xfree( wpt_tmp ); return; } getAttr(attr, ATTR_OBJECTNAME, &wpt_tmp->shortname, '\x1f'); getAttr(attr, ATTR_USRMRK, &wpt_tmp->description, '\x1f'); { char *bad; //remove \n and \x1f from description data while (NULL != (bad = strchr(wpt_tmp->description, '\x1f'))) { *bad = REPLACEMENT_SIRIUS_ATTR_SEPARATOR; } while (NULL != (bad = strchr(wpt_tmp->description, '\n'))) { *bad = ' '; } while (NULL != (bad = strchr(wpt_tmp->description, '\r'))) { *bad = ' '; } } waypt_add(wpt_tmp); } gbfclose(pFile); return; } // read a record to a file static int readRecord(gbfile* pFile, const char* pRecName, char *recData) { // get the rec name int len; char recName[ED_REC_NAME_SIZE+1]; char arrRecData[256]; for( len = 0; len < ED_REC_NAME_SIZE; len++) { int c = gbfgetc(pFile); // if we hit EOF failed if( c == EOF ) return FALSE; recName[len] = c; } // if the record name is not the reqiured type then error if( strncmp( recName, pRecName, ED_REC_NAME_SIZE) != 0 ) return FALSE; // get the rec data for( len = 0; TRUE; len++) { int c = gbfgetc( pFile); // if we hit EOF failed if( c == EOF ) return FALSE; // hit end of line if( c == EF_RECORD_DELIMTER ) break; arrRecData[len] = c; } // get the rec data to a string strncpy(recData, arrRecData, len); return TRUE; } // read position static int readPositionRecord(gbfile* pFile, double* lat, double* lng, long* timeStamp) { // read the lat record char recData[256] = {0}; if( !readRecord( pFile, EF_LAT_REC, recData) ) // no lat record then finished return FALSE; // read the latitude sscanf( (const char*)recData, "%lf", lat); // read the lng record if( !readRecord( pFile, EF_LONG_REC, recData) ) // no first record then finished return FALSE; // read the latitude sscanf( (const char*)recData, "%lf", lng); // if we are to read a time record if( timeStamp ) { // read the lng record if( !readRecord( pFile, EF_TIME_REC, recData) ) // no first record then finished return FALSE; // read the latitude sscanf( (const char*)recData, "%ld", timeStamp); } return TRUE; }