UI: Remove jansson requirement from UI and updater

Use json11 instead.
master
jp9000 2020-12-09 22:21:34 -08:00
parent 9cc5aa5629
commit a01d3e77b1
6 changed files with 95 additions and 168 deletions

View File

@ -81,7 +81,6 @@ include_directories(${LIBCURL_INCLUDE_DIRS})
add_definitions(${LIBCURL_DEFINITIONS}) add_definitions(${LIBCURL_DEFINITIONS})
if(WIN32) if(WIN32)
include_directories(${OBS_JANSSON_INCLUDE_DIRS})
include_directories(${BLAKE2_INCLUDE_DIR}) include_directories(${BLAKE2_INCLUDE_DIR})
set(obs_PLATFORM_SOURCES set(obs_PLATFORM_SOURCES
@ -96,8 +95,7 @@ if(WIN32)
win-update/win-update-helpers.hpp) win-update/win-update-helpers.hpp)
set(obs_PLATFORM_LIBRARIES set(obs_PLATFORM_LIBRARIES
crypt32 crypt32
blake2 blake2)
${OBS_JANSSON_IMPORT})
if(CMAKE_SIZEOF_VOID_P EQUAL 4) if(CMAKE_SIZEOF_VOID_P EQUAL 4)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /LARGEADDRESSAWARE") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /LARGEADDRESSAWARE")

View File

