CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/Core/Debugger/WebSocket/WebSocketUtils.cpp
Views: 1401
// Copyright (c) 2018- PPSSPP Project.12// This program is free software: you can redistribute it and/or modify3// it under the terms of the GNU General Public License as published by4// the Free Software Foundation, version 2.0 or later versions.56// This program is distributed in the hope that it will be useful,7// but WITHOUT ANY WARRANTY; without even the implied warranty of8// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the9// GNU General Public License 2.0 for more details.1011// A copy of the GPL 2.0 should have been included with the program.12// If not, see http://www.gnu.org/licenses/1314// Official git repository and contact information can be found at15// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.1617#include <cmath>18#include <limits>1920#include "Common/Data/Text/Parsers.h"21#include "Common/StringUtils.h"22#include "Core/Debugger/WebSocket/WebSocketUtils.h"23#include "Core/MemMap.h"2425inline void DebuggerJsonAddTicket(JsonWriter &writer, const JsonGet &data) {26const JsonNode *value = data.get("ticket");27if (value)28writer.writeRaw("ticket", json_stringify(value));29}3031JsonWriter &DebuggerRequest::Respond() {32writer_.begin();33writer_.writeString("event", name);34DebuggerJsonAddTicket(writer_, data);3536responseBegun_ = true;37return writer_;38}3940bool DebuggerRequest::Finish() {41if (responseBegun_ && !responseSent_) {42writer_.end();43if (responsePartial_)44ws->AddFragment(true, writer_.str());45else46ws->Send(writer_.str());47responseBegun_ = false;48responseSent_ = true;49responsePartial_ = false;50}5152return responseSent_;53}5455void DebuggerRequest::Flush() {56ws->AddFragment(false, writer_.flush());57responsePartial_ = true;58}5960static bool U32FromString(const char *str, uint32_t *out, bool allowFloat) {61if (TryParse(str, out))62return true;6364// Now let's try signed (the above parses only positive.)65if (str[0] == '-' && TryParse(&str[1], out)) {66*out = static_cast<uint32_t>(-static_cast<int>(*out));67return true;68}6970// We have to try float last because we use float bits, so 1.0 != 1.71if (allowFloat) {72union {73uint32_t u;74float f;75} bits;76if (TryParse(str, &bits.f)) {77*out = bits.u;78return true;79}8081if (!strcasecmp(str, "nan")) {82*out = 0x7FC00000;83return true;84} else if (!strcasecmp(str, "infinity") || !strcasecmp(str, "inf")) {85*out = 0x7F800000;86return true;87} else if (!strcasecmp(str, "-infinity") || !strcasecmp(str, "-inf")) {88*out = 0xFF800000;89return true;90}91}9293return false;94}9596bool DebuggerRequest::HasParam(const char *name, bool ignoreNull) {97const JsonNode *node = data.get(name);98if (!node) {99return false;100}101if (node->value.getTag() == JSON_NULL) {102return !ignoreNull;103}104return true;105}106107bool DebuggerRequest::ParamU32(const char *name, uint32_t *out, bool allowFloatBits, DebuggerParamType type) {108bool allowLoose = type == DebuggerParamType::REQUIRED_LOOSE || type == DebuggerParamType::OPTIONAL_LOOSE;109bool required = type == DebuggerParamType::REQUIRED || type == DebuggerParamType::REQUIRED_LOOSE;110111const JsonNode *node = data.get(name);112if (!node) {113if (required)114Fail(StringFromFormat("Missing '%s' parameter", name));115return !required;116}117118auto tag = node->value.getTag();119if (tag == JSON_NUMBER) {120double val = node->value.toNumber();121bool isInteger = trunc(val) == val;122if (!isInteger && !allowLoose) {123// JSON doesn't give a great way to differentiate ints and floats.124// Let's play it safe and require a string.125if (allowFloatBits)126Fail(StringFromFormat("Could not parse '%s' parameter: use a string for non integer values", name));127else128Fail(StringFromFormat("Could not parse '%s' parameter: integer required", name));129return false;130} else if (!isInteger && allowFloatBits) {131union {132float f;133uint32_t u;134} bits = { (float)val };135*out = bits.u;136return true;137}138139if (val < 0 && val >= std::numeric_limits<int32_t>::min()) {140// Convert to unsigned representation.141*out = (uint32_t)(int32_t)val;142return true;143} else if (val >= 0 && val <= std::numeric_limits<uint32_t>::max()) {144*out = (uint32_t)val;145return true;146} else if (allowLoose) {147*out = val >= 0 ? std::numeric_limits<uint32_t>::max() : std::numeric_limits<uint32_t>::min();148return true;149}150151if (allowFloatBits)152Fail(StringFromFormat("Could not parse '%s' parameter: outside 32 bit range (use string for float)", name));153else154Fail(StringFromFormat("Could not parse '%s' parameter: outside 32 bit range", name));155return false;156}157if (tag != JSON_STRING) {158if (type == DebuggerParamType::REQUIRED || tag != JSON_NULL) {159Fail(StringFromFormat("Invalid '%s' parameter type", name));160return false;161}162return true;163}164165if (U32FromString(node->value.toString(), out, allowFloatBits))166return true;167168if (allowFloatBits)169Fail(StringFromFormat("Could not parse '%s' parameter: number expected", name));170else171Fail(StringFromFormat("Could not parse '%s' parameter: integer required", name));172return false;173}174175bool DebuggerRequest::ParamBool(const char *name, bool *out, DebuggerParamType type) {176bool allowLoose = type == DebuggerParamType::REQUIRED_LOOSE || type == DebuggerParamType::OPTIONAL_LOOSE;177bool required = type == DebuggerParamType::REQUIRED || type == DebuggerParamType::REQUIRED_LOOSE;178179const JsonNode *node = data.get(name);180if (!node) {181if (required)182Fail(StringFromFormat("Missing '%s' parameter", name));183return !required;184}185186auto tag = node->value.getTag();187if (tag == JSON_NUMBER) {188double val = node->value.toNumber();189if (val == 1.0 || val == 0.0 || allowLoose) {190*out = val != 0.0;191return true;192}193194Fail(StringFromFormat("Could not parse '%s' parameter: should be true/1 or false/0", name));195return false;196}197if (tag == JSON_TRUE) {198*out = true;199return true;200}201if (tag == JSON_FALSE) {202*out = false;203return true;204}205if (tag != JSON_STRING) {206if (type == DebuggerParamType::REQUIRED || tag != JSON_NULL) {207Fail(StringFromFormat("Invalid '%s' parameter type", name));208return false;209}210return true;211}212213const std::string s = node->value.toString();214if (s == "1" || s == "true") {215*out = true;216return true;217}218if (s == "0" || s == "false" || (s.empty() && allowLoose)) {219*out = false;220return true;221}222223if (allowLoose) {224*out = true;225return true;226}227228Fail(StringFromFormat("Could not parse '%s' parameter: boolean required", name));229return false;230}231232bool DebuggerRequest::ParamString(const char *name, std::string *out, DebuggerParamType type) {233bool allowLoose = type == DebuggerParamType::REQUIRED_LOOSE || type == DebuggerParamType::OPTIONAL_LOOSE;234bool required = type == DebuggerParamType::REQUIRED || type == DebuggerParamType::REQUIRED_LOOSE;235236const JsonNode *node = data.get(name);237if (!node) {238if (required)239Fail(StringFromFormat("Missing '%s' parameter", name));240return !required;241}242243auto tag = node->value.getTag();244if (tag == JSON_STRING) {245*out = node->value.toString();246return true;247} else if (!allowLoose) {248if (required || tag != JSON_NULL) {249Fail(StringFromFormat("Invalid '%s' parameter type", name));250return false;251}252return true;253}254255// For loose, let's allow a few things.256if (tag == JSON_TRUE) {257*out = "true";258return true;259} else if (tag == JSON_FALSE) {260*out = "false";261return true;262} else if (tag == JSON_NULL) {263if (required) {264out->clear();265}266return true;267} else if (tag == JSON_NUMBER) {268// Will have a decimal place, though.269*out = StringFromFormat("%f", node->value.toNumber());270return true;271}272273Fail(StringFromFormat("Invalid '%s' parameter type", name));274return false;275}276277uint32_t RoundMemAddressUp(uint32_t addr) {278if (addr < PSP_GetScratchpadMemoryBase())279return PSP_GetScratchpadMemoryBase();280else if (addr >= PSP_GetScratchpadMemoryEnd() && addr < PSP_GetVidMemBase())281return PSP_GetVidMemBase();282else if (addr >= PSP_GetVidMemEnd() && addr < PSP_GetKernelMemoryBase())283return PSP_GetKernelMemoryBase();284else if (addr >= PSP_GetUserMemoryEnd())285return PSP_GetScratchpadMemoryBase();286return addr;287}288289290