/* -*- 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 "WebCustomFormatUtils.h" #include "js/JSON.h" #include "mozilla/JSONStringWriteFuncs.h" #include "mozilla/JSONWriter.h" #include "mozilla/Logging.h" static mozilla::LazyLogModule gWebCustomFormatLog("WebCustomFormat"); #ifdef LOG # undef LOG #endif #define LOG(...) \ MOZ_LOG(gWebCustomFormatLog, mozilla::LogLevel::Debug, (__VA_ARGS__)) namespace mozilla::widget { void WebCustomFormatMapToJSON(const WebCustomFormatMap& aWebCustomFormatMap, nsACString& aResult) { JSONStringWriteFunc data; JSONWriter writer(data, JSONWriter::CollectionStyle::SingleLineStyle); const auto& flavors = aWebCustomFormatMap.Keys(); writer.Start(); for (const auto& flavor : flavors) { writer.StringProperty(flavor, aWebCustomFormatMap.Lookup(flavor).Data()); } writer.End(); aResult = std::move(data).StringRRef(); } namespace { class WebCustomFormatMapJSONHandler final : public JS::JSONParseHandler { public: bool propertyName(const JS::Latin1Char* name, size_t length) override { mCurrentProperty = nsDependentCSubstring(reinterpret_cast(name), length); return true; } bool stringValue(const JS::Latin1Char* str, size_t length) override { nsAutoCString value(reinterpret_cast(str), length); if (!mResult.WithEntryHandle(mCurrentProperty, [&value](auto&& entry) { if (entry.HasEntry()) { return false; } entry.Insert(std::move(value)); return true; })) { LOG("%s: web custom format %s exists", __FUNCTION__, mCurrentProperty.get()); } return true; } // WebCustomFormatMap only handles UTF8 encoded property and string value bool propertyName(const char16_t* name, size_t length) override { return false; } bool stringValue(const char16_t* str, size_t length) override { return false; } bool startObject() override { if (mStartTopLevelObject) { return false; } mStartTopLevelObject = true; return true; } bool endObject() override { return mStartTopLevelObject; } bool startArray() override { return false; } bool endArray() override { return false; } bool numberValue(double d) override { return false; } bool booleanValue(bool v) override { return false; } bool nullValue() override { return false; } void error(const char* msg, uint32_t line, uint32_t column) override {} explicit WebCustomFormatMapJSONHandler(WebCustomFormatMap& aResult) : mResult(aResult) {} private: nsCString mCurrentProperty; bool mStartTopLevelObject{false}; WebCustomFormatMap& mResult; }; } // namespace bool JSONToWebCustomFormatMap(const nsACString& aJSON, WebCustomFormatMap& aResult) { // Parse into a local map first so the caller's map is only mutated on // success. const nsPromiseFlatCString flatJSON(aJSON); WebCustomFormatMap parsed; WebCustomFormatMapJSONHandler handler(parsed); if (!JS::ParseJSONWithHandler( reinterpret_cast(flatJSON.get()), flatJSON.Length(), &handler)) { LOG("Fail to parse JSON string data: %s to WebCustomFormatMap", flatJSON.get()); return false; } aResult = std::move(parsed); return true; } } // namespace mozilla::widget