Implemented actual swkbd TextCheck support. Moved strbuf alloc from _swkbdProcessOutput into swkbdShow(), so that it can be used for TextCheck. Added validation for the out_string* params in swkbdShow(). The out_string buffer is now cleared before calling _swkbdProcessOutput.

This commit is contained in:
yellows8 2018-12-23 00:38:32 -05:00
parent e8482f7581
commit 56b767efbf
2 changed files with 64 additions and 14 deletions

View File

@ -8,7 +8,14 @@
#include "../types.h" #include "../types.h"
#include "../services/applet.h" #include "../services/applet.h"
typedef bool (*SwkbdTextCheckCb)(void *); ///< TextCheck callback. TODO typedef enum {
SwkbdTextCheckResult_OK = 0, ///< Success, valid string.
SwkbdTextCheckResult_Bad = 1, ///< Failure, invalid string. Error message is displayed in a message-box, pressing OK will return to swkbd again.
SwkbdTextCheckResult_Prompt = 2, ///< Failure, invalid string. Error message is displayed in a message-box, pressing Cancel will return to swkbd again, while pressing OK will continue as if the text was valid.
SwkbdTextCheckResult_Silent = 3, ///< Failure, invalid string. With value 3 and above, swkbd will silently not accept the string, without displaying any error.
} SwkbdTextCheckResult;
typedef SwkbdTextCheckResult (*SwkbdTextCheckCb)(char* tmp_string, size_t tmp_string_size); /// TextCheck callback set by \ref swkbdConfigSetTextCheckCallback, for validating the input string when the swkbd ok-button is pressed. This buffer contains an UTF-8 string. This callback should validate the input string, then return a \ref SwkbdTextCheckResult indicating success/failure. On failure, this function must write an error message to the tmp_string buffer, which will then be displayed by swkbd.
/// Base swkbd arg struct. /// Base swkbd arg struct.
typedef struct { typedef struct {
@ -165,14 +172,15 @@ void swkbdConfigSetInitialText(SwkbdConfig* c, const char* str);
void swkbdConfigSetDictionary(SwkbdConfig* c, const SwkbdDictWord *input, s32 entries); void swkbdConfigSetDictionary(SwkbdConfig* c, const SwkbdDictWord *input, s32 entries);
/** /**
* @brief Sets the TextCheck callback. TODO: this is not yet used. * @brief Sets the TextCheck callback.
* @param c SwkbdConfig struct. * @param c SwkbdConfig struct.
* @param cb callback * @param cb \ref SwkbdTextCheckCb callback.
*/ */
void swkbdConfigSetTextCheckCallback(SwkbdConfig* c, SwkbdTextCheckCb cb); void swkbdConfigSetTextCheckCallback(SwkbdConfig* c, SwkbdTextCheckCb cb);
/** /**
* @brief Launch swkbd with the specified config. This will return once swkbd is finished running. * @brief Launch swkbd with the specified config. This will return once swkbd is finished running.
* @note The string buffer is also used for the buffer passed to the \ref SwkbdTextCheckCb, when it's set. Hence, in that case this buffer should be large enough to handle TextCheck string input/output. The size passed to the callback is the same size passed here, -1.
* @param c SwkbdConfig struct. * @param c SwkbdConfig struct.
* @param out_string UTF-8 Output string buffer. * @param out_string UTF-8 Output string buffer.
* @param out_string_size UTF-8 Output string buffer size, including NUL-terminator. * @param out_string_size UTF-8 Output string buffer size, including NUL-terminator.

View File

@ -183,27 +183,54 @@ void swkbdConfigSetTextCheckCallback(SwkbdConfig* c, SwkbdTextCheckCb cb) {
c->arg.arg.textCheckCb = cb; c->arg.arg.textCheckCb = cb;
} }
static Result _swkbdProcessOutput(AppletHolder* h, char* out_string, size_t out_string_size) { static Result _swkbdProcessInteractive(SwkbdConfig* c, AppletHolder* h, uint16_t* strbuf, size_t strbuf_size, char* tmp_string, size_t tmp_string_size) {
Result rc=0;
AppletStorage storage;
u64 strsize=0;
u32 res=0;
rc = appletHolderPopInteractiveOutData(h, &storage);
if (R_FAILED(rc)) return rc;
if (R_SUCCEEDED(rc)) rc = appletStorageRead(&storage, 0, &strsize, sizeof(strsize));
if (R_SUCCEEDED(rc) && strsize > strbuf_size) strsize = strbuf_size;
if (R_SUCCEEDED(rc)) rc = appletStorageRead(&storage, sizeof(strsize), strbuf, strsize);
appletStorageClose(&storage);
if (R_SUCCEEDED(rc) && (c->arg.arg.textCheckFlag && c->arg.arg.textCheckCb)) {
_swkbdConvertToUTF8(tmp_string, strbuf, tmp_string_size-1);
res = c->arg.arg.textCheckCb(tmp_string, tmp_string_size-1);
_swkbdConvertToUTF16ByteSize(strbuf, tmp_string, strbuf_size-2);
}
if (R_SUCCEEDED(rc)) rc = appletCreateStorage(&storage, sizeof(res)+strbuf_size);
if (R_SUCCEEDED(rc)) {
rc = appletStorageWrite(&storage, 0, &res, sizeof(res));
if (R_SUCCEEDED(rc)) rc = appletStorageWrite(&storage, sizeof(res), strbuf, strbuf_size);
if (R_FAILED(rc)) appletStorageClose(&storage);
if (R_SUCCEEDED(rc)) rc = appletHolderPushInteractiveInData(h, &storage);
}
return rc;
}
static Result _swkbdProcessOutput(AppletHolder* h, uint16_t* strbuf, size_t strbuf_size, char* out_string, size_t out_string_size) {
Result rc=0; Result rc=0;
AppletStorage outstorage; AppletStorage outstorage;
u32 CloseResult=0; u32 CloseResult=0;
uint16_t* strbuf = NULL;
size_t strbuf_size = 0x7D4;
rc = appletHolderPopOutData(h, &outstorage); rc = appletHolderPopOutData(h, &outstorage);
if (R_FAILED(rc)) return rc; if (R_FAILED(rc)) return rc;
strbuf = (u16*)malloc(strbuf_size+2);
if (strbuf==NULL) rc = MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
if (strbuf) memset(strbuf, 0, strbuf_size+2);
if (R_SUCCEEDED(rc)) rc = appletStorageRead(&outstorage, 0, &CloseResult, sizeof(CloseResult)); if (R_SUCCEEDED(rc)) rc = appletStorageRead(&outstorage, 0, &CloseResult, sizeof(CloseResult));
if (R_SUCCEEDED(rc) && CloseResult!=0) rc = MAKERESULT(Module_Libnx, LibnxError_LibAppletBadExit); if (R_SUCCEEDED(rc) && CloseResult!=0) rc = MAKERESULT(Module_Libnx, LibnxError_LibAppletBadExit);
if (R_SUCCEEDED(rc)) rc = appletStorageRead(&outstorage, sizeof(CloseResult), strbuf, strbuf_size); if (R_SUCCEEDED(rc)) rc = appletStorageRead(&outstorage, sizeof(CloseResult), strbuf, strbuf_size);
if (R_SUCCEEDED(rc)) _swkbdConvertToUTF8(out_string, strbuf, out_string_size-1); if (R_SUCCEEDED(rc)) _swkbdConvertToUTF8(out_string, strbuf, out_string_size-1);
free(strbuf);
appletStorageClose(&outstorage); appletStorageClose(&outstorage);
return rc; return rc;
@ -213,12 +240,24 @@ Result swkbdShow(SwkbdConfig* c, char* out_string, size_t out_string_size) {
Result rc=0; Result rc=0;
AppletHolder holder; AppletHolder holder;
AppletStorage storage; AppletStorage storage;
uint16_t* strbuf = NULL;
size_t strbuf_size = 0x7D4;
if (out_string==NULL || out_string_size==0) return MAKERESULT(Module_Libnx, LibnxError_BadInput);
memset(&storage, 0, sizeof(AppletStorage)); memset(&storage, 0, sizeof(AppletStorage));
rc = appletCreateLibraryApplet(&holder, AppletId_swkbd, LibAppletMode_AllForeground); strbuf = (u16*)malloc(strbuf_size+2);
if (strbuf==NULL) rc = MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
if (strbuf) memset(strbuf, 0, strbuf_size+2);
if (R_FAILED(rc)) return rc; if (R_FAILED(rc)) return rc;
rc = appletCreateLibraryApplet(&holder, AppletId_swkbd, LibAppletMode_AllForeground);
if (R_FAILED(rc)) {
free(strbuf);
return rc;
}
LibAppletArgs commonargs; LibAppletArgs commonargs;
libappletArgsCreate(&commonargs, c->version); libappletArgsCreate(&commonargs, c->version);
rc = libappletArgsPush(&commonargs, &holder); rc = libappletArgsPush(&commonargs, &holder);
@ -238,7 +277,7 @@ Result swkbdShow(SwkbdConfig* c, char* out_string, size_t out_string_size) {
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
while(appletHolderWaitInteractiveOut(&holder)) { while(appletHolderWaitInteractiveOut(&holder)) {
//TODO: Handle Interactive data here. _swkbdProcessInteractive(c, &holder, strbuf, strbuf_size, out_string, out_string_size);
} }
} }
@ -254,13 +293,16 @@ Result swkbdShow(SwkbdConfig* c, char* out_string, size_t out_string_size) {
rc = MAKERESULT(Module_Libnx, LibnxError_LibAppletBadExit); rc = MAKERESULT(Module_Libnx, LibnxError_LibAppletBadExit);
} }
else { //success else { //success
rc = _swkbdProcessOutput(&holder, out_string, out_string_size); memset(out_string, 0, out_string_size);
rc = _swkbdProcessOutput(&holder, strbuf, strbuf_size, out_string, out_string_size);
} }
} }
appletHolderClose(&holder); appletHolderClose(&holder);
appletStorageCloseTmem(&storage); appletStorageCloseTmem(&storage);
free(strbuf);
return rc; return rc;
} }