@ -9,17 +9,19 @@ endif()
project(updater) project(updater)
include_directories(${OBS_JANSSON_INCLUDE_DIRS})
include_directories(${LIBLZMA_INCLUDE_DIRS}) include_directories(${LIBLZMA_INCLUDE_DIRS})
include_directories(SYSTEM "${CMAKE_SOURCE_DIR}/deps/json11")
include_directories(SYSTEM "${CMAKE_SOURCE_DIR}/libobs") include_directories(SYSTEM "${CMAKE_SOURCE_DIR}/libobs")
include_directories(${BLAKE2_INCLUDE_DIR}) include_directories(${BLAKE2_INCLUDE_DIR})
set(updater_HEADERS set(updater_HEADERS
${CMAKE_SOURCE_DIR}/deps/json11/json11.hpp
../win-update-helpers.hpp ../win-update-helpers.hpp
resource.h resource.h
updater.hpp updater.hpp
) )
set(updater_SOURCES set(updater_SOURCES
${CMAKE_SOURCE_DIR}/deps/json11/json11.cpp
../win-update-helpers.cpp ../win-update-helpers.cpp
init-hook-files.c init-hook-files.c
updater.cpp updater.cpp
@ -40,7 +42,6 @@ add_executable(updater WIN32
${updater_SOURCES} ${updater_SOURCES}
) )
target_link_libraries(updater target_link_libraries(updater
${OBS_JANSSON_IMPORT}
${STATIC_ZLIB_PATH} ${STATIC_ZLIB_PATH}
lzma lzma
blake2 blake2

View File

@ -26,6 +26,7 @@
#include <mutex> #include <mutex>
using namespace std; using namespace std;
using namespace json11;
/* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */
@ -603,68 +604,63 @@ static inline bool is_64bit_file(const char *file)
strstr(file, "64.exe") != nullptr; strstr(file, "64.exe") != nullptr;
} }
static inline bool has_str(const char *file, const char *str)
{
return (file && str) ? (strstr(file, str) != nullptr) : false;
}
#define UTF8ToWideBuf(wide, utf8) UTF8ToWide(wide, _countof(wide), utf8) #define UTF8ToWideBuf(wide, utf8) UTF8ToWide(wide, _countof(wide), utf8)
#define WideToUTF8Buf(utf8, wide) WideToUTF8(utf8, _countof(utf8), wide) #define WideToUTF8Buf(utf8, wide) WideToUTF8(utf8, _countof(utf8), wide)
#define UPDATE_URL L"https://cdn-fastly.obsproject.com/update_studio" #define UPDATE_URL L"https://cdn-fastly.obsproject.com/update_studio"
static bool AddPackageUpdateFiles(json_t *root, size_t idx, static bool AddPackageUpdateFiles(const Json &root, size_t idx,
const wchar_t *tempPath) const wchar_t *tempPath)
{ {
json_t *package = json_array_get(root, idx); const Json &package = root[idx];
json_t *name = json_object_get(package, "name"); const Json &name = package["name"];
json_t *files = json_object_get(package, "files"); const Json &files = package["files"];
bool isWin64 = is_64bit_windows(); bool isWin64 = is_64bit_windows();
if (!json_is_array(files)) if (!files.is_array())
return true; return true;
if (!json_is_string(name)) if (!name.is_string())
return true; return true;
wchar_t wPackageName[512]; wchar_t wPackageName[512];
const char *packageName = json_string_value(name); const string &packageName = name.string_value();
size_t fileCount = json_array_size(files); size_t fileCount = files.array_items().size();
if (!UTF8ToWideBuf(wPackageName, packageName)) if (!UTF8ToWideBuf(wPackageName, packageName.c_str()))
return false; return false;
if (strcmp(packageName, "core") != 0 && if (packageName != "core" &&
!NonCorePackageInstalled(packageName)) !NonCorePackageInstalled(packageName.c_str()))
return true; return true;
for (size_t j = 0; j < fileCount; j++) { for (size_t j = 0; j < fileCount; j++) {
json_t *file = json_array_get(files, j); const Json &file = files[j];
json_t *fileName = json_object_get(file, "name"); const Json &fileName = file["name"];
json_t *hash = json_object_get(file, "hash"); const Json &hash = file["hash"];
json_t *size = json_object_get(file, "size"); const Json &size = file["size"];
if (!json_is_string(fileName)) if (!fileName.is_string())
continue; continue;
if (!json_is_string(hash)) if (!hash.is_string())
continue; continue;
if (!json_is_integer(size)) if (!size.is_number())
continue; continue;
const char *fileUTF8 = json_string_value(fileName); const string &fileUTF8 = fileName.string_value();
const char *hashUTF8 = json_string_value(hash); const string &hashUTF8 = hash.string_value();
int fileSize = (int)json_integer_value(size); int fileSize = size.int_value();
if (strlen(hashUTF8) != BLAKE2_HASH_LENGTH * 2) if (hashUTF8.size() != BLAKE2_HASH_LENGTH * 2)
continue; continue;
if (!isWin64 && is_64bit_file(fileUTF8)) if (!isWin64 && is_64bit_file(fileUTF8.c_str()))
continue; continue;
/* ignore update files of opposite arch to reduce download */ /* ignore update files of opposite arch to reduce download */
if ((is32bit && has_str(fileUTF8, "/64bit/")) || if ((is32bit && fileUTF8.find("/64bit/") != string::npos) ||
(!is32bit && has_str(fileUTF8, "/32bit/"))) (!is32bit && fileUTF8.find("/32bit/") != string::npos))
continue; continue;
/* convert strings to wide */ /* convert strings to wide */
@ -674,9 +670,9 @@ static bool AddPackageUpdateFiles(json_t *root, size_t idx,
wchar_t updateHashStr[BLAKE2_HASH_STR_LENGTH]; wchar_t updateHashStr[BLAKE2_HASH_STR_LENGTH];
wchar_t tempFilePath[MAX_PATH]; wchar_t tempFilePath[MAX_PATH];
if (!UTF8ToWideBuf(updateFileName, fileUTF8)) if (!UTF8ToWideBuf(updateFileName, fileUTF8.c_str()))
continue; continue;
if (!UTF8ToWideBuf(updateHashStr, hashUTF8)) if (!UTF8ToWideBuf(updateHashStr, hashUTF8.c_str()))
continue; continue;
/* make sure paths are safe */ /* make sure paths are safe */
@ -928,7 +924,7 @@ static wchar_t tempPath[MAX_PATH] = {};
L"https://obsproject.com/update_studio/getpatchmanifest" L"https://obsproject.com/update_studio/getpatchmanifest"
#define HASH_NULL L"0000000000000000000000000000000000000000" #define HASH_NULL L"0000000000000000000000000000000000000000"
static bool UpdateVS2019Redists(json_t *root) static bool UpdateVS2019Redists(const Json &root)
{ {
/* ------------------------------------------ * /* ------------------------------------------ *
* Initialize session */ * Initialize session */
@ -992,18 +988,18 @@ static bool UpdateVS2019Redists(json_t *root)
/* ------------------------------------------ * /* ------------------------------------------ *
* Get expected hash */ * Get expected hash */
json_t *redistJson = json_object_get( const char *which = is32bit ? "vc2019_redist_x86" : "vc2019_redist_x64";
root, is32bit ? "vc2019_redist_x86" : "vc2019_redist_x64"); const Json &redistJson = root[which];
if (!redistJson) { if (!redistJson.is_string()) {
Status(L"Update failed: Could not parse VC2019 redist json"); Status(L"Update failed: Could not parse VC2019 redist json");
return false; return false;
} }
const char *expectedHashUTF8 = json_string_value(redistJson); const string &expectedHashUTF8 = redistJson.string_value();
wchar_t expectedHashWide[BLAKE2_HASH_STR_LENGTH]; wchar_t expectedHashWide[BLAKE2_HASH_STR_LENGTH];
BYTE expectedHash[BLAKE2_HASH_LENGTH]; BYTE expectedHash[BLAKE2_HASH_LENGTH];
if (!UTF8ToWideBuf(expectedHashWide, expectedHashUTF8)) { if (!UTF8ToWideBuf(expectedHashWide, expectedHashUTF8.c_str())) {
DeleteFile(destPath.c_str()); DeleteFile(destPath.c_str());
Status(L"Update failed: Couldn't convert Json for redist hash"); Status(L"Update failed: Couldn't convert Json for redist hash");
return false; return false;
@ -1218,18 +1214,18 @@ static bool Update(wchar_t *cmdLine)
return false; return false;
} }
json_error_t error; string error;
root = json_loads(manifestFile.c_str(), 0, &error); root = Json::parse(manifestFile, error);
if (!root) { if (!error.empty()) {
Status(L"Update failed: Couldn't parse update " Status(L"Update failed: Couldn't parse update "
L"manifest: %S", L"manifest: %S",
error.text); error.c_str());
return false; return false;
} }
} }
if (!json_is_object(root.get())) { if (!root.is_object()) {
Status(L"Update failed: Invalid update manifest"); Status(L"Update failed: Invalid update manifest");
return false; return false;
} }
@ -1237,10 +1233,8 @@ static bool Update(wchar_t *cmdLine)
/* ------------------------------------- * /* ------------------------------------- *
* Parse current manifest update files */ * Parse current manifest update files */
json_t *packages = json_object_get(root, "packages"); const Json::array &packages = root["packages"].array_items();
size_t packageCount = json_array_size(packages); for (size_t i = 0; i < packages.size(); i++) {
for (size_t i = 0; i < packageCount; i++) {
if (!AddPackageUpdateFiles(packages, i, tempPath)) { if (!AddPackageUpdateFiles(packages, i, tempPath)) {
Status(L"Update failed: Failed to process update packages"); Status(L"Update failed: Failed to process update packages");
return false; return false;
@ -1271,7 +1265,7 @@ static bool Update(wchar_t *cmdLine)
/* ------------------------------------- * /* ------------------------------------- *
* Generate file hash json */ * Generate file hash json */
Json files(json_array()); Json::array files;
for (update_t &update : updates) { for (update_t &update : updates) {
wchar_t whash_string[BLAKE2_HASH_STR_LENGTH]; wchar_t whash_string[BLAKE2_HASH_STR_LENGTH];
@ -1296,10 +1290,10 @@ static bool Update(wchar_t *cmdLine)
package_path += "/"; package_path += "/";
package_path += outputPath; package_path += outputPath;
json_t *obj = json_object(); files.emplace_back(Json::object{
json_object_set(obj, "name", json_string(package_path.c_str())); {"name", package_path},
json_object_set(obj, "hash", json_string(hash_string)); {"hash", hash_string},
json_array_append_new(files, obj); });
} }
/* ------------------------------------- * /* ------------------------------------- *
@ -1307,18 +1301,20 @@ static bool Update(wchar_t *cmdLine)
string newManifest; string newManifest;
if (json_array_size(files) > 0) { if (files.size() > 0) {
char *post_body = json_dumps(files, JSON_COMPACT); string post_body;
Json(files).dump(post_body);
int responseCode; int responseCode;
int len = (int)strlen(post_body); int len = (int)post_body.size();
uLong compressSize = compressBound(len); uLong compressSize = compressBound(len);
string compressedJson; string compressedJson;
compressedJson.resize(compressSize); compressedJson.resize(compressSize);
compress2((Bytef *)&compressedJson[0], &compressSize, compress2((Bytef *)&compressedJson[0], &compressSize,
(const Bytef *)post_body, len, Z_BEST_COMPRESSION); (const Bytef *)post_body.c_str(), len,
Z_BEST_COMPRESSION);
compressedJson.resize(compressSize); compressedJson.resize(compressSize);
bool success = !!HTTPPostData(PATCH_MANIFEST_URL, bool success = !!HTTPPostData(PATCH_MANIFEST_URL,
@ -1326,7 +1322,6 @@ static bool Update(wchar_t *cmdLine)
(int)compressedJson.size(), (int)compressedJson.size(),
L"Accept-Encoding: gzip", L"Accept-Encoding: gzip",
&responseCode, newManifest); &responseCode, newManifest);
free(post_body);
if (!success) if (!success)
return false; return false;
@ -1344,49 +1339,50 @@ static bool Update(wchar_t *cmdLine)
/* ------------------------------------- * /* ------------------------------------- *
* Parse new manifest */ * Parse new manifest */
json_error_t error; string error;
root = json_loads(newManifest.c_str(), 0, &error); root = Json::parse(newManifest, error);
if (!root) { if (!error.empty()) {
Status(L"Update failed: Couldn't parse patch manifest: %S", Status(L"Update failed: Couldn't parse patch manifest: %S",
error.text); error.c_str());
return false; return false;
} }
if (!json_is_array(root.get())) { if (!root.is_array()) {
Status(L"Update failed: Invalid patch manifest"); Status(L"Update failed: Invalid patch manifest");
return false; return false;
} }
packageCount = json_array_size(root); size_t packageCount = root.array_items().size();
for (size_t i = 0; i < packageCount; i++) { for (size_t i = 0; i < packageCount; i++) {
json_t *patch = json_array_get(root, i); const Json &patch = root[i];
if (!json_is_object(patch)) { if (!patch.is_object()) {
Status(L"Update failed: Invalid patch manifest"); Status(L"Update failed: Invalid patch manifest");
return false; return false;
} }
json_t *name_json = json_object_get(patch, "name"); const Json &name_json = patch["name"];
json_t *hash_json = json_object_get(patch, "hash"); const Json &hash_json = patch["hash"];
json_t *source_json = json_object_get(patch, "source"); const Json &source_json = patch["source"];
json_t *size_json = json_object_get(patch, "size"); const Json &size_json = patch["size"];
if (!json_is_string(name_json)) if (!name_json.is_string())
continue; continue;
if (!json_is_string(hash_json)) if (!hash_json.is_string())
continue; continue;
if (!json_is_string(source_json)) if (!source_json.is_string())
continue; continue;
if (!json_is_integer(size_json)) if (!size_json.is_number())
continue; continue;
const char *name = json_string_value(name_json); const string &name = name_json.string_value();
const char *hash = json_string_value(hash_json); const string &hash = hash_json.string_value();
const char *source = json_string_value(source_json); const string &source = source_json.string_value();
int size = (int)json_integer_value(size_json); int size = size_json.int_value();
UpdateWithPatchIfAvailable(name, hash, source, size); UpdateWithPatchIfAvailable(name.c_str(), hash.c_str(),
source.c_str(), size);
} }
/* ------------------------------------- * /* ------------------------------------- *

View File

@ -74,7 +74,7 @@
#endif #endif
#include <util/windows/WinHandle.hpp> #include <util/windows/WinHandle.hpp>
#include <jansson.h> #include <json11.hpp>
#include "resource.h" #include "resource.h"
bool HTTPGetFile(HINTERNET hConnect, const wchar_t *url, bool HTTPGetFile(HINTERNET hConnect, const wchar_t *url,

View File

@ -4,8 +4,6 @@
#include <windows.h> #include <windows.h>
#include <Wincrypt.h> #include <Wincrypt.h>
#include <jansson.h>
#include <cstdint> #include <cstdint>
#include <string> #include <string>
@ -69,72 +67,5 @@ public:
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
class Json {
json_t *json;
public:
inline Json() : json(nullptr) {}
explicit inline Json(json_t *json_) : json(json_) {}
inline Json(const Json &from) : json(json_incref(from.json)) {}
inline Json(Json &&from) : json(from.json) { from.json = nullptr; }
inline ~Json()
{
if (json)
json_decref(json);
}
inline Json &operator=(json_t *json_)
{
if (json)
json_decref(json);
json = json_;
return *this;
}
inline Json &operator=(const Json &from)
{
if (json)
json_decref(json);
json = json_incref(from.json);
return *this;
}
inline Json &operator=(Json &&from)
{
if (json)
json_decref(json);
json = from.json;
from.json = nullptr;
return *this;
}
inline operator json_t *() const { return json; }
inline bool operator!() const { return !json; }
inline const char *GetString(const char *name,
const char *def = nullptr) const
{
json_t *obj(json_object_get(json, name));
if (!obj)
return def;
return json_string_value(obj);
}
inline int64_t GetInt(const char *name, int def = 0) const
{
json_t *obj(json_object_get(json, name));
if (!obj)
return def;
return json_integer_value(obj);
}
inline json_t *GetObject(const char *name) const
{
return json_object_get(json, name);
}
inline json_t *get() const { return json; }
};
/* ------------------------------------------------------------------------ */
std::string vstrprintf(const char *format, va_list args); std::string vstrprintf(const char *format, va_list args);
std::string strprintf(const char *format, ...); std::string strprintf(const char *format, ...);

View File

@ -12,7 +12,7 @@
#include <util/windows/WinHandle.hpp> #include <util/windows/WinHandle.hpp>
#include <util/util.hpp> #include <util/util.hpp>
#include <jansson.h> #include <json11.hpp>
#include <blake2.h> #include <blake2.h>
#include <time.h> #include <time.h>
@ -25,6 +25,7 @@
#endif #endif
using namespace std; using namespace std;
using namespace json11;
struct QCef; struct QCef;
extern QCef *cef; extern QCef *cef;
@ -402,31 +403,31 @@ static bool ParseUpdateManifest(const char *manifest, bool *updatesAvailable,
string &notes_str, int &updateVer) string &notes_str, int &updateVer)
try { try {
json_error_t error; string error;
Json root(json_loads(manifest, 0, &error)); Json root = Json::parse(manifest, error);
if (!root) if (!error.empty())
throw strprintf("Failed reading json string (%d): %s", throw strprintf("Failed reading json string: %s",
error.line, error.text); error.c_str());
if (!json_is_object(root.get())) if (!root.is_object())
throw string("Root of manifest is not an object"); throw string("Root of manifest is not an object");
int major = root.GetInt("version_major"); int major = root["version_major"].int_value();
int minor = root.GetInt("version_minor"); int minor = root["version_minor"].int_value();
int patch = root.GetInt("version_patch"); int patch = root["version_patch"].int_value();
if (major == 0) if (major == 0)
throw strprintf("Invalid version number: %d.%d.%d", major, throw strprintf("Invalid version number: %d.%d.%d", major,
minor, patch); minor, patch);
json_t *notes = json_object_get(root, "notes"); const Json &notes = root["notes"];
if (!json_is_string(notes)) if (!notes.is_string())
throw string("'notes' value invalid"); throw string("'notes' value invalid");
notes_str = json_string_value(notes); notes_str = notes.string_value();
json_t *packages = json_object_get(root, "packages"); const Json &packages = root["packages"];
if (!json_is_array(packages)) if (!packages.is_array())
throw string("'packages' value invalid"); throw string("'packages' value invalid");
int cur_ver = LIBOBS_API_VER; int cur_ver = LIBOBS_API_VER;