mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Also move colorutil.cpp/h linking build fix experiment Delete a bunch of unused CMakeLists.txt files CMakeLists.txt linking fix Don't include NativeApp.h from any headers. Android.mk buildfix Half of the UWP fix Buildfix Minor project file cleanup Buildfixes Guess what? More buildfixes!
268 lines
7.3 KiB
C++
268 lines
7.3 KiB
C++
// Copyright (c) 2018- PPSSPP Project.
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, version 2.0 or later versions.
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License 2.0 for more details.
|
|
|
|
// A copy of the GPL 2.0 should have been included with the program.
|
|
// If not, see http://www.gnu.org/licenses/
|
|
|
|
// Official git repository and contact information can be found at
|
|
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
|
|
|
#include <cmath>
|
|
#include <limits>
|
|
#include "Common/Data/Text/Parsers.h"
|
|
#include "Common/StringUtils.h"
|
|
#include "Core/Debugger/WebSocket/WebSocketUtils.h"
|
|
|
|
JsonWriter &DebuggerRequest::Respond() {
|
|
writer_.begin();
|
|
writer_.writeString("event", name);
|
|
DebuggerJsonAddTicket(writer_, data);
|
|
|
|
responseBegun_ = true;
|
|
return writer_;
|
|
}
|
|
|
|
bool DebuggerRequest::Finish() {
|
|
if (responseBegun_ && !responseSent_) {
|
|
writer_.end();
|
|
if (responsePartial_)
|
|
ws->AddFragment(true, writer_.str());
|
|
else
|
|
ws->Send(writer_.str());
|
|
responseBegun_ = false;
|
|
responseSent_ = true;
|
|
responsePartial_ = false;
|
|
}
|
|
|
|
return responseSent_;
|
|
}
|
|
|
|
void DebuggerRequest::Flush() {
|
|
ws->AddFragment(false, writer_.flush());
|
|
responsePartial_ = true;
|
|
}
|
|
|
|
static bool U32FromString(const char *str, uint32_t *out, bool allowFloat) {
|
|
if (TryParse(str, out))
|
|
return true;
|
|
|
|
// Now let's try signed (the above parses only positive.)
|
|
if (str[0] == '-' && TryParse(&str[1], out)) {
|
|
*out = static_cast<uint32_t>(-static_cast<int>(*out));
|
|
return true;
|
|
}
|
|
|
|
// We have to try float last because we use float bits, so 1.0 != 1.
|
|
if (allowFloat) {
|
|
union {
|
|
uint32_t u;
|
|
float f;
|
|
} bits;
|
|
if (TryParse(str, &bits.f)) {
|
|
*out = bits.u;
|
|
return true;
|
|
}
|
|
|
|
if (!strcasecmp(str, "nan")) {
|
|
*out = 0x7FC00000;
|
|
return true;
|
|
} else if (!strcasecmp(str, "infinity") || !strcasecmp(str, "inf")) {
|
|
*out = 0x7F800000;
|
|
return true;
|
|
} else if (!strcasecmp(str, "-infinity") || !strcasecmp(str, "-inf")) {
|
|
*out = 0xFF800000;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool DebuggerRequest::HasParam(const char *name, bool ignoreNull) {
|
|
const JsonNode *node = data.get(name);
|
|
if (!node) {
|
|
return false;
|
|
}
|
|
if (node->value.getTag() == JSON_NULL) {
|
|
return !ignoreNull;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool DebuggerRequest::ParamU32(const char *name, uint32_t *out, bool allowFloatBits, DebuggerParamType type) {
|
|
bool allowLoose = type == DebuggerParamType::REQUIRED_LOOSE || type == DebuggerParamType::OPTIONAL_LOOSE;
|
|
bool required = type == DebuggerParamType::REQUIRED || type == DebuggerParamType::REQUIRED_LOOSE;
|
|
|
|
const JsonNode *node = data.get(name);
|
|
if (!node) {
|
|
if (required)
|
|
Fail(StringFromFormat("Missing '%s' parameter", name));
|
|
return !required;
|
|
}
|
|
|
|
auto tag = node->value.getTag();
|
|
if (tag == JSON_NUMBER) {
|
|
double val = node->value.toNumber();
|
|
bool isInteger = trunc(val) == val;
|
|
if (!isInteger && !allowLoose) {
|
|
// JSON doesn't give a great way to differentiate ints and floats.
|
|
// Let's play it safe and require a string.
|
|
if (allowFloatBits)
|
|
Fail(StringFromFormat("Could not parse '%s' parameter: use a string for non integer values", name));
|
|
else
|
|
Fail(StringFromFormat("Could not parse '%s' parameter: integer required", name));
|
|
return false;
|
|
} else if (!isInteger && allowFloatBits) {
|
|
union {
|
|
float f;
|
|
uint32_t u;
|
|
} bits = { (float)val };
|
|
*out = bits.u;
|
|
return true;
|
|
}
|
|
|
|
if (val < 0 && val >= std::numeric_limits<int32_t>::min()) {
|
|
// Convert to unsigned representation.
|
|
*out = (uint32_t)(int32_t)val;
|
|
return true;
|
|
} else if (val >= 0 && val <= std::numeric_limits<uint32_t>::max()) {
|
|
*out = (uint32_t)val;
|
|
return true;
|
|
} else if (allowLoose) {
|
|
*out = val >= 0 ? std::numeric_limits<uint32_t>::max() : std::numeric_limits<uint32_t>::min();
|
|
return true;
|
|
}
|
|
|
|
if (allowFloatBits)
|
|
Fail(StringFromFormat("Could not parse '%s' parameter: outside 32 bit range (use string for float)", name));
|
|
else
|
|
Fail(StringFromFormat("Could not parse '%s' parameter: outside 32 bit range", name));
|
|
return false;
|
|
}
|
|
if (tag != JSON_STRING) {
|
|
if (type == DebuggerParamType::REQUIRED || tag != JSON_NULL) {
|
|
Fail(StringFromFormat("Invalid '%s' parameter type", name));
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
if (U32FromString(node->value.toString(), out, allowFloatBits))
|
|
return true;
|
|
|
|
if (allowFloatBits)
|
|
Fail(StringFromFormat("Could not parse '%s' parameter: number expected", name));
|
|
else
|
|
Fail(StringFromFormat("Could not parse '%s' parameter: integer required", name));
|
|
return false;
|
|
}
|
|
|
|
bool DebuggerRequest::ParamBool(const char *name, bool *out, DebuggerParamType type) {
|
|
bool allowLoose = type == DebuggerParamType::REQUIRED_LOOSE || type == DebuggerParamType::OPTIONAL_LOOSE;
|
|
bool required = type == DebuggerParamType::REQUIRED || type == DebuggerParamType::REQUIRED_LOOSE;
|
|
|
|
const JsonNode *node = data.get(name);
|
|
if (!node) {
|
|
if (required)
|
|
Fail(StringFromFormat("Missing '%s' parameter", name));
|
|
return !required;
|
|
}
|
|
|
|
auto tag = node->value.getTag();
|
|
if (tag == JSON_NUMBER) {
|
|
double val = node->value.toNumber();
|
|
if (val == 1.0 || val == 0.0 || allowLoose) {
|
|
*out = val != 0.0;
|
|
return true;
|
|
}
|
|
|
|
Fail(StringFromFormat("Could not parse '%s' parameter: should be true/1 or false/0", name));
|
|
return false;
|
|
}
|
|
if (tag == JSON_TRUE) {
|
|
*out = true;
|
|
return true;
|
|
}
|
|
if (tag == JSON_FALSE) {
|
|
*out = false;
|
|
return true;
|
|
}
|
|
if (tag != JSON_STRING) {
|
|
if (type == DebuggerParamType::REQUIRED || tag != JSON_NULL) {
|
|
Fail(StringFromFormat("Invalid '%s' parameter type", name));
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
const std::string s = node->value.toString();
|
|
if (s == "1" || s == "true") {
|
|
*out = true;
|
|
return true;
|
|
}
|
|
if (s == "0" || s == "false" || (s == "" && allowLoose)) {
|
|
*out = false;
|
|
return true;
|
|
}
|
|
|
|
if (allowLoose) {
|
|
*out = true;
|
|
return true;
|
|
}
|
|
|
|
Fail(StringFromFormat("Could not parse '%s' parameter: boolean required", name));
|
|
return false;
|
|
}
|
|
|
|
bool DebuggerRequest::ParamString(const char *name, std::string *out, DebuggerParamType type) {
|
|
bool allowLoose = type == DebuggerParamType::REQUIRED_LOOSE || type == DebuggerParamType::OPTIONAL_LOOSE;
|
|
bool required = type == DebuggerParamType::REQUIRED || type == DebuggerParamType::REQUIRED_LOOSE;
|
|
|
|
const JsonNode *node = data.get(name);
|
|
if (!node) {
|
|
if (required)
|
|
Fail(StringFromFormat("Missing '%s' parameter", name));
|
|
return !required;
|
|
}
|
|
|
|
auto tag = node->value.getTag();
|
|
if (tag == JSON_STRING) {
|
|
*out = node->value.toString();
|
|
return true;
|
|
} else if (!allowLoose) {
|
|
if (required || tag != JSON_NULL) {
|
|
Fail(StringFromFormat("Invalid '%s' parameter type", name));
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// For loose, let's allow a few things.
|
|
if (tag == JSON_TRUE) {
|
|
*out = "true";
|
|
return true;
|
|
} else if (tag == JSON_FALSE) {
|
|
*out = "false";
|
|
return true;
|
|
} else if (tag == JSON_NULL) {
|
|
if (required) {
|
|
*out = "";
|
|
}
|
|
return true;
|
|
} else if (tag == JSON_NUMBER) {
|
|
// Will have a decimal place, though.
|
|
*out = StringFromFormat("%f", node->value.toNumber());
|
|
return true;
|
|
}
|
|
|
|
Fail(StringFromFormat("Invalid '%s' parameter type", name));
|
|
return false;
|
|
}
|