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/. */
11 #include "MainThreadUtils.h"
12 #include "mozilla/Assertions.h"
13 #include "mozilla/RandomNum.h"
14 #include "mozilla/Sprintf.h"
16 #include "ScopedNSSTypes.h"
18 [[nodiscard
]] static bool GenerateRandomBytesFromNSS(void* 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");
27 int len
= static_cast<int>(aLength
);
29 // Only try to use NSS on the main thread.
30 if (!NS_IsMainThread() || !NSS_IsInitialized()) {
34 mozilla::UniquePK11SlotInfo
slot(PK11_GetInternalSlot());
36 MOZ_ASSERT_UNREACHABLE("Null slot");
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
;
67 nsID
nsID::GenerateUUID() {
69 nsresult rv
= GenerateUUIDInPlace(uuid
);
70 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv
));
78 memset(m3
, 0, sizeof(m3
));
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') \
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; \
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) \
107 int32_t _i = number_of_chars; \
110 ADD_HEX_CHAR_TO_INT_OR_RETURN_FALSE(*char_pointer, dest_variable); \
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 */
136 bool expectFormat1
= (aIDStr
[0] == '{');
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
);
148 for (i
= 0; i
< 2; ++i
) {
149 PARSE_CHARS_TO_NUM(aIDStr
, m3
[i
], 2);
151 PARSE_HYPHEN(aIDStr
);
153 PARSE_CHARS_TO_NUM(aIDStr
, m3
[i
], 2);
157 return expectFormat1
? *aIDStr
== '}' : true;
160 #ifndef XPCOM_GLUE_AVOID_NSPR
163 * Returns a managed string in {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
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}"
214 ToHex32Bit(m0
, &aDest
[1]);
216 ToHex16Bit(m1
, &aDest
[10]);
218 ToHex16Bit(m2
, &aDest
[15]);
220 ToHex8Bit(m3
[0], &aDest
[20]);
221 ToHex8Bit(m3
[1], &aDest
[22]);
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]);
233 #endif // XPCOM_GLUE_AVOID_NSPR
235 nsID
* nsID::Clone() const {
236 auto id
= static_cast<nsID
*>(moz_xmalloc(sizeof(nsID
)));