diff --git a/nx/include/switch/applets/web.h b/nx/include/switch/applets/web.h index 65b7def4..080c4300 100644 --- a/nx/include/switch/applets/web.h +++ b/nx/include/switch/applets/web.h @@ -74,7 +74,7 @@ typedef struct { WebCommonTLVStorage storage; } WebCommonReply; -/// Types for \ref WebArgTLV. +/// Types for \ref WebArgTLV, input storage. typedef enum { WebArgType_Url = 0x1, ///< [1.0.0+] String, size 0xC00. Initial URL. WebArgType_CallbackUrl = 0x3, ///< [1.0.0+] String, size 0x400. @@ -122,6 +122,19 @@ typedef enum { WebArgType_PageScrollIndicator = 0x36, ///< [5.0.0+] u8 bool } WebArgType; +/// Types for \ref WebArgTLV, output storage. +/// Official user-processes doesn't check the TLV size for any of these. +typedef enum { + WebReplyType_ExitReason = 0x1, ///< [3.0.0+] u32 ShareExitReason + WebReplyType_LastUrl = 0x2, ///< [3.0.0+] string + WebReplyType_LastUrlSize = 0x3, ///< [3.0.0+] u64 + WebReplyType_SharePostResult = 0x4, ///< [3.0.0+] u32 SharePostResult + WebReplyType_PostServiceName = 0x5, ///< [3.0.0+] string + WebReplyType_PostServiceNameSize = 0x6, ///< [3.0.0+] u64 + WebReplyType_PostId = 0x7, ///< [3.0.0+] string + WebReplyType_PostIdSize = 0x8, ///< [3.0.0+] u64 +} WebReplyType; + /// This controls the initial page for ShareApplet, used by \ref webShareCreate. typedef enum { WebShareStartPage_Default = 0, ///< The default "/" page. @@ -474,3 +487,47 @@ Result webConfigSetPageScrollIndicator(WebCommonConfig* config, bool flag); */ Result webConfigShow(WebCommonConfig* config, WebCommonReply *out); +/** + * @brief Gets the ExitReason from the specified reply. + * @param reply WebCommonReply object. + * @param exitReason Output exitReason + */ +Result webReplyGetExitReason(WebCommonReply *reply, u32 *exitReason); + +/** + * @brief Gets the LastUrl from the specified reply. + * @note If you want to allocate a string buffer on heap, you can call this with outstr=NULL/outstr_maxsize=0 to get the out_size, then call it again with the allocated buffer. + * @param outstr Output string buffer. If NULL, the string is not loaded. + * @param outstr_maxsize Size of the buffer, including NUL-terminator. If outstr is set, this size must be >1. The size used for the actual string-copy is this size-1, to make sure the output is NUL-terminated (the entire buffer is cleared first). + * @param out_size Output string length including NUL-terminator, for the original input string in the reply loaded from a separate size field. + */ +Result webReplyGetLastUrl(WebCommonReply *reply, char *outstr, size_t outstr_maxsize, size_t *out_size); + +/** + * @brief Gets the SharePostResult from the specified reply. + * @note Only available with reply data from ShareApplet on [3.0.0+]. + * @param reply WebCommonReply object. + * @param sharePostResult Output sharePostResult + */ +Result webReplyGetSharePostResult(WebCommonReply *reply, u32 *sharePostResult); + +/** + * @brief Gets the PostServiceName from the specified reply. + * @note Only available with reply data from ShareApplet on [3.0.0+]. + * @note If you want to allocate a string buffer on heap, you can call this with outstr=NULL/outstr_maxsize=0 to get the out_size, then call it again with the allocated buffer. + * @param outstr Output string buffer. If NULL, the string is not loaded. + * @param outstr_maxsize Size of the buffer, including NUL-terminator. If outstr is set, this size must be >1. The size used for the actual string-copy is this size-1, to make sure the output is NUL-terminated (the entire buffer is cleared first). + * @param out_size Output string length including NUL-terminator, for the original input string in the reply loaded from a separate size field. + */ +Result webReplyGetPostServiceName(WebCommonReply *reply, char *outstr, size_t outstr_maxsize, size_t *out_size); + +/** + * @brief Gets the PostId from the specified reply. + * @note Only available with reply data from ShareApplet on [3.0.0+]. + * @note If you want to allocate a string buffer on heap, you can call this with outstr=NULL/outstr_maxsize=0 to get the out_size, then call it again with the allocated buffer. + * @param outstr Output string buffer. If NULL, the string is not loaded. + * @param outstr_maxsize Size of the buffer, including NUL-terminator. If outstr is set, this size must be >1. The size used for the actual string-copy is this size-1, to make sure the output is NUL-terminated (the entire buffer is cleared first). + * @param out_size Output string length including NUL-terminator, for the original input string in the reply loaded from a separate size field. + */ +Result webReplyGetPostId(WebCommonReply *reply, char *outstr, size_t outstr_maxsize, size_t *out_size); + diff --git a/nx/source/applets/web.c b/nx/source/applets/web.c index 03bd2e2b..d44cf58f 100644 --- a/nx/source/applets/web.c +++ b/nx/source/applets/web.c @@ -179,6 +179,43 @@ static Result _webTLVRead(WebCommonTLVStorage *storage, u16 type, void* argdata, return 0; } +static Result _webTLVReadVarSize(WebCommonTLVStorage *storage, u16 type, void* argdata, size_t argdata_size) { + Result rc = MAKERESULT(Module_Libnx, LibnxError_BadInput); + size_t i, count, offset; + u8 *dataptr = storage->data; + WebArgHeader *hdr = (WebArgHeader*)dataptr; + WebArgTLV *tlv; + size_t size = sizeof(storage->data); + + offset = sizeof(WebArgHeader); + if (size < offset) return rc; + + count = hdr->total_entries; + tlv = (WebArgTLV*)&dataptr[offset]; + + for (i=0; itype == type) { + if (argdata_size > tlv->size) argdata_size = tlv->size; + break; + } + + offset+= sizeof(WebArgTLV) + tlv->size; + if (size < offset) return rc; + } + + if (i==count) return MAKERESULT(Module_Libnx, LibnxError_NotFound); + if (size < offset + sizeof(WebArgTLV) + argdata_size) return rc; + + offset+= sizeof(WebArgTLV); + memcpy(argdata, &dataptr[offset], argdata_size); + + return 0; +} + static Result _webTLVSet(WebCommonConfig* config, u16 type, const void* argdata, u16 argdata_size) { return _webTLVWrite(&config->arg, type, argdata, argdata_size, argdata_size); } @@ -526,3 +563,64 @@ Result webConfigShow(WebCommonConfig* config, WebCommonReply *out) { return _webShow(config->appletid, config->version, &config->arg, sizeof(config->arg), reply, size); } +// For strings only available via TLVs. +static Result _webReplyGetString(WebCommonReply *reply, WebReplyType str_type, WebReplyType strsize_type, char *outstr, size_t outstr_maxsize, size_t *out_size) { + Result rc=0; + + if (outstr && outstr_maxsize <= 1) return MAKERESULT(Module_Libnx, LibnxError_BadInput); + + if (outstr) memset(outstr, 0, outstr_maxsize); + + if (!reply->type) { + rc = MAKERESULT(Module_Libnx, LibnxError_BadInput); + } + else { + if (outstr) rc = _webTLVReadVarSize(&reply->storage, str_type, outstr, outstr_maxsize-1); + if (R_SUCCEEDED(rc) && out_size) rc = _webTLVRead(&reply->storage, strsize_type, out_size, sizeof(*out_size)); + } + return rc; +} + +Result webReplyGetExitReason(WebCommonReply *reply, u32 *exitReason) { + if (!reply->type) { + *exitReason = reply->ret.exitReason; + } + else { + return _webTLVRead(&reply->storage, WebReplyType_ExitReason, exitReason, sizeof(*exitReason)); + } + return 0; +} + +Result webReplyGetLastUrl(WebCommonReply *reply, char *outstr, size_t outstr_maxsize, size_t *out_size) { + Result rc=0; + + if (outstr && outstr_maxsize <= 1) return MAKERESULT(Module_Libnx, LibnxError_BadInput); + + if (outstr) memset(outstr, 0, outstr_maxsize); + + if (!reply->type) { + if (outstr) strncpy(outstr, reply->ret.lastUrl, outstr_maxsize-1); + if (out_size) *out_size = reply->ret.lastUrlSize; + } + else { + if (outstr) rc = _webTLVReadVarSize(&reply->storage, WebReplyType_LastUrl, outstr, outstr_maxsize-1); + if (R_SUCCEEDED(rc) && out_size) rc = _webTLVRead(&reply->storage, WebReplyType_LastUrlSize, out_size, sizeof(*out_size)); + } + return rc; +} + +Result webReplyGetSharePostResult(WebCommonReply *reply, u32 *sharePostResult) { + if (reply->type) { + return _webTLVRead(&reply->storage, WebReplyType_SharePostResult, sharePostResult, sizeof(*sharePostResult)); + } + return MAKERESULT(Module_Libnx, LibnxError_BadInput); +} + +Result webReplyGetPostServiceName(WebCommonReply *reply, char *outstr, size_t outstr_maxsize, size_t *out_size) { + return _webReplyGetString(reply, WebReplyType_PostServiceName, WebReplyType_PostServiceNameSize, outstr, outstr_maxsize, out_size); +} + +Result webReplyGetPostId(WebCommonReply *reply, char *outstr, size_t outstr_maxsize, size_t *out_size) { + return _webReplyGetString(reply, WebReplyType_PostId, WebReplyType_PostIdSize, outstr, outstr_maxsize, out_size); +} +