1 #ifndef OSMIUM_OSM_METADATA_OPTIONS_HPP
2 #define OSMIUM_OSM_METADATA_OPTIONS_HPP
3 
4 /*
5 
6 This file is part of Osmium (https://osmcode.org/libosmium).
7 
8 Copyright 2013-2021 Jochen Topf <jochen@topf.org> and others (see README).
9 
10 Boost Software License - Version 1.0 - August 17th, 2003
11 
12 Permission is hereby granted, free of charge, to any person or organization
13 obtaining a copy of the software and accompanying documentation covered by
14 this license (the "Software") to use, reproduce, display, distribute,
15 execute, and transmit the Software, and to prepare derivative works of the
16 Software, and to permit third-parties to whom the Software is furnished to
17 do so, all subject to the following:
18 
19 The copyright notices in the Software and this entire statement, including
20 the above license grant, this restriction and the following disclaimer,
21 must be included in all copies of the Software, in whole or in part, and
22 all derivative works of the Software, unless such copies or derivative
23 works are solely in the form of machine-executable object code generated by
24 a source language processor.
25 
26 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
29 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
30 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
31 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
32 DEALINGS IN THE SOFTWARE.
33 
34 */
35 
36 #include <osmium/osm/object.hpp>
37 #include <osmium/util/string.hpp>
38 
39 #include <ostream>
40 #include <stdexcept>
41 #include <string>
42 
43 namespace osmium {
44 
45     /**
46      * Describes which metadata fields are available in an OSMObject. This is
47      * most often used to describe which metadata fields are available in the
48      * objects of an OSM file or which metadata information should be written
49      * to an OSM file.
50      */
51     class metadata_options {
52 
53         enum options : unsigned int {
54             md_none      = 0x00,
55             md_version   = 0x01,
56             md_timestamp = 0x02,
57             md_changeset = 0x04,
58             md_uid       = 0x08,
59             md_user      = 0x10,
60             md_all       = 0x1f
61         } m_options = md_all;
62 
63     public:
64 
65         metadata_options() noexcept = default;
66 
metadata_options(const std::string & attributes)67         explicit metadata_options(const std::string& attributes) {
68             if (attributes.empty() || attributes == "all" || attributes == "true" || attributes == "yes") {
69                 return;
70             }
71             if (attributes == "none" || attributes == "false" || attributes == "no") {
72                 m_options = options::md_none;
73                 return;
74             }
75 
76             const auto attrs = osmium::split_string(attributes, '+', true);
77             unsigned int opts = 0;
78             for (const auto& attr : attrs) {
79                 if (attr == "version") {
80                     opts |= options::md_version;
81                 } else if (attr == "timestamp") {
82                     opts |= options::md_timestamp;
83                 } else if (attr == "changeset") {
84                     opts |= options::md_changeset;
85                 } else if (attr == "uid") {
86                     opts |= options::md_uid;
87                 } else if (attr == "user") {
88                     opts |= options::md_user;
89                 } else {
90                     throw std::invalid_argument{std::string{"Unknown OSM object metadata attribute: '"} + attr + "'"};
91                 }
92             }
93             m_options = static_cast<options>(opts);
94         }
95 
96         /// At least one metadata attribute should be stored.
any() const97         bool any() const noexcept {
98             return m_options != 0;
99         }
100 
101         /// All metadata attributes should be stored.
all() const102         bool all() const noexcept {
103             return m_options == options::md_all;
104         }
105 
106         /// No metadata attributes should be stored.
none() const107         bool none() const noexcept {
108             return m_options == 0;
109         }
110 
version() const111         bool version() const noexcept {
112             return (m_options & options::md_version) != 0;
113         }
114 
set_version(bool flag)115         void set_version(bool flag) noexcept {
116             if (flag) {
117                 m_options = static_cast<options>(m_options | options::md_version);
118             } else {
119                 m_options = static_cast<options>(m_options & ~options::md_version);
120             }
121         }
122 
timestamp() const123         bool timestamp() const noexcept {
124             return (m_options & options::md_timestamp) != 0;
125         }
126 
set_timestamp(bool flag)127         void set_timestamp(bool flag) noexcept {
128             if (flag) {
129                 m_options = static_cast<options>(m_options | options::md_timestamp);
130             } else {
131                 m_options = static_cast<options>(m_options & ~options::md_timestamp);
132             }
133         }
134 
changeset() const135         bool changeset() const noexcept {
136             return (m_options & options::md_changeset) != 0;
137         }
138 
set_changeset(bool flag)139         void set_changeset(bool flag) noexcept {
140             if (flag) {
141                 m_options = static_cast<options>(m_options | options::md_changeset);
142             } else {
143                 m_options = static_cast<options>(m_options & ~options::md_changeset);
144             }
145         }
146 
uid() const147         bool uid() const noexcept {
148             return (m_options & options::md_uid) != 0;
149         }
150 
set_uid(bool flag)151         void set_uid(bool flag) noexcept {
152             if (flag) {
153                 m_options = static_cast<options>(m_options | options::md_uid);
154             } else {
155                 m_options = static_cast<options>(m_options & ~options::md_uid);
156             }
157         }
158 
user() const159         bool user() const noexcept {
160             return (m_options & options::md_user) != 0;
161         }
162 
set_user(bool flag)163         void set_user(bool flag) noexcept {
164             if (flag) {
165                 m_options = static_cast<options>(m_options | options::md_user);
166             } else {
167                 m_options = static_cast<options>(m_options & ~options::md_user);
168             }
169         }
170 
operator &=(const metadata_options & other)171         metadata_options operator&=(const metadata_options& other) {
172             m_options = static_cast<options>(other.m_options & m_options);
173             return *this;
174         }
175 
operator |=(const metadata_options & other)176         metadata_options operator|=(const metadata_options& other) {
177             m_options = static_cast<options>(other.m_options | m_options);
178             return *this;
179         }
180 
to_string() const181         std::string to_string() const {
182             std::string result;
183 
184             if (none()) {
185                 result = "none";
186                 return result;
187             }
188 
189             if (all()) {
190                 result = "all";
191                 return result;
192             }
193 
194             if (version()) {
195                 result += "version+";
196             }
197 
198             if (timestamp()) {
199                 result += "timestamp+";
200             }
201 
202             if (changeset()) {
203                 result += "changeset+";
204             }
205 
206             if (uid()) {
207                 result += "uid+";
208             }
209 
210             if (user()) {
211                 result += "user+";
212             }
213 
214             // remove last '+' character
215             result.pop_back();
216 
217             return result;
218         }
219 
220     }; // class metadata_options
221 
222     template <typename TChar, typename TTraits>
operator <<(std::basic_ostream<TChar,TTraits> & out,const metadata_options & options)223     inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const metadata_options& options) {
224         return out << options.to_string();
225     }
226 
227     /**
228      * Create an instance of metadata_options based on the availability of
229      * metadata of an instance of osmium::OSMObject.
230      */
detect_available_metadata(const osmium::OSMObject & object)231     inline osmium::metadata_options detect_available_metadata(const osmium::OSMObject& object) {
232         osmium::metadata_options opts;
233 
234         opts.set_version(object.version() > 0);
235         opts.set_timestamp(object.timestamp().valid());
236         opts.set_changeset(object.changeset() > 0);
237 
238         // Objects by anonymous users don't have these attributes set. There is no way
239         // to distinguish them from objects with a reduced number of metadata fields.
240         opts.set_uid(object.uid() > 0);
241         opts.set_user(object.user()[0] != '\0');
242 
243         return opts;
244     }
245 
246 } // namespace osmium
247 
248 #endif // OSMIUM_OSM_METADATA_OPTIONS_HPP
249