|
17 | 17 | * * |
18 | 18 | ********************************************************************************/ |
19 | 19 |
|
20 | | -/******************************************************************************** |
21 | | - * * |
22 | | - * Please consider this a placeholder for an actual GlobalId generation * |
23 | | - * algorithm. A real implementation could for example be based on Boost::uuid * |
24 | | - * * |
25 | | - ********************************************************************************/ |
26 | | - |
27 | | -#include <time.h> |
28 | | -#include <stdlib.h> |
| 20 | +#include <vector> |
29 | 21 | #include <algorithm> |
30 | 22 |
|
31 | 23 | #include <boost/uuid/uuid.hpp> |
32 | 24 | #include <boost/uuid/uuid_generators.hpp> |
33 | 25 | #include <boost/uuid/uuid_io.hpp> |
34 | 26 |
|
35 | | -#include "../ifcparse/IfcWrite.h" |
| 27 | +#include "../ifcparse/IfcGlobalId.h" |
36 | 28 | #include "../ifcparse/IfcException.h" |
37 | 29 |
|
38 | 30 | static const char* chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_$"; |
39 | 31 |
|
40 | 32 | // Converts an unsigned integer into a base64 string of length l |
41 | 33 | std::string base64(unsigned v, int l) { |
42 | | - std::string r; |
43 | | - r.reserve(l); |
44 | | - while ( v ) { |
45 | | - r.push_back(chars[v%64]); |
46 | | - v /= 64; |
47 | | - } |
48 | | - while ( r.size() != l ) r.push_back('0'); |
49 | | - std::reverse(r.begin(),r.end()); |
50 | | - return r; |
| 34 | + std::string r; |
| 35 | + r.reserve(l); |
| 36 | + while ( v ) { |
| 37 | + r.push_back(chars[v%64]); |
| 38 | + v /= 64; |
| 39 | + } |
| 40 | + while ( r.size() != l ) r.push_back('0'); |
| 41 | + std::reverse(r.begin(),r.end()); |
| 42 | + return r; |
51 | 43 | } |
52 | 44 |
|
53 | 45 | // Converts a base64 string into an unsigned integer |
54 | 46 | unsigned from_base64(const std::string& s) { |
55 | | - std::string::size_type zeros = s.find_first_not_of('0'); |
56 | | - unsigned r = 0; |
57 | | - if ( zeros != std::string::npos ) |
58 | | - for ( std::string::const_iterator i = s.begin()+zeros; i != s.end(); ++ i ) { |
59 | | - r *= 64; |
60 | | - const char* c = strchr(chars,*i); |
61 | | - if ( !c ) throw IfcParse::IfcException("Failed to decode GlobalId"); |
62 | | - r += (c-chars); |
63 | | - } |
64 | | - return r; |
| 47 | + std::string::size_type zeros = s.find_first_not_of('0'); |
| 48 | + unsigned r = 0; |
| 49 | + if ( zeros != std::string::npos ) |
| 50 | + for ( std::string::const_iterator i = s.begin()+zeros; i != s.end(); ++ i ) { |
| 51 | + r *= 64; |
| 52 | + const char* c = strchr(chars,*i); |
| 53 | + if ( !c ) throw IfcParse::IfcException("Failed to decode GlobalId"); |
| 54 | + r += (c-chars); |
| 55 | + } |
| 56 | + return r; |
65 | 57 | } |
66 | 58 |
|
67 | 59 | // Compresses the UUID byte array into a base64 representation |
68 | 60 | std::string compress(unsigned char* v) { |
69 | | - std::string r; |
70 | | - r.reserve(22); |
71 | | - r += base64(v[0],2); |
72 | | - for ( unsigned i = 1; i < 16; i += 3 ) { |
73 | | - r += base64((v[i]<<16) + (v[i+1]<<8) + v[i+2],4); |
74 | | - } |
75 | | - return r; |
| 61 | + std::string r; |
| 62 | + r.reserve(22); |
| 63 | + r += base64(v[0],2); |
| 64 | + for ( unsigned i = 1; i < 16; i += 3 ) { |
| 65 | + r += base64((v[i]<<16) + (v[i+1]<<8) + v[i+2],4); |
| 66 | + } |
| 67 | + return r; |
76 | 68 | } |
77 | 69 |
|
78 | 70 | // Expands the base64 representation into a UUID byte array |
79 | 71 | void expand(const std::string& s, std::vector<unsigned char>& v) { |
80 | | - v.push_back(from_base64(s.substr(0,2))); |
81 | | - for( unsigned i = 0; i < 5; ++i ) { |
82 | | - unsigned d = from_base64(s.substr(2+4*i,4)); |
83 | | - for ( unsigned j = 0; j < 3; ++ j ) { |
84 | | - v.push_back((d>>(8*(2-j))) % 256); |
85 | | - } |
86 | | - } |
| 72 | + v.push_back(from_base64(s.substr(0,2))); |
| 73 | + for( unsigned i = 0; i < 5; ++i ) { |
| 74 | + unsigned d = from_base64(s.substr(2+4*i,4)); |
| 75 | + for ( unsigned j = 0; j < 3; ++ j ) { |
| 76 | + v.push_back((d>>(8*(2-j))) % 256); |
| 77 | + } |
| 78 | + } |
87 | 79 | } |
88 | 80 |
|
89 | 81 | // A random number generator for the UUID |
90 | 82 | static boost::uuids::basic_random_generator<boost::mt19937> gen; |
91 | 83 |
|
92 | | -IfcWrite::IfcGuidHelper::IfcGuidHelper() { |
93 | | - boost::uuids::uuid u = gen(); |
94 | | - std::vector<unsigned char> v(u.size()); |
95 | | - std::copy(u.begin(), u.end(), v.begin()); |
96 | | - data = compress(&v[0]); |
| 84 | +IfcParse::IfcGlobalId::IfcGlobalId() { |
| 85 | + uuid_data = gen(); |
| 86 | + std::vector<unsigned char> v(uuid_data.size()); |
| 87 | + std::copy(uuid_data.begin(), uuid_data.end(), v.begin()); |
| 88 | + string_data = compress(&v[0]); |
| 89 | + formatted_string = boost::uuids::to_string(uuid_data); |
| 90 | + |
| 91 | +#ifndef NDEBUG |
| 92 | + std::vector<unsigned char> test_vector; |
| 93 | + expand(string_data, test_vector); |
| 94 | + boost::uuids::uuid test_uuid; |
| 95 | + std::copy(test_vector.begin(), test_vector.end(), test_uuid.begin()); |
| 96 | + if (uuid_data != test_uuid) { |
| 97 | + throw IfcParse::IfcException("Internal error generating GlobalId"); |
| 98 | + } |
| 99 | +#endif |
| 100 | +} |
| 101 | + |
| 102 | +IfcParse::IfcGlobalId::IfcGlobalId(const std::string& s) |
| 103 | + : string_data(s) |
| 104 | +{ |
| 105 | + std::vector<unsigned char> v; |
| 106 | + expand(string_data, v); |
| 107 | + std::copy(v.begin(), v.end(), uuid_data.begin()); |
| 108 | + formatted_string = boost::uuids::to_string(uuid_data); |
| 109 | + |
| 110 | +#ifndef NDEBUG |
| 111 | + const std::string test_string = compress(&uuid_data.data[0]); |
| 112 | + if (string_data != test_string) { |
| 113 | + throw IfcParse::IfcException("Internal error generating GlobalId"); |
| 114 | + } |
| 115 | +#endif |
| 116 | +} |
97 | 117 |
|
98 | | - std::vector<unsigned char> v2; |
99 | | - expand(data,v2); |
100 | | - boost::uuids::uuid u2; |
101 | | - std::copy(v2.begin(), v2.end(), u2.begin()); |
| 118 | +IfcParse::IfcGlobalId::operator const std::string&() const { |
| 119 | + return string_data; |
102 | 120 | } |
103 | | -IfcWrite::IfcGuidHelper::operator std::string() const { |
104 | | - return data; |
| 121 | + |
| 122 | +IfcParse::IfcGlobalId::operator const boost::uuids::uuid&() const { |
| 123 | + return uuid_data; |
105 | 124 | } |
106 | 125 |
|
107 | | -bool IfcWrite::IfcGuidHelper::seeded = false; |
| 126 | +const std::string& IfcParse::IfcGlobalId::formatted() const { |
| 127 | + return formatted_string; |
| 128 | +} |
0 commit comments