Added Textviewer (unfinished)

This commit is contained in:
d0k3 2017-06-26 01:44:16 +02:00
parent 9589731fa6
commit dd2efaedc5
7 changed files with 154 additions and 8 deletions

View File

@ -106,8 +106,10 @@ u32 IdentifyFileType(const char* path) {
} else if ((fsize <= PAYLOAD_MAX_SIZE) && ext && (strncasecmp(ext, "bin", 4) == 0)) { } else if ((fsize <= PAYLOAD_MAX_SIZE) && ext && (strncasecmp(ext, "bin", 4) == 0)) {
return BIN_LAUNCH; // assume it's an ARM9 payload return BIN_LAUNCH; // assume it's an ARM9 payload
#endif #endif
} else if ((fsize <= SCRIPT_MAX_SIZE) && ext && (strncasecmp(ext, SCRIPT_EXT, strnlen(SCRIPT_EXT, 16) + 1) == 0)) { } else if (ValidateText((char*) data, (fsize > 0X200) ? 0x200 : fsize)) {
return TXT_SCRIPT; // should be a script if ((fsize <= SCRIPT_MAX_SIZE) && ext && (strncasecmp(ext, SCRIPT_EXT, strnlen(SCRIPT_EXT, 16) + 1) == 0))
return TXT_SCRIPT | TXT_GENERIC; // should be a script (which is also generic text)
else if (fsize < TEMP_BUFFER_SIZE) return TXT_GENERIC;
} }
return 0; return 0;

View File

@ -23,6 +23,7 @@
#define BIN_KEYDB (1UL<<18) #define BIN_KEYDB (1UL<<18)
#define BIN_LEGKEY (1UL<<19) #define BIN_LEGKEY (1UL<<19)
#define TXT_SCRIPT (1UL<<20) #define TXT_SCRIPT (1UL<<20)
#define TXT_GENERIC (1UL<<21)
#define TYPE_BASE 0x00FFFFFF // 24 bit reserved for base types #define TYPE_BASE 0x00FFFFFF // 24 bit reserved for base types
#define FLAG_ENC (1UL<<28) #define FLAG_ENC (1UL<<28)

View File

