no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / xpcom / base / nsID.cpp
blob701bf647d1a10d1252cd5992b1c248cf871ce4fb
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "nsID.h"
9 #include <limits.h>
11 #include "MainThreadUtils.h"
12 #include "mozilla/Assertions.h"
13 #include "mozilla/RandomNum.h"
14 #include "mozilla/Sprintf.h"
15 #include "nss.h"
16 #include "ScopedNSSTypes.h"
18 [[nodiscard]] static bool GenerateRandomBytesFromNSS(void* aBuffer,
19 size_t aLength) {
20 MOZ_ASSERT(aBuffer);
22 // Bounds check that we can safely truncate size_t `aLength` to an int.
23 if (aLength == 0 || aLength > INT_MAX) {
24 MOZ_ASSERT_UNREACHABLE("Bad aLength");
25 return false;
27 int len = static_cast<int>(aLength);
29 // Only try to use NSS on the main thread.
30 if (!NS_IsMainThread() || !NSS_IsInitialized()) {
31 return false;
34 mozilla::UniquePK11SlotInfo slot(PK11_GetInternalSlot());
35 if (!slot) {
36 MOZ_ASSERT_UNREACHABLE("Null slot");
37 return false;
40 SECStatus srv = PK11_GenerateRandomOnSlot(
41 slot.get(), static_cast<unsigned char*>(aBuffer), len);
42 MOZ_ASSERT(srv == SECSuccess);
43 return (srv == SECSuccess);
46 nsresult nsID::GenerateUUIDInPlace(nsID& aId) {
47 // Firefox needs to generate some UUIDs before NSS has been initialized. We
48 // prefer NSS's RNG, but if NSS is not available yet or returns an error, fall
49 // back to MFBT's GenerateRandomBytes().
50 if (!GenerateRandomBytesFromNSS(&aId, sizeof(nsID)) &&
51 !mozilla::GenerateRandomBytesFromOS(&aId, sizeof(nsID))) {
52 MOZ_ASSERT_UNREACHABLE("GenerateRandomBytesFromOS() failed");
53 return NS_ERROR_NOT_AVAILABLE;
56 // Put in the version
57 aId.m2 &= 0x0fff;
58 aId.m2 |= 0x4000;
60 // Put in the variant
61 aId.m3[0] &= 0x3f;
62 aId.m3[0] |= 0x80;
64 return NS_OK;
67 nsID nsID::GenerateUUID() {
68 nsID uuid;
69 nsresult rv = GenerateUUIDInPlace(uuid);
70 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
71 return uuid;
74 void nsID::Clear() {
75 m0 = 0;
76 m1 = 0;
77 m2 = 0;
78 memset(m3, 0, sizeof(m3));
81 /**
82 * Multiplies the_int_var with 16 (0x10) and adds the value of the
83 * hexadecimal digit the_char. If it fails it returns false from
84 * the function it's used in.
87 #define ADD_HEX_CHAR_TO_INT_OR_RETURN_FALSE(the_char, the_int_var) \
88 the_int_var = (the_int_var << 4) + the_char; \
89 if (the_char >= '0' && the_char <= '9') \
90 the_int_var -= '0'; \
91 else if (the_char >= 'a' && the_char <= 'f') \
92 the_int_var -= 'a' - 10; \
93 else if (the_char >= 'A' && the_char <= 'F') \
94 the_int_var -= 'A' - 10; \
95 else \
96 return false
98 /**
99 * Parses number_of_chars characters from the char_pointer pointer and
100 * puts the number in the dest_variable. The pointer is moved to point
101 * at the first character after the parsed ones. If it fails it returns
102 * false from the function the macro is used in.
105 #define PARSE_CHARS_TO_NUM(char_pointer, dest_variable, number_of_chars) \
106 do { \
107 int32_t _i = number_of_chars; \
108 dest_variable = 0; \
109 while (_i) { \
110 ADD_HEX_CHAR_TO_INT_OR_RETURN_FALSE(*char_pointer, dest_variable); \
111 char_pointer++; \
112 _i--; \
114 } while (0)
117 * Parses a hyphen from the char_pointer string. If there is no hyphen there
118 * the function returns false from the function it's used in. The
119 * char_pointer is advanced one step.
122 #define PARSE_HYPHEN(char_pointer) \
123 if (*(char_pointer++) != '-') return false
126 * Turns a {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} string into
127 * an nsID. It can also handle the old format without the { and }.
130 bool nsID::Parse(const char* aIDStr) {
131 /* Optimized for speed */
132 if (!aIDStr) {
133 return false;
136 bool expectFormat1 = (aIDStr[0] == '{');
137 if (expectFormat1) {
138 ++aIDStr;
141 PARSE_CHARS_TO_NUM(aIDStr, m0, 8);
142 PARSE_HYPHEN(aIDStr);
143 PARSE_CHARS_TO_NUM(aIDStr, m1, 4);
144 PARSE_HYPHEN(aIDStr);
145 PARSE_CHARS_TO_NUM(aIDStr, m2, 4);
146 PARSE_HYPHEN(aIDStr);
147 int i;
148 for (i = 0; i < 2; ++i) {
149 PARSE_CHARS_TO_NUM(aIDStr, m3[i], 2);
151 PARSE_HYPHEN(aIDStr);
152 while (i < 8) {
153 PARSE_CHARS_TO_NUM(aIDStr, m3[i], 2);
154 i++;
157 return expectFormat1 ? *aIDStr == '}' : true;
160 #ifndef XPCOM_GLUE_AVOID_NSPR
163 * Returns a managed string in {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
164 * format.
166 nsIDToCString nsID::ToString() const { return nsIDToCString(*this); }
168 static const char sHexChars[256 * 2 + 1] =
169 "000102030405060708090a0b0c0d0e0f"
170 "101112131415161718191a1b1c1d1e1f"
171 "202122232425262728292a2b2c2d2e2f"
172 "303132333435363738393a3b3c3d3e3f"
173 "404142434445464748494a4b4c4d4e4f"
174 "505152535455565758595a5b5c5d5e5f"
175 "606162636465666768696a6b6c6d6e6f"
176 "707172737475767778797a7b7c7d7e7f"
177 "808182838485868788898a8b8c8d8e8f"
178 "909192939495969798999a9b9c9d9e9f"
179 "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
180 "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
181 "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
182 "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
183 "e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
184 "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff";
186 // Writes a zero-padded 8-bit integer as lowercase hex into aDest[0..2]
187 static void ToHex8Bit(uint8_t aValue, char* aDest) {
188 aDest[0] = sHexChars[2 * aValue];
189 aDest[1] = sHexChars[2 * aValue + 1];
192 // Writes a zero-padded 16-bit integer as lowercase hex into aDest[0..4]
193 static void ToHex16Bit(uint16_t aValue, char* aDest) {
194 const uint8_t hi = (aValue >> 8);
195 const uint8_t lo = aValue;
196 ToHex8Bit(hi, &aDest[0]);
197 ToHex8Bit(lo, &aDest[2]);
200 // Writes a zero-padded 32-bit integer as lowercase hex into aDest[0..8]
201 static void ToHex32Bit(uint32_t aValue, char* aDest) {
202 const uint16_t hi = (aValue >> 16);
203 const uint16_t lo = aValue;
204 ToHex16Bit(hi, &aDest[0]);
205 ToHex16Bit(lo, &aDest[4]);
208 void nsID::ToProvidedString(char (&aDest)[NSID_LENGTH]) const {
209 // Stringify manually, for best performance.
211 // "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}"
212 // "{ecc35fd2-9029-4287-a826-b0a241d48d31}"
213 aDest[0] = '{';
214 ToHex32Bit(m0, &aDest[1]);
215 aDest[9] = '-';
216 ToHex16Bit(m1, &aDest[10]);
217 aDest[14] = '-';
218 ToHex16Bit(m2, &aDest[15]);
219 aDest[19] = '-';
220 ToHex8Bit(m3[0], &aDest[20]);
221 ToHex8Bit(m3[1], &aDest[22]);
222 aDest[24] = '-';
223 ToHex8Bit(m3[2], &aDest[25]);
224 ToHex8Bit(m3[3], &aDest[27]);
225 ToHex8Bit(m3[4], &aDest[29]);
226 ToHex8Bit(m3[5], &aDest[31]);
227 ToHex8Bit(m3[6], &aDest[33]);
228 ToHex8Bit(m3[7], &aDest[35]);
229 aDest[37] = '}';
230 aDest[38] = '\0';
233 #endif // XPCOM_GLUE_AVOID_NSPR
235 nsID* nsID::Clone() const {
236 auto id = static_cast<nsID*>(moz_xmalloc(sizeof(nsID)));
237 *id = *this;
238 return id;