bool PrioEncoder::IsValidHexPublicKey(mozilla::Span<const char> aStr) { if (aStr.Length() != CURVE25519_KEY_LEN_HEX) { return false; } for (auto c : aStr) { if (!IsAsciiHexDigit(c)) { return false; } } return true; }
/* ** The workhorse sprintf code. */ int nsTextFormatter::dosprintf(SprintfStateStr* aState, const char16_t* aFmt, mozilla::Span<BoxedValue> aValues) { static const char16_t space = ' '; static const char16_t hex[] = u"0123456789abcdef"; static char16_t HEX[] = u"0123456789ABCDEF"; static const BoxedValue emptyString(u""); char16_t c; int flags, width, prec, radix; const char16_t* hexp; // Next argument for non-numbered arguments. size_t nextNaturalArg = 0; // True if we ever saw a numbered argument. bool sawNumberedArg = false; while ((c = *aFmt++) != 0) { int rv; if (c != '%') { rv = (*aState->stuff)(aState, aFmt - 1, 1); if (rv < 0) { return rv; } continue; } // Save the location of the "%" in case we decide it isn't a // format and want to just emit the text from the format string. const char16_t* percentPointer = aFmt - 1; /* ** Gobble up the % format string. Hopefully we have handled all ** of the strange cases! */ flags = 0; c = *aFmt++; if (c == '%') { /* quoting a % with %% */ rv = (*aState->stuff)(aState, aFmt - 1, 1); if (rv < 0) { return rv; } continue; } // Check for a numbered argument. bool sawWidth = false; const BoxedValue* thisArg = nullptr; if (c >= '0' && c <= '9') { size_t argNumber = 0; while (c && c >= '0' && c <= '9') { argNumber = (argNumber * 10) + (c - '0'); c = *aFmt++; } if (c == '$') { // Mixing numbered arguments and implicit arguments is // disallowed. if (nextNaturalArg > 0) { return -1; } c = *aFmt++; // Numbered arguments start at 1. --argNumber; if (argNumber >= aValues.Length()) { // A correctness issue but not a safety issue. MOZ_ASSERT(false); thisArg = &emptyString; } else { thisArg = &aValues[argNumber]; } sawNumberedArg = true; } else { width = argNumber; sawWidth = true; } } if (!sawWidth) { /* * Examine optional flags. Note that we do not implement the * '#' flag of sprintf(). The ANSI C spec. of the '#' flag is * somewhat ambiguous and not ideal, which is perhaps why * the various sprintf() implementations are inconsistent * on this feature. */ while ((c == '-') || (c == '+') || (c == ' ') || (c == '0')) { if (c == '-') { flags |= _LEFT; } if (c == '+') { flags |= _SIGNED; } if (c == ' ') { flags |= _SPACED; } if (c == '0') { flags |= _ZEROS; } c = *aFmt++; } if (flags & _SIGNED) { flags &= ~_SPACED; } if (flags & _LEFT) { flags &= ~_ZEROS; } /* width */ if (c == '*') { // Not supported with numbered arguments. if (sawNumberedArg) { return -1; } if (nextNaturalArg >= aValues.Length() || !aValues[nextNaturalArg].IntCompatible()) { // A correctness issue but not a safety issue. MOZ_ASSERT(false); width = 0; } else { width = aValues[nextNaturalArg++].mValue.mInt; } c = *aFmt++; } else { width = 0; while ((c >= '0') && (c <= '9')) { width = (width * 10) + (c - '0'); c = *aFmt++; } } } /* precision */ prec = -1; if (c == '.') { c = *aFmt++; if (c == '*') { // Not supported with numbered arguments. if (sawNumberedArg) { return -1; } if (nextNaturalArg >= aValues.Length() || !aValues[nextNaturalArg].IntCompatible()) { // A correctness issue but not a safety issue. MOZ_ASSERT(false); } else { prec = aValues[nextNaturalArg++].mValue.mInt; } c = *aFmt++; } else { prec = 0; while ((c >= '0') && (c <= '9')) { prec = (prec * 10) + (c - '0'); c = *aFmt++; } } } // If the argument isn't known yet, find it now. This is done // after the width and precision code, in case '*' was used. if (thisArg == nullptr) { // Mixing numbered arguments and implicit arguments is // disallowed. if (sawNumberedArg) { return -1; } if (nextNaturalArg >= aValues.Length()) { // A correctness issue but not a safety issue. MOZ_ASSERT(false); thisArg = &emptyString; } else { thisArg = &aValues[nextNaturalArg++]; } } /* Size. Defaults to 32 bits. */ uint64_t mask = UINT32_MAX; if (c == 'h') { c = *aFmt++; mask = UINT16_MAX; } else if (c == 'L') { c = *aFmt++; mask = UINT64_MAX; } else if (c == 'l') { c = *aFmt++; if (c == 'l') { c = *aFmt++; mask = UINT64_MAX; } else { mask = UINT32_MAX; } } /* format */ hexp = hex; radix = 10; // Several `MOZ_ASSERT`s below check for argument compatibility // with the format specifier. These are only debug assertions, // not release assertions, and exist to catch problems in C++ // callers of `nsTextFormatter`, as we do not have compile-time // checking of format strings. In release mode, these assertions // will be no-ops, and we will fall through to printing the // argument based on the known type of the argument. switch (c) { case 'd': case 'i': /* decimal/integer */ MOZ_ASSERT(thisArg->IntCompatible()); break; case 'o': /* octal */ MOZ_ASSERT(thisArg->IntCompatible()); radix = 8; flags |= _UNSIGNED; break; case 'u': /* unsigned decimal */ MOZ_ASSERT(thisArg->IntCompatible()); radix = 10; flags |= _UNSIGNED; break; case 'x': /* unsigned hex */ MOZ_ASSERT(thisArg->IntCompatible()); radix = 16; flags |= _UNSIGNED; break; case 'X': /* unsigned HEX */ MOZ_ASSERT(thisArg->IntCompatible()); radix = 16; hexp = HEX; flags |= _UNSIGNED; break; case 'e': case 'E': case 'f': case 'g': case 'G': MOZ_ASSERT(thisArg->mKind == DOUBLE); // Type-based printing below. break; case 'S': MOZ_ASSERT(thisArg->mKind == STRING16); // Type-based printing below. break; case 's': MOZ_ASSERT(thisArg->mKind == STRING); // Type-based printing below. break; case 'c': { if (!thisArg->IntCompatible()) { MOZ_ASSERT(false); // Type-based printing below. break; } if ((flags & _LEFT) == 0) { while (width-- > 1) { rv = (*aState->stuff)(aState, &space, 1); if (rv < 0) { return rv; } } } char16_t ch = thisArg->mValue.mInt; rv = (*aState->stuff)(aState, &ch, 1); if (rv < 0) { return rv; } if (flags & _LEFT) { while (width-- > 1) { rv = (*aState->stuff)(aState, &space, 1); if (rv < 0) { return rv; } } } } continue; case 'p': if (!thisArg->PointerCompatible()) { MOZ_ASSERT(false); break; } static_assert(sizeof(uint64_t) >= sizeof(void*), "pointers are larger than 64 bits"); rv = cvt_ll(aState, uintptr_t(thisArg->mValue.mPtr), width, prec, 16, flags | _UNSIGNED, hexp); if (rv < 0) { return rv; } continue; case 'n': if (thisArg->mKind != INTPOINTER) { return -1; } if (thisArg->mValue.mIntPtr != nullptr) { *thisArg->mValue.mIntPtr = aState->cur - aState->base; } continue; default: /* Not a % token after all... skip it */ rv = (*aState->stuff)(aState, percentPointer, aFmt - percentPointer); if (rv < 0) { return rv; } continue; } // If we get here, we want to handle the argument according to its // actual type; modified by the flags as appropriate. switch (thisArg->mKind) { case INT: case UINT: { int64_t val = thisArg->mValue.mInt; if ((flags & _UNSIGNED) == 0 && val < 0) { val = -val; flags |= _NEG; } rv = cvt_ll(aState, uint64_t(val) & mask, width, prec, radix, flags, hexp); } break; case INTPOINTER: case POINTER: // Always treat these as unsigned hex, no matter the format. static_assert(sizeof(uint64_t) >= sizeof(void*), "pointers are larger than 64 bits"); rv = cvt_ll(aState, uintptr_t(thisArg->mValue.mPtr), width, prec, 16, flags | _UNSIGNED, hexp); break; case DOUBLE: if (c != 'f' && c != 'E' && c != 'e' && c != 'G' && c != 'g') { // Pick some default. c = 'g'; } rv = cvt_f(aState, thisArg->mValue.mDouble, width, prec, c, flags); break; case STRING: rv = cvt_s(aState, thisArg->mValue.mString, width, prec, flags); break; case STRING16: rv = cvt_S(aState, thisArg->mValue.mString16, width, prec, flags); break; default: // Can't happen. MOZ_ASSERT(0); } if (rv < 0) { return rv; } } return 0; }