Introduce a JSON module (#379)
* Add JSON module * Merge upstream changes Fix memory leaks * Add json include to PackageScript * Merge upstream changes Fix memory leaks and increase max nesting * Fix documentation * Use AutoPtr in managing JSON handles * Merge upstream changes Order of items in an array is preserved after removing an item. * Merge upstream * Fix crash * Add VS projects files and fix mixed tab/spaces * Remove erroring on "json_free" * Add comments to "json.inc" file * Remove overloaded operators * Use of "override" keyword where needed * Fix parameter's name
This commit is contained in:
committed by
Vincent Herbet
parent
f96cb9a3b6
commit
361a6cc9e0
779
plugins/include/json.inc
Normal file
779
plugins/include/json.inc
Normal file
@ -0,0 +1,779 @@
|
||||
// vim: set ts=4 sw=4 tw=99 noet:
|
||||
//
|
||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
||||
// Copyright (C) The AMX Mod X Development Team.
|
||||
//
|
||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
||||
// https://alliedmods.net/amxmodx-license
|
||||
|
||||
//
|
||||
// JSON Natives
|
||||
//
|
||||
|
||||
#if defined _json_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _json_included
|
||||
|
||||
#pragma reqlib json
|
||||
#if !defined AMXMODX_NOAUTOLOAD
|
||||
#pragma loadlib json
|
||||
#endif
|
||||
|
||||
/*
|
||||
* JSON types
|
||||
*/
|
||||
enum JSONType
|
||||
{
|
||||
JSONError = -1,
|
||||
JSONNull = 1,
|
||||
JSONString = 2,
|
||||
JSONNumber = 3,
|
||||
JSONObject = 4,
|
||||
JSONArray = 5,
|
||||
JSONBoolean = 6
|
||||
};
|
||||
|
||||
/*
|
||||
* JSON invalid handle
|
||||
*/
|
||||
enum JSON
|
||||
{
|
||||
Invalid_JSON = -1
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper macros for checking type
|
||||
*/
|
||||
#define json_is_object(%1) (%1 != Invalid_JSON && json_get_type(%1) == JSONObject)
|
||||
#define json_is_array(%1) (%1 != Invalid_JSON && json_get_type(%1) == JSONArray)
|
||||
#define json_is_string(%1) (%1 != Invalid_JSON && json_get_type(%1) == JSONString)
|
||||
#define json_is_number(%1) (%1 != Invalid_JSON && json_get_type(%1) == JSONNumber)
|
||||
#define json_is_bool(%1) (%1 != Invalid_JSON && json_get_type(%1) == JSONBoolean)
|
||||
#define json_is_null(%1) (%1 != Invalid_JSON && json_get_type(%1) == JSONNull)
|
||||
#define json_is_true(%1) (%1 != Invalid_JSON && json_is_bool(%1) && json_get_bool(%1))
|
||||
#define json_is_false(%1) (%1 != Invalid_JSON && json_is_bool(%1) && !json_get_bool(%1))
|
||||
|
||||
/**
|
||||
* Parses JSON string or a file that contains JSON.
|
||||
*
|
||||
* @note Needs to be freed using json_free() native.
|
||||
*
|
||||
* @param string String to parse
|
||||
* @param is_file True to treat string param as filename, false otherwise
|
||||
* @param with_comments True if parsing JSON includes comments (it will ignore them), false otherwise
|
||||
*
|
||||
* @return JSON handle, Invalid_JSONValue if error occurred
|
||||
*/
|
||||
native JSON:json_parse(const string[], bool:is_file = false, bool:with_comments = false);
|
||||
|
||||
/**
|
||||
* Checks if the first value is the same as the second one.
|
||||
*
|
||||
* @param value1 JSON handle
|
||||
* @param value2 JSON handle
|
||||
*
|
||||
* @return True if they are the same, false otherwise
|
||||
* @error If passed value is not a valid handle
|
||||
*/
|
||||
native bool:json_equals(const JSON:value1, const JSON:value2);
|
||||
|
||||
/**
|
||||
* Validates json by checking if object have identically named
|
||||
* fields with matching types.
|
||||
*
|
||||
* @note Schema {"name":"", "age":0} will validate
|
||||
* {"name":"Joe", "age":25} and {"name":"Joe", "age":25, "gender":"m"},
|
||||
* but not {"name":"Joe"} or {"name":"Joe", "age":"Cucumber"}.
|
||||
*
|
||||
* @note In case of arrays, only first value in schema
|
||||
* is checked against all values in tested array.
|
||||
*
|
||||
* @note Empty objects ({}) validate all objects,
|
||||
* empty arrays ([]) validate all arrays,
|
||||
* null validates values of every type.
|
||||
*
|
||||
* @param schema JSON handle
|
||||
* @param value JSON handle
|
||||
*
|
||||
* @return True if passed value is valid, false otherwise
|
||||
* @error If a schema handle or value handle is invalid
|
||||
*/
|
||||
native bool:json_validate(const JSON:schema, const JSON:value);
|
||||
|
||||
/**
|
||||
* Gets value's parent handle.
|
||||
*
|
||||
* @note Parent's handle needs to be freed using json_free() native.
|
||||
*
|
||||
* @param value JSON handle
|
||||
*
|
||||
* @return Parent's handle
|
||||
*/
|
||||
native JSON:json_get_parent(const JSON:value);
|
||||
|
||||
/**
|
||||
* Gets JSON type of passed value.
|
||||
*
|
||||
* @param value JSON handle
|
||||
*
|
||||
* @return JSON type (JSONType constants)
|
||||
* @error If a value handle is invalid
|
||||
*/
|
||||
native JSONType:json_get_type(const JSON:value);
|
||||
|
||||
/**
|
||||
* Inits an empty object.
|
||||
*
|
||||
* @note Needs to be freed using json_free() native.
|
||||
*
|
||||
* @return JSON handle, Invalid_JSON if error occurred
|
||||
*/
|
||||
native JSON:json_init_object();
|
||||
|
||||
/**
|
||||
* Inits an empty array.
|
||||
*
|
||||
* @note Needs to be freed using json_free() native.
|
||||
*
|
||||
* @return JSON handle, Invalid_JSON if error occurred
|
||||
*/
|
||||
native JSON:json_init_array();
|
||||
|
||||
/**
|
||||
* Inits string data.
|
||||
*
|
||||
* @note Needs to be freed using json_free() native.
|
||||
*
|
||||
* @param value String that the handle will be initialized with
|
||||
*
|
||||
* @return JSON handle, Invalid_JSON if error occurred
|
||||
*/
|
||||
native JSON:json_init_string(const value[]);
|
||||
|
||||
/**
|
||||
* Inits a number.
|
||||
*
|
||||
* @note Needs to be freed using json_free() native.
|
||||
*
|
||||
* @param value Integer number that the handle will be initialized with
|
||||
*
|
||||
* @return JSON handle, Invalid_JSON if error occurred
|
||||
*/
|
||||
native JSON:json_init_number(value);
|
||||
|
||||
/**
|
||||
* Inits a real number.
|
||||
*
|
||||
* @note Needs to be freed using json_free() native.
|
||||
*
|
||||
* @param value Real number that the handle will be initialized with
|
||||
*
|
||||
* @return JSON handle, Invalid_JSON if error occurred
|
||||
*/
|
||||
native JSON:json_init_real(Float:value);
|
||||
|
||||
/**
|
||||
* Inits a boolean value.
|
||||
*
|
||||
* @note Needs to be freed using json_free() native.
|
||||
*
|
||||
* @param value Boolean value that the handle will be initialized with
|
||||
*
|
||||
* @return JSON handle, Invalid_JSON if error occurred
|
||||
*/
|
||||
native JSON:json_init_bool(bool:value);
|
||||
|
||||
/**
|
||||
* Inits a null.
|
||||
*
|
||||
* @note Needs to be freed using json_free() native.
|
||||
*
|
||||
* @return JSON handle, Invalid_JSON if error occurred
|
||||
*/
|
||||
native JSON:json_init_null();
|
||||
|
||||
/**
|
||||
* Creates deep copy of passed value.
|
||||
*
|
||||
* @note Needs to be freed using json_free() native.
|
||||
*
|
||||
* @param value JSON handle to be copied
|
||||
*
|
||||
* @return JSON handle, Invalid_JSON if error occurred
|
||||
* @error If passed value is not a valid handle
|
||||
*/
|
||||
native JSON:json_deep_copy(const JSON:value);
|
||||
|
||||
/**
|
||||
* Frees handle.
|
||||
*
|
||||
* @param handle JSON handle to be freed
|
||||
*
|
||||
* @return True if succeed, false otherwise
|
||||
* @error If passed handle is not a valid handle
|
||||
*/
|
||||
native bool:json_free(&JSON:handle);
|
||||
|
||||
/**
|
||||
* Gets string data.
|
||||
*
|
||||
* @param value JSON handle
|
||||
* @param buffer Buffer to copy string to
|
||||
* @param maxlen Maximum size of the buffer
|
||||
*
|
||||
* @return The number of cells written to the buffer
|
||||
* @error If passed value is not a valid handle
|
||||
*/
|
||||
native json_get_string(const JSON:value, buffer[], maxlen);
|
||||
|
||||
/**
|
||||
* Gets a number.
|
||||
*
|
||||
* @param value JSON handle
|
||||
*
|
||||
* @return Number
|
||||
* @error If passed value is not a valid handle
|
||||
*/
|
||||
native json_get_number(const JSON:value);
|
||||
|
||||
/**
|
||||
* Gets a real number.
|
||||
*
|
||||
* @param value JSON handle
|
||||
*
|
||||
* @return Real number
|
||||
* @error If passed value is not a valid handle
|
||||
*/
|
||||
native Float:json_get_real(const JSON:value);
|
||||
|
||||
/**
|
||||
* Gets a boolean value.
|
||||
*
|
||||
* @param value JSON handle
|
||||
*
|
||||
* @return Boolean value
|
||||
* @error If passed value is not a valid handle
|
||||
*/
|
||||
native bool:json_get_bool(const JSON:value);
|
||||
|
||||
/**
|
||||
* Gets a value from the array.
|
||||
*
|
||||
* @note Needs to be freed using json_free() native.
|
||||
*
|
||||
* @param array Array handle
|
||||
* @param index Position in the array (starting from 0)
|
||||
*
|
||||
* @return JSON handle, Invalid_JSON if error occurred
|
||||
* @error If passed handle is not a valid array
|
||||
*/
|
||||
native JSON:json_array_get_value(const JSON:array, index);
|
||||
|
||||
/**
|
||||
* Gets string data from the array.
|
||||
*
|
||||
* @param array Array handle
|
||||
* @param index Position in the array (starting from 0)
|
||||
* @param buffer Buffer to copy string to
|
||||
* @param maxlen Maximum size of the buffer
|
||||
*
|
||||
* @return The number of cells written to the buffer
|
||||
* @error If passed handle is not a valid array
|
||||
*/
|
||||
native json_array_get_string(const JSON:array, index, buffer[], maxlen);
|
||||
|
||||
/**
|
||||
* Gets a number from the array.
|
||||
*
|
||||
* @param array Array handle
|
||||
* @param index Position in the array (starting from 0)
|
||||
*
|
||||
* @return The number as integer
|
||||
* @error If passed handle is not a valid array
|
||||
*/
|
||||
native json_array_get_number(const JSON:array, index);
|
||||
|
||||
/**
|
||||
* Gets a real number from the array.
|
||||
*
|
||||
* @param array Array handle
|
||||
* @param index Position in the array (starting from 0)
|
||||
*
|
||||
* @return The number as float
|
||||
* @error If passed handle is not a valid array
|
||||
*/
|
||||
native Float:json_array_get_real(const JSON:array, index);
|
||||
|
||||
/**
|
||||
* Gets a boolean value from the array.
|
||||
*
|
||||
* @param array Array handle
|
||||
* @param index Position in the array (starting from 0)
|
||||
*
|
||||
* @return Boolean value
|
||||
* @error If passed handle is not a valid array
|
||||
*/
|
||||
native bool:json_array_get_bool(const JSON:array, index);
|
||||
|
||||
/**
|
||||
* Gets count of the elements in the array.
|
||||
*
|
||||
* @param array Array handle
|
||||
*
|
||||
* @return Number of elements in the array
|
||||
* @error If passed handle is not a valid array
|
||||
*/
|
||||
native json_array_get_count(const JSON:array);
|
||||
|
||||
/**
|
||||
* Replaces an element in the array with value.
|
||||
*
|
||||
* @param array Array handle
|
||||
* @param index Position in the array to be replaced
|
||||
* @param value JSON handle to set
|
||||
*
|
||||
* @return True if succeed, false otherwise
|
||||
* @error If passed handle is not a valid array
|
||||
*/
|
||||
native bool:json_array_replace_value(JSON:array, index, const JSON:value);
|
||||
|
||||
/**
|
||||
* Replaces an element in the array with string data.
|
||||
*
|
||||
* @param array Array handle
|
||||
* @param index Position in the array to be replaced
|
||||
* @param string String to copy
|
||||
*
|
||||
* @return True if succeed, false otherwise
|
||||
* @error If passed handle is not a valid array
|
||||
*/
|
||||
native bool:json_array_replace_string(JSON:array, index, const string[]);
|
||||
|
||||
/**
|
||||
* Replaces an element in the array with number.
|
||||
*
|
||||
* @param array Array handle
|
||||
* @param index Position in the array to be replaced
|
||||
* @param number Number to set
|
||||
*
|
||||
* @return True if succeed, false otherwise
|
||||
* @error If passed handle is not a valid array
|
||||
*/
|
||||
native bool:json_array_replace_number(JSON:array, index, number);
|
||||
|
||||
/**
|
||||
* Replaces an element in the array with real number.
|
||||
*
|
||||
* @param array Array handle
|
||||
* @param index Position in the array to be replaced
|
||||
* @param number Real number to set
|
||||
*
|
||||
* @return True if succeed, false otherwise
|
||||
* @error If passed handle is not a valid array
|
||||
*/
|
||||
native bool:json_array_replace_real(JSON:array, index, Float:number);
|
||||
|
||||
/**
|
||||
* Replaces an element in the array with boolean value.
|
||||
*
|
||||
* @param array Array handle
|
||||
* @param index Position in the array to be replaced
|
||||
* @param boolean Boolean value to set
|
||||
*
|
||||
* @return True if succeed, false otherwise
|
||||
* @error If passed handle is not a valid array
|
||||
*/
|
||||
native bool:json_array_replace_bool(JSON:array, index, bool:boolean);
|
||||
|
||||
/**
|
||||
* Replaces an element in the array with null.
|
||||
*
|
||||
* @param array Array handle
|
||||
* @param index Position in the array to be replaced
|
||||
*
|
||||
* @return True if succeed, false otherwise
|
||||
* @error If passed handle is not a valid array
|
||||
*/
|
||||
native bool:json_array_replace_null(JSON:array, index);
|
||||
|
||||
/**
|
||||
* Appends a value in the array.
|
||||
*
|
||||
* @param array Array handle
|
||||
* @param value JSON handle to set
|
||||
*
|
||||
* @return True if succeed, false otherwise
|
||||
* @error If passed handle is not a valid array
|
||||
*/
|
||||
native bool:json_array_append_value(JSON:array, const JSON:value);
|
||||
|
||||
/**
|
||||
* Appends string data in the array.
|
||||
*
|
||||
* @param array Array handle
|
||||
* @param string String to copy
|
||||
*
|
||||
* @return True if succeed, false otherwise
|
||||
* @error If passed handle is not a valid array
|
||||
*/
|
||||
native bool:json_array_append_string(JSON:array, const string[]);
|
||||
|
||||
/**
|
||||
* Appends a number in the array.
|
||||
*
|
||||
* @param array Array handle
|
||||
* @param number Number to set
|
||||
*
|
||||
* @return True if succeed, false otherwise
|
||||
* @error If passed handle is not a valid array
|
||||
*/
|
||||
native bool:json_array_append_number(JSON:array, number);
|
||||
|
||||
/**
|
||||
* Appends a real number in the array.
|
||||
*
|
||||
* @param array Array handle
|
||||
* @param number Real number to set
|
||||
*
|
||||
* @return True if succeed, false otherwise
|
||||
* @error If passed handle is not a valid array
|
||||
*/
|
||||
native bool:json_array_append_real(JSON:array, Float:number);
|
||||
|
||||
/**
|
||||
* Appends a boolean value in the array.
|
||||
*
|
||||
* @param array Array handle
|
||||
* @param boolean Boolean value to set
|
||||
*
|
||||
* @return True if succeed, false otherwise
|
||||
* @error If passed handle is not a valid array
|
||||
*/
|
||||
native bool:json_array_append_bool(JSON:array, bool:boolean);
|
||||
|
||||
/**
|
||||
* Appends a null in the array.
|
||||
*
|
||||
* @param array Array handle
|
||||
*
|
||||
* @return True if succeed, false otherwise
|
||||
* @error If passed handle is not a valid array
|
||||
*/
|
||||
native bool:json_array_append_null(JSON:array);
|
||||
|
||||
/**
|
||||
* Removes an element from the array.
|
||||
*
|
||||
* @note Order of values in array may change during execution.
|
||||
*
|
||||
* @param array Array handle
|
||||
* @param index Position in the array (starting from 0)
|
||||
*
|
||||
* @return True if succeed, false otherwise
|
||||
* @error If passed handle is not a valid array
|
||||
*/
|
||||
native bool:json_array_remove(JSON:array, index);
|
||||
|
||||
/**
|
||||
* Removes all elements from the array.
|
||||
*
|
||||
* @param array Array handle
|
||||
*
|
||||
* @return True if succeed, false otherwise
|
||||
* @error If passed handle is not a valid array
|
||||
*/
|
||||
native bool:json_array_clear(JSON:array);
|
||||
|
||||
/**
|
||||
* Gets a value from the object.
|
||||
*
|
||||
* @note Needs to be freed using json_free() native.
|
||||
* @note If dot notation is used some values may be inaccessible
|
||||
* because valid names in JSON can contain dots.
|
||||
*
|
||||
* @param object Object handle
|
||||
* @param name Key name
|
||||
* @param dot_not True to use dot notation, false to not
|
||||
*
|
||||
* @return JSON handle, Invalid_JSON if error occurred
|
||||
* @error If passed handle is not a valid object
|
||||
*/
|
||||
native JSON:json_object_get_value(const JSON:object, const name[], bool:dot_not = false);
|
||||
|
||||
/**
|
||||
* Gets string data from the object.
|
||||
*
|
||||
* @note If dot notation is used some values may be inaccessible
|
||||
* because valid names in JSON can contain dots.
|
||||
*
|
||||
* @param object Object handle
|
||||
* @param name Key name
|
||||
* @param buffer Buffer to copy string to
|
||||
* @param maxlen Maximum size of the buffer
|
||||
* @param dot_not True to use dot notation, false to not
|
||||
*
|
||||
* @return The number of cells written to the buffer
|
||||
* @error If passed handle is not a valid object
|
||||
*/
|
||||
native json_object_get_string(const JSON:object, const name[], buffer[], maxlen, bool:dot_not = false);
|
||||
|
||||
/**
|
||||
* Gets a number from the object.
|
||||
*
|
||||
* @note If dot notation is used some values may be inaccessible
|
||||
* because valid names in JSON can contain dots.
|
||||
*
|
||||
* @param object Object handle
|
||||
* @param name Key name
|
||||
* @param dot_not True to use dot notation, false to not
|
||||
*
|
||||
* @return Number
|
||||
* @error If passed handle is not a valid object
|
||||
*/
|
||||
native json_object_get_number(const JSON:object, const name[], bool:dot_not = false);
|
||||
|
||||
/**
|
||||
* Gets a real number from the object.
|
||||
*
|
||||
* @note If dot notation is used some values may be inaccessible
|
||||
* because valid names in JSON can contain dots.
|
||||
*
|
||||
* @param object Object handle
|
||||
* @param name Key name
|
||||
* @param dot_not True to use dot notation, false to not
|
||||
*
|
||||
* @return Real number
|
||||
* @error If passed handle is not a valid object
|
||||
*/
|
||||
native Float:json_object_get_real(const JSON:object, const name[], bool:dot_not = false);
|
||||
|
||||
/**
|
||||
* Gets a boolean value from the object.
|
||||
*
|
||||
* @note If dot notation is used some values may be inaccessible
|
||||
* because valid names in JSON can contain dots.
|
||||
*
|
||||
* @param object Object handle
|
||||
* @param name Key name
|
||||
* @param dot_not True to use dot notation, false to not
|
||||
*
|
||||
* @return Boolean value
|
||||
* @error If passed handle is not a valid object
|
||||
*/
|
||||
native bool:json_object_get_bool(const JSON:object, const name[], bool:dot_not = false);
|
||||
|
||||
/**
|
||||
* Gets count of the keys in the object.
|
||||
*
|
||||
* @param object Object handle
|
||||
*
|
||||
* @return Keys count
|
||||
* @error If passed handle is not a valid object
|
||||
*/
|
||||
native json_object_get_count(const JSON:object);
|
||||
|
||||
/**
|
||||
* Gets name of the object's key.
|
||||
*
|
||||
* @param object Object handle
|
||||
* @param index Position from which get key name
|
||||
* @param buffer Buffer to copy string to
|
||||
* @param maxlen Maximum size of the buffer
|
||||
*
|
||||
* @return The number of cells written to the buffer
|
||||
* @error If passed handle is not a valid object
|
||||
*/
|
||||
native json_object_get_name(const JSON:object, index, buffer[], maxlen);
|
||||
|
||||
/**
|
||||
* Gets a value at the specified position from the object.
|
||||
*
|
||||
* @note Needs to be freed using json_free() native.
|
||||
*
|
||||
* @param object Object handle
|
||||
* @param index Position from which get key name
|
||||
* @param buffer Buffer to copy string to
|
||||
* @param maxlen Maximum size of the buffer
|
||||
*
|
||||
* @return The number of cells written to the buffer
|
||||
* @error If passed handle is not a valid object
|
||||
*/
|
||||
native JSON:json_object_get_value_at(const JSON:object, index);
|
||||
|
||||
/**
|
||||
* Checks if the object has a value with a specific name and type.
|
||||
*
|
||||
* @param object Object handle
|
||||
* @param name Key name
|
||||
* @param type Type of value, if JSONError type will not be checked
|
||||
* @param dot_not True to use dot notation, false to not
|
||||
*
|
||||
* @return True if has, false if not
|
||||
* @error If passed handle is not a valid object
|
||||
*/
|
||||
native bool:json_object_has_value(const JSON:object, const name[], JSONType:type = JSONError, bool:dot_not = false);
|
||||
|
||||
/**
|
||||
* Sets a value in the object.
|
||||
*
|
||||
* @note If dot notation is used some values may be inaccessible
|
||||
* because valid names in JSON can contain dots.
|
||||
* @note It also removes the old value if any.
|
||||
*
|
||||
* @param object Object handle
|
||||
* @param name Key name
|
||||
* @param value JSON handle to set
|
||||
* @param dot_not True to use dot notation, false to not
|
||||
*
|
||||
* @return True if succeed, false otherwise
|
||||
* @error If passed handle is not a valid object
|
||||
*/
|
||||
native bool:json_object_set_value(JSON:object, const name[], const JSON:value, bool:dot_not = false);
|
||||
|
||||
/**
|
||||
* Sets string data in the object.
|
||||
*
|
||||
* @note If dot notation is used some values may be inaccessible
|
||||
* because valid names in JSON can contain dots.
|
||||
* @note It also removes the old value if any.
|
||||
*
|
||||
* @param object Object handle
|
||||
* @param name Key name
|
||||
* @param string String to copy
|
||||
* @param dot_not True to use dot notation, false to not
|
||||
*
|
||||
* @return True if succeed, false otherwise
|
||||
* @error If passed handle is not a valid object
|
||||
*/
|
||||
native bool:json_object_set_string(JSON:object, const name[], const string[], bool:dot_not = false);
|
||||
|
||||
/**
|
||||
* Sets a number in the object.
|
||||
*
|
||||
* @note If dot notation is used some values may be inaccessible
|
||||
* because valid names in JSON can contain dots.
|
||||
* @note It also removes the old value if any.
|
||||
*
|
||||
* @param object Object handle
|
||||
* @param name Key name
|
||||
* @param number Number to set
|
||||
* @param dot_not True to use dot notation, false to not
|
||||
*
|
||||
* @return True if succeed, false otherwise
|
||||
* @error If passed handle is not a valid object
|
||||
*/
|
||||
native bool:json_object_set_number(JSON:object, const name[], number, bool:dot_not = false);
|
||||
|
||||
/**
|
||||
* Sets a real number in the object.
|
||||
*
|
||||
* @note If dot notation is used some values may be inaccessible
|
||||
* because valid names in JSON can contain dots.
|
||||
* @note It also removes the old value if any.
|
||||
*
|
||||
* @param object Object handle
|
||||
* @param name Key name
|
||||
* @param number Real number to set
|
||||
* @param dot_not True to use dot notation, false to not
|
||||
*
|
||||
* @return True if succeed, false otherwise
|
||||
* @error If passed handle is not a valid object
|
||||
*/
|
||||
native bool:json_object_set_real(JSON:object, const name[], Float:number, bool:dot_not = false);
|
||||
|
||||
/**
|
||||
* Sets a boolean value in the object.
|
||||
*
|
||||
* @note If dot notation is used some values may be inaccessible
|
||||
* because valid names in JSON can contain dots.
|
||||
* @note It also removes the old value if any.
|
||||
*
|
||||
* @param object Object handle
|
||||
* @param name Key name
|
||||
* @param boolean Boolean value to set
|
||||
* @param dot_not True to use dot notation, false to not
|
||||
*
|
||||
* @return True if succeed, false otherwise
|
||||
* @error If passed handle is not a valid object
|
||||
*/
|
||||
native bool:json_object_set_bool(JSON:object, const name[], bool:boolean, bool:dot_not = false);
|
||||
|
||||
/**
|
||||
* Sets a null in the object.
|
||||
*
|
||||
* @note If dot notation is used some values may be inaccessible
|
||||
* because valid names in JSON can contain dots.
|
||||
* @note It also removes the old value if any.
|
||||
*
|
||||
* @param object Object handle
|
||||
* @param name Key name
|
||||
* @param dot_not True to use dot notation, false to not
|
||||
*
|
||||
* @return True if succeed, false otherwise
|
||||
* @error If passed handle is not a valid object
|
||||
*/
|
||||
native bool:json_object_set_null(JSON:object, const name[], bool:dot_not = false);
|
||||
|
||||
/**
|
||||
* Removes a key and its value in the object.
|
||||
*
|
||||
* @note If dot notation is used some values may be inaccessible
|
||||
* because valid names in JSON can contain dots.
|
||||
*
|
||||
* @param object Object handle
|
||||
* @param name Key name
|
||||
* @param dot_not True to use dot notation, false to not
|
||||
*
|
||||
* @return True if succeed, false otherwise
|
||||
* @error If passed handle is not a valid object
|
||||
*/
|
||||
native bool:json_object_remove(JSON:object, const name[], bool:dot_not = false);
|
||||
|
||||
/**
|
||||
* Removes all keys and their values in the object.
|
||||
*
|
||||
* @param object Object handle
|
||||
*
|
||||
* @return True if succeed, false otherwise
|
||||
* @error If passed handle is not a valid object
|
||||
*/
|
||||
native bool:json_object_clear(JSON:object);
|
||||
|
||||
/**
|
||||
* Gets size of serialization.
|
||||
*
|
||||
* @param value JSON handle
|
||||
* @param pretty True to count size for pretty format, false to not
|
||||
* @param null_byte True to include null byte, false to not
|
||||
*
|
||||
* @return Size of serialized string
|
||||
* @error If passed handle is not a valid value
|
||||
*/
|
||||
native json_serial_size(const JSON:value, bool:pretty = false, bool:null_byte = false);
|
||||
|
||||
/**
|
||||
* Copies serialized string to the buffer.
|
||||
*
|
||||
* @param value JSON handle
|
||||
* @param buffer Buffer to copy string to
|
||||
* @param maxlen Maximum size of the buffer
|
||||
* @param pretty True to format pretty JSON string, false to not
|
||||
*
|
||||
* @return The number of cells written to the buffer
|
||||
* @error If passed handle is not a valid value
|
||||
*/
|
||||
native json_serial_to_string(const JSON:value, buffer[], maxlen, bool:pretty = false);
|
||||
|
||||
/**
|
||||
* Copies serialized string to the file.
|
||||
*
|
||||
* @param value JSON handle
|
||||
* @param file Path to the file
|
||||
* @param pretty True to format pretty JSON string, false to not
|
||||
*
|
||||
* @return True if succeed, false otherwise
|
||||
* @error If passed handle is not a valid value
|
||||
*/
|
||||
native bool:json_serial_to_file(const JSON:value, const file[], bool:pretty = false);
|
494
plugins/testsuite/json_test.sma
Normal file
494
plugins/testsuite/json_test.sma
Normal file
@ -0,0 +1,494 @@
|
||||
// vim: set ts=4 sw=4 tw=99 noet:
|
||||
//
|
||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
||||
// Copyright (C) The AMX Mod X Development Team.
|
||||
//
|
||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
||||
// https://alliedmods.net/amxmodx-license
|
||||
|
||||
#include <amxmodx>
|
||||
#include <json>
|
||||
|
||||
//For encoding
|
||||
new buffer[500];
|
||||
|
||||
public plugin_init()
|
||||
{
|
||||
register_plugin("JSON Test", "1.0", "Ni3znajomy");
|
||||
register_srvcmd("json_test_encode", "cmdJSONTestEncode");
|
||||
register_srvcmd("json_test_decode", "cmdJSONTestDecode");
|
||||
register_srvcmd("json_test_replace", "cmdJSONTestReplace");
|
||||
register_srvcmd("json_test_validate", "cmdJSONTestValidate");
|
||||
register_srvcmd("json_test_has_key", "cmdJSONTestHasKey");
|
||||
register_srvcmd("json_test_remove", "cmdJSONTestRemove");
|
||||
}
|
||||
|
||||
public cmdJSONTestEncode()
|
||||
{
|
||||
if (read_argc() < 3)
|
||||
{
|
||||
server_print("Usage: json_test_encode <use init funcs> <use pretty format>");
|
||||
return;
|
||||
}
|
||||
// Use init funcs?
|
||||
new bool:init = bool:read_argv_int(1);
|
||||
|
||||
//Pretty
|
||||
new bool:pretty = bool:read_argv_int(2);
|
||||
|
||||
// Create root array
|
||||
new JSON:root_array = json_init_array();
|
||||
// Init & setup object
|
||||
new JSON:object = json_init_object();
|
||||
if (!init)
|
||||
{
|
||||
json_object_set_string(object, "string", "https://alliedmods.net");
|
||||
json_object_set_number(object, "number", 45);
|
||||
json_object_set_real(object, "real", -5.31);
|
||||
json_object_set_null(object, "null.null");
|
||||
json_object_set_bool(object, "bool.true", true, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
ObjectSetKey(object, "string", json_init_string("https://alliedmods.net"));
|
||||
ObjectSetKey(object, "number", json_init_number(45));
|
||||
ObjectSetKey(object, "real", json_init_real(-5.31));
|
||||
ObjectSetKey(object, "null.null", json_init_null());
|
||||
ObjectSetKey(object, "bool.true", json_init_bool(true), true);
|
||||
}
|
||||
|
||||
// Add object to root array
|
||||
ArrayAppendValue(root_array, object);
|
||||
|
||||
new JSON:parent = json_get_parent(root_array);
|
||||
if (parent != Invalid_JSON)
|
||||
{
|
||||
server_print("Root array has parent!");
|
||||
json_free(parent);
|
||||
json_free(root_array);
|
||||
return;
|
||||
}
|
||||
|
||||
// Append some values to root array
|
||||
if (!init)
|
||||
{
|
||||
json_array_append_real(root_array, -31.1);
|
||||
json_array_append_number(root_array, -42);
|
||||
json_array_append_bool(root_array, false);
|
||||
json_array_append_null(root_array);
|
||||
}
|
||||
else
|
||||
{
|
||||
ArrayAppendValue(root_array, json_init_real(-31.1));
|
||||
ArrayAppendValue(root_array, json_init_number(-42));
|
||||
ArrayAppendValue(root_array, json_init_bool(false));
|
||||
ArrayAppendValue(root_array, json_init_null());
|
||||
}
|
||||
|
||||
// Serialiaze to file and to buffer
|
||||
json_serial_to_file(root_array, "json_encode_test_to_file.txt", pretty);
|
||||
json_serial_to_string(root_array, buffer, charsmax(buffer), pretty);
|
||||
|
||||
// Put buffer's content to file
|
||||
new file = fopen("json_encode_test_to_string.txt", "wt");
|
||||
if (!file)
|
||||
{
|
||||
server_print("Couldn't create file");
|
||||
return;
|
||||
}
|
||||
|
||||
fputs(file, buffer);
|
||||
fclose(file);
|
||||
|
||||
server_print("Encoding done (%d bytes)", json_serial_size(root_array, pretty));
|
||||
json_free(root_array);
|
||||
}
|
||||
|
||||
public cmdJSONTestDecode()
|
||||
{
|
||||
// Check if encode command was run
|
||||
if (!strlen(buffer))
|
||||
{
|
||||
server_print("Run ^"json_test_encode^" first!");
|
||||
return;
|
||||
}
|
||||
|
||||
new JSON:root_array = json_parse(buffer);
|
||||
new JSON:for_compare = json_parse("json_encode_test_to_file.txt", true);
|
||||
|
||||
// Check if they are the same
|
||||
if (root_array != for_compare || !json_is_array(root_array))
|
||||
{
|
||||
if (root_array != Invalid_JSON)
|
||||
json_free(root_array);
|
||||
|
||||
if (for_compare != Invalid_JSON)
|
||||
json_free(for_compare);
|
||||
|
||||
server_print("Root value is not array!");
|
||||
return;
|
||||
}
|
||||
|
||||
// We don't need this anymore
|
||||
json_free(for_compare);
|
||||
|
||||
DecodeArray(root_array);
|
||||
|
||||
json_free(root_array);
|
||||
}
|
||||
|
||||
//Creating inversed root array
|
||||
public cmdJSONTestReplace()
|
||||
{
|
||||
// Check if encode command was run
|
||||
if (!strlen(buffer))
|
||||
{
|
||||
server_print("Run ^"json_test_encode^" first!");
|
||||
return;
|
||||
}
|
||||
|
||||
new JSON:root_array_orig = json_parse(buffer);
|
||||
new JSON:root_array_copy = json_deep_copy(root_array_orig);
|
||||
json_free(root_array_orig);
|
||||
|
||||
//Replace null with object
|
||||
new JSON:object = json_array_get_value(root_array_copy, 0);
|
||||
json_array_replace_value(root_array_copy, 4, object);
|
||||
json_free(object);
|
||||
|
||||
//Replace object with null
|
||||
json_array_replace_null(root_array_copy, 0);
|
||||
|
||||
//Replace bool with real and vice versa
|
||||
new Float:realnum = json_array_get_real(root_array_copy, 1);
|
||||
new bool:boolval = json_array_get_bool(root_array_copy, 3);
|
||||
json_array_replace_real(root_array_copy, 3, realnum);
|
||||
json_array_replace_bool(root_array_copy, 1, boolval);
|
||||
|
||||
//Replace number with random
|
||||
json_array_replace_number(root_array_copy, 2, random(42));
|
||||
|
||||
json_serial_to_file(root_array_copy, "json_replace_test.txt", true);
|
||||
|
||||
json_free(root_array_copy);
|
||||
|
||||
server_print("Values replaced!");
|
||||
}
|
||||
|
||||
public cmdJSONTestValidate()
|
||||
{
|
||||
// Check if encode command was run
|
||||
if (!strlen(buffer))
|
||||
{
|
||||
server_print("Run ^"json_test_encode^" first!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (read_argc() < 2)
|
||||
{
|
||||
server_print("Usage: json_test_validate <success>");
|
||||
return;
|
||||
}
|
||||
|
||||
//Should validating be succeed?
|
||||
new bool:success = bool:read_argv_int(1);
|
||||
|
||||
//Create schema
|
||||
new JSON:schema = json_init_object();
|
||||
|
||||
if (success)
|
||||
json_object_set_string(schema, "string", "");
|
||||
else
|
||||
json_object_set_real(schema, "string", 0.0);
|
||||
|
||||
json_object_set_number(schema, "number", 0);
|
||||
json_object_set_null(schema, "real"); //Null validate all types
|
||||
|
||||
new JSON:root_array = json_parse(buffer); //Get root array
|
||||
new JSON:object = json_array_get_value(root_array, 0); //Get object from it
|
||||
|
||||
new bool:result = json_validate(schema, object); //Validate object with our schema
|
||||
|
||||
server_print("Validate %d! (result: %d)", result, result == success);
|
||||
|
||||
json_free(object);
|
||||
json_free(schema);
|
||||
json_free(root_array);
|
||||
}
|
||||
|
||||
public cmdJSONTestHasKey()
|
||||
{
|
||||
// Check if encode command was run
|
||||
if (!strlen(buffer))
|
||||
{
|
||||
server_print("Run ^"json_test_encode^" first!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (read_argc() < 2)
|
||||
{
|
||||
server_print("Usage: json_test_has_key <key name> <dotnot> <type>");
|
||||
server_print("Available types:^nn - null^ns - string^nr - number^no - object^na - array^nb - boolean");
|
||||
return;
|
||||
}
|
||||
|
||||
//Get root array
|
||||
new JSON:root_array = json_parse(buffer);
|
||||
new JSON:object = json_array_get_value(root_array, 0); //Get object
|
||||
new keyname[32], type[10];
|
||||
new JSONType:jtype = JSONError;
|
||||
|
||||
read_argv(1, keyname, charsmax(keyname)); //Key name that have to be found
|
||||
new bool:dotnot = bool:read_argv_int(2); //Use dot natation? (optional)
|
||||
read_argv(3, type, charsmax(type)); //Type of searched value (optional)
|
||||
|
||||
//Get type
|
||||
switch(type[0])
|
||||
{
|
||||
case 'n': jtype = JSONNull;
|
||||
case 's': jtype = JSONString;
|
||||
case 'r': jtype = JSONNumber;
|
||||
case 'o': jtype = JSONObject;
|
||||
case 'a': jtype = JSONArray;
|
||||
case 'b': jtype = JSONBoolean;
|
||||
}
|
||||
|
||||
new bool:found = json_object_has_value(object, keyname, jtype, dotnot);
|
||||
|
||||
if (jtype == JSONError)
|
||||
server_print("Key %s%s!%s Found!", keyname, (dotnot) ? " using dotnot" : "", (found) ? "" : " Not");
|
||||
else
|
||||
{
|
||||
GetTypeName(jtype, type, charsmax(type)); //Get type as string
|
||||
server_print("Key %s (type: %s)%s!%s Found!", keyname, type, (dotnot) ? " using dotnot" : "", (found) ? "" : " Not");
|
||||
}
|
||||
|
||||
json_free(object);
|
||||
json_free(root_array);
|
||||
}
|
||||
|
||||
public cmdJSONTestRemove()
|
||||
{
|
||||
// Check if encode command was run
|
||||
if (!strlen(buffer))
|
||||
{
|
||||
server_print("Run ^"json_test_encode^" first!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (read_argc() < 3)
|
||||
{
|
||||
server_print("Usage: json_test_has_key <type> <index/key name> <dotnot>");
|
||||
server_print("Available types:^na - array^no - object");
|
||||
return;
|
||||
}
|
||||
|
||||
//Get root array
|
||||
new JSON:root_array = json_parse(buffer);
|
||||
new type[10], bool:is_object, bool:success;
|
||||
|
||||
read_argv(1, type, charsmax(type)); //Type
|
||||
is_object = type[0] == 'o'; //Is type object?
|
||||
if (!is_object && type[0] != 'a') //If not, is it array?
|
||||
{
|
||||
server_print("Unknown type: %c", type[0]); //Fail, unknown type
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_object)
|
||||
{
|
||||
new keyname[32];
|
||||
new JSON:object = json_array_get_value(root_array, 0);
|
||||
|
||||
read_argv(2, keyname, charsmax(keyname)); //Key to delete or "clear" if object have to be cleared
|
||||
new bool:dotnot = bool:read_argv_int(3); //Use dot notation?
|
||||
|
||||
if (equal(keyname, "clear"))
|
||||
success = json_object_clear(object);
|
||||
else
|
||||
success = json_object_remove(object, keyname, dotnot);
|
||||
|
||||
json_free(object);
|
||||
}
|
||||
else
|
||||
{
|
||||
new index = read_argv_int(2); //Entry to delete or -1 if array have to be cleared
|
||||
|
||||
if (index == -1)
|
||||
success = json_array_clear(root_array);
|
||||
else
|
||||
success = json_array_remove(root_array, index);
|
||||
}
|
||||
|
||||
//Dump result
|
||||
json_serial_to_file(root_array, "json_remove_test.txt", true); //Use pretty format for better view
|
||||
|
||||
json_free(root_array);
|
||||
|
||||
server_print("Removing %s! (Results dumped)", (success) ? "succeed" : "failed");
|
||||
}
|
||||
|
||||
ObjectSetKey(JSON:object, const key[], JSON:node, bool:dot_not = false)
|
||||
{
|
||||
json_object_set_value(object, key, node, dot_not);
|
||||
json_free(node);
|
||||
}
|
||||
|
||||
ArrayAppendValue(JSON:array, JSON:node)
|
||||
{
|
||||
json_array_append_value(array, node);
|
||||
json_free(node);
|
||||
}
|
||||
|
||||
DecodeArray(&JSON:array)
|
||||
{
|
||||
//for storing string data
|
||||
new tempbuf[2][100];
|
||||
new JSON:array_value, JSON:parent_value;
|
||||
for (new i = 0; i < json_array_get_count(array); i++)
|
||||
{
|
||||
array_value = json_array_get_value(array, i);
|
||||
parent_value = json_get_parent(array_value);
|
||||
|
||||
if (parent_value != array)
|
||||
{
|
||||
json_free(parent_value);
|
||||
json_free(array_value);
|
||||
|
||||
server_print("[Array] Parent value differs!");
|
||||
break;
|
||||
}
|
||||
|
||||
json_free(parent_value);
|
||||
|
||||
switch (json_get_type(array_value))
|
||||
{
|
||||
case JSONNull: server_print("Array Index %d (Null)", i);
|
||||
case JSONString:
|
||||
{
|
||||
json_get_string(array_value, tempbuf[0], charsmax(tempbuf[]));
|
||||
json_array_get_string(array, i, tempbuf[1], charsmax(tempbuf[]));
|
||||
|
||||
server_print("Array Index %d (String) value: %s | index: %s", i, tempbuf[0], tempbuf[1]);
|
||||
}
|
||||
case JSONNumber:
|
||||
{
|
||||
new num1 = json_get_number(array_value), num2 = json_array_get_number(array, i);
|
||||
new Float:num3 = json_get_real(array_value), Float:num4 = json_array_get_real(array, i);
|
||||
|
||||
server_print("Array Index %d (Number/Real) value: %d/%f | index: %d/%f", i, num1, num3, num2, num4);
|
||||
}
|
||||
case JSONObject:
|
||||
{
|
||||
new iCount = json_object_get_count(array_value);
|
||||
server_print("Array Index %d (Object) %d elements", i, iCount);
|
||||
|
||||
DecodeObject(array_value);
|
||||
}
|
||||
case JSONArray:
|
||||
{
|
||||
new iCount = json_array_get_count(array_value);
|
||||
server_print("Array Index %d (Array) %d elements", i, iCount);
|
||||
|
||||
DecodeArray(array_value);
|
||||
}
|
||||
case JSONBoolean:
|
||||
{
|
||||
new bool:val1 = json_get_bool(array_value), bool:val2 = json_array_get_bool(array, i);
|
||||
server_print("Array Index %d (Bool) value %d | index %d", i, val1, val2);
|
||||
}
|
||||
}
|
||||
|
||||
json_free(array_value);
|
||||
}
|
||||
}
|
||||
|
||||
DecodeObject(&JSON:object)
|
||||
{
|
||||
//for storing string data
|
||||
new tempbuf[2][100];
|
||||
new key[30];
|
||||
new JSON:obj_value, JSON:parent_value;
|
||||
for (new i = 0; i < json_object_get_count(object); i++)
|
||||
{
|
||||
json_object_get_name(object, i, key, charsmax(key));
|
||||
obj_value = json_object_get_value_at(object, i);
|
||||
parent_value = json_get_parent(obj_value);
|
||||
|
||||
if (parent_value != object)
|
||||
{
|
||||
json_free(parent_value);
|
||||
json_free(obj_value);
|
||||
|
||||
server_print("[Object] Parent value differs!");
|
||||
break;
|
||||
}
|
||||
|
||||
json_free(parent_value);
|
||||
|
||||
switch (json_get_type(obj_value))
|
||||
{
|
||||
case JSONNull: server_print(" Object Key ^"%s^" (Null)", key);
|
||||
case JSONString:
|
||||
{
|
||||
json_get_string(obj_value, tempbuf[0], charsmax(tempbuf[]));
|
||||
json_object_get_string(object, key, tempbuf[1], charsmax(tempbuf[]));
|
||||
|
||||
server_print(" Object Key ^"%s^" (String) value: %s | key: %s", key, tempbuf[0], tempbuf[1]);
|
||||
}
|
||||
case JSONNumber:
|
||||
{
|
||||
new num1 = json_get_number(obj_value), num2 = json_object_get_number(object, key);
|
||||
new Float:num3 = json_get_real(obj_value), Float:num4 = json_object_get_real(object, key);
|
||||
|
||||
server_print(" Object Key ^"%s^" (Number/Real) value: %d/%f | key: %d/%f", key, num1, num3, num2, num4);
|
||||
}
|
||||
case JSONObject:
|
||||
{
|
||||
new iCount = json_object_get_count(obj_value);
|
||||
server_print(" Object Key ^"%s^" (Object) %d elements", key, iCount);
|
||||
|
||||
//Let's get its value by dot notation
|
||||
if (equal(key, "bool"))
|
||||
{
|
||||
//dotnot
|
||||
new bool:val1 = json_object_get_bool(object, "bool.true", true);
|
||||
new bool:val2 = json_object_get_bool(obj_value, "true");
|
||||
json_object_get_name(obj_value, 0, key, charsmax(key));
|
||||
|
||||
server_print(" Object Key ^"%s^" (Bool) dot %d | nodot: %d", key, val1, val2);
|
||||
}
|
||||
else
|
||||
DecodeObject(obj_value);
|
||||
}
|
||||
case JSONArray:
|
||||
{
|
||||
new iCount = json_array_get_count(obj_value);
|
||||
server_print(" Object Key ^"%s^" (Array) %d elements", key, iCount);
|
||||
|
||||
DecodeArray(obj_value);
|
||||
}
|
||||
case JSONBoolean:
|
||||
{
|
||||
new bool:val1 = json_get_bool(obj_value), bool:val2 = json_object_get_bool(object, key);
|
||||
server_print(" Object Key ^"%s^" (Bool) value %d | index %d", key, val1, val2);
|
||||
}
|
||||
}
|
||||
|
||||
json_free(obj_value);
|
||||
}
|
||||
}
|
||||
|
||||
GetTypeName(JSONType:type, buffer[], maxlen)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case JSONNull: copy(buffer, maxlen, "Null");
|
||||
case JSONString: copy(buffer, maxlen, "String");
|
||||
case JSONNumber: copy(buffer, maxlen, "Number");
|
||||
case JSONObject: copy(buffer, maxlen, "Object");
|
||||
case JSONArray: copy(buffer, maxlen, "Array");
|
||||
case JSONBoolean: copy(buffer, maxlen, "Boolean");
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user