40 using std::ostringstream;
42 #include <curl/curl.h>
59 if ( stream == NULL ) {
65 std::string& str = *(
reinterpret_cast<std::string*
>( stream ) );
67 str.append( reinterpret_cast<const char*>(ptr), size*nmemb );
77 if ( stream == NULL ) {
83 std::string& str = *(
reinterpret_cast<std::string*
>( stream ) );
85 str.append( reinterpret_cast<const char*>(ptr), size*nmemb );
94 if ( curl_global_init( CURL_GLOBAL_ALL ) != CURLE_OK ) {
113 curl_global_cleanup();
132 CURL * curl_handle = curl_easy_init();
134 if ( curl_handle == NULL ) {
136 Log::instance()->
error(
"GbifOccurrences::load - Could not initialize curl handle\n" );
144 if ( curl_easy_setopt( curl_handle, CURLOPT_URL,
_source ) != CURLE_OK ) {
147 curl_easy_cleanup( curl_handle );
153 Log::instance()->
error(
"GbifOccurrences::load - Failed to set CURLOPT_HEADERFUNCTION\n" );
154 curl_easy_cleanup( curl_handle );
160 if ( curl_easy_setopt( curl_handle, CURLOPT_WRITEHEADER, &header ) != CURLE_OK ) {
162 Log::instance()->
error(
"GbifOccurrences::load - Failed to set CURLOPT_WRITEHEADER\n" );
163 curl_easy_cleanup( curl_handle );
169 Log::instance()->
error(
"GbifOccurrences::load - Failed to set CURLOPT_WRITEFUNCTION\n" );
170 curl_easy_cleanup( curl_handle );
174 std::string response;
176 if ( curl_easy_setopt( curl_handle, CURLOPT_WRITEDATA, &response ) != CURLE_OK ) {
178 Log::instance()->
error(
"GbifOccurrences::load - Failed to set CURLOPT_WRITEDATA\n" );
179 curl_easy_cleanup( curl_handle );
186 CURLcode curl_code = curl_easy_perform( curl_handle );
188 if ( curl_code != CURLE_OK )
190 Log::instance()->
error(
"GbifOccurrences::load - Could not get service info from the specified endpoint (CURL code error: %d)\n", curl_code );
191 curl_easy_cleanup( curl_handle );
195 curl_easy_cleanup( curl_handle );
198 if ( header.find(
"Content-Type: text/xml" ) == string::npos )
200 Log::instance()->
error(
"GbifOccurrences::load - URL does not seem to be a GBIF REST WS endpoint (HTTP Content-Type header is not text/xml)\n" );
219 Log::instance()->
error(
"GbifOccurrences::load - URL does not seem to be a GBIF WS REST endpoint (root element is not gbifResponse)\n" );
236 XML_Parser parser = XML_ParserCreateNS( NULL,
'/' );
240 Log::instance()->
error(
"Unable to allocate memory for capabilities response parser" );
248 XML_SetUserData( parser, info );
250 if ( ! XML_Parse( parser, xml->c_str(), xml->size(), 1 ) ) {
252 XML_Error error_code = XML_GetErrorCode( parser );
253 std::ostringstream errormsg;
254 errormsg << XML_ErrorString( error_code )
256 << XML_GetCurrentLineNumber( parser )
258 << XML_GetCurrentColumnNumber( parser )
261 Log::instance()->
error(
"XML Parser fatal error for capabilities response: %s\n", errormsg.str().c_str() );
262 XML_ParserFree( parser );
266 XML_ParserFree( parser );
282 if ( strncmp( el,
"http://portal.gbif.org/ws/response/gbif/gbifResponse", 52 ) == 0 ) {
287 else if ( strncmp( el,
"http://portal.gbif.org/ws/response/gbif/parameter", 49 ) == 0 ) {
289 bool is_maxresults =
false;
291 std::string value(
"");
293 for (
int i = 0; attr[i]; i += 2 ) {
296 if ( strncmp( attr[i],
"name", 4 ) == 0 ) {
298 if ( strncmp( attr[i+1],
"maxresults", 10 ) == 0 ) {
299 is_maxresults =
true;
302 else if ( strncmp( attr[i],
"value", 5 ) == 0 ) {
307 if ( is_maxresults ) {
312 XML_SetElementHandler( info.
_parser, NULL, NULL );
330 LstOccurrences::iterator ocs =
_presences.begin();
331 LstOccurrences::iterator end =
_presences.end();
333 while ( ocs != end ) {
337 if ( ! strcasecmp( groupId, oc->label() ) ) {
354 search_data.
_next = 0;
363 while ( search_data.
_next >= 0 ) {
385 CURL * curl_handle = curl_easy_init();
387 if ( curl_handle == NULL ) {
389 Log::instance()->
error(
"GbifOccurrences::_retrieveRecords - Could not initialize curl handle\n" );
396 std::ostringstream search_url;
398 search_url << source.c_str();
400 if ( source.find(
"?" ) != string::npos ) {
409 search_url <<
"startindex=" << data->
_next;
411 search_url <<
"&maxresults=" << limit;
414 #if LIBCURL_VERSION_NUM >= 0x070f04
415 search_url <<
"&scientificname=" << curl_easy_escape( curl_handle, data->
_occurrences->label(), 0 );
417 search_url <<
"&scientificname=" << curl_escape( data->
_occurrences->label(), 0 );
420 search_url <<
"&format=brief&coordinatestatus=true&coordinateissues=false";
427 if ( curl_easy_setopt( curl_handle, CURLOPT_URL, search_url.str().c_str() ) != CURLE_OK ) {
429 Log::instance()->
error(
"GbifOccurrences::_retrieveRecords - Failed to set CURLOPT_URL\n" );
430 curl_easy_cleanup( curl_handle );
436 Log::instance()->
error(
"GbifOccurrences::_retrieveRecords - Failed to set CURLOPT_HEADERFUNCTION\n" );
437 curl_easy_cleanup( curl_handle );
443 if ( curl_easy_setopt( curl_handle, CURLOPT_WRITEHEADER, &header ) != CURLE_OK ) {
445 Log::instance()->
error(
"GbifOccurrences::_retrieveRecords - Failed to set CURLOPT_WRITEHEADER\n" );
446 curl_easy_cleanup( curl_handle );
452 Log::instance()->
error(
"GbifOccurrences::_retrieveRecords - Failed to set CURLOPT_WRITEFUNCTION\n" );
453 curl_easy_cleanup( curl_handle );
457 std::string search_response;
459 if ( curl_easy_setopt( curl_handle, CURLOPT_WRITEDATA, &search_response ) != CURLE_OK ) {
461 Log::instance()->
error(
"GbifOccurrences::_retrieveRecords - Failed to set CURLOPT_WRITEDATA\n" );
462 curl_easy_cleanup( curl_handle );
466 Log::instance()->
info(
"Searching records using %s\n", search_url.str().c_str() );
469 CURLcode curl_code = curl_easy_perform( curl_handle );
471 if ( curl_code != CURLE_OK )
473 const char * error_msg = curl_easy_strerror( curl_code );
475 Log::instance()->
error(
"GbifOccurrences::_retrieveRecords - Could not search records from the specified GBIF endpoint (CURL error: %s)\n", error_msg );
477 curl_easy_cleanup( curl_handle );
481 curl_easy_cleanup( curl_handle );
484 if ( header.find(
"Content-Type: text/xml" ) == string::npos )
486 Log::instance()->
error(
"GbifOccurrences::_retrieveRecords - URL does not seem to be a GBIF WS REST endpoint (HTTP Content-Type header is not text/xml)\n" );
491 XML_Parser parser = XML_ParserCreateNS( NULL,
'/' );
503 XML_SetUserData( parser, data );
505 if ( ! XML_Parse( parser, search_response.c_str(), search_response.size(), 1 ) ) {
507 XML_Error error_code = XML_GetErrorCode( parser );
508 std::ostringstream errormsg;
509 errormsg << XML_ErrorString( error_code )
511 << XML_GetCurrentLineNumber( parser )
513 << XML_GetCurrentColumnNumber( parser )
516 Log::instance()->
error(
"XML Parser fatal error for search response: %s\n", errormsg.str().c_str() );
517 XML_ParserFree( parser );
521 XML_ParserFree( parser );
535 if ( strncmp( el,
"http://portal.gbif.org/ws/response/gbif/summary", 47 ) == 0 ) {
537 for (
int i = 0; attr[i]; i += 2 ) {
540 if ( strncmp( attr[i],
"next", 4 ) == 0 ) {
542 search_data.
_next = atoi( attr[i+1] );
547 else if ( strncmp( el,
"http://rs.tdwg.org/ontology/voc/TaxonOccurrence#/TaxonOccurrence", 64 ) == 0 ) {
549 for (
int i = 0; attr[i]; i += 2 ) {
552 if ( strncmp( attr[i],
"http://www.w3.org/1999/02/22-rdf-syntax-ns#/about", 49 ) == 0 ) {
559 else if ( strncmp( el,
"http://rs.tdwg.org/ontology/voc/TaxonOccurrence#/decimalLatitude", 64 ) == 0 ) {
564 else if ( strncmp( el,
"http://rs.tdwg.org/ontology/voc/TaxonOccurrence#/decimalLongitude", 65 ) == 0 ) {
577 if ( strncmp( el,
"http://rs.tdwg.org/ontology/voc/TaxonOccurrence#/TaxonOccurrence", 64 ) == 0 ) {
594 lt.append( value, len );
598 XML_SetCharacterDataHandler( search_data.
_parser, NULL );
610 lg.append( value, len );
614 XML_SetCharacterDataHandler( search_data.
_parser, NULL );
static void _endSearchElement(void *data, const char *el)
static OccurrencesReader * CreateOccurrencesReaderCallback(const char *source, const char *coordSystem)
LstOccurrences _presences
static size_t _curl_header_writer(void *ptr, size_t size, size_t nmemb, void *stream)
static Log * instance()
Returns the instance pointer, creating the object on the first call.
static size_t _curl_body_writer(void *ptr, size_t size, size_t nmemb, void *stream)
static void _startServiceInfoElement(void *data, const char *el, const char **attr)
void error(const char *format,...)
'Error' level.
static void _lgDataHandler(void *data, const char *value, int len)
static void _ltDataHandler(void *data, const char *value, int len)
OccurrencesPtr getPresences(const char *groupId)
bool _retrieveRecords(GbifRecordData *data, int limit)
GbifOccurrences(const char *url, const char *coordSystem)
bool _parseServiceInfo(const std::string *xml, ServiceInfo *info)
void info(const char *format,...)
'Info' level.
double Coord
Type of map coordinates.
static void _startSearchElement(void *data, const char *el, const char **attr)
OccurrencesPtr _occurrences