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