@ -455,6 +455,17 @@ bool run_line(const char* line_start, const char* line_end, u32* flags, char* er
return true; return true;
} }
// checks for illegal ASCII symbols
bool ValidateText(const char* text, u32 len) {
for (u32 i = 0; i < len; i++) {
char c = text[i];
if ((c == '\r') && ((i+1) < len) && (text[i+1] != '\n')) return false; // CR without LF
if ((c < 0x20) && (c != '\t') && (c != '\r') && (c != '\n')) return false; // illegal control char
if ((c == 0x7F) || (c == 0xFF)) return false; // other illegal char
}
return true;
}
bool ExecuteGM9Script(const char* path_script) { bool ExecuteGM9Script(const char* path_script) {
// revert mount state? // revert mount state?
char* script = (char*) SCRIPT_BUFFER; char* script = (char*) SCRIPT_BUFFER;

View File

@ -7,4 +7,5 @@
#define SCRIPT_EXT "gm9" #define SCRIPT_EXT "gm9"
#define SCRIPT_MAX_SIZE (SCRIPT_BUFFER_SIZE-VAR_BUFFER_SIZE-1) #define SCRIPT_MAX_SIZE (SCRIPT_BUFFER_SIZE-VAR_BUFFER_SIZE-1)
bool ValidateText(const char* text, u32 size);
bool ExecuteGM9Script(const char* path_script); bool ExecuteGM9Script(const char* path_script);

View File

@ -116,14 +116,14 @@ bool FileUnlock(const char* path) {
return true; return true;
} }
bool FileSetData(const char* path, const u8* data, size_t size, size_t foffset, bool create) { bool FileSetData(const char* path, const void* data, size_t size, size_t foffset, bool create) {
UINT bw; UINT bw;
if (!CheckWritePermissions(path)) return false; if (!CheckWritePermissions(path)) return false;
if ((DriveType(path) & DRV_FAT) && create) f_unlink(path); if ((DriveType(path) & DRV_FAT) && create) f_unlink(path);
return (fvx_qwrite(path, data, foffset, size, &bw) == FR_OK) && (bw == size); return (fvx_qwrite(path, data, foffset, size, &bw) == FR_OK) && (bw == size);
} }
size_t FileGetData(const char* path, u8* data, size_t size, size_t foffset) { size_t FileGetData(const char* path, void* data, size_t size, size_t foffset) {
UINT br; UINT br;
if (fvx_qread(path, data, foffset, size, &br) != FR_OK) br = 0; if (fvx_qread(path, data, foffset, size, &br) != FR_OK) br = 0;
return br; return br;

View File

@ -25,10 +25,10 @@ bool SetupBonusDrive(void);
bool FileUnlock(const char* path); bool FileUnlock(const char* path);
/** Create / open file and write the provided data to it **/ /** Create / open file and write the provided data to it **/
bool FileSetData(const char* path, const u8* data, size_t size, size_t foffset, bool create); bool FileSetData(const char* path, const void* data, size_t size, size_t foffset, bool create);
/** Read data from file@offset **/ /** Read data from file@offset **/
size_t FileGetData(const char* path, u8* data, size_t size, size_t foffset); size_t FileGetData(const char* path, void* data, size_t size, size_t foffset);
/** Get size of file **/ /** Get size of file **/
size_t FileGetSize(const char* path); size_t FileGetSize(const char* path);

View File

@ -41,12 +41,42 @@
#define COLOR_HVASCII RGB(0x40, 0x80, 0x50) #define COLOR_HVASCII RGB(0x40, 0x80, 0x50)
#define COLOR_HVHEX(i) ((i % 2) ? RGB(0x30, 0x90, 0x30) : RGB(0x30, 0x80, 0x30)) #define COLOR_HVHEX(i) ((i % 2) ? RGB(0x30, 0x90, 0x30) : RGB(0x30, 0x80, 0x30))
#define COLOR_TVOFFS RGB(0x40, 0x60, 0x50)
#define COLOR_TVTEXT RGB(0x30, 0x85, 0x30)
typedef struct { typedef struct {
char path[256]; char path[256];
u32 cursor; u32 cursor;
u32 scroll; u32 scroll;
} PaneData; } PaneData;
static inline u32 LineLen(const char* text, u32 len, const char* line) {
char* line0 = (char*) line;
char* line1 = (char*) line;
while ((line1 < (text + len)) && (*line1 != '\n') && *line1) line1++;
while ((line1 > line0) && (*(line1-1) <= ' ')) line1--;
return line1 - line0;
}
static inline char* LineSeek(const char* text, u32 len, const char* line, int off) {
char* lf = ((char*) line - 1);
// safety checks / ensure we are at the start of the line
if (line < text) return NULL;
if ((line >= (text + len)) && (off >= 0)) return (char*) line;
while ((lf >= text) && (*lf != '\n')) lf--;
// handle backwards search
for (; (off < 0) && (lf >= text); off++)
for (lf--; (lf >= text) && (*lf != '\n'); lf--);
// handle forwards search
for (; (off > 0) && (lf < text + len); off--)
for (lf++; (lf < text + len) && (*lf != '\n'); lf++);
return lf + 1;
}
void DrawUserInterface(const char* curr_path, DirEntry* curr_entry, DirStruct* clipboard, u32 curr_pane) { void DrawUserInterface(const char* curr_path, DirEntry* curr_entry, DirStruct* clipboard, u32 curr_pane) {
const u32 n_cb_show = 8; const u32 n_cb_show = 8;
const u32 bartxt_start = (FONT_HEIGHT_EXT == 10) ? 1 : 2; const u32 bartxt_start = (FONT_HEIGHT_EXT == 10) ? 1 : 2;
@ -267,7 +297,101 @@ u32 SdFormatMenu(void) {
return 0; return 0;
} }
u32 HexViewer(const char* path) { u32 MemTextViewer(const char* text, u32 len) {
const u32 vpad = 1;
const u32 hpad = 0;
// bool wordwrap = false;
char* line0 = (char*) text;
int lcurr = 0;
int off_x = 0;
u32 nlin_disp = SCREEN_HEIGHT / (FONT_HEIGHT_EXT + (2*vpad));
u32 llen_disp = (SCREEN_WIDTH_TOP - (2*hpad)) / FONT_WIDTH_EXT;
u32 llen_max = 0;
u32 nlines = 0;
// clear screens
ClearScreenF(true, true, COLOR_STD_BG);
static const char* instr = "Textviewer Controls:\n \n\x18\x19\x1A\x1B(+R) - Scroll\nR+Y - Wordwrap on/off\nX - Search / goto...\nB - Exit\n";
ShowString(instr);
// find maximum line len and # of lines
for (char* ptr = (char*) text; ptr < (text + len); ptr = LineSeek(text, len, ptr, 1)) {
u32 llen = LineLen(text, len, ptr);
if (llen > llen_max) llen_max = llen;
if (!*(ptr + llen)) len = (ptr + llen) - text; // zero found
nlines++;
}
// make room for line numbers
llen_disp -= 5;
while (true) {
// display text on screen
char dispstr[128]; // should be more than enough
char* arrow_l = dispstr;
char* arrow_r = dispstr + llen_disp - 1;
char* ptr = line0;
u32 nln = lcurr;
for (u32 y = vpad; y < SCREEN_HEIGHT; y += FONT_HEIGHT_EXT + (2*vpad)) {
char* ptr_next = LineSeek(text, len, ptr, 1);
u32 llen = LineLen(text, len, ptr);
u32 ncpy = ((int) llen < off_x) ? 0 : (llen - off_x);
if (ncpy > llen_disp) ncpy = llen_disp;
snprintf(dispstr, llen_disp + 1, "%-*.*s", (int) llen_disp, (int) llen_disp, "");
if (ncpy) memcpy(dispstr, ptr + off_x, ncpy);
for (char* d = dispstr; *d; d++) if (*d < ' ') *d = ' ';
// line number / text / arrows (pt.1)
if (llen > off_x + llen_disp) *(arrow_r-1) = *arrow_r = '>';
if (off_x) *arrow_l = *(arrow_l+1) = '<';
DrawStringF(TOP_SCREEN, hpad + (5*FONT_WIDTH_EXT), y, COLOR_TVTEXT, COLOR_STD_BG, dispstr);
if (ptr != ptr_next) DrawStringF(TOP_SCREEN, hpad, y, COLOR_TVOFFS, COLOR_STD_BG, "%04lu", nln + 1);
// arrows (pt.2)
snprintf(dispstr, llen_disp + 1, "%-*.*s", (int) llen_disp, (int) llen_disp, "");
if (llen > off_x + llen_disp) *(arrow_r-1) = *arrow_r = '>';
if (off_x) *arrow_l = *(arrow_l+1) = '<';
DrawStringF(TOP_SCREEN, hpad + (5*FONT_WIDTH_EXT), y, COLOR_TVOFFS, COLOR_TRANSPARENT, dispstr);
// advance pointer / line number
for (char* c = ptr; c < ptr_next; c++) if (*c == '\n') ++nln;
ptr = ptr_next;
}
// handle user input
u32 pad_state = InputWait();
if ((pad_state & BUTTON_R1) && (pad_state & BUTTON_L1)) CreateScreenshot();
else { // standard viewer mode
int lcurr_next = lcurr;
u32 step_ud = (pad_state & BUTTON_R1) ? nlin_disp : 1;
u32 step_lr = (pad_state & BUTTON_R1) ? llen_disp : 1;
if (pad_state & BUTTON_DOWN) lcurr_next += step_ud;
else if (pad_state & BUTTON_RIGHT) off_x += step_lr;
else if (pad_state & BUTTON_UP) lcurr_next -= step_ud;
else if (pad_state & BUTTON_LEFT) off_x -= step_lr;
else if (pad_state & (BUTTON_B|BUTTON_START)) break;
// check for problems, apply changes
if (lcurr_next + nlin_disp > nlines) lcurr_next = nlines - nlin_disp;
if (lcurr_next < 0) lcurr_next = 0;
if (lcurr_next != lcurr) {
line0 = LineSeek(text, len, line0, lcurr_next - lcurr);
lcurr = lcurr_next;
}
if (off_x + llen_disp > llen_max) off_x = llen_max - llen_disp;
if (off_x < 0) off_x = 0;
}
}
// clear screens
ClearScreenF(true, true, COLOR_STD_BG);
return 0;
}
u32 FileHexViewer(const char* path) {
static const u32 max_data = (SCREEN_HEIGHT / 8) * 16; static const u32 max_data = (SCREEN_HEIGHT / 8) * 16;
static u32 mode = 0; static u32 mode = 0;
u8* data = TEMP_BUFFER; u8* data = TEMP_BUFFER;
@ -701,6 +825,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
int n_opt = 0; int n_opt = 0;
int special = (special_opt) ? ++n_opt : -1; int special = (special_opt) ? ++n_opt : -1;
int hexviewer = ++n_opt; int hexviewer = ++n_opt;
int textviewer = (filetype & TXT_GENERIC) ? ++n_opt : -1;
int calcsha = ++n_opt; int calcsha = ++n_opt;
int calccmac = (CheckCmacPath(curr_entry->path) == 0) ? ++n_opt : -1; int calccmac = (CheckCmacPath(curr_entry->path) == 0) ? ++n_opt : -1;
int copystd = (!in_output_path) ? ++n_opt : -1; int copystd = (!in_output_path) ? ++n_opt : -1;
@ -734,6 +859,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
(filetype & TXT_SCRIPT) ? "Execute GM9 script" : "???"; (filetype & TXT_SCRIPT) ? "Execute GM9 script" : "???";
optionstr[hexviewer-1] = "Show in Hexeditor"; optionstr[hexviewer-1] = "Show in Hexeditor";
optionstr[calcsha-1] = "Calculate SHA-256"; optionstr[calcsha-1] = "Calculate SHA-256";
if (textviewer > 0) optionstr[textviewer-1] = "Show in Textviewer";
if (calccmac > 0) optionstr[calccmac-1] = "Calculate CMAC"; if (calccmac > 0) optionstr[calccmac-1] = "Calculate CMAC";
if (copystd > 0) optionstr[copystd-1] = "Copy to " OUTPUT_PATH; if (copystd > 0) optionstr[copystd-1] = "Copy to " OUTPUT_PATH;
if (inject > 0) optionstr[inject-1] = "Inject data @offset"; if (inject > 0) optionstr[inject-1] = "Inject data @offset";
@ -742,7 +868,12 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
int user_select = ShowSelectPrompt(n_opt, optionstr, (n_marked > 1) ? int user_select = ShowSelectPrompt(n_opt, optionstr, (n_marked > 1) ?
"%s\n%(%lu files selected)" : "%s", pathstr, n_marked); "%s\n%(%lu files selected)" : "%s", pathstr, n_marked);
if (user_select == hexviewer) { // -> show in hex viewer if (user_select == hexviewer) { // -> show in hex viewer
HexViewer(curr_entry->path); FileHexViewer(curr_entry->path);
return 0;
} else if (user_select == textviewer) { // -> show in text viewer
char* text = (char*) TEMP_BUFFER;
u32 len = FileGetData(curr_entry->path, text, TEMP_BUFFER_SIZE, 0);
MemTextViewer(text, len);
return 0; return 0;
} else if (user_select == calcsha) { // -> calculate SHA-256 } else if (user_select == calcsha) { // -> calculate SHA-256
Sha256Calculator(curr_entry->path); Sha256Calculator(curr_entry->path);