Skip to content

Commit

Permalink
Replace json decoder with json-c library
Browse files Browse the repository at this point in the history
Summary: The license of the current json decoder used in the ext_json library
presents ackaging issues for debian, replace the library with the
MIT licensed json-c library. The integration code here is a port of
the PECL jsonc extension by Remi Collet.

There is one main outstanding issues:

* There are a few facebook specific changes to the json decoder to
  implement an FB_LOOSE flag allowing json like '{z:1}' to be valid,
  this has not been reimplemented.

There are probably a variety of smaller issues as well, the patch mearly
appears to work in some circumstances and still needs careful review.
Closes #2612

Reviewed By: @JoelMarcey

Differential Revision: D1316200

Pulled By: @ptarjan
  • Loading branch information
ebernhardson authored and JoelMarcey committed May 13, 2014
1 parent 008a17b commit 04fd889
Show file tree
Hide file tree
Showing 7 changed files with 362 additions and 31 deletions.
25 changes: 25 additions & 0 deletions CMake/FindLibjsonc.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Find libjsonc
#
# LIBJSONC_INCLUDE_DIR
# LIBJSONC_LIBRARY

IF (LIBJSONC_INCLUDE_DIR)
# Already in cache, be silent
SET(LIBJSONC_FIND_QUIETLY TRUE)
ENDIF (LIBJSONC_INCLUDE_DIR)

FIND_PATH(LIBJSONC_INCLUDE_DIR json/json.h json-c/json.h)
FIND_LIBRARY(LIBJSONC_LIBRARY json json-c)

if (LIBJSONC_LIBRARY)
add_definitions(-DHAVE_JSONC)
endif()

IF (EXISTS ${LIBJSONC_INCLUDE_DIR}/json-c/json.h)
add_definitions(-DJSONC_INCLUDE_WITH_C)
endif()

INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBJSONC DEFAULT_MSG LIBJSONC_LIBRARY LIBJSONC_INCLUDE_DIR)

MARK_AS_ADVANCED(LIBJSONC_LIBRARY LIBJSONC_INCLUDE_DIR)
8 changes: 8 additions & 0 deletions CMake/HPHPFindLibs.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ if (LIBINOTIFY_INCLUDE_DIR)
include_directories(${LIBINOTIFY_INCLUDE_DIR})
endif()

find_package(Libjsonc)
if (LIBJSONC_INCLUDE_DIR)
include_directories(${LIBJSONC_INCLUDE_DIR})
endif()

# iconv checks
find_package(Libiconv REQUIRED)
include_directories(${LIBICONV_INCLUDE_DIR})
Expand Down Expand Up @@ -403,6 +408,9 @@ macro(hphp_link target)
target_link_libraries(${target} ${LIBEVENT_LIB})
target_link_libraries(${target} ${CURL_LIBRARIES})
target_link_libraries(${target} ${LIBGLOG_LIBRARY})
if (LIBJSONC_LIBRARY)
target_link_libraries(${target} ${LIBJSONC_LIBRARY})
endif()

if (LibXed_LIBRARY)
target_link_libraries(${target} ${LibXed_LIBRARY})
Expand Down
5 changes: 5 additions & 0 deletions hphp/runtime/ext/json/JSON_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

// If we have json-c then don't use this library since that one has a more
// permissive licence
#ifndef HAVE_JSONC

#include "hphp/runtime/ext/json/JSON_parser.h"
#include <vector>
Expand Down Expand Up @@ -955,3 +958,5 @@ bool JSON_parser(Variant &z, const char *p, int length, bool const assoc,
}

}

#endif /* HAVE_JSONC */
3 changes: 3 additions & 0 deletions hphp/runtime/ext/json/JSON_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ enum json_error_codes {
JSON_ERROR_CTRL_CHAR,
JSON_ERROR_SYNTAX,
JSON_ERROR_UTF8,
JSON_ERROR_RECURSION,
JSON_ERROR_INF_OR_NAN,
JSON_ERROR_UNSUPPORTED_TYPE
};

