1 /******************************************************************************
2 * Copyright (c) 2012, Howard Butler hobu.inc@gmail.com
3 *
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following
8 * conditions are met:
9 *
10 *     * Redistributions of source code must retain the above copyright
11 *       notice, this list of conditions and the following disclaimer.
12 *     * Redistributions in binary form must reproduce the above copyright
13 *       notice, this list of conditions and the following disclaimer in
14 *       the documentation and/or other materials provided
15 *       with the distribution.
16 *     * Neither the name of Hobu, Inc. or Flaxen Geo Consulting nor the
17 *       names of its contributors may be used to endorse or promote
18 *       products derived from this software without specific prior
19 *       written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
28 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
32 * OF SUCH DAMAGE.
33 ****************************************************************************/
34 
35 #pragma once
36 
37 #include <pdal/pdal_internal.hpp>
38 
39 #include <pdal/util/Bounds.hpp>
40 #include <pdal/util/Utils.hpp>
41 #include <pdal/util/Uuid.hpp>
42 
43 #include <map>
44 #include <memory>
45 #include <vector>
46 #include <stdint.h>
47 
48 namespace pdal
49 {
50 
51 class SpatialReference;
52 
53 enum class MetadataType
54 {
55     Instance,
56     Array
57 };
58 
59 class Metadata;
60 class MetadataNode;
61 class MetadataNodeImpl;
62 typedef std::shared_ptr<MetadataNodeImpl> MetadataNodeImplPtr;
63 typedef std::vector<MetadataNodeImplPtr> MetadataImplList;
64 typedef std::map<std::string, MetadataImplList> MetadataSubnodes;
65 typedef std::vector<MetadataNode> MetadataNodeList;
66 
67 class PDAL_DLL MetadataNodeImpl
68 {
69     friend class MetadataNode;
70 
71 private:
MetadataNodeImpl(const std::string & name)72     MetadataNodeImpl(const std::string& name) : m_kind(MetadataType::Instance)
73         { m_name = name; }
74 
MetadataNodeImpl()75     MetadataNodeImpl() : m_kind(MetadataType::Instance)
76     {}
77 
makeArray(MetadataImplList & l)78     void makeArray(MetadataImplList& l)
79     {
80         for (auto li = l.begin(); li != l.end(); ++li)
81         {
82             MetadataNodeImplPtr node = *li;
83             node->m_kind = MetadataType::Array;
84         }
85     }
86 
add(const std::string & name)87     MetadataNodeImplPtr add(const std::string& name)
88     {
89         MetadataNodeImplPtr sub(new MetadataNodeImpl(name));
90         MetadataImplList& l = m_subnodes[name];
91         l.push_back(sub);
92         if (l.size() > 1)
93             makeArray(l);
94         return sub;
95     }
96 
addList(const std::string & name)97     MetadataNodeImplPtr addList(const std::string& name)
98     {
99         MetadataNodeImplPtr sub(new MetadataNodeImpl(name));
100         MetadataImplList& l = m_subnodes[name];
101         l.push_back(sub);
102         makeArray(l);
103         return sub;
104     }
105 
add(MetadataNodeImplPtr node)106     MetadataNodeImplPtr add(MetadataNodeImplPtr node)
107     {
108         MetadataImplList& l = m_subnodes[node->m_name];
109         l.push_back(node);
110         if (l.size() > 1)
111             makeArray(l);
112         return node;
113     }
114 
addList(MetadataNodeImplPtr node)115     MetadataNodeImplPtr addList(MetadataNodeImplPtr node)
116     {
117         MetadataImplList& l = m_subnodes[node->m_name];
118         l.push_back(node);
119         makeArray(l);
120         return node;
121     }
122 
replace(MetadataNodeImplPtr node)123     MetadataNodeImplPtr replace(MetadataNodeImplPtr node)
124     {
125         auto ni = m_subnodes.find(node->m_name);
126         if (ni == m_subnodes.end())
127             return MetadataNodeImplPtr();
128         MetadataImplList& l = ni->second;
129         if (l.size() != 1)
130             return MetadataNodeImplPtr();
131         l.front() = node;
132         return node;
133     }
134 
operator ==(const MetadataNodeImpl & m) const135     bool operator == (const MetadataNodeImpl& m) const
136     {
137         if (m_name != m.m_name || m_descrip != m.m_descrip ||
138             m_type != m.m_type || m_value != m.m_value)
139             return false;
140         if (m_subnodes.size() != m.m_subnodes.size())
141             return false;
142 
143         auto mi2 = m.m_subnodes.begin();
144         for (auto mi = m_subnodes.begin(); mi != m_subnodes.end(); ++mi, ++mi2)
145         {
146             if (mi->first != mi2->first)
147                 return false;
148             const MetadataImplList& ml = mi->second;
149             const MetadataImplList& ml2 = mi->second;
150             if (ml.size() != ml2.size())
151                 return false;
152             auto li2 = ml2.begin();
153             for (auto li = ml.begin(); li != ml.end(); ++li, ++li2)
154             {
155                 auto node1 = *li;
156                 auto node2 = *li2;
157                 if (!(*node1 == *node2))
158                     return false;
159             }
160         }
161         return true;
162     }
163 
164     template <typename T>
setValue(const T & t)165     inline void setValue(const T& t)
166     {
167         m_type = "unknown";
168         m_value = Utils::toString(t);
169     }
170 
171     template <std::size_t N>
172     inline void setValue(const char(& c)[N]);
173 
174     void setValue(const double& d, size_t precision);
175 
subnodes(const std::string & name)176     MetadataImplList& subnodes(const std::string &name)
177     {
178         auto si = m_subnodes.find(name);
179         if (si != m_subnodes.end())
180             return si->second;
181 
182         static MetadataImplList l;
183         return l;
184     }
185 
subnodes(const std::string & name) const186     const MetadataImplList& subnodes(const std::string& name) const
187     {
188         MetadataNodeImpl *nc_this = const_cast<MetadataNodeImpl *>(this);
189         return nc_this->subnodes(name);
190     }
191 
nodeType(const std::string & name) const192     MetadataType nodeType(const std::string& name) const
193     {
194         const MetadataImplList& l = subnodes(name);
195         if (l.size())
196         {
197             MetadataNodeImplPtr node = *l.begin();
198             return node->m_kind;
199         }
200         return MetadataType::Instance;
201     }
202 
203     std::string m_name;
204     std::string m_descrip;
205     std::string m_type;
206     std::string m_value;
207     MetadataType m_kind;
208     MetadataSubnodes m_subnodes;
209 };
210 
211 template <>
setValue(const bool & b)212 inline void MetadataNodeImpl::setValue(const bool& b)
213 {
214     m_type = "boolean";
215     m_value = b ? "true" : "false";
216 }
217 
218 template <>
setValue(const std::string & s)219 inline void MetadataNodeImpl::setValue(const std::string& s)
220 {
221     m_type = "string";
222     m_value = s;
223 }
224 
225 template <>
setValue(const char * const & c)226 inline void MetadataNodeImpl::setValue(const char * const & c)
227 {
228     m_type = "string";
229     m_value = c;
230 }
231 
232 template <std::size_t N>
setValue(const char (& c)[N])233 inline void MetadataNodeImpl::setValue(const char(& c)[N])
234 {
235     m_type = "string";
236     m_value = c;
237 }
238 
239 template <>
setValue(const float & f)240 inline void MetadataNodeImpl::setValue(const float& f)
241 {
242     m_type = "float";
243     m_value = Utils::toString(f);
244 }
245 
246 template <>
setValue(const double & d)247 inline void MetadataNodeImpl::setValue<double>(const double& d)
248 {
249     m_type = "double";
250 
251     // Get rid of -0.
252     double dd = d;
253     if (dd == 0.0)
254         dd = 0.0;
255     m_value = Utils::toString(dd);
256 }
257 
setValue(const double & d,size_t precision)258 inline void MetadataNodeImpl::setValue(const double& d,
259     size_t precision)
260 {
261     m_type = "double";
262 
263     // Get rid of -0.
264     double dd = d;
265     if (dd == 0.0)
266         dd = 0.0;
267     m_value = Utils::toString(dd, precision);
268 }
269 
270 template <>
271 void PDAL_DLL MetadataNodeImpl::setValue(const SpatialReference& ref);
272 
273 template <>
setValue(const BOX3D & b)274 inline void MetadataNodeImpl::setValue(const BOX3D& b)
275 {
276     m_type = "bounds";
277     m_value = Utils::toString(b);
278 }
279 
280 template <>
setValue(const unsigned char & u)281 inline void MetadataNodeImpl::setValue(const unsigned char& u)
282 {
283     m_type = "nonNegativeInteger";
284     m_value = Utils::toString(u);
285 }
286 
287 template <>
setValue(const unsigned short & u)288 inline void MetadataNodeImpl::setValue(const unsigned short& u)
289 {
290     m_type = "nonNegativeInteger";
291     m_value = Utils::toString(u);
292 }
293 
294 template <>
setValue(const unsigned int & u)295 inline void MetadataNodeImpl::setValue(const unsigned int& u)
296 {
297     m_type = "nonNegativeInteger";
298     m_value = Utils::toString(u);
299 }
300 
301 template <>
setValue(const unsigned long & u)302 inline void MetadataNodeImpl::setValue(const unsigned long& u)
303 {
304     m_type = "nonNegativeInteger";
305     m_value = Utils::toString(u);
306 }
307 
308 template <>
setValue(const unsigned long long & u)309 inline void MetadataNodeImpl::setValue(const unsigned long long& u)
310 {
311     m_type = "nonNegativeInteger";
312     m_value = Utils::toString(u);
313 }
314 
315 template <>
setValue(const char & i)316 inline void MetadataNodeImpl::setValue(const char& i)
317 {
318     m_type = "integer";
319     m_value = Utils::toString(i);
320 }
321 
322 template <>
setValue(const signed char & i)323 inline void MetadataNodeImpl::setValue(const signed char& i)
324 {
325     m_type = "integer";
326     m_value = Utils::toString(i);
327 }
328 
329 template <>
setValue(const short & s)330 inline void MetadataNodeImpl::setValue(const short& s)
331 {
332     m_type = "integer";
333     m_value = Utils::toString(s);
334 }
335 
336 template <>
setValue(const int & i)337 inline void MetadataNodeImpl::setValue(const int& i)
338 {
339     m_type = "integer";
340     m_value = Utils::toString(i);
341 }
342 
343 template <>
setValue(const long & l)344 inline void MetadataNodeImpl::setValue(const long& l)
345 {
346     m_type = "integer";
347     m_value = Utils::toString(l);
348 }
349 
350 template <>
setValue(const long long & l)351 inline void MetadataNodeImpl::setValue(const long long& l)
352 {
353     m_type = "integer";
354     m_value = Utils::toString(l);
355 }
356 
357 template <>
setValue(const Uuid & u)358 inline void MetadataNodeImpl::setValue(const Uuid& u)
359 {
360     m_type = "uuid";
361     m_value = u.toString();
362 }
363 
364 namespace MetadataDetail
365 {
366 
367 class value_error
368 {};
369 
370 template<typename T>
value(const std::string & type,const std::string & value)371 T value(const std::string& type, const std::string& value)
372 {
373     T t{};
374 
375     if (type == "base64Binary")
376     {
377         std::vector<uint8_t> encVal = Utils::base64_decode(value);
378         encVal.resize(sizeof(T));
379         t = *(reinterpret_cast<T *>(encVal.data()));
380     }
381     else if (!Utils::fromString(value, t))
382         throw value_error();
383     return t;
384 }
385 
386 template<>
value(const std::string &,const std::string & value)387 inline std::string value(const std::string&, const std::string& value)
388 { return value; }
389 
390 } // namespace MetadataDetail
391 
392 
393 class PDAL_DLL MetadataNode
394 {
395     friend class Metadata;
396     friend inline
397         bool operator == (const MetadataNode& m1, const MetadataNode& m2);
398     friend inline
399         bool operator != (const MetadataNode& m1, const MetadataNode& m2);
400 
401 public:
MetadataNode()402     MetadataNode() : m_impl(new MetadataNodeImpl())
403         {}
404 
MetadataNode(const std::string & name)405     MetadataNode(const std::string& name) : m_impl(new MetadataNodeImpl(name))
406         {}
407 
add(const std::string & name)408     MetadataNode add(const std::string& name)
409         { return MetadataNode(m_impl->add(name)); }
410 
addList(const std::string & name)411     MetadataNode addList(const std::string& name)
412         { return MetadataNode(m_impl->addList(name)); }
413 
clone(const std::string & name) const414     MetadataNode clone(const std::string& name) const
415     {
416         MetadataNode node;
417         node.m_impl.reset(new MetadataNodeImpl(*m_impl));
418         node.m_impl->m_name = name;
419         return node;
420     }
421 
add(MetadataNode node)422     MetadataNode add(MetadataNode node)
423         { return MetadataNode(m_impl->add(node.m_impl)); }
424 
addList(MetadataNode node)425     MetadataNode addList(MetadataNode node)
426         { return MetadataNode(m_impl->addList(node.m_impl)); }
427 
addEncoded(const std::string & name,const unsigned char * buf,size_t size,const std::string & descrip=std::string ())428     MetadataNode addEncoded(const std::string& name,
429         const unsigned char *buf, size_t size,
430         const std::string& descrip = std::string())
431     {
432         MetadataNodeImplPtr impl = m_impl->add(name);
433         impl->setValue(Utils::base64_encode(buf, size));
434         impl->m_type = "base64Binary";
435         impl->m_descrip = descrip;
436         return MetadataNode(impl);
437     }
438 
addListEncoded(const std::string & name,const unsigned char * buf,size_t size,const std::string & descrip=std::string ())439     MetadataNode addListEncoded(const std::string& name,
440         const unsigned char *buf, size_t size,
441         const std::string& descrip = std::string())
442     {
443         MetadataNodeImplPtr impl = m_impl->addList(name);
444         impl->setValue(Utils::base64_encode(buf, size));
445         impl->m_type = "base64Binary";
446         impl->m_descrip = descrip;
447         return MetadataNode(impl);
448     }
449 
addWithType(const std::string & name,const std::string & value,const std::string & type,const std::string & descrip)450     MetadataNode addWithType(const std::string& name, const std::string& value,
451         const std::string& type, const std::string& descrip)
452     {
453         MetadataNodeImplPtr impl = m_impl->add(name);
454         impl->m_type = type;
455         impl->m_value = value;
456         impl->m_descrip = descrip;
457         return MetadataNode(impl);
458     }
459 
add(const std::string & name,const double & value,const std::string & descrip=std::string (),size_t precision=10)460     MetadataNode add(const std::string& name, const double& value,
461         const std::string& descrip = std::string(), size_t precision = 10)
462     {
463         MetadataNodeImplPtr impl = m_impl->add(name);
464         impl->setValue(value, precision);
465         impl->m_descrip = descrip;
466         return MetadataNode(impl);
467     }
468 
469     template<typename T>
add(const std::string & name,const T & value,const std::string & descrip=std::string ())470     MetadataNode add(const std::string& name, const T& value,
471         const std::string& descrip = std::string())
472     {
473         MetadataNodeImplPtr impl = m_impl->add(name);
474         impl->setValue(value);
475         impl->m_descrip = descrip;
476         return MetadataNode(impl);
477     }
478 
479     template<typename T>
addList(const std::string & name,const T & value,const std::string & descrip=std::string ())480     MetadataNode addList(const std::string& name, const T& value,
481         const std::string& descrip = std::string())
482     {
483         MetadataNodeImplPtr impl = m_impl->addList(name);
484         impl->setValue(value);
485         impl->m_descrip = descrip;
486         return MetadataNode(impl);
487     }
488 
addOrUpdate(const std::string & lname,const double & value,const std::string & descrip=std::string (),size_t precision=10)489     MetadataNode addOrUpdate(const std::string& lname, const double& value,
490         const std::string& descrip = std::string(), size_t precision = 10)
491     {
492         if (m_impl->nodeType(lname) == MetadataType::Array)
493             throw pdal_error("Can't call addOrUpdate() on subnode list.");
494         MetadataImplList& l = m_impl->subnodes(lname);
495 
496         if (l.empty())
497             return add(lname, value, descrip, precision);
498         MetadataNodeImplPtr impl(new MetadataNodeImpl(lname));
499         impl->setValue(value, precision);
500         l.front() = impl;
501         return MetadataNode(impl);
502     }
503 
504     template<typename T>
addOrUpdate(const std::string & lname,const T & value)505     MetadataNode addOrUpdate(const std::string& lname, const T& value)
506     {
507         if (m_impl->nodeType(lname) == MetadataType::Array)
508             throw pdal_error("Can't call addOrUpdate() on subnode list.");
509         MetadataImplList& l = m_impl->subnodes(lname);
510 
511         if (l.empty())
512             return add(lname, value);
513         MetadataNodeImplPtr impl(new MetadataNodeImpl(lname));
514         impl->setValue(value);
515         l.front() = impl;
516         return MetadataNode(impl);
517     }
518 
519     template<typename T>
addOrUpdate(const std::string & lname,const T & value,const std::string & descrip)520     MetadataNode addOrUpdate(const std::string& lname, const T& value,
521         const std::string& descrip)
522     {
523         MetadataNode m = addOrUpdate(lname, value);
524         m.m_impl->m_descrip = descrip;
525         return m;
526     }
527 
addOrUpdate(MetadataNode n)528     MetadataNode addOrUpdate(MetadataNode n)
529     {
530         if (m_impl->nodeType(n.name()) == MetadataType::Array)
531             throw pdal_error("Can't call addOrUpdate() on subnode list.");
532 
533         MetadataNode m;
534         if (m_impl->subnodes(n.name()).empty())
535             m = add(n);
536         else
537             m = MetadataNode(m_impl->replace(n.m_impl));
538         return m;
539     }
540 
type() const541     std::string type() const
542         { return m_impl->m_type; }
543 
kind() const544     MetadataType kind() const
545         { return m_impl->m_kind; }
546 
name() const547     std::string name() const
548         { return m_impl->m_name; }
549 
550     template<typename T>
value() const551     T value() const
552     {
553         T t{};
554 
555         try
556         {
557             t = MetadataDetail::value<T>(m_impl->m_type, m_impl->m_value);
558         }
559         catch (MetadataDetail::value_error&)
560         {
561             // Reset in case the fromString conversion messed it up.
562             t = T();
563             std::cerr << "Error converting metadata [" << name() <<
564                 "] = " << m_impl->m_value << " to type " <<
565                 Utils::typeidName<T>() << " -- return default initialized.";
566         }
567         return t;
568     }
569 
value() const570     std::string value() const
571     {
572         return value<std::string>();
573     }
574 
jsonValue() const575     std::string jsonValue() const
576     {
577         if (m_impl->m_type == "json")
578             return value();
579 
580         std::string v(Utils::escapeJSON(value()));
581         if (m_impl->m_type == "double")
582             if (v == "NaN" || v == "Infinity" || v == "-Infinity")
583                 v = "\"" + v + "\"";
584         if (m_impl->m_type == "string" || m_impl->m_type == "base64Binary" ||
585             m_impl->m_type == "uuid" || m_impl->m_type == "matrix")
586         {
587             std::string val("\"");
588             val += escapeQuotes(v) + "\"";
589             return val;
590         }
591 
592         return v;
593     }
594 
description() const595     std::string description() const
596         { return m_impl->m_descrip; }
597 
children() const598     MetadataNodeList children() const
599     {
600         MetadataNodeList outnodes;
601 
602         const MetadataSubnodes& nodes = m_impl->m_subnodes;
603         for (auto si = nodes.begin(); si != nodes.end(); ++si)
604         {
605             const MetadataImplList& l = si->second;
606             for (auto li = l.begin(); li != l.end(); ++li)
607                 outnodes.push_back(MetadataNode(*li));
608         }
609         return outnodes;
610     }
611 
children(const std::string & name) const612     MetadataNodeList children(const std::string& name) const
613     {
614         MetadataNodeList outnodes;
615 
616         auto si = m_impl->m_subnodes.find(name);
617         if (si != m_impl->m_subnodes.end())
618         {
619             const MetadataImplList& l = si->second;
620             for (auto li = l.begin(); li != l.end(); ++li)
621                 outnodes.push_back(MetadataNode(*li));
622         }
623         return outnodes;
624     }
625 
hasChildren() const626     bool hasChildren() const
627         { return m_impl->m_subnodes.size(); }
628 
childNames() const629     std::vector<std::string> childNames() const
630     {
631         std::vector<std::string> names;
632 
633         MetadataSubnodes& nodes = m_impl->m_subnodes;
634         for (auto si = nodes.begin(); si != nodes.end(); ++si)
635             names.push_back(si->first);
636         return names;
637     }
638 
operator bool() const639     operator bool () const
640         { return !empty(); }
operator !()641     bool operator ! ()
642         { return empty(); }
valid() const643     bool valid() const
644         { return !empty(); }
empty() const645     bool empty() const
646         { return m_impl->m_name.empty() && !hasChildren(); }
647 
648     template <typename PREDICATE>
find(PREDICATE p) const649     MetadataNode find(PREDICATE p) const
650     {
651         if (p(*this))
652             return *this;
653         auto nodes = children();
654         for (auto ai = nodes.begin(); ai != nodes.end(); ++ai)
655         {
656             MetadataNode n = ai->find(p);
657             if (!n.empty())
658                 return n;
659         }
660         return MetadataNode();
661     }
662 
663     template <typename PREDICATE>
findChildren(PREDICATE p)664     MetadataNodeList findChildren(PREDICATE p)
665     {
666         MetadataNodeList matches;
667 
668         auto nodes = children();
669         for (auto ai = nodes.begin(); ai != nodes.end(); ++ai)
670         {
671             MetadataNode& n = *ai;
672             if (p(n))
673                 matches.push_back(n);
674         }
675         return matches;
676     }
677 
678     template <typename PREDICATE>
findChild(PREDICATE p) const679     MetadataNode findChild(PREDICATE p) const
680     {
681         auto nodes = children();
682         for (auto ai = nodes.begin(); ai != nodes.end(); ++ai)
683         {
684             MetadataNode& n = *ai;
685             if (p(n))
686                 return n;
687         }
688         return MetadataNode();
689     }
690 
findChild(const char * s) const691     MetadataNode findChild(const char *s) const
692         { return findChild(std::string(s)); }
693 
findChild(std::string s) const694     MetadataNode findChild(std::string s) const
695     {
696         auto splitString = [](std::string& s) -> std::string
697         {
698             std::string val;
699             size_t pos = s.find(':');
700             if (pos == std::string::npos)
701             {
702                 val = s;
703                 s.clear();
704             }
705             else
706             {
707                 val = s.substr(0, pos);
708                 s = (pos == s.size() - 1) ? "" : s.substr(pos + 1);
709             }
710             return val;
711         };
712 
713         if (s.empty())
714             return *this;
715         std::string lname = splitString(s);
716         auto nodes = children(lname);
717         for (auto ai = nodes.begin(); ai != nodes.end(); ++ai)
718         {
719             MetadataNode& n = *ai;
720             MetadataNode child = n.findChild(s);
721             if (!child.empty())
722                 return child;
723         }
724         return MetadataNode();
725     }
726 
727 private:
728     MetadataNodeImplPtr m_impl;
729 
MetadataNode(MetadataNodeImplPtr node)730     MetadataNode(MetadataNodeImplPtr node) : m_impl(node)
731         {}
732 
escapeQuotes(const std::string & in) const733     std::string escapeQuotes(const std::string& in) const
734     {
735         std::string out;
736         for (std::size_t i(0); i < in.size(); ++i)
737         {
738             if (in[i] == '"' && ((i && in[i - 1] != '\\') || !i))
739             {
740                 out.push_back('\\');
741             }
742             out.push_back(in[i]);
743         }
744         return out;
745     }
746 };
747 
operator ==(const MetadataNode & m1,const MetadataNode & m2)748 inline bool operator == (const MetadataNode& m1, const MetadataNode& m2)
749 {
750     return m1.m_impl == m2.m_impl;
751 }
752 
operator !=(const MetadataNode & m1,const MetadataNode & m2)753 inline bool operator != (const MetadataNode& m1, const MetadataNode& m2)
754 {
755     return !(m1.m_impl == m2.m_impl);
756 }
757 
758 
759 class Metadata
760 {
761     friend class BasePointTable;
762 
763 public:
Metadata()764     Metadata() : m_root("root"), m_private("private")
765     {}
766 
Metadata(const std::string & name)767     Metadata(const std::string& name) : m_name(name)
768     {}
769 
getNode() const770     MetadataNode getNode() const
771         { return m_root; }
772 
773     static std::string PDAL_DLL inferType(const std::string& val);
774 private:
775     MetadataNode m_root;
776     MetadataNode m_private;
777     std::string m_name;
778 };
779 typedef std::shared_ptr<Metadata> MetadataPtr;
780 
781 } // namespace pdal
782 
783 
784