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