00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059 #ifndef LIBLAS_GUID_HPP_INCLUDED
00060 #define LIBLAS_GUID_HPP_INCLUDED
00061
00062 #include <liblas/cstdint.hpp>
00063 #include <liblas/detail/sha1.hpp>
00064 #include <liblas/detail/utility.hpp>
00065 #include <iosfwd>
00066 #include <iomanip>
00067 #include <algorithm>
00068 #include <limits>
00069 #include <stdexcept>
00070 #include <sstream>
00071 #include <string>
00072 #include <cstdlib>
00073 #include <cstring>
00074 #include <ctime>
00075 #include <cassert>
00076
00077 namespace liblas {
00078
00088 class guid
00089 {
00090 public:
00091
00095 guid()
00096 {
00097 std::fill(data_, data_ + static_size, 0);
00098 }
00099
00104 explicit guid(char const* const str)
00105 {
00106 if (0 == str)
00107 throw_invalid_argument();
00108 construct(std::string(str));
00109 }
00110
00115 template <typename ch, typename char_traits, typename alloc>
00116 explicit guid(std::basic_string<ch, char_traits, alloc> const& str)
00117 {
00118 construct(str);
00119 }
00120
00128 guid(liblas::uint32_t const& d1, liblas::uint16_t const& d2, liblas::uint16_t const& d3, liblas::uint8_t const (&d4)[8])
00129 {
00130 construct(d1, d2, d3, d4);
00131 }
00132
00135 guid(guid const& rhs)
00136 {
00137 std::copy(rhs.data_, rhs.data_ + static_size, data_);
00138 }
00139
00142 ~guid()
00143 {}
00144
00147 guid& operator=(guid const& rhs)
00148 {
00149 if (&rhs != this)
00150 {
00151 std::copy(rhs.data_, rhs.data_ + static_size, data_);
00152 }
00153 return *this;
00154 }
00155
00158 bool operator==(guid const& rhs) const
00159 {
00160 return std::equal(data_, data_ + static_size, rhs.data_);
00161 }
00162
00165 bool operator!=(guid const& rhs) const
00166 {
00167 return (!(*this == rhs));
00168 }
00169
00175 bool operator<(guid const& rhs) const
00176 {
00177 return std::lexicographical_compare(data_, data_ + static_size, rhs.data_, rhs.data_ + static_size);
00178 }
00179
00185 bool operator>(guid const& rhs) const
00186 {
00187 return std::lexicographical_compare(rhs.data_, rhs.data_ + static_size, data_, data_ + static_size);
00188 }
00189
00193 bool operator<=(guid const& rhs) const
00194 {
00195 return (*this == rhs) || (*this < rhs);
00196 }
00197
00201 bool operator>=(guid const& rhs) const
00202 {
00203 return (*this == rhs) || (*this > rhs);
00204 }
00205
00210 bool is_null() const
00211 {
00212 return ((*this) == null());
00213 }
00214
00220 std::string to_string() const
00221 {
00222 return to_basic_string<std::string::value_type, std::string::traits_type, std::string::allocator_type>();
00223 }
00224
00228 template <typename ch, typename char_traits, typename alloc>
00229 std::basic_string<ch, char_traits, alloc> to_basic_string() const
00230 {
00231 std::basic_string<ch, char_traits, alloc> s;
00232 std::basic_stringstream<ch, char_traits, alloc> ss;
00233 liblas::guid const& g = *this;
00234 ss << g;
00235 if (!ss || !(ss >> s))
00236 {
00237 throw std::runtime_error("failed to convert guid to string");
00238 }
00239
00240 assert(!s.empty());
00241 return s;
00242 }
00243
00247 size_t byte_count() const
00248 {
00249 return static_size;
00250 }
00251
00252
00255 template <typename ByteOutputIterator>
00256 void output_bytes(ByteOutputIterator out) const
00257 {
00258 std::copy(data_, data_ + static_size, out);
00259 }
00260
00267 void output_data(liblas::uint32_t& d1, liblas::uint16_t& d2, liblas::uint16_t& d3, liblas::uint8_t (&d4)[8]) const
00268 {
00269 d1 = d2 = d3 = 0;
00270 std::size_t pos = 0;
00271 int const charbit = std::numeric_limits<liblas::uint8_t>::digits;
00272
00273 for (; pos < 4; ++pos)
00274 {
00275
00276 d1 <<= charbit;
00277 d1 |= static_cast<unsigned char>(data_[pos]);
00278 }
00279
00280 for (; pos < 6; ++pos)
00281 {
00282 d2 <<= charbit;
00283 d2 |= static_cast<unsigned char>(data_[pos]);
00284 }
00285
00286 for (; pos < 8; ++pos)
00287 {
00288 d3 <<= charbit;
00289 d3 |= static_cast<unsigned char>(data_[pos]);
00290 }
00291
00292 for (std::size_t j = 0; j < sizeof(d4); ++j)
00293 {
00294 d4[j] = data_[j + 8];
00295 }
00296 }
00297
00301 static guid const& null()
00302 {
00303 static const guid n;
00304 return n;
00305 }
00306
00310 static guid create()
00311 {
00312 return create_random_based();
00313 }
00314
00317 static guid create(guid const& namespace_guid, char const* name, int name_length)
00318 {
00319 return create_name_based(namespace_guid, name, name_length);
00320 }
00321
00324 static inline bool get_showbraces(std::ios_base & iosbase)
00325 {
00326 return (iosbase.iword(get_showbraces_index()) != 0);
00327 }
00328
00331 static inline void set_showbraces(std::ios_base & iosbase, bool showbraces)
00332 {
00333 iosbase.iword(get_showbraces_index()) = showbraces;
00334 }
00335
00338 static inline std::ios_base& showbraces(std::ios_base& iosbase)
00339 {
00340 set_showbraces(iosbase, true);
00341 return iosbase;
00342 }
00343 static inline std::ios_base& noshowbraces(std::ios_base& iosbase)
00344 {
00345 set_showbraces(iosbase, false);
00346 return iosbase;
00347 }
00348
00350 friend std::ostream& operator<<(std::ostream& os, guid const& g);
00351
00353 friend std::istream& operator>>(std::istream& is, guid &g);
00354
00355 private:
00356
00357 void throw_invalid_argument() const
00358 {
00359 throw std::invalid_argument("invalid guid string");
00360 }
00361
00362 template <typename ch, typename char_traits, typename alloc>
00363 void construct(std::basic_string<ch, char_traits, alloc> const& str)
00364 {
00365 std::basic_stringstream <ch, char_traits, alloc > ss;
00366 if (!(ss << str) || !(ss >> *this))
00367 {
00368 throw_invalid_argument();
00369 }
00370 }
00371
00372 void construct(liblas::uint32_t const& d1, liblas::uint16_t const& d2, liblas::uint16_t const& d3, liblas::uint8_t const (&d4)[8])
00373 {
00374 std::ostringstream ss;
00375 ss.flags(std::ios::hex);
00376 ss.fill('0');
00377
00378 ss.width(8);
00379 ss << d1;
00380 ss << '-';
00381
00382 ss.width(4);
00383 ss << d2;
00384 ss << '-';
00385
00386 ss.width(4);
00387 ss << d3;
00388 ss << '-';
00389
00390 for (std::size_t i = 0; i < sizeof(d4); ++i)
00391 {
00392 ss.width(2);
00393 ss << static_cast<liblas::uint32_t>(d4[i]);
00394 if (1 == i)
00395 ss << '-';
00396 }
00397
00398 construct(ss.str());
00399 }
00400
00401
00402 static guid create_random_based()
00403 {
00404 guid result;
00405 static bool init_rand = true;
00406 if (init_rand)
00407 {
00408 std::srand(static_cast<unsigned int>(std::time(0)));
00409 init_rand = false;
00410 }
00411
00412 for (size_t i = 0; i < static_size; i++)
00413 {
00414 result.data_[i] = detail::generate_random_byte<liblas::uint8_t>();
00415 }
00416
00417
00418
00419 result.data_[8] &= 0xBF;
00420 result.data_[8] |= 0x80;
00421
00422
00423
00424 result.data_[6] &= 0x4F;
00425 result.data_[6] |= 0x40;
00426
00427 return result;
00428 }
00429
00430
00431 static guid create_name_based(guid const& namespace_guid, char const* name, int name_length)
00432 {
00433 using liblas::uint8_t;
00434
00435 detail::SHA1 sha1;
00436 sha1.Input(namespace_guid.data_, namespace_guid.static_size);
00437 sha1.Input(name, name_length);
00438 unsigned int digest[5];
00439
00440 if (sha1.Result(digest) == false)
00441 {
00442 throw std::runtime_error("create error");
00443 }
00444
00445 guid result;
00446 for (int i = 0; i < 4; ++i)
00447 {
00448
00449 result.data_[i*4+0] = static_cast<uint8_t>((digest[i] >> 24) & 0xFF);
00450 result.data_[i*4+1] = static_cast<uint8_t>((digest[i] >> 16) & 0xFF);
00451 result.data_[i*4+2] = static_cast<uint8_t>((digest[i] >> 8) & 0xFF);
00452 result.data_[i*4+3] = static_cast<uint8_t>((digest[i] >> 0) & 0xFF);
00453 }
00454
00455
00456
00457 result.data_[8] &= 0xBF;
00458 result.data_[8] |= 0x80;
00459
00460
00461
00462 result.data_[6] &= 0x5F;
00463 result.data_[6] |= 0x50;
00464
00465 return result;
00466 }
00467
00468 static int get_showbraces_index()
00469 {
00470 static int index = std::ios_base::xalloc();
00471 return index;
00472 }
00473
00474 private:
00475
00476 static const std::size_t static_size = 16;
00477 liblas::uint8_t data_[static_size];
00478 };
00479
00480 inline std::ostream& operator<<(std::ostream& os, guid const& g)
00481 {
00482 using namespace std;
00483
00484
00485
00486 std::ios_base::fmtflags flags_saver(os.flags());
00487 std::streamsize width_saver(os.width());
00488 std::ostream::char_type fill_saver(os.fill());
00489
00490 const std::ostream::sentry ok(os);
00491 if (ok)
00492 {
00493 bool showbraces = guid::get_showbraces(os);
00494 if (showbraces)
00495 {
00496 os << '{';
00497 }
00498 os << hex;
00499 os.fill('0');
00500 for (size_t i = 0; i < g.static_size; ++i)
00501 {
00502 os.width(2);
00503 os << static_cast<unsigned int>(g.data_[i]);
00504 if (i == 3 || i == 5 || i == 7 || i == 9)
00505 {
00506 os << '-';
00507 }
00508 }
00509 if (showbraces)
00510 {
00511 os << '}';
00512 }
00513 }
00514
00515 os.flags(flags_saver);
00516 os.width(width_saver);
00517 os.fill(fill_saver);
00518
00519 return os;
00520 }
00521
00522 inline std::istream& operator>>(std::istream& is, guid &g)
00523 {
00524 using namespace std;
00525
00526 typedef std::istream::char_type char_type;
00527 guid temp_guid;
00528 const std::istream::sentry ok(is);
00529 if (ok)
00530 {
00531 char_type c;
00532 c = static_cast<char_type>(is.peek());
00533 bool bHaveBraces = false;
00534 if (c == '{')
00535 {
00536 bHaveBraces = true;
00537 is >> c;
00538 }
00539
00540 for (size_t i = 0; i < temp_guid.static_size && is; ++i)
00541 {
00542 std::stringstream ss;
00543
00544
00545 is >> c; ss << c;
00546 is >> c; ss << c;
00547
00548
00549 unsigned int val = 0;
00550 ss >> hex >> val;
00551 if (!ss)
00552 {
00553 is.setstate(ios_base::failbit);
00554 }
00555
00556
00557 if (val > 255)
00558 {
00559 is.setstate(ios_base::badbit);
00560 }
00561
00562 temp_guid.data_[i] = static_cast<liblas::uint8_t>(val);
00563
00564 if (is)
00565 {
00566 if (i == 3 || i == 5 || i == 7 || i == 9)
00567 {
00568 is >> c;
00569 if (c != '-')
00570 is.setstate(ios_base::failbit);
00571 }
00572 }
00573 }
00574
00575 if (bHaveBraces && is)
00576 {
00577 is >> c;
00578 if (c != '}')
00579 is.setstate(ios_base::failbit);
00580 }
00581
00582 if (is)
00583 {
00584 g = temp_guid;
00585 }
00586 }
00587
00588 return is;
00589 }
00590
00591 }
00592
00593 #endif // LIBLAS_GUID_HPP_INCLUDED