• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  //
2  // C++ Implementation: GUIDData
3  //
4  // Description: GUIDData class header
5  // Implements the GUIDData data structure and support methods
6  //
7  //
8  // Author: Rod Smith <rodsmith@rodsbooks.com>, (C) 2010-2011
9  //
10  // Copyright: See COPYING file that comes with this distribution
11  //
12  //
13  
14  #define __STDC_LIMIT_MACROS
15  #define __STDC_CONSTANT_MACROS
16  
17  #include <stdio.h>
18  #include <time.h>
19  #include <string.h>
20  #include <string>
21  #include <iostream>
22  #include "guid.h"
23  #include "support.h"
24  
25  using namespace std;
26  
27  bool GUIDData::firstInstance = 1;
28  
GUIDData(void)29  GUIDData::GUIDData(void) {
30     if (firstInstance) {
31        srand((unsigned int) time(0));
32        firstInstance = 0;
33     } // if
34     Zero();
35  } // constructor
36  
GUIDData(const GUIDData & orig)37  GUIDData::GUIDData(const GUIDData & orig) {
38     memcpy(uuidData, orig.uuidData, sizeof(uuidData));
39  } // copy constructor
40  
GUIDData(const string & orig)41  GUIDData::GUIDData(const string & orig) {
42     operator=(orig);
43  } // copy (from string) constructor
44  
GUIDData(const char * orig)45  GUIDData::GUIDData(const char * orig) {
46     operator=(orig);
47  } // copy (from char*) constructor
48  
~GUIDData(void)49  GUIDData::~GUIDData(void) {
50  } // destructor
51  
operator =(const GUIDData & orig)52  GUIDData & GUIDData::operator=(const GUIDData & orig) {
53     memcpy(uuidData, orig.uuidData, sizeof(uuidData));
54     return *this;
55  } // GUIDData::operator=(const GUIDData & orig)
56  
57  // Assign the GUID from a string input value. A GUID is normally formatted
58  // with four dashes as element separators, for a total length of 36
59  // characters. If the input string is this long or longer, this function
60  // assumes standard separator positioning; if the input string is less
61  // than 36 characters long, this function assumes the input GUID has
62  // been compressed by removal of separators. In either event, there's
63  // little in the way of sanity checking, so garbage in = garbage out!
64  // One special case: If the first character is 'r' or 'R', a random
65  // GUID is assigned.
operator =(const string & orig)66  GUIDData & GUIDData::operator=(const string & orig) {
67     string copy, fragment;
68     size_t len;
69     // Break points for segments, either with or without characters separating the segments....
70     size_t longSegs[6] = {0, 9, 14, 19, 24, 36};
71     size_t shortSegs[6] = {0, 8, 12, 16, 20, 32};
72     size_t *segStart = longSegs; // Assume there are separators between segments
73  
74     // If first character is an 'R' or 'r', set a random GUID; otherwise,
75     // try to parse it as a real GUID
76     if ((orig[0] == 'R') || (orig[0] == 'r')) {
77        Randomize();
78     } else {
79        Zero();
80  
81        // Delete stray spaces....
82        copy = DeleteSpaces(orig);
83  
84        // If length is too short, assume there are no separators between segments
85        len = copy.length();
86        if (len < 36) {
87           segStart = shortSegs;
88        };
89  
90        // Extract data fragments at fixed locations and convert to
91        // integral types....
92        if (len >= segStart[1]) {
93           uuidData[3] = StrToHex(copy, 0);
94           uuidData[2] = StrToHex(copy, 2);
95           uuidData[1] = StrToHex(copy, 4);
96           uuidData[0] = StrToHex(copy, 6);
97        } // if
98        if (len >= segStart[2]) {
99           uuidData[5] = StrToHex(copy, (unsigned int) segStart[1]);
100           uuidData[4] = StrToHex(copy, (unsigned int) segStart[1] + 2);
101        } // if
102        if (len >= segStart[3]) {
103           uuidData[7] = StrToHex(copy, (unsigned int) segStart[2]);
104           uuidData[6] = StrToHex(copy, (unsigned int) segStart[2] + 2);
105        } // if
106        if (len >= segStart[4]) {
107           uuidData[8] = StrToHex(copy, (unsigned int) segStart[3]);
108           uuidData[9] = StrToHex(copy, (unsigned int) segStart[3] + 2);
109        } // if
110        if (len >= segStart[5]) {
111           uuidData[10] = StrToHex(copy, (unsigned int) segStart[4]);
112           uuidData[11] = StrToHex(copy, (unsigned int) segStart[4] + 2);
113           uuidData[12] = StrToHex(copy, (unsigned int) segStart[4] + 4);
114           uuidData[13] = StrToHex(copy, (unsigned int) segStart[4] + 6);
115           uuidData[14] = StrToHex(copy, (unsigned int) segStart[4] + 8);
116           uuidData[15] = StrToHex(copy, (unsigned int) segStart[4] + 10);
117        } // if
118     } // if/else randomize/set value
119  
120     return *this;
121  } // GUIDData::operator=(const string & orig)
122  
123  // Assignment from C-style string; rely on C++ casting....
operator =(const char * orig)124  GUIDData & GUIDData::operator=(const char * orig) {
125     return operator=((string) orig);
126  } // GUIDData::operator=(const char * orig)
127  
128  // Erase the contents of the GUID
Zero(void)129  void GUIDData::Zero(void) {
130     memset(uuidData, 0, sizeof(uuidData));
131  } // GUIDData::Zero()
132  
133  // Set a completely random GUID value....
134  // The uuid_generate() function returns a value that needs to have its
135  // first three fields byte-reversed to conform to Intel's GUID layout.
136  // The Windows UuidCreate() function doesn't need this adjustment. If
137  // neither function is defined, or if UuidCreate() fails, set a completely
138  // random GUID -- not completely kosher, but it works on most platforms
139  // (immediately after creating the UUID on Windows 7 being an important
140  // exception).
Randomize(void)141  void GUIDData::Randomize(void) {
142     int i, uuidGenerated = 0;
143  
144  #ifdef _UUID_UUID_H
145     uuid_generate(uuidData);
146     ReverseBytes(&uuidData[0], 4);
147     ReverseBytes(&uuidData[4], 2);
148     ReverseBytes(&uuidData[6], 2);
149     uuidGenerated = 1;
150  #endif
151  #if defined (_RPC_H) || defined (__RPC_H__)
152     UUID MsUuid;
153     if (UuidCreate(&MsUuid) == RPC_S_OK) {
154        memcpy(uuidData, &MsUuid, 16);
155        uuidGenerated = 1;
156     } // if
157  #endif
158  
159     if (!uuidGenerated) {
160        cerr << "Warning! Unable to generate a proper UUID! Creating an improper one as a last\n"
161             << "resort! Windows 7 may crash if you save this partition table!\a\n";
162        for (i = 0; i < 16; i++)
163           uuidData[i] = (unsigned char) (256.0 * (rand() / (RAND_MAX + 1.0)));
164     } // if
165  } // GUIDData::Randomize
166  
167  // Equality operator; returns 1 if the GUIDs are equal, 0 if they're unequal
operator ==(const GUIDData & orig) const168  int GUIDData::operator==(const GUIDData & orig) const {
169     return !memcmp(uuidData, orig.uuidData, sizeof(uuidData));
170  } // GUIDData::operator==
171  
172  // Inequality operator; returns 1 if the GUIDs are unequal, 0 if they're equal
operator !=(const GUIDData & orig) const173  int GUIDData::operator!=(const GUIDData & orig) const {
174     return !operator==(orig);
175  } // GUIDData::operator!=
176  
177  // Return the GUID as a string, suitable for display to the user.
AsString(void) const178  string GUIDData::AsString(void) const {
179     char theString[40];
180  
181     sprintf(theString,
182             "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
183             uuidData[3], uuidData[2], uuidData[1], uuidData[0], uuidData[5],
184             uuidData[4], uuidData[7], uuidData[6], uuidData[8], uuidData[9],
185             uuidData[10], uuidData[11], uuidData[12], uuidData[13], uuidData[14],
186             uuidData[15]);
187     return theString;
188  } // GUIDData::AsString(void)
189  
190  // Delete spaces or braces (which often enclose GUIDs) from the orig string,
191  // returning modified string.
DeleteSpaces(string s)192  string GUIDData::DeleteSpaces(string s) {
193     size_t position;
194  
195     if (s.length() > 0) {
196        for (position = s.length(); position > 0; position--) {
197           if ((s[position - 1] == ' ') || (s[position - 1] == '{') || (s[position - 1] == '}')) {
198              s.erase(position - 1, 1);
199           } // if
200        } // for
201     } // if
202     return s;
203  } // GUIDData::DeleteSpaces()
204  
205  /*******************************
206   *                             *
207   * Non-class support functions *
208   *                             *
209   *******************************/
210  
211  // Display a GUID as a string....
operator <<(ostream & os,const GUIDData & data)212  ostream & operator<<(ostream & os, const GUIDData & data) {
213  //   string asString;
214  
215     os << data.AsString();
216     return os;
217  } // GUIDData::operator<<()
218