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/. */
9 #include "nsUnicharUtils.h"
11 template <typename char_type
>
12 /* static */ mozilla::UniquePtr
<TMimeType
<char_type
>>
13 TMimeType
<char_type
>::Parse(const nsTSubstring
<char_type
>& aMimeType
) {
14 // See https://mimesniff.spec.whatwg.org/#parsing-a-mime-type
17 const char_type
* pos
= aMimeType
.BeginReading();
18 const char_type
* end
= aMimeType
.EndReading();
19 while (pos
< end
&& NS_IsHTTPWhitespace(*pos
)) {
25 while (end
> pos
&& NS_IsHTTPWhitespace(*(end
- 1))) {
30 const char_type
* typeStart
= pos
;
31 while (pos
< end
&& *pos
!= '/') {
32 if (!NS_IsHTTPTokenPoint(*pos
)) {
37 const char_type
* typeEnd
= pos
;
38 if (typeStart
== typeEnd
) {
51 const char_type
* subtypeStart
= pos
;
52 const char_type
* subtypeEnd
= nullptr;
53 while (pos
< end
&& *pos
!= ';') {
54 if (!NS_IsHTTPTokenPoint(*pos
)) {
55 // If we hit a whitespace, check that the rest of
56 // the subtype is whitespace, otherwise fail.
57 if (NS_IsHTTPWhitespace(*pos
)) {
60 while (pos
< end
&& *pos
!= ';') {
61 if (!NS_IsHTTPWhitespace(*pos
)) {
72 if (subtypeEnd
== nullptr) {
75 if (subtypeStart
== subtypeEnd
) {
80 nsTString
<char_type
> type
;
81 nsTString
<char_type
> subtype
;
82 for (const char_type
* c
= typeStart
; c
< typeEnd
; ++c
) {
83 type
.Append(ToLowerCaseASCII(*c
));
85 for (const char_type
* c
= subtypeStart
; c
< subtypeEnd
; ++c
) {
86 subtype
.Append(ToLowerCaseASCII(*c
));
88 mozilla::UniquePtr
<TMimeType
<char_type
>> mimeType(
89 mozilla::MakeUnique
<TMimeType
<char_type
>>(type
, subtype
));
97 while (pos
< end
&& NS_IsHTTPWhitespace(*pos
)) {
101 const char_type
* namePos
= pos
;
103 // Steps 11.3 and 11.4
104 nsTString
<char_type
> paramName
;
105 bool paramNameHadInvalidChars
= false;
106 while (pos
< end
&& *pos
!= ';' && *pos
!= '=') {
107 if (!NS_IsHTTPTokenPoint(*pos
)) {
108 paramNameHadInvalidChars
= true;
110 paramName
.Append(ToLowerCaseASCII(*pos
));
114 // Might as well check for base64 now
116 // trim leading and trailing spaces
117 while (namePos
< pos
&& NS_IsHTTPWhitespace(*namePos
)) {
120 if (namePos
< pos
&& ToLowerCaseASCII(*namePos
) == 'b' &&
121 ++namePos
< pos
&& ToLowerCaseASCII(*namePos
) == 'a' &&
122 ++namePos
< pos
&& ToLowerCaseASCII(*namePos
) == 's' &&
123 ++namePos
< pos
&& ToLowerCaseASCII(*namePos
) == 'e' &&
124 ++namePos
< pos
&& ToLowerCaseASCII(*namePos
) == '6' &&
125 ++namePos
< pos
&& ToLowerCaseASCII(*namePos
) == '4') {
126 while (++namePos
< pos
&& NS_IsHTTPWhitespace(*namePos
)) {
128 mimeType
->mIsBase64
= namePos
== pos
;
146 ParameterValue paramValue
;
147 bool paramValueHadInvalidChars
= false;
157 while (pos
< end
&& *pos
!= '"' && *pos
!= '\\') {
158 if (!NS_IsHTTPQuotedStringTokenPoint(*pos
)) {
159 paramValueHadInvalidChars
= true;
161 if (!NS_IsHTTPTokenPoint(*pos
)) {
162 paramValue
.mRequiresQuoting
= true;
164 paramValue
.Append(*pos
);
169 if (pos
< end
&& *pos
== '\\') {
175 if (!NS_IsHTTPQuotedStringTokenPoint(*pos
)) {
176 paramValueHadInvalidChars
= true;
178 if (!NS_IsHTTPTokenPoint(*pos
)) {
179 paramValue
.mRequiresQuoting
= true;
181 paramValue
.Append(*pos
);
187 paramValue
.Append('\\');
188 paramValue
.mRequiresQuoting
= true;
196 while (pos
< end
&& *pos
!= ';') {
203 const char_type
* paramValueStart
= pos
;
204 while (pos
< end
&& *pos
!= ';') {
209 const char_type
* paramValueLastChar
= pos
- 1;
210 while (paramValueLastChar
>= paramValueStart
&&
211 NS_IsHTTPWhitespace(*paramValueLastChar
)) {
212 --paramValueLastChar
;
216 if (paramValueStart
> paramValueLastChar
) {
220 for (const char_type
* c
= paramValueStart
; c
<= paramValueLastChar
; ++c
) {
221 if (!NS_IsHTTPQuotedStringTokenPoint(*c
)) {
222 paramValueHadInvalidChars
= true;
224 if (!NS_IsHTTPTokenPoint(*c
)) {
225 paramValue
.mRequiresQuoting
= true;
227 paramValue
.Append(*c
);
232 if (!paramName
.IsEmpty() && !paramNameHadInvalidChars
&&
233 !paramValueHadInvalidChars
) {
234 // XXX Is the assigned value used anywhere?
235 paramValue
= mimeType
->mParameters
.LookupOrInsertWith(paramName
, [&] {
236 mimeType
->mParameterNames
.AppendElement(paramName
);
246 template <typename char_type
>
247 void TMimeType
<char_type
>::Serialize(nsTSubstring
<char_type
>& aOutput
) const {
248 aOutput
.Assign(mType
);
249 aOutput
.AppendLiteral("/");
250 aOutput
.Append(mSubtype
);
251 for (uint32_t i
= 0; i
< mParameterNames
.Length(); i
++) {
252 auto name
= mParameterNames
[i
];
253 aOutput
.AppendLiteral(";");
254 aOutput
.Append(name
);
255 aOutput
.AppendLiteral("=");
256 GetParameterValue(name
, aOutput
, true);
260 template <typename char_type
>
261 void TMimeType
<char_type
>::GetFullType(nsTSubstring
<char_type
>& aOutput
) const {
262 aOutput
.Assign(mType
);
263 aOutput
.AppendLiteral("/");
264 aOutput
.Append(mSubtype
);
267 template <typename char_type
>
268 bool TMimeType
<char_type
>::HasParameter(
269 const nsTSubstring
<char_type
>& aName
) const {
270 return mParameters
.Get(aName
, nullptr);
273 template <typename char_type
>
274 bool TMimeType
<char_type
>::GetParameterValue(
275 const nsTSubstring
<char_type
>& aName
, nsTSubstring
<char_type
>& aOutput
,
276 bool aAppend
) const {
281 ParameterValue value
;
282 if (!mParameters
.Get(aName
, &value
)) {
286 if (value
.mRequiresQuoting
|| value
.IsEmpty()) {
287 aOutput
.AppendLiteral("\"");
288 const char_type
* vcur
= value
.BeginReading();
289 const char_type
* vend
= value
.EndReading();
290 while (vcur
< vend
) {
291 if (*vcur
== '"' || *vcur
== '\\') {
292 aOutput
.AppendLiteral("\\");
294 aOutput
.Append(*vcur
);
297 aOutput
.AppendLiteral("\"");
299 aOutput
.Append(value
);
305 template <typename char_type
>
306 void TMimeType
<char_type
>::SetParameterValue(
307 const nsTSubstring
<char_type
>& aName
,
308 const nsTSubstring
<char_type
>& aValue
) {
309 mParameters
.WithEntryHandle(aName
, [&](auto&& entry
) {
311 mParameterNames
.AppendElement(aName
);
313 ParameterValue value
;
314 value
.Append(aValue
);
315 entry
.InsertOrUpdate(std::move(value
));
319 template mozilla::UniquePtr
<TMimeType
<char16_t
>> TMimeType
<char16_t
>::Parse(
320 const nsTSubstring
<char16_t
>& aMimeType
);
321 template mozilla::UniquePtr
<TMimeType
<char>> TMimeType
<char>::Parse(
322 const nsTSubstring
<char>& aMimeType
);
323 template void TMimeType
<char16_t
>::Serialize(
324 nsTSubstring
<char16_t
>& aOutput
) const;
325 template void TMimeType
<char>::Serialize(nsTSubstring
<char>& aOutput
) const;
326 template void TMimeType
<char16_t
>::GetFullType(
327 nsTSubstring
<char16_t
>& aOutput
) const;
328 template void TMimeType
<char>::GetFullType(nsTSubstring
<char>& aOutput
) const;
329 template bool TMimeType
<char16_t
>::HasParameter(
330 const nsTSubstring
<char16_t
>& aName
) const;
331 template bool TMimeType
<char>::HasParameter(
332 const nsTSubstring
<char>& aName
) const;
333 template bool TMimeType
<char16_t
>::GetParameterValue(
334 const nsTSubstring
<char16_t
>& aName
, nsTSubstring
<char16_t
>& aOutput
,
336 template bool TMimeType
<char>::GetParameterValue(
337 const nsTSubstring
<char>& aName
, nsTSubstring
<char>& aOutput
,
339 template void TMimeType
<char16_t
>::SetParameterValue(
340 const nsTSubstring
<char16_t
>& aName
, const nsTSubstring
<char16_t
>& aValue
);
341 template void TMimeType
<char>::SetParameterValue(
342 const nsTSubstring
<char>& aName
, const nsTSubstring
<char>& aValue
);