mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-12-25 15:39:55 +00:00
e8e728454c
- Parsing invalid JSON no longer asserts Instead of asserting when coming across malformed JSON, JsonParser::parse now returns an Optional<JsonValue>. - Disallow trailing commas in JSON objects and arrays - No longer parse 'undefined', as that is a purely JS thing - No longer allow non-whitespace after anything consumed by the initial parse() call. Examples of things that were valid and no longer are: - undefineddfz - {"foo": 1}abcd - [1,2,3]4 - JsonObject.for_each_member now iterates in original insertion order
266 lines
6.5 KiB
C++
266 lines
6.5 KiB
C++
/*
|
|
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
|
* list of conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
* and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <AK/Forward.h>
|
|
#include <AK/IPv4Address.h>
|
|
#include <AK/Optional.h>
|
|
#include <AK/String.h>
|
|
#include <AK/StringBuilder.h>
|
|
|
|
namespace AK {
|
|
|
|
class JsonValue {
|
|
public:
|
|
enum class Type {
|
|
Null,
|
|
Int32,
|
|
UnsignedInt32,
|
|
Int64,
|
|
UnsignedInt64,
|
|
#if !defined(KERNEL)
|
|
Double,
|
|
#endif
|
|
Bool,
|
|
String,
|
|
Array,
|
|
Object,
|
|
};
|
|
|
|
static Optional<JsonValue> from_string(const StringView&);
|
|
|
|
explicit JsonValue(Type = Type::Null);
|
|
~JsonValue() { clear(); }
|
|
|
|
JsonValue(const JsonValue&);
|
|
JsonValue(JsonValue&&);
|
|
|
|
JsonValue& operator=(const JsonValue&);
|
|
JsonValue& operator=(JsonValue&&);
|
|
|
|
JsonValue(int);
|
|
JsonValue(unsigned);
|
|
JsonValue(long);
|
|
JsonValue(long unsigned);
|
|
JsonValue(long long);
|
|
JsonValue(long long unsigned);
|
|
|
|
#if !defined(KERNEL)
|
|
JsonValue(double);
|
|
#endif
|
|
JsonValue(bool);
|
|
JsonValue(const char*);
|
|
JsonValue(const String&);
|
|
JsonValue(const IPv4Address&);
|
|
JsonValue(const JsonArray&);
|
|
JsonValue(const JsonObject&);
|
|
|
|
JsonValue(JsonArray&&);
|
|
JsonValue(JsonObject&&);
|
|
|
|
// FIXME: Implement these
|
|
JsonValue& operator=(JsonArray&&) = delete;
|
|
JsonValue& operator=(JsonObject&&) = delete;
|
|
|
|
template<typename Builder>
|
|
typename Builder::OutputType serialized() const;
|
|
template<typename Builder>
|
|
void serialize(Builder&) const;
|
|
|
|
String as_string_or(const String& alternative)
|
|
{
|
|
if (is_string())
|
|
return as_string();
|
|
return alternative;
|
|
}
|
|
|
|
String to_string() const
|
|
{
|
|
if (is_string())
|
|
return as_string();
|
|
return serialized<StringBuilder>();
|
|
}
|
|
|
|
Optional<IPv4Address> to_ipv4_address() const
|
|
{
|
|
if (!is_string())
|
|
return {};
|
|
return IPv4Address::from_string(as_string());
|
|
}
|
|
|
|
int to_int(int default_value = 0) const { return to_i32(default_value); }
|
|
i32 to_i32(i32 default_value = 0) const { return to_number<i32>(default_value); }
|
|
|
|
unsigned to_uint(unsigned default_value = 0) const { return to_u32(default_value); }
|
|
u32 to_u32(u32 default_value = 0) const { return to_number<u32>(default_value); }
|
|
|
|
bool to_bool(bool default_value = false) const
|
|
{
|
|
if (!is_bool())
|
|
return default_value;
|
|
return as_bool();
|
|
}
|
|
|
|
i32 as_i32() const
|
|
{
|
|
ASSERT(is_i32());
|
|
return m_value.as_i32;
|
|
}
|
|
|
|
u32 as_u32() const
|
|
{
|
|
ASSERT(is_u32());
|
|
return m_value.as_u32;
|
|
}
|
|
|
|
i64 as_i64() const
|
|
{
|
|
ASSERT(is_i64());
|
|
return m_value.as_i64;
|
|
}
|
|
|
|
u64 as_u64() const
|
|
{
|
|
ASSERT(is_u64());
|
|
return m_value.as_u64;
|
|
}
|
|
|
|
int as_bool() const
|
|
{
|
|
ASSERT(is_bool());
|
|
return m_value.as_bool;
|
|
}
|
|
|
|
String as_string() const
|
|
{
|
|
ASSERT(is_string());
|
|
return *m_value.as_string;
|
|
}
|
|
|
|
const JsonObject& as_object() const
|
|
{
|
|
ASSERT(is_object());
|
|
return *m_value.as_object;
|
|
}
|
|
|
|
const JsonArray& as_array() const
|
|
{
|
|
ASSERT(is_array());
|
|
return *m_value.as_array;
|
|
}
|
|
|
|
#if !defined(KERNEL)
|
|
double as_double() const
|
|
{
|
|
ASSERT(is_double());
|
|
return m_value.as_double;
|
|
}
|
|
#endif
|
|
|
|
Type type() const
|
|
{
|
|
return m_type;
|
|
}
|
|
|
|
bool is_null() const { return m_type == Type::Null; }
|
|
bool is_bool() const { return m_type == Type::Bool; }
|
|
bool is_string() const { return m_type == Type::String; }
|
|
bool is_i32() const { return m_type == Type::Int32; }
|
|
bool is_u32() const { return m_type == Type::UnsignedInt32; }
|
|
bool is_i64() const { return m_type == Type::Int64; }
|
|
bool is_u64() const { return m_type == Type::UnsignedInt64; }
|
|
#if !defined(KERNEL)
|
|
bool is_double() const
|
|
{
|
|
return m_type == Type::Double;
|
|
}
|
|
#endif
|
|
bool is_array() const
|
|
{
|
|
return m_type == Type::Array;
|
|
}
|
|
bool is_object() const { return m_type == Type::Object; }
|
|
bool is_number() const
|
|
{
|
|
switch (m_type) {
|
|
case Type::Int32:
|
|
case Type::UnsignedInt32:
|
|
case Type::Int64:
|
|
case Type::UnsignedInt64:
|
|
#if !defined(KERNEL)
|
|
case Type::Double:
|
|
#endif
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
template<typename T>
|
|
T to_number(T default_value = 0) const
|
|
{
|
|
#if !defined(KERNEL)
|
|
if (is_double())
|
|
return (T)as_double();
|
|
#endif
|
|
if (type() == Type::Int32)
|
|
return (T)as_i32();
|
|
if (type() == Type::UnsignedInt32)
|
|
return (T)as_u32();
|
|
if (type() == Type::Int64)
|
|
return (T)as_i64();
|
|
if (type() == Type::UnsignedInt64)
|
|
return (T)as_u64();
|
|
return default_value;
|
|
}
|
|
|
|
bool equals(const JsonValue& other) const;
|
|
|
|
private:
|
|
void clear();
|
|
void copy_from(const JsonValue&);
|
|
|
|
Type m_type { Type::Null };
|
|
|
|
union {
|
|
StringImpl* as_string { nullptr };
|
|
JsonArray* as_array;
|
|
JsonObject* as_object;
|
|
#if !defined(KERNEL)
|
|
double as_double;
|
|
#endif
|
|
i32 as_i32;
|
|
u32 as_u32;
|
|
i64 as_i64;
|
|
u64 as_u64;
|
|
bool as_bool;
|
|
} m_value;
|
|
};
|
|
|
|
}
|
|
|
|
using AK::JsonValue;
|