@@ -8,12 +8,14 @@ use crate::{
8
8
use gdal_sys:: {
9
9
self , CPLErr , GDALAccess , GDALDatasetH , GDALMajorObjectH , OGRErr , OGRLayerH , OGRwkbGeometryType ,
10
10
} ;
11
- use libc:: { c_double, c_int} ;
11
+ use libc:: { c_double, c_int, c_uint } ;
12
12
use ptr:: null_mut;
13
13
14
14
use crate :: errors:: * ;
15
15
use std:: convert:: TryInto ;
16
16
17
+ use bitflags:: bitflags;
18
+
17
19
pub type GeoTransform = [ c_double ; 6 ] ;
18
20
static START : Once = Once :: new ( ) ;
19
21
@@ -30,6 +32,73 @@ pub fn _register_drivers() {
30
32
}
31
33
}
32
34
35
+ // GDal extended open flags, skipped by bindgen
36
+ //
37
+ // Note that the `GDAL_OF_SHARED` option is removed from the set
38
+ // of allowed option because it subverts the [`Send`] implementation
39
+ // that allow passing the dataset the another thread.
40
+ // See https://github.com/georust/gdal/issues/154.
41
+ #[ cfg( major_ge_2) ]
42
+ bitflags ! {
43
+ pub struct GdalOpenFlags : c_uint {
44
+ const GDAL_OF_READONLY = 0x00 ;
45
+ // Open in update mode.
46
+ const GDAL_OF_UPDATE = 0x01 ;
47
+ // Allow raster and vector drivers to be used.
48
+ const GDAL_OF_ALL = 0x00 ;
49
+ // Allow raster drivers to be used.
50
+ const GDAL_OF_RASTER = 0x02 ;
51
+ // Allow vector drivers to be used.
52
+ const GDAL_OF_VECTOR = 0x04 ;
53
+ // Allow gnm drivers to be used.
54
+ #[ cfg( all( major_ge_2, minor_ge_1) ) ]
55
+ const GDAL_OF_GNM = 0x08 ;
56
+ // Allow multidimensional raster drivers to be used.
57
+ #[ cfg( all( major_ge_3, minor_ge_1) ) ]
58
+ const GDAL_OF_MULTIDIM_RASTER = 0x10 ;
59
+ // Emit error message in case of failed open.
60
+ const GDAL_OF_VERBOSE_ERROR = 0x40 ;
61
+ // Open as internal dataset. Such dataset isn't registered in the global list
62
+ // of opened dataset. Cannot be used with GDAL_OF_SHARED.
63
+ const GDAL_OF_INTERNAL = 0x80 ;
64
+ // Let GDAL decide if a array-based or hashset-based storage strategy for
65
+ // cached blocks must be used.
66
+ // GDAL_OF_DEFAULT_BLOCK_ACCESS, GDAL_OF_ARRAY_BLOCK_ACCESS and
67
+ // GDAL_OF_HASHSET_BLOCK_ACCESS are mutually exclusive.
68
+ #[ cfg( all( major_ge_2, minor_ge_1) ) ]
69
+ const GDAL_OF_DEFAULT_BLOCK_ACCESS = 0 ;
70
+ #[ cfg( all( major_ge_2, minor_ge_1) ) ]
71
+ const GDAL_OF_ARRAY_BLOCK_ACCESS = 0x100 ;
72
+ #[ cfg( all( major_ge_2, minor_ge_1) ) ]
73
+ const GDAL_OF_HASHSET_BLOCK_ACCESS = 0x200 ;
74
+ }
75
+ }
76
+
77
+ impl Default for GdalOpenFlags {
78
+ fn default ( ) -> GdalOpenFlags {
79
+ GdalOpenFlags :: GDAL_OF_READONLY
80
+ }
81
+ }
82
+
83
+ impl From < GDALAccess :: Type > for GdalOpenFlags {
84
+ fn from ( val : GDALAccess :: Type ) -> GdalOpenFlags {
85
+ if val == GDALAccess :: GA_Update {
86
+ GdalOpenFlags :: GDAL_OF_UPDATE
87
+ } else {
88
+ GdalOpenFlags :: GDAL_OF_READONLY
89
+ }
90
+ }
91
+ }
92
+
93
+ // Open parameters
94
+ #[ derive( Debug , Default ) ]
95
+ pub struct DatasetOptions < ' a > {
96
+ pub open_flags : GdalOpenFlags ,
97
+ pub allowed_drivers : Option < & ' a [ & ' a str ] > ,
98
+ pub open_options : Option < & ' a [ & ' a str ] > ,
99
+ pub sibling_files : Option < & ' a [ & ' a str ] > ,
100
+ }
101
+
33
102
// GDAL Docs state: The returned dataset should only be accessed by one thread at a time.
34
103
// See: https://gdal.org/api/raster_c_api.html#_CPPv48GDALOpenPKc10GDALAccess
35
104
// Additionally, VRT Datasets are not safe before GDAL 2.3.
@@ -47,24 +116,18 @@ impl Dataset {
47
116
}
48
117
49
118
pub fn open ( path : & Path ) -> Result < Dataset > {
50
- Self :: open_ex ( path, None , None , None , None )
119
+ Self :: open_ex ( path, DatasetOptions :: default ( ) )
51
120
}
52
121
53
- pub fn open_ex (
54
- path : & Path ,
55
- open_flags : Option < GDALAccess :: Type > ,
56
- allowed_drivers : Option < & [ & str ] > , // TODO: use parameters
57
- open_options : Option < & [ & str ] > ,
58
- sibling_files : Option < & [ & str ] > ,
59
- ) -> Result < Dataset > {
122
+ pub fn open_ex ( path : & Path , options : DatasetOptions ) -> Result < Dataset > {
60
123
_register_drivers ( ) ;
61
124
let filename = path. to_string_lossy ( ) ;
62
125
let c_filename = CString :: new ( filename. as_ref ( ) ) ?;
63
- let c_open_flags = open_flags. unwrap_or ( GDALAccess :: GA_ReadOnly ) ; // This defaults to GdalAccess::GA_ReadOnly
126
+ let c_open_flags = options . open_flags . bits ;
64
127
65
128
// handle driver params:
66
129
// we need to keep the CStrings and the pointers around
67
- let c_allowed_drivers = allowed_drivers. map ( |d| {
130
+ let c_allowed_drivers = options . allowed_drivers . map ( |d| {
68
131
d. iter ( )
69
132
. map ( |& s| CString :: new ( s) )
70
133
. collect :: < std:: result:: Result < Vec < CString > , NulError > > ( )
@@ -77,15 +140,15 @@ impl Dataset {
77
140
let mut c_drivers_ptrs = c_drivers_vec. iter ( ) . map ( |s| s. as_ptr ( ) ) . collect :: < Vec < _ > > ( ) ;
78
141
c_drivers_ptrs. push ( ptr:: null ( ) ) ;
79
142
80
- let c_drivers_ptr = if allowed_drivers. is_some ( ) {
143
+ let c_drivers_ptr = if options . allowed_drivers . is_some ( ) {
81
144
c_drivers_ptrs. as_ptr ( )
82
145
} else {
83
146
ptr:: null ( )
84
147
} ;
85
148
86
149
// handle open options params:
87
150
// we need to keep the CStrings and the pointers around
88
- let c_open_options = open_options. map ( |d| {
151
+ let c_open_options = options . open_options . map ( |d| {
89
152
d. iter ( )
90
153
. map ( |& s| CString :: new ( s) )
91
154
. collect :: < std:: result:: Result < Vec < CString > , NulError > > ( )
@@ -101,15 +164,15 @@ impl Dataset {
101
164
. collect :: < Vec < _ > > ( ) ;
102
165
c_open_options_ptrs. push ( ptr:: null ( ) ) ;
103
166
104
- let c_open_options_ptr = if open_options. is_some ( ) {
167
+ let c_open_options_ptr = if options . open_options . is_some ( ) {
105
168
c_open_options_ptrs. as_ptr ( )
106
169
} else {
107
170
ptr:: null ( )
108
171
} ;
109
172
110
173
// handle sibling files params:
111
174
// we need to keep the CStrings and the pointers around
112
- let c_sibling_files = sibling_files. map ( |d| {
175
+ let c_sibling_files = options . sibling_files . map ( |d| {
113
176
d. iter ( )
114
177
. map ( |& s| CString :: new ( s) )
115
178
. collect :: < std:: result:: Result < Vec < CString > , NulError > > ( )
@@ -125,7 +188,7 @@ impl Dataset {
125
188
. collect :: < Vec < _ > > ( ) ;
126
189
c_sibling_files_ptrs. push ( ptr:: null ( ) ) ;
127
190
128
- let c_sibling_files_ptr = if sibling_files. is_some ( ) {
191
+ let c_sibling_files_ptr = if options . sibling_files . is_some ( ) {
129
192
c_sibling_files_ptrs. as_ptr ( )
130
193
} else {
131
194
ptr:: null ( )
@@ -576,10 +639,11 @@ mod tests {
576
639
577
640
let ds = Dataset :: open_ex (
578
641
& temp_path,
579
- Some ( GDALAccess :: GA_Update ) ,
580
- Some ( & [ "GPKG" ] ) ,
581
- None ,
582
- None ,
642
+ DatasetOptions {
643
+ open_flags : GDALAccess :: GA_Update . into ( ) ,
644
+ allowed_drivers : Some ( & [ "GPKG" ] ) ,
645
+ ..DatasetOptions :: default ( )
646
+ } ,
583
647
)
584
648
. unwrap ( ) ;
585
649
( temp_path, ds)
@@ -598,10 +662,10 @@ mod tests {
598
662
fn test_open_ex_ro_vector ( ) {
599
663
Dataset :: open_ex (
600
664
fixture ! ( "roads.geojson" ) ,
601
- Some ( GDALAccess :: GA_ReadOnly ) ,
602
- None ,
603
- None ,
604
- None ,
665
+ DatasetOptions {
666
+ open_flags : GDALAccess :: GA_ReadOnly . into ( ) ,
667
+ .. DatasetOptions :: default ( )
668
+ } ,
605
669
)
606
670
. unwrap ( ) ;
607
671
}
@@ -610,10 +674,10 @@ mod tests {
610
674
fn test_open_ex_update_vector ( ) {
611
675
Dataset :: open_ex (
612
676
fixture ! ( "roads.geojson" ) ,
613
- Some ( GDALAccess :: GA_Update ) ,
614
- None ,
615
- None ,
616
- None ,
677
+ DatasetOptions {
678
+ open_flags : GDALAccess :: GA_Update . into ( ) ,
679
+ .. DatasetOptions :: default ( )
680
+ } ,
617
681
)
618
682
. unwrap ( ) ;
619
683
}
@@ -622,31 +686,62 @@ mod tests {
622
686
fn test_open_ex_allowed_driver_vector ( ) {
623
687
Dataset :: open_ex (
624
688
fixture ! ( "roads.geojson" ) ,
625
- None ,
626
- Some ( & [ "GeoJSON" ] ) ,
627
- None ,
628
- None ,
689
+ DatasetOptions {
690
+ allowed_drivers : Some ( & [ "GeoJSON" ] ) ,
691
+ .. DatasetOptions :: default ( )
692
+ } ,
629
693
)
630
694
. unwrap ( ) ;
631
695
}
632
696
633
697
#[ test]
634
698
fn test_open_ex_allowed_driver_vector_fail ( ) {
635
- Dataset :: open_ex ( fixture ! ( "roads.geojson" ) , None , Some ( & [ "TIFF" ] ) , None , None ) . unwrap_err ( ) ;
699
+ Dataset :: open_ex (
700
+ fixture ! ( "roads.geojson" ) ,
701
+ DatasetOptions {
702
+ allowed_drivers : Some ( & [ "TIFF" ] ) ,
703
+ ..DatasetOptions :: default ( )
704
+ } ,
705
+ )
706
+ . unwrap_err ( ) ;
636
707
}
637
708
638
709
#[ test]
639
710
fn test_open_ex_open_option ( ) {
640
711
Dataset :: open_ex (
641
712
fixture ! ( "roads.geojson" ) ,
642
- None ,
643
- None ,
644
- Some ( & [ "FLATTEN_NESTED_ATTRIBUTES=YES" ] ) ,
645
- None ,
713
+ DatasetOptions {
714
+ open_options : Some ( & [ "FLATTEN_NESTED_ATTRIBUTES=YES" ] ) ,
715
+ .. DatasetOptions :: default ( )
716
+ } ,
646
717
)
647
718
. unwrap ( ) ;
648
719
}
649
720
721
+ #[ test]
722
+ fn test_open_ex_extended_flags_vector ( ) {
723
+ Dataset :: open_ex (
724
+ fixture ! ( "roads.geojson" ) ,
725
+ DatasetOptions {
726
+ open_flags : GdalOpenFlags :: GDAL_OF_UPDATE | GdalOpenFlags :: GDAL_OF_VECTOR ,
727
+ ..DatasetOptions :: default ( )
728
+ } ,
729
+ )
730
+ . unwrap ( ) ;
731
+ }
732
+
733
+ #[ test]
734
+ fn test_open_ex_extended_flags_vector_fail ( ) {
735
+ Dataset :: open_ex (
736
+ fixture ! ( "roads.geojson" ) ,
737
+ DatasetOptions {
738
+ open_flags : GdalOpenFlags :: GDAL_OF_UPDATE | GdalOpenFlags :: GDAL_OF_RASTER ,
739
+ ..DatasetOptions :: default ( )
740
+ } ,
741
+ )
742
+ . unwrap_err ( ) ;
743
+ }
744
+
650
745
#[ test]
651
746
fn test_layer_count ( ) {
652
747
let ds = Dataset :: open ( fixture ! ( "roads.geojson" ) ) . unwrap ( ) ;
0 commit comments