From 36d22d82aa202bb199967e9512281e9a53db42c9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 21:33:14 +0200 Subject: Adding upstream version 115.7.0esr. Signed-off-by: Daniel Baumann --- dom/base/MimeType.cpp | 347 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 347 insertions(+) create mode 100644 dom/base/MimeType.cpp (limited to 'dom/base/MimeType.cpp') diff --git a/dom/base/MimeType.cpp b/dom/base/MimeType.cpp new file mode 100644 index 0000000000..d9defe3b57 --- /dev/null +++ b/dom/base/MimeType.cpp @@ -0,0 +1,347 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "MimeType.h" +#include "nsUnicharUtils.h" + +namespace { +template +constexpr bool IsHTTPTokenPoint(Char aChar) { + using UnsignedChar = typename mozilla::detail::MakeUnsignedChar::Type; + auto c = static_cast(aChar); + return c == '!' || c == '#' || c == '$' || c == '%' || c == '&' || + c == '\'' || c == '*' || c == '+' || c == '-' || c == '.' || + c == '^' || c == '_' || c == '`' || c == '|' || c == '~' || + mozilla::IsAsciiAlphanumeric(c); +} + +template +constexpr bool IsHTTPQuotedStringTokenPoint(Char aChar) { + using UnsignedChar = typename mozilla::detail::MakeUnsignedChar::Type; + auto c = static_cast(aChar); + return c == 0x9 || (c >= ' ' && c <= '~') || mozilla::IsNonAsciiLatin1(c); +} + +template +constexpr bool IsHTTPWhitespace(Char aChar) { + using UnsignedChar = typename mozilla::detail::MakeUnsignedChar::Type; + auto c = static_cast(aChar); + return c == 0x9 || c == 0xA || c == 0xD || c == 0x20; +} +} // namespace + +template +/* static */ mozilla::UniquePtr> +TMimeType::Parse(const nsTSubstring& aMimeType) { + // See https://mimesniff.spec.whatwg.org/#parsing-a-mime-type + + // Steps 1-2 + const char_type* pos = aMimeType.BeginReading(); + const char_type* end = aMimeType.EndReading(); + while (pos < end && IsHTTPWhitespace(*pos)) { + ++pos; + } + if (pos == end) { + return nullptr; + } + while (end > pos && IsHTTPWhitespace(*(end - 1))) { + --end; + } + + // Steps 3-4 + const char_type* typeStart = pos; + while (pos < end && *pos != '/') { + if (!IsHTTPTokenPoint(*pos)) { + return nullptr; + } + ++pos; + } + const char_type* typeEnd = pos; + if (typeStart == typeEnd) { + return nullptr; + } + + // Step 5 + if (pos == end) { + return nullptr; + } + + // Step 6 + ++pos; + + // Step 7-9 + const char_type* subtypeStart = pos; + const char_type* subtypeEnd = nullptr; + while (pos < end && *pos != ';') { + if (!IsHTTPTokenPoint(*pos)) { + // If we hit a whitespace, check that the rest of + // the subtype is whitespace, otherwise fail. + if (IsHTTPWhitespace(*pos)) { + subtypeEnd = pos; + ++pos; + while (pos < end && *pos != ';') { + if (!IsHTTPWhitespace(*pos)) { + return nullptr; + } + ++pos; + } + break; + } + return nullptr; + } + ++pos; + } + if (subtypeEnd == nullptr) { + subtypeEnd = pos; + } + if (subtypeStart == subtypeEnd) { + return nullptr; + } + + // Step 10 + nsTString type; + nsTString subtype; + for (const char_type* c = typeStart; c < typeEnd; ++c) { + type.Append(ToLowerCaseASCII(*c)); + } + for (const char_type* c = subtypeStart; c < subtypeEnd; ++c) { + subtype.Append(ToLowerCaseASCII(*c)); + } + mozilla::UniquePtr> mimeType( + mozilla::MakeUnique>(type, subtype)); + + // Step 11 + while (pos < end) { + // Step 11.1 + ++pos; + + // Step 11.2 + while (pos < end && IsHTTPWhitespace(*pos)) { + ++pos; + } + + // Steps 11.3 and 11.4 + nsTString paramName; + bool paramNameHadInvalidChars = false; + while (pos < end && *pos != ';' && *pos != '=') { + if (!IsHTTPTokenPoint(*pos)) { + paramNameHadInvalidChars = true; + } + paramName.Append(ToLowerCaseASCII(*pos)); + ++pos; + } + + // Step 11.5 + if (pos < end) { + if (*pos == ';') { + continue; + } + ++pos; + } + + // Step 11.6 + if (pos == end) { + break; + } + + // Step 11.7 + ParameterValue paramValue; + bool paramValueHadInvalidChars = false; + + // Step 11.8 + if (*pos == '"') { + // Step 11.8.1 + ++pos; + + // Step 11.8.2 + while (true) { + // Step 11.8.2.1 + while (pos < end && *pos != '"' && *pos != '\\') { + if (!IsHTTPQuotedStringTokenPoint(*pos)) { + paramValueHadInvalidChars = true; + } + if (!IsHTTPTokenPoint(*pos)) { + paramValue.mRequiresQuoting = true; + } + paramValue.Append(*pos); + ++pos; + } + + // Step 11.8.2.2 + if (pos < end && *pos == '\\') { + // Step 11.8.2.2.1 + ++pos; + + // Step 11.8.2.2.2 + if (pos < end) { + if (!IsHTTPQuotedStringTokenPoint(*pos)) { + paramValueHadInvalidChars = true; + } + if (!IsHTTPTokenPoint(*pos)) { + paramValue.mRequiresQuoting = true; + } + paramValue.Append(*pos); + ++pos; + continue; + } + + // Step 11.8.2.2.3 + paramValue.Append('\\'); + paramValue.mRequiresQuoting = true; + } + + // Step 11.8.2.3 + break; + } + + // Step 11.8.3 + while (pos < end && *pos != ';') { + ++pos; + } + + // Step 11.9 + } else { + // Step 11.9.1 + const char_type* paramValueStart = pos; + while (pos < end && *pos != ';') { + ++pos; + } + + // Step 11.9.2 + const char_type* paramValueLastChar = pos - 1; + while (paramValueLastChar >= paramValueStart && + IsHTTPWhitespace(*paramValueLastChar)) { + --paramValueLastChar; + } + + // Step 11.9.3 + if (paramValueStart > paramValueLastChar) { + continue; + } + + for (const char_type* c = paramValueStart; c <= paramValueLastChar; ++c) { + if (!IsHTTPQuotedStringTokenPoint(*c)) { + paramValueHadInvalidChars = true; + } + if (!IsHTTPTokenPoint(*c)) { + paramValue.mRequiresQuoting = true; + } + paramValue.Append(*c); + } + } + + // Step 11.10 + if (!paramName.IsEmpty() && !paramNameHadInvalidChars && + !paramValueHadInvalidChars) { + // XXX Is the assigned value used anywhere? + paramValue = mimeType->mParameters.LookupOrInsertWith(paramName, [&] { + mimeType->mParameterNames.AppendElement(paramName); + return paramValue; + }); + } + } + + // Step 12 + return mimeType; +} + +template +void TMimeType::Serialize(nsTSubstring& aOutput) const { + aOutput.Assign(mType); + aOutput.AppendLiteral("/"); + aOutput.Append(mSubtype); + for (uint32_t i = 0; i < mParameterNames.Length(); i++) { + auto name = mParameterNames[i]; + aOutput.AppendLiteral(";"); + aOutput.Append(name); + aOutput.AppendLiteral("="); + GetParameterValue(name, aOutput, true); + } +} + +template +void TMimeType::GetFullType(nsTSubstring& aOutput) const { + aOutput.Assign(mType); + aOutput.AppendLiteral("/"); + aOutput.Append(mSubtype); +} + +template +bool TMimeType::HasParameter( + const nsTSubstring& aName) const { + return mParameters.Get(aName, nullptr); +} + +template +bool TMimeType::GetParameterValue( + const nsTSubstring& aName, nsTSubstring& aOutput, + bool aAppend) const { + if (!aAppend) { + aOutput.Truncate(); + } + + ParameterValue value; + if (!mParameters.Get(aName, &value)) { + return false; + } + + if (value.mRequiresQuoting || value.IsEmpty()) { + aOutput.AppendLiteral("\""); + const char_type* vcur = value.BeginReading(); + const char_type* vend = value.EndReading(); + while (vcur < vend) { + if (*vcur == '"' || *vcur == '\\') { + aOutput.AppendLiteral("\\"); + } + aOutput.Append(*vcur); + vcur++; + } + aOutput.AppendLiteral("\""); + } else { + aOutput.Append(value); + } + + return true; +} + +template +void TMimeType::SetParameterValue( + const nsTSubstring& aName, + const nsTSubstring& aValue) { + mParameters.WithEntryHandle(aName, [&](auto&& entry) { + if (!entry) { + mParameterNames.AppendElement(aName); + } + ParameterValue value; + value.Append(aValue); + entry.InsertOrUpdate(std::move(value)); + }); +} + +template mozilla::UniquePtr> TMimeType::Parse( + const nsTSubstring& aMimeType); +template mozilla::UniquePtr> TMimeType::Parse( + const nsTSubstring& aMimeType); +template void TMimeType::Serialize( + nsTSubstring& aOutput) const; +template void TMimeType::Serialize(nsTSubstring& aOutput) const; +template void TMimeType::GetFullType( + nsTSubstring& aOutput) const; +template void TMimeType::GetFullType(nsTSubstring& aOutput) const; +template bool TMimeType::HasParameter( + const nsTSubstring& aName) const; +template bool TMimeType::HasParameter( + const nsTSubstring& aName) const; +template bool TMimeType::GetParameterValue( + const nsTSubstring& aName, nsTSubstring& aOutput, + bool aAppend) const; +template bool TMimeType::GetParameterValue( + const nsTSubstring& aName, nsTSubstring& aOutput, + bool aAppend) const; +template void TMimeType::SetParameterValue( + const nsTSubstring& aName, const nsTSubstring& aValue); +template void TMimeType::SetParameterValue( + const nsTSubstring& aName, const nsTSubstring& aValue); -- cgit v1.2.3