json_error_codes json_get_last_error_code();
Expand Down
87 changes: 56 additions & 31 deletions hphp/runtime/ext/json/ext_json.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,16 @@ namespace HPHP {

///////////////////////////////////////////////////////////////////////////////
// json_encode() options
const int64_t k_JSON_HEX_TAG = 1<<0;
const int64_t k_JSON_HEX_AMP = 1<<1;
const int64_t k_JSON_HEX_APOS = 1<<2;
const int64_t k_JSON_HEX_QUOT = 1<<3;
const int64_t k_JSON_FORCE_OBJECT = 1<<4;
const int64_t k_JSON_NUMERIC_CHECK = 1<<5;
const int64_t k_JSON_UNESCAPED_SLASHES = 1<<6;
const int64_t k_JSON_PRETTY_PRINT = 1<<7;
const int64_t k_JSON_UNESCAPED_UNICODE = 1<<8;
const int64_t k_JSON_HEX_TAG = 1<<0;
const int64_t k_JSON_HEX_AMP = 1<<1;
const int64_t k_JSON_HEX_APOS = 1<<2;
const int64_t k_JSON_HEX_QUOT = 1<<3;
const int64_t k_JSON_FORCE_OBJECT = 1<<4;
const int64_t k_JSON_NUMERIC_CHECK = 1<<5;
const int64_t k_JSON_UNESCAPED_SLASHES = 1<<6;
const int64_t k_JSON_PRETTY_PRINT = 1<<7;
const int64_t k_JSON_UNESCAPED_UNICODE = 1<<8;
const int64_t k_JSON_PARTIAL_OUTPUT_ON_ERROR = 1<<9;

// json_decode() options
const int64_t k_JSON_BIGINT_AS_STRING = 1<<0;
Expand All @@ -57,6 +58,12 @@ const int64_t k_JSON_ERROR_SYNTAX
= json_error_codes::JSON_ERROR_SYNTAX;
const int64_t k_JSON_ERROR_UTF8
= json_error_codes::JSON_ERROR_UTF8;
const int64_t k_JSON_ERROR_RECURSION
= json_error_codes::JSON_ERROR_RECURSION;
const int64_t k_JSON_ERROR_INF_OR_NAN
= json_error_codes::JSON_ERROR_INF_OR_NAN;
const int64_t k_JSON_ERROR_UNSUPPORTED_TYPE
= json_error_codes::JSON_ERROR_UNSUPPORTED_TYPE;

///////////////////////////////////////////////////////////////////////////////
int64_t HHVM_FUNCTION(json_last_error) {
Expand All @@ -67,7 +74,8 @@ String HHVM_FUNCTION(json_last_error_msg) {
return json_get_last_error_msg();
}

String HHVM_FUNCTION(json_encode, const Variant& value, int64_t options /* = 0 */,
String HHVM_FUNCTION(json_encode, const Variant& value,
int64_t options /* = 0 */,
int64_t depth /* = 512 */) {

json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);
Expand Down Expand Up @@ -155,27 +163,32 @@ Variant HHVM_FUNCTION(json_decode, const String& json, bool assoc /* = false */,

///////////////////////////////////////////////////////////////////////////////

const StaticString s_JSON_HEX_TAG("JSON_HEX_TAG");
const StaticString s_JSON_HEX_AMP("JSON_HEX_AMP");
const StaticString s_JSON_HEX_APOS("JSON_HEX_APOS");
const StaticString s_JSON_HEX_QUOT("JSON_HEX_QUOT");
const StaticString s_JSON_FORCE_OBJECT("JSON_FORCE_OBJECT");
const StaticString s_JSON_NUMERIC_CHECK("JSON_NUMERIC_CHECK");
const StaticString s_JSON_UNESCAPED_SLASHES("JSON_UNESCAPED_SLASHES");
const StaticString s_JSON_PRETTY_PRINT("JSON_PRETTY_PRINT");
const StaticString s_JSON_UNESCAPED_UNICODE("JSON_UNESCAPED_UNICODE");
const StaticString s_JSON_BIGINT_AS_STRING("JSON_BIGINT_AS_STRING");
const StaticString s_JSON_FB_LOOSE("JSON_FB_LOOSE");
const StaticString s_JSON_FB_UNLIMITED("JSON_FB_UNLIMITED");
const StaticString s_JSON_FB_EXTRA_ESCAPES("JSON_FB_EXTRA_ESCAPES");
const StaticString s_JSON_FB_COLLECTIONS("JSON_FB_COLLECTIONS");
const StaticString s_JSON_FB_STABLE_MAPS("JSON_FB_STABLE_MAPS");
const StaticString s_JSON_ERROR_NONE("JSON_ERROR_NONE");
const StaticString s_JSON_ERROR_DEPTH("JSON_ERROR_DEPTH");
const StaticString s_JSON_ERROR_STATE_MISMATCH("JSON_ERROR_STATE_MISMATCH");
const StaticString s_JSON_ERROR_CTRL_CHAR("JSON_ERROR_CTRL_CHAR");
const StaticString s_JSON_ERROR_SYNTAX("JSON_ERROR_SYNTAX");
const StaticString s_JSON_ERROR_UTF8("JSON_ERROR_UTF8");
const StaticString
s_JSON_HEX_TAG("JSON_HEX_TAG"),
s_JSON_HEX_AMP("JSON_HEX_AMP"),
s_JSON_HEX_APOS("JSON_HEX_APOS"),
s_JSON_HEX_QUOT("JSON_HEX_QUOT"),
s_JSON_FORCE_OBJECT("JSON_FORCE_OBJECT"),
s_JSON_NUMERIC_CHECK("JSON_NUMERIC_CHECK"),
s_JSON_UNESCAPED_SLASHES("JSON_UNESCAPED_SLASHES"),
s_JSON_PRETTY_PRINT("JSON_PRETTY_PRINT"),
s_JSON_UNESCAPED_UNICODE("JSON_UNESCAPED_UNICODE"),
s_JSON_PARTIAL_OUTPUT_ON_ERROR("JSON_PARTIAL_OUTPUT_ON_ERROR"),
s_JSON_BIGINT_AS_STRING("JSON_BIGINT_AS_STRING"),
s_JSON_FB_LOOSE("JSON_FB_LOOSE"),
s_JSON_FB_UNLIMITED("JSON_FB_UNLIMITED"),
s_JSON_FB_EXTRA_ESCAPES("JSON_FB_EXTRA_ESCAPES"),
s_JSON_FB_COLLECTIONS("JSON_FB_COLLECTIONS"),
s_JSON_FB_STABLE_MAPS("JSON_FB_STABLE_MAPS"),
s_JSON_ERROR_NONE("JSON_ERROR_NONE"),
s_JSON_ERROR_DEPTH("JSON_ERROR_DEPTH"),
s_JSON_ERROR_STATE_MISMATCH("JSON_ERROR_STATE_MISMATCH"),
s_JSON_ERROR_CTRL_CHAR("JSON_ERROR_CTRL_CHAR"),
s_JSON_ERROR_SYNTAX("JSON_ERROR_SYNTAX"),
s_JSON_ERROR_UTF8("JSON_ERROR_UTF8"),
s_JSON_ERROR_RECURSION("JSON_ERROR_RECURSION"),
s_JSON_ERROR_INF_OR_NAN("JSON_ERROR_INF_OR_NAN"),
s_JSON_ERROR_UNSUPPORTED_TYPE("JSON_ERROR_UNSUPPORTED_TYPE");

class JsonExtension : public Extension {
public:
Expand Down Expand Up @@ -208,6 +221,9 @@ class JsonExtension : public Extension {
Native::registerConstant<KindOfInt64>(
s_JSON_UNESCAPED_UNICODE.get(), k_JSON_UNESCAPED_UNICODE
);
Native::registerConstant<KindOfInt64>(
s_JSON_PARTIAL_OUTPUT_ON_ERROR.get(), k_JSON_PARTIAL_OUTPUT_ON_ERROR
);
Native::registerConstant<KindOfInt64>(
s_JSON_BIGINT_AS_STRING.get(), k_JSON_BIGINT_AS_STRING
);
Expand Down Expand Up @@ -244,6 +260,15 @@ class JsonExtension : public Extension {
Native::registerConstant<KindOfInt64>(
s_JSON_ERROR_UTF8.get(), k_JSON_ERROR_UTF8
);
Native::registerConstant<KindOfInt64>(
s_JSON_ERROR_RECURSION.get(), k_JSON_ERROR_RECURSION
);
Native::registerConstant<KindOfInt64>(
s_JSON_ERROR_INF_OR_NAN.get(), k_JSON_ERROR_INF_OR_NAN
);
Native::registerConstant<KindOfInt64>(
s_JSON_ERROR_UNSUPPORTED_TYPE.get(), k_JSON_ERROR_UNSUPPORTED_TYPE
);

HHVM_FE(json_last_error);
HHVM_FE(json_last_error_msg);
Expand Down
1 change: 1 addition & 0 deletions hphp/runtime/ext/json/ext_json.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ extern const int64_t k_JSON_NUMERIC_CHECK;
extern const int64_t k_JSON_UNESCAPED_SLASHES;
extern const int64_t k_JSON_PRETTY_PRINT;
extern const int64_t k_JSON_UNESCAPED_UNICODE;
extern const int64_t k_JSON_PARTIAL_OUTPUT_ON_ERROR;
extern const int64_t k_JSON_FB_LOOSE;
extern const int64_t k_JSON_FB_EXTRA_ESCAPES;
extern const int64_t k_JSON_FB_UNLIMITED;
Expand Down
Loading

0 comments on commit 04fd889

Please sign in to comment.