1 /**********************************************************************
2 * $Id$
3 *
4 * Project: MapServer
5 * Purpose: OGR Output (for WFS)
6 * Author: Frank Warmerdam (warmerdam@pobox.com)
7 *
8 **********************************************************************
9 * Copyright (c) 2010, Frank Warmerdam <warmerdam@pobox.com>
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a
12 * copy of this software and associated documentation files (the "Software"),
13 * to deal in the Software without restriction, including without limitation
14 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 * and/or sell copies of the Software, and to permit persons to whom the
16 * Software is furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included in
19 * all copies of this Software or works derived from this Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 * DEALINGS IN THE SOFTWARE.
28 **********************************************************************/
29
30 #include <assert.h>
31 #include "mapserver.h"
32 #include "mapproject.h"
33 #include "mapthread.h"
34 #include "mapows.h"
35
36 #include "ogr_api.h"
37 #include "ogr_srs_api.h"
38 #include "cpl_conv.h"
39 #include "cpl_vsi.h"
40 #include "cpl_string.h"
41
42 #include <string>
43
44 /************************************************************************/
45 /* msInitDefaultOGROutputFormat() */
46 /************************************************************************/
47
msInitDefaultOGROutputFormat(outputFormatObj * format)48 int msInitDefaultOGROutputFormat( outputFormatObj *format )
49
50 {
51 OGRSFDriverH hDriver;
52
53 msOGRInitialize();
54
55 /* -------------------------------------------------------------------- */
56 /* check that this driver exists. Note visiting drivers should */
57 /* be pretty threadsafe so don't bother acquiring the GDAL */
58 /* lock. */
59 /* -------------------------------------------------------------------- */
60 hDriver = OGRGetDriverByName( format->driver+4 );
61 if( hDriver == NULL ) {
62 msSetError( MS_MISCERR, "No OGR driver named `%s' available.",
63 "msInitDefaultOGROutputFormat()", format->driver+4 );
64 return MS_FAILURE;
65 }
66
67 if( !OGR_Dr_TestCapability( hDriver, ODrCCreateDataSource ) ) {
68 msSetError( MS_MISCERR, "OGR `%s' driver does not support output.",
69 "msInitDefaultOGROutputFormat()", format->driver+4 );
70 return MS_FAILURE;
71 }
72
73 /* -------------------------------------------------------------------- */
74 /* Initialize the object. */
75 /* -------------------------------------------------------------------- */
76 format->imagemode = MS_IMAGEMODE_FEATURE;
77 format->renderer = MS_RENDER_WITH_OGR;
78
79 /* perhaps we should eventually hardcode mimetypes and extensions
80 for some formats? */
81
82 return MS_SUCCESS;
83 }
84
85 /************************************************************************/
86 /* msCSLConcatenate() */
87 /************************************************************************/
88
msCSLConcatenate(char ** papszResult,char ** papszToBeAdded)89 static char** msCSLConcatenate( char** papszResult, char** papszToBeAdded )
90 {
91 char** papszIter = papszToBeAdded;
92 while( papszIter && *papszIter )
93 {
94 papszResult = CSLAddString(papszResult, *papszIter);
95 papszIter ++;
96 }
97 return papszResult;
98 }
99
100 /************************************************************************/
101 /* msOGRRecursiveFileList() */
102 /* */
103 /* Collect a list of all files under the named directory, */
104 /* including those in subdirectories. */
105 /************************************************************************/
106
msOGRRecursiveFileList(const char * path)107 char **msOGRRecursiveFileList( const char *path )
108 {
109 char **file_list;
110 char **result_list = NULL;
111 int i, count, change;
112
113 file_list = CPLReadDir( path );
114 count = CSLCount(file_list);
115
116 /* -------------------------------------------------------------------- */
117 /* Sort the file list so we always get them back in the same */
118 /* order - it makes autotests more stable. */
119 /* -------------------------------------------------------------------- */
120 do {
121 change = 0;
122 for( i = 0; i < count-1; i++ ) {
123 if( strcasecmp(file_list[i],file_list[i+1]) > 0 ) {
124 char *temp = file_list[i];
125 file_list[i] = file_list[i+1];
126 file_list[i+1] = temp;
127 change = 1;
128 }
129 }
130 } while( change );
131
132 /* -------------------------------------------------------------------- */
133 /* collect names we want and process subdirectories. */
134 /* -------------------------------------------------------------------- */
135 for( i = 0; i < count; i++ ) {
136 char full_filename[MS_MAXPATHLEN];
137 VSIStatBufL sStatBuf;
138
139 if( EQUAL(file_list[i],".") || EQUAL(file_list[i],"..") )
140 continue;
141
142 strlcpy( full_filename,
143 CPLFormFilename( path, file_list[i], NULL ),
144 sizeof(full_filename) );
145
146 if( VSIStatL( full_filename, &sStatBuf ) != 0 )
147 continue;
148
149 if( VSI_ISREG( sStatBuf.st_mode ) ) {
150 result_list = CSLAddString( result_list, full_filename );
151 } else if( VSI_ISDIR( sStatBuf.st_mode ) ) {
152 char **subfiles = msOGRRecursiveFileList( full_filename );
153
154 result_list = msCSLConcatenate( result_list, subfiles );
155
156 CSLDestroy( subfiles );
157 }
158 }
159
160 CSLDestroy( file_list );
161
162 return result_list;
163 }
164
165 /************************************************************************/
166 /* msOGRCleanupDS() */
167 /************************************************************************/
msOGRCleanupDS(const char * datasource_name)168 static void msOGRCleanupDS( const char *datasource_name )
169
170 {
171 char **file_list;
172 char path[MS_MAXPATHLEN];
173 int i;
174 VSIStatBufL sStatBuf;
175
176 if( VSIStatL( datasource_name, &sStatBuf ) != 0 )
177 return;
178 if( VSI_ISDIR( sStatBuf.st_mode ) )
179 strlcpy( path, datasource_name, sizeof(path) );
180 else
181 strlcpy( path, CPLGetPath( datasource_name ), sizeof(path) );
182
183 file_list = CPLReadDir( path );
184
185 for( i = 0; file_list != NULL && file_list[i] != NULL; i++ ) {
186 char full_filename[MS_MAXPATHLEN];
187 VSIStatBufL sStatBuf;
188
189 if( EQUAL(file_list[i],".") || EQUAL(file_list[i],"..") )
190 continue;
191
192 strlcpy( full_filename,
193 CPLFormFilename( path, file_list[i], NULL ),
194 sizeof(full_filename) );
195
196 if( VSIStatL( full_filename, &sStatBuf ) != 0 )
197 continue;
198
199 if( VSI_ISREG( sStatBuf.st_mode ) ) {
200 VSIUnlink( full_filename );
201 } else if( VSI_ISDIR( sStatBuf.st_mode ) ) {
202 msOGRCleanupDS( full_filename );
203 }
204 }
205
206 CSLDestroy( file_list );
207
208 VSIRmdir( path );
209 }
210
211 /************************************************************************/
212 /* msOGRSetPoints() */
213 /************************************************************************/
214
msOGRSetPoints(OGRGeometryH hGeom,lineObj * line,int bWant2DOutput)215 static void msOGRSetPoints( OGRGeometryH hGeom, lineObj *line, int bWant2DOutput)
216 {
217 int i;
218 if( bWant2DOutput )
219 {
220 for( i = 0; i < line->numpoints; i++ ) {
221 OGR_G_SetPoint_2D( hGeom, i,
222 line->point[i].x,
223 line->point[i].y );
224 }
225 }
226 else {
227 for( i = 0; i < line->numpoints; i++ ) {
228 OGR_G_SetPoint( hGeom, i,
229 line->point[i].x,
230 line->point[i].y,
231 #ifdef USE_POINT_Z_M
232 line->point[i].z
233 #else
234 0.0
235 #endif
236 );
237 }
238 }
239 }
240
241 /************************************************************************/
242 /* msOGRWriteShape() */
243 /************************************************************************/
244
msOGRWriteShape(layerObj * map_layer,OGRLayerH hOGRLayer,shapeObj * shape,gmlItemListObj * item_list,int nFirstOGRFieldIndex,const char * pszFeatureid)245 static int msOGRWriteShape( layerObj *map_layer, OGRLayerH hOGRLayer,
246 shapeObj *shape, gmlItemListObj *item_list,
247 int nFirstOGRFieldIndex, const char *pszFeatureid )
248
249 {
250 OGRGeometryH hGeom = NULL;
251 OGRFeatureH hFeat;
252 OGRErr eErr;
253 int i, out_field;
254 OGRwkbGeometryType eLayerGType, eFlattenLayerGType;
255 OGRFeatureDefnH hLayerDefn;
256 int bWant2DOutput;
257
258 hLayerDefn = OGR_L_GetLayerDefn( hOGRLayer );
259 eLayerGType = OGR_FD_GetGeomType(hLayerDefn);
260 eFlattenLayerGType = wkbFlatten(eLayerGType);
261 bWant2DOutput = (eLayerGType == eFlattenLayerGType);
262
263 /* -------------------------------------------------------------------- */
264 /* Transform point geometry. */
265 /* -------------------------------------------------------------------- */
266 if( shape->type == MS_SHAPE_POINT ) {
267 OGRGeometryH hMP = NULL;
268 int j;
269
270 if( shape->numlines < 1 ) {
271 msSetError(MS_MISCERR,
272 "Failed on odd point geometry.",
273 "msOGRWriteShape()");
274 return MS_FAILURE;
275 }
276
277 if( shape->numlines == 1 && shape->line[0].numpoints > 1 )
278 {
279 hGeom = OGR_G_CreateGeometry( wkbMultiPoint );
280 for( j = 0; j < shape->line[0].numpoints; j++ ) {
281 OGRGeometryH hPoint = OGR_G_CreateGeometry( wkbPoint );
282 if( bWant2DOutput ) {
283 OGR_G_SetPoint_2D( hPoint, 0,
284 shape->line[0].point[j].x,
285 shape->line[0].point[j].y );
286 }
287 else {
288 OGR_G_SetPoint( hPoint, 0,
289 shape->line[0].point[j].x,
290 shape->line[0].point[j].y,
291 #ifdef USE_POINT_Z_M
292 shape->line[0].point[j].z
293 #else
294 0.0
295 #endif
296 );
297 }
298
299 OGR_G_AddGeometryDirectly( hGeom, hPoint );
300 }
301 }
302 else
303 {
304 if( shape->numlines > 1 )
305 hMP = OGR_G_CreateGeometry( wkbMultiPoint );
306
307 for( j = 0; j < shape->numlines; j++ ) {
308 if( shape->line[j].numpoints != 1 ) {
309 msSetError(MS_MISCERR,
310 "Failed on odd point geometry.",
311 "msOGRWriteShape()");
312 return MS_FAILURE;
313 }
314
315 hGeom = OGR_G_CreateGeometry( wkbPoint );
316 if( bWant2DOutput ) {
317 OGR_G_SetPoint_2D( hGeom, 0,
318 shape->line[j].point[0].x,
319 shape->line[j].point[0].y );
320 }
321 else {
322 OGR_G_SetPoint( hGeom, 0,
323 shape->line[j].point[0].x,
324 shape->line[j].point[0].y,
325 #ifdef USE_POINT_Z_M
326 shape->line[j].point[0].z
327 #else
328 0.0
329 #endif
330 );
331 }
332
333 if( hMP != NULL ) {
334 OGR_G_AddGeometryDirectly( hMP, hGeom );
335 }
336 }
337
338 if( hMP != NULL )
339 hGeom = hMP;
340 }
341 }
342
343 /* -------------------------------------------------------------------- */
344 /* Transform line geometry. */
345 /* -------------------------------------------------------------------- */
346 else if( shape->type == MS_SHAPE_LINE ) {
347 OGRGeometryH hML = NULL;
348 int j;
349
350 if( shape->numlines < 1 || shape->line[0].numpoints < 2 ) {
351 msSetError(MS_MISCERR,
352 "Failed on odd line geometry.",
353 "msOGRWriteShape()");
354 return MS_FAILURE;
355 }
356
357 if( shape->numlines > 1 )
358 hML = OGR_G_CreateGeometry( wkbMultiLineString );
359
360 for( j = 0; j < shape->numlines; j++ ) {
361 hGeom = OGR_G_CreateGeometry( wkbLineString );
362
363 msOGRSetPoints( hGeom, &(shape->line[j]), bWant2DOutput);
364
365 if( hML != NULL ) {
366 OGR_G_AddGeometryDirectly( hML, hGeom );
367 hGeom = hML;
368 }
369 }
370 }
371
372 /* -------------------------------------------------------------------- */
373 /* Transform polygon geometry. */
374 /* -------------------------------------------------------------------- */
375 else if( shape->type == MS_SHAPE_POLYGON ) {
376 int iRing, iOuter;
377 int *outer_flags;
378 OGRGeometryH hMP;
379
380 if( shape->numlines < 1 ) {
381 msSetError(MS_MISCERR,
382 "Failed on odd polygon geometry.",
383 "msOGRWriteShape()");
384 return MS_FAILURE;
385 }
386
387 outer_flags = msGetOuterList( shape );
388 hMP = OGR_G_CreateGeometry( wkbMultiPolygon );
389
390 for( iOuter = 0; iOuter < shape->numlines; iOuter++ ) {
391 int *inner_flags;
392 OGRGeometryH hRing;
393
394 if( !outer_flags[iOuter] )
395 continue;
396
397 hGeom = OGR_G_CreateGeometry( wkbPolygon );
398
399 /* handle outer ring */
400
401 hRing = OGR_G_CreateGeometry( wkbLinearRing );
402
403 msOGRSetPoints( hRing, &(shape->line[iOuter]), bWant2DOutput);
404
405 OGR_G_AddGeometryDirectly( hGeom, hRing );
406
407
408 /* handle inner rings (holes) */
409 inner_flags = msGetInnerList( shape, iOuter, outer_flags );
410
411 for( iRing = 0; iRing < shape->numlines; iRing++ ) {
412 if( !inner_flags[iRing] )
413 continue;
414
415 hRing = OGR_G_CreateGeometry( wkbLinearRing );
416
417 msOGRSetPoints( hRing, &(shape->line[iRing]), bWant2DOutput);
418
419 OGR_G_AddGeometryDirectly( hGeom, hRing );
420 }
421
422 free(inner_flags);
423
424 OGR_G_AddGeometryDirectly( hMP, hGeom );
425 }
426
427 free(outer_flags);
428
429 if( OGR_G_GetGeometryCount( hMP ) == 1 ) {
430 hGeom = OGR_G_Clone( OGR_G_GetGeometryRef( hMP, 0 ) );
431 OGR_G_DestroyGeometry( hMP );
432 } else {
433 hGeom = hMP;
434 }
435 }
436
437 /* -------------------------------------------------------------------- */
438 /* Consider trying to force the geometry to a new type if it */
439 /* doesn't match the layer. */
440 /* -------------------------------------------------------------------- */
441 if( hGeom != NULL ) {
442 OGRwkbGeometryType eFlattenFeatureGType =
443 wkbFlatten(OGR_G_GetGeometryType( hGeom ));
444
445 if( eFlattenFeatureGType != eFlattenLayerGType ) {
446 if( eFlattenLayerGType == wkbPolygon )
447 hGeom = OGR_G_ForceToPolygon( hGeom );
448
449 else if( eFlattenLayerGType == wkbMultiPolygon )
450 hGeom = OGR_G_ForceToMultiPolygon( hGeom );
451
452 else if( eFlattenLayerGType == wkbMultiPoint )
453 hGeom = OGR_G_ForceToMultiPoint( hGeom );
454
455 else if( eFlattenLayerGType == wkbMultiLineString )
456 hGeom = OGR_G_ForceToMultiLineString( hGeom );
457 }
458 }
459
460 /* -------------------------------------------------------------------- */
461 /* Consider flattening the geometry to 2D if we want 2D */
462 /* output. */
463 /* Note: this shouldn't be called in recent OGR versions where */
464 /* OGR_G_SetPoint_2D is properly honoured. */
465 /* -------------------------------------------------------------------- */
466
467 if( bWant2DOutput && hGeom != NULL ) {
468 OGRwkbGeometryType eFeatureGType = OGR_G_GetGeometryType( hGeom );
469 if( eFeatureGType != wkbFlatten(eFeatureGType) )
470 OGR_G_FlattenTo2D( hGeom );
471 }
472
473 /* -------------------------------------------------------------------- */
474 /* Create the feature, and attach the geometry. */
475 /* -------------------------------------------------------------------- */
476 hFeat = OGR_F_Create( hLayerDefn );
477
478 OGR_F_SetGeometryDirectly( hFeat, hGeom );
479
480 /* -------------------------------------------------------------------- */
481 /* Set attributes. */
482 /* -------------------------------------------------------------------- */
483 out_field = nFirstOGRFieldIndex;
484 for( i = 0; i < item_list->numitems; i++ ) {
485 gmlItemObj *item = item_list->items + i;
486
487 if(pszFeatureid && !strcmp(pszFeatureid, item->name)) {
488 char *endptr;
489 long feature_id = strtol(shape->values[i],&endptr,10);
490 if(endptr && *endptr==0) {
491 /* only set the featureid if it is numeric */
492 OGR_F_SetFID(hFeat, feature_id);
493 }
494 }
495
496 if( !item->visible )
497 continue;
498
499 /* Avoid setting empty strings for numeric fields, so that OGR */
500 /* doesn't take them as 0. (#4633) */
501 if( shape->values[i][0] == '\0' ) {
502 OGRFieldDefnH hFieldDefn = OGR_FD_GetFieldDefn(hLayerDefn, out_field);
503 OGRFieldType eFieldType = OGR_Fld_GetType(hFieldDefn);
504 if( eFieldType == OFTInteger || eFieldType == OFTReal
505 || eFieldType == OFTInteger64
506 )
507 {
508 out_field++;
509 continue;
510 }
511 }
512
513 OGR_F_SetFieldString( hFeat, out_field++, shape->values[i] );
514 }
515
516 /* -------------------------------------------------------------------- */
517 /* Write out and cleanup. */
518 /* -------------------------------------------------------------------- */
519 eErr = OGR_L_CreateFeature( hOGRLayer, hFeat );
520
521 OGR_F_Destroy( hFeat );
522
523 if( eErr != OGRERR_NONE ) {
524 msSetError( MS_OGRERR,
525 "Attempt to write feature failed (code=%d):\n%s",
526 "msOGRWriteShape()",
527 (int) eErr,
528 CPLGetLastErrorMsg() );
529 }
530
531 if( eErr == OGRERR_NONE )
532 return MS_SUCCESS;
533 else
534 return MS_FAILURE;
535 }
536
537 /************************************************************************/
538 /* msOGRStdoutWriteFunction() */
539 /************************************************************************/
540
541 /* Used by /vsistdout/ */
msOGRStdoutWriteFunction(const void * ptr,size_t size,size_t nmemb,FILE * stream)542 static size_t msOGRStdoutWriteFunction(const void* ptr, size_t size, size_t nmemb, FILE* stream)
543 {
544 msIOContext *ioctx = (msIOContext*) stream;
545 return msIO_contextWrite(ioctx, ptr, size * nmemb ) / size;
546 }
547
548 /************************************************************************/
549 /* msOGROutputGetAdditonalFiles() */
550 /* */
551 /* Collect additional files specified in */
552 /* wfs/ows_additional_files_in_output of WEB.METADATA and LAYER.METADATA */
553 /************************************************************************/
554
555 /* Result to be freed with CSLDestroy() */
msOGROutputGetAdditonalFiles(mapObj * map)556 static char** msOGROutputGetAdditonalFiles( mapObj *map )
557 {
558 int i;
559 hashTableObj* hSetAdditionalFiles;
560 char** papszFiles = NULL;
561
562 hSetAdditionalFiles = msCreateHashTable();
563
564 for( i = -1; i < map->numlayers; i++ )
565 {
566 const char* value;
567 if( i < 0 )
568 {
569 value = msOWSLookupMetadata(&(map->web.metadata), "FO", "additional_files_in_output");
570 }
571 else
572 {
573 layerObj *layer = GET_LAYER(map, i);
574 if( !layer->resultcache || layer->resultcache->numresults == 0 )
575 continue;
576 value = msOWSLookupMetadata(&(layer->metadata), "FO", "additional_files_in_output");
577 }
578
579 if( value != NULL )
580 {
581 char** papszList = CSLTokenizeString2( value, ",", CSLT_HONOURSTRINGS );
582 char** papszListIter = papszList;
583 while( papszListIter && *papszListIter )
584 {
585 const char* file = *papszListIter;
586 VSIStatBufL sStat;
587
588 if( strncmp(file, "http://", strlen("http://")) == 0 ||
589 strncmp(file, "https://", strlen("https://")) == 0 )
590 {
591 /* Remote file ? We will use /vsicurl_streaming/ to read it */
592 if( msLookupHashTable(hSetAdditionalFiles, file) == NULL )
593 {
594 msInsertHashTable(hSetAdditionalFiles, file, "YES");
595 papszFiles = CSLAddString(papszFiles, CPLSPrintf("/vsicurl_streaming/%s", file));
596 }
597 }
598 else
599 {
600 int nLen = (int)strlen(file);
601 char filename[MS_MAXPATHLEN];
602
603 if( CPLIsFilenameRelative(file) )
604 {
605 if( !map->shapepath )
606 msTryBuildPath(filename, map->mappath, file);
607 else
608 msTryBuildPath3(filename, map->mappath, map->shapepath, file);
609 }
610 else
611 strlcpy(filename, file, MS_MAXPATHLEN);
612
613 if( nLen > 2 && (
614 strcmp(file + nLen - 1, "/") == 0 ||
615 strcmp(file + nLen - 2, "/*") == 0 ) )
616 {
617 *strrchr(filename, '/') = '\0';
618 }
619 else if( nLen > 2 && (
620 strcmp(file + nLen - 1, "\\") == 0 ||
621 strcmp(file + nLen - 2, "\\*") == 0 ) )
622 {
623 *strrchr(filename, '\\') = '\0';
624 }
625
626 if( msLookupHashTable(hSetAdditionalFiles, filename) == NULL )
627 {
628 msInsertHashTable(hSetAdditionalFiles, filename, "YES");
629 if( VSIStatL( filename, &sStat ) == 0 )
630 {
631 if( VSI_ISDIR( sStat.st_mode ) )
632 {
633 char** papszDirContent = msOGRRecursiveFileList(filename);
634 papszFiles = msCSLConcatenate(papszFiles, papszDirContent);
635 CSLDestroy(papszDirContent);
636 }
637 else
638 {
639 papszFiles = CSLAddString(papszFiles, filename);
640 }
641 }
642 else
643 {
644 msDebug("File %s does not exist.\n", filename);
645 }
646 }
647 }
648
649 papszListIter ++;
650 }
651 CSLDestroy(papszList);
652 }
653 }
654
655 msFreeHashTable(hSetAdditionalFiles);
656
657 return papszFiles;
658 }
659
660 /************************************************************************/
661 /* msOGRWriteFromQuery() */
662 /************************************************************************/
663
msOGRWriteFromQuery(mapObj * map,outputFormatObj * format,int sendheaders)664 int msOGRWriteFromQuery( mapObj *map, outputFormatObj *format, int sendheaders )
665
666 {
667 /* -------------------------------------------------------------------- */
668 /* Variable declarations. */
669 /* -------------------------------------------------------------------- */
670 OGRSFDriverH hDriver;
671 OGRDataSourceH hDS;
672 const char *storage;
673 const char *fo_filename;
674 const char *form;
675 char datasource_name[MS_MAXPATHLEN];
676 char base_dir[MS_MAXPATHLEN];
677 char *request_dir = NULL;
678 char **ds_options = NULL;
679 char **layer_options = NULL;
680 char **file_list = NULL;
681 int iLayer, i;
682 int bDataSourceNameIsRequestDir = FALSE;
683 int bUseFeatureId = MS_FALSE;
684 const char* pszMatchingFeatures;
685 int nMatchingFeatures = -1;
686 const char* pszFormatName = format->driver+4;
687
688 pszMatchingFeatures = msGetOutputFormatOption(format, "_matching_features_", "");
689 if( pszMatchingFeatures[0] != '\0' )
690 nMatchingFeatures = atoi(pszMatchingFeatures);
691
692 /* -------------------------------------------------------------------- */
693 /* Fetch the output format driver. */
694 /* -------------------------------------------------------------------- */
695 msOGRInitialize();
696
697 hDriver = OGRGetDriverByName( pszFormatName );
698 if( hDriver == NULL ) {
699 msSetError( MS_MISCERR, "No OGR driver named `%s' available.",
700 "msOGRWriteFromQuery()", pszFormatName );
701 return MS_FAILURE;
702 }
703
704 /* -------------------------------------------------------------------- */
705 /* Capture datasource and layer creation options. */
706 /* -------------------------------------------------------------------- */
707 for( i=0; i < format->numformatoptions; i++ ) {
708 if( strncasecmp(format->formatoptions[i],"LCO:",4) == 0 )
709 layer_options = CSLAddString( layer_options,
710 format->formatoptions[i] + 4 );
711 if( strncasecmp(format->formatoptions[i],"DSCO:",5) == 0 )
712 ds_options = CSLAddString( ds_options,
713 format->formatoptions[i] + 5 );
714 }
715 if( EQUAL(pszFormatName, "GeoJSON") && nMatchingFeatures >= 0 )
716 {
717 const char* pszNativeData =
718 CSLFetchNameValueDef(layer_options, "NATIVE_DATA", "{}");
719 if( pszNativeData[strlen(pszNativeData)-1] == '}' )
720 {
721 std::string tmpl(pszNativeData);
722 tmpl.resize(tmpl.size() - 1);
723 if( strlen(pszNativeData) > 2 )
724 tmpl += ',';
725 tmpl += "\"numberMatched\":";
726 tmpl += std::to_string(nMatchingFeatures);
727 tmpl += '}';
728 layer_options = CSLSetNameValue(layer_options,
729 "NATIVE_MEDIA_TYPE",
730 "application/vnd.geo+json");
731 layer_options = CSLSetNameValue(layer_options,
732 "NATIVE_DATA",
733 tmpl.c_str());
734 }
735 }
736 if(!strcasecmp("true",msGetOutputFormatOption(format,"USE_FEATUREID","false"))) {
737 bUseFeatureId = MS_TRUE;
738 }
739
740 /* ==================================================================== */
741 /* Determine the output datasource name to use. */
742 /* ==================================================================== */
743 storage = msGetOutputFormatOption( format, "STORAGE", "filesystem" );
744 if( EQUAL(storage,"stream") && !msIO_isStdContext() ) {
745 msIOContext *ioctx = msIO_getHandler (stdout);
746 if( ioctx != NULL )
747 VSIStdoutSetRedirection( msOGRStdoutWriteFunction, (FILE*)ioctx );
748 else
749 /* bug #4858, streaming output won't work if standard output has been
750 * redirected, we switch to memory output in this case
751 */
752 storage = "memory";
753 }
754
755 /* -------------------------------------------------------------------- */
756 /* Where are we putting stuff? */
757 /* -------------------------------------------------------------------- */
758 if( EQUAL(storage,"filesystem") ) {
759 base_dir[0] = '\0' ;
760 } else if( EQUAL(storage,"memory") ) {
761 strcpy( base_dir, "/vsimem/ogr_out/" );
762 } else if( EQUAL(storage,"stream") ) {
763 /* handled later */
764 } else {
765 msSetError( MS_MISCERR,
766 "STORAGE=%s value not supported.",
767 "msOGRWriteFromQuery()",
768 storage );
769 CSLDestroy(layer_options);
770 CSLDestroy(ds_options);
771 return MS_FAILURE;
772 }
773
774 /* -------------------------------------------------------------------- */
775 /* Create a subdirectory to handle this request. */
776 /* -------------------------------------------------------------------- */
777 if( !EQUAL(storage,"stream") ) {
778 const char* dir_to_create;
779 if (strlen(base_dir) > 0)
780 request_dir = msTmpFile(map, NULL, base_dir, "" );
781 else
782 request_dir = msTmpFile(map, NULL, NULL, "" );
783
784 if( request_dir[strlen(request_dir)-1] == '.' )
785 request_dir[strlen(request_dir)-1] = '\0';
786
787 dir_to_create = request_dir;
788 /* Workaround issue in GDAL versions released at this time :
789 * GDAL issue fixed per https://trac.osgeo.org/gdal/ticket/6991 */
790 if( EQUAL(storage,"memory") && EQUAL(format->driver+4, "ESRI Shapefile") )
791 {
792 dir_to_create = base_dir;
793 }
794
795 if( VSIMkdir( dir_to_create, 0777 ) != 0 ) {
796 msSetError( MS_MISCERR,
797 "Attempt to create directory '%s' failed.",
798 "msOGRWriteFromQuery()",
799 dir_to_create );
800 msFree(request_dir);
801 CSLDestroy(layer_options);
802 CSLDestroy(ds_options);
803 return MS_FAILURE;
804 }
805 }
806 /* else handled later */
807
808 /* -------------------------------------------------------------------- */
809 /* Setup the full datasource name. */
810 /* -------------------------------------------------------------------- */
811 form = msGetOutputFormatOption( format, "FORM", "zip" );
812
813 if( EQUAL(form,"zip") )
814 fo_filename = msGetOutputFormatOption( format, "FILENAME", "result.zip" );
815 else
816 fo_filename = msGetOutputFormatOption( format, "FILENAME", "result.dat" );
817
818 /* Validate that the filename does not contain any directory */
819 /* information, which might lead to removal of unwanted files. (#4086) */
820 if( strchr(fo_filename, '/') != NULL || strchr(fo_filename, ':') != NULL ||
821 strchr(fo_filename, '\\') != NULL ) {
822 msSetError( MS_MISCERR,
823 "Invalid value for FILENAME option. "
824 "It must not contain any directory information.",
825 "msOGRWriteFromQuery()" );
826 msFree(request_dir);
827 CSLDestroy(layer_options);
828 CSLDestroy(ds_options);
829 return MS_FAILURE;
830 }
831
832 if( !EQUAL(storage,"stream") )
833 {
834 msBuildPath( datasource_name, request_dir, fo_filename );
835
836 if( EQUAL(form,"zip") )
837 {
838 /* if generating a zip file, remove the zip extension for the internal */
839 /* filename */
840 if( EQUAL(CPLGetExtension(datasource_name), "zip") ) {
841 *strrchr(datasource_name, '.') = '\0';
842 }
843
844 /* and add .dat extension if user didn't provide another extension */
845 if( EQUAL(CPLGetExtension(datasource_name), "") ) {
846 strcat(datasource_name, ".dat");
847 }
848 }
849
850 /* Shapefile and MapInfo driver only properly work with multiple layers */
851 /* if the output dataset name is a directory */
852 if( EQUAL(format->driver+4, "ESRI Shapefile") ||
853 EQUAL(format->driver+4, "MapInfo File") )
854 {
855 bDataSourceNameIsRequestDir = TRUE;
856 strcpy(datasource_name, request_dir);
857 }
858 }
859 else
860 strcpy( datasource_name, "/vsistdout/" );
861
862 msFree( request_dir );
863 request_dir = NULL;
864
865 /* -------------------------------------------------------------------- */
866 /* Emit content type headers for stream output now. */
867 /* -------------------------------------------------------------------- */
868 if( EQUAL(storage,"stream") ) {
869 if( sendheaders && format->mimetype ) {
870 msIO_setHeader("Content-Type","%s",format->mimetype);
871 msIO_sendHeaders();
872 } else
873 msIO_fprintf( stdout, "%c", 10 );
874 }
875
876 /* ==================================================================== */
877 /* Create the datasource. */
878 /* ==================================================================== */
879 hDS = OGR_Dr_CreateDataSource( hDriver, datasource_name, ds_options );
880 CSLDestroy( ds_options );
881
882 if( hDS == NULL ) {
883 msOGRCleanupDS( datasource_name );
884 msSetError( MS_MISCERR,
885 "OGR CreateDataSource failed for '%s' with driver '%s'.",
886 "msOGRWriteFromQuery()",
887 datasource_name,
888 format->driver+4 );
889 CSLDestroy(layer_options);
890 return MS_FAILURE;
891 }
892
893 /* ==================================================================== */
894 /* Process each layer with a resultset. */
895 /* ==================================================================== */
896 for( iLayer = 0; iLayer < map->numlayers; iLayer++ ) {
897 int status = 0;
898 layerObj *layer = GET_LAYER(map, iLayer);
899 shapeObj resultshape;
900 OGRLayerH hOGRLayer;
901 OGRwkbGeometryType eGeomType;
902 OGRSpatialReferenceH srs = NULL;
903 gmlItemListObj *item_list = NULL;
904 const char *value;
905 char *pszWKT;
906 int nFirstOGRFieldIndex = -1;
907 const char *pszFeatureid = NULL;
908
909 if( !layer->resultcache )
910 continue;
911
912 /* -------------------------------------------------------------------- */
913 /* Will we need to reproject? */
914 /* -------------------------------------------------------------------- */
915 if(layer->transform == MS_TRUE)
916 layer->project = msProjectionsDiffer(&(layer->projection),
917 &(layer->map->projection));
918
919 /* -------------------------------------------------------------------- */
920 /* Establish the geometry type to use for the created layer. */
921 /* First we consult the wfs_geomtype field and fallback to */
922 /* deriving something from the type of the mapserver layer. */
923 /* -------------------------------------------------------------------- */
924 value = msOWSLookupMetadata(&(layer->metadata), "FOG", "geomtype");
925 if( value == NULL ) {
926 if( layer->type == MS_LAYER_POINT )
927 value = "Point";
928 else if( layer->type == MS_LAYER_LINE )
929 value = "LineString";
930 else if( layer->type == MS_LAYER_POLYGON )
931 value = "Polygon";
932 else
933 value = "Geometry";
934 }
935
936 if(bUseFeatureId)
937 pszFeatureid = msOWSLookupMetadata(&(layer->metadata), "FOG", "featureid");
938
939 if( strcasecmp(value,"Point") == 0 )
940 eGeomType = wkbPoint;
941 else if( strcasecmp(value,"LineString") == 0 )
942 eGeomType = wkbLineString;
943 else if( strcasecmp(value,"Polygon") == 0 )
944 eGeomType = wkbPolygon;
945 else if( strcasecmp(value,"MultiPoint") == 0 )
946 eGeomType = wkbMultiPoint;
947 else if( strcasecmp(value,"MultiLineString") == 0 )
948 eGeomType = wkbMultiLineString;
949 else if( strcasecmp(value,"MultiPolygon") == 0 )
950 eGeomType = wkbMultiPolygon;
951 else if( strcasecmp(value,"GeometryCollection") == 0 )
952 eGeomType = wkbGeometryCollection;
953 else if( strcasecmp(value,"Point25D") == 0 )
954 eGeomType = wkbPoint25D;
955 else if( strcasecmp(value,"LineString25D") == 0 )
956 eGeomType = wkbLineString25D;
957 else if( strcasecmp(value,"Polygon25D") == 0 )
958 eGeomType = wkbPolygon25D;
959 else if( strcasecmp(value,"MultiPoint25D") == 0 )
960 eGeomType = wkbMultiPoint25D;
961 else if( strcasecmp(value,"MultiLineString25D") == 0 )
962 eGeomType = wkbMultiLineString25D;
963 else if( strcasecmp(value,"MultiPolygon25D") == 0 )
964 eGeomType = wkbMultiPolygon25D;
965 else if( strcasecmp(value,"GeometryCollection25D") == 0 )
966 eGeomType = wkbGeometryCollection25D;
967 else if( strcasecmp(value,"Unknown") == 0
968 || strcasecmp(value,"Geometry") == 0 )
969 eGeomType = wkbUnknown;
970 else if( strcasecmp(value,"None") == 0 )
971 eGeomType = wkbNone;
972 else
973 eGeomType = wkbUnknown;
974
975 /* -------------------------------------------------------------------- */
976 /* Create a spatial reference. */
977 /* -------------------------------------------------------------------- */
978 pszWKT = msProjectionObj2OGCWKT( &(map->projection) );
979 if( pszWKT != NULL ) {
980 srs = OSRNewSpatialReference( pszWKT );
981 msFree( pszWKT );
982 }
983
984 /* -------------------------------------------------------------------- */
985 /* Create the corresponding OGR Layer. */
986 /* -------------------------------------------------------------------- */
987 hOGRLayer = OGR_DS_CreateLayer( hDS, layer->name, srs, eGeomType,
988 layer_options );
989 if( hOGRLayer == NULL ) {
990 OGR_DS_Destroy( hDS );
991 msOGRCleanupDS( datasource_name );
992 msSetError( MS_MISCERR,
993 "OGR OGR_DS_CreateLayer failed for layer '%s' with driver '%s'.",
994 "msOGRWriteFromQuery()",
995 layer->name,
996 format->driver+4 );
997 CSLDestroy(layer_options);
998 return MS_FAILURE;
999 }
1000
1001 if( srs != NULL )
1002 OSRRelease( srs );
1003
1004 /* -------------------------------------------------------------------- */
1005 /* Create appropriate attributes on this layer. */
1006 /* -------------------------------------------------------------------- */
1007 item_list = msGMLGetItems( layer, "G" );
1008 assert( item_list->numitems == layer->numitems );
1009
1010 for( i = 0; i < layer->numitems; i++ ) {
1011 OGRFieldDefnH hFldDefn;
1012 OGRErr eErr;
1013 const char *name;
1014 gmlItemObj *item = item_list->items + i;
1015 OGRFieldType eType;
1016
1017 if( !item->visible )
1018 continue;
1019
1020 if( item->alias )
1021 name = item->alias;
1022 else
1023 name = item->name;
1024
1025 if( item->type == NULL )
1026 eType = OFTString;
1027 else if( EQUAL(item->type,"Integer") )
1028 eType = OFTInteger;
1029 else if( EQUAL(item->type,"Long") )
1030 eType = OFTInteger64;
1031 else if( EQUAL(item->type,"Real") )
1032 eType = OFTReal;
1033 else if( EQUAL(item->type,"Character") )
1034 eType = OFTString;
1035 else if( EQUAL(item->type,"Date") )
1036 eType = OFTDate;
1037 else if( EQUAL(item->type,"Time") )
1038 eType = OFTTime;
1039 else if( EQUAL(item->type,"DateTime") )
1040 eType = OFTDateTime;
1041 else if( EQUAL(item->type,"Boolean") )
1042 eType = OFTInteger;
1043 else
1044 eType = OFTString;
1045
1046 hFldDefn = OGR_Fld_Create( name, eType );
1047
1048 if( item->width != 0 )
1049 OGR_Fld_SetWidth( hFldDefn, item->width );
1050 if( item->precision != 0 )
1051 OGR_Fld_SetPrecision( hFldDefn, item->precision );
1052
1053 eErr = OGR_L_CreateField( hOGRLayer, hFldDefn, TRUE );
1054 OGR_Fld_Destroy( hFldDefn );
1055
1056 if( eErr != OGRERR_NONE ) {
1057 msSetError( MS_OGRERR,
1058 "Failed to create field '%s' in output feature schema:\n%s",
1059 "msOGRWriteFromQuery()",
1060 layer->items[i],
1061 CPLGetLastErrorMsg() );
1062
1063 OGR_DS_Destroy( hDS );
1064 msOGRCleanupDS( datasource_name );
1065 msGMLFreeItems(item_list);
1066 CSLDestroy(layer_options);
1067 return MS_FAILURE;
1068 }
1069
1070 /* The index of the first field we create is not necessarily 0 */
1071 if( nFirstOGRFieldIndex < 0 )
1072 nFirstOGRFieldIndex = OGR_FD_GetFieldCount(
1073 OGR_L_GetLayerDefn( hOGRLayer ) ) - 1;
1074 }
1075
1076 /* -------------------------------------------------------------------- */
1077 /* Setup joins if needed. This is likely untested. */
1078 /* -------------------------------------------------------------------- */
1079 if(layer->numjoins > 0) {
1080 int j;
1081 for(j=0; j<layer->numjoins; j++) {
1082 status = msJoinConnect(layer, &(layer->joins[j]));
1083 if(status != MS_SUCCESS) {
1084 OGR_DS_Destroy( hDS );
1085 msOGRCleanupDS( datasource_name );
1086 msGMLFreeItems(item_list);
1087 CSLDestroy(layer_options);
1088 return status;
1089 }
1090 }
1091 }
1092
1093 msInitShape( &resultshape );
1094
1095 /* -------------------------------------------------------------------- */
1096 /* Loop over all the shapes in the resultcache. */
1097 /* -------------------------------------------------------------------- */
1098 for(i=0; i < layer->resultcache->numresults; i++) {
1099
1100 msFreeShape(&resultshape); /* init too */
1101
1102 /*
1103 ** Read the shape.
1104 */
1105 if( layer->resultcache->results[i].shape )
1106 {
1107 /* msDebug("Using cached shape %ld\n", layer->resultcache->results[i].shapeindex); */
1108 status = msCopyShape(layer->resultcache->results[i].shape, &resultshape);
1109 }
1110 else
1111 {
1112 status = msLayerGetShape(layer, &resultshape, &(layer->resultcache->results[i]));
1113 }
1114
1115 if(status != MS_SUCCESS) {
1116 OGR_DS_Destroy( hDS );
1117 msOGRCleanupDS( datasource_name );
1118 msGMLFreeItems(item_list);
1119 msFreeShape(&resultshape);
1120 CSLDestroy(layer_options);
1121 return status;
1122 }
1123
1124 /*
1125 ** Perform classification, and some annotation related magic.
1126 */
1127 resultshape.classindex =
1128 msShapeGetClass(layer, map, &resultshape, NULL, -1);
1129
1130 if( resultshape.classindex >= 0
1131 && (layer->_class[resultshape.classindex]->text.string
1132 || layer->labelitem)
1133 && layer->_class[resultshape.classindex]->numlabels > 0
1134 && layer->_class[resultshape.classindex]->labels[0]->size != -1 ) {
1135 resultshape.text = msShapeGetLabelAnnotation(layer,&resultshape,layer->_class[resultshape.classindex]->labels[0]);
1136 }
1137
1138 /*
1139 ** prepare any necessary JOINs here (one-to-one only)
1140 */
1141 if( layer->numjoins > 0) {
1142 int j;
1143
1144 for(j=0; j < layer->numjoins; j++) {
1145 if(layer->joins[j].type == MS_JOIN_ONE_TO_ONE) {
1146 msJoinPrepare(&(layer->joins[j]), &resultshape);
1147 msJoinNext(&(layer->joins[j])); /* fetch the first row */
1148 }
1149 }
1150 }
1151
1152 if( layer->project ) {
1153 if( layer->reprojectorLayerToMap == NULL )
1154 {
1155 layer->reprojectorLayerToMap = msProjectCreateReprojector(
1156 &layer->projection, &layer->map->projection);
1157 }
1158 if( layer->reprojectorLayerToMap )
1159 status = msProjectShapeEx(layer->reprojectorLayerToMap, &resultshape);
1160 else
1161 status = MS_FAILURE;
1162 }
1163
1164 /*
1165 ** Write out the feature to OGR.
1166 */
1167
1168 if( status == MS_SUCCESS )
1169 status = msOGRWriteShape( layer, hOGRLayer, &resultshape,
1170 item_list, nFirstOGRFieldIndex, pszFeatureid );
1171
1172 if(status != MS_SUCCESS) {
1173 OGR_DS_Destroy( hDS );
1174 msOGRCleanupDS( datasource_name );
1175 msGMLFreeItems(item_list);
1176 msFreeShape(&resultshape);
1177 CSLDestroy(layer_options);
1178 return status;
1179 }
1180 }
1181
1182 msGMLFreeItems(item_list);
1183 msFreeShape(&resultshape); /* init too */
1184 }
1185
1186 /* -------------------------------------------------------------------- */
1187 /* Close the datasource. */
1188 /* -------------------------------------------------------------------- */
1189 OGR_DS_Destroy( hDS );
1190
1191 CSLDestroy( layer_options );
1192
1193 /* -------------------------------------------------------------------- */
1194 /* Get list of resulting files. */
1195 /* -------------------------------------------------------------------- */
1196
1197 if( EQUAL(form,"simple") ) {
1198 file_list = CSLAddString( NULL, datasource_name );
1199 } else {
1200 char datasource_path[MS_MAXPATHLEN];
1201
1202 if( bDataSourceNameIsRequestDir )
1203 file_list = msOGRRecursiveFileList( datasource_name );
1204 else
1205 {
1206 strncpy( datasource_path, CPLGetPath( datasource_name ), MS_MAXPATHLEN-1 );
1207 file_list = msOGRRecursiveFileList( datasource_path );
1208 }
1209 }
1210
1211 /* -------------------------------------------------------------------- */
1212 /* If our "storage" is stream then the output has already been */
1213 /* sent back to the client and we don't need to copy it now. */
1214 /* -------------------------------------------------------------------- */
1215 if( EQUAL(storage,"stream") ) {
1216 /* already done */
1217 }
1218
1219 /* -------------------------------------------------------------------- */
1220 /* Handle case of simple file written to stdout. */
1221 /* -------------------------------------------------------------------- */
1222 else if( EQUAL(form,"simple") ) {
1223 char buffer[1024];
1224 int bytes_read;
1225 FILE *fp;
1226 const char *jsonp;
1227
1228 jsonp = msGetOutputFormatOption( format, "JSONP", NULL );
1229 if( sendheaders ) {
1230 if( !jsonp )
1231 msIO_setHeader("Content-Disposition","attachment; filename=%s",
1232 CPLGetFilename( file_list[0] ) );
1233 if( format->mimetype )
1234 msIO_setHeader("Content-Type","%s",format->mimetype);
1235 msIO_sendHeaders();
1236 } else
1237 msIO_fprintf( stdout, "%c", 10 );
1238
1239 fp = VSIFOpenL( file_list[0], "r" );
1240 if( fp == NULL ) {
1241 msSetError( MS_MISCERR,
1242 "Failed to open result file '%s'.",
1243 "msOGRWriteFromQuery()",
1244 file_list[0] );
1245 msOGRCleanupDS( datasource_name );
1246 return MS_FAILURE;
1247 }
1248
1249 if( jsonp != NULL ) msIO_fprintf( stdout, "%s(", jsonp );
1250
1251 while( (bytes_read = VSIFReadL( buffer, 1, sizeof(buffer), fp )) > 0 )
1252 msIO_fwrite( buffer, 1, bytes_read, stdout );
1253 VSIFCloseL( fp );
1254
1255 if (jsonp != NULL) msIO_fprintf( stdout, ");\n" );
1256 }
1257
1258 /* -------------------------------------------------------------------- */
1259 /* Handle the case of a multi-part result. */
1260 /* -------------------------------------------------------------------- */
1261 else if( EQUAL(form,"multipart") ) {
1262 char **papszAdditionalFiles;
1263 static const char *boundary = "xxOGRBoundaryxx";
1264 msIO_setHeader("Content-Type","multipart/mixed; boundary=%s",boundary);
1265 msIO_sendHeaders();
1266 msIO_fprintf(stdout,"--%s\r\n",boundary );
1267
1268 papszAdditionalFiles = msOGROutputGetAdditonalFiles(map);
1269 file_list = msCSLConcatenate(file_list, papszAdditionalFiles);
1270 CSLDestroy(papszAdditionalFiles);
1271
1272 for( i = 0; file_list != NULL && file_list[i] != NULL; i++ ) {
1273 FILE *fp;
1274 int bytes_read;
1275 char buffer[1024];
1276
1277 if( sendheaders )
1278 msIO_fprintf( stdout,
1279 "Content-Disposition: attachment; filename=%s\r\n"
1280 "Content-Type: application/binary\r\n"
1281 "Content-Transfer-Encoding: binary\r\n\r\n",
1282 CPLGetFilename( file_list[i] ));
1283
1284
1285 fp = VSIFOpenL( file_list[i], "r" );
1286 if( fp == NULL ) {
1287 msSetError( MS_MISCERR,
1288 "Failed to open result file '%s'.",
1289 "msOGRWriteFromQuery()",
1290 file_list[0] );
1291 msOGRCleanupDS( datasource_name );
1292 return MS_FAILURE;
1293 }
1294
1295 while( (bytes_read = VSIFReadL( buffer, 1, sizeof(buffer), fp )) > 0 )
1296 msIO_fwrite( buffer, 1, bytes_read, stdout );
1297 VSIFCloseL( fp );
1298
1299 if (file_list[i+1] == NULL)
1300 msIO_fprintf( stdout, "\r\n--%s--\r\n", boundary );
1301 else
1302 msIO_fprintf( stdout, "\r\n--%s\r\n", boundary );
1303 }
1304 }
1305
1306 /* -------------------------------------------------------------------- */
1307 /* Handle the case of a zip file result. */
1308 /* -------------------------------------------------------------------- */
1309 else if( EQUAL(form,"zip") ) {
1310 FILE *fp;
1311 char *zip_filename = msTmpFile(map, NULL, "/vsimem/ogrzip/", "zip" );
1312 void *hZip;
1313 int bytes_read;
1314 char buffer[1024];
1315 char **papszAdditionalFiles;
1316
1317 hZip = CPLCreateZip( zip_filename, NULL );
1318
1319 papszAdditionalFiles = msOGROutputGetAdditonalFiles(map);
1320 file_list = msCSLConcatenate(file_list, papszAdditionalFiles);
1321 CSLDestroy(papszAdditionalFiles);
1322
1323 for( i = 0; file_list != NULL && file_list[i] != NULL; i++ ) {
1324
1325 CPLCreateFileInZip( hZip, CPLGetFilename(file_list[i]), NULL );
1326
1327 fp = VSIFOpenL( file_list[i], "r" );
1328 if( fp == NULL ) {
1329 CPLCloseZip( hZip );
1330 msSetError( MS_MISCERR,
1331 "Failed to open result file '%s'.",
1332 "msOGRWriteFromQuery()",
1333 file_list[0] );
1334 msOGRCleanupDS( datasource_name );
1335 return MS_FAILURE;
1336 }
1337
1338 while( (bytes_read = VSIFReadL( buffer, 1, sizeof(buffer), fp )) > 0 ) {
1339 CPLWriteFileInZip( hZip, buffer, bytes_read );
1340 }
1341 VSIFCloseL( fp );
1342
1343 CPLCloseFileInZip( hZip );
1344 }
1345 CPLCloseZip( hZip );
1346
1347 if( sendheaders ) {
1348 const char* zip_filename = fo_filename;
1349 /* Make sure the filename is ended by .zip */
1350 if( !EQUAL(CPLGetExtension(zip_filename), "zip") &&
1351 !EQUAL(CPLGetExtension(zip_filename), "kmz") )
1352 zip_filename = CPLFormFilename(NULL, fo_filename, "zip");
1353 msIO_setHeader("Content-Disposition","attachment; filename=%s",zip_filename);
1354 msIO_setHeader("Content-Type","application/zip");
1355 msIO_sendHeaders();
1356 }
1357
1358 fp = VSIFOpenL( zip_filename, "r" );
1359 if( fp == NULL ) {
1360 msSetError( MS_MISCERR,
1361 "Failed to open zip file '%s'.",
1362 "msOGRWriteFromQuery()",
1363 file_list[0] );
1364 msOGRCleanupDS( datasource_name );
1365 return MS_FAILURE;
1366 }
1367
1368 while( (bytes_read = VSIFReadL( buffer, 1, sizeof(buffer), fp )) > 0 )
1369 msIO_fwrite( buffer, 1, bytes_read, stdout );
1370 VSIFCloseL( fp );
1371
1372 msFree( zip_filename );
1373 }
1374
1375 /* -------------------------------------------------------------------- */
1376 /* Handle illegal form value. */
1377 /* -------------------------------------------------------------------- */
1378 else {
1379 msSetError( MS_MISCERR, "Unsupported FORM=%s value.",
1380 "msOGRWriteFromQuery()", form );
1381 msOGRCleanupDS( datasource_name );
1382 return MS_FAILURE;
1383 }
1384
1385 msOGRCleanupDS( datasource_name );
1386
1387 CSLDestroy( file_list );
1388
1389 return MS_SUCCESS;
1390 }
1391
1392 /************************************************************************/
1393 /* msPopulateRenderVTableOGR() */
1394 /************************************************************************/
1395
msPopulateRendererVTableOGR(rendererVTableObj * renderer)1396 int msPopulateRendererVTableOGR( rendererVTableObj *renderer )
1397 {
1398 /* we aren't really a normal renderer so we leave everything default */
1399 return MS_SUCCESS;
1400 }
1401