зеркало из https://github.com/mozilla/gecko-dev.git
120 строки
3.5 KiB
C++
120 строки
3.5 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* 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 "JSONFormatter.h"
|
|
|
|
#include <algorithm>
|
|
#include <cassert>
|
|
#include <string.h>
|
|
|
|
static std::string replaceAll(std::string Mangled, std::string Pattern,
|
|
std::string Replacement) {
|
|
size_t Pos = 0;
|
|
while ((Pos = Mangled.find(Pattern, Pos)) != std::string::npos) {
|
|
Mangled = Mangled.replace(Pos, Pattern.length(), Replacement);
|
|
Pos += Replacement.length();
|
|
}
|
|
return Mangled;
|
|
}
|
|
|
|
/**
|
|
* Hacky escaping logic with the goal of not upsetting the much more thorough
|
|
* rust JSON parsing library that actually understands UTF-8. Double-quote
|
|
* and (escaping) backslash are escaped, as is tab (\t), with newlines (\r\n
|
|
* and \n) normalized to escaped \n.
|
|
*
|
|
* Additionally, everything that's not printable ASCII is simply erased. The
|
|
* motivating file is media/openmax_il/il112/OMX_Other.h#93 which has a
|
|
* corrupted apostrophe as <92> in there. The better course of action would
|
|
* be a validating UTF-8 parse that discards corrupt/non-printable characters.
|
|
* Since this is motivated by a commenting proof-of-concept and builds are
|
|
* already slow, I'm punting on that.
|
|
*/
|
|
std::string JSONFormatter::escape(std::string Input) {
|
|
bool NeedsEscape = false;
|
|
for (char C : Input) {
|
|
if (C == '\\' || C == '"' || C < 32 || C > 126) {
|
|
NeedsEscape = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!NeedsEscape) {
|
|
return Input;
|
|
}
|
|
|
|
std::string Cur = Input;
|
|
Cur = replaceAll(Cur, "\\", "\\\\");
|
|
Cur = replaceAll(Cur, "\"", "\\\"");
|
|
Cur = replaceAll(Cur, "\t", "\\t");
|
|
Cur = replaceAll(Cur, "\r\n", "\\n");
|
|
Cur = replaceAll(Cur, "\n", "\\n");
|
|
Cur.erase(std::remove_if(Cur.begin(), Cur.end(),
|
|
[](char C){ return C < 32 || C > 126; }),
|
|
Cur.end());
|
|
return Cur;
|
|
}
|
|
|
|
void JSONFormatter::add(const char *Name, const char *Value) {
|
|
assert(PropertyCount < kMaxProperties);
|
|
Properties[PropertyCount] = Property(Name, std::string(Value));
|
|
PropertyCount++;
|
|
|
|
// `"Name":"Value",`
|
|
Length += strlen(Name) + 3 + strlen(Value) + 2 + 1;
|
|
}
|
|
|
|
void JSONFormatter::add(const char *Name, std::string Value) {
|
|
std::string Escaped = escape(std::move(Value));
|
|
|
|
// `"Name":"Escaped",`
|
|
Length += strlen(Name) + 3 + Escaped.length() + 2 + 1;
|
|
|
|
assert(PropertyCount < kMaxProperties);
|
|
Properties[PropertyCount] = Property(Name, std::move(Escaped));
|
|
PropertyCount++;
|
|
}
|
|
|
|
void JSONFormatter::add(const char *Name, int Value) {
|
|
// 1 digit
|
|
assert(Value >= 0 && Value < 10);
|
|
|
|
assert(PropertyCount < kMaxProperties);
|
|
Properties[PropertyCount] = Property(Name, Value);
|
|
PropertyCount++;
|
|
|
|
// `"Name":V,`
|
|
Length += strlen(Name) + 3 + 2;
|
|
}
|
|
|
|
void JSONFormatter::format(std::string &Result) {
|
|
Result.reserve(Length + 2);
|
|
|
|
Result.push_back('{');
|
|
for (int I = 0; I < PropertyCount; I++) {
|
|
Result.push_back('"');
|
|
Result.append(Properties[I].Name);
|
|
Result.push_back('"');
|
|
Result.push_back(':');
|
|
|
|
if (Properties[I].IsString) {
|
|
Result.push_back('"');
|
|
Result.append(Properties[I].StringValue);
|
|
Result.push_back('"');
|
|
} else {
|
|
Result.push_back(Properties[I].IntValue + '0');
|
|
}
|
|
|
|
if (I + 1 != PropertyCount) {
|
|
Result.push_back(',');
|
|
}
|
|
}
|
|
|
|
Result.push_back('}');
|
|
Result.push_back('\n');
|
|
|
|
assert(Result.length() == Length + 2);
|
|
}
|