diff --git a/audioplayer.c b/audioplayer.c
index 1bfe2dd..00eb945 100644
--- a/audioplayer.c
+++ b/audioplayer.c
@@ -1,479 +1,479 @@
-/*
- VitaShell
- Copyright (C) 2015-2018, TheFloW
-
- 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, either version 3 of the License, or
- (at your option) any later version.
-
- 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 for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
-*/
-
-#include "main.h"
-#include "archive.h"
-#include "audioplayer.h"
-#include "file.h"
-#include "theme.h"
-#include "language.h"
-#include "utils.h"
-#include "audio/lrcparse.h"
-
-#include "audio/player.h"
-
-static struct fileInfo *fileinfo = NULL;
-static vita2d_texture *tex = NULL;
-
-
-/**
-* Calculate the x-axis position if draw text in center
-* @param[in] sx start x-axis
-* @param[in] ex end x-axis
-* @param[in] text
-* @return x-axis position
-*/
-float getCenteroffset(float sx,float ex,char* string){
- if(!string||(string[0] == '\0'))
- return sx;
-
- float drawWidthSpace = ex - sx;
- uint16_t stringWidth = pgf_text_width(string);
- return stringWidth > drawWidthSpace ? sx : sx + (drawWidthSpace - stringWidth) / 2 ;
-}
-
-/**
-* Try to load lrc file from audio path
-* @param[in] path audio path
-* @param[out] totalms set 0
-* @param[out] lyricsIndex set 0
-* @return Lyrics pointer , NULL is fail
-*/
-Lyrics* loadLyricsFile(const char *path, uint64_t *totalms, uint32_t *lyricsIndex){
- size_t pathlength = strlen(path);
- *totalms = *lyricsIndex = 0;
-
- while(pathlength > 0){
- if(path[pathlength] == '.'){
- break;
- }
- pathlength--;
- }
-
- if(pathlength < 0)
- return NULL;
-
- char lrcPath[pathlength + 5 * sizeof(char)];
- memccpy(lrcPath,path,sizeof(char),pathlength);//copy path string except filename extension
- strcpy(lrcPath+pathlength,".lrc");
-
- return lrcParseLoadWithFile(lrcPath);
-}
-
-/**
-* Draw the lyrics from the designated area
-* @param[in] lyrics Lyrics pointer
-* @param[in] cur_time_string Playing time string
-* @param[out] totalms Playing time (millisecond)
-* @param[out] lyricsIndex Index of lyrics
-* @param[in] lrcSpaceX Designated area starting point x
-* @param[in] lrcSpaceX Designated area starting point y
-*/
-void drawLyrics(Lyrics* lyrics, const char *cur_time_string, uint64_t* totalms, uint32_t* lyricsIndex, float lrcSpaceX, float lrcSpaceY){
- if(!lyrics)
- return;
-
- char hourString[3];
- char minuteString[3];
- char secondString[3];
-
- strncpy(hourString,cur_time_string,sizeof(hourString));
- strncpy(minuteString,cur_time_string + 3,sizeof(minuteString));
- strncpy(secondString,cur_time_string + 6,sizeof(secondString));
-
- *totalms = (((atoi(hourString) * 60) + atoi(minuteString)) * 60 + atoi(secondString)) * 1000;
-
- uint32_t m_index = *lyricsIndex >= 1 ? (*lyricsIndex - 1) : *lyricsIndex;
- float right_max_x = SCREEN_WIDTH - SHELL_MARGIN_X;
- //draw current lyrics
- pgf_draw_textf(getCenteroffset(lrcSpaceX,right_max_x,lyrics->lrclines[m_index].word),lrcSpaceY, AUDIO_INFO_ASSIGN, "%s",lyrics->lrclines[m_index].word);
-
- int i;
- for (i = 1;i < 7; i++){//draw 6 line lyrics for preview
- int n_index = m_index + i;
- if(n_index + 1 > lyrics->lyricscount)
- break;
- pgf_draw_textf(getCenteroffset(lrcSpaceX,right_max_x,lyrics->lrclines[n_index].word),lrcSpaceY + FONT_Y_SPACE * i, AUDIO_INFO, "%s",lyrics->lrclines[n_index].word);
- }
-
- if (*totalms >= (lyrics->lrclines[*lyricsIndex].totalms) ){
- *lyricsIndex = *lyricsIndex + 1;
- } else if (( *lyricsIndex >= 1 ) & ( *totalms < (lyrics->lrclines[*lyricsIndex - 1].totalms ))) {
- *lyricsIndex = *lyricsIndex - 1;
- }
-}
-
-void shortenString(char *out, const char *in, int width) {
- strcpy(out, in);
-
- int i;
- for (i = strlen(out)-1; i > 0; i--) {
- if (pgf_text_width(out) < width)
- break;
-
- out[i] = '\0';
- }
-}
-
-vita2d_texture *getAlternativeCoverImage(const char *file) {
- char path[MAX_PATH_LENGTH];
-
- char *p = strrchr(file, '/');
- if (p) {
- *p = '\0';
-
- snprintf(path, MAX_PATH_LENGTH - 1, "%s/cover.jpg", file);
- if (checkFileExist(path)) {
- *p = '/';
- return vita2d_load_JPEG_file(path);
- }
-
- snprintf(path, MAX_PATH_LENGTH - 1, "%s/folder.jpg", file);
- if (checkFileExist(path)) {
- *p = '/';
- return vita2d_load_JPEG_file(path);
- }
-
- *p = '/';
- }
-
- return NULL;
-}
-
-void getAudioInfo(const char *file) {
- char *buffer = NULL;
-
- fileinfo = getInfoFunct();
-
- if (tex) {
- vita2d_wait_rendering_done();
- vita2d_free_texture(tex);
- tex = NULL;
- }
-
- switch (fileinfo->encapsulatedPictureType) {
- case JPEG_IMAGE:
- case PNG_IMAGE:
- {
- SceUID fd = sceIoOpen(file, SCE_O_RDONLY, 0);
- if (fd >= 0) {
- char *buffer = malloc(fileinfo->encapsulatedPictureLength);
- if (buffer) {
- sceIoLseek32(fd, fileinfo->encapsulatedPictureOffset, SCE_SEEK_SET);
- sceIoRead(fd, buffer, fileinfo->encapsulatedPictureLength);
- sceIoClose(fd);
-
- if (fileinfo->encapsulatedPictureType == JPEG_IMAGE)
- tex = vita2d_load_JPEG_buffer(buffer, fileinfo->encapsulatedPictureLength);
-
- if (fileinfo->encapsulatedPictureType == PNG_IMAGE)
- tex = vita2d_load_PNG_buffer(buffer);
-
- if (tex)
- vita2d_texture_set_filters(tex, SCE_GXM_TEXTURE_FILTER_LINEAR, SCE_GXM_TEXTURE_FILTER_LINEAR);
-
- free(buffer);
- }
-
- break;
- }
- }
- }
-
- if (!tex)
- tex = getAlternativeCoverImage(file);
-}
-
-int audioPlayer(const char *file, int type, FileList *list, FileListEntry *entry, int *base_pos, int *rel_pos) {
- static int speed_list[] = { -7, -3, -1, 0, 1, 3, 7 };
- #define N_SPEED (sizeof(speed_list) / sizeof(int))
-
- sceAppMgrAcquireBgmPort();
-
- powerLock();
-
- setAudioFunctions(type);
-
- initFunct(0);
- loadFunct((char *)file);
- playFunct();
-
- getAudioInfo(file);
-
- uint64_t totalms = 0;
- uint32_t lyricsIndex = 0;
- Lyrics* lyrics = loadLyricsFile(file,&totalms,&lyricsIndex);
-
- int scroll_count = 0;
- float scroll_x = 0.0f;
-
- while (1) {
- char cur_time_string[12];
- getTimeStringFunct(cur_time_string);
-
- readPad();
-
- // Cancel
- if (pressed_pad[PAD_CANCEL]) {
- break;
- }
-
- // Display off
- if (pressed_pad[PAD_TRIANGLE]) {
- scePowerRequestDisplayOff();
- }
-
- // Toggle play/pause
- if (pressed_pad[PAD_ENTER]) {
- if (isPlayingFunct() && getPlayingSpeedFunct() == 0) {
- pauseFunct();
- } else {
- setPlayingSpeedFunct(0);
- playFunct();
- }
- }
-
- if (pressed_pad[PAD_LEFT] || pressed_pad[PAD_RIGHT]) {
- int speed = getPlayingSpeedFunct();
-
- if (pressed_pad[PAD_LEFT]) {
- int i;
- for (i = 0; i < N_SPEED; i++) {
- if (speed_list[i] == speed) {
- if (i > 0)
- speed = speed_list[i-1];
- break;
- }
- }
- }
-
- if (pressed_pad[PAD_RIGHT]) {
- int i;
- for (i = 0; i < N_SPEED; i++) {
- if (speed_list[i] == speed) {
- if (i < N_SPEED - 1)
- speed = speed_list[i + 1];
- break;
- }
- }
- }
-
- setPlayingSpeedFunct(speed);
-
- playFunct();
- }
-
- // Previous/next song.
- if (getPercentageFunct() == 100.0f || endOfStreamFunct() ||
- pressed_pad[PAD_LTRIGGER] || pressed_pad[PAD_RTRIGGER]) {
- int previous = pressed_pad[PAD_LTRIGGER];
- if (previous && strcmp(cur_time_string, "00:00:00") != 0) {
- lrcParseClose(lyrics);
- endFunct();
- initFunct(0);
- loadFunct((char *)file);
- playFunct();
-
- getAudioInfo(file);
-
- lyrics = loadLyricsFile(file,&totalms,&lyricsIndex);
-
- } else {
- int available = 0;
-
- int old_base_pos = *base_pos;
- int old_rel_pos = *rel_pos;
- FileListEntry *old_entry = entry;
-
- if (getPercentageFunct() == 100.0f && !endOfStreamFunct())
- previous = 1;
-
- if (endOfStreamFunct())
- previous = 0;
-
- while (previous ? entry->previous : entry->next) {
- entry = previous ? entry->previous : entry->next;
-
- if (previous) {
- if (*rel_pos > 0) {
- (*rel_pos)--;
- } else if (*base_pos > 0) {
- (*base_pos)--;
- }
- } else {
- if ((*rel_pos + 1) < list->length) {
- if ((*rel_pos + 1) < MAX_POSITION) {
- (*rel_pos)++;
- } else if ((*base_pos+*rel_pos + 1) < list->length) {
- (*base_pos)++;
- }
- }
- }
-
- if (!entry->is_folder) {
- char path[MAX_PATH_LENGTH];
- snprintf(path, MAX_PATH_LENGTH - 1, "%s%s", list->path, entry->name);
- int type = getFileType(path);
- if (type == FILE_TYPE_MP3 || type == FILE_TYPE_OGG) {
- file = path;
-
- lrcParseClose(lyrics);
- endFunct();
-
- setAudioFunctions(type);
-
- initFunct(0);
- loadFunct((char *)file);
- playFunct();
-
- getAudioInfo(file);
-
- lyrics = loadLyricsFile(file,&totalms,&lyricsIndex);
-
- available = 1;
- break;
- }
- }
- }
-
- if (!available) {
- *base_pos = old_base_pos;
- *rel_pos = old_rel_pos;
- entry = old_entry;
- break;
- }
- }
- }
-
- // Start drawing
- startDrawing(bg_audio_image);
-
- // Draw shell info
- drawShellInfo(file);
-
- float cover_size = MAX_ENTRIES * FONT_Y_SPACE;
-
- // Cover
- if (tex) {
- vita2d_draw_texture_scale(tex, SHELL_MARGIN_X, START_Y, cover_size / vita2d_texture_get_width(tex), cover_size / vita2d_texture_get_height(tex));
- } else {
- vita2d_draw_texture(cover_image, SHELL_MARGIN_X, START_Y);
- }
-
- // Info
- float x = 2.0f * SHELL_MARGIN_X + cover_size;
-
- pgf_draw_text(x, START_Y + (0 * FONT_Y_SPACE), AUDIO_INFO_ASSIGN, language_container[TITLE]);
- pgf_draw_text(x, START_Y + (1 * FONT_Y_SPACE), AUDIO_INFO_ASSIGN, language_container[ALBUM]);
- pgf_draw_text(x, START_Y + (2 * FONT_Y_SPACE), AUDIO_INFO_ASSIGN, language_container[ARTIST]);
- pgf_draw_text(x, START_Y + (3 * FONT_Y_SPACE), AUDIO_INFO_ASSIGN, language_container[GENRE]);
- pgf_draw_text(x, START_Y + (4 * FONT_Y_SPACE), AUDIO_INFO_ASSIGN, language_container[YEAR]);
-
- x += 120.0f;
-
- vita2d_enable_clipping();
- vita2d_set_clip_rectangle(x + 1.0f, START_Y, x + 1.0f + 390.0f, START_Y + (5 * FONT_Y_SPACE));
-
- float title_x = x;
- uint32_t color = AUDIO_INFO;
-
- int width = (int)pgf_text_width(fileinfo->title);
- if (width >= 390.0f) {
- if (scroll_count < 60) {
- scroll_x = title_x;
- } else if (scroll_count < width + 90) {
- scroll_x--;
- } else if (scroll_count < width + 120) {
- color = (color & 0x00FFFFFF) | ((((color >> 24) * (scroll_count - width - 90)) / 30) << 24); // fade-in in 0.5s
- scroll_x = title_x;
- } else {
- scroll_count = 0;
- }
-
- scroll_count++;
-
- title_x = scroll_x;
- }
-
- pgf_draw_text(title_x, START_Y + (0 * FONT_Y_SPACE), color, fileinfo->title[0] == '\0' ? "-" : fileinfo->title);
- pgf_draw_text(x, START_Y + (1 * FONT_Y_SPACE), AUDIO_INFO, fileinfo->album[0] == '\0' ? "-" : fileinfo->album);
- pgf_draw_text(x, START_Y + (2 * FONT_Y_SPACE), AUDIO_INFO, fileinfo->artist[0] == '\0' ? "-" : fileinfo->artist);
- pgf_draw_text(x, START_Y + (3 * FONT_Y_SPACE), AUDIO_INFO, fileinfo->genre[0] == '\0' ? "-" : fileinfo->genre);
- pgf_draw_text(x, START_Y + (4 * FONT_Y_SPACE), AUDIO_INFO, fileinfo->year[0] == '\0' ? "-" : fileinfo->year);
-
- vita2d_disable_clipping();
-
- x -= 120.0f;
-
- drawLyrics(lyrics, cur_time_string, &totalms, &lyricsIndex, x, START_Y + (6 * FONT_Y_SPACE));
-
- float y = SCREEN_HEIGHT - 6.0f * SHELL_MARGIN_Y;
-
- // Icon
- vita2d_texture *icon = NULL;
-
- if (getPlayingSpeedFunct() != 0) {
- if (getPlayingSpeedFunct() < 0) {
- icon = fastrewind_image;
- } else {
- icon = fastforward_image;
- }
-
- pgf_draw_textf(x + 45.0f, y, AUDIO_SPEED, "%dx", abs(getPlayingSpeedFunct() + (getPlayingSpeedFunct() < 0 ? -1 : 1)));
- } else {
- if (isPlayingFunct()) {
- icon = pause_image;
- } else {
- icon = play_image;
- }
- }
-
- vita2d_draw_texture(icon, x, y + 3.0f);
-
- // Time
- char string[32];
- sprintf(string, "%s / %s", cur_time_string, fileinfo->strLength);
- float time_x = ALIGN_RIGHT(SCREEN_WIDTH-SHELL_MARGIN_X, pgf_text_width(string));
-
- int w = pgf_draw_text(time_x, y, AUDIO_TIME_CURRENT, cur_time_string);
- pgf_draw_text(time_x + (float)w, y, AUDIO_TIME_SLASH, " /");
- pgf_draw_text(ALIGN_RIGHT(SCREEN_WIDTH-SHELL_MARGIN_X, pgf_text_width(fileinfo->strLength)), y, AUDIO_TIME_TOTAL, fileinfo->strLength);
-
- float length = SCREEN_WIDTH - 3.0f * SHELL_MARGIN_X - cover_size;
- vita2d_draw_rectangle(x, (y) + FONT_Y_SPACE + 10.0f, length, 8, AUDIO_TIME_BAR_BG);
- vita2d_draw_rectangle(x, (y) + FONT_Y_SPACE + 10.0f, getPercentageFunct() * length / 100.0f, 8, AUDIO_TIME_BAR);
-
- // End drawing
- endDrawing();
- }
-
- if (tex) {
- vita2d_wait_rendering_done();
- vita2d_free_texture(tex);
- tex = NULL;
- }
-
- lrcParseClose(lyrics);
- endFunct();
-
- powerUnlock();
-
- sceAppMgrReleaseBgmPort();
-
- return 0;
-}
+/*
+ VitaShell
+ Copyright (C) 2015-2018, TheFloW
+
+ 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, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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 for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+#include "main.h"
+#include "archive.h"
+#include "audioplayer.h"
+#include "file.h"
+#include "theme.h"
+#include "language.h"
+#include "utils.h"
+#include "audio/lrcparse.h"
+
+#include "audio/player.h"
+
+static struct fileInfo *fileinfo = NULL;
+static vita2d_texture *tex = NULL;
+
+
+/**
+* Calculate the x-axis position if draw text in center
+* @param[in] sx start x-axis
+* @param[in] ex end x-axis
+* @param[in] text
+* @return x-axis position
+*/
+float getCenteroffset(float sx,float ex,char* string){
+ if(!string||(string[0] == '\0'))
+ return sx;
+
+ float drawWidthSpace = ex - sx;
+ uint16_t stringWidth = pgf_text_width(string);
+ return stringWidth > drawWidthSpace ? sx : sx + (drawWidthSpace - stringWidth) / 2 ;
+}
+
+/**
+* Try to load lrc file from audio path
+* @param[in] path audio path
+* @param[out] totalms set 0
+* @param[out] lyricsIndex set 0
+* @return Lyrics pointer , NULL is fail
+*/
+Lyrics* loadLyricsFile(const char *path, uint64_t *totalms, uint32_t *lyricsIndex){
+ size_t pathlength = strlen(path);
+ *totalms = *lyricsIndex = 0;
+
+ while(pathlength > 0){
+ if(path[pathlength] == '.'){
+ break;
+ }
+ pathlength--;
+ }
+
+ if(pathlength < 0)
+ return NULL;
+
+ char lrcPath[pathlength + 5 * sizeof(char)];
+ memccpy(lrcPath,path,sizeof(char),pathlength);//copy path string except filename extension
+ strcpy(lrcPath+pathlength,".lrc");
+
+ return lrcParseLoadWithFile(lrcPath);
+}
+
+/**
+* Draw the lyrics from the designated area
+* @param[in] lyrics Lyrics pointer
+* @param[in] cur_time_string Playing time string
+* @param[out] totalms Playing time (millisecond)
+* @param[out] lyricsIndex Index of lyrics
+* @param[in] lrcSpaceX Designated area starting point x
+* @param[in] lrcSpaceX Designated area starting point y
+*/
+void drawLyrics(Lyrics* lyrics, const char *cur_time_string, uint64_t* totalms, uint32_t* lyricsIndex, float lrcSpaceX, float lrcSpaceY){
+ if(!lyrics)
+ return;
+
+ char hourString[3];
+ char minuteString[3];
+ char secondString[3];
+
+ strncpy(hourString,cur_time_string,sizeof(hourString));
+ strncpy(minuteString,cur_time_string + 3,sizeof(minuteString));
+ strncpy(secondString,cur_time_string + 6,sizeof(secondString));
+
+ *totalms = (((atoi(hourString) * 60) + atoi(minuteString)) * 60 + atoi(secondString)) * 1000;
+
+ uint32_t m_index = *lyricsIndex >= 1 ? (*lyricsIndex - 1) : *lyricsIndex;
+ float right_max_x = SCREEN_WIDTH - SHELL_MARGIN_X;
+ //draw current lyrics
+ pgf_draw_textf(getCenteroffset(lrcSpaceX,right_max_x,lyrics->lrclines[m_index].word),lrcSpaceY, AUDIO_INFO_ASSIGN, "%s",lyrics->lrclines[m_index].word);
+
+ int i;
+ for (i = 1;i < 7; i++){//draw 6 line lyrics for preview
+ int n_index = m_index + i;
+ if(n_index + 1 > lyrics->lyricscount)
+ break;
+ pgf_draw_textf(getCenteroffset(lrcSpaceX,right_max_x,lyrics->lrclines[n_index].word),lrcSpaceY + FONT_Y_SPACE * i, AUDIO_INFO, "%s",lyrics->lrclines[n_index].word);
+ }
+
+ if (*totalms >= (lyrics->lrclines[*lyricsIndex].totalms) ){
+ *lyricsIndex = *lyricsIndex + 1;
+ } else if (( *lyricsIndex >= 1 ) & ( *totalms < (lyrics->lrclines[*lyricsIndex - 1].totalms ))) {
+ *lyricsIndex = *lyricsIndex - 1;
+ }
+}
+
+void shortenString(char *out, const char *in, int width) {
+ strcpy(out, in);
+
+ int i;
+ for (i = strlen(out)-1; i > 0; i--) {
+ if (pgf_text_width(out) < width)
+ break;
+
+ out[i] = '\0';
+ }
+}
+
+vita2d_texture *getAlternativeCoverImage(const char *file) {
+ char path[MAX_PATH_LENGTH];
+
+ char *p = strrchr(file, '/');
+ if (p) {
+ *p = '\0';
+
+ snprintf(path, MAX_PATH_LENGTH - 1, "%s/cover.jpg", file);
+ if (checkFileExist(path)) {
+ *p = '/';
+ return vita2d_load_JPEG_file(path);
+ }
+
+ snprintf(path, MAX_PATH_LENGTH - 1, "%s/folder.jpg", file);
+ if (checkFileExist(path)) {
+ *p = '/';
+ return vita2d_load_JPEG_file(path);
+ }
+
+ *p = '/';
+ }
+
+ return NULL;
+}
+
+void getAudioInfo(const char *file) {
+ char *buffer = NULL;
+
+ fileinfo = getInfoFunct();
+
+ if (tex) {
+ vita2d_wait_rendering_done();
+ vita2d_free_texture(tex);
+ tex = NULL;
+ }
+
+ switch (fileinfo->encapsulatedPictureType) {
+ case JPEG_IMAGE:
+ case PNG_IMAGE:
+ {
+ SceUID fd = sceIoOpen(file, SCE_O_RDONLY, 0);
+ if (fd >= 0) {
+ char *buffer = malloc(fileinfo->encapsulatedPictureLength);
+ if (buffer) {
+ sceIoLseek32(fd, fileinfo->encapsulatedPictureOffset, SCE_SEEK_SET);
+ sceIoRead(fd, buffer, fileinfo->encapsulatedPictureLength);
+ sceIoClose(fd);
+
+ if (fileinfo->encapsulatedPictureType == JPEG_IMAGE)
+ tex = vita2d_load_JPEG_buffer(buffer, fileinfo->encapsulatedPictureLength);
+
+ if (fileinfo->encapsulatedPictureType == PNG_IMAGE)
+ tex = vita2d_load_PNG_buffer(buffer);
+
+ if (tex)
+ vita2d_texture_set_filters(tex, SCE_GXM_TEXTURE_FILTER_LINEAR, SCE_GXM_TEXTURE_FILTER_LINEAR);
+
+ free(buffer);
+ }
+
+ break;
+ }
+ }
+ }
+
+ if (!tex)
+ tex = getAlternativeCoverImage(file);
+}
+
+int audioPlayer(const char *file, int type, FileList *list, FileListEntry *entry, int *base_pos, int *rel_pos) {
+ static int speed_list[] = { -7, -3, -1, 0, 1, 3, 7 };
+ #define N_SPEED (sizeof(speed_list) / sizeof(int))
+
+ sceAppMgrAcquireBgmPort();
+
+ powerLock();
+
+ setAudioFunctions(type);
+
+ initFunct(0);
+ loadFunct((char *)file);
+ playFunct();
+
+ getAudioInfo(file);
+
+ uint64_t totalms = 0;
+ uint32_t lyricsIndex = 0;
+ Lyrics* lyrics = loadLyricsFile(file,&totalms,&lyricsIndex);
+
+ int scroll_count = 0;
+ float scroll_x = 0.0f;
+
+ while (1) {
+ char cur_time_string[12];
+ getTimeStringFunct(cur_time_string);
+
+ readPad();
+
+ // Cancel
+ if (pressed_pad[PAD_CANCEL]) {
+ break;
+ }
+
+ // Display off
+ if (pressed_pad[PAD_TRIANGLE]) {
+ scePowerRequestDisplayOff();
+ }
+
+ // Toggle play/pause
+ if (pressed_pad[PAD_ENTER]) {
+ if (isPlayingFunct() && getPlayingSpeedFunct() == 0) {
+ pauseFunct();
+ } else {
+ setPlayingSpeedFunct(0);
+ playFunct();
+ }
+ }
+
+ if (pressed_pad[PAD_LEFT] || pressed_pad[PAD_RIGHT]) {
+ int speed = getPlayingSpeedFunct();
+
+ if (pressed_pad[PAD_LEFT]) {
+ int i;
+ for (i = 0; i < N_SPEED; i++) {
+ if (speed_list[i] == speed) {
+ if (i > 0)
+ speed = speed_list[i-1];
+ break;
+ }
+ }
+ }
+
+ if (pressed_pad[PAD_RIGHT]) {
+ int i;
+ for (i = 0; i < N_SPEED; i++) {
+ if (speed_list[i] == speed) {
+ if (i < N_SPEED - 1)
+ speed = speed_list[i + 1];
+ break;
+ }
+ }
+ }
+
+ setPlayingSpeedFunct(speed);
+
+ playFunct();
+ }
+
+ // Previous/next song.
+ if (getPercentageFunct() == 100.0f || endOfStreamFunct() ||
+ pressed_pad[PAD_LTRIGGER] || pressed_pad[PAD_RTRIGGER]) {
+ int previous = pressed_pad[PAD_LTRIGGER];
+ if (previous && strcmp(cur_time_string, "00:00:00") != 0) {
+ lrcParseClose(lyrics);
+ endFunct();
+ initFunct(0);
+ loadFunct((char *)file);
+ playFunct();
+
+ getAudioInfo(file);
+
+ lyrics = loadLyricsFile(file,&totalms,&lyricsIndex);
+
+ } else {
+ int available = 0;
+
+ int old_base_pos = *base_pos;
+ int old_rel_pos = *rel_pos;
+ FileListEntry *old_entry = entry;
+
+ if (getPercentageFunct() == 100.0f && !endOfStreamFunct())
+ previous = 1;
+
+ if (endOfStreamFunct())
+ previous = 0;
+
+ while (previous ? entry->previous : entry->next) {
+ entry = previous ? entry->previous : entry->next;
+
+ if (previous) {
+ if (*rel_pos > 0) {
+ (*rel_pos)--;
+ } else if (*base_pos > 0) {
+ (*base_pos)--;
+ }
+ } else {
+ if ((*rel_pos + 1) < list->length) {
+ if ((*rel_pos + 1) < MAX_POSITION) {
+ (*rel_pos)++;
+ } else if ((*base_pos+*rel_pos + 1) < list->length) {
+ (*base_pos)++;
+ }
+ }
+ }
+
+ if (!entry->is_folder) {
+ char path[MAX_PATH_LENGTH];
+ snprintf(path, MAX_PATH_LENGTH - 1, "%s%s", list->path, entry->name);
+ int type = getFileType(path);
+ if (type == FILE_TYPE_MP3 || type == FILE_TYPE_OGG) {
+ file = path;
+
+ lrcParseClose(lyrics);
+ endFunct();
+
+ setAudioFunctions(type);
+
+ initFunct(0);
+ loadFunct((char *)file);
+ playFunct();
+
+ getAudioInfo(file);
+
+ lyrics = loadLyricsFile(file,&totalms,&lyricsIndex);
+
+ available = 1;
+ break;
+ }
+ }
+ }
+
+ if (!available) {
+ *base_pos = old_base_pos;
+ *rel_pos = old_rel_pos;
+ entry = old_entry;
+ break;
+ }
+ }
+ }
+
+ // Start drawing
+ startDrawing(bg_audio_image);
+
+ // Draw shell info
+ drawShellInfo(file);
+
+ float cover_size = MAX_ENTRIES * FONT_Y_SPACE;
+
+ // Cover
+ if (tex) {
+ vita2d_draw_texture_scale(tex, SHELL_MARGIN_X, START_Y, cover_size / vita2d_texture_get_width(tex), cover_size / vita2d_texture_get_height(tex));
+ } else {
+ vita2d_draw_texture(cover_image, SHELL_MARGIN_X, START_Y);
+ }
+
+ // Info
+ float x = 2.0f * SHELL_MARGIN_X + cover_size;
+
+ pgf_draw_text(x, START_Y + (0 * FONT_Y_SPACE), AUDIO_INFO_ASSIGN, language_container[TITLE]);
+ pgf_draw_text(x, START_Y + (1 * FONT_Y_SPACE), AUDIO_INFO_ASSIGN, language_container[ALBUM]);
+ pgf_draw_text(x, START_Y + (2 * FONT_Y_SPACE), AUDIO_INFO_ASSIGN, language_container[ARTIST]);
+ pgf_draw_text(x, START_Y + (3 * FONT_Y_SPACE), AUDIO_INFO_ASSIGN, language_container[GENRE]);
+ pgf_draw_text(x, START_Y + (4 * FONT_Y_SPACE), AUDIO_INFO_ASSIGN, language_container[YEAR]);
+
+ x += 120.0f;
+
+ vita2d_enable_clipping();
+ vita2d_set_clip_rectangle(x + 1.0f, START_Y, x + 1.0f + 390.0f, START_Y + (5 * FONT_Y_SPACE));
+
+ float title_x = x;
+ uint32_t color = AUDIO_INFO;
+
+ int width = (int)pgf_text_width(fileinfo->title);
+ if (width >= 390.0f) {
+ if (scroll_count < 60) {
+ scroll_x = title_x;
+ } else if (scroll_count < width + 90) {
+ scroll_x--;
+ } else if (scroll_count < width + 120) {
+ color = (color & 0x00FFFFFF) | ((((color >> 24) * (scroll_count - width - 90)) / 30) << 24); // fade-in in 0.5s
+ scroll_x = title_x;
+ } else {
+ scroll_count = 0;
+ }
+
+ scroll_count++;
+
+ title_x = scroll_x;
+ }
+
+ pgf_draw_text(title_x, START_Y + (0 * FONT_Y_SPACE), color, fileinfo->title[0] == '\0' ? "-" : fileinfo->title);
+ pgf_draw_text(x, START_Y + (1 * FONT_Y_SPACE), AUDIO_INFO, fileinfo->album[0] == '\0' ? "-" : fileinfo->album);
+ pgf_draw_text(x, START_Y + (2 * FONT_Y_SPACE), AUDIO_INFO, fileinfo->artist[0] == '\0' ? "-" : fileinfo->artist);
+ pgf_draw_text(x, START_Y + (3 * FONT_Y_SPACE), AUDIO_INFO, fileinfo->genre[0] == '\0' ? "-" : fileinfo->genre);
+ pgf_draw_text(x, START_Y + (4 * FONT_Y_SPACE), AUDIO_INFO, fileinfo->year[0] == '\0' ? "-" : fileinfo->year);
+
+ vita2d_disable_clipping();
+
+ x -= 120.0f;
+
+ drawLyrics(lyrics, cur_time_string, &totalms, &lyricsIndex, x, START_Y + (6 * FONT_Y_SPACE));
+
+ float y = SCREEN_HEIGHT - 6.0f * SHELL_MARGIN_Y;
+
+ // Icon
+ vita2d_texture *icon = NULL;
+
+ if (getPlayingSpeedFunct() != 0) {
+ if (getPlayingSpeedFunct() < 0) {
+ icon = fastrewind_image;
+ } else {
+ icon = fastforward_image;
+ }
+
+ pgf_draw_textf(x + 45.0f, y, AUDIO_SPEED, "%dx", abs(getPlayingSpeedFunct() + (getPlayingSpeedFunct() < 0 ? -1 : 1)));
+ } else {
+ if (isPlayingFunct()) {
+ icon = pause_image;
+ } else {
+ icon = play_image;
+ }
+ }
+
+ vita2d_draw_texture(icon, x, y + 3.0f);
+
+ // Time
+ char string[32];
+ sprintf(string, "%s / %s", cur_time_string, fileinfo->strLength);
+ float time_x = ALIGN_RIGHT(SCREEN_WIDTH-SHELL_MARGIN_X, pgf_text_width(string));
+
+ int w = pgf_draw_text(time_x, y, AUDIO_TIME_CURRENT, cur_time_string);
+ pgf_draw_text(time_x + (float)w, y, AUDIO_TIME_SLASH, " /");
+ pgf_draw_text(ALIGN_RIGHT(SCREEN_WIDTH-SHELL_MARGIN_X, pgf_text_width(fileinfo->strLength)), y, AUDIO_TIME_TOTAL, fileinfo->strLength);
+
+ float length = SCREEN_WIDTH - 3.0f * SHELL_MARGIN_X - cover_size;
+ vita2d_draw_rectangle(x, (y) + FONT_Y_SPACE + 10.0f, length, 8, AUDIO_TIME_BAR_BG);
+ vita2d_draw_rectangle(x, (y) + FONT_Y_SPACE + 10.0f, getPercentageFunct() * length / 100.0f, 8, AUDIO_TIME_BAR);
+
+ // End drawing
+ endDrawing();
+ }
+
+ if (tex) {
+ vita2d_wait_rendering_done();
+ vita2d_free_texture(tex);
+ tex = NULL;
+ }
+
+ lrcParseClose(lyrics);
+ endFunct();
+
+ powerUnlock();
+
+ sceAppMgrReleaseBgmPort();
+
+ return 0;
+}
diff --git a/audioplayer.h b/audioplayer.h
index c75e8f4..96b6062 100644
--- a/audioplayer.h
+++ b/audioplayer.h
@@ -1,24 +1,24 @@
-/*
- VitaShell
- Copyright (C) 2015-2018, TheFloW
-
- 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, either version 3 of the License, or
- (at your option) any later version.
-
- 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 for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
-*/
-
-#ifndef __AUDIOPLAYER_H__
-#define __AUDIOPLAYER_H__
-
-int audioPlayer(const char *file, int type, FileList *list, FileListEntry *entry, int *base_pos, int *rel_pos);
-
+/*
+ VitaShell
+ Copyright (C) 2015-2018, TheFloW
+
+ 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, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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 for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+#ifndef __AUDIOPLAYER_H__
+#define __AUDIOPLAYER_H__
+
+int audioPlayer(const char *file, int type, FileList *list, FileListEntry *entry, int *base_pos, int *rel_pos);
+
#endif
\ No newline at end of file
diff --git a/coredump.c b/coredump.c
index e1ac59d..fa3c664 100644
--- a/coredump.c
+++ b/coredump.c
@@ -1,337 +1,337 @@
-/*
- VitaShell
- Copyright (C) 2015-2018, TheFloW
-
- 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, either version 3 of the License, or
- (at your option) any later version.
-
- 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 for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
-*/
-
-#include "main.h"
-#include "file.h"
-#include "utils.h"
-#include "theme.h"
-#include "coredump.h"
-#include "elf.h"
-
-typedef struct {
- int unk_0; // 0x00
- int size; // 0x04
- int unk_8; // 0x08
- char name[16]; // 0x0C
- int unk_1C; // 0x1C
- int num; // 0x20
-} InfoHeader; // 0x24
-
-typedef struct {
- int unk; // 0x00
- int perm; // 0x04
- uint32_t addr; // 0x08
- uint32_t size; // 0x0C
- int unk_10; // 0x10
-} ModuleSegment; // 0x14
-
-typedef struct {
- int unk_0; // 0x00
- int uid; // 0x04
- int sdk_version; // 0x08
- int version; // 0xC
- int unk_10; // 0x10
- int addr_14; // 0x14
- int unk_18; // 0x18
- int addr_1C; // 0x1C
- int unk_20; // 0x20
- char name[28]; // 0x24
- int unk_44; // 0x40
- int unk_48; // 0x44 2
- uint32_t nid; // 0x48
- int num_segments; // 0x4C
- ModuleSegment segments[1]; // 0x50
- uint32_t addr[4]; // 0x78
-} ModuleInfoOneSegment; // 0x88
-
-typedef struct {
- int unk_0; // 0x00
- int uid; // 0x04
- int sdk_version; // 0x08
- int version; // 0xC
- int unk_10; // 0x10
- int addr_14; // 0x14
- int unk_18; // 0x18
- int addr_1C; // 0x1C
- int unk_20; // 0x20
- char name[28]; // 0x24
- int unk_44; // 0x40
- int unk_48; // 0x44 2
- uint32_t nid; // 0x48
- int num_segments; // 0x4C
- ModuleSegment segments[2]; // 0x50
- uint32_t addr[4]; // 0x78
-} ModuleInfoTwoSegment; // 0x88
-
-typedef struct {
- int unk; // 0x00
- int uid; // 0x04
- char name[32]; // 0x08
- int type; // 0x28
- uint32_t vaddr; // 0x2C
- uint32_t vsize; // 0x30
- int unk_34;
- int unk_38;
- int unk_3C;
- int unk_40;
- int unk_44;
-} MemBlkInfo; // 0x48
-
-typedef struct {
- int size; // 0x00
- int uid; // 0x04
- char name[32]; // 0x08
- int unk_28; // 0x28
- int unk_2C[18]; // 0x2C
- int cause; // 0x74
- int unk_78[9]; // 0x78
- uint32_t pc; // 0x9C
- int unk_A0[10]; // 0xA0
-} ThreadInfo; // 0xC8
-
-typedef struct {
- int size; // 0x00
- int uid; // 0x04
- uint32_t regs[16]; // 0x08
- int unk[75]; // 0x48
- uint32_t bad_v_addr; // 0x174
-} ThreadRegInfo; // 0x178
-
-// ARM registers
-static char *regnames[] = { "a1", "a2", "a3", "a4",
- "v1", "v2", "v3", "v4",
- "v5", "v6", "v7", "v8",
- "ip", "sp", "lr", "pc" };
-
-static char *getCauseName(int cause) {
- switch (cause) {
- case 0x30002:
- return "Undefined instruction exception";
-
- case 0x30003:
- return "Prefetch abort exception";
-
- case 0x30004:
- return "Data abort exception";
-
- case 0x60080:
- return "Division by zero";
- }
-
- return "Unknown cause";
-}
-
-static int decompressGzip(uint8_t *dst, int size_dst, uint8_t *src, int size_src) {
- z_stream z;
- memset(&z, 0, sizeof(z_stream));
-
- z.avail_in = size_src;
- z.next_in = src;
- z.avail_out = size_dst;
- z.next_out = dst;
-
- if (inflateInit2(&z, 15 + 32) != Z_OK)
- return -1;
-
- if (inflate(&z, Z_FINISH) != Z_STREAM_END) {
- inflateEnd(&z);
- return -2;
- }
-
- inflateEnd(&z);
- return z.total_out;
-}
-
-int coredumpViewer(const char *file) {
- void *buffer = memalign(4096, BIG_BUFFER_SIZE);
- if (!buffer)
- return VITASHELL_ERROR_NO_MEMORY;
-
- int size = ReadFile(file, buffer, BIG_BUFFER_SIZE);
-
- if (*(uint16_t *)buffer == 0x8B1F) {
- void *out_buf = memalign(4096, BIG_BUFFER_SIZE);
- if (!out_buf) {
- free(buffer);
- return VITASHELL_ERROR_NO_MEMORY;
- }
-
- int out_size = decompressGzip(out_buf, BIG_BUFFER_SIZE, buffer, size);
- if (out_size < 0) {
- free(out_buf);
- free(buffer);
- return -3;
- }
-
- memcpy(buffer, out_buf, out_size);
-
- free(out_buf);
- }
-
- Elf32_Ehdr *ehdr = (Elf32_Ehdr *)buffer;
- Elf32_Phdr *phdr = (Elf32_Phdr *)((uint32_t)buffer + ehdr->e_phoff);
-
- if (ehdr->e_ident[EI_MAG0] != ELFMAG0 ||
- ehdr->e_ident[EI_MAG1] != ELFMAG1 ||
- ehdr->e_ident[EI_MAG2] != ELFMAG2 ||
- ehdr->e_ident[EI_MAG3] != ELFMAG3) {
- free(buffer);
- return VITASHELL_ERROR_INVALID_MAGIC;
- }
-
- char thname[32], modname[32];
- SceUID thid = -1, modid = -1;
- uint32_t epc = -1, rel_epc = -1;
- int cause = -1;
- uint32_t bad_v_addr = -1;
- uint32_t regs[16];
-
- int i;
- for (i = 0; i < ehdr->e_phnum; i++) {
- if (phdr[i].p_type == 0x4) {
- void *program = malloc(phdr[i].p_filesz);
- if (!program) {
- free(buffer);
- return VITASHELL_ERROR_NO_MEMORY;
- }
-
- memcpy(program, buffer + phdr[i].p_offset, phdr[i].p_filesz);
-
- InfoHeader *info = (InfoHeader *)program;
-
- if (strcmp(info->name, "THREAD_INFO") == 0) {
- int j;
- for (j = 0; j < ((InfoHeader *)program)->num; j++) {
- ThreadInfo *thread_info = (ThreadInfo *)(program + sizeof(InfoHeader));
- if (thread_info[j].cause != 0) {
- strcpy(thname, thread_info[j].name);
- thid = thread_info[j].uid;
- epc = thread_info[j].pc;
- cause = thread_info[j].cause;
- break;
- }
- }
- } else if (strcmp(info->name, "THREAD_REG_INFO") == 0) {
- int j;
- for (j = 0; j < ((InfoHeader *)program)->num; j++) {
- ThreadRegInfo *thread_reg_info = (ThreadRegInfo *)(program + sizeof(InfoHeader));
-
- if (thread_reg_info[j].uid == thid) {
- memcpy(®s, thread_reg_info[j].regs, sizeof(regs));
- bad_v_addr = thread_reg_info[j].bad_v_addr;
- break;
- }
- }
- } else if (strcmp(info->name, "MODULE_INFO") == 0) {
- uint32_t offset = 0;
-
- int j;
- for (j = 0; j < ((InfoHeader *)program)->num; j++) {
- ModuleInfoTwoSegment *mod_info = (ModuleInfoTwoSegment *)(program + sizeof(InfoHeader) + offset);
-
- if (epc >= mod_info->segments[0].addr && epc < (mod_info->segments[0].addr+mod_info->segments[0].size)) {
- strcpy(modname, mod_info->name);
- modid = mod_info->uid;
- rel_epc = epc - mod_info->segments[0].addr;
- break;
- }
-
- if (mod_info->num_segments == 2) {
- offset += sizeof(ModuleInfoTwoSegment);
- } else {
- offset += sizeof(ModuleInfoOneSegment);
- }
- }
- }
-
- free(program);
- }
- }
-
- while (1) {
- readPad();
-
- if (pressed_pad[PAD_CANCEL]) {
- break;
- }
-
- // Start drawing
- startDrawing(bg_text_image);
-
- // Draw shell info
- drawShellInfo(file);
-
- float y = START_Y;
-
- // Exception
- pgf_draw_text(SHELL_MARGIN_X, y, TEXT_COLOR, "Exception");
- pgf_draw_text(COREDUMP_INFO_X, y, TEXT_COLOR, getCauseName(cause));
- y += FONT_Y_SPACE;
-
- // Thread ID
- pgf_draw_text(SHELL_MARGIN_X, y, TEXT_COLOR, "Thread ID");
- pgf_draw_textf(COREDUMP_INFO_X, y, TEXT_COLOR, "0x%08X", thid);
- y += FONT_Y_SPACE;
-
- // Thread name
- pgf_draw_text(SHELL_MARGIN_X, y, TEXT_COLOR, "Thread name");
- pgf_draw_text(COREDUMP_INFO_X, y, TEXT_COLOR, thname);
- y += FONT_Y_SPACE;
-
- // EPC
- pgf_draw_text(SHELL_MARGIN_X, y, TEXT_COLOR, "EPC");
- if (rel_epc != -1)
- pgf_draw_textf(COREDUMP_INFO_X, y, TEXT_COLOR, "%s + 0x%08X", modname, rel_epc);
- else
- pgf_draw_textf(COREDUMP_INFO_X, y, TEXT_COLOR, "0x%08X", epc);
- y += FONT_Y_SPACE;
-
- // Cause
- pgf_draw_text(SHELL_MARGIN_X, y, TEXT_COLOR, "Cause");
- pgf_draw_textf(COREDUMP_INFO_X, y, TEXT_COLOR, "0x%08X", cause);
- y += FONT_Y_SPACE;
-
- // BadVAddr
- pgf_draw_text(SHELL_MARGIN_X, y, TEXT_COLOR, "BadVAddr");
- pgf_draw_textf(COREDUMP_INFO_X, y, TEXT_COLOR, "0x%08X", bad_v_addr);
- y += FONT_Y_SPACE;
-
- // Registers
- int j;
- for (j = 0; j < 4; j++) {
- float x = SHELL_MARGIN_X;
-
- int i;
- for (i = 0; i < 4; i++) {
- pgf_draw_textf(x, y, TEXT_COLOR, "%s:", regnames[j * 4 + i]);
- x += COREDUMP_REGISTER_NAME_SPACE;
-
- pgf_draw_textf(x, y, TEXT_COLOR, "0x%08X", regs[j * 4 + i]);
- x += COREDUMP_REGISTER_SPACE;
- }
-
- y += FONT_Y_SPACE;
- }
-
- // End drawing
- endDrawing();
- }
-
- free(buffer);
- return 0;
+/*
+ VitaShell
+ Copyright (C) 2015-2018, TheFloW
+
+ 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, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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 for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+#include "main.h"
+#include "file.h"
+#include "utils.h"
+#include "theme.h"
+#include "coredump.h"
+#include "elf.h"
+
+typedef struct {
+ int unk_0; // 0x00
+ int size; // 0x04
+ int unk_8; // 0x08
+ char name[16]; // 0x0C
+ int unk_1C; // 0x1C
+ int num; // 0x20
+} InfoHeader; // 0x24
+
+typedef struct {
+ int unk; // 0x00
+ int perm; // 0x04
+ uint32_t addr; // 0x08
+ uint32_t size; // 0x0C
+ int unk_10; // 0x10
+} ModuleSegment; // 0x14
+
+typedef struct {
+ int unk_0; // 0x00
+ int uid; // 0x04
+ int sdk_version; // 0x08
+ int version; // 0xC
+ int unk_10; // 0x10
+ int addr_14; // 0x14
+ int unk_18; // 0x18
+ int addr_1C; // 0x1C
+ int unk_20; // 0x20
+ char name[28]; // 0x24
+ int unk_44; // 0x40
+ int unk_48; // 0x44 2
+ uint32_t nid; // 0x48
+ int num_segments; // 0x4C
+ ModuleSegment segments[1]; // 0x50
+ uint32_t addr[4]; // 0x78
+} ModuleInfoOneSegment; // 0x88
+
+typedef struct {
+ int unk_0; // 0x00
+ int uid; // 0x04
+ int sdk_version; // 0x08
+ int version; // 0xC
+ int unk_10; // 0x10
+ int addr_14; // 0x14
+ int unk_18; // 0x18
+ int addr_1C; // 0x1C
+ int unk_20; // 0x20
+ char name[28]; // 0x24
+ int unk_44; // 0x40
+ int unk_48; // 0x44 2
+ uint32_t nid; // 0x48
+ int num_segments; // 0x4C
+ ModuleSegment segments[2]; // 0x50
+ uint32_t addr[4]; // 0x78
+} ModuleInfoTwoSegment; // 0x88
+
+typedef struct {
+ int unk; // 0x00
+ int uid; // 0x04
+ char name[32]; // 0x08
+ int type; // 0x28
+ uint32_t vaddr; // 0x2C
+ uint32_t vsize; // 0x30
+ int unk_34;
+ int unk_38;
+ int unk_3C;
+ int unk_40;
+ int unk_44;
+} MemBlkInfo; // 0x48
+
+typedef struct {
+ int size; // 0x00
+ int uid; // 0x04
+ char name[32]; // 0x08
+ int unk_28; // 0x28
+ int unk_2C[18]; // 0x2C
+ int cause; // 0x74
+ int unk_78[9]; // 0x78
+ uint32_t pc; // 0x9C
+ int unk_A0[10]; // 0xA0
+} ThreadInfo; // 0xC8
+
+typedef struct {
+ int size; // 0x00
+ int uid; // 0x04
+ uint32_t regs[16]; // 0x08
+ int unk[75]; // 0x48
+ uint32_t bad_v_addr; // 0x174
+} ThreadRegInfo; // 0x178
+
+// ARM registers
+static char *regnames[] = { "a1", "a2", "a3", "a4",
+ "v1", "v2", "v3", "v4",
+ "v5", "v6", "v7", "v8",
+ "ip", "sp", "lr", "pc" };
+
+static char *getCauseName(int cause) {
+ switch (cause) {
+ case 0x30002:
+ return "Undefined instruction exception";
+
+ case 0x30003:
+ return "Prefetch abort exception";
+
+ case 0x30004:
+ return "Data abort exception";
+
+ case 0x60080:
+ return "Division by zero";
+ }
+
+ return "Unknown cause";
+}
+
+static int decompressGzip(uint8_t *dst, int size_dst, uint8_t *src, int size_src) {
+ z_stream z;
+ memset(&z, 0, sizeof(z_stream));
+
+ z.avail_in = size_src;
+ z.next_in = src;
+ z.avail_out = size_dst;
+ z.next_out = dst;
+
+ if (inflateInit2(&z, 15 + 32) != Z_OK)
+ return -1;
+
+ if (inflate(&z, Z_FINISH) != Z_STREAM_END) {
+ inflateEnd(&z);
+ return -2;
+ }
+
+ inflateEnd(&z);
+ return z.total_out;
+}
+
+int coredumpViewer(const char *file) {
+ void *buffer = memalign(4096, BIG_BUFFER_SIZE);
+ if (!buffer)
+ return VITASHELL_ERROR_NO_MEMORY;
+
+ int size = ReadFile(file, buffer, BIG_BUFFER_SIZE);
+
+ if (*(uint16_t *)buffer == 0x8B1F) {
+ void *out_buf = memalign(4096, BIG_BUFFER_SIZE);
+ if (!out_buf) {
+ free(buffer);
+ return VITASHELL_ERROR_NO_MEMORY;
+ }
+
+ int out_size = decompressGzip(out_buf, BIG_BUFFER_SIZE, buffer, size);
+ if (out_size < 0) {
+ free(out_buf);
+ free(buffer);
+ return -3;
+ }
+
+ memcpy(buffer, out_buf, out_size);
+
+ free(out_buf);
+ }
+
+ Elf32_Ehdr *ehdr = (Elf32_Ehdr *)buffer;
+ Elf32_Phdr *phdr = (Elf32_Phdr *)((uint32_t)buffer + ehdr->e_phoff);
+
+ if (ehdr->e_ident[EI_MAG0] != ELFMAG0 ||
+ ehdr->e_ident[EI_MAG1] != ELFMAG1 ||
+ ehdr->e_ident[EI_MAG2] != ELFMAG2 ||
+ ehdr->e_ident[EI_MAG3] != ELFMAG3) {
+ free(buffer);
+ return VITASHELL_ERROR_INVALID_MAGIC;
+ }
+
+ char thname[32], modname[32];
+ SceUID thid = -1, modid = -1;
+ uint32_t epc = -1, rel_epc = -1;
+ int cause = -1;
+ uint32_t bad_v_addr = -1;
+ uint32_t regs[16];
+
+ int i;
+ for (i = 0; i < ehdr->e_phnum; i++) {
+ if (phdr[i].p_type == 0x4) {
+ void *program = malloc(phdr[i].p_filesz);
+ if (!program) {
+ free(buffer);
+ return VITASHELL_ERROR_NO_MEMORY;
+ }
+
+ memcpy(program, buffer + phdr[i].p_offset, phdr[i].p_filesz);
+
+ InfoHeader *info = (InfoHeader *)program;
+
+ if (strcmp(info->name, "THREAD_INFO") == 0) {
+ int j;
+ for (j = 0; j < ((InfoHeader *)program)->num; j++) {
+ ThreadInfo *thread_info = (ThreadInfo *)(program + sizeof(InfoHeader));
+ if (thread_info[j].cause != 0) {
+ strcpy(thname, thread_info[j].name);
+ thid = thread_info[j].uid;
+ epc = thread_info[j].pc;
+ cause = thread_info[j].cause;
+ break;
+ }
+ }
+ } else if (strcmp(info->name, "THREAD_REG_INFO") == 0) {
+ int j;
+ for (j = 0; j < ((InfoHeader *)program)->num; j++) {
+ ThreadRegInfo *thread_reg_info = (ThreadRegInfo *)(program + sizeof(InfoHeader));
+
+ if (thread_reg_info[j].uid == thid) {
+ memcpy(®s, thread_reg_info[j].regs, sizeof(regs));
+ bad_v_addr = thread_reg_info[j].bad_v_addr;
+ break;
+ }
+ }
+ } else if (strcmp(info->name, "MODULE_INFO") == 0) {
+ uint32_t offset = 0;
+
+ int j;
+ for (j = 0; j < ((InfoHeader *)program)->num; j++) {
+ ModuleInfoTwoSegment *mod_info = (ModuleInfoTwoSegment *)(program + sizeof(InfoHeader) + offset);
+
+ if (epc >= mod_info->segments[0].addr && epc < (mod_info->segments[0].addr+mod_info->segments[0].size)) {
+ strcpy(modname, mod_info->name);
+ modid = mod_info->uid;
+ rel_epc = epc - mod_info->segments[0].addr;
+ break;
+ }
+
+ if (mod_info->num_segments == 2) {
+ offset += sizeof(ModuleInfoTwoSegment);
+ } else {
+ offset += sizeof(ModuleInfoOneSegment);
+ }
+ }
+ }
+
+ free(program);
+ }
+ }
+
+ while (1) {
+ readPad();
+
+ if (pressed_pad[PAD_CANCEL]) {
+ break;
+ }
+
+ // Start drawing
+ startDrawing(bg_text_image);
+
+ // Draw shell info
+ drawShellInfo(file);
+
+ float y = START_Y;
+
+ // Exception
+ pgf_draw_text(SHELL_MARGIN_X, y, TEXT_COLOR, "Exception");
+ pgf_draw_text(COREDUMP_INFO_X, y, TEXT_COLOR, getCauseName(cause));
+ y += FONT_Y_SPACE;
+
+ // Thread ID
+ pgf_draw_text(SHELL_MARGIN_X, y, TEXT_COLOR, "Thread ID");
+ pgf_draw_textf(COREDUMP_INFO_X, y, TEXT_COLOR, "0x%08X", thid);
+ y += FONT_Y_SPACE;
+
+ // Thread name
+ pgf_draw_text(SHELL_MARGIN_X, y, TEXT_COLOR, "Thread name");
+ pgf_draw_text(COREDUMP_INFO_X, y, TEXT_COLOR, thname);
+ y += FONT_Y_SPACE;
+
+ // EPC
+ pgf_draw_text(SHELL_MARGIN_X, y, TEXT_COLOR, "EPC");
+ if (rel_epc != -1)
+ pgf_draw_textf(COREDUMP_INFO_X, y, TEXT_COLOR, "%s + 0x%08X", modname, rel_epc);
+ else
+ pgf_draw_textf(COREDUMP_INFO_X, y, TEXT_COLOR, "0x%08X", epc);
+ y += FONT_Y_SPACE;
+
+ // Cause
+ pgf_draw_text(SHELL_MARGIN_X, y, TEXT_COLOR, "Cause");
+ pgf_draw_textf(COREDUMP_INFO_X, y, TEXT_COLOR, "0x%08X", cause);
+ y += FONT_Y_SPACE;
+
+ // BadVAddr
+ pgf_draw_text(SHELL_MARGIN_X, y, TEXT_COLOR, "BadVAddr");
+ pgf_draw_textf(COREDUMP_INFO_X, y, TEXT_COLOR, "0x%08X", bad_v_addr);
+ y += FONT_Y_SPACE;
+
+ // Registers
+ int j;
+ for (j = 0; j < 4; j++) {
+ float x = SHELL_MARGIN_X;
+
+ int i;
+ for (i = 0; i < 4; i++) {
+ pgf_draw_textf(x, y, TEXT_COLOR, "%s:", regnames[j * 4 + i]);
+ x += COREDUMP_REGISTER_NAME_SPACE;
+
+ pgf_draw_textf(x, y, TEXT_COLOR, "0x%08X", regs[j * 4 + i]);
+ x += COREDUMP_REGISTER_SPACE;
+ }
+
+ y += FONT_Y_SPACE;
+ }
+
+ // End drawing
+ endDrawing();
+ }
+
+ free(buffer);
+ return 0;
}
\ No newline at end of file
diff --git a/coredump.h b/coredump.h
index 644a6bc..9076d5f 100644
--- a/coredump.h
+++ b/coredump.h
@@ -1,24 +1,24 @@
-/*
- VitaShell
- Copyright (C) 2015-2018, TheFloW
-
- 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, either version 3 of the License, or
- (at your option) any later version.
-
- 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 for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
-*/
-
-#ifndef __COREDUMP_H__
-#define __COREDUMP_H__
-
-int coredumpViewer(const char *file);
-
+/*
+ VitaShell
+ Copyright (C) 2015-2018, TheFloW
+
+ 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, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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 for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+#ifndef __COREDUMP_H__
+#define __COREDUMP_H__
+
+int coredumpViewer(const char *file);
+
#endif
\ No newline at end of file
diff --git a/l10n/german.txt b/l10n/german.txt
index d7db846..dacebb6 100644
--- a/l10n/german.txt
+++ b/l10n/german.txt
@@ -1,177 +1,177 @@
-# VitaShell German Translation by VegaRoXas and Tails32; updated by Ch3ck3r (VitaShell 1.62)
-
-# Allgemeine Texte
-ERROR = "Fehler 0x%08X."
-OK = "OK"
-YES = "Ja"
-NO = "Nein"
-CANCEL = "Abbrechen"
-ON = "An"
-OFF = "Aus"
-FILE_ = "Datei"
-FOLDER = "Ordner"
-
-# Prozess-Texte
-MOVING = "Verschiebe..."
-COPYING = "Kopiere..."
-DELETING = "Lösche..."
-EXPORTING = "Exportiere..."
-INSTALLING = "Installiere..."
-DOWNLOADING = "Lade herunter..."
-EXTRACTING = "Entpacke..."
-COMPRESSING = "Komprimiere..."
-HASHING = "Erstelle Hash..."
-REFRESHING = "Aktualisiere..."
-
-# Musik Player Texte
-TITLE = "Titel"
-ALBUM = "Album"
-ARTIST = "Künstler"
-GENRE = "Genre"
-YEAR = "Jahr"
-
-# Hex-Editor Texte
-OFFSET = "Offset"
-OPEN_HEX_EDITOR = "Im Hex-Editor öffnen"
-
-# Text-Editor Texte
-EDIT_LINE = "Zeile bearbeiten"
-ENTER_SEARCH_TERM = "Suchbegriff eingeben"
-
-# Dateibrowser-Kontextmenü Texte
-REFRESH_LIVEAREA = "Livearea aktualisieren"
-MOUNT_UMA0 = "Mount uma0:"
-MOUNT_IMC0 = "Mount imc0:"
-MOUNT_USB_UX0 = "Mount USB ux0:"
-UMOUNT_USB_UX0 = "Umount USB ux0:"
-SORT_BY = "Sortiere nach"
-BY_NAME = "Name"
-BY_SIZE = "Größe"
-BY_DATE = "Datum"
-MARK_ALL = "Alles auswählen"
-UNMARK_ALL = "Auswahl aufheben"
-MOVE = "Verschieben"
-COPY = "Kopieren"
-PASTE = "Einfügen"
-DELETE = "Löschen"
-RENAME = "Umbenennen"
-NEW_FOLDER = "Neuer Ordner"
-PROPERTIES = "Eigenschaften"
-MORE = "Mehr"
-COMPRESS = "Komprimieren"
-INSTALL_ALL = "Alle installieren"
-INSTALL_FOLDER = "Ordner installieren"
-CALCULATE_SHA1 = "SHA1 berechnen"
-EXPORT_MEDIA = "Medien exportieren"
-CUT = "Ausschneiden"
-INSERT_EMPTY_LINE = "Leere Zeile einfügen"
-SEARCH = "Suchen"
-
-# Dateibrowser Berechtigungs Texte
-PROPERTY_NAME = "Name"
-PROPERTY_TYPE = "Art"
-PROPERTY_FSELF_MODE = "FSELF Modus"
-PROPERTY_SIZE = "Größe"
-PROPERTY_COMPRESSED_SIZE = "Komprimierte Größe"
-PROPERTY_CONTAINS = "Beinhaltet"
-PROPERTY_CONTAINS_FILES_FOLDERS = "%d Dateien, %d Ordner"
-PROPERTY_CREATION_DATE = "Erstellungsdatum"
-PROPERTY_MODFICATION_DATE = "Veränderungsdatum"
-PROPERTY_TYPE_BMP = "Bitmap Bildformat"
-PROPERTY_TYPE_INI = "Konfigurationsdatei"
-PROPERTY_TYPE_JPEG = "JPEG Bildformat"
-PROPERTY_TYPE_MP3 = "MP3 Audiodatei"
-PROPERTY_TYPE_OGG = "OGG Audiodatei"
-PROPERTY_TYPE_PNG = "PNG Bildformat"
-PROPERTY_TYPE_RAR = "RAR Archiv"
-PROPERTY_TYPE_SFO = "SFO Datei"
-PROPERTY_TYPE_TXT = "Textdokument"
-PROPERTY_TYPE_VPK = "VPK Paket"
-PROPERTY_TYPE_XML = "XML Datei"
-PROPERTY_TYPE_ZIP = "ZIP Archiv"
-PROPERTY_TYPE_FSELF = "FSELF Datei"
-PROPERTY_FSELF_MODE_SAFE = "Sicher"
-PROPERTY_FSELF_MODE_UNSAFE = "Nicht Sicher"
-PROPERTY_FSELF_MODE_SCE = "SCE signiert"
-
-# Dateibrowser Texte
-REFRESHED = "%d Datei(en) aktualisiert."
-COPIED_FILE = "%d Datei(en) kopiert."
-COPIED_FOLDER = "%d Ordner kopiert."
-COPIED_FILES_FOLDERS = "%d Element(e) kopiert."
-
-# Fragen in Dialogfenstern
-DELETE_FILE_QUESTION = "Möchtest du die Datei wirklich löschen?"
-DELETE_FOLDER_QUESTION = "Möchtest du den Ordner wirklich löschen?"
-DELETE_FILES_FOLDERS_QUESTION = "Möchtest du die ausgewählten Elemente wirklich löschen?"
-EXPORT_FILE_QUESTION = "Möchtest du diese Datei zu den Medien exportieren?"
-EXPORT_FOLDER_QUESTION = "Möchtest du diesen Ordner zu den Medien exportieren?"
-EXPORT_FILES_FOLDERS_QUESTION = "Möchtest du diese Elemente zu den Medien exportieren?"
-EXPORT_NO_MEDIA = "Keine Mediendateien zum Exportieren verfügbar."
-EXPORT_SONGS_INFO = "%d Lied(er) exportiert."
-EXPORT_VIDEOS_INFO = "%d Video(s) exportiert."
-EXPORT_PICTURES_INFO = "%d Bild(er) exportiert."
-EXPORT_SONGS_VIDEOS_INFO = "%d Lied(er) und %d Video(s) exportiert."
-EXPORT_SONGS_PICTURES_INFO = "%d Lied(er) und %d Bild(er) exportiert."
-EXPORT_VIDEOS_PICTURES_INFO = "%d Video(s) und %d Bild(er) exportiert."
-EXPORT_SONGS_VIDEOS_PICTURES_INFO = "%d Lied(er) %d Video(s) und %d Bild(er) exportiert."
-INSTALL_ALL_QUESTION = "Möchtest du alle in diesem Ordner verfügbaren Pakete installieren?"
-INSTALL_FOLDER_QUESTION = "Möchtest du diesen Ordner installieren?\Warnung: hierdurch wird nach der Installation\auch der Ordner gelöscht!"
-INSTALL_QUESTION = "Möchtest du dieses Paket installieren?"
-INSTALL_WARNING = "Dieses Paket benötigt erweiterte Berechtigungen.\Es wird Zugriff auf deine persönlichen Informationen haben.\Bitte installiere es nur, falls es aus einer vertrauenswürdigen Quelle stammt\oder fahre auf eigene Gefahr fort.\\Möchtest du die Installation fortsetzen?"
-INSTALL_BRICK_WARNING = "Dieses Paket nutzt Funktionen, um Partitionen zu\verwalten und kann möglicherweise dein Gerät zerstören.\Bitte installiere es nur, falls es aus einer vertrauenswürdigen Quelle stammt\oder fahre auf eigene Gefahr fort.\\Möchtest du die Installation fortsetzen?"
-HASH_FILE_QUESTION = "Einen SHA1-Hash zu erstellen kann einige Zeit\in Anspruch nehmen. Die benötigte Zeit\ist von der Dateigröße abhängig.\\Möchtest du fortfahren?"
-SAVE_MODIFICATIONS = "Möchtest du die Änderungen speichern?"
-REFRESH_LIVEAREA_QUESTION = "Die Livearea zu aktualisieren kann einige Zeit in Anspruch nehmen.\Möchtest du fortfahren?"
-
-# HENkaku Einstellungen Texte
-HENKAKU_SETTINGS = "HENkaku Einstellungen"
-HENKAKU_ENABLE_PSN_SPOOFING = "Aktiviere PSN Vortäuschung"
-HENKAKU_ENABLE_UNSAFE_HOMEBREW = "Nicht sichere Homebrews zulassen"
-HENKAKU_ENABLE_VERSION_SPOOFING = "Aktiviere Versions Vortäuschung"
-HENKAKU_SPOOFED_VERSION = "Vorgetäuschte Version"
-HENKAKU_RESTORE_DEFAULT_SETTINGS = "Stelle Standardeinstellungen wieder her"
-HENKAKU_RELOAD_CONFIG = "taiHEN config.txt zurücksetzen"
-HENKAKU_RESTORE_DEFAULT_MESSAGE = "Standardeinstellungen wurden erfolgreich zurückgesetzt."
-HENKAKU_RELOAD_CONFIG_MESSAGE = "taiHEN config.txt wurde erfolgreich zurückgesetzt."
-HENKAKU_UNSAFE_HOMEBREW_MESSAGE = "Nicht sichere Homebrews können dein Gerät\permanent beschädigen, wenn diese falsch angewendet,\eingestellt oder böswillig genutzt werden.\Bitte sei vorsichtig, wenn du diese installierst."
-
-# VitaShell Einstellungen
-VITASHELL_SETTINGS_MAIN = "Haupteinstellungen"
-VITASHELL_SETTINGS_LANGUAGE = "Sprache"
-VITASHELL_SETTINGS_THEME = "Thema"
-VITASHELL_SETTINGS_USBDEVICE = "USB Gerät"
-VITASHELL_SETTINGS_SELECT_BUTTON = "SELECT Knopf"
-VITASHELL_SETTINGS_NO_AUTO_UPDATE = "Auto-Update deaktivieren"
-VITASHELL_SETTINGS_RESTART_SHELL = "VitaShell Neustarten"
-VITASHELL_SETTINGS_POWER = "Power"
-VITASHELL_SETTINGS_REBOOT = "Neustarten"
-VITASHELL_SETTINGS_POWEROFF = "Ausschalten"
-VITASHELL_SETTINGS_STANDBY = "Standby"
-VITASHELL_SETTINGS_USB_MEMORY_CARD = "Memory Card"
-VITASHELL_SETTINGS_USB_GAME_CARD = "Game Card"
-VITASHELL_SETTINGS_SELECT_BUTTON_USB = "USB"
-VITASHELL_SETTINGS_SELECT_BUTTON_FTP = "FTP"
-
-# USB Texte
-USB_CONNECTED = "USB verbunden"
-USB_UMA0_MOUNTED = "uma0: mounted."
-USB_UX0_MOUNTED = "USB ux0: mounted."
-USB_UX0_UMOUNTED = "USB ux0: umounted."
-USB_NOT_CONNECTED = "Verbinde dieses Gerät mit einem PC durch ein USB Kabel"
-USB_CONNECTION_NOT_AVAILABLE = "USB Verbindung ist auf diesem Gerät nicht verfügbar."
-USB_WAIT_ATTACH = "Zum Fortsetzen bitte ein USB Gerät anschließen.\Wenn es bereits angeschlossen ist, bitte trennen\und erneut anschließen."
-
-# Andere
-IMC0_MOUNTED = "imc0: mounted."
-SAFE_MODE = "SICHERER MODUS"
-UNSAFE_MODE = "UNSICHERER MODUS"
-PLEASE_WAIT = "Bitte warten..."
-AME_CARD_NOT_FOUND = "Bitte eine Game Card einstecken."
-NO_SPACE_ERROR = "Es steht nicht genügend Speicherplatz zur Verfügung.\Es wird %s an zusätzlichem freien Speicher benötigt."
-EXTENDED_PERMISSIONS_REQUIRED = "Diese Funktion benötigt erweiterte Berechtigungen.\Bitte aktiviere zuerst 'Nicht sichere Homebrews zulassen'."
-WIFI_ERROR = "Es wird eine aktive WLAN-Verbindung benötigt."
-FTP_SERVER = "FTP-Server läuft unter\ftp://%s:%i\\Drücke 'OK', um den Server im Hintergrund laufen zu lassen.\Drücke 'Abbrechen', um die Verbindung zu trennen."
-UPDATE_QUESTION = "VitaShell %s ist jetzt verfügbar.\\Möchtest du die Anwendung aktualisieren?"
-ARCHIVE_NAME = "Archiv Name"
-COMPRESSION_LEVEL = "Kompressionslevel (0-9)"
+# VitaShell German Translation by VegaRoXas and Tails32; updated by Ch3ck3r (VitaShell 1.62)
+
+# Allgemeine Texte
+ERROR = "Fehler 0x%08X."
+OK = "OK"
+YES = "Ja"
+NO = "Nein"
+CANCEL = "Abbrechen"
+ON = "An"
+OFF = "Aus"
+FILE_ = "Datei"
+FOLDER = "Ordner"
+
+# Prozess-Texte
+MOVING = "Verschiebe..."
+COPYING = "Kopiere..."
+DELETING = "Lösche..."
+EXPORTING = "Exportiere..."
+INSTALLING = "Installiere..."
+DOWNLOADING = "Lade herunter..."
+EXTRACTING = "Entpacke..."
+COMPRESSING = "Komprimiere..."
+HASHING = "Erstelle Hash..."
+REFRESHING = "Aktualisiere..."
+
+# Musik Player Texte
+TITLE = "Titel"
+ALBUM = "Album"
+ARTIST = "Künstler"
+GENRE = "Genre"
+YEAR = "Jahr"
+
+# Hex-Editor Texte
+OFFSET = "Offset"
+OPEN_HEX_EDITOR = "Im Hex-Editor öffnen"
+
+# Text-Editor Texte
+EDIT_LINE = "Zeile bearbeiten"
+ENTER_SEARCH_TERM = "Suchbegriff eingeben"
+
+# Dateibrowser-Kontextmenü Texte
+REFRESH_LIVEAREA = "Livearea aktualisieren"
+MOUNT_UMA0 = "Mount uma0:"
+MOUNT_IMC0 = "Mount imc0:"
+MOUNT_USB_UX0 = "Mount USB ux0:"
+UMOUNT_USB_UX0 = "Umount USB ux0:"
+SORT_BY = "Sortiere nach"
+BY_NAME = "Name"
+BY_SIZE = "Größe"
+BY_DATE = "Datum"
+MARK_ALL = "Alles auswählen"
+UNMARK_ALL = "Auswahl aufheben"
+MOVE = "Verschieben"
+COPY = "Kopieren"
+PASTE = "Einfügen"
+DELETE = "Löschen"
+RENAME = "Umbenennen"
+NEW_FOLDER = "Neuer Ordner"
+PROPERTIES = "Eigenschaften"
+MORE = "Mehr"
+COMPRESS = "Komprimieren"
+INSTALL_ALL = "Alle installieren"
+INSTALL_FOLDER = "Ordner installieren"
+CALCULATE_SHA1 = "SHA1 berechnen"
+EXPORT_MEDIA = "Medien exportieren"
+CUT = "Ausschneiden"
+INSERT_EMPTY_LINE = "Leere Zeile einfügen"
+SEARCH = "Suchen"
+
+# Dateibrowser Berechtigungs Texte
+PROPERTY_NAME = "Name"
+PROPERTY_TYPE = "Art"
+PROPERTY_FSELF_MODE = "FSELF Modus"
+PROPERTY_SIZE = "Größe"
+PROPERTY_COMPRESSED_SIZE = "Komprimierte Größe"
+PROPERTY_CONTAINS = "Beinhaltet"
+PROPERTY_CONTAINS_FILES_FOLDERS = "%d Dateien, %d Ordner"
+PROPERTY_CREATION_DATE = "Erstellungsdatum"
+PROPERTY_MODFICATION_DATE = "Veränderungsdatum"
+PROPERTY_TYPE_BMP = "Bitmap Bildformat"
+PROPERTY_TYPE_INI = "Konfigurationsdatei"
+PROPERTY_TYPE_JPEG = "JPEG Bildformat"
+PROPERTY_TYPE_MP3 = "MP3 Audiodatei"
+PROPERTY_TYPE_OGG = "OGG Audiodatei"
+PROPERTY_TYPE_PNG = "PNG Bildformat"
+PROPERTY_TYPE_RAR = "RAR Archiv"
+PROPERTY_TYPE_SFO = "SFO Datei"
+PROPERTY_TYPE_TXT = "Textdokument"
+PROPERTY_TYPE_VPK = "VPK Paket"
+PROPERTY_TYPE_XML = "XML Datei"
+PROPERTY_TYPE_ZIP = "ZIP Archiv"
+PROPERTY_TYPE_FSELF = "FSELF Datei"
+PROPERTY_FSELF_MODE_SAFE = "Sicher"
+PROPERTY_FSELF_MODE_UNSAFE = "Nicht Sicher"
+PROPERTY_FSELF_MODE_SCE = "SCE signiert"
+
+# Dateibrowser Texte
+REFRESHED = "%d Datei(en) aktualisiert."
+COPIED_FILE = "%d Datei(en) kopiert."
+COPIED_FOLDER = "%d Ordner kopiert."
+COPIED_FILES_FOLDERS = "%d Element(e) kopiert."
+
+# Fragen in Dialogfenstern
+DELETE_FILE_QUESTION = "Möchtest du die Datei wirklich löschen?"
+DELETE_FOLDER_QUESTION = "Möchtest du den Ordner wirklich löschen?"
+DELETE_FILES_FOLDERS_QUESTION = "Möchtest du die ausgewählten Elemente wirklich löschen?"
+EXPORT_FILE_QUESTION = "Möchtest du diese Datei zu den Medien exportieren?"
+EXPORT_FOLDER_QUESTION = "Möchtest du diesen Ordner zu den Medien exportieren?"
+EXPORT_FILES_FOLDERS_QUESTION = "Möchtest du diese Elemente zu den Medien exportieren?"
+EXPORT_NO_MEDIA = "Keine Mediendateien zum Exportieren verfügbar."
+EXPORT_SONGS_INFO = "%d Lied(er) exportiert."
+EXPORT_VIDEOS_INFO = "%d Video(s) exportiert."
+EXPORT_PICTURES_INFO = "%d Bild(er) exportiert."
+EXPORT_SONGS_VIDEOS_INFO = "%d Lied(er) und %d Video(s) exportiert."
+EXPORT_SONGS_PICTURES_INFO = "%d Lied(er) und %d Bild(er) exportiert."
+EXPORT_VIDEOS_PICTURES_INFO = "%d Video(s) und %d Bild(er) exportiert."
+EXPORT_SONGS_VIDEOS_PICTURES_INFO = "%d Lied(er) %d Video(s) und %d Bild(er) exportiert."
+INSTALL_ALL_QUESTION = "Möchtest du alle in diesem Ordner verfügbaren Pakete installieren?"
+INSTALL_FOLDER_QUESTION = "Möchtest du diesen Ordner installieren?\Warnung: hierdurch wird nach der Installation\auch der Ordner gelöscht!"
+INSTALL_QUESTION = "Möchtest du dieses Paket installieren?"
+INSTALL_WARNING = "Dieses Paket benötigt erweiterte Berechtigungen.\Es wird Zugriff auf deine persönlichen Informationen haben.\Bitte installiere es nur, falls es aus einer vertrauenswürdigen Quelle stammt\oder fahre auf eigene Gefahr fort.\\Möchtest du die Installation fortsetzen?"
+INSTALL_BRICK_WARNING = "Dieses Paket nutzt Funktionen, um Partitionen zu\verwalten und kann möglicherweise dein Gerät zerstören.\Bitte installiere es nur, falls es aus einer vertrauenswürdigen Quelle stammt\oder fahre auf eigene Gefahr fort.\\Möchtest du die Installation fortsetzen?"
+HASH_FILE_QUESTION = "Einen SHA1-Hash zu erstellen kann einige Zeit\in Anspruch nehmen. Die benötigte Zeit\ist von der Dateigröße abhängig.\\Möchtest du fortfahren?"
+SAVE_MODIFICATIONS = "Möchtest du die Änderungen speichern?"
+REFRESH_LIVEAREA_QUESTION = "Die Livearea zu aktualisieren kann einige Zeit in Anspruch nehmen.\Möchtest du fortfahren?"
+
+# HENkaku Einstellungen Texte
+HENKAKU_SETTINGS = "HENkaku Einstellungen"
+HENKAKU_ENABLE_PSN_SPOOFING = "Aktiviere PSN Vortäuschung"
+HENKAKU_ENABLE_UNSAFE_HOMEBREW = "Nicht sichere Homebrews zulassen"
+HENKAKU_ENABLE_VERSION_SPOOFING = "Aktiviere Versions Vortäuschung"
+HENKAKU_SPOOFED_VERSION = "Vorgetäuschte Version"
+HENKAKU_RESTORE_DEFAULT_SETTINGS = "Stelle Standardeinstellungen wieder her"
+HENKAKU_RELOAD_CONFIG = "taiHEN config.txt zurücksetzen"
+HENKAKU_RESTORE_DEFAULT_MESSAGE = "Standardeinstellungen wurden erfolgreich zurückgesetzt."
+HENKAKU_RELOAD_CONFIG_MESSAGE = "taiHEN config.txt wurde erfolgreich zurückgesetzt."
+HENKAKU_UNSAFE_HOMEBREW_MESSAGE = "Nicht sichere Homebrews können dein Gerät\permanent beschädigen, wenn diese falsch angewendet,\eingestellt oder böswillig genutzt werden.\Bitte sei vorsichtig, wenn du diese installierst."
+
+# VitaShell Einstellungen
+VITASHELL_SETTINGS_MAIN = "Haupteinstellungen"
+VITASHELL_SETTINGS_LANGUAGE = "Sprache"
+VITASHELL_SETTINGS_THEME = "Thema"
+VITASHELL_SETTINGS_USBDEVICE = "USB Gerät"
+VITASHELL_SETTINGS_SELECT_BUTTON = "SELECT Knopf"
+VITASHELL_SETTINGS_NO_AUTO_UPDATE = "Auto-Update deaktivieren"
+VITASHELL_SETTINGS_RESTART_SHELL = "VitaShell Neustarten"
+VITASHELL_SETTINGS_POWER = "Power"
+VITASHELL_SETTINGS_REBOOT = "Neustarten"
+VITASHELL_SETTINGS_POWEROFF = "Ausschalten"
+VITASHELL_SETTINGS_STANDBY = "Standby"
+VITASHELL_SETTINGS_USB_MEMORY_CARD = "Memory Card"
+VITASHELL_SETTINGS_USB_GAME_CARD = "Game Card"
+VITASHELL_SETTINGS_SELECT_BUTTON_USB = "USB"
+VITASHELL_SETTINGS_SELECT_BUTTON_FTP = "FTP"
+
+# USB Texte
+USB_CONNECTED = "USB verbunden"
+USB_UMA0_MOUNTED = "uma0: mounted."
+USB_UX0_MOUNTED = "USB ux0: mounted."
+USB_UX0_UMOUNTED = "USB ux0: umounted."
+USB_NOT_CONNECTED = "Verbinde dieses Gerät mit einem PC durch ein USB Kabel"
+USB_CONNECTION_NOT_AVAILABLE = "USB Verbindung ist auf diesem Gerät nicht verfügbar."
+USB_WAIT_ATTACH = "Zum Fortsetzen bitte ein USB Gerät anschließen.\Wenn es bereits angeschlossen ist, bitte trennen\und erneut anschließen."
+
+# Andere
+IMC0_MOUNTED = "imc0: mounted."
+SAFE_MODE = "SICHERER MODUS"
+UNSAFE_MODE = "UNSICHERER MODUS"
+PLEASE_WAIT = "Bitte warten..."
+AME_CARD_NOT_FOUND = "Bitte eine Game Card einstecken."
+NO_SPACE_ERROR = "Es steht nicht genügend Speicherplatz zur Verfügung.\Es wird %s an zusätzlichem freien Speicher benötigt."
+EXTENDED_PERMISSIONS_REQUIRED = "Diese Funktion benötigt erweiterte Berechtigungen.\Bitte aktiviere zuerst 'Nicht sichere Homebrews zulassen'."
+WIFI_ERROR = "Es wird eine aktive WLAN-Verbindung benötigt."
+FTP_SERVER = "FTP-Server läuft unter\ftp://%s:%i\\Drücke 'OK', um den Server im Hintergrund laufen zu lassen.\Drücke 'Abbrechen', um die Verbindung zu trennen."
+UPDATE_QUESTION = "VitaShell %s ist jetzt verfügbar.\\Möchtest du die Anwendung aktualisieren?"
+ARCHIVE_NAME = "Archiv Name"
+COMPRESSION_LEVEL = "Kompressionslevel (0-9)"
diff --git a/l10n/norwegian.txt b/l10n/norwegian.txt
index affeab2..d60c65d 100644
--- a/l10n/norwegian.txt
+++ b/l10n/norwegian.txt
@@ -1,203 +1,203 @@
-# VitaShell norwegian translation by habibi
-
-# General strings
-ERROR = "Feilmelding 0x%08X."
-OK = "OK"
-YES = "Ja"
-NO = "Nei"
-CANCEL = "Avbryt"
-ON = "På"
-OFF = "Av"
-FILE_ = "Fil"
-FOLDER = "Mappe"
-
-# Progress strings
-MOVING = "Flytter..."
-COPYING = "Kopierer..."
-DELETING = "Sletter..."
-IMPORTING = "Importerer..."
-EXPORTING = "Eksporterer..."
-INSTALLING = "Installerer..."
-DOWNLOADING = "Laster ned..."
-EXTRACTING = "Pakker ut..."
-COMPRESSING = "Komprimerer..."
-HASHING = "Sjekker hash..."
-REFRESHING = "Oppdaterer..."
-SENDING = "Sender..."
-RECEIVING = "Mottar..."
-
-# Audio player strings
-TITLE = "Tittel"
-ALBUM = "Album"
-ARTIST = "Artist"
-GENRE = "Sjanger"
-YEAR = "År"
-
-# Hex editor strings
-OFFSET = "Offset"
-OPEN_HEX_EDITOR = "Åpne hex-redigeringsprogram"
-
-# Text editor strings
-EDIT_LINE = "Rediger linje"
-ENTER_SEARCH_TERM = "Skriv inn søkeord"
-
-# Context menu strings
-REFRESH_LIVEAREA = "Oppdater LiveArea™"
-REFRESH_LICENSE_DB = "Oppdater lisensdatabase"
-MOUNT_UMA0 = "Monter uma0:"
-MOUNT_IMC0 = "Monter imc0:"
-MOUNT_USB_UX0 = "Monter USB ux0:"
-UMOUNT_USB_UX0 = "Avmonter USB ux0:"
-SORT_BY = "Sorter etter"
-BY_NAME = "Navn"
-BY_SIZE = "Størrelse"
-BY_DATE = "Dato"
-MARK_ALL = "Marker alle"
-UNMARK_ALL = "Fjern markering"
-MOVE = "Klipp ut"
-COPY = "Kopier"
-PASTE = "Lim inn"
-DELETE = "Slett"
-RENAME = "Endre navn"
-NEW_FOLDER = "Ny mappe"
-PROPERTIES = "Egenskaper"
-SEND = "Send"
-RECEIVE = "Motta"
-MORE = "Mer"
-COMPRESS = "Komprimer"
-INSTALL_ALL = "Installer alle"
-INSTALL_FOLDER = "Installer mappe"
-CALCULATE_SHA1 = "Kalkuler SHA1"
-OPEN_DECRYPTED = "Åpne dekryptert"
-EXPORT_MEDIA = "Eksporter media"
-CUT = "Kutt"
-INSERT_EMPTY_LINE = "Sett inn tom linje"
-SEARCH = "Søk"
-
-# File browser properties strings
-PROPERTY_NAME = "Navn"
-PROPERTY_TYPE = "Type"
-PROPERTY_FSELF_MODE = "FSELF modus"
-PROPERTY_SIZE = "Størrelse"
-PROPERTY_COMPRESSED_SIZE = "Komprimert størrelse"
-PROPERTY_CONTAINS = "Inneholder"
-PROPERTY_CONTAINS_FILES_FOLDERS = "%d filer, %d mapper"
-PROPERTY_CREATION_DATE = "Opprettet"
-PROPERTY_MODFICATION_DATE = "Modifisert"
-PROPERTY_TYPE_ARCHIVE = "Arkiv"
-PROPERTY_TYPE_BMP = "BMP bilde"
-PROPERTY_TYPE_INI = "Konfigurasjonsfil"
-PROPERTY_TYPE_JPEG = "JPEG bilde"
-PROPERTY_TYPE_MP3 = "MP3 lydfil"
-PROPERTY_TYPE_OGG = "OGG lydfil"
-PROPERTY_TYPE_PNG = "PNG bilde"
-PROPERTY_TYPE_SFO = "SFO fil"
-PROPERTY_TYPE_TXT = "Tekstdokument"
-PROPERTY_TYPE_VPK = "VPK pakke"
-PROPERTY_TYPE_XML = "XML fil"
-PROPERTY_TYPE_FSELF = "FSELF fil"
-PROPERTY_FSELF_MODE_SAFE = "Sikker"
-PROPERTY_FSELF_MODE_UNSAFE = "Usikker"
-PROPERTY_FSELF_MODE_SCE = "SCE signert"
-
-# File browser strings
-REFRESHED = "Oppdaterte %d elementer."
-COPIED_FILE = "Kopierte %d fil(er)."
-COPIED_FOLDER = "Kopierte %d mappe(r)."
-COPIED_FILES_FOLDERS = "Kopierte %d file(r)/mappe(r)."
-IMPORTED_LICENSES = "Importerte %d lisens(er)."
-
-# Dialog questions
-DELETE_FILE_QUESTION = "Er du sikker på at du vil slette denne filen?"
-DELETE_FOLDER_QUESTION = "Er du sikker på at du vil slette denne mappen?"
-DELETE_FILES_FOLDERS_QUESTION = "Er du sikker på at du vil slette disse filene/mappene?"
-EXPORT_FILE_QUESTION = "Vil du eksportere denne filen til media?"
-EXPORT_FOLDER_QUESTION = "Vil du eksportere denne mappen til media?"
-EXPORT_FILES_FOLDERS_QUESTION = "Vil du eksportere disse filene/mappene til media?"
-EXPORT_NO_MEDIA = "Ingen mediafiler tilgjengelig til å eksportere."
-EXPORT_SONGS_INFO = "Eksporterte %d song(er)."
-EXPORT_VIDEOS_INFO = "Eksporterte %d video(er)."
-EXPORT_PICTURES_INFO = "Eksporterte %d bilde(r)."
-EXPORT_SONGS_VIDEOS_INFO = "Eksporterte %d sang(er) and %d video(er)."
-EXPORT_SONGS_PICTURES_INFO = "Eksporterte %d sang(er) and %d bilde(r)."
-EXPORT_VIDEOS_PICTURES_INFO = "Eksporterte %d video(er) and %d bilde(r)."
-EXPORT_SONGS_VIDEOS_PICTURES_INFO = "Eksporterte %d sang(er) %d video(er) and %d bilde(r)."
-INSTALL_ALL_QUESTION = "Vil du installere alle pakkene i denne mappen?"
-INSTALL_FOLDER_QUESTION = "Vil du installere denne mappen?\Varsel: denne handlingen vil også slette\mappen etter installasjon!"
-INSTALL_QUESTION = "Vil du installere denne pakken?"
-INSTALL_WARNING = "Denne pakken krever utvidede tillatelser.\Den vil ha tilgang til dine personlige opplysninger.\Hvis du ikke fikk den av en trygg kilde,\fortsett på egen risiko.\\Vil du fortsette installasjonen?"
-INSTALL_BRICK_WARNING = "Denne pakken bruker funksjoner som remonterer\partisjoner og kan potensielt ødelegge din enhet.\Hvis du ikke fikk den av en trygg kilde,\fortsett på egen risiko.\\Vil du fortsette installasjonen?"
-HASH_FILE_QUESTION = "SHA1-hashing kan ta lang tid. Fortsette?"
-SAVE_MODIFICATIONS = "Lagre endringer?"
-REFRESH_LIVEAREA_QUESTION = "Oppdatering av LiveArea™ kan ta lang tid. Fortsette?"
-REFRESH_LICENSE_DB_QUESTION = "Oppdatering av lisensdatabase kan ta lang tid. Fortsette?"
-
-# HENkaku settings strings
-HENKAKU_SETTINGS = "HENkaku instillinger"
-HENKAKU_ENABLE_PSN_SPOOFING = "Aktiver PSN-forfalskning"
-HENKAKU_ENABLE_UNSAFE_HOMEBREW = "Aktiver usikker homebrew"
-HENKAKU_ENABLE_VERSION_SPOOFING = "Aktiver versjon-forfalskning"
-HENKAKU_SPOOFED_VERSION = "Forfalsket versjon"
-HENKAKU_RESTORE_DEFAULT_SETTINGS = "Gjenopprett standardinnstillinger"
-HENKAKU_RELOAD_CONFIG = "Last inn taiHEN config.txt"
-HENKAKU_RESTORE_DEFAULT_MESSAGE = "Standardinnstillinger gjenopprettet."
-HENKAKU_RELOAD_CONFIG_MESSAGE = "taiHEN config.txt lastet inn."
-HENKAKU_UNSAFE_HOMEBREW_MESSAGE = "Usikker homebrew kan skade enheten din\permanent, hvis de er misbrukt, feilkonfigurert,\eller skadelig.\Fortsett på egen risiko."
-
-# VitaShell settings
-VITASHELL_SETTINGS_MAIN = "Hovedinnstillinger"
-VITASHELL_SETTINGS_LANGUAGE = "Språk"
-VITASHELL_SETTINGS_THEME = "Tema"
-VITASHELL_SETTINGS_USBDEVICE = "USB-enhet"
-VITASHELL_SETTINGS_SELECT_BUTTON = "SELECT-knapp"
-VITASHELL_SETTINGS_NO_AUTO_UPDATE = "Deaktiver automatiske oppdateringer"
-VITASHELL_SETTINGS_RESTART_SHELL = "Restart VitaShell"
-VITASHELL_SETTINGS_POWER = "Strøm"
-VITASHELL_SETTINGS_REBOOT = "Restart"
-VITASHELL_SETTINGS_POWEROFF = "Skru av"
-VITASHELL_SETTINGS_STANDBY = "Standby"
-VITASHELL_SETTINGS_USB_MEMORY_CARD = "Minnekort"
-VITASHELL_SETTINGS_USB_GAME_CARD = "Spillkort"
-VITASHELL_SETTINGS_USB_SD2VITA = "sd2vita"
-VITASHELL_SETTINGS_USB_PSVSD = "psvsd"
-VITASHELL_SETTINGS_SELECT_BUTTON_USB = "USB"
-VITASHELL_SETTINGS_SELECT_BUTTON_FTP = "FTP"
-
-# USB strings
-USB_CONNECTED = "USB tilkoblet"
-USB_UMA0_MOUNTED = "uma0: montert."
-USB_UX0_MOUNTED = "USB ux0: montert."
-USB_UX0_UMOUNTED = "USB ux0: avmontert."
-USB_NOT_CONNECTED = "Koble til denne enheten med USB-kabel."
-USB_CONNECTION_NOT_AVAILABLE = "USB-tilkobling er ikke tilgjengelig på denne enheten."
-USB_WAIT_ATTACH = "Koble til USB-enhet for å fortsette.\Hvis den allerede er koblet til,\koble inn og ut."
-
-# QR strings
-QR_SCANNING = "Leter etter QR koder..."
-QR_OPEN_WEBSITE = "Vil du åpne denne lenken?\%s"
-QR_SHOW_CONTENTS = "QR Code sier:\%s"
-QR_CONFIRM_INSTALL = "Vil du installere denne pakken?\%s\Fil: %s\Størrelse: %s"
-QR_CONFIRM_DOWNLOAD = "Vil du laste ned denne filen?\%s\Fil: %s\Størrelse: %s"
-
-# Adhoc strings
-ADHOC_RECEIVE_SEARCHING_PSVITA = "Leter etter PS Vita.\Vennligst vent..."
-ADHOC_SELECT_PSVITA = "Velg PS Vita:"
-ADHOC_RECEIVE_QUESTION = "Vil du motta fra %s?"
-ADHOC_CLIENT_DECLINED = "Klienten har nektet forespørselen."
-
-# Others
-IMC0_MOUNTED = "imc0: montert."
-SAFE_MODE = "SIKKER MODUS"
-UNSAFE_MODE = "USIKKER MODUS"
-PLEASE_WAIT = "Vennligst vent..."
-MEMORY_CARD_NOT_FOUND = "Vennligst sett inn minnekort."
-GAME_CARD_NOT_FOUND = "Vennligst sett inn spillkort."
-MICROSD_NOT_FOUND = "Vennligst sett inn microSD."
-NO_SPACE_ERROR = "Det er ikke nok plass på minnekortet.\Minst %s mer plass er nødvendig."
-EXTENDED_PERMISSIONS_REQUIRED = "Denne funksjonen krever utvidede tillatelser.\Vennligst skru på 'Aktiver usikker homebrew' først."
-WIFI_ERROR = "Du trenger Wi-Fi for å gjøre dette."
-FTP_SERVER = "FTP-server kjører på\ftp://%s:%i\\Velg 'OK' for å holde det i bakgrunnen.\Velg 'Avbryt' for å koble av."
-UPDATE_QUESTION = "VitaShell %s er nå tilgjengelig.\\Vil du oppdatere?"
-ARCHIVE_NAME = "Arkivnavn"
-COMPRESSION_LEVEL = "Komprimeringsnivå (0-9)"
-ENTER_PASSWORD = "Skriv inn passord"
+# VitaShell norwegian translation by habibi
+
+# General strings
+ERROR = "Feilmelding 0x%08X."
+OK = "OK"
+YES = "Ja"
+NO = "Nei"
+CANCEL = "Avbryt"
+ON = "På"
+OFF = "Av"
+FILE_ = "Fil"
+FOLDER = "Mappe"
+
+# Progress strings
+MOVING = "Flytter..."
+COPYING = "Kopierer..."
+DELETING = "Sletter..."
+IMPORTING = "Importerer..."
+EXPORTING = "Eksporterer..."
+INSTALLING = "Installerer..."
+DOWNLOADING = "Laster ned..."
+EXTRACTING = "Pakker ut..."
+COMPRESSING = "Komprimerer..."
+HASHING = "Sjekker hash..."
+REFRESHING = "Oppdaterer..."
+SENDING = "Sender..."
+RECEIVING = "Mottar..."
+
+# Audio player strings
+TITLE = "Tittel"
+ALBUM = "Album"
+ARTIST = "Artist"
+GENRE = "Sjanger"
+YEAR = "År"
+
+# Hex editor strings
+OFFSET = "Offset"
+OPEN_HEX_EDITOR = "Åpne hex-redigeringsprogram"
+
+# Text editor strings
+EDIT_LINE = "Rediger linje"
+ENTER_SEARCH_TERM = "Skriv inn søkeord"
+
+# Context menu strings
+REFRESH_LIVEAREA = "Oppdater LiveArea™"
+REFRESH_LICENSE_DB = "Oppdater lisensdatabase"
+MOUNT_UMA0 = "Monter uma0:"
+MOUNT_IMC0 = "Monter imc0:"
+MOUNT_USB_UX0 = "Monter USB ux0:"
+UMOUNT_USB_UX0 = "Avmonter USB ux0:"
+SORT_BY = "Sorter etter"
+BY_NAME = "Navn"
+BY_SIZE = "Størrelse"
+BY_DATE = "Dato"
+MARK_ALL = "Marker alle"
+UNMARK_ALL = "Fjern markering"
+MOVE = "Klipp ut"
+COPY = "Kopier"
+PASTE = "Lim inn"
+DELETE = "Slett"
+RENAME = "Endre navn"
+NEW_FOLDER = "Ny mappe"
+PROPERTIES = "Egenskaper"
+SEND = "Send"
+RECEIVE = "Motta"
+MORE = "Mer"
+COMPRESS = "Komprimer"
+INSTALL_ALL = "Installer alle"
+INSTALL_FOLDER = "Installer mappe"
+CALCULATE_SHA1 = "Kalkuler SHA1"
+OPEN_DECRYPTED = "Åpne dekryptert"
+EXPORT_MEDIA = "Eksporter media"
+CUT = "Kutt"
+INSERT_EMPTY_LINE = "Sett inn tom linje"
+SEARCH = "Søk"
+
+# File browser properties strings
+PROPERTY_NAME = "Navn"
+PROPERTY_TYPE = "Type"
+PROPERTY_FSELF_MODE = "FSELF modus"
+PROPERTY_SIZE = "Størrelse"
+PROPERTY_COMPRESSED_SIZE = "Komprimert størrelse"
+PROPERTY_CONTAINS = "Inneholder"
+PROPERTY_CONTAINS_FILES_FOLDERS = "%d filer, %d mapper"
+PROPERTY_CREATION_DATE = "Opprettet"
+PROPERTY_MODFICATION_DATE = "Modifisert"
+PROPERTY_TYPE_ARCHIVE = "Arkiv"
+PROPERTY_TYPE_BMP = "BMP bilde"
+PROPERTY_TYPE_INI = "Konfigurasjonsfil"
+PROPERTY_TYPE_JPEG = "JPEG bilde"
+PROPERTY_TYPE_MP3 = "MP3 lydfil"
+PROPERTY_TYPE_OGG = "OGG lydfil"
+PROPERTY_TYPE_PNG = "PNG bilde"
+PROPERTY_TYPE_SFO = "SFO fil"
+PROPERTY_TYPE_TXT = "Tekstdokument"
+PROPERTY_TYPE_VPK = "VPK pakke"
+PROPERTY_TYPE_XML = "XML fil"
+PROPERTY_TYPE_FSELF = "FSELF fil"
+PROPERTY_FSELF_MODE_SAFE = "Sikker"
+PROPERTY_FSELF_MODE_UNSAFE = "Usikker"
+PROPERTY_FSELF_MODE_SCE = "SCE signert"
+
+# File browser strings
+REFRESHED = "Oppdaterte %d elementer."
+COPIED_FILE = "Kopierte %d fil(er)."
+COPIED_FOLDER = "Kopierte %d mappe(r)."
+COPIED_FILES_FOLDERS = "Kopierte %d file(r)/mappe(r)."
+IMPORTED_LICENSES = "Importerte %d lisens(er)."
+
+# Dialog questions
+DELETE_FILE_QUESTION = "Er du sikker på at du vil slette denne filen?"
+DELETE_FOLDER_QUESTION = "Er du sikker på at du vil slette denne mappen?"
+DELETE_FILES_FOLDERS_QUESTION = "Er du sikker på at du vil slette disse filene/mappene?"
+EXPORT_FILE_QUESTION = "Vil du eksportere denne filen til media?"
+EXPORT_FOLDER_QUESTION = "Vil du eksportere denne mappen til media?"
+EXPORT_FILES_FOLDERS_QUESTION = "Vil du eksportere disse filene/mappene til media?"
+EXPORT_NO_MEDIA = "Ingen mediafiler tilgjengelig til å eksportere."
+EXPORT_SONGS_INFO = "Eksporterte %d song(er)."
+EXPORT_VIDEOS_INFO = "Eksporterte %d video(er)."
+EXPORT_PICTURES_INFO = "Eksporterte %d bilde(r)."
+EXPORT_SONGS_VIDEOS_INFO = "Eksporterte %d sang(er) and %d video(er)."
+EXPORT_SONGS_PICTURES_INFO = "Eksporterte %d sang(er) and %d bilde(r)."
+EXPORT_VIDEOS_PICTURES_INFO = "Eksporterte %d video(er) and %d bilde(r)."
+EXPORT_SONGS_VIDEOS_PICTURES_INFO = "Eksporterte %d sang(er) %d video(er) and %d bilde(r)."
+INSTALL_ALL_QUESTION = "Vil du installere alle pakkene i denne mappen?"
+INSTALL_FOLDER_QUESTION = "Vil du installere denne mappen?\Varsel: denne handlingen vil også slette\mappen etter installasjon!"
+INSTALL_QUESTION = "Vil du installere denne pakken?"
+INSTALL_WARNING = "Denne pakken krever utvidede tillatelser.\Den vil ha tilgang til dine personlige opplysninger.\Hvis du ikke fikk den av en trygg kilde,\fortsett på egen risiko.\\Vil du fortsette installasjonen?"
+INSTALL_BRICK_WARNING = "Denne pakken bruker funksjoner som remonterer\partisjoner og kan potensielt ødelegge din enhet.\Hvis du ikke fikk den av en trygg kilde,\fortsett på egen risiko.\\Vil du fortsette installasjonen?"
+HASH_FILE_QUESTION = "SHA1-hashing kan ta lang tid. Fortsette?"
+SAVE_MODIFICATIONS = "Lagre endringer?"
+REFRESH_LIVEAREA_QUESTION = "Oppdatering av LiveArea™ kan ta lang tid. Fortsette?"
+REFRESH_LICENSE_DB_QUESTION = "Oppdatering av lisensdatabase kan ta lang tid. Fortsette?"
+
+# HENkaku settings strings
+HENKAKU_SETTINGS = "HENkaku instillinger"
+HENKAKU_ENABLE_PSN_SPOOFING = "Aktiver PSN-forfalskning"
+HENKAKU_ENABLE_UNSAFE_HOMEBREW = "Aktiver usikker homebrew"
+HENKAKU_ENABLE_VERSION_SPOOFING = "Aktiver versjon-forfalskning"
+HENKAKU_SPOOFED_VERSION = "Forfalsket versjon"
+HENKAKU_RESTORE_DEFAULT_SETTINGS = "Gjenopprett standardinnstillinger"
+HENKAKU_RELOAD_CONFIG = "Last inn taiHEN config.txt"
+HENKAKU_RESTORE_DEFAULT_MESSAGE = "Standardinnstillinger gjenopprettet."
+HENKAKU_RELOAD_CONFIG_MESSAGE = "taiHEN config.txt lastet inn."
+HENKAKU_UNSAFE_HOMEBREW_MESSAGE = "Usikker homebrew kan skade enheten din\permanent, hvis de er misbrukt, feilkonfigurert,\eller skadelig.\Fortsett på egen risiko."
+
+# VitaShell settings
+VITASHELL_SETTINGS_MAIN = "Hovedinnstillinger"
+VITASHELL_SETTINGS_LANGUAGE = "Språk"
+VITASHELL_SETTINGS_THEME = "Tema"
+VITASHELL_SETTINGS_USBDEVICE = "USB-enhet"
+VITASHELL_SETTINGS_SELECT_BUTTON = "SELECT-knapp"
+VITASHELL_SETTINGS_NO_AUTO_UPDATE = "Deaktiver automatiske oppdateringer"
+VITASHELL_SETTINGS_RESTART_SHELL = "Restart VitaShell"
+VITASHELL_SETTINGS_POWER = "Strøm"
+VITASHELL_SETTINGS_REBOOT = "Restart"
+VITASHELL_SETTINGS_POWEROFF = "Skru av"
+VITASHELL_SETTINGS_STANDBY = "Standby"
+VITASHELL_SETTINGS_USB_MEMORY_CARD = "Minnekort"
+VITASHELL_SETTINGS_USB_GAME_CARD = "Spillkort"
+VITASHELL_SETTINGS_USB_SD2VITA = "sd2vita"
+VITASHELL_SETTINGS_USB_PSVSD = "psvsd"
+VITASHELL_SETTINGS_SELECT_BUTTON_USB = "USB"
+VITASHELL_SETTINGS_SELECT_BUTTON_FTP = "FTP"
+
+# USB strings
+USB_CONNECTED = "USB tilkoblet"
+USB_UMA0_MOUNTED = "uma0: montert."
+USB_UX0_MOUNTED = "USB ux0: montert."
+USB_UX0_UMOUNTED = "USB ux0: avmontert."
+USB_NOT_CONNECTED = "Koble til denne enheten med USB-kabel."
+USB_CONNECTION_NOT_AVAILABLE = "USB-tilkobling er ikke tilgjengelig på denne enheten."
+USB_WAIT_ATTACH = "Koble til USB-enhet for å fortsette.\Hvis den allerede er koblet til,\koble inn og ut."
+
+# QR strings
+QR_SCANNING = "Leter etter QR koder..."
+QR_OPEN_WEBSITE = "Vil du åpne denne lenken?\%s"
+QR_SHOW_CONTENTS = "QR Code sier:\%s"
+QR_CONFIRM_INSTALL = "Vil du installere denne pakken?\%s\Fil: %s\Størrelse: %s"
+QR_CONFIRM_DOWNLOAD = "Vil du laste ned denne filen?\%s\Fil: %s\Størrelse: %s"
+
+# Adhoc strings
+ADHOC_RECEIVE_SEARCHING_PSVITA = "Leter etter PS Vita.\Vennligst vent..."
+ADHOC_SELECT_PSVITA = "Velg PS Vita:"
+ADHOC_RECEIVE_QUESTION = "Vil du motta fra %s?"
+ADHOC_CLIENT_DECLINED = "Klienten har nektet forespørselen."
+
+# Others
+IMC0_MOUNTED = "imc0: montert."
+SAFE_MODE = "SIKKER MODUS"
+UNSAFE_MODE = "USIKKER MODUS"
+PLEASE_WAIT = "Vennligst vent..."
+MEMORY_CARD_NOT_FOUND = "Vennligst sett inn minnekort."
+GAME_CARD_NOT_FOUND = "Vennligst sett inn spillkort."
+MICROSD_NOT_FOUND = "Vennligst sett inn microSD."
+NO_SPACE_ERROR = "Det er ikke nok plass på minnekortet.\Minst %s mer plass er nødvendig."
+EXTENDED_PERMISSIONS_REQUIRED = "Denne funksjonen krever utvidede tillatelser.\Vennligst skru på 'Aktiver usikker homebrew' først."
+WIFI_ERROR = "Du trenger Wi-Fi for å gjøre dette."
+FTP_SERVER = "FTP-server kjører på\ftp://%s:%i\\Velg 'OK' for å holde det i bakgrunnen.\Velg 'Avbryt' for å koble av."
+UPDATE_QUESTION = "VitaShell %s er nå tilgjengelig.\\Vil du oppdatere?"
+ARCHIVE_NAME = "Arkivnavn"
+COMPRESSION_LEVEL = "Komprimeringsnivå (0-9)"
+ENTER_PASSWORD = "Skriv inn passord"
diff --git a/l10n/russian.txt b/l10n/russian.txt
index 7230f94..6bc6322 100644
--- a/l10n/russian.txt
+++ b/l10n/russian.txt
@@ -1,217 +1,217 @@
-# VitaShell language file | класть в ux0:VitaShell/language/ | перевод play007 ('http://4pda.ru/forum/index.php?showuser=4495180')
-
-# General strings
-ERROR = "Ошибка 0x%08X."
-OK = "OK"
-YES = "Да"
-NO = "Нет"
-CANCEL = "Отмена"
-ON = "Вкл."
-OFF = "Откл."
-FILE_ = "Файл"
-FOLDER = "<Папка>"
-
-# Progress strings
-MOVING = "Перемещение.."
-COPYING = "Копирование.."
-DELETING = "Удаление.."
-IMPORTING = "Импорт медиафайлов.."
-EXPORTING = "Экспорт медиафайлов.."
-INSTALLING = "Установка.."
-DOWNLOADING = "Загрузка.."
-EXTRACTING = "Извлечение.."
-COMPRESSING = "Архивирование.."
-HASHING = "Хеширование.."
-REFRESHING = "Обновление.."
-SENDING = "Отправка.."
-RECEIVING = "Получение.."
-
-# Audio player strings
-TITLE = "Название"
-ALBUM = "Альбом"
-ARTIST = "Исполнитель"
-GENRE = "Жанр"
-YEAR = "Год"
-
-# Hex editor strings
-OFFSET = "Смещение:"
-OPEN_HEX_EDITOR = "Открыть в Hex редакторе"
-
-# Text editor strings
-EDIT_LINE = "Редактировать строку"
-ENTER_SEARCH_TERM = "Поиск.."
-
-# Context menu strings
-REFRESH_LIVEAREA = "Обновить LiveArea™"
-REFRESH_LICENSE_DB = "Обновить базу лицензий"
-MOUNT_UMA0 = "Смонтировать uma0:"
-MOUNT_IMC0 = "Смонтировать imc0:"
-MOUNT_XMC0 = "Смонтировать xmc0:"
-UMOUNT_UMA0 = "Размонтировать uma0:"
-UMOUNT_IMC0 = "Размонтировать imc0:"
-UMOUNT_XMC0 = "Размонтировать xmc0:"
-MOUNT_USB_UX0 = "Смонтировать USB в ux0:"
-UMOUNT_USB_UX0 = "Размонтировать USB с ux0:"
-MOUNT_GAMECARD_UX0 = "Смонтировать карту с игрой в ux0:"
-UMOUNT_GAMECARD_UX0 = "Размонтировать карту с игрой в ux0:"
-SORT_BY = "Сортировка"
-BY_NAME = "По имени"
-BY_SIZE = "По размеру"
-BY_DATE = "По дате"
-MARK_ALL = "Выделить всё"
-UNMARK_ALL = "Снять выделение"
-MOVE = "Переместить"
-COPY = "Копировать"
-PASTE = "Вставить"
-DELETE = "Удалить"
-RENAME = "Переименовать"
-NEW_FOLDER = "Создать папку"
-NEW = "Создать"
-NEW_FILE = "Создать файл"
-PROPERTIES = "Свойства"
-SEND = "Отправить"
-RECEIVE = "Принять"
-MORE = "Дополнительно"
-COMPRESS = "Архивировать"
-INSTALL_ALL = "Установить все .vpk"
-INSTALL_FOLDER = "Установить из папки"
-CALCULATE_SHA1 = "Вычислить SHA1"
-OPEN_DECRYPTED = "Открыть расшифрованным"
-EXPORT_MEDIA = "Экспорт медиафайлов"
-CUT = "Вырезать"
-INSERT_EMPTY_LINE = "Вставить пустую строку"
-SEARCH = "Поиск"
-
-# File browser properties strings
-PROPERTY_NAME = "Имя"
-PROPERTY_TYPE = "Тип файла"
-PROPERTY_FSELF_MODE = "Режим FSELF"
-PROPERTY_SIZE = "Размер"
-PROPERTY_COMPRESSED_SIZE = "Сжат до"
-PROPERTY_CONTAINS = "Содержимое"
-PROPERTY_CONTAINS_FILES_FOLDERS = "Файлов: %d, папок: %d"
-PROPERTY_CREATION_DATE = "Дата создания"
-PROPERTY_MODFICATION_DATE = "Дата изменения"
-PROPERTY_TYPE_ARCHIVE = "Архив"
-PROPERTY_TYPE_BMP = "Точечный рисунок"
-PROPERTY_TYPE_INI = "Файл настроек"
-PROPERTY_TYPE_JPEG = "Изображение JPEG"
-PROPERTY_TYPE_MP3 = "Аудиофайл MP3"
-PROPERTY_TYPE_OGG = "Аудиофайл OGG"
-PROPERTY_TYPE_PNG = "Изображение PNG"
-PROPERTY_TYPE_SFO = "Файл SFO"
-PROPERTY_TYPE_TXT = "Текст. документ"
-PROPERTY_TYPE_VPK = "Пакет VPK"
-PROPERTY_TYPE_XML = "Файл XML"
-PROPERTY_TYPE_FSELF = "Файл FSELF"
-PROPERTY_FSELF_MODE_SAFE = "Безопасный"
-PROPERTY_FSELF_MODE_UNSAFE = "Небезопасный"
-PROPERTY_FSELF_MODE_SCE = "Подписан SCE"
-
-# File browser strings
-REFRESHED = "Обновлено %d файл(-ов)"
-COPIED_FILE = "Скопирован(-о) %d файл(-ов)"
-COPIED_FOLDER = "Скопирован(-о) %d папок(-ка)"
-COPIED_FILES_FOLDERS = "Скопирован(-о) %d файлов/папок"
-IMPORTED_LICENSES = "Импортировано %d лицензий(-я)."
-
-# Dialog questions
-DELETE_FILE_QUESTION = "Вы действительно хотите удалить этот файл?"
-DELETE_FOLDER_QUESTION = "Вы действительно хотите удалить эту папку?"
-DELETE_FILES_FOLDERS_QUESTION = "Вы действительно хотите удалить эти данные?"
-EXPORT_FILE_QUESTION = "Экспортировать этот файл в медиатеку?"
-EXPORT_FOLDER_QUESTION = "Экспортировать эту папку в медиатеку?"
-EXPORT_FILES_FOLDERS_QUESTION = "Экспортировать выбранные данные в медиатеку?"
-EXPORT_NO_MEDIA = "Нет подходящих для экспорта медиафайлов"
-EXPORT_SONGS_INFO = "Отчёт:\\Экспортировано композиций: %d"
-EXPORT_VIDEOS_INFO = "Отчёт:\\Экспортировано видео: %d"
-EXPORT_PICTURES_INFO = "Отчёт:\\Экспортировано изображений: %d"
-EXPORT_SONGS_VIDEOS_INFO = "Отчёт:\\Экспортировано:\Композиций: %d\Видео: %d"
-EXPORT_SONGS_PICTURES_INFO = "Отчёт:\\Экспортировано:\Композиций: %d\Изображений: %d"
-EXPORT_VIDEOS_PICTURES_INFO = "Отчёт:\\Экспортировано:\Видео: %d\Изображений: %d"
-EXPORT_SONGS_VIDEOS_PICTURES_INFO = "Отчёт:\\Экспортировано:\Композиций: %d\Видео: %d\Изображений: %d"
-INSTALL_ALL_QUESTION = "Установка vpk\\Установить все .vpk из этой папки?"
-INSTALL_FOLDER_QUESTION = "Установка из папки\\Использовать данную папку в качестве источника\для установки пакета?\Внимание:\По окончанию процесса установки папка и её\содержимое будут удалены!"
-INSTALL_QUESTION = "Установка .vpk\\Установить данный пакет?"
-INSTALL_WARNING = "Внимание!\\Установка пакета требует доступа к системным разделам.\Это позволяет получить доступ к вашим личным данным.\Пакеты, скачанные из непроверенных источников, могут\содержать вредоносный код.\\Продолжить установку?"
-INSTALL_BRICK_WARNING = "Внимание!\\Установка пакета требует доступа к системным разделам.\При наличии вредоносного кода, ваше устройство может\быть безвозвратно выведено из строя.\Установка пакетов, скачанных из непроверенных источников,\производится на ваш страх и риск.\\Продолжить установку?"
-HASH_FILE_QUESTION = "Внимание!\\Рассчёт хеша SHA1 может занять длительное время.\Продолжить?"
-SAVE_MODIFICATIONS = "Вы хотите сохранить свои изменения?"
-REFRESH_LIVEAREA_QUESTION = "Обновление LiveArea™ может занять время. Продолжить?"
-REFRESH_LICENSE_DB_QUESTION = "Обновление базы лицензий может занять время. Продолжить?"
-
-# HENkaku settings strings
-HENKAKU_SETTINGS = "Настройки HENkaku"
-HENKAKU_ENABLE_PSN_SPOOFING = "Включить PSN спуффинг"
-HENKAKU_ENABLE_UNSAFE_HOMEBREW = "Включить небезопасные приложения"
-HENKAKU_ENABLE_VERSION_SPOOFING = "Включить подмену версии"
-HENKAKU_SPOOFED_VERSION = "Поддельная версия"
-HENKAKU_RESTORE_DEFAULT_SETTINGS = "Восстановить стандартные настройки"
-HENKAKU_RELOAD_CONFIG = "Перезагрузить taiHEN config.txt"
-HENKAKU_RESTORE_DEFAULT_MESSAGE = "Стандартные настройки восстановлены"
-HENKAKU_RELOAD_CONFIG_MESSAGE = "taiHEN config.txt был успешно перезагружен"
-HENKAKU_UNSAFE_HOMEBREW_MESSAGE = "Небезопасные приложения могут повредить ваше устройство навсегда, если они используются неправильно, неправильно настроены, или вредоносны.\Пожалуйста, проявляйте осторожность при их установке."
-
-# VitaShell settings
-VITASHELL_SETTINGS_MAIN = "Настройки VitaShell"
-VITASHELL_SETTINGS_LANGUAGE = "Язык%"
-VITASHELL_SETTINGS_THEME = "Тема:"
-VITASHELL_SETTINGS_USBDEVICE = "USB устройство:"
-VITASHELL_SETTINGS_SELECT_BUTTON = "Действие кнопки SELECT:"
-VITASHELL_SETTINGS_NO_AUTO_UPDATE = "Отключить автообновление:"
-VITASHELL_SETTINGS_RESTART_SHELL = "Перезапустить VitaShell"
-VITASHELL_SETTINGS_POWER = "Питание"
-VITASHELL_SETTINGS_REBOOT = "Перезагрузка"
-VITASHELL_SETTINGS_POWEROFF = "Выключение"
-VITASHELL_SETTINGS_STANDBY = "Сон"
-VITASHELL_SETTINGS_USB_MEMORY_CARD = "Карта памяти"
-VITASHELL_SETTINGS_USB_GAME_CARD = "Карта с игрой"
-VITASHELL_SETTINGS_USB_SD2VITA = "SD2Vita"
-VITASHELL_SETTINGS_USB_PSVSD = "psvsd"
-VITASHELL_SETTINGS_SELECT_BUTTON_USB = "USB соединение"
-VITASHELL_SETTINGS_SELECT_BUTTON_FTP = "FTP сервер"
-
-# USB strings
-USB_CONNECTED = "Передача данных:\USB соединение установлено"
-USB_UX0_MOUNTED = "USB носитель смонтирован в ux0:"
-USB_UX0_UMOUNTED = "USB носитель размонтирован с ux0:"
-GAMECARD_UX0_MOUNTED = "Карта с игрой смонтирована в ux0:"
-GAMECARD_UX0_uMOUNTED = "Карта с игрой размонтирована с ux0:"
-USB_NOT_CONNECTED = "Передача данных:\Подключите PS Vita к ПК с помощью USB кабеля"
-USB_CONNECTION_NOT_AVAILABLE = "Ошибка:\\Невозножно активировать USB соединение на этом устройстве"
-USB_WAIT_ATTACH = "Подключите USB накопитель, прежде чем продолжить.\Если уже установлено, попробуйте\извлечь его и подключить повторно"
-
-# QR strings
-QR_SCANNING = "Поднесите приставку к QR-коду"
-QR_OPEN_WEBSITE = "Вы хотите открыть этот сайт?:\%s"
-QR_SHOW_CONTENTS = "QR-код имеет:\%s"
-QR_CONFIRM_INSTALL = "Вы хотите установить:\%s\Файл: %s\Размер: %s"
-QR_CONFIRM_DOWNLOAD = "Вы хотите скачать:\%s\Файл: %s\Размер: %s"
-
-# Adhoc strings
-ADHOC_RECEIVE_SEARCHING_PSVITA = "Поиск PSVita для получения файла\Пожалуйста, подождите"
-ADHOC_SELECT_PSVITA = "Выберите PSVita:"
-ADHOC_RECEIVE_QUESTION = "Вы хотите получить от %s?"
-ADHOC_CLIENT_DECLINED = "Клиент отклонил ваш запрос"
-
-# Others
-UMA0_MOUNTED = "uma0: смонтировано"
-UMA0_UMOUNTED = "uma0: размонтировано"
-IMC0_MOUNTED = "imc0: смонтировано"
-IMC0_UMOUNTED = "imc0: размонтировано"
-XMC0_MOUNTED = "xmc0: смонтировано"
-XMC0_UMOUNTED = "xmc0: размонтировано"
-SAFE_MODE = "БЕЗОПАСНЫЙ РЕЖИМ"
-UNSAFE_MODE = "НЕБЕЗОПАСНЫЙ РЕЖИМ"
-PLEASE_WAIT = "Момент.."
-MEMORY_CARD_NOT_FOUND = "Пожалуйста, вставьте карту памяти в PS Vita"
-GAME_CARD_NOT_FOUND = "Пожалуйста, вставьте карту с игрой"
-MICROSD_NOT_FOUND = "Пожалуйста, вставьте MicroSD"
-NO_SPACE_ERROR = "Внимание!\Недостаточно свободного места на карте памяти.\Необходимо минимум %s."
-EXTENDED_PERMISSIONS_REQUIRED = "Для выполения этого действия нужны права\Чтобы их получить, поставьте галку на/'Включить небезопасные приложения' в настройках HENkaku"
-WIFI_ERROR = "Для запуска FTP-сервера нужно Wi-Fi соединение"
-FTP_SERVER = "FTP-сервер доступен по адресу:\ftp://%s:%i\\'OK' - скрыть окно (сервер в фоне)\'Отмена' - остановка сервера"
-UPDATE_QUESTION = "Для установки доступна VitaShell %s.\\Выполнить обновление?"
-ARCHIVE_NAME = "Имя архива"
-COMPRESSION_LEVEL = "Уровень сжатия (0-9)"
-ENTER_PASSWORD = "Введите пароль"
+# VitaShell language file | класть в ux0:VitaShell/language/ | перевод play007 ('http://4pda.ru/forum/index.php?showuser=4495180')
+
+# General strings
+ERROR = "Ошибка 0x%08X."
+OK = "OK"
+YES = "Да"
+NO = "Нет"
+CANCEL = "Отмена"
+ON = "Вкл."
+OFF = "Откл."
+FILE_ = "Файл"
+FOLDER = "<Папка>"
+
+# Progress strings
+MOVING = "Перемещение.."
+COPYING = "Копирование.."
+DELETING = "Удаление.."
+IMPORTING = "Импорт медиафайлов.."
+EXPORTING = "Экспорт медиафайлов.."
+INSTALLING = "Установка.."
+DOWNLOADING = "Загрузка.."
+EXTRACTING = "Извлечение.."
+COMPRESSING = "Архивирование.."
+HASHING = "Хеширование.."
+REFRESHING = "Обновление.."
+SENDING = "Отправка.."
+RECEIVING = "Получение.."
+
+# Audio player strings
+TITLE = "Название"
+ALBUM = "Альбом"
+ARTIST = "Исполнитель"
+GENRE = "Жанр"
+YEAR = "Год"
+
+# Hex editor strings
+OFFSET = "Смещение:"
+OPEN_HEX_EDITOR = "Открыть в Hex редакторе"
+
+# Text editor strings
+EDIT_LINE = "Редактировать строку"
+ENTER_SEARCH_TERM = "Поиск.."
+
+# Context menu strings
+REFRESH_LIVEAREA = "Обновить LiveArea™"
+REFRESH_LICENSE_DB = "Обновить базу лицензий"
+MOUNT_UMA0 = "Смонтировать uma0:"
+MOUNT_IMC0 = "Смонтировать imc0:"
+MOUNT_XMC0 = "Смонтировать xmc0:"
+UMOUNT_UMA0 = "Размонтировать uma0:"
+UMOUNT_IMC0 = "Размонтировать imc0:"
+UMOUNT_XMC0 = "Размонтировать xmc0:"
+MOUNT_USB_UX0 = "Смонтировать USB в ux0:"
+UMOUNT_USB_UX0 = "Размонтировать USB с ux0:"
+MOUNT_GAMECARD_UX0 = "Смонтировать карту с игрой в ux0:"
+UMOUNT_GAMECARD_UX0 = "Размонтировать карту с игрой в ux0:"
+SORT_BY = "Сортировка"
+BY_NAME = "По имени"
+BY_SIZE = "По размеру"
+BY_DATE = "По дате"
+MARK_ALL = "Выделить всё"
+UNMARK_ALL = "Снять выделение"
+MOVE = "Переместить"
+COPY = "Копировать"
+PASTE = "Вставить"
+DELETE = "Удалить"
+RENAME = "Переименовать"
+NEW_FOLDER = "Создать папку"
+NEW = "Создать"
+NEW_FILE = "Создать файл"
+PROPERTIES = "Свойства"
+SEND = "Отправить"
+RECEIVE = "Принять"
+MORE = "Дополнительно"
+COMPRESS = "Архивировать"
+INSTALL_ALL = "Установить все .vpk"
+INSTALL_FOLDER = "Установить из папки"
+CALCULATE_SHA1 = "Вычислить SHA1"
+OPEN_DECRYPTED = "Открыть расшифрованным"
+EXPORT_MEDIA = "Экспорт медиафайлов"
+CUT = "Вырезать"
+INSERT_EMPTY_LINE = "Вставить пустую строку"
+SEARCH = "Поиск"
+
+# File browser properties strings
+PROPERTY_NAME = "Имя"
+PROPERTY_TYPE = "Тип файла"
+PROPERTY_FSELF_MODE = "Режим FSELF"
+PROPERTY_SIZE = "Размер"
+PROPERTY_COMPRESSED_SIZE = "Сжат до"
+PROPERTY_CONTAINS = "Содержимое"
+PROPERTY_CONTAINS_FILES_FOLDERS = "Файлов: %d, папок: %d"
+PROPERTY_CREATION_DATE = "Дата создания"
+PROPERTY_MODFICATION_DATE = "Дата изменения"
+PROPERTY_TYPE_ARCHIVE = "Архив"
+PROPERTY_TYPE_BMP = "Точечный рисунок"
+PROPERTY_TYPE_INI = "Файл настроек"
+PROPERTY_TYPE_JPEG = "Изображение JPEG"
+PROPERTY_TYPE_MP3 = "Аудиофайл MP3"
+PROPERTY_TYPE_OGG = "Аудиофайл OGG"
+PROPERTY_TYPE_PNG = "Изображение PNG"
+PROPERTY_TYPE_SFO = "Файл SFO"
+PROPERTY_TYPE_TXT = "Текст. документ"
+PROPERTY_TYPE_VPK = "Пакет VPK"
+PROPERTY_TYPE_XML = "Файл XML"
+PROPERTY_TYPE_FSELF = "Файл FSELF"
+PROPERTY_FSELF_MODE_SAFE = "Безопасный"
+PROPERTY_FSELF_MODE_UNSAFE = "Небезопасный"
+PROPERTY_FSELF_MODE_SCE = "Подписан SCE"
+
+# File browser strings
+REFRESHED = "Обновлено %d файл(-ов)"
+COPIED_FILE = "Скопирован(-о) %d файл(-ов)"
+COPIED_FOLDER = "Скопирован(-о) %d папок(-ка)"
+COPIED_FILES_FOLDERS = "Скопирован(-о) %d файлов/папок"
+IMPORTED_LICENSES = "Импортировано %d лицензий(-я)."
+
+# Dialog questions
+DELETE_FILE_QUESTION = "Вы действительно хотите удалить этот файл?"
+DELETE_FOLDER_QUESTION = "Вы действительно хотите удалить эту папку?"
+DELETE_FILES_FOLDERS_QUESTION = "Вы действительно хотите удалить эти данные?"
+EXPORT_FILE_QUESTION = "Экспортировать этот файл в медиатеку?"
+EXPORT_FOLDER_QUESTION = "Экспортировать эту папку в медиатеку?"
+EXPORT_FILES_FOLDERS_QUESTION = "Экспортировать выбранные данные в медиатеку?"
+EXPORT_NO_MEDIA = "Нет подходящих для экспорта медиафайлов"
+EXPORT_SONGS_INFO = "Отчёт:\\Экспортировано композиций: %d"
+EXPORT_VIDEOS_INFO = "Отчёт:\\Экспортировано видео: %d"
+EXPORT_PICTURES_INFO = "Отчёт:\\Экспортировано изображений: %d"
+EXPORT_SONGS_VIDEOS_INFO = "Отчёт:\\Экспортировано:\Композиций: %d\Видео: %d"
+EXPORT_SONGS_PICTURES_INFO = "Отчёт:\\Экспортировано:\Композиций: %d\Изображений: %d"
+EXPORT_VIDEOS_PICTURES_INFO = "Отчёт:\\Экспортировано:\Видео: %d\Изображений: %d"
+EXPORT_SONGS_VIDEOS_PICTURES_INFO = "Отчёт:\\Экспортировано:\Композиций: %d\Видео: %d\Изображений: %d"
+INSTALL_ALL_QUESTION = "Установка vpk\\Установить все .vpk из этой папки?"
+INSTALL_FOLDER_QUESTION = "Установка из папки\\Использовать данную папку в качестве источника\для установки пакета?\Внимание:\По окончанию процесса установки папка и её\содержимое будут удалены!"
+INSTALL_QUESTION = "Установка .vpk\\Установить данный пакет?"
+INSTALL_WARNING = "Внимание!\\Установка пакета требует доступа к системным разделам.\Это позволяет получить доступ к вашим личным данным.\Пакеты, скачанные из непроверенных источников, могут\содержать вредоносный код.\\Продолжить установку?"
+INSTALL_BRICK_WARNING = "Внимание!\\Установка пакета требует доступа к системным разделам.\При наличии вредоносного кода, ваше устройство может\быть безвозвратно выведено из строя.\Установка пакетов, скачанных из непроверенных источников,\производится на ваш страх и риск.\\Продолжить установку?"
+HASH_FILE_QUESTION = "Внимание!\\Рассчёт хеша SHA1 может занять длительное время.\Продолжить?"
+SAVE_MODIFICATIONS = "Вы хотите сохранить свои изменения?"
+REFRESH_LIVEAREA_QUESTION = "Обновление LiveArea™ может занять время. Продолжить?"
+REFRESH_LICENSE_DB_QUESTION = "Обновление базы лицензий может занять время. Продолжить?"
+
+# HENkaku settings strings
+HENKAKU_SETTINGS = "Настройки HENkaku"
+HENKAKU_ENABLE_PSN_SPOOFING = "Включить PSN спуффинг"
+HENKAKU_ENABLE_UNSAFE_HOMEBREW = "Включить небезопасные приложения"
+HENKAKU_ENABLE_VERSION_SPOOFING = "Включить подмену версии"
+HENKAKU_SPOOFED_VERSION = "Поддельная версия"
+HENKAKU_RESTORE_DEFAULT_SETTINGS = "Восстановить стандартные настройки"
+HENKAKU_RELOAD_CONFIG = "Перезагрузить taiHEN config.txt"
+HENKAKU_RESTORE_DEFAULT_MESSAGE = "Стандартные настройки восстановлены"
+HENKAKU_RELOAD_CONFIG_MESSAGE = "taiHEN config.txt был успешно перезагружен"
+HENKAKU_UNSAFE_HOMEBREW_MESSAGE = "Небезопасные приложения могут повредить ваше устройство навсегда, если они используются неправильно, неправильно настроены, или вредоносны.\Пожалуйста, проявляйте осторожность при их установке."
+
+# VitaShell settings
+VITASHELL_SETTINGS_MAIN = "Настройки VitaShell"
+VITASHELL_SETTINGS_LANGUAGE = "Язык%"
+VITASHELL_SETTINGS_THEME = "Тема:"
+VITASHELL_SETTINGS_USBDEVICE = "USB устройство:"
+VITASHELL_SETTINGS_SELECT_BUTTON = "Действие кнопки SELECT:"
+VITASHELL_SETTINGS_NO_AUTO_UPDATE = "Отключить автообновление:"
+VITASHELL_SETTINGS_RESTART_SHELL = "Перезапустить VitaShell"
+VITASHELL_SETTINGS_POWER = "Питание"
+VITASHELL_SETTINGS_REBOOT = "Перезагрузка"
+VITASHELL_SETTINGS_POWEROFF = "Выключение"
+VITASHELL_SETTINGS_STANDBY = "Сон"
+VITASHELL_SETTINGS_USB_MEMORY_CARD = "Карта памяти"
+VITASHELL_SETTINGS_USB_GAME_CARD = "Карта с игрой"
+VITASHELL_SETTINGS_USB_SD2VITA = "SD2Vita"
+VITASHELL_SETTINGS_USB_PSVSD = "psvsd"
+VITASHELL_SETTINGS_SELECT_BUTTON_USB = "USB соединение"
+VITASHELL_SETTINGS_SELECT_BUTTON_FTP = "FTP сервер"
+
+# USB strings
+USB_CONNECTED = "Передача данных:\USB соединение установлено"
+USB_UX0_MOUNTED = "USB носитель смонтирован в ux0:"
+USB_UX0_UMOUNTED = "USB носитель размонтирован с ux0:"
+GAMECARD_UX0_MOUNTED = "Карта с игрой смонтирована в ux0:"
+GAMECARD_UX0_uMOUNTED = "Карта с игрой размонтирована с ux0:"
+USB_NOT_CONNECTED = "Передача данных:\Подключите PS Vita к ПК с помощью USB кабеля"
+USB_CONNECTION_NOT_AVAILABLE = "Ошибка:\\Невозножно активировать USB соединение на этом устройстве"
+USB_WAIT_ATTACH = "Подключите USB накопитель, прежде чем продолжить.\Если уже установлено, попробуйте\извлечь его и подключить повторно"
+
+# QR strings
+QR_SCANNING = "Поднесите приставку к QR-коду"
+QR_OPEN_WEBSITE = "Вы хотите открыть этот сайт?:\%s"
+QR_SHOW_CONTENTS = "QR-код имеет:\%s"
+QR_CONFIRM_INSTALL = "Вы хотите установить:\%s\Файл: %s\Размер: %s"
+QR_CONFIRM_DOWNLOAD = "Вы хотите скачать:\%s\Файл: %s\Размер: %s"
+
+# Adhoc strings
+ADHOC_RECEIVE_SEARCHING_PSVITA = "Поиск PSVita для получения файла\Пожалуйста, подождите"
+ADHOC_SELECT_PSVITA = "Выберите PSVita:"
+ADHOC_RECEIVE_QUESTION = "Вы хотите получить от %s?"
+ADHOC_CLIENT_DECLINED = "Клиент отклонил ваш запрос"
+
+# Others
+UMA0_MOUNTED = "uma0: смонтировано"
+UMA0_UMOUNTED = "uma0: размонтировано"
+IMC0_MOUNTED = "imc0: смонтировано"
+IMC0_UMOUNTED = "imc0: размонтировано"
+XMC0_MOUNTED = "xmc0: смонтировано"
+XMC0_UMOUNTED = "xmc0: размонтировано"
+SAFE_MODE = "БЕЗОПАСНЫЙ РЕЖИМ"
+UNSAFE_MODE = "НЕБЕЗОПАСНЫЙ РЕЖИМ"
+PLEASE_WAIT = "Момент.."
+MEMORY_CARD_NOT_FOUND = "Пожалуйста, вставьте карту памяти в PS Vita"
+GAME_CARD_NOT_FOUND = "Пожалуйста, вставьте карту с игрой"
+MICROSD_NOT_FOUND = "Пожалуйста, вставьте MicroSD"
+NO_SPACE_ERROR = "Внимание!\Недостаточно свободного места на карте памяти.\Необходимо минимум %s."
+EXTENDED_PERMISSIONS_REQUIRED = "Для выполения этого действия нужны права\Чтобы их получить, поставьте галку на/'Включить небезопасные приложения' в настройках HENkaku"
+WIFI_ERROR = "Для запуска FTP-сервера нужно Wi-Fi соединение"
+FTP_SERVER = "FTP-сервер доступен по адресу:\ftp://%s:%i\\'OK' - скрыть окно (сервер в фоне)\'Отмена' - остановка сервера"
+UPDATE_QUESTION = "Для установки доступна VitaShell %s.\\Выполнить обновление?"
+ARCHIVE_NAME = "Имя архива"
+COMPRESSION_LEVEL = "Уровень сжатия (0-9)"
+ENTER_PASSWORD = "Введите пароль"
diff --git a/l10n/spanish.txt b/l10n/spanish.txt
index 9415794..94f82b6 100644
--- a/l10n/spanish.txt
+++ b/l10n/spanish.txt
@@ -1,217 +1,217 @@
-# VitaShell spanish translation by ppizarror, Shadyck, Darkmet98, Keizel and NikowFreak
-
-# General strings - Carácteres generales
-ERROR = "Error 0x%08X."
-OK = "Aceptar"
-YES = "Sí"
-NO = "No"
-CANCEL = "Cancelar"
-ON = "Encendido"
-OFF = "Apagado"
-FILE_ = "Archivo"
-FOLDER = "Carpeta"
-
-# Progress strings - Carácteres de progresos
-MOVING = "Moviendo..."
-COPYING = "Copiando..."
-DELETING = "Eliminando..."
-IMPORTING = "Importando..."
-EXPORTING = "Exportando..."
-INSTALLING = "Instalando..."
-DOWNLOADING = "Descargando..."
-EXTRACTING = "Extrayendo..."
-COMPRESSING = "Comprimiendo..."
-HASHING = "Hashing..."
-REFRESHING = "Actualizando..."
-SENDING = "Enviando..."
-RECEIVING = "Recibiendo..."
-
-# Audio player strings - Carácteres del reproductor de audio
-TITLE = "Título"
-ALBUM = "Álbum"
-ARTIST = "Artista"
-GENRE = "Género"
-YEAR = "Año"
-
-# Hex editor strings - Carácteres del editor hexadecimal
-OFFSET = "Offset"
-OPEN_HEX_EDITOR = "Abrir editor hexadecimal"
-
-# Text editor strings - Carácteres del editor de texto
-EDIT_LINE = "Editar línea"
-ENTER_SEARCH_TERM = "Introduzca el término de búsqueda"
-
-# File browser context menu strings - Carácteres del menú contextual del explorador de archivos
-REFRESH_LIVEAREA = "Actualizar LiveArea™"
-REFRESH_LICENSE_DB = "Actualizar DB de licencias"
-MOUNT_UMA0 = "Montar uma0:"
-MOUNT_IMC0 = "Montar imc0:"
-MOUNT_XMC0 = "Montar xmc0:"
-UMOUNT_UMA0 = "Desmontar uma0:"
-UMOUNT_IMC0 = "Desmontar imc0:"
-UMOUNT_XMC0 = "Desmontar xmc0:"
-MOUNT_USB_UX0 = "Montar USB ux0:"
-UMOUNT_USB_UX0 = "Desmontar USB ux0:"
-MOUNT_GAMECARD_UX0 = "Montar gamecard ux0:"
-UMOUNT_GAMECARD_UX0 = "Desmontar gamecard ux0:"
-SORT_BY = "Ordenar por"
-BY_NAME = "Nombre"
-BY_SIZE = "Tamaño"
-BY_DATE = "Fecha"
-MARK_ALL = "Marcar todo"
-UNMARK_ALL = "Desmarcar todo"
-MOVE = "Mover"
-COPY = "Copiar"
-PASTE = "Pegar"
-DELETE = "Eliminar"
-RENAME = "Renombrar"
-NEW_FOLDER = "Nueva carpeta"
-NEW = "Nuevo"
-NEW_FILE = "Nuevo archivo"
-PROPERTIES = "Propiedades"
-SEND = "Enviar"
-RECEIVE = "Recibir"
-MORE = "Más"
-COMPRESS = "Compresión"
-INSTALL_ALL = "Instalar todo"
-INSTALL_FOLDER = "Instalar carpeta"
-CALCULATE_SHA1 = "Calcular SHA1"
-OPEN_DECRYPTED = "Abrir desencriptado"
-EXPORT_MEDIA = "Exportar multimedia"
-CUT = "Cortar"
-INSERT_EMPTY_LINE = "Insertar una línea"
-SEARCH = "Buscar"
-
-# File browser properties strings - Carácteres de las propiedades del explorador de archivos
-PROPERTY_NAME = "Nombre"
-PROPERTY_TYPE = "Tipo"
-PROPERTY_FSELF_MODE = "Modo FSELF"
-PROPERTY_SIZE = "Tamaño"
-PROPERTY_COMPRESSED_SIZE = "Tamaño comprimido"
-PROPERTY_CONTAINS = "Contiene"
-PROPERTY_CONTAINS_FILES_FOLDERS = "%d archivos, %d carpetas"
-PROPERTY_CREATION_DATE = "Fecha de creación"
-PROPERTY_MODFICATION_DATE = "Fecha de última modificación"
-PROPERTY_TYPE_ARCHIVE = "Archivo"
-PROPERTY_TYPE_BMP = "Imagen Bitmap"
-PROPERTY_TYPE_INI = "Archivo de configuración"
-PROPERTY_TYPE_JPEG = "Imagen JPEG"
-PROPERTY_TYPE_MP3 = "Archivo de audio MP3"
-PROPERTY_TYPE_OGG = "Archivo de audio OGG"
-PROPERTY_TYPE_PNG = "Imagen PNG"
-PROPERTY_TYPE_SFO = "Archivo SFO"
-PROPERTY_TYPE_TXT = "Documento de texto"
-PROPERTY_TYPE_VPK = "Fichero VPK"
-PROPERTY_TYPE_XML = "Archivo XML"
-PROPERTY_TYPE_FSELF = "Archivo FSELF"
-PROPERTY_FSELF_MODE_SAFE = "Seguro"
-PROPERTY_FSELF_MODE_UNSAFE = "Inseguro"
-PROPERTY_FSELF_MODE_SCE = "Firmado SCE"
-
-# File browser strings - Carácteres del explorador de archivos
-REFRESHED = "Actualizados %d elementos."
-COPIED_FILE = "Copiados %d archivo/os."
-COPIED_FOLDER = "Copiados %d carpeta/as."
-COPIED_FILES_FOLDERS = "Copiados %d archivos y/o carpetas."
-IMPORTED_LICENSES = "Importadas %d licencias."
-
-# Dialog questions - Preguntas del diálogo
-DELETE_FILE_QUESTION = "¿Estás seguro de que quieres eliminar este/os archivo/os?"
-DELETE_FOLDER_QUESTION = "¿Estás seguro de que quieres eliminar esta/as carpeta/as?"
-DELETE_FILES_FOLDERS_QUESTION = "¿Estás seguro de que quieres eliminar estas carpetas y/o archivos?"
-EXPORT_FILE_QUESTION = "¿Quieres exportar este archivo a multimedia?"
-EXPORT_FOLDER_QUESTION = "¿Quieres exportar esta carpeta a multimedia?"
-EXPORT_FILES_FOLDERS_QUESTION = "¿Quieres exportar estas carpetas y/o archivos a multimedia?"
-EXPORT_NO_MEDIA = "No hay archivos multimedia disponibles para exportar"
-EXPORT_SONGS_INFO = "Exportada %d canción/es."
-EXPORT_VIDEOS_INFO = "Exportado %d video/os."
-EXPORT_PICTURES_INFO = "Exportada %d imagen/es."
-EXPORT_SONGS_VIDEOS_INFO = "Exportado %d canción/es y %d vídeo/os."
-EXPORT_SONGS_PICTURES_INFO = "Exportado %d canción/es y %d imagen/es."
-EXPORT_VIDEOS_PICTURES_INFO = "Exportado %d vídeo/os y %d imagen/es."
-EXPORT_SONGS_VIDEOS_PICTURES_INFO = "Exportado %d canción/es %d vídeo/os y %d imagen/es."
-INSTALL_ALL_QUESTION = "¿Quieres instalar todos los ficheros que hay de esta carpeta?"
-INSTALL_FOLDER_QUESTION = "¿Quieres instalar esta carpeta?\Aviso: ¡Esta acción también borrará\la carpeta después de la instalación!"
-INSTALL_QUESTION = "¿Quieres instalar este fichero?"
-INSTALL_WARNING = "Este fichero requiere de permisos especiales.\Puede tener acceso a tu información personal\Si no lo has obtenido en un sitio seguro,\por favor, procede con cuidado\\¿Quieres continuar con la instalación?"
-INSTALL_BRICK_WARNING = "Este fichero usa funciones que remontan\particiones y puede dañar gravemente tu dispositivo\Si no lo has obtenido en un sitio seguro,\por favor, procede con cuidado\\¿Quieres continuar con la instalación?"
-HASH_FILE_QUESTION = "Realizar la operación para el hashing SHA1 puede llegar a tardar un tiempo. ¿Quieres continuar?"
-SAVE_MODIFICATIONS = "¿Desea guardar los cambios?"
-REFRESH_LIVEAREA_QUESTION = "Actualizar LiveArea™ puede demorar unos minutos. ¿Quieres continuar?"
-REFRESH_LICENSE_DB_QUESTION = "Actualizar la DB de licencias puede demorar unos minutos. ¿Quieres continuar?"
-
-# HENkaku settings strings - Ajustes de HENkaku
-HENKAKU_SETTINGS = "Opciones de HENkaku"
-HENKAKU_ENABLE_PSN_SPOOFING = "Activar spoofing de PSN"
-HENKAKU_ENABLE_UNSAFE_HOMEBREW = "Activar homebrew inseguro"
-HENKAKU_ENABLE_VERSION_SPOOFING = "Activar spoofing de versión"
-HENKAKU_SPOOFED_VERSION = "Versión spoofeada"
-HENKAKU_RESTORE_DEFAULT_SETTINGS = "Restablecer opciones por defecto"
-HENKAKU_RELOAD_CONFIG = "Recargar taiHEN config.txt"
-HENKAKU_RESTORE_DEFAULT_MESSAGE = "La configuración por defecto ha sido correctamente restaurada."
-HENKAKU_RELOAD_CONFIG_MESSAGE = "taiHEN config.txt ha sido correctamente recargado."
-HENKAKU_UNSAFE_HOMEBREW_MESSAGE = "Homebrews inseguros pueden dañar tu dispositivo\permanentemente si se usan inadecuadamente, si se encuentran mal configurados,\o si son maliciosos.\\Por favor, procede con cuidado al instalarlos."
-
-# VitaShell settings - Ajustes de VitaShell
-VITASHELL_SETTINGS_MAIN = "Configuración principal"
-VITASHELL_SETTINGS_LANGUAGE = "Idioma"
-VITASHELL_SETTINGS_THEME = "Tema"
-VITASHELL_SETTINGS_USBDEVICE = "Dispositivo USB"
-VITASHELL_SETTINGS_SELECT_BUTTON = "Botón SELECT"
-VITASHELL_SETTINGS_NO_AUTO_UPDATE = "Desactivar auto-actualización"
-VITASHELL_SETTINGS_RESTART_SHELL = "Reiniciar VitaShell"
-VITASHELL_SETTINGS_POWER = "Menú de Apagado"
-VITASHELL_SETTINGS_REBOOT = "Reiniciar"
-VITASHELL_SETTINGS_POWEROFF = "Apagar"
-VITASHELL_SETTINGS_STANDBY = "Suspensión"
-VITASHELL_SETTINGS_USB_MEMORY_CARD = "Tarjeta de Memoria"
-VITASHELL_SETTINGS_USB_GAME_CARD = "Tarjeta de Juego"
-VITASHELL_SETTINGS_USB_SD2VITA = "sd2vita"
-VITASHELL_SETTINGS_USB_PSVSD = "psvsd"
-VITASHELL_SETTINGS_SELECT_BUTTON_USB = "USB"
-VITASHELL_SETTINGS_SELECT_BUTTON_FTP = "FTP"
-
-# USB strings - Carácteres USB
-USB_CONNECTED = "USB conectado"
-USB_UX0_MOUNTED = "USB ux0: montada."
-USB_UX0_UMOUNTED = "USB ux0: desmontada."
-GAMECARD_UX0_MOUNTED = "gamecard ux0: montada."
-GAMECARD_UX0_uMOUNTED = "gamecard ux0: desmontada."
-USB_NOT_CONNECTED = "Conecta este sistema a un PC usando un cable USB."
-USB_CONNECTION_NOT_AVAILABLE = "La conexión USB no está disponible en este dispositivo."
-USB_WAIT_ATTACH = "Por favor, conecte un Pendrive USB para continuar\Si ya se ha conectado, por favor, desconectelo\y vuelva a conectarlo."
-
-# QR strings - Carácteres QR
-QR_SCANNING = "Escaneando códigos QR..."
-QR_OPEN_WEBSITE = "¿Quieres abrir este enlace:\%s ?"
-QR_SHOW_CONTENTS = "El código QR dice:\%s"
-QR_CONFIRM_INSTALL = "¿Quieres instalar este paquete:\%s?\Archivo: %s\Peso: %s"
-QR_CONFIRM_DOWNLOAD = "¿Quieres descargar este archivo:\%s?\Archivo: %s\Peso: %s"
-
-# Adhoc strings - Carácteres Adhoc
-ADHOC_RECEIVE_SEARCHING_PSVITA = "Buscando una PSVita para recibir archivos...\Por favor espere..."
-ADHOC_SELECT_PSVITA = "Seleccione una PSVita:"
-ADHOC_RECEIVE_QUESTION = "Quiere recibir desde %s?"
-ADHOC_CLIENT_DECLINED = "El cliente ha rechazado su solicitud."
-
-# Others - Otros
-UMA0_MOUNTED = "uma0: montada."
-UMA0_UMOUNTED = "uma0: desmontada."
-IMC0_MOUNTED = "imc0: montada."
-IMC0_UMOUNTED = "imc0: desmontada."
-XMC0_MOUNTED = "xmc0: montada."
-XMC0_UMOUNTED = "xmc0: desmontada."
-SAFE_MODE = "MODO SEGURO"
-UNSAFE_MODE = "MODO INSEGURO"
-PLEASE_WAIT = "Por favor, espere..."
-MEMORY_CARD_NOT_FOUND = "Por favor, introduzca la tarjeta de memoria."
-GAME_CARD_NOT_FOUND = "Por favor, introduzca la tarjeta del juego."
-MICROSD_NOT_FOUND = "Por favor, introduzca la Micro SD."
-NO_SPACE_ERROR = "No hay espacio libre en la tarjeta de memoria.\Se necesita al menos %s de espacio."
-EXTENDED_PERMISSIONS_REQUIRED = "Esta caracteristica requiere permisos especiales.\Por favor, activa 'Activar homebrew inseguro' primero."
-WIFI_ERROR = "Tienes que activar la conexión Wi-Fi para usar esta función."
-FTP_SERVER = "El servidor FTP está activo en\ftp://%s:%i\\Pulsa 'Aceptar' para mantenerlo en segundo plano\Pulsa 'Cancelar' para desconectarte."
-UPDATE_QUESTION = "VitaShell %s está disponible\\¿Quieres actualizar la aplicación?"
-ARCHIVE_NAME = "Nombre de archivo"
-COMPRESSION_LEVEL = "Nivel de compresión (0-9)"
-ENTER_PASSWORD = "Ingrese contraseña"
+# VitaShell spanish translation by ppizarror, Shadyck, Darkmet98, Keizel and NikowFreak
+
+# General strings - Carácteres generales
+ERROR = "Error 0x%08X."
+OK = "Aceptar"
+YES = "Sí"
+NO = "No"
+CANCEL = "Cancelar"
+ON = "Encendido"
+OFF = "Apagado"
+FILE_ = "Archivo"
+FOLDER = "Carpeta"
+
+# Progress strings - Carácteres de progresos
+MOVING = "Moviendo..."
+COPYING = "Copiando..."
+DELETING = "Eliminando..."
+IMPORTING = "Importando..."
+EXPORTING = "Exportando..."
+INSTALLING = "Instalando..."
+DOWNLOADING = "Descargando..."
+EXTRACTING = "Extrayendo..."
+COMPRESSING = "Comprimiendo..."
+HASHING = "Hashing..."
+REFRESHING = "Actualizando..."
+SENDING = "Enviando..."
+RECEIVING = "Recibiendo..."
+
+# Audio player strings - Carácteres del reproductor de audio
+TITLE = "Título"
+ALBUM = "Álbum"
+ARTIST = "Artista"
+GENRE = "Género"
+YEAR = "Año"
+
+# Hex editor strings - Carácteres del editor hexadecimal
+OFFSET = "Offset"
+OPEN_HEX_EDITOR = "Abrir editor hexadecimal"
+
+# Text editor strings - Carácteres del editor de texto
+EDIT_LINE = "Editar línea"
+ENTER_SEARCH_TERM = "Introduzca el término de búsqueda"
+
+# File browser context menu strings - Carácteres del menú contextual del explorador de archivos
+REFRESH_LIVEAREA = "Actualizar LiveArea™"
+REFRESH_LICENSE_DB = "Actualizar DB de licencias"
+MOUNT_UMA0 = "Montar uma0:"
+MOUNT_IMC0 = "Montar imc0:"
+MOUNT_XMC0 = "Montar xmc0:"
+UMOUNT_UMA0 = "Desmontar uma0:"
+UMOUNT_IMC0 = "Desmontar imc0:"
+UMOUNT_XMC0 = "Desmontar xmc0:"
+MOUNT_USB_UX0 = "Montar USB ux0:"
+UMOUNT_USB_UX0 = "Desmontar USB ux0:"
+MOUNT_GAMECARD_UX0 = "Montar gamecard ux0:"
+UMOUNT_GAMECARD_UX0 = "Desmontar gamecard ux0:"
+SORT_BY = "Ordenar por"
+BY_NAME = "Nombre"
+BY_SIZE = "Tamaño"
+BY_DATE = "Fecha"
+MARK_ALL = "Marcar todo"
+UNMARK_ALL = "Desmarcar todo"
+MOVE = "Mover"
+COPY = "Copiar"
+PASTE = "Pegar"
+DELETE = "Eliminar"
+RENAME = "Renombrar"
+NEW_FOLDER = "Nueva carpeta"
+NEW = "Nuevo"
+NEW_FILE = "Nuevo archivo"
+PROPERTIES = "Propiedades"
+SEND = "Enviar"
+RECEIVE = "Recibir"
+MORE = "Más"
+COMPRESS = "Compresión"
+INSTALL_ALL = "Instalar todo"
+INSTALL_FOLDER = "Instalar carpeta"
+CALCULATE_SHA1 = "Calcular SHA1"
+OPEN_DECRYPTED = "Abrir desencriptado"
+EXPORT_MEDIA = "Exportar multimedia"
+CUT = "Cortar"
+INSERT_EMPTY_LINE = "Insertar una línea"
+SEARCH = "Buscar"
+
+# File browser properties strings - Carácteres de las propiedades del explorador de archivos
+PROPERTY_NAME = "Nombre"
+PROPERTY_TYPE = "Tipo"
+PROPERTY_FSELF_MODE = "Modo FSELF"
+PROPERTY_SIZE = "Tamaño"
+PROPERTY_COMPRESSED_SIZE = "Tamaño comprimido"
+PROPERTY_CONTAINS = "Contiene"
+PROPERTY_CONTAINS_FILES_FOLDERS = "%d archivos, %d carpetas"
+PROPERTY_CREATION_DATE = "Fecha de creación"
+PROPERTY_MODFICATION_DATE = "Fecha de última modificación"
+PROPERTY_TYPE_ARCHIVE = "Archivo"
+PROPERTY_TYPE_BMP = "Imagen Bitmap"
+PROPERTY_TYPE_INI = "Archivo de configuración"
+PROPERTY_TYPE_JPEG = "Imagen JPEG"
+PROPERTY_TYPE_MP3 = "Archivo de audio MP3"
+PROPERTY_TYPE_OGG = "Archivo de audio OGG"
+PROPERTY_TYPE_PNG = "Imagen PNG"
+PROPERTY_TYPE_SFO = "Archivo SFO"
+PROPERTY_TYPE_TXT = "Documento de texto"
+PROPERTY_TYPE_VPK = "Fichero VPK"
+PROPERTY_TYPE_XML = "Archivo XML"
+PROPERTY_TYPE_FSELF = "Archivo FSELF"
+PROPERTY_FSELF_MODE_SAFE = "Seguro"
+PROPERTY_FSELF_MODE_UNSAFE = "Inseguro"
+PROPERTY_FSELF_MODE_SCE = "Firmado SCE"
+
+# File browser strings - Carácteres del explorador de archivos
+REFRESHED = "Actualizados %d elementos."
+COPIED_FILE = "Copiados %d archivo/os."
+COPIED_FOLDER = "Copiados %d carpeta/as."
+COPIED_FILES_FOLDERS = "Copiados %d archivos y/o carpetas."
+IMPORTED_LICENSES = "Importadas %d licencias."
+
+# Dialog questions - Preguntas del diálogo
+DELETE_FILE_QUESTION = "¿Estás seguro de que quieres eliminar este/os archivo/os?"
+DELETE_FOLDER_QUESTION = "¿Estás seguro de que quieres eliminar esta/as carpeta/as?"
+DELETE_FILES_FOLDERS_QUESTION = "¿Estás seguro de que quieres eliminar estas carpetas y/o archivos?"
+EXPORT_FILE_QUESTION = "¿Quieres exportar este archivo a multimedia?"
+EXPORT_FOLDER_QUESTION = "¿Quieres exportar esta carpeta a multimedia?"
+EXPORT_FILES_FOLDERS_QUESTION = "¿Quieres exportar estas carpetas y/o archivos a multimedia?"
+EXPORT_NO_MEDIA = "No hay archivos multimedia disponibles para exportar"
+EXPORT_SONGS_INFO = "Exportada %d canción/es."
+EXPORT_VIDEOS_INFO = "Exportado %d video/os."
+EXPORT_PICTURES_INFO = "Exportada %d imagen/es."
+EXPORT_SONGS_VIDEOS_INFO = "Exportado %d canción/es y %d vídeo/os."
+EXPORT_SONGS_PICTURES_INFO = "Exportado %d canción/es y %d imagen/es."
+EXPORT_VIDEOS_PICTURES_INFO = "Exportado %d vídeo/os y %d imagen/es."
+EXPORT_SONGS_VIDEOS_PICTURES_INFO = "Exportado %d canción/es %d vídeo/os y %d imagen/es."
+INSTALL_ALL_QUESTION = "¿Quieres instalar todos los ficheros que hay de esta carpeta?"
+INSTALL_FOLDER_QUESTION = "¿Quieres instalar esta carpeta?\Aviso: ¡Esta acción también borrará\la carpeta después de la instalación!"
+INSTALL_QUESTION = "¿Quieres instalar este fichero?"
+INSTALL_WARNING = "Este fichero requiere de permisos especiales.\Puede tener acceso a tu información personal\Si no lo has obtenido en un sitio seguro,\por favor, procede con cuidado\\¿Quieres continuar con la instalación?"
+INSTALL_BRICK_WARNING = "Este fichero usa funciones que remontan\particiones y puede dañar gravemente tu dispositivo\Si no lo has obtenido en un sitio seguro,\por favor, procede con cuidado\\¿Quieres continuar con la instalación?"
+HASH_FILE_QUESTION = "Realizar la operación para el hashing SHA1 puede llegar a tardar un tiempo. ¿Quieres continuar?"
+SAVE_MODIFICATIONS = "¿Desea guardar los cambios?"
+REFRESH_LIVEAREA_QUESTION = "Actualizar LiveArea™ puede demorar unos minutos. ¿Quieres continuar?"
+REFRESH_LICENSE_DB_QUESTION = "Actualizar la DB de licencias puede demorar unos minutos. ¿Quieres continuar?"
+
+# HENkaku settings strings - Ajustes de HENkaku
+HENKAKU_SETTINGS = "Opciones de HENkaku"
+HENKAKU_ENABLE_PSN_SPOOFING = "Activar spoofing de PSN"
+HENKAKU_ENABLE_UNSAFE_HOMEBREW = "Activar homebrew inseguro"
+HENKAKU_ENABLE_VERSION_SPOOFING = "Activar spoofing de versión"
+HENKAKU_SPOOFED_VERSION = "Versión spoofeada"
+HENKAKU_RESTORE_DEFAULT_SETTINGS = "Restablecer opciones por defecto"
+HENKAKU_RELOAD_CONFIG = "Recargar taiHEN config.txt"
+HENKAKU_RESTORE_DEFAULT_MESSAGE = "La configuración por defecto ha sido correctamente restaurada."
+HENKAKU_RELOAD_CONFIG_MESSAGE = "taiHEN config.txt ha sido correctamente recargado."
+HENKAKU_UNSAFE_HOMEBREW_MESSAGE = "Homebrews inseguros pueden dañar tu dispositivo\permanentemente si se usan inadecuadamente, si se encuentran mal configurados,\o si son maliciosos.\\Por favor, procede con cuidado al instalarlos."
+
+# VitaShell settings - Ajustes de VitaShell
+VITASHELL_SETTINGS_MAIN = "Configuración principal"
+VITASHELL_SETTINGS_LANGUAGE = "Idioma"
+VITASHELL_SETTINGS_THEME = "Tema"
+VITASHELL_SETTINGS_USBDEVICE = "Dispositivo USB"
+VITASHELL_SETTINGS_SELECT_BUTTON = "Botón SELECT"
+VITASHELL_SETTINGS_NO_AUTO_UPDATE = "Desactivar auto-actualización"
+VITASHELL_SETTINGS_RESTART_SHELL = "Reiniciar VitaShell"
+VITASHELL_SETTINGS_POWER = "Menú de Apagado"
+VITASHELL_SETTINGS_REBOOT = "Reiniciar"
+VITASHELL_SETTINGS_POWEROFF = "Apagar"
+VITASHELL_SETTINGS_STANDBY = "Suspensión"
+VITASHELL_SETTINGS_USB_MEMORY_CARD = "Tarjeta de Memoria"
+VITASHELL_SETTINGS_USB_GAME_CARD = "Tarjeta de Juego"
+VITASHELL_SETTINGS_USB_SD2VITA = "sd2vita"
+VITASHELL_SETTINGS_USB_PSVSD = "psvsd"
+VITASHELL_SETTINGS_SELECT_BUTTON_USB = "USB"
+VITASHELL_SETTINGS_SELECT_BUTTON_FTP = "FTP"
+
+# USB strings - Carácteres USB
+USB_CONNECTED = "USB conectado"
+USB_UX0_MOUNTED = "USB ux0: montada."
+USB_UX0_UMOUNTED = "USB ux0: desmontada."
+GAMECARD_UX0_MOUNTED = "gamecard ux0: montada."
+GAMECARD_UX0_uMOUNTED = "gamecard ux0: desmontada."
+USB_NOT_CONNECTED = "Conecta este sistema a un PC usando un cable USB."
+USB_CONNECTION_NOT_AVAILABLE = "La conexión USB no está disponible en este dispositivo."
+USB_WAIT_ATTACH = "Por favor, conecte un Pendrive USB para continuar\Si ya se ha conectado, por favor, desconectelo\y vuelva a conectarlo."
+
+# QR strings - Carácteres QR
+QR_SCANNING = "Escaneando códigos QR..."
+QR_OPEN_WEBSITE = "¿Quieres abrir este enlace:\%s ?"
+QR_SHOW_CONTENTS = "El código QR dice:\%s"
+QR_CONFIRM_INSTALL = "¿Quieres instalar este paquete:\%s?\Archivo: %s\Peso: %s"
+QR_CONFIRM_DOWNLOAD = "¿Quieres descargar este archivo:\%s?\Archivo: %s\Peso: %s"
+
+# Adhoc strings - Carácteres Adhoc
+ADHOC_RECEIVE_SEARCHING_PSVITA = "Buscando una PSVita para recibir archivos...\Por favor espere..."
+ADHOC_SELECT_PSVITA = "Seleccione una PSVita:"
+ADHOC_RECEIVE_QUESTION = "Quiere recibir desde %s?"
+ADHOC_CLIENT_DECLINED = "El cliente ha rechazado su solicitud."
+
+# Others - Otros
+UMA0_MOUNTED = "uma0: montada."
+UMA0_UMOUNTED = "uma0: desmontada."
+IMC0_MOUNTED = "imc0: montada."
+IMC0_UMOUNTED = "imc0: desmontada."
+XMC0_MOUNTED = "xmc0: montada."
+XMC0_UMOUNTED = "xmc0: desmontada."
+SAFE_MODE = "MODO SEGURO"
+UNSAFE_MODE = "MODO INSEGURO"
+PLEASE_WAIT = "Por favor, espere..."
+MEMORY_CARD_NOT_FOUND = "Por favor, introduzca la tarjeta de memoria."
+GAME_CARD_NOT_FOUND = "Por favor, introduzca la tarjeta del juego."
+MICROSD_NOT_FOUND = "Por favor, introduzca la Micro SD."
+NO_SPACE_ERROR = "No hay espacio libre en la tarjeta de memoria.\Se necesita al menos %s de espacio."
+EXTENDED_PERMISSIONS_REQUIRED = "Esta caracteristica requiere permisos especiales.\Por favor, activa 'Activar homebrew inseguro' primero."
+WIFI_ERROR = "Tienes que activar la conexión Wi-Fi para usar esta función."
+FTP_SERVER = "El servidor FTP está activo en\ftp://%s:%i\\Pulsa 'Aceptar' para mantenerlo en segundo plano\Pulsa 'Cancelar' para desconectarte."
+UPDATE_QUESTION = "VitaShell %s está disponible\\¿Quieres actualizar la aplicación?"
+ARCHIVE_NAME = "Nombre de archivo"
+COMPRESSION_LEVEL = "Nivel de compresión (0-9)"
+ENTER_PASSWORD = "Ingrese contraseña"
diff --git a/main_context.c b/main_context.c
index ab5cafe..f3fc8d9 100644
--- a/main_context.c
+++ b/main_context.c
@@ -1,1233 +1,1233 @@
-/*
- VitaShell
- Copyright (C) 2015-2018, TheFloW
-
- 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, either version 3 of the License, or
- (at your option) any later version.
-
- 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 for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
-*/
-
-#include "main.h"
-#include "init.h"
-#include "io_process.h"
-#include "context_menu.h"
-#include "file.h"
-#include "language.h"
-#include "property_dialog.h"
-#include "message_dialog.h"
-#include "netcheck_dialog.h"
-#include "ime_dialog.h"
-#include "utils.h"
-#include "usb.h"
-
-char pfs_mounted_path[MAX_PATH_LENGTH];
-char pfs_mount_point[MAX_MOUNT_POINT_LENGTH];
-int read_only = 0;
-
-enum MenuHomeEntrys {
- MENU_HOME_ENTRY_REFRESH_LIVEAREA,
- MENU_HOME_ENTRY_REFRESH_LICENSE_DB,
- MENU_HOME_ENTRY_MOUNT_UMA0,
- MENU_HOME_ENTRY_MOUNT_IMC0,
- MENU_HOME_ENTRY_MOUNT_XMC0,
- MENU_HOME_ENTRY_UMOUNT_UMA0,
- MENU_HOME_ENTRY_UMOUNT_IMC0,
- MENU_HOME_ENTRY_UMOUNT_XMC0,
- MENU_HOME_ENTRY_MOUNT_USB_UX0,
- MENU_HOME_ENTRY_UMOUNT_USB_UX0,
- MENU_HOME_ENTRY_MOUNT_GAMECARD_UX0,
- MENU_HOME_ENTRY_UMOUNT_GAMECARD_UX0,
-};
-
-MenuEntry menu_home_entries[] = {
- { REFRESH_LIVEAREA, 0, 0, CTX_INVISIBLE },
- { REFRESH_LICENSE_DB, 1, 0, CTX_INVISIBLE },
- { MOUNT_UMA0, 3, 0, CTX_INVISIBLE },
- { MOUNT_IMC0, 4, 0, CTX_INVISIBLE },
- { MOUNT_XMC0, 5, 0, CTX_INVISIBLE },
- { UMOUNT_UMA0, 7, 0, CTX_INVISIBLE },
- { UMOUNT_IMC0, 8, 0, CTX_INVISIBLE },
- { UMOUNT_XMC0, 9, 0, CTX_INVISIBLE },
- { MOUNT_USB_UX0, 11, 0, CTX_INVISIBLE },
- { UMOUNT_USB_UX0, 12, 0, CTX_INVISIBLE },
- { MOUNT_GAMECARD_UX0, 14, 0, CTX_INVISIBLE },
- { UMOUNT_GAMECARD_UX0, 15, 0, CTX_INVISIBLE },
-};
-
-#define N_MENU_HOME_ENTRIES (sizeof(menu_home_entries) / sizeof(MenuEntry))
-
-enum MenuMainEntrys {
- MENU_MAIN_ENTRY_OPEN_DECRYPTED,
- MENU_MAIN_ENTRY_MARK_UNMARK_ALL,
- MENU_MAIN_ENTRY_MOVE,
- MENU_MAIN_ENTRY_COPY,
- MENU_MAIN_ENTRY_PASTE,
- MENU_MAIN_ENTRY_DELETE,
- MENU_MAIN_ENTRY_RENAME,
- MENU_MAIN_ENTRY_NEW,
- MENU_MAIN_ENTRY_PROPERTIES,
- MENU_MAIN_ENTRY_SORT_BY,
- MENU_MAIN_ENTRY_MORE,
- MENU_MAIN_ENTRY_SEND,
- MENU_MAIN_ENTRY_RECEIVE,
-};
-
-MenuEntry menu_main_entries[] = {
- { OPEN_DECRYPTED, 0, 0, CTX_INVISIBLE },
- { MARK_ALL, 1, 0, CTX_INVISIBLE },
- { MOVE, 3, 0, CTX_INVISIBLE },
- { COPY, 4, 0, CTX_INVISIBLE },
- { PASTE, 5, 0, CTX_INVISIBLE },
- { DELETE, 7, 0, CTX_INVISIBLE },
- { RENAME, 8, 0, CTX_INVISIBLE },
- { NEW, 10, CTX_FLAG_MORE, CTX_VISIBLE },
- { PROPERTIES, 11, 0, CTX_INVISIBLE },
- { SORT_BY, 13, CTX_FLAG_MORE, CTX_VISIBLE },
- { MORE, 14, CTX_FLAG_MORE, CTX_INVISIBLE },
- { SEND, 17, 0, CTX_INVISIBLE }, // CTX_FLAG_BARRIER
- { RECEIVE, 18, 0, CTX_INVISIBLE },
-};
-
-#define N_MENU_MAIN_ENTRIES (sizeof(menu_main_entries) / sizeof(MenuEntry))
-
-enum MenuSortEntrys {
- MENU_SORT_ENTRY_BY_NAME,
- MENU_SORT_ENTRY_BY_SIZE,
- MENU_SORT_ENTRY_BY_DATE,
-};
-
-MenuEntry menu_sort_entries[] = {
- { BY_NAME, 12, 0, CTX_INVISIBLE },
- { BY_SIZE, 13, 0, CTX_INVISIBLE },
- { BY_DATE, 14, 0, CTX_INVISIBLE },
-};
-
-#define N_MENU_SORT_ENTRIES (sizeof(menu_sort_entries) / sizeof(MenuEntry))
-
-enum MenuMoreEntrys {
- MENU_MORE_ENTRY_COMPRESS,
- MENU_MORE_ENTRY_INSTALL_ALL,
- MENU_MORE_ENTRY_INSTALL_FOLDER,
- MENU_MORE_ENTRY_EXPORT_MEDIA,
- MENU_MORE_ENTRY_CALCULATE_SHA1,
-};
-
-MenuEntry menu_more_entries[] = {
- { COMPRESS, 12, 0, CTX_INVISIBLE },
- { INSTALL_ALL, 13, 0, CTX_INVISIBLE },
- { INSTALL_FOLDER, 14, 0, CTX_INVISIBLE },
- { EXPORT_MEDIA, 15, 0, CTX_INVISIBLE },
- { CALCULATE_SHA1, 16, 0, CTX_INVISIBLE },
-};
-
-#define N_MENU_MORE_ENTRIES (sizeof(menu_more_entries) / sizeof(MenuEntry))
-
-enum MenuNewEntrys {
- MENU_NEW_FILE,
- MENU_NEW_FOLDER
-};
-
-MenuEntry menu_new_entries[] = {
- {NEW_FILE, 10, 0, CTX_INVISIBLE},
- {NEW_FOLDER, 11, 0, CTX_INVISIBLE}
-
-};
-
-#define N_MENU_NEW_ENTRIES (sizeof(menu_new_entries) / sizeof(MenuEntry))
-
-static int contextMenuHomeEnterCallback(int sel, void *context);
-static int contextMenuMainEnterCallback(int sel, void *context);
-static int contextMenuSortEnterCallback(int sel, void *context);
-static int contextMenuMoreEnterCallback(int sel, void *context);
-static int contextMenuNewEnterCallback(int sel, void *context);
-
-ContextMenu context_menu_home = {
- .parent = NULL,
- .entries = menu_home_entries,
- .n_entries = N_MENU_HOME_ENTRIES,
- .max_width = 0.0f,
- .callback = contextMenuHomeEnterCallback,
- .sel = -1,
-};
-
-ContextMenu context_menu_main = {
- .parent = NULL,
- .entries = menu_main_entries,
- .n_entries = N_MENU_MAIN_ENTRIES,
- .max_width = 0.0f,
- .callback = contextMenuMainEnterCallback,
- .sel = -1,
-};
-
-ContextMenu context_menu_sort = {
- .parent = &context_menu_main,
- .entries = menu_sort_entries,
- .n_entries = N_MENU_SORT_ENTRIES,
- .max_width = 0.0f,
- .callback = contextMenuSortEnterCallback,
- .sel = -1,
-};
-
-ContextMenu context_menu_more = {
- .parent = &context_menu_main,
- .entries = menu_more_entries,
- .n_entries = N_MENU_MORE_ENTRIES,
- .max_width = 0.0f,
- .callback = contextMenuMoreEnterCallback,
- .sel = -1,
-};
-
-ContextMenu context_menu_new = {
- .parent = &context_menu_main,
- .entries = menu_new_entries,
- .n_entries = N_MENU_NEW_ENTRIES,
- .max_width = 0.0f,
- .callback = contextMenuNewEnterCallback,
- .sel = -1,
-};
-
-/*
- SceAppMgr mount IDs:
- 0x64: ux0:picture
- 0x65: ur0:user/00/psnfriend
- 0x66: ur0:user/00/psnmsg
- 0x69: ux0:music
- 0x6E: ux0:appmeta
- 0xC8: ur0:temp/sqlite
- 0xCD: ux0:cache
- 0x12E: ur0:user/00/trophy/data/sce_trop
- 0x12F: ur0:user/00/trophy/data
- 0x3E8: ux0:app, vs0:app, gro0:app
- 0x3E9: ux0:patch
- 0x3EB: ?
- 0x3EA: ux0:addcont
- 0x3EC: ux0:theme
- 0x3ED: ux0:user/00/savedata
- 0x3EE: ur0:user/00/savedata
- 0x3EF: vs0:sys/external
- 0x3F0: vs0:data/external
-*/
-
-int known_pfs_ids[] = {
- 0x6E,
- 0x12E,
- 0x12F,
- 0x3ED,
-};
-
-int pfsMount(const char *path) {
- int res;
- char work_path[MAX_PATH_LENGTH];
- char klicensee[0x10];
- char license_buf[0x200];
- ShellMountIdArgs args;
-
- memset(klicensee, 0, sizeof(klicensee));
-
-/*
- snprintf(work_path, MAX_PATH_LENGTH - 1, "%ssce_sys/package/work.bin", path);
- if (ReadFile(work_path, license_buf, sizeof(license_buf)) == sizeof(license_buf)) {
- int res = shellUserGetRifVitaKey(license_buf, klicensee);
- debugPrintf("read license: 0x%08X\n", res);
- }
-*/
- args.process_titleid = VITASHELL_TITLEID;
- args.path = path;
- args.desired_mount_point = NULL;
- args.klicensee = klicensee;
- args.mount_point = pfs_mount_point;
-
- read_only = 0;
-
- int i;
- for (i = 0; i < sizeof(known_pfs_ids) / sizeof(int); i++) {
- args.id = known_pfs_ids[i];
-
- res = shellUserMountById(&args);
- if (res >= 0)
- return res;
- }
-
- read_only = 1;
- return sceAppMgrGameDataMount(path, 0, 0, pfs_mount_point);
-}
-
-int pfsUmount() {
- if (pfs_mount_point[0] == 0)
- return -1;
-
- int res = sceAppMgrUmount(pfs_mount_point);
- if (res >= 0) {
- memset(pfs_mount_point, 0, sizeof(pfs_mount_point));
- memset(pfs_mounted_path, 0, sizeof(pfs_mounted_path));
- }
-
- return res;
-}
-
-void initContextMenuWidth() {
- int i;
-
- // Home
- for (i = 0; i < N_MENU_HOME_ENTRIES; i++) {
- context_menu_home.max_width = MAX(context_menu_home.max_width, pgf_text_width(language_container[menu_home_entries[i].name]));
- }
-
- context_menu_home.max_width += 2.0f * CONTEXT_MENU_MARGIN;
- context_menu_home.max_width = MAX(context_menu_home.max_width, CONTEXT_MENU_MIN_WIDTH);
-
- // Main
- for (i = 0; i < N_MENU_MAIN_ENTRIES; i++) {
- context_menu_main.max_width = MAX(context_menu_main.max_width, pgf_text_width(language_container[menu_main_entries[i].name]));
-
- if (menu_main_entries[i].name == MARK_ALL) {
- menu_main_entries[i].name = UNMARK_ALL;
- i--;
- }
- }
-
- context_menu_main.max_width += 2.0f * CONTEXT_MENU_MARGIN;
- context_menu_main.max_width = MAX(context_menu_main.max_width, CONTEXT_MENU_MIN_WIDTH);
-
- // Sort
- for (i = 0; i < N_MENU_SORT_ENTRIES; i++) {
- context_menu_sort.max_width = MAX(context_menu_sort.max_width, pgf_text_width(language_container[menu_sort_entries[i].name]));
- }
-
- context_menu_sort.max_width += 2.0f * CONTEXT_MENU_MARGIN;
- context_menu_sort.max_width = MAX(context_menu_sort.max_width, CONTEXT_MENU_MIN_WIDTH);
-
- // More
- for (i = 0; i < N_MENU_MORE_ENTRIES; i++) {
- context_menu_more.max_width = MAX(context_menu_more.max_width, pgf_text_width(language_container[menu_more_entries[i].name]));
- }
-
- context_menu_more.max_width += 2.0f * CONTEXT_MENU_MARGIN;
- context_menu_more.max_width = MAX(context_menu_more.max_width, CONTEXT_MENU_MIN_WIDTH);
-
- // New
- for (i = 0; i < N_MENU_NEW_ENTRIES; i++) {
- context_menu_new.max_width = MAX(context_menu_new.max_width,
- pgf_text_width(language_container[menu_new_entries[i].name]));
- }
- context_menu_new.max_width += 2.0f * CONTEXT_MENU_MARGIN;
- context_menu_new.max_width = MAX(context_menu_new.max_width, CONTEXT_MENU_MIN_WIDTH);
-}
-
-void setContextMenuHomeVisibilities() {
- int i;
-
- // All visible
- for (i = 0; i < N_MENU_HOME_ENTRIES; i++) {
- if (menu_home_entries[i].visibility == CTX_INVISIBLE)
- menu_home_entries[i].visibility = CTX_VISIBLE;
- }
-
- if (checkFolderExist("uma0:")) {
- menu_home_entries[MENU_HOME_ENTRY_MOUNT_UMA0].visibility = CTX_INVISIBLE;
- } else {
- menu_home_entries[MENU_HOME_ENTRY_MOUNT_USB_UX0].visibility = CTX_INVISIBLE;
- }
-
- if ((kernel_modid >= 0 || kernel_modid == 0x8002D013) && user_modid >= 0 &&
- shellUserIsUx0Redirected("sdstor0:uma-pp-act-a", "sdstor0:uma-lp-act-entire") == 1) {
- menu_home_entries[MENU_HOME_ENTRY_MOUNT_UMA0].visibility = CTX_INVISIBLE;
- menu_home_entries[MENU_HOME_ENTRY_MOUNT_USB_UX0].visibility = CTX_INVISIBLE;
- } else {
- menu_home_entries[MENU_HOME_ENTRY_UMOUNT_USB_UX0].visibility = CTX_INVISIBLE;
- }
-
- if (!checkFileExist("sdstor0:gcd-lp-ign-entire")) {
- menu_home_entries[MENU_HOME_ENTRY_MOUNT_GAMECARD_UX0].visibility = CTX_INVISIBLE;
- menu_home_entries[MENU_HOME_ENTRY_UMOUNT_GAMECARD_UX0].visibility = CTX_INVISIBLE;
- } else {
- if ((kernel_modid >= 0 || kernel_modid == 0x8002D013) && user_modid >= 0 &&
- shellUserIsUx0Redirected("sdstor0:gcd-lp-ign-entire", "sdstor0:gcd-lp-ign-entire") == 1) {
- menu_home_entries[MENU_HOME_ENTRY_MOUNT_GAMECARD_UX0].visibility = CTX_INVISIBLE;
- } else {
- menu_home_entries[MENU_HOME_ENTRY_UMOUNT_GAMECARD_UX0].visibility = CTX_INVISIBLE;
- }
- }
-
- // Invisible if already mounted or there is no internal storage
- if (!checkFileExist("sdstor0:int-lp-ign-userext") || checkFolderExist("imc0:"))
- menu_home_entries[MENU_HOME_ENTRY_MOUNT_IMC0].visibility = CTX_INVISIBLE;
-
- // Invisible if already mounted or there is no Memory Card
- if (!checkFileExist("sdstor0:xmc-lp-ign-userext") || checkFolderExist("xmc0:"))
- menu_home_entries[MENU_HOME_ENTRY_MOUNT_XMC0].visibility = CTX_INVISIBLE;
-
- // Invisible if not mounted
- if (!checkFolderExist("uma0:"))
- menu_home_entries[MENU_HOME_ENTRY_UMOUNT_UMA0].visibility = CTX_INVISIBLE;
-
- // Invisible if not mounted
- if (!checkFolderExist("imc0:"))
- menu_home_entries[MENU_HOME_ENTRY_UMOUNT_IMC0].visibility = CTX_INVISIBLE;
-
- // Invisible if not mounted
- if (!checkFolderExist("xmc0:"))
- menu_home_entries[MENU_HOME_ENTRY_UMOUNT_XMC0].visibility = CTX_INVISIBLE;
-
- // Go to first entry
- for (i = 0; i < N_MENU_HOME_ENTRIES; i++) {
- if (menu_home_entries[i].visibility == CTX_VISIBLE) {
- context_menu_home.sel = i;
- break;
- }
- }
-
- if (i == N_MENU_HOME_ENTRIES)
- context_menu_home.sel = -1;
-}
-
-void setContextMenuMainVisibilities() {
- int i;
-
- // All visible
- for (i = 0; i < N_MENU_MAIN_ENTRIES; i++) {
- if (menu_main_entries[i].visibility == CTX_INVISIBLE)
- menu_main_entries[i].visibility = CTX_VISIBLE;
- }
-
- FileListEntry *file_entry = fileListGetNthEntry(&file_list, base_pos + rel_pos);
- if (!file_entry)
- return;
-
- // menu_main_entries[MENU_MAIN_ENTRY_SEND].flags = CTX_FLAG_BARRIER;
- // menu_main_entries[MENU_MAIN_ENTRY_RECEIVE].flags = 0;
-
- // Invisble entries when on '..'
- if (strcmp(file_entry->name, DIR_UP) == 0) {
- menu_main_entries[MENU_MAIN_ENTRY_OPEN_DECRYPTED].visibility = CTX_INVISIBLE;
- menu_main_entries[MENU_MAIN_ENTRY_MARK_UNMARK_ALL].visibility = CTX_INVISIBLE;
- menu_main_entries[MENU_MAIN_ENTRY_MOVE].visibility = CTX_INVISIBLE;
- menu_main_entries[MENU_MAIN_ENTRY_COPY].visibility = CTX_INVISIBLE;
- menu_main_entries[MENU_MAIN_ENTRY_DELETE].visibility = CTX_INVISIBLE;
- menu_main_entries[MENU_MAIN_ENTRY_RENAME].visibility = CTX_INVISIBLE;
- menu_main_entries[MENU_MAIN_ENTRY_PROPERTIES].visibility = CTX_INVISIBLE;
- menu_main_entries[MENU_MAIN_ENTRY_SEND].visibility = CTX_INVISIBLE;
- // menu_main_entries[MENU_MAIN_ENTRY_RECEIVE].flags = CTX_FLAG_BARRIER;
- }
-
- // Invisible 'Paste' if nothing is copied yet
- if (copy_list.length == 0) {
- menu_main_entries[MENU_MAIN_ENTRY_PASTE].visibility = CTX_INVISIBLE;
- }
-
- // Invisible 'Paste' if the files to move are not from the same partition
- if (copy_mode == COPY_MODE_MOVE) {
- char *p = strchr(file_list.path, ':');
- char *q = strchr(copy_list.path, ':');
- if (p && q) {
- *p = '\0';
- *q = '\0';
-
- if (strcasecmp(file_list.path, copy_list.path) != 0) {
- menu_main_entries[MENU_MAIN_ENTRY_PASTE].visibility = CTX_INVISIBLE;
- }
-
- *q = ':';
- *p = ':';
- } else {
- menu_main_entries[MENU_MAIN_ENTRY_PASTE].visibility = CTX_INVISIBLE;
- }
- }
-
- // Invisible write operations in archives
- // TODO: read-only mount points
- if (isInArchive() || (pfs_mounted_path[0] && strstr(file_list.path, pfs_mounted_path) && read_only)) {
- menu_main_entries[MENU_MAIN_ENTRY_OPEN_DECRYPTED].visibility = CTX_INVISIBLE;
- menu_main_entries[MENU_MAIN_ENTRY_MOVE].visibility = CTX_INVISIBLE;
- menu_main_entries[MENU_MAIN_ENTRY_PASTE].visibility = CTX_INVISIBLE;
- menu_main_entries[MENU_MAIN_ENTRY_DELETE].visibility = CTX_INVISIBLE;
- menu_main_entries[MENU_MAIN_ENTRY_RENAME].visibility = CTX_INVISIBLE;
- menu_main_entries[MENU_MAIN_ENTRY_NEW].visibility = CTX_INVISIBLE;
- menu_main_entries[MENU_MAIN_ENTRY_SEND].visibility = CTX_INVISIBLE;
- menu_main_entries[MENU_MAIN_ENTRY_RECEIVE].visibility = CTX_INVISIBLE;
- }
-
- // Mark/Unmark all text
- if (mark_list.length == (file_list.length - 1)) { // All marked
- menu_main_entries[MENU_MAIN_ENTRY_MARK_UNMARK_ALL].name = UNMARK_ALL;
- } else { // Not all marked yet
- // On marked entry
- if (fileListFindEntry(&mark_list, file_entry->name)) {
- menu_main_entries[MENU_MAIN_ENTRY_MARK_UNMARK_ALL].name = UNMARK_ALL;
- } else {
- menu_main_entries[MENU_MAIN_ENTRY_MARK_UNMARK_ALL].name = MARK_ALL;
- }
- }
-
- // Invisible if it's not folder or sce_pfs does not exist
- if (!file_entry->is_folder) {
- menu_main_entries[MENU_MAIN_ENTRY_OPEN_DECRYPTED].visibility = CTX_INVISIBLE;
- } else {
- char path[MAX_PATH_LENGTH];
- snprintf(path, MAX_PATH_LENGTH - 1, "%s%ssce_pfs", file_list.path, file_entry->name);
-
- if (!checkFolderExist(path))
- menu_main_entries[MENU_MAIN_ENTRY_OPEN_DECRYPTED].visibility = CTX_INVISIBLE;
- }
-
- // Go to first entry
- for (i = 0; i < N_MENU_MAIN_ENTRIES; i++) {
- if (menu_main_entries[i].visibility == CTX_VISIBLE) {
- context_menu_main.sel = i;
- break;
- }
- }
-
- if (i == N_MENU_MAIN_ENTRIES)
- context_menu_main.sel = -1;
-}
-
-void setContextMenuSortVisibilities() {
- int i;
-
- // All visible
- for (i = 0; i < N_MENU_SORT_ENTRIES; i++) {
- if (menu_sort_entries[i].visibility == CTX_INVISIBLE)
- menu_sort_entries[i].visibility = CTX_VISIBLE;
- }
-
- // Invisible when it's the current mode
- if (sort_mode == SORT_BY_NAME)
- menu_sort_entries[MENU_SORT_ENTRY_BY_NAME].visibility = CTX_INVISIBLE;
- else if (sort_mode == SORT_BY_SIZE)
- menu_sort_entries[MENU_SORT_ENTRY_BY_SIZE].visibility = CTX_INVISIBLE;
- else if (sort_mode == SORT_BY_DATE)
- menu_sort_entries[MENU_SORT_ENTRY_BY_DATE].visibility = CTX_INVISIBLE;
-
- // Go to first entry
- for (i = 0; i < N_MENU_SORT_ENTRIES; i++) {
- if (menu_sort_entries[i].visibility == CTX_VISIBLE) {
- context_menu_sort.sel = i;
- break;
- }
- }
-
- if (i == N_MENU_SORT_ENTRIES)
- context_menu_sort.sel = -1;
-}
-
-void setContextMenuMoreVisibilities() {
- int i;
-
- // All visible
- for (i = 0; i < N_MENU_MORE_ENTRIES; i++) {
- if (menu_more_entries[i].visibility == CTX_INVISIBLE)
- menu_more_entries[i].visibility = CTX_VISIBLE;
- }
-
- FileListEntry *file_entry = fileListGetNthEntry(&file_list, base_pos + rel_pos);
- if (!file_entry)
- return;
-
- // Invisble entries when on '..'
- if (strcmp(file_entry->name, DIR_UP) == 0) {
- menu_more_entries[MENU_MORE_ENTRY_COMPRESS].visibility = CTX_INVISIBLE;
- menu_more_entries[MENU_MORE_ENTRY_INSTALL_ALL].visibility = CTX_INVISIBLE;
- menu_more_entries[MENU_MORE_ENTRY_INSTALL_FOLDER].visibility = CTX_INVISIBLE;
- menu_more_entries[MENU_MORE_ENTRY_EXPORT_MEDIA].visibility = CTX_INVISIBLE;
- menu_more_entries[MENU_MORE_ENTRY_CALCULATE_SHA1].visibility = CTX_INVISIBLE;
- }
-
- // Invisble operations in archives
- if (isInArchive() || (pfs_mounted_path[0] && strstr(file_list.path, pfs_mounted_path) && read_only)) {
- menu_more_entries[MENU_MORE_ENTRY_COMPRESS].visibility = CTX_INVISIBLE;
- menu_more_entries[MENU_MORE_ENTRY_INSTALL_ALL].visibility = CTX_INVISIBLE;
- menu_more_entries[MENU_MORE_ENTRY_INSTALL_FOLDER].visibility = CTX_INVISIBLE;
- menu_more_entries[MENU_MORE_ENTRY_EXPORT_MEDIA].visibility = CTX_INVISIBLE;
- menu_more_entries[MENU_MORE_ENTRY_CALCULATE_SHA1].visibility = CTX_INVISIBLE;
- }
-
- if (file_entry->is_folder) {
- menu_more_entries[MENU_MORE_ENTRY_CALCULATE_SHA1].visibility = CTX_INVISIBLE;
-
- char check_path[MAX_PATH_LENGTH];
-
- do {
- if (strcasecmp(file_list.path, "ux0:app/") == 0 ||
- strcasecmp(file_list.path, "ux0:patch/") == 0) {
- menu_more_entries[MENU_MORE_ENTRY_INSTALL_FOLDER].visibility = CTX_INVISIBLE;
- break;
- }
-
- snprintf(check_path, MAX_PATH_LENGTH - 1, "%s%s/eboot.bin", file_list.path, file_entry->name);
- if (!checkFileExist(check_path)) {
- menu_more_entries[MENU_MORE_ENTRY_INSTALL_FOLDER].visibility = CTX_INVISIBLE;
- break;
- }
-
- snprintf(check_path, MAX_PATH_LENGTH - 1, "%s%s/sce_sys/param.sfo", file_list.path, file_entry->name);
- if (!checkFileExist(check_path)) {
- menu_more_entries[MENU_MORE_ENTRY_INSTALL_FOLDER].visibility = CTX_INVISIBLE;
- break;
- }
- } while (0);
- } else {
- menu_more_entries[MENU_MORE_ENTRY_INSTALL_FOLDER].visibility = CTX_INVISIBLE;
- }
-
- if(file_entry->type != FILE_TYPE_VPK) {
- menu_more_entries[MENU_MORE_ENTRY_INSTALL_ALL].visibility = CTX_INVISIBLE;
- }
-
- // Invisible export for non-media files
- if (!file_entry->is_folder &&
- file_entry->type != FILE_TYPE_BMP && file_entry->type != FILE_TYPE_JPEG &&
- file_entry->type != FILE_TYPE_PNG && file_entry->type != FILE_TYPE_MP3 &&
- file_entry->type != FILE_TYPE_MP4) {
- menu_more_entries[MENU_MORE_ENTRY_EXPORT_MEDIA].visibility = CTX_INVISIBLE;
- }
-
- // Go to first entry
- for (i = 0; i < N_MENU_MORE_ENTRIES; i++) {
- if (menu_more_entries[i].visibility == CTX_VISIBLE) {
- context_menu_more.sel = i;
- break;
- }
- }
-
- if (i == N_MENU_MORE_ENTRIES)
- context_menu_more.sel = -1;
-}
-
-void setContextMenuNewVisibilities() {
- int i;
-
- // All visible
- for (i = 0; i < N_MENU_NEW_ENTRIES; i++) {
- if (menu_new_entries[i].visibility == CTX_INVISIBLE)
- menu_new_entries[i].visibility = CTX_VISIBLE;
- }
-
- // Go to first entry
- for (i = 0; i < N_MENU_NEW_ENTRIES; i++) {
- if (menu_new_entries[i].visibility == CTX_VISIBLE) {
- context_menu_new.sel = i;
- break;
- }
- }
-
- if (i == N_MENU_NEW_ENTRIES)
- context_menu_new.sel = -1;
-}
-
-static int contextMenuHomeEnterCallback(int sel, void *context) {
- switch (sel) {
- case MENU_HOME_ENTRY_REFRESH_LIVEAREA:
- {
- if (is_safe_mode) {
- infoDialog(language_container[EXTENDED_PERMISSIONS_REQUIRED]);
- } else {
- initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_YESNO, language_container[REFRESH_LIVEAREA_QUESTION]);
- setDialogStep(DIALOG_STEP_REFRESH_LIVEAREA_QUESTION);
- }
-
- break;
- }
-
- case MENU_HOME_ENTRY_REFRESH_LICENSE_DB:
- {
- if (is_safe_mode) {
- infoDialog(language_container[EXTENDED_PERMISSIONS_REQUIRED]);
- } else {
- initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_YESNO, language_container[REFRESH_LICENSE_DB_QUESTION]);
- setDialogStep(DIALOG_STEP_REFRESH_LICENSE_DB_QUESTION);
- }
-
- break;
- }
-
- case MENU_HOME_ENTRY_MOUNT_UMA0:
- {
- if (is_safe_mode) {
- infoDialog(language_container[EXTENDED_PERMISSIONS_REQUIRED]);
- } else {
- if (checkFileExist("sdstor0:uma-lp-act-entire")) {
- int res = vshIoMount(0xF00, NULL, 0, 0, 0, 0);
- if (res < 0)
- errorDialog(res);
- else
- infoDialog(language_container[UMA0_MOUNTED]);
- refreshFileList();
- } else {
- initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_CANCEL, language_container[USB_WAIT_ATTACH]);
- setDialogStep(DIALOG_STEP_USB_ATTACH_WAIT);
- }
- }
-
- break;
- }
-
- case MENU_HOME_ENTRY_MOUNT_IMC0:
- {
- if (is_safe_mode) {
- infoDialog(language_container[EXTENDED_PERMISSIONS_REQUIRED]);
- } else {
- int res = vshIoMount(0xD00, NULL, 2, 0, 0, 0);
- if (res < 0)
- errorDialog(res);
- else
- infoDialog(language_container[IMC0_MOUNTED]);
- refreshFileList();
- }
-
- break;
- }
-
- case MENU_HOME_ENTRY_MOUNT_XMC0:
- {
- if (is_safe_mode) {
- infoDialog(language_container[EXTENDED_PERMISSIONS_REQUIRED]);
- } else {
- int res = vshIoMount(0xE00, NULL, 2, 0, 0, 0);
- if (res < 0)
- errorDialog(res);
- else
- infoDialog(language_container[XMC0_MOUNTED]);
- refreshFileList();
- }
-
- break;
- }
-
- case MENU_HOME_ENTRY_UMOUNT_UMA0:
- {
- if (is_safe_mode) {
- infoDialog(language_container[EXTENDED_PERMISSIONS_REQUIRED]);
- } else {
- vshIoUmount(0xF00, 0, 0, 0);
- vshIoUmount(0xF00, 1, 0, 0);
- infoDialog(language_container[UMA0_UMOUNTED]);
- refreshFileList();
- }
-
- break;
- }
-
- case MENU_HOME_ENTRY_UMOUNT_IMC0:
- {
- if (is_safe_mode) {
- infoDialog(language_container[EXTENDED_PERMISSIONS_REQUIRED]);
- } else {
- vshIoUmount(0xD00, 0, 0, 0);
- vshIoUmount(0xD00, 1, 0, 0);
- infoDialog(language_container[IMC0_UMOUNTED]);
- refreshFileList();
- }
-
- break;
- }
-
- case MENU_HOME_ENTRY_UMOUNT_XMC0:
- {
- if (is_safe_mode) {
- infoDialog(language_container[EXTENDED_PERMISSIONS_REQUIRED]);
- } else {
- vshIoUmount(0xE00, 0, 0, 0);
- vshIoUmount(0xE00, 1, 0, 0);
- infoDialog(language_container[XMC0_UMOUNTED]);
- refreshFileList();
- }
-
- break;
- }
-
- case MENU_HOME_ENTRY_MOUNT_USB_UX0:
- {
- if (mountUsbUx0() >= 0) {
- infoDialog(language_container[USB_UX0_MOUNTED]);
- refreshFileList();
- }
- break;
- }
-
- case MENU_HOME_ENTRY_UMOUNT_USB_UX0:
- {
- if (umountUsbUx0() >= 0) {
- infoDialog(language_container[USB_UX0_UMOUNTED]);
- refreshFileList();
- }
- break;
- }
-
- case MENU_HOME_ENTRY_MOUNT_GAMECARD_UX0:
- {
- if (mountGamecardUx0() >= 0) {
- infoDialog(language_container[GAMECARD_UX0_MOUNTED]);
- refreshFileList();
- }
- break;
- }
-
- case MENU_HOME_ENTRY_UMOUNT_GAMECARD_UX0:
- {
- if (umountGamecardUx0() >= 0) {
- infoDialog(language_container[GAMECARD_UX0_UMOUNTED]);
- refreshFileList();
- }
- break;
- }
- }
-
- return CONTEXT_MENU_CLOSING;
-}
-
-static int contextMenuMainEnterCallback(int sel, void *context) {
- switch (sel) {
-
- case MENU_MAIN_ENTRY_OPEN_DECRYPTED:
- {
- FileListEntry *file_entry = fileListGetNthEntry(&file_list, base_pos + rel_pos);
- if (file_entry) {
- char path[MAX_PATH_LENGTH];
- int res;
-
- pfsUmount();
-
- snprintf(path, MAX_PATH_LENGTH - 1, "%s%s", file_list.path, file_entry->name);
- res = pfsMount(path);
-
- // In case we're at ux0:patch or grw0:patch we need to apply the mounting at ux0:app or gro0:app
- if (res < 0) {
- if (strncasecmp(file_list.path, "ux0:patch", 9) == 0 ||
- strncasecmp(file_list.path, "grw0:patch", 10) == 0) {
- snprintf(path, MAX_PATH_LENGTH - 1, "ux0:app/%s", file_entry->name);
- res = pfsMount(path);
-
- if (res < 0) {
- snprintf(path, MAX_PATH_LENGTH - 1, "gro0:app/%s", file_entry->name);
- res = pfsMount(path);
- }
- }
- }
-
- if (res < 0)
- errorDialog(res);
-
- if (res >= 0) {
- addEndSlash(file_list.path);
- strcat(file_list.path, file_entry->name);
- strcpy(pfs_mounted_path, file_list.path);
- dirLevelUp();
-
- // Save last dir
- WriteFile(VITASHELL_LASTDIR, file_list.path, strlen(file_list.path) + 1);
-
- // Open folder
- int res = refreshFileList();
- if (res < 0)
- errorDialog(res);
- } else {
- errorDialog(res);
- }
- }
-
- break;
- }
-
- case MENU_MAIN_ENTRY_MARK_UNMARK_ALL:
- {
- FileListEntry *file_entry = fileListGetNthEntry(&file_list, base_pos + rel_pos);
- if (file_entry) {
- int on_marked_entry = 0;
- int length = mark_list.length;
-
- if (fileListFindEntry(&mark_list, file_entry->name))
- on_marked_entry = 1;
-
- // Empty mark list
- fileListEmpty(&mark_list);
-
- // Mark all if not all entries are marked yet and we are not focusing on a marked entry
- if (length != (file_list.length - 1) && !on_marked_entry) {
- FileListEntry *file_entry = file_list.head->next; // Ignore '..'
-
- int i;
- for (i = 0; i < file_list.length - 1; i++) {
- fileListAddEntry(&mark_list, fileListCopyEntry(file_entry), SORT_NONE);
-
- // Next
- file_entry = file_entry->next;
- }
- }
- }
-
- break;
- }
-
- case MENU_MAIN_ENTRY_MOVE:
- case MENU_MAIN_ENTRY_COPY:
- {
- FileListEntry *file_entry = fileListGetNthEntry(&file_list, base_pos + rel_pos);
- if (file_entry) {
- // Umount if last path copied from is the pfs mounted path
- if (pfs_mounted_path[0] &&
- !strstr(file_list.path, pfs_mounted_path) &&
- strstr(copy_list.path, pfs_mounted_path)) {
- pfsUmount();
- }
-
- // Mode
- if (sel == MENU_MAIN_ENTRY_MOVE) {
- copy_mode = COPY_MODE_MOVE;
- } else {
- copy_mode = isInArchive() ? COPY_MODE_EXTRACT : COPY_MODE_NORMAL;
- }
-
- strcpy(archive_copy_path, archive_path);
-
- // Empty copy list at first
- fileListEmpty(©_list);
-
- // Paths
- if (fileListFindEntry(&mark_list, file_entry->name)) { // On marked entry
- // Copy mark list to copy list
- FileListEntry *mark_entry = mark_list.head;
-
- int i;
- for (i = 0; i < mark_list.length; i++) {
- fileListAddEntry(©_list, fileListCopyEntry(mark_entry), SORT_NONE);
-
- // Next
- mark_entry = mark_entry->next;
- }
- } else {
- fileListAddEntry(©_list, fileListCopyEntry(file_entry), SORT_NONE);
- }
-
- strcpy(copy_list.path, file_list.path);
- copy_list.is_in_archive = isInArchive();
-
- char *message;
-
- // On marked entry
- if (copy_list.length > 1 && fileListFindEntry(©_list, file_entry->name)) {
- message = language_container[COPIED_FILES_FOLDERS];
- } else {
- message = language_container[file_entry->is_folder ? COPIED_FOLDER : COPIED_FILE];
- }
-
- // Copy message
- infoDialog(message, copy_list.length);
- }
-
- break;
- }
-
- case MENU_MAIN_ENTRY_PASTE:
- {
- int copy_text = 0;
-
- switch (copy_mode) {
- case COPY_MODE_NORMAL:
- copy_text = COPYING;
- break;
-
- case COPY_MODE_MOVE:
- copy_text = MOVING;
- break;
-
- case COPY_MODE_EXTRACT:
- copy_text = EXTRACTING;
- break;
- }
-
- initMessageDialog(MESSAGE_DIALOG_PROGRESS_BAR, language_container[copy_text]);
- setDialogStep(DIALOG_STEP_PASTE);
- break;
- }
-
- case MENU_MAIN_ENTRY_DELETE:
- {
- FileListEntry *file_entry = fileListGetNthEntry(&file_list, base_pos + rel_pos);
- if (file_entry) {
- char *message;
-
- // On marked entry
- if (mark_list.length > 1 && fileListFindEntry(&mark_list, file_entry->name)) {
- message = language_container[DELETE_FILES_FOLDERS_QUESTION];
- } else {
- message = language_container[file_entry->is_folder ? DELETE_FOLDER_QUESTION : DELETE_FILE_QUESTION];
- }
-
- initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_YESNO, message);
- setDialogStep(DIALOG_STEP_DELETE_QUESTION);
- }
-
- break;
- }
-
- case MENU_MAIN_ENTRY_RENAME:
- {
- FileListEntry *file_entry = fileListGetNthEntry(&file_list, base_pos + rel_pos);
- if (file_entry) {
- char name[MAX_NAME_LENGTH];
- strcpy(name, file_entry->name);
- removeEndSlash(name);
-
- initImeDialog(language_container[RENAME], name, MAX_NAME_LENGTH, SCE_IME_TYPE_BASIC_LATIN, 0, 0);
-
- setDialogStep(DIALOG_STEP_RENAME);
- }
-
- break;
- }
-
- case MENU_MAIN_ENTRY_PROPERTIES:
- {
- FileListEntry *file_entry = fileListGetNthEntry(&file_list, base_pos + rel_pos);
- if (file_entry) {
- snprintf(cur_file, MAX_PATH_LENGTH - 1, "%s%s", file_list.path, file_entry->name);
- initPropertyDialog(cur_file, file_entry);
- }
-
- break;
- }
-
- case MENU_MAIN_ENTRY_NEW:
- {
- setContextMenu(&context_menu_new);
- setContextMenuNewVisibilities();
- return CONTEXT_MENU_MORE_OPENING;
- }
-
- case MENU_MAIN_ENTRY_MORE:
- {
- setContextMenu(&context_menu_more);
- setContextMenuMoreVisibilities();
- return CONTEXT_MENU_MORE_OPENING;
- }
-
- case MENU_MAIN_ENTRY_SORT_BY:
- {
- setContextMenu(&context_menu_sort);
- setContextMenuSortVisibilities();
- return CONTEXT_MENU_MORE_OPENING;
- }
-
- case MENU_MAIN_ENTRY_SEND:
- {
- initNetCheckDialog(SCE_NETCHECK_DIALOG_MODE_PSP_ADHOC_JOIN, 60 * 1000 * 1000);
- setDialogStep(DIALOG_STEP_ADHOC_SEND_NETCHECK);
- break;
- }
-
- case MENU_MAIN_ENTRY_RECEIVE:
- {
- initNetCheckDialog(SCE_NETCHECK_DIALOG_MODE_PSP_ADHOC_CONN, 0);
- setDialogStep(DIALOG_STEP_ADHOC_RECEIVE_NETCHECK);
- break;
- }
- }
-
- return CONTEXT_MENU_CLOSING;
-}
-
-static int contextMenuSortEnterCallback(int sel, void *context) {
- switch (sel) {
- case MENU_SORT_ENTRY_BY_NAME:
- sort_mode = SORT_BY_NAME;
- break;
-
- case MENU_SORT_ENTRY_BY_SIZE:
- sort_mode = SORT_BY_SIZE;
- break;
-
- case MENU_SORT_ENTRY_BY_DATE:
- sort_mode = SORT_BY_DATE;
- break;
- }
-
- // Refresh list
- refreshFileList();
-
- return CONTEXT_MENU_CLOSING;
-}
-
-static int contextMenuMoreEnterCallback(int sel, void *context) {
- switch (sel) {
- case MENU_MORE_ENTRY_COMPRESS:
- {
- FileListEntry *file_entry = fileListGetNthEntry(&file_list, base_pos + rel_pos);
- if (file_entry) {
- char path[MAX_NAME_LENGTH];
-
- // On marked entry
- if (mark_list.length > 1 && fileListFindEntry(&mark_list, file_entry->name)) {
- int end_slash = removeEndSlash(file_list.path);
-
- char *p = strrchr(file_list.path, '/');
- if (!p)
- p = strrchr(file_list.path, ':');
-
- if (strlen(p + 1) > 0) {
- strcpy(path, p + 1);
- } else {
- strncpy(path, file_list.path, p - file_list.path);
- path[p - file_list.path] = '\0';
- }
-
- if (end_slash)
- addEndSlash(file_list.path);
- } else {
- char *p = strrchr(file_entry->name, '.');
- if (!p)
- p = strrchr(file_entry->name, '/');
- if (!p)
- p = file_entry->name + strlen(file_entry->name);
-
- strncpy(path, file_entry->name, p-file_entry->name);
- path[p - file_entry->name] = '\0';
- }
-
- // Append .zip extension
- strcat(path, ".zip");
-
- initImeDialog(language_container[ARCHIVE_NAME], path, MAX_NAME_LENGTH, SCE_IME_TYPE_BASIC_LATIN, 0, 0);
- setDialogStep(DIALOG_STEP_COMPRESS_NAME);
- }
-
- break;
- }
-
- case MENU_MORE_ENTRY_INSTALL_ALL:
- {
- // Empty install list
- fileListEmpty(&install_list);
-
- FileListEntry *file_entry = file_list.head->next; // Ignore '..'
-
- int i;
- for (i = 0; i < file_list.length - 1; i++) {
- char path[MAX_PATH_LENGTH];
- snprintf(path, MAX_PATH_LENGTH - 1, "%s%s", file_list.path, file_entry->name);
-
- int type = getFileType(path);
- if (type == FILE_TYPE_VPK) {
- fileListAddEntry(&install_list, fileListCopyEntry(file_entry), SORT_NONE);
- }
-
- // Next
- file_entry = file_entry->next;
- }
-
- strcpy(install_list.path, file_list.path);
-
- initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_YESNO, language_container[INSTALL_ALL_QUESTION]);
- setDialogStep(DIALOG_STEP_INSTALL_QUESTION);
-
- break;
- }
-
- case MENU_MORE_ENTRY_INSTALL_FOLDER:
- {
- FileListEntry *file_entry = fileListGetNthEntry(&file_list, base_pos + rel_pos);
- if (file_entry) {
- snprintf(cur_file, MAX_PATH_LENGTH - 1, "%s%s", file_list.path, file_entry->name);
- initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_YESNO, language_container[INSTALL_FOLDER_QUESTION]);
- setDialogStep(DIALOG_STEP_INSTALL_QUESTION);
- }
-
- break;
- }
-
- case MENU_MORE_ENTRY_EXPORT_MEDIA:
- {
- FileListEntry *file_entry = fileListGetNthEntry(&file_list, base_pos + rel_pos);
- if (file_entry) {
- char *message;
-
- // On marked entry
- if (mark_list.length > 1 && fileListFindEntry(&mark_list, file_entry->name)) {
- message = language_container[EXPORT_FILES_FOLDERS_QUESTION];
- } else {
- message = language_container[file_entry->is_folder ? EXPORT_FOLDER_QUESTION : EXPORT_FILE_QUESTION];
- }
-
- initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_YESNO, message);
- setDialogStep(DIALOG_STEP_EXPORT_QUESTION);
- }
-
- break;
- }
-
- case MENU_MORE_ENTRY_CALCULATE_SHA1:
- {
- // Ensure user wants to actually take the hash
- initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_YESNO, language_container[HASH_FILE_QUESTION]);
- setDialogStep(DIALOG_STEP_HASH_QUESTION);
- break;
- }
- }
-
- return CONTEXT_MENU_CLOSING;
-}
-
-static int contextMenuNewEnterCallback(int sel, void *context) {
- switch (sel) {
- case MENU_NEW_FILE: {
- char path[MAX_PATH_LENGTH];
- int count = 1;
- while (1) {
- if (count == 1) {
- snprintf(path, MAX_PATH_LENGTH - 1, "%s%s", file_list.path,
- language_container[NEW_FILE]);
- } else {
- snprintf(path, MAX_PATH_LENGTH - 1, "%s%s (%d)", file_list.path,
- language_container[NEW_FILE], count);
- }
- if (!checkFileExist(path))
- break;
-
- count++;
- }
- initImeDialog(language_container[NEW_FILE], path + strlen(file_list.path),
- MAX_NAME_LENGTH, SCE_IME_TYPE_BASIC_LATIN, 0, 0);
- setDialogStep(DIALOG_STEP_NEW_FILE);
- break;
- };
- case MENU_NEW_FOLDER: {
- // Find a new folder name
- char path[MAX_PATH_LENGTH];
-
- int count = 1;
- while (1) {
- if (count == 1) {
- snprintf(path, MAX_PATH_LENGTH - 1, "%s%s", file_list.path,
- language_container[NEW_FOLDER]);
- } else {
- snprintf(path, MAX_PATH_LENGTH - 1, "%s%s (%d)", file_list.path,
- language_container[NEW_FOLDER], count);
- }
-
- if (!checkFolderExist(path))
- break;
-
- count++;
- }
-
- initImeDialog(language_container[NEW_FOLDER], path + strlen(file_list.path),
- MAX_NAME_LENGTH, SCE_IME_TYPE_BASIC_LATIN, 0, 0);
- setDialogStep(DIALOG_STEP_NEW_FOLDER);
- break;
- }
- }
- // Refresh list
- refreshFileList();
-
- return CONTEXT_MENU_CLOSING;
-}
-
+/*
+ VitaShell
+ Copyright (C) 2015-2018, TheFloW
+
+ 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, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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 for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+#include "main.h"
+#include "init.h"
+#include "io_process.h"
+#include "context_menu.h"
+#include "file.h"
+#include "language.h"
+#include "property_dialog.h"
+#include "message_dialog.h"
+#include "netcheck_dialog.h"
+#include "ime_dialog.h"
+#include "utils.h"
+#include "usb.h"
+
+char pfs_mounted_path[MAX_PATH_LENGTH];
+char pfs_mount_point[MAX_MOUNT_POINT_LENGTH];
+int read_only = 0;
+
+enum MenuHomeEntrys {
+ MENU_HOME_ENTRY_REFRESH_LIVEAREA,
+ MENU_HOME_ENTRY_REFRESH_LICENSE_DB,
+ MENU_HOME_ENTRY_MOUNT_UMA0,
+ MENU_HOME_ENTRY_MOUNT_IMC0,
+ MENU_HOME_ENTRY_MOUNT_XMC0,
+ MENU_HOME_ENTRY_UMOUNT_UMA0,
+ MENU_HOME_ENTRY_UMOUNT_IMC0,
+ MENU_HOME_ENTRY_UMOUNT_XMC0,
+ MENU_HOME_ENTRY_MOUNT_USB_UX0,
+ MENU_HOME_ENTRY_UMOUNT_USB_UX0,
+ MENU_HOME_ENTRY_MOUNT_GAMECARD_UX0,
+ MENU_HOME_ENTRY_UMOUNT_GAMECARD_UX0,
+};
+
+MenuEntry menu_home_entries[] = {
+ { REFRESH_LIVEAREA, 0, 0, CTX_INVISIBLE },
+ { REFRESH_LICENSE_DB, 1, 0, CTX_INVISIBLE },
+ { MOUNT_UMA0, 3, 0, CTX_INVISIBLE },
+ { MOUNT_IMC0, 4, 0, CTX_INVISIBLE },
+ { MOUNT_XMC0, 5, 0, CTX_INVISIBLE },
+ { UMOUNT_UMA0, 7, 0, CTX_INVISIBLE },
+ { UMOUNT_IMC0, 8, 0, CTX_INVISIBLE },
+ { UMOUNT_XMC0, 9, 0, CTX_INVISIBLE },
+ { MOUNT_USB_UX0, 11, 0, CTX_INVISIBLE },
+ { UMOUNT_USB_UX0, 12, 0, CTX_INVISIBLE },
+ { MOUNT_GAMECARD_UX0, 14, 0, CTX_INVISIBLE },
+ { UMOUNT_GAMECARD_UX0, 15, 0, CTX_INVISIBLE },
+};
+
+#define N_MENU_HOME_ENTRIES (sizeof(menu_home_entries) / sizeof(MenuEntry))
+
+enum MenuMainEntrys {
+ MENU_MAIN_ENTRY_OPEN_DECRYPTED,
+ MENU_MAIN_ENTRY_MARK_UNMARK_ALL,
+ MENU_MAIN_ENTRY_MOVE,
+ MENU_MAIN_ENTRY_COPY,
+ MENU_MAIN_ENTRY_PASTE,
+ MENU_MAIN_ENTRY_DELETE,
+ MENU_MAIN_ENTRY_RENAME,
+ MENU_MAIN_ENTRY_NEW,
+ MENU_MAIN_ENTRY_PROPERTIES,
+ MENU_MAIN_ENTRY_SORT_BY,
+ MENU_MAIN_ENTRY_MORE,
+ MENU_MAIN_ENTRY_SEND,
+ MENU_MAIN_ENTRY_RECEIVE,
+};
+
+MenuEntry menu_main_entries[] = {
+ { OPEN_DECRYPTED, 0, 0, CTX_INVISIBLE },
+ { MARK_ALL, 1, 0, CTX_INVISIBLE },
+ { MOVE, 3, 0, CTX_INVISIBLE },
+ { COPY, 4, 0, CTX_INVISIBLE },
+ { PASTE, 5, 0, CTX_INVISIBLE },
+ { DELETE, 7, 0, CTX_INVISIBLE },
+ { RENAME, 8, 0, CTX_INVISIBLE },
+ { NEW, 10, CTX_FLAG_MORE, CTX_VISIBLE },
+ { PROPERTIES, 11, 0, CTX_INVISIBLE },
+ { SORT_BY, 13, CTX_FLAG_MORE, CTX_VISIBLE },
+ { MORE, 14, CTX_FLAG_MORE, CTX_INVISIBLE },
+ { SEND, 17, 0, CTX_INVISIBLE }, // CTX_FLAG_BARRIER
+ { RECEIVE, 18, 0, CTX_INVISIBLE },
+};
+
+#define N_MENU_MAIN_ENTRIES (sizeof(menu_main_entries) / sizeof(MenuEntry))
+
+enum MenuSortEntrys {
+ MENU_SORT_ENTRY_BY_NAME,
+ MENU_SORT_ENTRY_BY_SIZE,
+ MENU_SORT_ENTRY_BY_DATE,
+};
+
+MenuEntry menu_sort_entries[] = {
+ { BY_NAME, 12, 0, CTX_INVISIBLE },
+ { BY_SIZE, 13, 0, CTX_INVISIBLE },
+ { BY_DATE, 14, 0, CTX_INVISIBLE },
+};
+
+#define N_MENU_SORT_ENTRIES (sizeof(menu_sort_entries) / sizeof(MenuEntry))
+
+enum MenuMoreEntrys {
+ MENU_MORE_ENTRY_COMPRESS,
+ MENU_MORE_ENTRY_INSTALL_ALL,
+ MENU_MORE_ENTRY_INSTALL_FOLDER,
+ MENU_MORE_ENTRY_EXPORT_MEDIA,
+ MENU_MORE_ENTRY_CALCULATE_SHA1,
+};
+
+MenuEntry menu_more_entries[] = {
+ { COMPRESS, 12, 0, CTX_INVISIBLE },
+ { INSTALL_ALL, 13, 0, CTX_INVISIBLE },
+ { INSTALL_FOLDER, 14, 0, CTX_INVISIBLE },
+ { EXPORT_MEDIA, 15, 0, CTX_INVISIBLE },
+ { CALCULATE_SHA1, 16, 0, CTX_INVISIBLE },
+};
+
+#define N_MENU_MORE_ENTRIES (sizeof(menu_more_entries) / sizeof(MenuEntry))
+
+enum MenuNewEntrys {
+ MENU_NEW_FILE,
+ MENU_NEW_FOLDER
+};
+
+MenuEntry menu_new_entries[] = {
+ {NEW_FILE, 10, 0, CTX_INVISIBLE},
+ {NEW_FOLDER, 11, 0, CTX_INVISIBLE}
+
+};
+
+#define N_MENU_NEW_ENTRIES (sizeof(menu_new_entries) / sizeof(MenuEntry))
+
+static int contextMenuHomeEnterCallback(int sel, void *context);
+static int contextMenuMainEnterCallback(int sel, void *context);
+static int contextMenuSortEnterCallback(int sel, void *context);
+static int contextMenuMoreEnterCallback(int sel, void *context);
+static int contextMenuNewEnterCallback(int sel, void *context);
+
+ContextMenu context_menu_home = {
+ .parent = NULL,
+ .entries = menu_home_entries,
+ .n_entries = N_MENU_HOME_ENTRIES,
+ .max_width = 0.0f,
+ .callback = contextMenuHomeEnterCallback,
+ .sel = -1,
+};
+
+ContextMenu context_menu_main = {
+ .parent = NULL,
+ .entries = menu_main_entries,
+ .n_entries = N_MENU_MAIN_ENTRIES,
+ .max_width = 0.0f,
+ .callback = contextMenuMainEnterCallback,
+ .sel = -1,
+};
+
+ContextMenu context_menu_sort = {
+ .parent = &context_menu_main,
+ .entries = menu_sort_entries,
+ .n_entries = N_MENU_SORT_ENTRIES,
+ .max_width = 0.0f,
+ .callback = contextMenuSortEnterCallback,
+ .sel = -1,
+};
+
+ContextMenu context_menu_more = {
+ .parent = &context_menu_main,
+ .entries = menu_more_entries,
+ .n_entries = N_MENU_MORE_ENTRIES,
+ .max_width = 0.0f,
+ .callback = contextMenuMoreEnterCallback,
+ .sel = -1,
+};
+
+ContextMenu context_menu_new = {
+ .parent = &context_menu_main,
+ .entries = menu_new_entries,
+ .n_entries = N_MENU_NEW_ENTRIES,
+ .max_width = 0.0f,
+ .callback = contextMenuNewEnterCallback,
+ .sel = -1,
+};
+
+/*
+ SceAppMgr mount IDs:
+ 0x64: ux0:picture
+ 0x65: ur0:user/00/psnfriend
+ 0x66: ur0:user/00/psnmsg
+ 0x69: ux0:music
+ 0x6E: ux0:appmeta
+ 0xC8: ur0:temp/sqlite
+ 0xCD: ux0:cache
+ 0x12E: ur0:user/00/trophy/data/sce_trop
+ 0x12F: ur0:user/00/trophy/data
+ 0x3E8: ux0:app, vs0:app, gro0:app
+ 0x3E9: ux0:patch
+ 0x3EB: ?
+ 0x3EA: ux0:addcont
+ 0x3EC: ux0:theme
+ 0x3ED: ux0:user/00/savedata
+ 0x3EE: ur0:user/00/savedata
+ 0x3EF: vs0:sys/external
+ 0x3F0: vs0:data/external
+*/
+
+int known_pfs_ids[] = {
+ 0x6E,
+ 0x12E,
+ 0x12F,
+ 0x3ED,
+};
+
+int pfsMount(const char *path) {
+ int res;
+ char work_path[MAX_PATH_LENGTH];
+ char klicensee[0x10];
+ char license_buf[0x200];
+ ShellMountIdArgs args;
+
+ memset(klicensee, 0, sizeof(klicensee));
+
+/*
+ snprintf(work_path, MAX_PATH_LENGTH - 1, "%ssce_sys/package/work.bin", path);
+ if (ReadFile(work_path, license_buf, sizeof(license_buf)) == sizeof(license_buf)) {
+ int res = shellUserGetRifVitaKey(license_buf, klicensee);
+ debugPrintf("read license: 0x%08X\n", res);
+ }
+*/
+ args.process_titleid = VITASHELL_TITLEID;
+ args.path = path;
+ args.desired_mount_point = NULL;
+ args.klicensee = klicensee;
+ args.mount_point = pfs_mount_point;
+
+ read_only = 0;
+
+ int i;
+ for (i = 0; i < sizeof(known_pfs_ids) / sizeof(int); i++) {
+ args.id = known_pfs_ids[i];
+
+ res = shellUserMountById(&args);
+ if (res >= 0)
+ return res;
+ }
+
+ read_only = 1;
+ return sceAppMgrGameDataMount(path, 0, 0, pfs_mount_point);
+}
+
+int pfsUmount() {
+ if (pfs_mount_point[0] == 0)
+ return -1;
+
+ int res = sceAppMgrUmount(pfs_mount_point);
+ if (res >= 0) {
+ memset(pfs_mount_point, 0, sizeof(pfs_mount_point));
+ memset(pfs_mounted_path, 0, sizeof(pfs_mounted_path));
+ }
+
+ return res;
+}
+
+void initContextMenuWidth() {
+ int i;
+
+ // Home
+ for (i = 0; i < N_MENU_HOME_ENTRIES; i++) {
+ context_menu_home.max_width = MAX(context_menu_home.max_width, pgf_text_width(language_container[menu_home_entries[i].name]));
+ }
+
+ context_menu_home.max_width += 2.0f * CONTEXT_MENU_MARGIN;
+ context_menu_home.max_width = MAX(context_menu_home.max_width, CONTEXT_MENU_MIN_WIDTH);
+
+ // Main
+ for (i = 0; i < N_MENU_MAIN_ENTRIES; i++) {
+ context_menu_main.max_width = MAX(context_menu_main.max_width, pgf_text_width(language_container[menu_main_entries[i].name]));
+
+ if (menu_main_entries[i].name == MARK_ALL) {
+ menu_main_entries[i].name = UNMARK_ALL;
+ i--;
+ }
+ }
+
+ context_menu_main.max_width += 2.0f * CONTEXT_MENU_MARGIN;
+ context_menu_main.max_width = MAX(context_menu_main.max_width, CONTEXT_MENU_MIN_WIDTH);
+
+ // Sort
+ for (i = 0; i < N_MENU_SORT_ENTRIES; i++) {
+ context_menu_sort.max_width = MAX(context_menu_sort.max_width, pgf_text_width(language_container[menu_sort_entries[i].name]));
+ }
+
+ context_menu_sort.max_width += 2.0f * CONTEXT_MENU_MARGIN;
+ context_menu_sort.max_width = MAX(context_menu_sort.max_width, CONTEXT_MENU_MIN_WIDTH);
+
+ // More
+ for (i = 0; i < N_MENU_MORE_ENTRIES; i++) {
+ context_menu_more.max_width = MAX(context_menu_more.max_width, pgf_text_width(language_container[menu_more_entries[i].name]));
+ }
+
+ context_menu_more.max_width += 2.0f * CONTEXT_MENU_MARGIN;
+ context_menu_more.max_width = MAX(context_menu_more.max_width, CONTEXT_MENU_MIN_WIDTH);
+
+ // New
+ for (i = 0; i < N_MENU_NEW_ENTRIES; i++) {
+ context_menu_new.max_width = MAX(context_menu_new.max_width,
+ pgf_text_width(language_container[menu_new_entries[i].name]));
+ }
+ context_menu_new.max_width += 2.0f * CONTEXT_MENU_MARGIN;
+ context_menu_new.max_width = MAX(context_menu_new.max_width, CONTEXT_MENU_MIN_WIDTH);
+}
+
+void setContextMenuHomeVisibilities() {
+ int i;
+
+ // All visible
+ for (i = 0; i < N_MENU_HOME_ENTRIES; i++) {
+ if (menu_home_entries[i].visibility == CTX_INVISIBLE)
+ menu_home_entries[i].visibility = CTX_VISIBLE;
+ }
+
+ if (checkFolderExist("uma0:")) {
+ menu_home_entries[MENU_HOME_ENTRY_MOUNT_UMA0].visibility = CTX_INVISIBLE;
+ } else {
+ menu_home_entries[MENU_HOME_ENTRY_MOUNT_USB_UX0].visibility = CTX_INVISIBLE;
+ }
+
+ if ((kernel_modid >= 0 || kernel_modid == 0x8002D013) && user_modid >= 0 &&
+ shellUserIsUx0Redirected("sdstor0:uma-pp-act-a", "sdstor0:uma-lp-act-entire") == 1) {
+ menu_home_entries[MENU_HOME_ENTRY_MOUNT_UMA0].visibility = CTX_INVISIBLE;
+ menu_home_entries[MENU_HOME_ENTRY_MOUNT_USB_UX0].visibility = CTX_INVISIBLE;
+ } else {
+ menu_home_entries[MENU_HOME_ENTRY_UMOUNT_USB_UX0].visibility = CTX_INVISIBLE;
+ }
+
+ if (!checkFileExist("sdstor0:gcd-lp-ign-entire")) {
+ menu_home_entries[MENU_HOME_ENTRY_MOUNT_GAMECARD_UX0].visibility = CTX_INVISIBLE;
+ menu_home_entries[MENU_HOME_ENTRY_UMOUNT_GAMECARD_UX0].visibility = CTX_INVISIBLE;
+ } else {
+ if ((kernel_modid >= 0 || kernel_modid == 0x8002D013) && user_modid >= 0 &&
+ shellUserIsUx0Redirected("sdstor0:gcd-lp-ign-entire", "sdstor0:gcd-lp-ign-entire") == 1) {
+ menu_home_entries[MENU_HOME_ENTRY_MOUNT_GAMECARD_UX0].visibility = CTX_INVISIBLE;
+ } else {
+ menu_home_entries[MENU_HOME_ENTRY_UMOUNT_GAMECARD_UX0].visibility = CTX_INVISIBLE;
+ }
+ }
+
+ // Invisible if already mounted or there is no internal storage
+ if (!checkFileExist("sdstor0:int-lp-ign-userext") || checkFolderExist("imc0:"))
+ menu_home_entries[MENU_HOME_ENTRY_MOUNT_IMC0].visibility = CTX_INVISIBLE;
+
+ // Invisible if already mounted or there is no Memory Card
+ if (!checkFileExist("sdstor0:xmc-lp-ign-userext") || checkFolderExist("xmc0:"))
+ menu_home_entries[MENU_HOME_ENTRY_MOUNT_XMC0].visibility = CTX_INVISIBLE;
+
+ // Invisible if not mounted
+ if (!checkFolderExist("uma0:"))
+ menu_home_entries[MENU_HOME_ENTRY_UMOUNT_UMA0].visibility = CTX_INVISIBLE;
+
+ // Invisible if not mounted
+ if (!checkFolderExist("imc0:"))
+ menu_home_entries[MENU_HOME_ENTRY_UMOUNT_IMC0].visibility = CTX_INVISIBLE;
+
+ // Invisible if not mounted
+ if (!checkFolderExist("xmc0:"))
+ menu_home_entries[MENU_HOME_ENTRY_UMOUNT_XMC0].visibility = CTX_INVISIBLE;
+
+ // Go to first entry
+ for (i = 0; i < N_MENU_HOME_ENTRIES; i++) {
+ if (menu_home_entries[i].visibility == CTX_VISIBLE) {
+ context_menu_home.sel = i;
+ break;
+ }
+ }
+
+ if (i == N_MENU_HOME_ENTRIES)
+ context_menu_home.sel = -1;
+}
+
+void setContextMenuMainVisibilities() {
+ int i;
+
+ // All visible
+ for (i = 0; i < N_MENU_MAIN_ENTRIES; i++) {
+ if (menu_main_entries[i].visibility == CTX_INVISIBLE)
+ menu_main_entries[i].visibility = CTX_VISIBLE;
+ }
+
+ FileListEntry *file_entry = fileListGetNthEntry(&file_list, base_pos + rel_pos);
+ if (!file_entry)
+ return;
+
+ // menu_main_entries[MENU_MAIN_ENTRY_SEND].flags = CTX_FLAG_BARRIER;
+ // menu_main_entries[MENU_MAIN_ENTRY_RECEIVE].flags = 0;
+
+ // Invisble entries when on '..'
+ if (strcmp(file_entry->name, DIR_UP) == 0) {
+ menu_main_entries[MENU_MAIN_ENTRY_OPEN_DECRYPTED].visibility = CTX_INVISIBLE;
+ menu_main_entries[MENU_MAIN_ENTRY_MARK_UNMARK_ALL].visibility = CTX_INVISIBLE;
+ menu_main_entries[MENU_MAIN_ENTRY_MOVE].visibility = CTX_INVISIBLE;
+ menu_main_entries[MENU_MAIN_ENTRY_COPY].visibility = CTX_INVISIBLE;
+ menu_main_entries[MENU_MAIN_ENTRY_DELETE].visibility = CTX_INVISIBLE;
+ menu_main_entries[MENU_MAIN_ENTRY_RENAME].visibility = CTX_INVISIBLE;
+ menu_main_entries[MENU_MAIN_ENTRY_PROPERTIES].visibility = CTX_INVISIBLE;
+ menu_main_entries[MENU_MAIN_ENTRY_SEND].visibility = CTX_INVISIBLE;
+ // menu_main_entries[MENU_MAIN_ENTRY_RECEIVE].flags = CTX_FLAG_BARRIER;
+ }
+
+ // Invisible 'Paste' if nothing is copied yet
+ if (copy_list.length == 0) {
+ menu_main_entries[MENU_MAIN_ENTRY_PASTE].visibility = CTX_INVISIBLE;
+ }
+
+ // Invisible 'Paste' if the files to move are not from the same partition
+ if (copy_mode == COPY_MODE_MOVE) {
+ char *p = strchr(file_list.path, ':');
+ char *q = strchr(copy_list.path, ':');
+ if (p && q) {
+ *p = '\0';
+ *q = '\0';
+
+ if (strcasecmp(file_list.path, copy_list.path) != 0) {
+ menu_main_entries[MENU_MAIN_ENTRY_PASTE].visibility = CTX_INVISIBLE;
+ }
+
+ *q = ':';
+ *p = ':';
+ } else {
+ menu_main_entries[MENU_MAIN_ENTRY_PASTE].visibility = CTX_INVISIBLE;
+ }
+ }
+
+ // Invisible write operations in archives
+ // TODO: read-only mount points
+ if (isInArchive() || (pfs_mounted_path[0] && strstr(file_list.path, pfs_mounted_path) && read_only)) {
+ menu_main_entries[MENU_MAIN_ENTRY_OPEN_DECRYPTED].visibility = CTX_INVISIBLE;
+ menu_main_entries[MENU_MAIN_ENTRY_MOVE].visibility = CTX_INVISIBLE;
+ menu_main_entries[MENU_MAIN_ENTRY_PASTE].visibility = CTX_INVISIBLE;
+ menu_main_entries[MENU_MAIN_ENTRY_DELETE].visibility = CTX_INVISIBLE;
+ menu_main_entries[MENU_MAIN_ENTRY_RENAME].visibility = CTX_INVISIBLE;
+ menu_main_entries[MENU_MAIN_ENTRY_NEW].visibility = CTX_INVISIBLE;
+ menu_main_entries[MENU_MAIN_ENTRY_SEND].visibility = CTX_INVISIBLE;
+ menu_main_entries[MENU_MAIN_ENTRY_RECEIVE].visibility = CTX_INVISIBLE;
+ }
+
+ // Mark/Unmark all text
+ if (mark_list.length == (file_list.length - 1)) { // All marked
+ menu_main_entries[MENU_MAIN_ENTRY_MARK_UNMARK_ALL].name = UNMARK_ALL;
+ } else { // Not all marked yet
+ // On marked entry
+ if (fileListFindEntry(&mark_list, file_entry->name)) {
+ menu_main_entries[MENU_MAIN_ENTRY_MARK_UNMARK_ALL].name = UNMARK_ALL;
+ } else {
+ menu_main_entries[MENU_MAIN_ENTRY_MARK_UNMARK_ALL].name = MARK_ALL;
+ }
+ }
+
+ // Invisible if it's not folder or sce_pfs does not exist
+ if (!file_entry->is_folder) {
+ menu_main_entries[MENU_MAIN_ENTRY_OPEN_DECRYPTED].visibility = CTX_INVISIBLE;
+ } else {
+ char path[MAX_PATH_LENGTH];
+ snprintf(path, MAX_PATH_LENGTH - 1, "%s%ssce_pfs", file_list.path, file_entry->name);
+
+ if (!checkFolderExist(path))
+ menu_main_entries[MENU_MAIN_ENTRY_OPEN_DECRYPTED].visibility = CTX_INVISIBLE;
+ }
+
+ // Go to first entry
+ for (i = 0; i < N_MENU_MAIN_ENTRIES; i++) {
+ if (menu_main_entries[i].visibility == CTX_VISIBLE) {
+ context_menu_main.sel = i;
+ break;
+ }
+ }
+
+ if (i == N_MENU_MAIN_ENTRIES)
+ context_menu_main.sel = -1;
+}
+
+void setContextMenuSortVisibilities() {
+ int i;
+
+ // All visible
+ for (i = 0; i < N_MENU_SORT_ENTRIES; i++) {
+ if (menu_sort_entries[i].visibility == CTX_INVISIBLE)
+ menu_sort_entries[i].visibility = CTX_VISIBLE;
+ }
+
+ // Invisible when it's the current mode
+ if (sort_mode == SORT_BY_NAME)
+ menu_sort_entries[MENU_SORT_ENTRY_BY_NAME].visibility = CTX_INVISIBLE;
+ else if (sort_mode == SORT_BY_SIZE)
+ menu_sort_entries[MENU_SORT_ENTRY_BY_SIZE].visibility = CTX_INVISIBLE;
+ else if (sort_mode == SORT_BY_DATE)
+ menu_sort_entries[MENU_SORT_ENTRY_BY_DATE].visibility = CTX_INVISIBLE;
+
+ // Go to first entry
+ for (i = 0; i < N_MENU_SORT_ENTRIES; i++) {
+ if (menu_sort_entries[i].visibility == CTX_VISIBLE) {
+ context_menu_sort.sel = i;
+ break;
+ }
+ }
+
+ if (i == N_MENU_SORT_ENTRIES)
+ context_menu_sort.sel = -1;
+}
+
+void setContextMenuMoreVisibilities() {
+ int i;
+
+ // All visible
+ for (i = 0; i < N_MENU_MORE_ENTRIES; i++) {
+ if (menu_more_entries[i].visibility == CTX_INVISIBLE)
+ menu_more_entries[i].visibility = CTX_VISIBLE;
+ }
+
+ FileListEntry *file_entry = fileListGetNthEntry(&file_list, base_pos + rel_pos);
+ if (!file_entry)
+ return;
+
+ // Invisble entries when on '..'
+ if (strcmp(file_entry->name, DIR_UP) == 0) {
+ menu_more_entries[MENU_MORE_ENTRY_COMPRESS].visibility = CTX_INVISIBLE;
+ menu_more_entries[MENU_MORE_ENTRY_INSTALL_ALL].visibility = CTX_INVISIBLE;
+ menu_more_entries[MENU_MORE_ENTRY_INSTALL_FOLDER].visibility = CTX_INVISIBLE;
+ menu_more_entries[MENU_MORE_ENTRY_EXPORT_MEDIA].visibility = CTX_INVISIBLE;
+ menu_more_entries[MENU_MORE_ENTRY_CALCULATE_SHA1].visibility = CTX_INVISIBLE;
+ }
+
+ // Invisble operations in archives
+ if (isInArchive() || (pfs_mounted_path[0] && strstr(file_list.path, pfs_mounted_path) && read_only)) {
+ menu_more_entries[MENU_MORE_ENTRY_COMPRESS].visibility = CTX_INVISIBLE;
+ menu_more_entries[MENU_MORE_ENTRY_INSTALL_ALL].visibility = CTX_INVISIBLE;
+ menu_more_entries[MENU_MORE_ENTRY_INSTALL_FOLDER].visibility = CTX_INVISIBLE;
+ menu_more_entries[MENU_MORE_ENTRY_EXPORT_MEDIA].visibility = CTX_INVISIBLE;
+ menu_more_entries[MENU_MORE_ENTRY_CALCULATE_SHA1].visibility = CTX_INVISIBLE;
+ }
+
+ if (file_entry->is_folder) {
+ menu_more_entries[MENU_MORE_ENTRY_CALCULATE_SHA1].visibility = CTX_INVISIBLE;
+
+ char check_path[MAX_PATH_LENGTH];
+
+ do {
+ if (strcasecmp(file_list.path, "ux0:app/") == 0 ||
+ strcasecmp(file_list.path, "ux0:patch/") == 0) {
+ menu_more_entries[MENU_MORE_ENTRY_INSTALL_FOLDER].visibility = CTX_INVISIBLE;
+ break;
+ }
+
+ snprintf(check_path, MAX_PATH_LENGTH - 1, "%s%s/eboot.bin", file_list.path, file_entry->name);
+ if (!checkFileExist(check_path)) {
+ menu_more_entries[MENU_MORE_ENTRY_INSTALL_FOLDER].visibility = CTX_INVISIBLE;
+ break;
+ }
+
+ snprintf(check_path, MAX_PATH_LENGTH - 1, "%s%s/sce_sys/param.sfo", file_list.path, file_entry->name);
+ if (!checkFileExist(check_path)) {
+ menu_more_entries[MENU_MORE_ENTRY_INSTALL_FOLDER].visibility = CTX_INVISIBLE;
+ break;
+ }
+ } while (0);
+ } else {
+ menu_more_entries[MENU_MORE_ENTRY_INSTALL_FOLDER].visibility = CTX_INVISIBLE;
+ }
+
+ if(file_entry->type != FILE_TYPE_VPK) {
+ menu_more_entries[MENU_MORE_ENTRY_INSTALL_ALL].visibility = CTX_INVISIBLE;
+ }
+
+ // Invisible export for non-media files
+ if (!file_entry->is_folder &&
+ file_entry->type != FILE_TYPE_BMP && file_entry->type != FILE_TYPE_JPEG &&
+ file_entry->type != FILE_TYPE_PNG && file_entry->type != FILE_TYPE_MP3 &&
+ file_entry->type != FILE_TYPE_MP4) {
+ menu_more_entries[MENU_MORE_ENTRY_EXPORT_MEDIA].visibility = CTX_INVISIBLE;
+ }
+
+ // Go to first entry
+ for (i = 0; i < N_MENU_MORE_ENTRIES; i++) {
+ if (menu_more_entries[i].visibility == CTX_VISIBLE) {
+ context_menu_more.sel = i;
+ break;
+ }
+ }
+
+ if (i == N_MENU_MORE_ENTRIES)
+ context_menu_more.sel = -1;
+}
+
+void setContextMenuNewVisibilities() {
+ int i;
+
+ // All visible
+ for (i = 0; i < N_MENU_NEW_ENTRIES; i++) {
+ if (menu_new_entries[i].visibility == CTX_INVISIBLE)
+ menu_new_entries[i].visibility = CTX_VISIBLE;
+ }
+
+ // Go to first entry
+ for (i = 0; i < N_MENU_NEW_ENTRIES; i++) {
+ if (menu_new_entries[i].visibility == CTX_VISIBLE) {
+ context_menu_new.sel = i;
+ break;
+ }
+ }
+
+ if (i == N_MENU_NEW_ENTRIES)
+ context_menu_new.sel = -1;
+}
+
+static int contextMenuHomeEnterCallback(int sel, void *context) {
+ switch (sel) {
+ case MENU_HOME_ENTRY_REFRESH_LIVEAREA:
+ {
+ if (is_safe_mode) {
+ infoDialog(language_container[EXTENDED_PERMISSIONS_REQUIRED]);
+ } else {
+ initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_YESNO, language_container[REFRESH_LIVEAREA_QUESTION]);
+ setDialogStep(DIALOG_STEP_REFRESH_LIVEAREA_QUESTION);
+ }
+
+ break;
+ }
+
+ case MENU_HOME_ENTRY_REFRESH_LICENSE_DB:
+ {
+ if (is_safe_mode) {
+ infoDialog(language_container[EXTENDED_PERMISSIONS_REQUIRED]);
+ } else {
+ initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_YESNO, language_container[REFRESH_LICENSE_DB_QUESTION]);
+ setDialogStep(DIALOG_STEP_REFRESH_LICENSE_DB_QUESTION);
+ }
+
+ break;
+ }
+
+ case MENU_HOME_ENTRY_MOUNT_UMA0:
+ {
+ if (is_safe_mode) {
+ infoDialog(language_container[EXTENDED_PERMISSIONS_REQUIRED]);
+ } else {
+ if (checkFileExist("sdstor0:uma-lp-act-entire")) {
+ int res = vshIoMount(0xF00, NULL, 0, 0, 0, 0);
+ if (res < 0)
+ errorDialog(res);
+ else
+ infoDialog(language_container[UMA0_MOUNTED]);
+ refreshFileList();
+ } else {
+ initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_CANCEL, language_container[USB_WAIT_ATTACH]);
+ setDialogStep(DIALOG_STEP_USB_ATTACH_WAIT);
+ }
+ }
+
+ break;
+ }
+
+ case MENU_HOME_ENTRY_MOUNT_IMC0:
+ {
+ if (is_safe_mode) {
+ infoDialog(language_container[EXTENDED_PERMISSIONS_REQUIRED]);
+ } else {
+ int res = vshIoMount(0xD00, NULL, 2, 0, 0, 0);
+ if (res < 0)
+ errorDialog(res);
+ else
+ infoDialog(language_container[IMC0_MOUNTED]);
+ refreshFileList();
+ }
+
+ break;
+ }
+
+ case MENU_HOME_ENTRY_MOUNT_XMC0:
+ {
+ if (is_safe_mode) {
+ infoDialog(language_container[EXTENDED_PERMISSIONS_REQUIRED]);
+ } else {
+ int res = vshIoMount(0xE00, NULL, 2, 0, 0, 0);
+ if (res < 0)
+ errorDialog(res);
+ else
+ infoDialog(language_container[XMC0_MOUNTED]);
+ refreshFileList();
+ }
+
+ break;
+ }
+
+ case MENU_HOME_ENTRY_UMOUNT_UMA0:
+ {
+ if (is_safe_mode) {
+ infoDialog(language_container[EXTENDED_PERMISSIONS_REQUIRED]);
+ } else {
+ vshIoUmount(0xF00, 0, 0, 0);
+ vshIoUmount(0xF00, 1, 0, 0);
+ infoDialog(language_container[UMA0_UMOUNTED]);
+ refreshFileList();
+ }
+
+ break;
+ }
+
+ case MENU_HOME_ENTRY_UMOUNT_IMC0:
+ {
+ if (is_safe_mode) {
+ infoDialog(language_container[EXTENDED_PERMISSIONS_REQUIRED]);
+ } else {
+ vshIoUmount(0xD00, 0, 0, 0);
+ vshIoUmount(0xD00, 1, 0, 0);
+ infoDialog(language_container[IMC0_UMOUNTED]);
+ refreshFileList();
+ }
+
+ break;
+ }
+
+ case MENU_HOME_ENTRY_UMOUNT_XMC0:
+ {
+ if (is_safe_mode) {
+ infoDialog(language_container[EXTENDED_PERMISSIONS_REQUIRED]);
+ } else {
+ vshIoUmount(0xE00, 0, 0, 0);
+ vshIoUmount(0xE00, 1, 0, 0);
+ infoDialog(language_container[XMC0_UMOUNTED]);
+ refreshFileList();
+ }
+
+ break;
+ }
+
+ case MENU_HOME_ENTRY_MOUNT_USB_UX0:
+ {
+ if (mountUsbUx0() >= 0) {
+ infoDialog(language_container[USB_UX0_MOUNTED]);
+ refreshFileList();
+ }
+ break;
+ }
+
+ case MENU_HOME_ENTRY_UMOUNT_USB_UX0:
+ {
+ if (umountUsbUx0() >= 0) {
+ infoDialog(language_container[USB_UX0_UMOUNTED]);
+ refreshFileList();
+ }
+ break;
+ }
+
+ case MENU_HOME_ENTRY_MOUNT_GAMECARD_UX0:
+ {
+ if (mountGamecardUx0() >= 0) {
+ infoDialog(language_container[GAMECARD_UX0_MOUNTED]);
+ refreshFileList();
+ }
+ break;
+ }
+
+ case MENU_HOME_ENTRY_UMOUNT_GAMECARD_UX0:
+ {
+ if (umountGamecardUx0() >= 0) {
+ infoDialog(language_container[GAMECARD_UX0_UMOUNTED]);
+ refreshFileList();
+ }
+ break;
+ }
+ }
+
+ return CONTEXT_MENU_CLOSING;
+}
+
+static int contextMenuMainEnterCallback(int sel, void *context) {
+ switch (sel) {
+
+ case MENU_MAIN_ENTRY_OPEN_DECRYPTED:
+ {
+ FileListEntry *file_entry = fileListGetNthEntry(&file_list, base_pos + rel_pos);
+ if (file_entry) {
+ char path[MAX_PATH_LENGTH];
+ int res;
+
+ pfsUmount();
+
+ snprintf(path, MAX_PATH_LENGTH - 1, "%s%s", file_list.path, file_entry->name);
+ res = pfsMount(path);
+
+ // In case we're at ux0:patch or grw0:patch we need to apply the mounting at ux0:app or gro0:app
+ if (res < 0) {
+ if (strncasecmp(file_list.path, "ux0:patch", 9) == 0 ||
+ strncasecmp(file_list.path, "grw0:patch", 10) == 0) {
+ snprintf(path, MAX_PATH_LENGTH - 1, "ux0:app/%s", file_entry->name);
+ res = pfsMount(path);
+
+ if (res < 0) {
+ snprintf(path, MAX_PATH_LENGTH - 1, "gro0:app/%s", file_entry->name);
+ res = pfsMount(path);
+ }
+ }
+ }
+
+ if (res < 0)
+ errorDialog(res);
+
+ if (res >= 0) {
+ addEndSlash(file_list.path);
+ strcat(file_list.path, file_entry->name);
+ strcpy(pfs_mounted_path, file_list.path);
+ dirLevelUp();
+
+ // Save last dir
+ WriteFile(VITASHELL_LASTDIR, file_list.path, strlen(file_list.path) + 1);
+
+ // Open folder
+ int res = refreshFileList();
+ if (res < 0)
+ errorDialog(res);
+ } else {
+ errorDialog(res);
+ }
+ }
+
+ break;
+ }
+
+ case MENU_MAIN_ENTRY_MARK_UNMARK_ALL:
+ {
+ FileListEntry *file_entry = fileListGetNthEntry(&file_list, base_pos + rel_pos);
+ if (file_entry) {
+ int on_marked_entry = 0;
+ int length = mark_list.length;
+
+ if (fileListFindEntry(&mark_list, file_entry->name))
+ on_marked_entry = 1;
+
+ // Empty mark list
+ fileListEmpty(&mark_list);
+
+ // Mark all if not all entries are marked yet and we are not focusing on a marked entry
+ if (length != (file_list.length - 1) && !on_marked_entry) {
+ FileListEntry *file_entry = file_list.head->next; // Ignore '..'
+
+ int i;
+ for (i = 0; i < file_list.length - 1; i++) {
+ fileListAddEntry(&mark_list, fileListCopyEntry(file_entry), SORT_NONE);
+
+ // Next
+ file_entry = file_entry->next;
+ }
+ }
+ }
+
+ break;
+ }
+
+ case MENU_MAIN_ENTRY_MOVE:
+ case MENU_MAIN_ENTRY_COPY:
+ {
+ FileListEntry *file_entry = fileListGetNthEntry(&file_list, base_pos + rel_pos);
+ if (file_entry) {
+ // Umount if last path copied from is the pfs mounted path
+ if (pfs_mounted_path[0] &&
+ !strstr(file_list.path, pfs_mounted_path) &&
+ strstr(copy_list.path, pfs_mounted_path)) {
+ pfsUmount();
+ }
+
+ // Mode
+ if (sel == MENU_MAIN_ENTRY_MOVE) {
+ copy_mode = COPY_MODE_MOVE;
+ } else {
+ copy_mode = isInArchive() ? COPY_MODE_EXTRACT : COPY_MODE_NORMAL;
+ }
+
+ strcpy(archive_copy_path, archive_path);
+
+ // Empty copy list at first
+ fileListEmpty(©_list);
+
+ // Paths
+ if (fileListFindEntry(&mark_list, file_entry->name)) { // On marked entry
+ // Copy mark list to copy list
+ FileListEntry *mark_entry = mark_list.head;
+
+ int i;
+ for (i = 0; i < mark_list.length; i++) {
+ fileListAddEntry(©_list, fileListCopyEntry(mark_entry), SORT_NONE);
+
+ // Next
+ mark_entry = mark_entry->next;
+ }
+ } else {
+ fileListAddEntry(©_list, fileListCopyEntry(file_entry), SORT_NONE);
+ }
+
+ strcpy(copy_list.path, file_list.path);
+ copy_list.is_in_archive = isInArchive();
+
+ char *message;
+
+ // On marked entry
+ if (copy_list.length > 1 && fileListFindEntry(©_list, file_entry->name)) {
+ message = language_container[COPIED_FILES_FOLDERS];
+ } else {
+ message = language_container[file_entry->is_folder ? COPIED_FOLDER : COPIED_FILE];
+ }
+
+ // Copy message
+ infoDialog(message, copy_list.length);
+ }
+
+ break;
+ }
+
+ case MENU_MAIN_ENTRY_PASTE:
+ {
+ int copy_text = 0;
+
+ switch (copy_mode) {
+ case COPY_MODE_NORMAL:
+ copy_text = COPYING;
+ break;
+
+ case COPY_MODE_MOVE:
+ copy_text = MOVING;
+ break;
+
+ case COPY_MODE_EXTRACT:
+ copy_text = EXTRACTING;
+ break;
+ }
+
+ initMessageDialog(MESSAGE_DIALOG_PROGRESS_BAR, language_container[copy_text]);
+ setDialogStep(DIALOG_STEP_PASTE);
+ break;
+ }
+
+ case MENU_MAIN_ENTRY_DELETE:
+ {
+ FileListEntry *file_entry = fileListGetNthEntry(&file_list, base_pos + rel_pos);
+ if (file_entry) {
+ char *message;
+
+ // On marked entry
+ if (mark_list.length > 1 && fileListFindEntry(&mark_list, file_entry->name)) {
+ message = language_container[DELETE_FILES_FOLDERS_QUESTION];
+ } else {
+ message = language_container[file_entry->is_folder ? DELETE_FOLDER_QUESTION : DELETE_FILE_QUESTION];
+ }
+
+ initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_YESNO, message);
+ setDialogStep(DIALOG_STEP_DELETE_QUESTION);
+ }
+
+ break;
+ }
+
+ case MENU_MAIN_ENTRY_RENAME:
+ {
+ FileListEntry *file_entry = fileListGetNthEntry(&file_list, base_pos + rel_pos);
+ if (file_entry) {
+ char name[MAX_NAME_LENGTH];
+ strcpy(name, file_entry->name);
+ removeEndSlash(name);
+
+ initImeDialog(language_container[RENAME], name, MAX_NAME_LENGTH, SCE_IME_TYPE_BASIC_LATIN, 0, 0);
+
+ setDialogStep(DIALOG_STEP_RENAME);
+ }
+
+ break;
+ }
+
+ case MENU_MAIN_ENTRY_PROPERTIES:
+ {
+ FileListEntry *file_entry = fileListGetNthEntry(&file_list, base_pos + rel_pos);
+ if (file_entry) {
+ snprintf(cur_file, MAX_PATH_LENGTH - 1, "%s%s", file_list.path, file_entry->name);
+ initPropertyDialog(cur_file, file_entry);
+ }
+
+ break;
+ }
+
+ case MENU_MAIN_ENTRY_NEW:
+ {
+ setContextMenu(&context_menu_new);
+ setContextMenuNewVisibilities();
+ return CONTEXT_MENU_MORE_OPENING;
+ }
+
+ case MENU_MAIN_ENTRY_MORE:
+ {
+ setContextMenu(&context_menu_more);
+ setContextMenuMoreVisibilities();
+ return CONTEXT_MENU_MORE_OPENING;
+ }
+
+ case MENU_MAIN_ENTRY_SORT_BY:
+ {
+ setContextMenu(&context_menu_sort);
+ setContextMenuSortVisibilities();
+ return CONTEXT_MENU_MORE_OPENING;
+ }
+
+ case MENU_MAIN_ENTRY_SEND:
+ {
+ initNetCheckDialog(SCE_NETCHECK_DIALOG_MODE_PSP_ADHOC_JOIN, 60 * 1000 * 1000);
+ setDialogStep(DIALOG_STEP_ADHOC_SEND_NETCHECK);
+ break;
+ }
+
+ case MENU_MAIN_ENTRY_RECEIVE:
+ {
+ initNetCheckDialog(SCE_NETCHECK_DIALOG_MODE_PSP_ADHOC_CONN, 0);
+ setDialogStep(DIALOG_STEP_ADHOC_RECEIVE_NETCHECK);
+ break;
+ }
+ }
+
+ return CONTEXT_MENU_CLOSING;
+}
+
+static int contextMenuSortEnterCallback(int sel, void *context) {
+ switch (sel) {
+ case MENU_SORT_ENTRY_BY_NAME:
+ sort_mode = SORT_BY_NAME;
+ break;
+
+ case MENU_SORT_ENTRY_BY_SIZE:
+ sort_mode = SORT_BY_SIZE;
+ break;
+
+ case MENU_SORT_ENTRY_BY_DATE:
+ sort_mode = SORT_BY_DATE;
+ break;
+ }
+
+ // Refresh list
+ refreshFileList();
+
+ return CONTEXT_MENU_CLOSING;
+}
+
+static int contextMenuMoreEnterCallback(int sel, void *context) {
+ switch (sel) {
+ case MENU_MORE_ENTRY_COMPRESS:
+ {
+ FileListEntry *file_entry = fileListGetNthEntry(&file_list, base_pos + rel_pos);
+ if (file_entry) {
+ char path[MAX_NAME_LENGTH];
+
+ // On marked entry
+ if (mark_list.length > 1 && fileListFindEntry(&mark_list, file_entry->name)) {
+ int end_slash = removeEndSlash(file_list.path);
+
+ char *p = strrchr(file_list.path, '/');
+ if (!p)
+ p = strrchr(file_list.path, ':');
+
+ if (strlen(p + 1) > 0) {
+ strcpy(path, p + 1);
+ } else {
+ strncpy(path, file_list.path, p - file_list.path);
+ path[p - file_list.path] = '\0';
+ }
+
+ if (end_slash)
+ addEndSlash(file_list.path);
+ } else {
+ char *p = strrchr(file_entry->name, '.');
+ if (!p)
+ p = strrchr(file_entry->name, '/');
+ if (!p)
+ p = file_entry->name + strlen(file_entry->name);
+
+ strncpy(path, file_entry->name, p-file_entry->name);
+ path[p - file_entry->name] = '\0';
+ }
+
+ // Append .zip extension
+ strcat(path, ".zip");
+
+ initImeDialog(language_container[ARCHIVE_NAME], path, MAX_NAME_LENGTH, SCE_IME_TYPE_BASIC_LATIN, 0, 0);
+ setDialogStep(DIALOG_STEP_COMPRESS_NAME);
+ }
+
+ break;
+ }
+
+ case MENU_MORE_ENTRY_INSTALL_ALL:
+ {
+ // Empty install list
+ fileListEmpty(&install_list);
+
+ FileListEntry *file_entry = file_list.head->next; // Ignore '..'
+
+ int i;
+ for (i = 0; i < file_list.length - 1; i++) {
+ char path[MAX_PATH_LENGTH];
+ snprintf(path, MAX_PATH_LENGTH - 1, "%s%s", file_list.path, file_entry->name);
+
+ int type = getFileType(path);
+ if (type == FILE_TYPE_VPK) {
+ fileListAddEntry(&install_list, fileListCopyEntry(file_entry), SORT_NONE);
+ }
+
+ // Next
+ file_entry = file_entry->next;
+ }
+
+ strcpy(install_list.path, file_list.path);
+
+ initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_YESNO, language_container[INSTALL_ALL_QUESTION]);
+ setDialogStep(DIALOG_STEP_INSTALL_QUESTION);
+
+ break;
+ }
+
+ case MENU_MORE_ENTRY_INSTALL_FOLDER:
+ {
+ FileListEntry *file_entry = fileListGetNthEntry(&file_list, base_pos + rel_pos);
+ if (file_entry) {
+ snprintf(cur_file, MAX_PATH_LENGTH - 1, "%s%s", file_list.path, file_entry->name);
+ initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_YESNO, language_container[INSTALL_FOLDER_QUESTION]);
+ setDialogStep(DIALOG_STEP_INSTALL_QUESTION);
+ }
+
+ break;
+ }
+
+ case MENU_MORE_ENTRY_EXPORT_MEDIA:
+ {
+ FileListEntry *file_entry = fileListGetNthEntry(&file_list, base_pos + rel_pos);
+ if (file_entry) {
+ char *message;
+
+ // On marked entry
+ if (mark_list.length > 1 && fileListFindEntry(&mark_list, file_entry->name)) {
+ message = language_container[EXPORT_FILES_FOLDERS_QUESTION];
+ } else {
+ message = language_container[file_entry->is_folder ? EXPORT_FOLDER_QUESTION : EXPORT_FILE_QUESTION];
+ }
+
+ initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_YESNO, message);
+ setDialogStep(DIALOG_STEP_EXPORT_QUESTION);
+ }
+
+ break;
+ }
+
+ case MENU_MORE_ENTRY_CALCULATE_SHA1:
+ {
+ // Ensure user wants to actually take the hash
+ initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_YESNO, language_container[HASH_FILE_QUESTION]);
+ setDialogStep(DIALOG_STEP_HASH_QUESTION);
+ break;
+ }
+ }
+
+ return CONTEXT_MENU_CLOSING;
+}
+
+static int contextMenuNewEnterCallback(int sel, void *context) {
+ switch (sel) {
+ case MENU_NEW_FILE: {
+ char path[MAX_PATH_LENGTH];
+ int count = 1;
+ while (1) {
+ if (count == 1) {
+ snprintf(path, MAX_PATH_LENGTH - 1, "%s%s", file_list.path,
+ language_container[NEW_FILE]);
+ } else {
+ snprintf(path, MAX_PATH_LENGTH - 1, "%s%s (%d)", file_list.path,
+ language_container[NEW_FILE], count);
+ }
+ if (!checkFileExist(path))
+ break;
+
+ count++;
+ }
+ initImeDialog(language_container[NEW_FILE], path + strlen(file_list.path),
+ MAX_NAME_LENGTH, SCE_IME_TYPE_BASIC_LATIN, 0, 0);
+ setDialogStep(DIALOG_STEP_NEW_FILE);
+ break;
+ };
+ case MENU_NEW_FOLDER: {
+ // Find a new folder name
+ char path[MAX_PATH_LENGTH];
+
+ int count = 1;
+ while (1) {
+ if (count == 1) {
+ snprintf(path, MAX_PATH_LENGTH - 1, "%s%s", file_list.path,
+ language_container[NEW_FOLDER]);
+ } else {
+ snprintf(path, MAX_PATH_LENGTH - 1, "%s%s (%d)", file_list.path,
+ language_container[NEW_FOLDER], count);
+ }
+
+ if (!checkFolderExist(path))
+ break;
+
+ count++;
+ }
+
+ initImeDialog(language_container[NEW_FOLDER], path + strlen(file_list.path),
+ MAX_NAME_LENGTH, SCE_IME_TYPE_BASIC_LATIN, 0, 0);
+ setDialogStep(DIALOG_STEP_NEW_FOLDER);
+ break;
+ }
+ }
+ // Refresh list
+ refreshFileList();
+
+ return CONTEXT_MENU_CLOSING;
+}
+
diff --git a/modules/kernel/CMakeLists.txt b/modules/kernel/CMakeLists.txt
index 1dda2e3..6209be6 100644
--- a/modules/kernel/CMakeLists.txt
+++ b/modules/kernel/CMakeLists.txt
@@ -1,49 +1,49 @@
-cmake_minimum_required(VERSION 2.8)
-
-if(NOT DEFINED CMAKE_TOOLCHAIN_FILE)
- if(DEFINED ENV{VITASDK})
- set(CMAKE_TOOLCHAIN_FILE "$ENV{VITASDK}/share/vita.toolchain.cmake" CACHE PATH "toolchain file")
- else()
- message(FATAL_ERROR "Please define VITASDK to point to your SDK path!")
- endif()
-endif()
-
-project(kernel)
-include("${VITASDK}/share/vita.cmake" REQUIRED)
-
-set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wl,-q -Wall -O3 -nostdlib")
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti -fno-exceptions")
-
-add_executable(kernel
- main.c
-)
-
-target_link_libraries(kernel
- SceIofilemgrForDriver_stub
- SceSysclibForDriver_stub
- SceSysmemForDriver_stub
- SceModulemgrForDriver_stub
- SceThreadmgrForDriver_stub
- SceProcessmgrForDriver_stub
- SceNpDrmForDriver_stub
- taihenForKernel_stub
- taihenModuleUtils_stub
-)
-
-vita_create_self(kernel.skprx kernel CONFIG exports.yml UNSAFE)
-
-vita_create_stubs(stubs kernel ${CMAKE_SOURCE_DIR}/exports.yml KERNEL)
-
-install(DIRECTORY ${CMAKE_BINARY_DIR}/stubs/
- DESTINATION lib
- FILES_MATCHING PATTERN "*.a"
-)
-
-install(FILES vitashell_kernel.h
- DESTINATION include
-)
-
-add_custom_target(copy
- COMMAND cp kernel.skprx ../../../resources/kernel.skprx
- DEPENDS kernel.skprx
+cmake_minimum_required(VERSION 2.8)
+
+if(NOT DEFINED CMAKE_TOOLCHAIN_FILE)
+ if(DEFINED ENV{VITASDK})
+ set(CMAKE_TOOLCHAIN_FILE "$ENV{VITASDK}/share/vita.toolchain.cmake" CACHE PATH "toolchain file")
+ else()
+ message(FATAL_ERROR "Please define VITASDK to point to your SDK path!")
+ endif()
+endif()
+
+project(kernel)
+include("${VITASDK}/share/vita.cmake" REQUIRED)
+
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wl,-q -Wall -O3 -nostdlib")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti -fno-exceptions")
+
+add_executable(kernel
+ main.c
+)
+
+target_link_libraries(kernel
+ SceIofilemgrForDriver_stub
+ SceSysclibForDriver_stub
+ SceSysmemForDriver_stub
+ SceModulemgrForDriver_stub
+ SceThreadmgrForDriver_stub
+ SceProcessmgrForDriver_stub
+ SceNpDrmForDriver_stub
+ taihenForKernel_stub
+ taihenModuleUtils_stub
+)
+
+vita_create_self(kernel.skprx kernel CONFIG exports.yml UNSAFE)
+
+vita_create_stubs(stubs kernel ${CMAKE_SOURCE_DIR}/exports.yml KERNEL)
+
+install(DIRECTORY ${CMAKE_BINARY_DIR}/stubs/
+ DESTINATION lib
+ FILES_MATCHING PATTERN "*.a"
+)
+
+install(FILES vitashell_kernel.h
+ DESTINATION include
+)
+
+add_custom_target(copy
+ COMMAND cp kernel.skprx ../../../resources/kernel.skprx
+ DEPENDS kernel.skprx
)
\ No newline at end of file
diff --git a/modules/kernel/exports.yml b/modules/kernel/exports.yml
index b9f754d..7a528f8 100644
--- a/modules/kernel/exports.yml
+++ b/modules/kernel/exports.yml
@@ -1,16 +1,16 @@
-VitaShellKernel2:
- attributes: 0
- version:
- major: 1
- minor: 0
- main:
- start: module_start
- stop: module_stop
- modules:
- VitaShellKernel2Library:
- syscall: true
- functions:
- - shellKernelIsUx0Redirected
- - shellKernelRedirectUx0
- - shellKernelMountById
+VitaShellKernel2:
+ attributes: 0
+ version:
+ major: 1
+ minor: 0
+ main:
+ start: module_start
+ stop: module_stop
+ modules:
+ VitaShellKernel2Library:
+ syscall: true
+ functions:
+ - shellKernelIsUx0Redirected
+ - shellKernelRedirectUx0
+ - shellKernelMountById
- shellKernelGetRifVitaKey
\ No newline at end of file
diff --git a/modules/kernel/main.c b/modules/kernel/main.c
index b2e55be..3d589f0 100644
--- a/modules/kernel/main.c
+++ b/modules/kernel/main.c
@@ -1,290 +1,290 @@
-/*
- VitaShell
- Copyright (C) 2015-2018, TheFloW
-
- 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, either version 3 of the License, or
- (at your option) any later version.
-
- 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 for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
-*/
-
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include
-
-#include
-
-#include "vitashell_kernel.h"
-
-#define MOUNT_POINT_ID 0x800
-
-int module_get_export_func(SceUID pid, const char *modname, uint32_t libnid, uint32_t funcnid, uintptr_t *func);
-int module_get_offset(SceUID pid, SceUID modid, int segidx, size_t offset, uintptr_t *addr);
-
-typedef struct {
- const char *dev;
- const char *dev2;
- const char *blkdev;
- const char *blkdev2;
- int id;
-} SceIoDevice;
-
-typedef struct {
- int id;
- const char *dev_unix;
- int unk;
- int dev_major;
- int dev_minor;
- const char *dev_filesystem;
- int unk2;
- SceIoDevice *dev;
- int unk3;
- SceIoDevice *dev2;
- int unk4;
- int unk5;
- int unk6;
- int unk7;
-} SceIoMountPoint;
-
-static char ux0_blkdev[64], ux0_blkdev2[64];
-
-static SceIoDevice ux0_dev = { "ux0:", "exfatux0", ux0_blkdev, ux0_blkdev2, MOUNT_POINT_ID };
-
-static SceIoMountPoint *(* sceIoFindMountPoint)(int id) = NULL;
-
-static SceUID hookid = -1;
-
-static tai_hook_ref_t ksceSysrootIsSafeModeRef;
-
-static tai_hook_ref_t ksceSblAimgrIsDolceRef;
-
-static int ksceSysrootIsSafeModePatched() {
- return 1;
-}
-
-static int ksceSblAimgrIsDolcePatched() {
- return 1;
-}
-
-int shellKernelIsUx0Redirected(const char *blkdev, const char *blkdev2) {
- char k_blkdev[64], k_blkdev2[64];
-
- uint32_t state;
- ENTER_SYSCALL(state);
-
- SceIoMountPoint *mount = sceIoFindMountPoint(MOUNT_POINT_ID);
- if (!mount) {
- EXIT_SYSCALL(state);
- return 0;
- }
-
- ksceKernelStrncpyUserToKernel(k_blkdev, blkdev, sizeof(k_blkdev)-1);
- ksceKernelStrncpyUserToKernel(k_blkdev2, blkdev2, sizeof(k_blkdev2)-1);
-
- if (mount && mount->dev && mount->dev->blkdev && strcmp(mount->dev->blkdev, k_blkdev) == 0) {
- EXIT_SYSCALL(state);
- return 1;
- }
-
- EXIT_SYSCALL(state);
- return 0;
-}
-
-int shellKernelRedirectUx0(const char *blkdev, const char *blkdev2) {
- uint32_t state;
- ENTER_SYSCALL(state);
-
- SceIoMountPoint *mount = sceIoFindMountPoint(MOUNT_POINT_ID);
- if (!mount) {
- EXIT_SYSCALL(state);
- return -1;
- }
-
- ksceKernelStrncpyUserToKernel(ux0_blkdev, blkdev, sizeof(ux0_blkdev)-1);
- ksceKernelStrncpyUserToKernel(ux0_blkdev2, blkdev2, sizeof(ux0_blkdev2)-1);
-
- mount->dev = &ux0_dev;
- mount->dev2 = &ux0_dev;
-
- EXIT_SYSCALL(state);
- return 0;
-}
-
-int _shellKernelMountById(ShellMountIdArgs *args) {
- int res;
-
- void *(* sceAppMgrFindProcessInfoByPid)(void *data, SceUID pid);
- int (* sceAppMgrMountById)(SceUID pid, void *info, int id, const char *titleid, const char *path, const char *desired_mount_point, const void *klicensee, char *mount_point);
- int (* _ksceKernelGetModuleInfo)(SceUID pid, SceUID modid, SceKernelModuleInfo *info);
-
- // Get tai module info
- tai_module_info_t tai_info;
- tai_info.size = sizeof(tai_module_info_t);
- if (taiGetModuleInfoForKernel(KERNEL_PID, "SceAppMgr", &tai_info) < 0)
- return SCE_KERNEL_START_SUCCESS;
-
- switch (tai_info.module_nid) {
- case 0xDBB29DB7: // 3.60 retail
- module_get_offset(KERNEL_PID, tai_info.modid, 0, 0x2DE1, (uintptr_t *)&sceAppMgrFindProcessInfoByPid);
- module_get_offset(KERNEL_PID, tai_info.modid, 0, 0x19B51, (uintptr_t *)&sceAppMgrMountById);
- break;
-
- case 0x1C9879D6: // 3.65 retail
- module_get_offset(KERNEL_PID, tai_info.modid, 0, 0x2DE1, (uintptr_t *)&sceAppMgrFindProcessInfoByPid);
- module_get_offset(KERNEL_PID, tai_info.modid, 0, 0x19E61, (uintptr_t *)&sceAppMgrMountById);
- break;
-
- case 0x54E2E984: // 3.67 retail
- case 0xC3C538DE: // 3.68 retail
- module_get_offset(KERNEL_PID, tai_info.modid, 0, 0x2DE1, (uintptr_t *)&sceAppMgrFindProcessInfoByPid);
- module_get_offset(KERNEL_PID, tai_info.modid, 0, 0x19E6D, (uintptr_t *)&sceAppMgrMountById);
- break;
- }
-
- res = module_get_export_func(KERNEL_PID, "SceKernelModulemgr", 0xC445FA63, 0xD269F915, (uintptr_t *)&_ksceKernelGetModuleInfo);
- if (res < 0)
- res = module_get_export_func(KERNEL_PID, "SceKernelModulemgr", 0x92C9FFC2, 0xDAA90093, (uintptr_t *)&_ksceKernelGetModuleInfo);
- if (res < 0)
- return res;
-
- // Module info
- SceKernelModuleInfo mod_info;
- mod_info.size = sizeof(SceKernelModuleInfo);
- res = _ksceKernelGetModuleInfo(KERNEL_PID, tai_info.modid, &mod_info);
- if (res < 0)
- return res;
-
- uint32_t appmgr_data_addr = (uint32_t)mod_info.segments[1].vaddr;
-
- SceUID process_id = ksceKernelGetProcessId();
-
- void *info = sceAppMgrFindProcessInfoByPid((void *)(appmgr_data_addr + 0x500), process_id);
- if (!info)
- return -1;
-
- char process_titleid[12];
- char path[256];
- char desired_mount_point[16];
- char mount_point[16];
- char klicensee[16];
-
- memset(mount_point, 0, sizeof(mount_point));
-
- if (args->process_titleid)
- ksceKernelStrncpyUserToKernel(process_titleid, (uintptr_t)args->process_titleid, 11);
- if (args->path)
- ksceKernelStrncpyUserToKernel(path, (uintptr_t)args->path, 255);
- if (args->desired_mount_point)
- ksceKernelStrncpyUserToKernel(desired_mount_point, (uintptr_t)args->desired_mount_point, 15);
- if (args->klicensee)
- ksceKernelMemcpyUserToKernel(klicensee, (uintptr_t)args->klicensee, 0x10);
-
- res = sceAppMgrMountById(process_id, info + 0x580, args->id, args->process_titleid ? process_titleid : NULL, args->path ? path : NULL,
- args->desired_mount_point ? desired_mount_point : NULL, args->klicensee ? klicensee : NULL, mount_point);
-
- if (args->mount_point)
- ksceKernelStrncpyKernelToUser((uintptr_t)args->mount_point, mount_point, 15);
-
- return res;
-}
-
-int shellKernelMountById(ShellMountIdArgs *args) {
- uint32_t state;
- ENTER_SYSCALL(state);
-
- ShellMountIdArgs k_args;
- ksceKernelMemcpyUserToKernel(&k_args, (uintptr_t)args, sizeof(ShellMountIdArgs));
-
- int res = ksceKernelRunWithStack(0x2000, (void *)_shellKernelMountById, &k_args);
-
- EXIT_SYSCALL(state);
- return res;
-}
-
-int shellKernelGetRifVitaKey(const void *license_buf, void *klicensee) {
- char k_license_buf[0x200];
- char k_klicensee[0x10];
-
- memset(k_klicensee, 0, sizeof(k_klicensee));
-
- if (license_buf)
- ksceKernelMemcpyUserToKernel(k_license_buf, license_buf, sizeof(k_license_buf));
-
- int res = ksceNpDrmGetRifVitaKey(k_license_buf, k_klicensee, NULL, NULL, NULL, NULL);
-
- if (klicensee)
- ksceKernelMemcpyKernelToUser(klicensee, k_klicensee, sizeof(k_klicensee));
-
- return res;
-}
-
-void _start() __attribute__ ((weak, alias("module_start")));
-int module_start(SceSize args, void *argp) {
- SceUID tmp1, tmp2;
- // Get tai module info
- tai_module_info_t info;
- info.size = sizeof(tai_module_info_t);
- if (taiGetModuleInfoForKernel(KERNEL_PID, "SceIofilemgr", &info) < 0)
- return SCE_KERNEL_START_SUCCESS;
-
- // Get important function
- switch (info.module_nid) {
- case 0x9642948C: // 3.60 retail
- module_get_offset(KERNEL_PID, info.modid, 0, 0x138C1, (uintptr_t *)&sceIoFindMountPoint);
- break;
-
- case 0xA96ACE9D: // 3.65 retail
- case 0x3347A95F: // 3.67 retail
- case 0x90DA33DE: // 3.68 retail
- module_get_offset(KERNEL_PID, info.modid, 0, 0x182F5, (uintptr_t *)&sceIoFindMountPoint);
- break;
-
- default:
- return SCE_KERNEL_START_SUCCESS;
- }
-
- // Fake safe mode so that SceUsbMass can be loaded
- tmp1 = taiHookFunctionExportForKernel(KERNEL_PID, &ksceSysrootIsSafeModeRef, "SceSysmem", 0x2ED7F97A, 0x834439A7, ksceSysrootIsSafeModePatched);
- if (tmp1 < 0)
- return SCE_KERNEL_START_SUCCESS;
- // this patch is only needed on handheld units
- tmp2 = taiHookFunctionExportForKernel(KERNEL_PID, &ksceSblAimgrIsDolceRef, "SceSysmem", 0xFD00C69A, 0x71608CA3, ksceSblAimgrIsDolcePatched);
- if (tmp2 < 0)
- return SCE_KERNEL_START_SUCCESS;
-
- // Load SceUsbMass
- SceUID modid = ksceKernelLoadStartModule("ux0:VitaShell/module/umass.skprx", 0, NULL, 0, NULL, NULL);
-
- // Release patch
- taiHookReleaseForKernel(tmp1, ksceSysrootIsSafeModeRef);
- taiHookReleaseForKernel(tmp2, ksceSblAimgrIsDolceRef);
-
- // Check result
- if (modid < 0)
- return SCE_KERNEL_START_SUCCESS;
-
- // Fake safe mode in SceUsbServ
- hookid = taiHookFunctionImportForKernel(KERNEL_PID, &ksceSysrootIsSafeModeRef, "SceUsbServ", 0x2ED7F97A, 0x834439A7, ksceSysrootIsSafeModePatched);
-
- return SCE_KERNEL_START_SUCCESS;
-}
-
-int module_stop(SceSize args, void *argp) {
- if (hookid >= 0)
- taiHookReleaseForKernel(hookid, ksceSysrootIsSafeModeRef);
-
- return SCE_KERNEL_STOP_SUCCESS;
+/*
+ VitaShell
+ Copyright (C) 2015-2018, TheFloW
+
+ 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, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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 for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include
+
+#include "vitashell_kernel.h"
+
+#define MOUNT_POINT_ID 0x800
+
+int module_get_export_func(SceUID pid, const char *modname, uint32_t libnid, uint32_t funcnid, uintptr_t *func);
+int module_get_offset(SceUID pid, SceUID modid, int segidx, size_t offset, uintptr_t *addr);
+
+typedef struct {
+ const char *dev;
+ const char *dev2;
+ const char *blkdev;
+ const char *blkdev2;
+ int id;
+} SceIoDevice;
+
+typedef struct {
+ int id;
+ const char *dev_unix;
+ int unk;
+ int dev_major;
+ int dev_minor;
+ const char *dev_filesystem;
+ int unk2;
+ SceIoDevice *dev;
+ int unk3;
+ SceIoDevice *dev2;
+ int unk4;
+ int unk5;
+ int unk6;
+ int unk7;
+} SceIoMountPoint;
+
+static char ux0_blkdev[64], ux0_blkdev2[64];
+
+static SceIoDevice ux0_dev = { "ux0:", "exfatux0", ux0_blkdev, ux0_blkdev2, MOUNT_POINT_ID };
+
+static SceIoMountPoint *(* sceIoFindMountPoint)(int id) = NULL;
+
+static SceUID hookid = -1;
+
+static tai_hook_ref_t ksceSysrootIsSafeModeRef;
+
+static tai_hook_ref_t ksceSblAimgrIsDolceRef;
+
+static int ksceSysrootIsSafeModePatched() {
+ return 1;
+}
+
+static int ksceSblAimgrIsDolcePatched() {
+ return 1;
+}
+
+int shellKernelIsUx0Redirected(const char *blkdev, const char *blkdev2) {
+ char k_blkdev[64], k_blkdev2[64];
+
+ uint32_t state;
+ ENTER_SYSCALL(state);
+
+ SceIoMountPoint *mount = sceIoFindMountPoint(MOUNT_POINT_ID);
+ if (!mount) {
+ EXIT_SYSCALL(state);
+ return 0;
+ }
+
+ ksceKernelStrncpyUserToKernel(k_blkdev, blkdev, sizeof(k_blkdev)-1);
+ ksceKernelStrncpyUserToKernel(k_blkdev2, blkdev2, sizeof(k_blkdev2)-1);
+
+ if (mount && mount->dev && mount->dev->blkdev && strcmp(mount->dev->blkdev, k_blkdev) == 0) {
+ EXIT_SYSCALL(state);
+ return 1;
+ }
+
+ EXIT_SYSCALL(state);
+ return 0;
+}
+
+int shellKernelRedirectUx0(const char *blkdev, const char *blkdev2) {
+ uint32_t state;
+ ENTER_SYSCALL(state);
+
+ SceIoMountPoint *mount = sceIoFindMountPoint(MOUNT_POINT_ID);
+ if (!mount) {
+ EXIT_SYSCALL(state);
+ return -1;
+ }
+
+ ksceKernelStrncpyUserToKernel(ux0_blkdev, blkdev, sizeof(ux0_blkdev)-1);
+ ksceKernelStrncpyUserToKernel(ux0_blkdev2, blkdev2, sizeof(ux0_blkdev2)-1);
+
+ mount->dev = &ux0_dev;
+ mount->dev2 = &ux0_dev;
+
+ EXIT_SYSCALL(state);
+ return 0;
+}
+
+int _shellKernelMountById(ShellMountIdArgs *args) {
+ int res;
+
+ void *(* sceAppMgrFindProcessInfoByPid)(void *data, SceUID pid);
+ int (* sceAppMgrMountById)(SceUID pid, void *info, int id, const char *titleid, const char *path, const char *desired_mount_point, const void *klicensee, char *mount_point);
+ int (* _ksceKernelGetModuleInfo)(SceUID pid, SceUID modid, SceKernelModuleInfo *info);
+
+ // Get tai module info
+ tai_module_info_t tai_info;
+ tai_info.size = sizeof(tai_module_info_t);
+ if (taiGetModuleInfoForKernel(KERNEL_PID, "SceAppMgr", &tai_info) < 0)
+ return SCE_KERNEL_START_SUCCESS;
+
+ switch (tai_info.module_nid) {
+ case 0xDBB29DB7: // 3.60 retail
+ module_get_offset(KERNEL_PID, tai_info.modid, 0, 0x2DE1, (uintptr_t *)&sceAppMgrFindProcessInfoByPid);
+ module_get_offset(KERNEL_PID, tai_info.modid, 0, 0x19B51, (uintptr_t *)&sceAppMgrMountById);
+ break;
+
+ case 0x1C9879D6: // 3.65 retail
+ module_get_offset(KERNEL_PID, tai_info.modid, 0, 0x2DE1, (uintptr_t *)&sceAppMgrFindProcessInfoByPid);
+ module_get_offset(KERNEL_PID, tai_info.modid, 0, 0x19E61, (uintptr_t *)&sceAppMgrMountById);
+ break;
+
+ case 0x54E2E984: // 3.67 retail
+ case 0xC3C538DE: // 3.68 retail
+ module_get_offset(KERNEL_PID, tai_info.modid, 0, 0x2DE1, (uintptr_t *)&sceAppMgrFindProcessInfoByPid);
+ module_get_offset(KERNEL_PID, tai_info.modid, 0, 0x19E6D, (uintptr_t *)&sceAppMgrMountById);
+ break;
+ }
+
+ res = module_get_export_func(KERNEL_PID, "SceKernelModulemgr", 0xC445FA63, 0xD269F915, (uintptr_t *)&_ksceKernelGetModuleInfo);
+ if (res < 0)
+ res = module_get_export_func(KERNEL_PID, "SceKernelModulemgr", 0x92C9FFC2, 0xDAA90093, (uintptr_t *)&_ksceKernelGetModuleInfo);
+ if (res < 0)
+ return res;
+
+ // Module info
+ SceKernelModuleInfo mod_info;
+ mod_info.size = sizeof(SceKernelModuleInfo);
+ res = _ksceKernelGetModuleInfo(KERNEL_PID, tai_info.modid, &mod_info);
+ if (res < 0)
+ return res;
+
+ uint32_t appmgr_data_addr = (uint32_t)mod_info.segments[1].vaddr;
+
+ SceUID process_id = ksceKernelGetProcessId();
+
+ void *info = sceAppMgrFindProcessInfoByPid((void *)(appmgr_data_addr + 0x500), process_id);
+ if (!info)
+ return -1;
+
+ char process_titleid[12];
+ char path[256];
+ char desired_mount_point[16];
+ char mount_point[16];
+ char klicensee[16];
+
+ memset(mount_point, 0, sizeof(mount_point));
+
+ if (args->process_titleid)
+ ksceKernelStrncpyUserToKernel(process_titleid, (uintptr_t)args->process_titleid, 11);
+ if (args->path)
+ ksceKernelStrncpyUserToKernel(path, (uintptr_t)args->path, 255);
+ if (args->desired_mount_point)
+ ksceKernelStrncpyUserToKernel(desired_mount_point, (uintptr_t)args->desired_mount_point, 15);
+ if (args->klicensee)
+ ksceKernelMemcpyUserToKernel(klicensee, (uintptr_t)args->klicensee, 0x10);
+
+ res = sceAppMgrMountById(process_id, info + 0x580, args->id, args->process_titleid ? process_titleid : NULL, args->path ? path : NULL,
+ args->desired_mount_point ? desired_mount_point : NULL, args->klicensee ? klicensee : NULL, mount_point);
+
+ if (args->mount_point)
+ ksceKernelStrncpyKernelToUser((uintptr_t)args->mount_point, mount_point, 15);
+
+ return res;
+}
+
+int shellKernelMountById(ShellMountIdArgs *args) {
+ uint32_t state;
+ ENTER_SYSCALL(state);
+
+ ShellMountIdArgs k_args;
+ ksceKernelMemcpyUserToKernel(&k_args, (uintptr_t)args, sizeof(ShellMountIdArgs));
+
+ int res = ksceKernelRunWithStack(0x2000, (void *)_shellKernelMountById, &k_args);
+
+ EXIT_SYSCALL(state);
+ return res;
+}
+
+int shellKernelGetRifVitaKey(const void *license_buf, void *klicensee) {
+ char k_license_buf[0x200];
+ char k_klicensee[0x10];
+
+ memset(k_klicensee, 0, sizeof(k_klicensee));
+
+ if (license_buf)
+ ksceKernelMemcpyUserToKernel(k_license_buf, license_buf, sizeof(k_license_buf));
+
+ int res = ksceNpDrmGetRifVitaKey(k_license_buf, k_klicensee, NULL, NULL, NULL, NULL);
+
+ if (klicensee)
+ ksceKernelMemcpyKernelToUser(klicensee, k_klicensee, sizeof(k_klicensee));
+
+ return res;
+}
+
+void _start() __attribute__ ((weak, alias("module_start")));
+int module_start(SceSize args, void *argp) {
+ SceUID tmp1, tmp2;
+ // Get tai module info
+ tai_module_info_t info;
+ info.size = sizeof(tai_module_info_t);
+ if (taiGetModuleInfoForKernel(KERNEL_PID, "SceIofilemgr", &info) < 0)
+ return SCE_KERNEL_START_SUCCESS;
+
+ // Get important function
+ switch (info.module_nid) {
+ case 0x9642948C: // 3.60 retail
+ module_get_offset(KERNEL_PID, info.modid, 0, 0x138C1, (uintptr_t *)&sceIoFindMountPoint);
+ break;
+
+ case 0xA96ACE9D: // 3.65 retail
+ case 0x3347A95F: // 3.67 retail
+ case 0x90DA33DE: // 3.68 retail
+ module_get_offset(KERNEL_PID, info.modid, 0, 0x182F5, (uintptr_t *)&sceIoFindMountPoint);
+ break;
+
+ default:
+ return SCE_KERNEL_START_SUCCESS;
+ }
+
+ // Fake safe mode so that SceUsbMass can be loaded
+ tmp1 = taiHookFunctionExportForKernel(KERNEL_PID, &ksceSysrootIsSafeModeRef, "SceSysmem", 0x2ED7F97A, 0x834439A7, ksceSysrootIsSafeModePatched);
+ if (tmp1 < 0)
+ return SCE_KERNEL_START_SUCCESS;
+ // this patch is only needed on handheld units
+ tmp2 = taiHookFunctionExportForKernel(KERNEL_PID, &ksceSblAimgrIsDolceRef, "SceSysmem", 0xFD00C69A, 0x71608CA3, ksceSblAimgrIsDolcePatched);
+ if (tmp2 < 0)
+ return SCE_KERNEL_START_SUCCESS;
+
+ // Load SceUsbMass
+ SceUID modid = ksceKernelLoadStartModule("ux0:VitaShell/module/umass.skprx", 0, NULL, 0, NULL, NULL);
+
+ // Release patch
+ taiHookReleaseForKernel(tmp1, ksceSysrootIsSafeModeRef);
+ taiHookReleaseForKernel(tmp2, ksceSblAimgrIsDolceRef);
+
+ // Check result
+ if (modid < 0)
+ return SCE_KERNEL_START_SUCCESS;
+
+ // Fake safe mode in SceUsbServ
+ hookid = taiHookFunctionImportForKernel(KERNEL_PID, &ksceSysrootIsSafeModeRef, "SceUsbServ", 0x2ED7F97A, 0x834439A7, ksceSysrootIsSafeModePatched);
+
+ return SCE_KERNEL_START_SUCCESS;
+}
+
+int module_stop(SceSize args, void *argp) {
+ if (hookid >= 0)
+ taiHookReleaseForKernel(hookid, ksceSysrootIsSafeModeRef);
+
+ return SCE_KERNEL_STOP_SUCCESS;
}
\ No newline at end of file
diff --git a/modules/patch/CMakeLists.txt b/modules/patch/CMakeLists.txt
index 679661a..5db3709 100644
--- a/modules/patch/CMakeLists.txt
+++ b/modules/patch/CMakeLists.txt
@@ -1,32 +1,32 @@
-cmake_minimum_required(VERSION 2.8)
-
-if(NOT DEFINED CMAKE_TOOLCHAIN_FILE)
- if(DEFINED ENV{VITASDK})
- set(CMAKE_TOOLCHAIN_FILE "$ENV{VITASDK}/share/vita.toolchain.cmake" CACHE PATH "toolchain file")
- else()
- message(FATAL_ERROR "Please define VITASDK to point to your SDK path!")
- endif()
-endif()
-
-project(patch)
-include("${VITASDK}/share/vita.cmake" REQUIRED)
-
-set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wl,-q -Wall -O3 -nostdlib")
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti -fno-exceptions")
-
-add_executable(patch
- main.c
-)
-
-target_link_libraries(patch
- taihenForKernel_stub
-)
-
-vita_create_self(patch.skprx patch CONFIG exports.yml UNSAFE)
-
-vita_create_stubs(stubs patch ${CMAKE_SOURCE_DIR}/exports.yml KERNEL)
-
-add_custom_target(copy
- COMMAND cp patch.skprx ../../../resources/patch.skprx
- DEPENDS patch.skprx
+cmake_minimum_required(VERSION 2.8)
+
+if(NOT DEFINED CMAKE_TOOLCHAIN_FILE)
+ if(DEFINED ENV{VITASDK})
+ set(CMAKE_TOOLCHAIN_FILE "$ENV{VITASDK}/share/vita.toolchain.cmake" CACHE PATH "toolchain file")
+ else()
+ message(FATAL_ERROR "Please define VITASDK to point to your SDK path!")
+ endif()
+endif()
+
+project(patch)
+include("${VITASDK}/share/vita.cmake" REQUIRED)
+
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wl,-q -Wall -O3 -nostdlib")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti -fno-exceptions")
+
+add_executable(patch
+ main.c
+)
+
+target_link_libraries(patch
+ taihenForKernel_stub
+)
+
+vita_create_self(patch.skprx patch CONFIG exports.yml UNSAFE)
+
+vita_create_stubs(stubs patch ${CMAKE_SOURCE_DIR}/exports.yml KERNEL)
+
+add_custom_target(copy
+ COMMAND cp patch.skprx ../../../resources/patch.skprx
+ DEPENDS patch.skprx
)
\ No newline at end of file
diff --git a/modules/patch/exports.yml b/modules/patch/exports.yml
index 2846676..9c62760 100644
--- a/modules/patch/exports.yml
+++ b/modules/patch/exports.yml
@@ -1,8 +1,8 @@
-VitaShellPatch:
- attributes: 0
- version:
- major: 1
- minor: 0
- main:
- start: module_start
+VitaShellPatch:
+ attributes: 0
+ version:
+ major: 1
+ minor: 0
+ main:
+ start: module_start
stop: module_stop
\ No newline at end of file
diff --git a/modules/patch/main.c b/modules/patch/main.c
index e5afe48..9f32d56 100644
--- a/modules/patch/main.c
+++ b/modules/patch/main.c
@@ -1,59 +1,59 @@
-/*
- VitaShell
- Copyright (C) 2015-2018, TheFloW
-
- 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, either version 3 of the License, or
- (at your option) any later version.
-
- 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 for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
-*/
-
-#include
-#include
-
-static SceUID hooks[2];
-
-void _start() __attribute__ ((weak, alias("module_start")));
-int module_start(SceSize args, void *argp) {
- // Get tai module info
- tai_module_info_t info;
- info.size = sizeof(tai_module_info_t);
- if (taiGetModuleInfoForKernel(KERNEL_PID, "SceAppMgr", &info) < 0)
- return SCE_KERNEL_START_SUCCESS;
-
- // Patch to allow Memory Card remount
- uint32_t nop_nop_opcode = 0xBF00BF00;
- switch (info.module_nid) {
- case 0xDBB29DB7: // 3.60 retail
- case 0x1C9879D6: // 3.65 retail
- hooks[0] = taiInjectDataForKernel(KERNEL_PID, info.modid, 0, 0xB338, &nop_nop_opcode, 4);
- hooks[1] = taiInjectDataForKernel(KERNEL_PID, info.modid, 0, 0xB368, &nop_nop_opcode, 2);
- break;
-
- case 0x54E2E984: // 3.67 retail
- case 0xC3C538DE: // 3.68 retail
- hooks[0] = taiInjectDataForKernel(KERNEL_PID, info.modid, 0, 0xB344, &nop_nop_opcode, 4);
- hooks[1] = taiInjectDataForKernel(KERNEL_PID, info.modid, 0, 0xB374, &nop_nop_opcode, 2);
- break;
- }
-
- return SCE_KERNEL_START_SUCCESS;
-}
-
-int module_stop(SceSize args, void *argp) {
- if (hooks[1] >= 0)
- taiInjectReleaseForKernel(hooks[1]);
-
- if (hooks[0] >= 0)
- taiInjectReleaseForKernel(hooks[0]);
-
- return SCE_KERNEL_STOP_SUCCESS;
+/*
+ VitaShell
+ Copyright (C) 2015-2018, TheFloW
+
+ 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, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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 for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+#include
+#include
+
+static SceUID hooks[2];
+
+void _start() __attribute__ ((weak, alias("module_start")));
+int module_start(SceSize args, void *argp) {
+ // Get tai module info
+ tai_module_info_t info;
+ info.size = sizeof(tai_module_info_t);
+ if (taiGetModuleInfoForKernel(KERNEL_PID, "SceAppMgr", &info) < 0)
+ return SCE_KERNEL_START_SUCCESS;
+
+ // Patch to allow Memory Card remount
+ uint32_t nop_nop_opcode = 0xBF00BF00;
+ switch (info.module_nid) {
+ case 0xDBB29DB7: // 3.60 retail
+ case 0x1C9879D6: // 3.65 retail
+ hooks[0] = taiInjectDataForKernel(KERNEL_PID, info.modid, 0, 0xB338, &nop_nop_opcode, 4);
+ hooks[1] = taiInjectDataForKernel(KERNEL_PID, info.modid, 0, 0xB368, &nop_nop_opcode, 2);
+ break;
+
+ case 0x54E2E984: // 3.67 retail
+ case 0xC3C538DE: // 3.68 retail
+ hooks[0] = taiInjectDataForKernel(KERNEL_PID, info.modid, 0, 0xB344, &nop_nop_opcode, 4);
+ hooks[1] = taiInjectDataForKernel(KERNEL_PID, info.modid, 0, 0xB374, &nop_nop_opcode, 2);
+ break;
+ }
+
+ return SCE_KERNEL_START_SUCCESS;
+}
+
+int module_stop(SceSize args, void *argp) {
+ if (hooks[1] >= 0)
+ taiInjectReleaseForKernel(hooks[1]);
+
+ if (hooks[0] >= 0)
+ taiInjectReleaseForKernel(hooks[0]);
+
+ return SCE_KERNEL_STOP_SUCCESS;
}
\ No newline at end of file
diff --git a/modules/usbdevice/CMakeLists.txt b/modules/usbdevice/CMakeLists.txt
index e4c916d..2177ff3 100644
--- a/modules/usbdevice/CMakeLists.txt
+++ b/modules/usbdevice/CMakeLists.txt
@@ -1,32 +1,32 @@
-cmake_minimum_required(VERSION 2.8)
-
-if(NOT DEFINED CMAKE_TOOLCHAIN_FILE)
- if(DEFINED ENV{VITASDK})
- set(CMAKE_TOOLCHAIN_FILE "$ENV{VITASDK}/share/vita.toolchain.cmake" CACHE PATH "toolchain file")
- else()
- message(FATAL_ERROR "Please define VITASDK to point to your SDK path!")
- endif()
-endif()
-
-project(usbdevice)
-include("${VITASDK}/share/vita.cmake" REQUIRED)
-
-set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wl,-q -Wall -O3 -nostdlib")
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti -fno-exceptions")
-
-add_executable(usbdevice
- main.c
-)
-
-target_link_libraries(usbdevice
- SceIofilemgrForDriver_stub
- SceSysclibForDriver_stub
- taihenForKernel_stub
-)
-
-vita_create_self(usbdevice.skprx usbdevice CONFIG exports.yml UNSAFE)
-
-add_custom_target(copy
- COMMAND cp usbdevice.skprx ../../../resources/usbdevice.skprx
- DEPENDS usbdevice.skprx
+cmake_minimum_required(VERSION 2.8)
+
+if(NOT DEFINED CMAKE_TOOLCHAIN_FILE)
+ if(DEFINED ENV{VITASDK})
+ set(CMAKE_TOOLCHAIN_FILE "$ENV{VITASDK}/share/vita.toolchain.cmake" CACHE PATH "toolchain file")
+ else()
+ message(FATAL_ERROR "Please define VITASDK to point to your SDK path!")
+ endif()
+endif()
+
+project(usbdevice)
+include("${VITASDK}/share/vita.cmake" REQUIRED)
+
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wl,-q -Wall -O3 -nostdlib")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti -fno-exceptions")
+
+add_executable(usbdevice
+ main.c
+)
+
+target_link_libraries(usbdevice
+ SceIofilemgrForDriver_stub
+ SceSysclibForDriver_stub
+ taihenForKernel_stub
+)
+
+vita_create_self(usbdevice.skprx usbdevice CONFIG exports.yml UNSAFE)
+
+add_custom_target(copy
+ COMMAND cp usbdevice.skprx ../../../resources/usbdevice.skprx
+ DEPENDS usbdevice.skprx
)
\ No newline at end of file
diff --git a/modules/usbdevice/exports.yml b/modules/usbdevice/exports.yml
index e8eade1..d0899dd 100644
--- a/modules/usbdevice/exports.yml
+++ b/modules/usbdevice/exports.yml
@@ -1,8 +1,8 @@
-VitaShellUsbDevice:
- attributes: 0
- version:
- major: 1
- minor: 0
- main:
- start: module_start
+VitaShellUsbDevice:
+ attributes: 0
+ version:
+ major: 1
+ minor: 0
+ main:
+ start: module_start
stop: module_stop
\ No newline at end of file
diff --git a/modules/usbdevice/main.c b/modules/usbdevice/main.c
index afa58d7..08ba67d 100644
--- a/modules/usbdevice/main.c
+++ b/modules/usbdevice/main.c
@@ -1,95 +1,95 @@
-/*
- VitaShell
- Copyright (C) 2015-2018, TheFloW
-
- 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, either version 3 of the License, or
- (at your option) any later version.
-
- 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 for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
-*/
-
-#include
-#include
-
-#include
-#include
-
-#include
-
-static tai_hook_ref_t ksceIoOpenRef;
-static tai_hook_ref_t ksceIoReadRef;
-
-static SceUID hooks[3];
-
-static int first = 1;
-
-static SceUID ksceIoOpenPatched(const char *file, int flags, SceMode mode) {
- first = 1;
-
- SceUID fd = TAI_CONTINUE(SceUID, ksceIoOpenRef, file, flags, mode);
-
- if (fd == 0x800F090D)
- return TAI_CONTINUE(SceUID, ksceIoOpenRef, file, flags & ~SCE_O_WRONLY, mode);
-
- return fd;
-}
-
-static int ksceIoReadPatched(SceUID fd, void *data, SceSize size) {
- int res = TAI_CONTINUE(int, ksceIoReadRef, fd, data, size);
-
- if (first) {
- first = 0;
-
- // Manipulate boot sector to support exFAT
- if (memcmp(data + 0x3, "EXFAT", 5) == 0) {
- // Sector size
- *(uint16_t *)(data + 0xB) = 1 << *(uint8_t *)(data + 0x6C);
-
- // Volume size
- *(uint32_t *)(data + 0x20) = *(uint32_t *)(data + 0x48);
- }
- }
-
- return res;
-}
-
-void _start() __attribute__ ((weak, alias("module_start")));
-int module_start(SceSize args, void *argp) {
- // Get tai module info
- tai_module_info_t info;
- info.size = sizeof(tai_module_info_t);
- if (taiGetModuleInfoForKernel(KERNEL_PID, "SceUsbstorVStorDriver", &info) < 0)
- return SCE_KERNEL_START_SUCCESS;
-
- // Remove image path limitation
- char zero[0x6E];
- memset(zero, 0, 0x6E);
- hooks[0] = taiInjectDataForKernel(KERNEL_PID, info.modid, 0, 0x1738, zero, 0x6E);
-
- // Add patches to support exFAT
- hooks[1] = taiHookFunctionImportForKernel(KERNEL_PID, &ksceIoOpenRef, "SceUsbstorVStorDriver", 0x40FD29C7, 0x75192972, ksceIoOpenPatched);
- hooks[2] = taiHookFunctionImportForKernel(KERNEL_PID, &ksceIoReadRef, "SceUsbstorVStorDriver", 0x40FD29C7, 0xE17EFC03, ksceIoReadPatched);
-
- return SCE_KERNEL_START_SUCCESS;
-}
-
-int module_stop(SceSize args, void *argp) {
- if (hooks[2] >= 0)
- taiHookReleaseForKernel(hooks[2], ksceIoReadRef);
-
- if (hooks[1] >= 0)
- taiHookReleaseForKernel(hooks[1], ksceIoOpenRef);
-
- if (hooks[0] >= 0)
- taiInjectReleaseForKernel(hooks[0]);
-
- return SCE_KERNEL_STOP_SUCCESS;
-}
+/*
+ VitaShell
+ Copyright (C) 2015-2018, TheFloW
+
+ 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, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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 for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+#include
+#include
+
+#include
+#include
+
+#include
+
+static tai_hook_ref_t ksceIoOpenRef;
+static tai_hook_ref_t ksceIoReadRef;
+
+static SceUID hooks[3];
+
+static int first = 1;
+
+static SceUID ksceIoOpenPatched(const char *file, int flags, SceMode mode) {
+ first = 1;
+
+ SceUID fd = TAI_CONTINUE(SceUID, ksceIoOpenRef, file, flags, mode);
+
+ if (fd == 0x800F090D)
+ return TAI_CONTINUE(SceUID, ksceIoOpenRef, file, flags & ~SCE_O_WRONLY, mode);
+
+ return fd;
+}
+
+static int ksceIoReadPatched(SceUID fd, void *data, SceSize size) {
+ int res = TAI_CONTINUE(int, ksceIoReadRef, fd, data, size);
+
+ if (first) {
+ first = 0;
+
+ // Manipulate boot sector to support exFAT
+ if (memcmp(data + 0x3, "EXFAT", 5) == 0) {
+ // Sector size
+ *(uint16_t *)(data + 0xB) = 1 << *(uint8_t *)(data + 0x6C);
+
+ // Volume size
+ *(uint32_t *)(data + 0x20) = *(uint32_t *)(data + 0x48);
+ }
+ }
+
+ return res;
+}
+
+void _start() __attribute__ ((weak, alias("module_start")));
+int module_start(SceSize args, void *argp) {
+ // Get tai module info
+ tai_module_info_t info;
+ info.size = sizeof(tai_module_info_t);
+ if (taiGetModuleInfoForKernel(KERNEL_PID, "SceUsbstorVStorDriver", &info) < 0)
+ return SCE_KERNEL_START_SUCCESS;
+
+ // Remove image path limitation
+ char zero[0x6E];
+ memset(zero, 0, 0x6E);
+ hooks[0] = taiInjectDataForKernel(KERNEL_PID, info.modid, 0, 0x1738, zero, 0x6E);
+
+ // Add patches to support exFAT
+ hooks[1] = taiHookFunctionImportForKernel(KERNEL_PID, &ksceIoOpenRef, "SceUsbstorVStorDriver", 0x40FD29C7, 0x75192972, ksceIoOpenPatched);
+ hooks[2] = taiHookFunctionImportForKernel(KERNEL_PID, &ksceIoReadRef, "SceUsbstorVStorDriver", 0x40FD29C7, 0xE17EFC03, ksceIoReadPatched);
+
+ return SCE_KERNEL_START_SUCCESS;
+}
+
+int module_stop(SceSize args, void *argp) {
+ if (hooks[2] >= 0)
+ taiHookReleaseForKernel(hooks[2], ksceIoReadRef);
+
+ if (hooks[1] >= 0)
+ taiHookReleaseForKernel(hooks[1], ksceIoOpenRef);
+
+ if (hooks[0] >= 0)
+ taiInjectReleaseForKernel(hooks[0]);
+
+ return SCE_KERNEL_STOP_SUCCESS;
+}
diff --git a/modules/user/CMakeLists.txt b/modules/user/CMakeLists.txt
index 8850da8..ed5c0be 100644
--- a/modules/user/CMakeLists.txt
+++ b/modules/user/CMakeLists.txt
@@ -1,43 +1,43 @@
-cmake_minimum_required(VERSION 2.8)
-
-if(NOT DEFINED CMAKE_TOOLCHAIN_FILE)
- if(DEFINED ENV{VITASDK})
- set(CMAKE_TOOLCHAIN_FILE "$ENV{VITASDK}/share/vita.toolchain.cmake" CACHE PATH "toolchain file")
- else()
- message(FATAL_ERROR "Please define VITASDK to point to your SDK path!")
- endif()
-endif()
-
-project(user)
-include("${VITASDK}/share/vita.cmake" REQUIRED)
-
-set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wl,-q -Wall -O3 -nostdlib")
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti -fno-exceptions")
-
-add_executable(user
- main.c
-)
-
-target_link_libraries(user
- SceLibKernel_stub
- SceIofilemgr_stub
- VitaShellKernel2_stub
-)
-
-vita_create_self(user.suprx user CONFIG exports.yml UNSAFE)
-
-vita_create_stubs(stubs user ${CMAKE_SOURCE_DIR}/exports.yml)
-
-install(DIRECTORY ${CMAKE_BINARY_DIR}/stubs/
- DESTINATION lib
- FILES_MATCHING PATTERN "*.a"
-)
-
-install(FILES vitashell_user.h
- DESTINATION include
-)
-
-add_custom_target(copy
- COMMAND cp user.suprx ../../../resources/user.suprx
- DEPENDS user.suprx
+cmake_minimum_required(VERSION 2.8)
+
+if(NOT DEFINED CMAKE_TOOLCHAIN_FILE)
+ if(DEFINED ENV{VITASDK})
+ set(CMAKE_TOOLCHAIN_FILE "$ENV{VITASDK}/share/vita.toolchain.cmake" CACHE PATH "toolchain file")
+ else()
+ message(FATAL_ERROR "Please define VITASDK to point to your SDK path!")
+ endif()
+endif()
+
+project(user)
+include("${VITASDK}/share/vita.cmake" REQUIRED)
+
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wl,-q -Wall -O3 -nostdlib")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti -fno-exceptions")
+
+add_executable(user
+ main.c
+)
+
+target_link_libraries(user
+ SceLibKernel_stub
+ SceIofilemgr_stub
+ VitaShellKernel2_stub
+)
+
+vita_create_self(user.suprx user CONFIG exports.yml UNSAFE)
+
+vita_create_stubs(stubs user ${CMAKE_SOURCE_DIR}/exports.yml)
+
+install(DIRECTORY ${CMAKE_BINARY_DIR}/stubs/
+ DESTINATION lib
+ FILES_MATCHING PATTERN "*.a"
+)
+
+install(FILES vitashell_user.h
+ DESTINATION include
+)
+
+add_custom_target(copy
+ COMMAND cp user.suprx ../../../resources/user.suprx
+ DEPENDS user.suprx
)
\ No newline at end of file
diff --git a/modules/user/exports.yml b/modules/user/exports.yml
index c13f82c..1a94a02 100644
--- a/modules/user/exports.yml
+++ b/modules/user/exports.yml
@@ -1,16 +1,16 @@
-VitaShellUser:
- attributes: 0
- version:
- major: 1
- minor: 0
- main:
- start: module_start
- stop: module_stop
- modules:
- VitaShellUserLibrary:
- syscall: false
- functions:
- - shellUserIsUx0Redirected
- - shellUserRedirectUx0
- - shellUserMountById
+VitaShellUser:
+ attributes: 0
+ version:
+ major: 1
+ minor: 0
+ main:
+ start: module_start
+ stop: module_stop
+ modules:
+ VitaShellUserLibrary:
+ syscall: false
+ functions:
+ - shellUserIsUx0Redirected
+ - shellUserRedirectUx0
+ - shellUserMountById
- shellUserGetRifVitaKey
\ No newline at end of file
diff --git a/modules/user/main.c b/modules/user/main.c
index 656620f..debc2e1 100644
--- a/modules/user/main.c
+++ b/modules/user/main.c
@@ -1,52 +1,52 @@
-/*
- VitaShell
- Copyright (C) 2015-2018, TheFloW
-
- 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, either version 3 of the License, or
- (at your option) any later version.
-
- 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 for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
-*/
-
-#include
-#include
-#include
-
-#include
-#include
-#include
-
-#include "vitashell_user.h"
-
-int shellUserIsUx0Redirected(const char *blkdev, const char *blkdev2) {
- return shellKernelIsUx0Redirected(blkdev, blkdev2);
-}
-
-int shellUserRedirectUx0(const char *blkdev, const char *blkdev2) {
- return shellKernelRedirectUx0(blkdev, blkdev2);
-}
-
-int shellUserMountById(ShellMountIdArgs *args) {
- return shellKernelMountById(args);
-}
-
-int shellUserGetRifVitaKey(const void *license_buf, void *klicensee) {
- return shellKernelGetRifVitaKey(license_buf, klicensee);
-}
-
-void _start() __attribute__ ((weak, alias("module_start")));
-int module_start(SceSize args, void *argp) {
- return SCE_KERNEL_START_SUCCESS;
-}
-
-int module_stop(SceSize args, void *argp) {
- return SCE_KERNEL_STOP_SUCCESS;
+/*
+ VitaShell
+ Copyright (C) 2015-2018, TheFloW
+
+ 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, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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 for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include "vitashell_user.h"
+
+int shellUserIsUx0Redirected(const char *blkdev, const char *blkdev2) {
+ return shellKernelIsUx0Redirected(blkdev, blkdev2);
+}
+
+int shellUserRedirectUx0(const char *blkdev, const char *blkdev2) {
+ return shellKernelRedirectUx0(blkdev, blkdev2);
+}
+
+int shellUserMountById(ShellMountIdArgs *args) {
+ return shellKernelMountById(args);
+}
+
+int shellUserGetRifVitaKey(const void *license_buf, void *klicensee) {
+ return shellKernelGetRifVitaKey(license_buf, klicensee);
+}
+
+void _start() __attribute__ ((weak, alias("module_start")));
+int module_start(SceSize args, void *argp) {
+ return SCE_KERNEL_START_SUCCESS;
+}
+
+int module_stop(SceSize args, void *argp) {
+ return SCE_KERNEL_STOP_SUCCESS;
}
\ No newline at end of file
diff --git a/network_download.c b/network_download.c
index 6e2d1d7..307e156 100644
--- a/network_download.c
+++ b/network_download.c
@@ -1,278 +1,278 @@
-/*
- VitaShell
- Copyright (C) 2015-2018, TheFloW
-
- 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, either version 3 of the License, or
- (at your option) any later version.
-
- 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 for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
-*/
-
-#include "main.h"
-#include "io_process.h"
-#include "network_download.h"
-#include "package_installer.h"
-#include "archive.h"
-#include "file.h"
-#include "message_dialog.h"
-#include "language.h"
-#include "utils.h"
-
-#define VITASHELL_USER_AGENT "VitaShell/1.00 libhttp/1.1"
-
-int getDownloadFileSize(const char *src, uint64_t *size) {
- int res;
- int statusCode;
- int tmplId = -1, connId = -1, reqId = -1;
-
- res = sceHttpCreateTemplate(VITASHELL_USER_AGENT, SCE_HTTP_VERSION_1_1, SCE_TRUE);
- if (res < 0)
- goto ERROR_EXIT;
-
- tmplId = res;
-
- res = sceHttpCreateConnectionWithURL(tmplId, src, SCE_TRUE);
- if (res < 0)
- goto ERROR_EXIT;
-
- connId = res;
-
- res = sceHttpCreateRequestWithURL(connId, SCE_HTTP_METHOD_GET, src, 0);
- if (res < 0)
- goto ERROR_EXIT;
-
- reqId = res;
-
- res = sceHttpSendRequest(reqId, NULL, 0);
- if (res < 0)
- goto ERROR_EXIT;
-
- res = sceHttpGetStatusCode(reqId, &statusCode);
- if (res < 0)
- goto ERROR_EXIT;
-
- if (statusCode == 200) {
- res = sceHttpGetResponseContentLength(reqId, size);
- }
-
-ERROR_EXIT:
- if (reqId >= 0)
- sceHttpDeleteRequest(reqId);
-
- if (connId >= 0)
- sceHttpDeleteConnection(connId);
-
- if (tmplId >= 0)
- sceHttpDeleteTemplate(tmplId);
-
- return res;
-}
-
-int getFieldFromHeader(const char *src, const char *field, const char **data, unsigned int *valueLen) {
- int res;
- char *header;
- unsigned int headerSize;
- int tmplId = -1, connId = -1, reqId = -1;
-
- res = sceHttpCreateTemplate(VITASHELL_USER_AGENT, SCE_HTTP_VERSION_1_1, SCE_TRUE);
- if (res < 0)
- goto ERROR_EXIT;
-
- tmplId = res;
-
- res = sceHttpCreateConnectionWithURL(tmplId, src, SCE_TRUE);
- if (res < 0)
- goto ERROR_EXIT;
-
- connId = res;
-
- res = sceHttpCreateRequestWithURL(connId, SCE_HTTP_METHOD_GET, src, 0);
- if (res < 0)
- goto ERROR_EXIT;
-
- reqId = res;
-
- res = sceHttpSendRequest(reqId, NULL, 0);
- if (res < 0)
- goto ERROR_EXIT;
-
- res = sceHttpGetAllResponseHeaders(reqId, &header, &headerSize);
- if (res < 0)
- goto ERROR_EXIT;
-
- res = sceHttpParseResponseHeader(header, headerSize, field, data, valueLen);
- if (res < 0) {
- *data = "";
- *valueLen = 0;
- res = 0;
- }
-
-ERROR_EXIT:
- if (reqId >= 0)
- sceHttpDeleteRequest(reqId);
-
- if (connId >= 0)
- sceHttpDeleteConnection(connId);
-
- if (tmplId >= 0)
- sceHttpDeleteTemplate(tmplId);
-
- return res;
-}
-
-int downloadFile(const char *src, const char *dst, FileProcessParam *param) {
- int res;
- int statusCode;
- int tmplId = -1, connId = -1, reqId = -1;
- SceUID fd = -1;
- int ret = 1;
-
- res = sceHttpCreateTemplate(VITASHELL_USER_AGENT, SCE_HTTP_VERSION_1_1, SCE_TRUE);
- if (res < 0)
- goto ERROR_EXIT;
-
- tmplId = res;
-
- res = sceHttpCreateConnectionWithURL(tmplId, src, SCE_TRUE);
- if (res < 0)
- goto ERROR_EXIT;
-
- connId = res;
-
- res = sceHttpCreateRequestWithURL(connId, SCE_HTTP_METHOD_GET, src, 0);
- if (res < 0)
- goto ERROR_EXIT;
-
- reqId = res;
-
- res = sceHttpSendRequest(reqId, NULL, 0);
- if (res < 0)
- goto ERROR_EXIT;
-
- res = sceHttpGetStatusCode(reqId, &statusCode);
- if (res < 0)
- goto ERROR_EXIT;
-
- if (statusCode == 200) {
- res = sceIoOpen(dst, SCE_O_WRONLY | SCE_O_CREAT | SCE_O_TRUNC, 0777);
- if (res < 0)
- goto ERROR_EXIT;
-
- fd = res;
-
- uint8_t buf[4096];
-
- while (1) {
- int read = sceHttpReadData(reqId, buf, sizeof(buf));
-
- if (read < 0) {
- res = read;
- break;
- }
-
- if (read == 0)
- break;
-
- int written = sceIoWrite(fd, buf, read);
-
- if (written < 0) {
- res = written;
- break;
- }
-
- if (param) {
- if (param->value)
- (*param->value) += read;
-
- if (param->SetProgress)
- param->SetProgress(param->value ? *param->value : 0, param->max);
-
- if (param->cancelHandler && param->cancelHandler()) {
- ret = 0;
- break;
- }
- }
- }
- }
-
-ERROR_EXIT:
- if (fd >= 0)
- sceIoClose(fd);
-
- if (reqId >= 0)
- sceHttpDeleteRequest(reqId);
-
- if (connId >= 0)
- sceHttpDeleteConnection(connId);
-
- if (tmplId >= 0)
- sceHttpDeleteTemplate(tmplId);
-
- if (res < 0)
- return res;
-
- return ret;
-}
-
-int downloadFileProcess(const char *url, const char *dest, int successStep) {
- SceUID thid = -1;
-
- // Lock power timers
- powerLock();
-
- // Set progress to 0%
- sceMsgDialogProgressBarSetValue(SCE_MSG_DIALOG_PROGRESSBAR_TARGET_BAR_DEFAULT, 0);
- sceKernelDelayThread(DIALOG_WAIT); // Needed to see the percentage
-
- // File size
- uint64_t size = 0;
- getDownloadFileSize(url, &size);
-
- // Update thread
- thid = createStartUpdateThread(size, 1);
-
- // Download
- uint64_t value = 0;
-
- FileProcessParam param;
- param.value = &value;
- param.max = size;
- param.SetProgress = SetProgress;
- param.cancelHandler = cancelHandler;
-
- int res = downloadFile(url, dest, ¶m);
- if (res <= 0) {
- sceIoRemove(dest);
- closeWaitDialog();
- setDialogStep(DIALOG_STEP_CANCELED);
- errorDialog(res);
- goto EXIT;
- }
-
- // Set progress to 100%
- sceMsgDialogProgressBarSetValue(SCE_MSG_DIALOG_PROGRESSBAR_TARGET_BAR_DEFAULT, 100);
- sceKernelDelayThread(COUNTUP_WAIT);
-
- // Close
- if (successStep != 0) {
- sceMsgDialogClose();
- setDialogStep(successStep);
- }
-
-EXIT:
- if (thid >= 0)
- sceKernelWaitThreadEnd(thid, NULL, NULL);
-
- // Unlock power timers
- powerUnlock();
-
- return sceKernelExitDeleteThread(0);
+/*
+ VitaShell
+ Copyright (C) 2015-2018, TheFloW
+
+ 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, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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 for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+#include "main.h"
+#include "io_process.h"
+#include "network_download.h"
+#include "package_installer.h"
+#include "archive.h"
+#include "file.h"
+#include "message_dialog.h"
+#include "language.h"
+#include "utils.h"
+
+#define VITASHELL_USER_AGENT "VitaShell/1.00 libhttp/1.1"
+
+int getDownloadFileSize(const char *src, uint64_t *size) {
+ int res;
+ int statusCode;
+ int tmplId = -1, connId = -1, reqId = -1;
+
+ res = sceHttpCreateTemplate(VITASHELL_USER_AGENT, SCE_HTTP_VERSION_1_1, SCE_TRUE);
+ if (res < 0)
+ goto ERROR_EXIT;
+
+ tmplId = res;
+
+ res = sceHttpCreateConnectionWithURL(tmplId, src, SCE_TRUE);
+ if (res < 0)
+ goto ERROR_EXIT;
+
+ connId = res;
+
+ res = sceHttpCreateRequestWithURL(connId, SCE_HTTP_METHOD_GET, src, 0);
+ if (res < 0)
+ goto ERROR_EXIT;
+
+ reqId = res;
+
+ res = sceHttpSendRequest(reqId, NULL, 0);
+ if (res < 0)
+ goto ERROR_EXIT;
+
+ res = sceHttpGetStatusCode(reqId, &statusCode);
+ if (res < 0)
+ goto ERROR_EXIT;
+
+ if (statusCode == 200) {
+ res = sceHttpGetResponseContentLength(reqId, size);
+ }
+
+ERROR_EXIT:
+ if (reqId >= 0)
+ sceHttpDeleteRequest(reqId);
+
+ if (connId >= 0)
+ sceHttpDeleteConnection(connId);
+
+ if (tmplId >= 0)
+ sceHttpDeleteTemplate(tmplId);
+
+ return res;
+}
+
+int getFieldFromHeader(const char *src, const char *field, const char **data, unsigned int *valueLen) {
+ int res;
+ char *header;
+ unsigned int headerSize;
+ int tmplId = -1, connId = -1, reqId = -1;
+
+ res = sceHttpCreateTemplate(VITASHELL_USER_AGENT, SCE_HTTP_VERSION_1_1, SCE_TRUE);
+ if (res < 0)
+ goto ERROR_EXIT;
+
+ tmplId = res;
+
+ res = sceHttpCreateConnectionWithURL(tmplId, src, SCE_TRUE);
+ if (res < 0)
+ goto ERROR_EXIT;
+
+ connId = res;
+
+ res = sceHttpCreateRequestWithURL(connId, SCE_HTTP_METHOD_GET, src, 0);
+ if (res < 0)
+ goto ERROR_EXIT;
+
+ reqId = res;
+
+ res = sceHttpSendRequest(reqId, NULL, 0);
+ if (res < 0)
+ goto ERROR_EXIT;
+
+ res = sceHttpGetAllResponseHeaders(reqId, &header, &headerSize);
+ if (res < 0)
+ goto ERROR_EXIT;
+
+ res = sceHttpParseResponseHeader(header, headerSize, field, data, valueLen);
+ if (res < 0) {
+ *data = "";
+ *valueLen = 0;
+ res = 0;
+ }
+
+ERROR_EXIT:
+ if (reqId >= 0)
+ sceHttpDeleteRequest(reqId);
+
+ if (connId >= 0)
+ sceHttpDeleteConnection(connId);
+
+ if (tmplId >= 0)
+ sceHttpDeleteTemplate(tmplId);
+
+ return res;
+}
+
+int downloadFile(const char *src, const char *dst, FileProcessParam *param) {
+ int res;
+ int statusCode;
+ int tmplId = -1, connId = -1, reqId = -1;
+ SceUID fd = -1;
+ int ret = 1;
+
+ res = sceHttpCreateTemplate(VITASHELL_USER_AGENT, SCE_HTTP_VERSION_1_1, SCE_TRUE);
+ if (res < 0)
+ goto ERROR_EXIT;
+
+ tmplId = res;
+
+ res = sceHttpCreateConnectionWithURL(tmplId, src, SCE_TRUE);
+ if (res < 0)
+ goto ERROR_EXIT;
+
+ connId = res;
+
+ res = sceHttpCreateRequestWithURL(connId, SCE_HTTP_METHOD_GET, src, 0);
+ if (res < 0)
+ goto ERROR_EXIT;
+
+ reqId = res;
+
+ res = sceHttpSendRequest(reqId, NULL, 0);
+ if (res < 0)
+ goto ERROR_EXIT;
+
+ res = sceHttpGetStatusCode(reqId, &statusCode);
+ if (res < 0)
+ goto ERROR_EXIT;
+
+ if (statusCode == 200) {
+ res = sceIoOpen(dst, SCE_O_WRONLY | SCE_O_CREAT | SCE_O_TRUNC, 0777);
+ if (res < 0)
+ goto ERROR_EXIT;
+
+ fd = res;
+
+ uint8_t buf[4096];
+
+ while (1) {
+ int read = sceHttpReadData(reqId, buf, sizeof(buf));
+
+ if (read < 0) {
+ res = read;
+ break;
+ }
+
+ if (read == 0)
+ break;
+
+ int written = sceIoWrite(fd, buf, read);
+
+ if (written < 0) {
+ res = written;
+ break;
+ }
+
+ if (param) {
+ if (param->value)
+ (*param->value) += read;
+
+ if (param->SetProgress)
+ param->SetProgress(param->value ? *param->value : 0, param->max);
+
+ if (param->cancelHandler && param->cancelHandler()) {
+ ret = 0;
+ break;
+ }
+ }
+ }
+ }
+
+ERROR_EXIT:
+ if (fd >= 0)
+ sceIoClose(fd);
+
+ if (reqId >= 0)
+ sceHttpDeleteRequest(reqId);
+
+ if (connId >= 0)
+ sceHttpDeleteConnection(connId);
+
+ if (tmplId >= 0)
+ sceHttpDeleteTemplate(tmplId);
+
+ if (res < 0)
+ return res;
+
+ return ret;
+}
+
+int downloadFileProcess(const char *url, const char *dest, int successStep) {
+ SceUID thid = -1;
+
+ // Lock power timers
+ powerLock();
+
+ // Set progress to 0%
+ sceMsgDialogProgressBarSetValue(SCE_MSG_DIALOG_PROGRESSBAR_TARGET_BAR_DEFAULT, 0);
+ sceKernelDelayThread(DIALOG_WAIT); // Needed to see the percentage
+
+ // File size
+ uint64_t size = 0;
+ getDownloadFileSize(url, &size);
+
+ // Update thread
+ thid = createStartUpdateThread(size, 1);
+
+ // Download
+ uint64_t value = 0;
+
+ FileProcessParam param;
+ param.value = &value;
+ param.max = size;
+ param.SetProgress = SetProgress;
+ param.cancelHandler = cancelHandler;
+
+ int res = downloadFile(url, dest, ¶m);
+ if (res <= 0) {
+ sceIoRemove(dest);
+ closeWaitDialog();
+ setDialogStep(DIALOG_STEP_CANCELED);
+ errorDialog(res);
+ goto EXIT;
+ }
+
+ // Set progress to 100%
+ sceMsgDialogProgressBarSetValue(SCE_MSG_DIALOG_PROGRESSBAR_TARGET_BAR_DEFAULT, 100);
+ sceKernelDelayThread(COUNTUP_WAIT);
+
+ // Close
+ if (successStep != 0) {
+ sceMsgDialogClose();
+ setDialogStep(successStep);
+ }
+
+EXIT:
+ if (thid >= 0)
+ sceKernelWaitThreadEnd(thid, NULL, NULL);
+
+ // Unlock power timers
+ powerUnlock();
+
+ return sceKernelExitDeleteThread(0);
}
\ No newline at end of file
diff --git a/network_download.h b/network_download.h
index 9961202..d058e4e 100644
--- a/network_download.h
+++ b/network_download.h
@@ -1,33 +1,33 @@
-/*
- VitaShell
- Copyright (C) 2015-2018, TheFloW
-
- 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, either version 3 of the License, or
- (at your option) any later version.
-
- 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 for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
-*/
-
-/*
- * network_download
- * same as network_update.h // network_update.c
- * just modified to download any file from url, destination and successStep (0 for no step)
- */
-
-#ifndef __NETWORK_DOWNLOAD_H__
-#define __NETWORK_DOWNLOAD_H__
-
-int getDownloadFileSize(const char *src, uint64_t *size);
-int getFieldFromHeader(const char *src, const char *field, const char **data, unsigned int *valueLen);
-int downloadFile(const char *src, const char *dst, FileProcessParam *param);
-int downloadFileProcess(const char *url, const char *dest, int successStep);
-
+/*
+ VitaShell
+ Copyright (C) 2015-2018, TheFloW
+
+ 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, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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 for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+/*
+ * network_download
+ * same as network_update.h // network_update.c
+ * just modified to download any file from url, destination and successStep (0 for no step)
+ */
+
+#ifndef __NETWORK_DOWNLOAD_H__
+#define __NETWORK_DOWNLOAD_H__
+
+int getDownloadFileSize(const char *src, uint64_t *size);
+int getFieldFromHeader(const char *src, const char *field, const char **data, unsigned int *valueLen);
+int downloadFile(const char *src, const char *dst, FileProcessParam *param);
+int downloadFileProcess(const char *url, const char *dest, int successStep);
+
#endif
\ No newline at end of file
diff --git a/psarc.c b/psarc.c
index 701fc38..fcffe61 100644
--- a/psarc.c
+++ b/psarc.c
@@ -1,531 +1,531 @@
-/*
- VitaShell
- Copyright (C) 2015-2018, TheFloW
-
- 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, either version 3 of the License, or
- (at your option) any later version.
-
- 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 for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
-*/
-
-#include "main.h"
-#include "psarc.h"
-#include "file.h"
-#include "utils.h"
-
-#define SCE_FIOS_FH_SIZE 80
-#define SCE_FIOS_DH_SIZE 80
-#define SCE_FIOS_OP_SIZE 168
-#define SCE_FIOS_CHUNK_SIZE 64
-
-#define SCE_FIOS_ALIGN_UP(val, align) (((val) + ((align) - 1)) & ~((align) - 1))
-#define SCE_FIOS_STORAGE_SIZE(num, size) (((num) * (size)) + SCE_FIOS_ALIGN_UP(SCE_FIOS_ALIGN_UP((num), 8) / 8, 8))
-
-#define SCE_FIOS_DH_STORAGE_SIZE(numDHs, pathMax) SCE_FIOS_STORAGE_SIZE(numDHs, SCE_FIOS_DH_SIZE + pathMax)
-#define SCE_FIOS_FH_STORAGE_SIZE(numFHs, pathMax) SCE_FIOS_STORAGE_SIZE(numFHs, SCE_FIOS_FH_SIZE + pathMax)
-#define SCE_FIOS_OP_STORAGE_SIZE(numOps, pathMax) SCE_FIOS_STORAGE_SIZE(numOps, SCE_FIOS_OP_SIZE + pathMax)
-#define SCE_FIOS_CHUNK_STORAGE_SIZE(numChunks) SCE_FIOS_STORAGE_SIZE(numChunks, SCE_FIOS_CHUNK_SIZE)
-
-#define SCE_FIOS_BUFFER_INITIALIZER { 0, 0 }
-#define SCE_FIOS_PSARC_DEARCHIVER_CONTEXT_INITIALIZER { sizeof(SceFiosPsarcDearchiverContext), 0, 0, 0, {0, 0, 0} }
-#define SCE_FIOS_PARAMS_INITIALIZER { 0, sizeof(SceFiosParams), 0, 0, 2, 1, 0, 0, 256 * 1024, 2, 0, 0, 0, 0, 0, SCE_FIOS_BUFFER_INITIALIZER, SCE_FIOS_BUFFER_INITIALIZER, SCE_FIOS_BUFFER_INITIALIZER, SCE_FIOS_BUFFER_INITIALIZER, NULL, NULL, NULL, { 66, 189, 66 }, { 0x40000, 0, 0x40000}, { 8 * 1024, 16 * 1024, 8 * 1024}}
-
-typedef int32_t SceFiosFH;
-typedef int32_t SceFiosDH;
-typedef uint64_t SceFiosDate;
-typedef int64_t SceFiosOffset;
-typedef int64_t SceFiosSize;
-
-typedef struct SceFiosPsarcDearchiverContext {
- size_t sizeOfContext;
- size_t workBufferSize;
- void *pWorkBuffer;
- intptr_t flags;
- intptr_t reserved[3];
-} SceFiosPsarcDearchiverContext;
-
-typedef struct SceFiosBuffer {
- void *pPtr;
- size_t length;
-} SceFiosBuffer;
-
-typedef struct SceFiosParams {
- uint32_t initialized : 1;
- uint32_t paramsSize : 15;
- uint32_t pathMax : 16;
- uint32_t profiling;
- uint32_t ioThreadCount;
- uint32_t threadsPerScheduler;
- uint32_t extraFlag1 : 1;
- uint32_t extraFlags : 31;
- uint32_t maxChunk;
- uint8_t maxDecompressorThreadCount;
- uint8_t reserved1;
- uint8_t reserved2;
- uint8_t reserved3;
- intptr_t reserved4;
- intptr_t reserved5;
- SceFiosBuffer opStorage;
- SceFiosBuffer fhStorage;
- SceFiosBuffer dhStorage;
- SceFiosBuffer chunkStorage;
- void *pVprintf;
- void *pMemcpy;
- void *pProfileCallback;
- int threadPriority[3];
- int threadAffinity[3];
- int threadStackSize[3];
-} SceFiosParams;
-
-typedef struct SceFiosDirEntry {
- SceFiosOffset fileSize;
- uint32_t statFlags;
- uint16_t nameLength;
- uint16_t fullPathLength;
- uint16_t offsetToName;
- uint16_t reserved[3];
- char fullPath[1024];
-} SceFiosDirEntry;
-
-typedef struct SceFiosStat {
- SceFiosOffset fileSize;
- SceFiosDate accessDate;
- SceFiosDate modificationDate;
- SceFiosDate creationDate;
- uint32_t statFlags;
- uint32_t reserved;
- int64_t uid;
- int64_t gid;
- int64_t dev;
- int64_t ino;
- int64_t mode;
-} SceFiosStat;
-
-int sceFiosInitialize(const SceFiosParams *params);
-void sceFiosTerminate();
-
-SceFiosSize sceFiosArchiveGetMountBufferSizeSync(const void *attr, const char *path, void *params);
-int sceFiosArchiveMountSync(const void *attr, SceFiosFH *fh, const char *path, const char *mount_point, SceFiosBuffer mount_buffer, void *params);
-int sceFiosArchiveUnmountSync(const void *attr, SceFiosFH fh);
-
-int sceFiosStatSync(const void *attr, const char *path, SceFiosStat *stat);
-
-int sceFiosFHOpenSync(const void *attr, SceFiosFH *fh, const char *path, const void *params);
-SceFiosSize sceFiosFHReadSync(const void *attr, SceFiosFH fh, void *data, SceFiosSize size);
-int sceFiosFHCloseSync(const void *attr, SceFiosFH fh);
-
-int sceFiosDHOpenSync(const void *attr, SceFiosDH *dh, const char *path, SceFiosBuffer buf);
-int sceFiosDHReadSync(const void *attr, SceFiosDH dh, SceFiosDirEntry *dir);
-int sceFiosDHCloseSync(const void *attr, SceFiosDH dh);
-
-SceDateTime *sceFiosDateToSceDateTime(SceFiosDate date, SceDateTime *sce_date);
-
-int sceFiosIOFilterAdd(int index, void (* callback)(), void *context);
-int sceFiosIOFilterRemove(int index);
-
-void sceFiosIOFilterPsarcDearchiver();
-
-int64_t g_OpStorage[SCE_FIOS_OP_STORAGE_SIZE(64, MAX_PATH_LENGTH) / sizeof(int64_t) + 1];
-int64_t g_ChunkStorage[SCE_FIOS_CHUNK_STORAGE_SIZE(1024) / sizeof(int64_t) + 1];
-int64_t g_FHStorage[SCE_FIOS_FH_STORAGE_SIZE(32, MAX_PATH_LENGTH) / sizeof(int64_t) + 1];
-int64_t g_DHStorage[SCE_FIOS_DH_STORAGE_SIZE(32, MAX_PATH_LENGTH) / sizeof(int64_t) + 1];
-
-SceFiosPsarcDearchiverContext g_DearchiverContext = SCE_FIOS_PSARC_DEARCHIVER_CONTEXT_INITIALIZER;
-char g_DearchiverWorkBuffer[0x30000] __attribute__((aligned(64)));
-int g_ArchiveIndex = 0;
-SceFiosBuffer g_MountBuffer = SCE_FIOS_BUFFER_INITIALIZER;
-SceFiosFH g_ArchiveFH = -1;
-
-int psarcOpen(const char *file) {
- int res;
-
- SceFiosParams params = SCE_FIOS_PARAMS_INITIALIZER;
- params.opStorage.pPtr = g_OpStorage;
- params.opStorage.length = sizeof(g_OpStorage);
- params.chunkStorage.pPtr = g_ChunkStorage;
- params.chunkStorage.length = sizeof(g_ChunkStorage);
- params.fhStorage.pPtr = g_FHStorage;
- params.fhStorage.length = sizeof(g_FHStorage);
- params.dhStorage.pPtr = g_DHStorage;
- params.dhStorage.length = sizeof(g_DHStorage);
- params.pathMax = MAX_PATH_LENGTH;
-
- res = sceFiosInitialize(¶ms);
- if (res < 0)
- goto ERROR_INITIALIZE;
-
- g_DearchiverContext.workBufferSize = sizeof(g_DearchiverWorkBuffer);
- g_DearchiverContext.pWorkBuffer = g_DearchiverWorkBuffer;
-
- res = sceFiosIOFilterAdd(g_ArchiveIndex, sceFiosIOFilterPsarcDearchiver, &g_DearchiverContext);
- if (res < 0)
- goto ERROR_FILTER_ADD;
-
- SceFiosSize result = sceFiosArchiveGetMountBufferSizeSync(NULL, file, NULL);
- if (result < 0) {
- res = (int)result;
- goto ERROR_ARCHIVE_GET_MOUNT_BUFFER_SIZE;
- }
-
- g_MountBuffer.length = (size_t)result;
- g_MountBuffer.pPtr = malloc(g_MountBuffer.length);
-
- res = sceFiosArchiveMountSync(NULL, &g_ArchiveFH, file, file, g_MountBuffer, NULL);
- if (res < 0)
- goto ERROR_ARCHIVE_MOUNT;
-
- return res;
-
-ERROR_ARCHIVE_MOUNT:
- free(g_MountBuffer.pPtr);
-
-ERROR_ARCHIVE_GET_MOUNT_BUFFER_SIZE:
- sceFiosIOFilterRemove(g_ArchiveIndex);
-
-ERROR_FILTER_ADD:
- sceFiosTerminate();
-
-ERROR_INITIALIZE:
- return res;
-}
-
-int psarcClose() {
- sceFiosArchiveUnmountSync(NULL, g_ArchiveFH);
- free(g_MountBuffer.pPtr);
- sceFiosIOFilterRemove(g_ArchiveIndex);
- sceFiosTerminate();
-
- return 0;
-}
-
-int fileListGetPsarcEntries(FileList *list, const char *path, int sort) {
- int res;
-
- if (!list)
- return VITASHELL_ERROR_ILLEGAL_ADDR;
-
- SceFiosDH dh = -1;
- SceFiosBuffer buf = SCE_FIOS_BUFFER_INITIALIZER;
- res = sceFiosDHOpenSync(NULL, &dh, path, buf);
- if (res < 0)
- return res;
-
- FileListEntry *entry = malloc(sizeof(FileListEntry));
- if (entry) {
- entry->name_length = strlen(DIR_UP);
- entry->name = malloc(entry->name_length + 1);
- strcpy(entry->name, DIR_UP);
- entry->is_folder = 1;
- entry->type = FILE_TYPE_UNKNOWN;
- fileListAddEntry(list, entry, sort);
- }
-
- do {
- SceFiosDirEntry dir;
- memset(&dir, 0, sizeof(SceFiosDirEntry));
-
- res = sceFiosDHReadSync(NULL, dh, &dir);
-
- if (res >= 0) {
- char *name = dir.fullPath + dir.offsetToName;
-
- SceFiosStat stat;
- memset(&stat, 0, sizeof(SceFiosStat));
-
- if (sceFiosStatSync(NULL, dir.fullPath, &stat) >= 0) {
- FileListEntry *entry = malloc(sizeof(FileListEntry));
- if (entry) {
- entry->is_folder = stat.statFlags & 0x1;
- if (entry->is_folder) {
- entry->name_length = strlen(name) + 1;
- entry->name = malloc(entry->name_length + 1);
- strcpy(entry->name, name);
- addEndSlash(entry->name);
- entry->type = FILE_TYPE_UNKNOWN;
- list->folders++;
- } else {
- entry->name_length = strlen(name);
- entry->name = malloc(entry->name_length + 1);
- strcpy(entry->name, name);
- entry->type = getFileType(entry->name);
- list->files++;
- }
-
- entry->size = stat.fileSize;
-
- SceDateTime time;
-
- sceFiosDateToSceDateTime(stat.accessDate, &time);
- memcpy(&entry->ctime, (SceDateTime *)&time, sizeof(SceDateTime));
-
- sceFiosDateToSceDateTime(stat.modificationDate, &time);
- memcpy(&entry->mtime, (SceDateTime *)&time, sizeof(SceDateTime));
-
- sceFiosDateToSceDateTime(stat.creationDate, &time);
- memcpy(&entry->atime, (SceDateTime *)&time, sizeof(SceDateTime));
-
- fileListAddEntry(list, entry, sort);
- }
- }
- }
- } while (res >= 0);
-
- sceFiosDHCloseSync(NULL, dh);
-
- return 0;
-}
-
-int getPsarcPathInfo(const char *path, uint64_t *size, uint32_t *folders, uint32_t *files, int (* handler)(const char *path)) {
- SceFiosDH dh = -1;
- SceFiosBuffer buf = SCE_FIOS_BUFFER_INITIALIZER;
- if (sceFiosDHOpenSync(NULL, &dh, path, buf) >= 0) {
- int res = 0;
-
- do {
- SceFiosDirEntry dir;
- memset(&dir, 0, sizeof(SceFiosDirEntry));
-
- res = sceFiosDHReadSync(NULL, dh, &dir);
- if (res >= 0) {
- char *name = dir.fullPath + dir.offsetToName;
-
- char *new_path = malloc(strlen(path) + strlen(name) + 2);
- snprintf(new_path, MAX_PATH_LENGTH - 1, "%s%s%s", path, hasEndSlash(path) ? "" : "/", name);
-
- if (handler && handler(new_path)) {
- free(new_path);
- continue;
- }
-
- if (dir.statFlags & 0x1) {
- int ret = getPsarcPathInfo(new_path, size, folders, files, handler);
- if (ret <= 0) {
- free(new_path);
- sceFiosDHCloseSync(NULL, dh);
- return ret;
- }
- } else {
- if (size)
- (*size) += dir.fileSize;
-
- if (files)
- (*files)++;
- }
-
- free(new_path);
- }
- } while (res >= 0);
-
- sceFiosDHCloseSync(NULL, dh);
-
- if (folders)
- (*folders)++;
- } else {
- if (handler && handler(path))
- return 1;
-
- if (size) {
- SceFiosStat stat;
- memset(&stat, 0, sizeof(SceFiosStat));
-
- int res = sceFiosStatSync(NULL, path, &stat);
- if (res < 0)
- return res;
-
- (*size) += stat.fileSize;
- }
-
- if (files)
- (*files)++;
- }
-
- return 1;
-}
-
-int extractPsarcFile(const char *src_path, const char *dst_path, FileProcessParam *param) {
- SceUID fdsrc = psarcFileOpen(src_path, SCE_O_RDONLY, 0);
- if (fdsrc < 0)
- return fdsrc;
-
- SceUID fddst = sceIoOpen(dst_path, SCE_O_WRONLY | SCE_O_CREAT | SCE_O_TRUNC, 0777);
- if (fddst < 0) {
- psarcFileClose(fdsrc);
- return fddst;
- }
-
- void *buf = memalign(4096, TRANSFER_SIZE);
-
- while (1) {
- int read = psarcFileRead(fdsrc, buf, TRANSFER_SIZE);
-
- if (read < 0) {
- free(buf);
-
- sceIoClose(fddst);
- psarcFileClose(fdsrc);
-
- sceIoRemove(dst_path);
-
- return read;
- }
-
- if (read == 0)
- break;
-
- int written = sceIoWrite(fddst, buf, read);
-
- if (written < 0) {
- free(buf);
-
- sceIoClose(fddst);
- psarcFileClose(fdsrc);
-
- sceIoRemove(dst_path);
-
- return written;
- }
-
- if (param) {
- if (param->value)
- (*param->value) += read;
-
- if (param->SetProgress)
- param->SetProgress(param->value ? *param->value : 0, param->max);
-
- if (param->cancelHandler && param->cancelHandler()) {
- free(buf);
-
- sceIoClose(fddst);
- psarcFileClose(fdsrc);
-
- sceIoRemove(dst_path);
-
- return 0;
- }
- }
- }
-
- free(buf);
-
- sceIoClose(fddst);
- psarcFileClose(fdsrc);
-
- return 1;
-}
-
-int extractPsarcPath(const char *src_path, const char *dst_path, FileProcessParam *param) {
- SceFiosDH dh = -1;
- SceFiosBuffer buf = SCE_FIOS_BUFFER_INITIALIZER;
- if (sceFiosDHOpenSync(NULL, &dh, src_path, buf) >= 0) {
- int ret = sceIoMkdir(dst_path, 0777);
- if (ret < 0 && ret != SCE_ERROR_ERRNO_EEXIST) {
- sceFiosDHCloseSync(NULL, dh);
- return ret;
- }
-
- if (param) {
- if (param->value)
- (*param->value) += DIRECTORY_SIZE;
-
- if (param->SetProgress)
- param->SetProgress(param->value ? *param->value : 0, param->max);
-
- if (param->cancelHandler && param->cancelHandler()) {
- sceFiosDHCloseSync(NULL, dh);
- return 0;
- }
- }
-
- int res = 0;
-
- do {
- SceFiosDirEntry dir;
- memset(&dir, 0, sizeof(SceFiosDirEntry));
-
- res = sceFiosDHReadSync(NULL, dh, &dir);
- if (res >= 0) {
- char *name = dir.fullPath + dir.offsetToName;
-
- char *new_src_path = malloc(strlen(src_path) + strlen(name) + 2);
- snprintf(new_src_path, MAX_PATH_LENGTH - 1, "%s%s%s", src_path, hasEndSlash(src_path) ? "" : "/", name);
-
- char *new_dst_path = malloc(strlen(dst_path) + strlen(name) + 2);
- snprintf(new_dst_path, MAX_PATH_LENGTH - 1, "%s%s%s", dst_path, hasEndSlash(dst_path) ? "" : "/", name);
-
- int ret = 0;
-
- if (dir.statFlags & 0x1) {
- ret = extractPsarcPath(new_src_path, new_dst_path, param);
- } else {
- ret = extractPsarcFile(new_src_path, new_dst_path, param);
- }
-
- free(new_dst_path);
- free(new_src_path);
-
- if (ret <= 0) {
- sceFiosDHCloseSync(NULL, dh);
- return ret;
- }
- }
- } while (res >= 0);
-
- sceFiosDHCloseSync(NULL, dh);
- } else {
- return extractPsarcFile(src_path, dst_path, param);
- }
-
- return 1;
-}
-
-int psarcFileGetstat(const char *file, SceIoStat *stat) {
- SceFiosStat fios_stat;
- memset(&fios_stat, 0, sizeof(SceFiosStat));
- int res = sceFiosStatSync(NULL, file, &fios_stat);
- if (res < 0)
- return res;
-
- if (stat) {
- stat->st_mode = (fios_stat.statFlags & 0x1) ? SCE_S_IFDIR : SCE_S_IFREG;
- stat->st_size = fios_stat.fileSize;
-
- SceDateTime time;
-
- sceFiosDateToSceDateTime(fios_stat.accessDate, &time);
- memcpy(&stat->st_ctime, (SceDateTime *)&time, sizeof(SceDateTime));
-
- sceFiosDateToSceDateTime(fios_stat.modificationDate, &time);
- memcpy(&stat->st_mtime, (SceDateTime *)&time, sizeof(SceDateTime));
-
- sceFiosDateToSceDateTime(fios_stat.creationDate, &time);
- memcpy(&stat->st_atime, (SceDateTime *)&time, sizeof(SceDateTime));
- }
-
- return res;
-}
-
-int psarcFileOpen(const char *file, int flags, SceMode mode) {
- SceFiosFH fh = -1;
-
- int res = sceFiosFHOpenSync(NULL, &fh, file, NULL);
- if (res < 0)
- return res;
-
- return fh;
-}
-
-int psarcFileRead(SceUID fd, void *data, SceSize size) {
- return (int)sceFiosFHReadSync(NULL, fd, data, (SceFiosSize)size);
-}
-
-int psarcFileClose(SceUID fd) {
- return sceFiosFHCloseSync(NULL, fd);
+/*
+ VitaShell
+ Copyright (C) 2015-2018, TheFloW
+
+ 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, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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 for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+#include "main.h"
+#include "psarc.h"
+#include "file.h"
+#include "utils.h"
+
+#define SCE_FIOS_FH_SIZE 80
+#define SCE_FIOS_DH_SIZE 80
+#define SCE_FIOS_OP_SIZE 168
+#define SCE_FIOS_CHUNK_SIZE 64
+
+#define SCE_FIOS_ALIGN_UP(val, align) (((val) + ((align) - 1)) & ~((align) - 1))
+#define SCE_FIOS_STORAGE_SIZE(num, size) (((num) * (size)) + SCE_FIOS_ALIGN_UP(SCE_FIOS_ALIGN_UP((num), 8) / 8, 8))
+
+#define SCE_FIOS_DH_STORAGE_SIZE(numDHs, pathMax) SCE_FIOS_STORAGE_SIZE(numDHs, SCE_FIOS_DH_SIZE + pathMax)
+#define SCE_FIOS_FH_STORAGE_SIZE(numFHs, pathMax) SCE_FIOS_STORAGE_SIZE(numFHs, SCE_FIOS_FH_SIZE + pathMax)
+#define SCE_FIOS_OP_STORAGE_SIZE(numOps, pathMax) SCE_FIOS_STORAGE_SIZE(numOps, SCE_FIOS_OP_SIZE + pathMax)
+#define SCE_FIOS_CHUNK_STORAGE_SIZE(numChunks) SCE_FIOS_STORAGE_SIZE(numChunks, SCE_FIOS_CHUNK_SIZE)
+
+#define SCE_FIOS_BUFFER_INITIALIZER { 0, 0 }
+#define SCE_FIOS_PSARC_DEARCHIVER_CONTEXT_INITIALIZER { sizeof(SceFiosPsarcDearchiverContext), 0, 0, 0, {0, 0, 0} }
+#define SCE_FIOS_PARAMS_INITIALIZER { 0, sizeof(SceFiosParams), 0, 0, 2, 1, 0, 0, 256 * 1024, 2, 0, 0, 0, 0, 0, SCE_FIOS_BUFFER_INITIALIZER, SCE_FIOS_BUFFER_INITIALIZER, SCE_FIOS_BUFFER_INITIALIZER, SCE_FIOS_BUFFER_INITIALIZER, NULL, NULL, NULL, { 66, 189, 66 }, { 0x40000, 0, 0x40000}, { 8 * 1024, 16 * 1024, 8 * 1024}}
+
+typedef int32_t SceFiosFH;
+typedef int32_t SceFiosDH;
+typedef uint64_t SceFiosDate;
+typedef int64_t SceFiosOffset;
+typedef int64_t SceFiosSize;
+
+typedef struct SceFiosPsarcDearchiverContext {
+ size_t sizeOfContext;
+ size_t workBufferSize;
+ void *pWorkBuffer;
+ intptr_t flags;
+ intptr_t reserved[3];
+} SceFiosPsarcDearchiverContext;
+
+typedef struct SceFiosBuffer {
+ void *pPtr;
+ size_t length;
+} SceFiosBuffer;
+
+typedef struct SceFiosParams {
+ uint32_t initialized : 1;
+ uint32_t paramsSize : 15;
+ uint32_t pathMax : 16;
+ uint32_t profiling;
+ uint32_t ioThreadCount;
+ uint32_t threadsPerScheduler;
+ uint32_t extraFlag1 : 1;
+ uint32_t extraFlags : 31;
+ uint32_t maxChunk;
+ uint8_t maxDecompressorThreadCount;
+ uint8_t reserved1;
+ uint8_t reserved2;
+ uint8_t reserved3;
+ intptr_t reserved4;
+ intptr_t reserved5;
+ SceFiosBuffer opStorage;
+ SceFiosBuffer fhStorage;
+ SceFiosBuffer dhStorage;
+ SceFiosBuffer chunkStorage;
+ void *pVprintf;
+ void *pMemcpy;
+ void *pProfileCallback;
+ int threadPriority[3];
+ int threadAffinity[3];
+ int threadStackSize[3];
+} SceFiosParams;
+
+typedef struct SceFiosDirEntry {
+ SceFiosOffset fileSize;
+ uint32_t statFlags;
+ uint16_t nameLength;
+ uint16_t fullPathLength;
+ uint16_t offsetToName;
+ uint16_t reserved[3];
+ char fullPath[1024];
+} SceFiosDirEntry;
+
+typedef struct SceFiosStat {
+ SceFiosOffset fileSize;
+ SceFiosDate accessDate;
+ SceFiosDate modificationDate;
+ SceFiosDate creationDate;
+ uint32_t statFlags;
+ uint32_t reserved;
+ int64_t uid;
+ int64_t gid;
+ int64_t dev;
+ int64_t ino;
+ int64_t mode;
+} SceFiosStat;
+
+int sceFiosInitialize(const SceFiosParams *params);
+void sceFiosTerminate();
+
+SceFiosSize sceFiosArchiveGetMountBufferSizeSync(const void *attr, const char *path, void *params);
+int sceFiosArchiveMountSync(const void *attr, SceFiosFH *fh, const char *path, const char *mount_point, SceFiosBuffer mount_buffer, void *params);
+int sceFiosArchiveUnmountSync(const void *attr, SceFiosFH fh);
+
+int sceFiosStatSync(const void *attr, const char *path, SceFiosStat *stat);
+
+int sceFiosFHOpenSync(const void *attr, SceFiosFH *fh, const char *path, const void *params);
+SceFiosSize sceFiosFHReadSync(const void *attr, SceFiosFH fh, void *data, SceFiosSize size);
+int sceFiosFHCloseSync(const void *attr, SceFiosFH fh);
+
+int sceFiosDHOpenSync(const void *attr, SceFiosDH *dh, const char *path, SceFiosBuffer buf);
+int sceFiosDHReadSync(const void *attr, SceFiosDH dh, SceFiosDirEntry *dir);
+int sceFiosDHCloseSync(const void *attr, SceFiosDH dh);
+
+SceDateTime *sceFiosDateToSceDateTime(SceFiosDate date, SceDateTime *sce_date);
+
+int sceFiosIOFilterAdd(int index, void (* callback)(), void *context);
+int sceFiosIOFilterRemove(int index);
+
+void sceFiosIOFilterPsarcDearchiver();
+
+int64_t g_OpStorage[SCE_FIOS_OP_STORAGE_SIZE(64, MAX_PATH_LENGTH) / sizeof(int64_t) + 1];
+int64_t g_ChunkStorage[SCE_FIOS_CHUNK_STORAGE_SIZE(1024) / sizeof(int64_t) + 1];
+int64_t g_FHStorage[SCE_FIOS_FH_STORAGE_SIZE(32, MAX_PATH_LENGTH) / sizeof(int64_t) + 1];
+int64_t g_DHStorage[SCE_FIOS_DH_STORAGE_SIZE(32, MAX_PATH_LENGTH) / sizeof(int64_t) + 1];
+
+SceFiosPsarcDearchiverContext g_DearchiverContext = SCE_FIOS_PSARC_DEARCHIVER_CONTEXT_INITIALIZER;
+char g_DearchiverWorkBuffer[0x30000] __attribute__((aligned(64)));
+int g_ArchiveIndex = 0;
+SceFiosBuffer g_MountBuffer = SCE_FIOS_BUFFER_INITIALIZER;
+SceFiosFH g_ArchiveFH = -1;
+
+int psarcOpen(const char *file) {
+ int res;
+
+ SceFiosParams params = SCE_FIOS_PARAMS_INITIALIZER;
+ params.opStorage.pPtr = g_OpStorage;
+ params.opStorage.length = sizeof(g_OpStorage);
+ params.chunkStorage.pPtr = g_ChunkStorage;
+ params.chunkStorage.length = sizeof(g_ChunkStorage);
+ params.fhStorage.pPtr = g_FHStorage;
+ params.fhStorage.length = sizeof(g_FHStorage);
+ params.dhStorage.pPtr = g_DHStorage;
+ params.dhStorage.length = sizeof(g_DHStorage);
+ params.pathMax = MAX_PATH_LENGTH;
+
+ res = sceFiosInitialize(¶ms);
+ if (res < 0)
+ goto ERROR_INITIALIZE;
+
+ g_DearchiverContext.workBufferSize = sizeof(g_DearchiverWorkBuffer);
+ g_DearchiverContext.pWorkBuffer = g_DearchiverWorkBuffer;
+
+ res = sceFiosIOFilterAdd(g_ArchiveIndex, sceFiosIOFilterPsarcDearchiver, &g_DearchiverContext);
+ if (res < 0)
+ goto ERROR_FILTER_ADD;
+
+ SceFiosSize result = sceFiosArchiveGetMountBufferSizeSync(NULL, file, NULL);
+ if (result < 0) {
+ res = (int)result;
+ goto ERROR_ARCHIVE_GET_MOUNT_BUFFER_SIZE;
+ }
+
+ g_MountBuffer.length = (size_t)result;
+ g_MountBuffer.pPtr = malloc(g_MountBuffer.length);
+
+ res = sceFiosArchiveMountSync(NULL, &g_ArchiveFH, file, file, g_MountBuffer, NULL);
+ if (res < 0)
+ goto ERROR_ARCHIVE_MOUNT;
+
+ return res;
+
+ERROR_ARCHIVE_MOUNT:
+ free(g_MountBuffer.pPtr);
+
+ERROR_ARCHIVE_GET_MOUNT_BUFFER_SIZE:
+ sceFiosIOFilterRemove(g_ArchiveIndex);
+
+ERROR_FILTER_ADD:
+ sceFiosTerminate();
+
+ERROR_INITIALIZE:
+ return res;
+}
+
+int psarcClose() {
+ sceFiosArchiveUnmountSync(NULL, g_ArchiveFH);
+ free(g_MountBuffer.pPtr);
+ sceFiosIOFilterRemove(g_ArchiveIndex);
+ sceFiosTerminate();
+
+ return 0;
+}
+
+int fileListGetPsarcEntries(FileList *list, const char *path, int sort) {
+ int res;
+
+ if (!list)
+ return VITASHELL_ERROR_ILLEGAL_ADDR;
+
+ SceFiosDH dh = -1;
+ SceFiosBuffer buf = SCE_FIOS_BUFFER_INITIALIZER;
+ res = sceFiosDHOpenSync(NULL, &dh, path, buf);
+ if (res < 0)
+ return res;
+
+ FileListEntry *entry = malloc(sizeof(FileListEntry));
+ if (entry) {
+ entry->name_length = strlen(DIR_UP);
+ entry->name = malloc(entry->name_length + 1);
+ strcpy(entry->name, DIR_UP);
+ entry->is_folder = 1;
+ entry->type = FILE_TYPE_UNKNOWN;
+ fileListAddEntry(list, entry, sort);
+ }
+
+ do {
+ SceFiosDirEntry dir;
+ memset(&dir, 0, sizeof(SceFiosDirEntry));
+
+ res = sceFiosDHReadSync(NULL, dh, &dir);
+
+ if (res >= 0) {
+ char *name = dir.fullPath + dir.offsetToName;
+
+ SceFiosStat stat;
+ memset(&stat, 0, sizeof(SceFiosStat));
+
+ if (sceFiosStatSync(NULL, dir.fullPath, &stat) >= 0) {
+ FileListEntry *entry = malloc(sizeof(FileListEntry));
+ if (entry) {
+ entry->is_folder = stat.statFlags & 0x1;
+ if (entry->is_folder) {
+ entry->name_length = strlen(name) + 1;
+ entry->name = malloc(entry->name_length + 1);
+ strcpy(entry->name, name);
+ addEndSlash(entry->name);
+ entry->type = FILE_TYPE_UNKNOWN;
+ list->folders++;
+ } else {
+ entry->name_length = strlen(name);
+ entry->name = malloc(entry->name_length + 1);
+ strcpy(entry->name, name);
+ entry->type = getFileType(entry->name);
+ list->files++;
+ }
+
+ entry->size = stat.fileSize;
+
+ SceDateTime time;
+
+ sceFiosDateToSceDateTime(stat.accessDate, &time);
+ memcpy(&entry->ctime, (SceDateTime *)&time, sizeof(SceDateTime));
+
+ sceFiosDateToSceDateTime(stat.modificationDate, &time);
+ memcpy(&entry->mtime, (SceDateTime *)&time, sizeof(SceDateTime));
+
+ sceFiosDateToSceDateTime(stat.creationDate, &time);
+ memcpy(&entry->atime, (SceDateTime *)&time, sizeof(SceDateTime));
+
+ fileListAddEntry(list, entry, sort);
+ }
+ }
+ }
+ } while (res >= 0);
+
+ sceFiosDHCloseSync(NULL, dh);
+
+ return 0;
+}
+
+int getPsarcPathInfo(const char *path, uint64_t *size, uint32_t *folders, uint32_t *files, int (* handler)(const char *path)) {
+ SceFiosDH dh = -1;
+ SceFiosBuffer buf = SCE_FIOS_BUFFER_INITIALIZER;
+ if (sceFiosDHOpenSync(NULL, &dh, path, buf) >= 0) {
+ int res = 0;
+
+ do {
+ SceFiosDirEntry dir;
+ memset(&dir, 0, sizeof(SceFiosDirEntry));
+
+ res = sceFiosDHReadSync(NULL, dh, &dir);
+ if (res >= 0) {
+ char *name = dir.fullPath + dir.offsetToName;
+
+ char *new_path = malloc(strlen(path) + strlen(name) + 2);
+ snprintf(new_path, MAX_PATH_LENGTH - 1, "%s%s%s", path, hasEndSlash(path) ? "" : "/", name);
+
+ if (handler && handler(new_path)) {
+ free(new_path);
+ continue;
+ }
+
+ if (dir.statFlags & 0x1) {
+ int ret = getPsarcPathInfo(new_path, size, folders, files, handler);
+ if (ret <= 0) {
+ free(new_path);
+ sceFiosDHCloseSync(NULL, dh);
+ return ret;
+ }
+ } else {
+ if (size)
+ (*size) += dir.fileSize;
+
+ if (files)
+ (*files)++;
+ }
+
+ free(new_path);
+ }
+ } while (res >= 0);
+
+ sceFiosDHCloseSync(NULL, dh);
+
+ if (folders)
+ (*folders)++;
+ } else {
+ if (handler && handler(path))
+ return 1;
+
+ if (size) {
+ SceFiosStat stat;
+ memset(&stat, 0, sizeof(SceFiosStat));
+
+ int res = sceFiosStatSync(NULL, path, &stat);
+ if (res < 0)
+ return res;
+
+ (*size) += stat.fileSize;
+ }
+
+ if (files)
+ (*files)++;
+ }
+
+ return 1;
+}
+
+int extractPsarcFile(const char *src_path, const char *dst_path, FileProcessParam *param) {
+ SceUID fdsrc = psarcFileOpen(src_path, SCE_O_RDONLY, 0);
+ if (fdsrc < 0)
+ return fdsrc;
+
+ SceUID fddst = sceIoOpen(dst_path, SCE_O_WRONLY | SCE_O_CREAT | SCE_O_TRUNC, 0777);
+ if (fddst < 0) {
+ psarcFileClose(fdsrc);
+ return fddst;
+ }
+
+ void *buf = memalign(4096, TRANSFER_SIZE);
+
+ while (1) {
+ int read = psarcFileRead(fdsrc, buf, TRANSFER_SIZE);
+
+ if (read < 0) {
+ free(buf);
+
+ sceIoClose(fddst);
+ psarcFileClose(fdsrc);
+
+ sceIoRemove(dst_path);
+
+ return read;
+ }
+
+ if (read == 0)
+ break;
+
+ int written = sceIoWrite(fddst, buf, read);
+
+ if (written < 0) {
+ free(buf);
+
+ sceIoClose(fddst);
+ psarcFileClose(fdsrc);
+
+ sceIoRemove(dst_path);
+
+ return written;
+ }
+
+ if (param) {
+ if (param->value)
+ (*param->value) += read;
+
+ if (param->SetProgress)
+ param->SetProgress(param->value ? *param->value : 0, param->max);
+
+ if (param->cancelHandler && param->cancelHandler()) {
+ free(buf);
+
+ sceIoClose(fddst);
+ psarcFileClose(fdsrc);
+
+ sceIoRemove(dst_path);
+
+ return 0;
+ }
+ }
+ }
+
+ free(buf);
+
+ sceIoClose(fddst);
+ psarcFileClose(fdsrc);
+
+ return 1;
+}
+
+int extractPsarcPath(const char *src_path, const char *dst_path, FileProcessParam *param) {
+ SceFiosDH dh = -1;
+ SceFiosBuffer buf = SCE_FIOS_BUFFER_INITIALIZER;
+ if (sceFiosDHOpenSync(NULL, &dh, src_path, buf) >= 0) {
+ int ret = sceIoMkdir(dst_path, 0777);
+ if (ret < 0 && ret != SCE_ERROR_ERRNO_EEXIST) {
+ sceFiosDHCloseSync(NULL, dh);
+ return ret;
+ }
+
+ if (param) {
+ if (param->value)
+ (*param->value) += DIRECTORY_SIZE;
+
+ if (param->SetProgress)
+ param->SetProgress(param->value ? *param->value : 0, param->max);
+
+ if (param->cancelHandler && param->cancelHandler()) {
+ sceFiosDHCloseSync(NULL, dh);
+ return 0;
+ }
+ }
+
+ int res = 0;
+
+ do {
+ SceFiosDirEntry dir;
+ memset(&dir, 0, sizeof(SceFiosDirEntry));
+
+ res = sceFiosDHReadSync(NULL, dh, &dir);
+ if (res >= 0) {
+ char *name = dir.fullPath + dir.offsetToName;
+
+ char *new_src_path = malloc(strlen(src_path) + strlen(name) + 2);
+ snprintf(new_src_path, MAX_PATH_LENGTH - 1, "%s%s%s", src_path, hasEndSlash(src_path) ? "" : "/", name);
+
+ char *new_dst_path = malloc(strlen(dst_path) + strlen(name) + 2);
+ snprintf(new_dst_path, MAX_PATH_LENGTH - 1, "%s%s%s", dst_path, hasEndSlash(dst_path) ? "" : "/", name);
+
+ int ret = 0;
+
+ if (dir.statFlags & 0x1) {
+ ret = extractPsarcPath(new_src_path, new_dst_path, param);
+ } else {
+ ret = extractPsarcFile(new_src_path, new_dst_path, param);
+ }
+
+ free(new_dst_path);
+ free(new_src_path);
+
+ if (ret <= 0) {
+ sceFiosDHCloseSync(NULL, dh);
+ return ret;
+ }
+ }
+ } while (res >= 0);
+
+ sceFiosDHCloseSync(NULL, dh);
+ } else {
+ return extractPsarcFile(src_path, dst_path, param);
+ }
+
+ return 1;
+}
+
+int psarcFileGetstat(const char *file, SceIoStat *stat) {
+ SceFiosStat fios_stat;
+ memset(&fios_stat, 0, sizeof(SceFiosStat));
+ int res = sceFiosStatSync(NULL, file, &fios_stat);
+ if (res < 0)
+ return res;
+
+ if (stat) {
+ stat->st_mode = (fios_stat.statFlags & 0x1) ? SCE_S_IFDIR : SCE_S_IFREG;
+ stat->st_size = fios_stat.fileSize;
+
+ SceDateTime time;
+
+ sceFiosDateToSceDateTime(fios_stat.accessDate, &time);
+ memcpy(&stat->st_ctime, (SceDateTime *)&time, sizeof(SceDateTime));
+
+ sceFiosDateToSceDateTime(fios_stat.modificationDate, &time);
+ memcpy(&stat->st_mtime, (SceDateTime *)&time, sizeof(SceDateTime));
+
+ sceFiosDateToSceDateTime(fios_stat.creationDate, &time);
+ memcpy(&stat->st_atime, (SceDateTime *)&time, sizeof(SceDateTime));
+ }
+
+ return res;
+}
+
+int psarcFileOpen(const char *file, int flags, SceMode mode) {
+ SceFiosFH fh = -1;
+
+ int res = sceFiosFHOpenSync(NULL, &fh, file, NULL);
+ if (res < 0)
+ return res;
+
+ return fh;
+}
+
+int psarcFileRead(SceUID fd, void *data, SceSize size) {
+ return (int)sceFiosFHReadSync(NULL, fd, data, (SceFiosSize)size);
+}
+
+int psarcFileClose(SceUID fd) {
+ return sceFiosFHCloseSync(NULL, fd);
}
\ No newline at end of file
diff --git a/qr.c b/qr.c
index f69af54..34852c6 100644
--- a/qr.c
+++ b/qr.c
@@ -1,354 +1,354 @@
-/*
- VitaShell
- Copyright (C) 2015-2018, TheFloW
-
- 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, either version 3 of the License, or
- (at your option) any later version.
-
- 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 for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
-*/
-
-#include "qr.h"
-
-#include
-#include
-#include
-
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include
-
-#include "main.h"
-#include "io_process.h"
-#include "network_download.h"
-#include "package_installer.h"
-#include "archive.h"
-#include "file.h"
-#include "message_dialog.h"
-#include "language.h"
-#include "utils.h"
-
-static int qr_enabled;
-
-static struct quirc *qr;
-static uint32_t* qr_data;
-static char *data;
-static int qr_next;
-
-static vita2d_texture *camera_tex;
-
-static SceCameraInfo cam_info;
-static SceCameraRead cam_info_read;
-
-static char last_qr[MAX_QR_LENGTH];
-static char last_download[MAX_QR_LENGTH];
-static int last_qr_len;
-static int qr_scanned = 0;
-
-static SceUID thid;
-
-int qr_thread() {
- qr = quirc_new();
- quirc_resize(qr, CAM_WIDTH, CAM_HEIGHT);
- qr_next = 1;
- while (1) {
- sceKernelDelayThread(10);
- if (qr_next == 0 && qr_scanned == 0) {
- uint8_t *image;
- int w, h;
- image = quirc_begin(qr, &w, &h);
- uint32_t colourRGBA;
- int i;
- for (i = 0; i < w*h; i++) {
- colourRGBA = qr_data[i];
- image[i] = ((colourRGBA & 0x000000FF) + ((colourRGBA & 0x0000FF00) >> 8) + ((colourRGBA & 0x00FF0000) >> 16)) / 3;
- }
- quirc_end(qr);
- int num_codes = quirc_count(qr);
- if (num_codes > 0) {
- struct quirc_code code;
- struct quirc_data data;
- quirc_decode_error_t err;
-
- quirc_extract(qr, 0, &code);
- err = quirc_decode(&code, &data);
- if (err) {
- } else {
- memcpy(last_qr, data.payload, data.payload_len);
- last_qr_len = data.payload_len;
- qr_scanned = 1;
- }
- } else {
- memset(last_qr, 0, MAX_QR_LENGTH);
- }
- qr_next = 1;
- sceKernelDelayThread(250000);
- }
- }
-}
-
-int qr_scan_thread(SceSize args, void *argp) {
- data = last_qr;
- if (last_qr_len > 4) {
- if (!(data[0] == 'h' && data[1] == 't' && data[2] == 't' && data[3] == 'p')) {
- initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_OK, language_container[QR_SHOW_CONTENTS], data);
- setDialogStep(DIALOG_STEP_QR_SHOW_CONTENTS);
- return sceKernelExitDeleteThread(0);
- }
- } else {
- initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_OK, language_container[QR_SHOW_CONTENTS], data);
- setDialogStep(DIALOG_STEP_QR_SHOW_CONTENTS);
- return sceKernelExitDeleteThread(0);
- }
-
- initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_NONE, language_container[PLEASE_WAIT]);
-
- // check for attached file
- const char *headerData;
- unsigned int headerLen;
- unsigned int fileNameLength = 0;
- int vpk = 0;
- char *fileName = "";
- uint64_t fileSize;
- char sizeString[16];
- int ret;
-
- ret = getDownloadFileSize(data, &fileSize);
- if (ret < 0)
- goto NETWORK_FAILURE;
-
- ret = getFieldFromHeader(data, "Content-Disposition", &headerData, &headerLen);
- if (ret < 0)
- goto NETWORK_FAILURE;
-
- getSizeString(sizeString, fileSize);
- sceMsgDialogClose();
-
- // Wait for it to stop loading
- while (isMessageDialogRunning()) {
- sceKernelDelayThread(10 * 1000);
- }
-
- if (headerLen <= 0) {
- char *next;
- fileName = data;
- while ((next = strpbrk(fileName + 1, "\\/"))) fileName = next;
- if (fileName != last_qr) fileName++;
-
- char *ext = strrchr(fileName, '.');
- if (ext) {
- vpk = getFileType(fileName) == FILE_TYPE_VPK;
- } else {
- initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_YESNO, language_container[QR_OPEN_WEBSITE], data);
- setDialogStep(DIALOG_STEP_QR_OPEN_WEBSITE);
- return sceKernelExitDeleteThread(0);
- }
- } else {
- if (strstr(headerData, "inline") != NULL) {
- initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_YESNO, language_container[QR_OPEN_WEBSITE], data);
- setDialogStep(DIALOG_STEP_QR_OPEN_WEBSITE);
- return sceKernelExitDeleteThread(0);
- }
-
- char *p = strstr(headerData, "filename=");
- if (!p)
- goto EXIT;
-
- fileName = p+9;
-
- p = strchr(fileName, '\n');
- if (p)
- *p = '\0';
-
- // Trim at beginning
- while (*fileName < 0x20 ||
- *fileName == ' ' || *fileName == '\\' ||
- *fileName == '/' || *fileName == ':' ||
- *fileName == '*' || *fileName == '?' ||
- *fileName == '"' || *fileName == '<' ||
- *fileName == '>' || *fileName == '|') {
- fileName++;
- }
-
- // Trim at end
- int i;
- for (i = strlen(fileName)-1; i >= 0; i--) {
- if (fileName[i] < 0x20 ||
- fileName[i] == ' ' || fileName[i] == '\\' ||
- fileName[i] == '/' || fileName[i] == ':' ||
- fileName[i] == '*' || fileName[i] == '?' ||
- fileName[i] == '"' || fileName[i] == '<' ||
- fileName[i] == '>' || fileName[i] == '|') {
- fileName[i] = 0;
- } else {
- break;
- }
- }
-
- // VPK type
- vpk = getFileType(fileName) == FILE_TYPE_VPK;
- }
-
- if (vpk)
- initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_YESNO, language_container[QR_CONFIRM_INSTALL], data, fileName, sizeString);
- else
- initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_YESNO, language_container[QR_CONFIRM_DOWNLOAD], data, fileName, sizeString);
- setDialogStep(DIALOG_STEP_QR_CONFIRM);
-
- // Wait for response
- while (getDialogStep() == DIALOG_STEP_QR_CONFIRM) {
- sceKernelDelayThread(10 * 1000);
- }
-
- // No
- if (getDialogStep() == DIALOG_STEP_NONE) {
- goto EXIT;
- }
-
- // Yes
- char download_path[MAX_URL_LENGTH];
- char short_name[MAX_URL_LENGTH];
- int count = 0;
-
- char *ext = strrchr(fileName, '.');
- if (ext) {
- int len = ext-fileName;
- if (len > sizeof(short_name) - 1)
- len = sizeof(short_name) - 1;
- strncpy(short_name, fileName, len);
- short_name[len] = '\0';
- } else {
- strncpy(short_name, fileName, sizeof(short_name) - 1);
- ext = "";
- }
- while (1) {
- if (count == 0)
- snprintf(download_path, sizeof(download_path) - 1, "ux0:download/%s", fileName);
- else
- snprintf(download_path, sizeof(download_path) - 1, "ux0:download/%s (%d)%s", short_name, count, ext);
-
- SceIoStat stat;
- memset(&stat, 0, sizeof(SceIoStat));
- if (sceIoGetstat(download_path, &stat) < 0)
- break;
- count++;
- }
-
- sceIoMkdir("ux0:download", 0006);
-
- strcpy(last_download, download_path);
- if (vpk)
- return downloadFileProcess(data, download_path, DIALOG_STEP_QR_DOWNLOADED_VPK);
- else
- return downloadFileProcess(data, download_path, DIALOG_STEP_QR_DOWNLOADED);
-
-EXIT:
- return sceKernelExitDeleteThread(0);
-
-NETWORK_FAILURE:
- sceMsgDialogClose();
- while (isMessageDialogRunning()) {
- sceKernelDelayThread(10 * 1000);
- }
-
- initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_YESNO, language_container[QR_OPEN_WEBSITE], data);
- setDialogStep(DIALOG_STEP_QR_OPEN_WEBSITE);
- return sceKernelExitDeleteThread(0);
-}
-
-int initQR() {
- SceKernelMemBlockType orig = vita2d_texture_get_alloc_memblock_type();
- vita2d_texture_set_alloc_memblock_type(SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW);
- camera_tex = vita2d_create_empty_texture(CAM_WIDTH, CAM_HEIGHT);
- vita2d_texture_set_alloc_memblock_type(orig);
-
- cam_info.size = sizeof(SceCameraInfo);
- cam_info.format = SCE_CAMERA_FORMAT_ABGR;
- cam_info.resolution = SCE_CAMERA_RESOLUTION_640_360;
- cam_info.pitch = vita2d_texture_get_stride(camera_tex) - (CAM_WIDTH << 2);
- cam_info.sizeIBase = (CAM_WIDTH * CAM_HEIGHT) << 2;
- cam_info.pIBase = vita2d_texture_get_datap(camera_tex);
- cam_info.framerate = 30;
-
- cam_info_read.size = sizeof(SceCameraRead);
- cam_info_read.mode = 0;
- if (sceCameraOpen(1, &cam_info) < 0) {
- qr_enabled = 0;
- vita2d_free_texture(camera_tex);
- return -1;
- }
-
- thid = sceKernelCreateThread("qr_decode_thread", qr_thread, 0x40, 0x100000, 0, 0, NULL);
- if (thid >= 0) sceKernelStartThread(thid, 0, NULL);
- qr_enabled = 1;
- return 0;
-}
-
-int finishQR() {
- sceKernelDeleteThread(thid);
- vita2d_free_texture(camera_tex);
- sceCameraClose(1);
- quirc_destroy(qr);
- return 0;
-}
-
-int startQR() {
- return sceCameraStart(1);
-}
-
-int stopQR() {
- int res = sceCameraStop(1);
-
- int y;
- for (y = 0; y < CAM_HEIGHT; y++) {
- int x;
- for (x = 0; x < CAM_WIDTH; x++) {
- ((uint32_t *)qr_data)[x + CAM_WIDTH * y] = 0;
- }
- }
-
- return res;
-}
-
-int renderCameraQR(int x, int y) {
- sceCameraRead(1, &cam_info_read);
- vita2d_draw_texture(camera_tex, x, y);
- if (qr_next) {
- qr_data = (uint32_t *)vita2d_texture_get_datap(camera_tex);
- qr_next = 0;
- }
- return 0;
-}
-
-char *getLastQR() {
- return data;
-}
-
-char *getLastDownloadQR() {
- return last_download;
-}
-
-int scannedQR() {
- return qr_scanned;
-}
-
-void setScannedQR(int s) {
- qr_scanned = s;
-}
-
-int enabledQR() {
- return qr_enabled;
+/*
+ VitaShell
+ Copyright (C) 2015-2018, TheFloW
+
+ 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, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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 for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+#include "qr.h"
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "main.h"
+#include "io_process.h"
+#include "network_download.h"
+#include "package_installer.h"
+#include "archive.h"
+#include "file.h"
+#include "message_dialog.h"
+#include "language.h"
+#include "utils.h"
+
+static int qr_enabled;
+
+static struct quirc *qr;
+static uint32_t* qr_data;
+static char *data;
+static int qr_next;
+
+static vita2d_texture *camera_tex;
+
+static SceCameraInfo cam_info;
+static SceCameraRead cam_info_read;
+
+static char last_qr[MAX_QR_LENGTH];
+static char last_download[MAX_QR_LENGTH];
+static int last_qr_len;
+static int qr_scanned = 0;
+
+static SceUID thid;
+
+int qr_thread() {
+ qr = quirc_new();
+ quirc_resize(qr, CAM_WIDTH, CAM_HEIGHT);
+ qr_next = 1;
+ while (1) {
+ sceKernelDelayThread(10);
+ if (qr_next == 0 && qr_scanned == 0) {
+ uint8_t *image;
+ int w, h;
+ image = quirc_begin(qr, &w, &h);
+ uint32_t colourRGBA;
+ int i;
+ for (i = 0; i < w*h; i++) {
+ colourRGBA = qr_data[i];
+ image[i] = ((colourRGBA & 0x000000FF) + ((colourRGBA & 0x0000FF00) >> 8) + ((colourRGBA & 0x00FF0000) >> 16)) / 3;
+ }
+ quirc_end(qr);
+ int num_codes = quirc_count(qr);
+ if (num_codes > 0) {
+ struct quirc_code code;
+ struct quirc_data data;
+ quirc_decode_error_t err;
+
+ quirc_extract(qr, 0, &code);
+ err = quirc_decode(&code, &data);
+ if (err) {
+ } else {
+ memcpy(last_qr, data.payload, data.payload_len);
+ last_qr_len = data.payload_len;
+ qr_scanned = 1;
+ }
+ } else {
+ memset(last_qr, 0, MAX_QR_LENGTH);
+ }
+ qr_next = 1;
+ sceKernelDelayThread(250000);
+ }
+ }
+}
+
+int qr_scan_thread(SceSize args, void *argp) {
+ data = last_qr;
+ if (last_qr_len > 4) {
+ if (!(data[0] == 'h' && data[1] == 't' && data[2] == 't' && data[3] == 'p')) {
+ initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_OK, language_container[QR_SHOW_CONTENTS], data);
+ setDialogStep(DIALOG_STEP_QR_SHOW_CONTENTS);
+ return sceKernelExitDeleteThread(0);
+ }
+ } else {
+ initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_OK, language_container[QR_SHOW_CONTENTS], data);
+ setDialogStep(DIALOG_STEP_QR_SHOW_CONTENTS);
+ return sceKernelExitDeleteThread(0);
+ }
+
+ initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_NONE, language_container[PLEASE_WAIT]);
+
+ // check for attached file
+ const char *headerData;
+ unsigned int headerLen;
+ unsigned int fileNameLength = 0;
+ int vpk = 0;
+ char *fileName = "";
+ uint64_t fileSize;
+ char sizeString[16];
+ int ret;
+
+ ret = getDownloadFileSize(data, &fileSize);
+ if (ret < 0)
+ goto NETWORK_FAILURE;
+
+ ret = getFieldFromHeader(data, "Content-Disposition", &headerData, &headerLen);
+ if (ret < 0)
+ goto NETWORK_FAILURE;
+
+ getSizeString(sizeString, fileSize);
+ sceMsgDialogClose();
+
+ // Wait for it to stop loading
+ while (isMessageDialogRunning()) {
+ sceKernelDelayThread(10 * 1000);
+ }
+
+ if (headerLen <= 0) {
+ char *next;
+ fileName = data;
+ while ((next = strpbrk(fileName + 1, "\\/"))) fileName = next;
+ if (fileName != last_qr) fileName++;
+
+ char *ext = strrchr(fileName, '.');
+ if (ext) {
+ vpk = getFileType(fileName) == FILE_TYPE_VPK;
+ } else {
+ initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_YESNO, language_container[QR_OPEN_WEBSITE], data);
+ setDialogStep(DIALOG_STEP_QR_OPEN_WEBSITE);
+ return sceKernelExitDeleteThread(0);
+ }
+ } else {
+ if (strstr(headerData, "inline") != NULL) {
+ initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_YESNO, language_container[QR_OPEN_WEBSITE], data);
+ setDialogStep(DIALOG_STEP_QR_OPEN_WEBSITE);
+ return sceKernelExitDeleteThread(0);
+ }
+
+ char *p = strstr(headerData, "filename=");
+ if (!p)
+ goto EXIT;
+
+ fileName = p+9;
+
+ p = strchr(fileName, '\n');
+ if (p)
+ *p = '\0';
+
+ // Trim at beginning
+ while (*fileName < 0x20 ||
+ *fileName == ' ' || *fileName == '\\' ||
+ *fileName == '/' || *fileName == ':' ||
+ *fileName == '*' || *fileName == '?' ||
+ *fileName == '"' || *fileName == '<' ||
+ *fileName == '>' || *fileName == '|') {
+ fileName++;
+ }
+
+ // Trim at end
+ int i;
+ for (i = strlen(fileName)-1; i >= 0; i--) {
+ if (fileName[i] < 0x20 ||
+ fileName[i] == ' ' || fileName[i] == '\\' ||
+ fileName[i] == '/' || fileName[i] == ':' ||
+ fileName[i] == '*' || fileName[i] == '?' ||
+ fileName[i] == '"' || fileName[i] == '<' ||
+ fileName[i] == '>' || fileName[i] == '|') {
+ fileName[i] = 0;
+ } else {
+ break;
+ }
+ }
+
+ // VPK type
+ vpk = getFileType(fileName) == FILE_TYPE_VPK;
+ }
+
+ if (vpk)
+ initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_YESNO, language_container[QR_CONFIRM_INSTALL], data, fileName, sizeString);
+ else
+ initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_YESNO, language_container[QR_CONFIRM_DOWNLOAD], data, fileName, sizeString);
+ setDialogStep(DIALOG_STEP_QR_CONFIRM);
+
+ // Wait for response
+ while (getDialogStep() == DIALOG_STEP_QR_CONFIRM) {
+ sceKernelDelayThread(10 * 1000);
+ }
+
+ // No
+ if (getDialogStep() == DIALOG_STEP_NONE) {
+ goto EXIT;
+ }
+
+ // Yes
+ char download_path[MAX_URL_LENGTH];
+ char short_name[MAX_URL_LENGTH];
+ int count = 0;
+
+ char *ext = strrchr(fileName, '.');
+ if (ext) {
+ int len = ext-fileName;
+ if (len > sizeof(short_name) - 1)
+ len = sizeof(short_name) - 1;
+ strncpy(short_name, fileName, len);
+ short_name[len] = '\0';
+ } else {
+ strncpy(short_name, fileName, sizeof(short_name) - 1);
+ ext = "";
+ }
+ while (1) {
+ if (count == 0)
+ snprintf(download_path, sizeof(download_path) - 1, "ux0:download/%s", fileName);
+ else
+ snprintf(download_path, sizeof(download_path) - 1, "ux0:download/%s (%d)%s", short_name, count, ext);
+
+ SceIoStat stat;
+ memset(&stat, 0, sizeof(SceIoStat));
+ if (sceIoGetstat(download_path, &stat) < 0)
+ break;
+ count++;
+ }
+
+ sceIoMkdir("ux0:download", 0006);
+
+ strcpy(last_download, download_path);
+ if (vpk)
+ return downloadFileProcess(data, download_path, DIALOG_STEP_QR_DOWNLOADED_VPK);
+ else
+ return downloadFileProcess(data, download_path, DIALOG_STEP_QR_DOWNLOADED);
+
+EXIT:
+ return sceKernelExitDeleteThread(0);
+
+NETWORK_FAILURE:
+ sceMsgDialogClose();
+ while (isMessageDialogRunning()) {
+ sceKernelDelayThread(10 * 1000);
+ }
+
+ initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_YESNO, language_container[QR_OPEN_WEBSITE], data);
+ setDialogStep(DIALOG_STEP_QR_OPEN_WEBSITE);
+ return sceKernelExitDeleteThread(0);
+}
+
+int initQR() {
+ SceKernelMemBlockType orig = vita2d_texture_get_alloc_memblock_type();
+ vita2d_texture_set_alloc_memblock_type(SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW);
+ camera_tex = vita2d_create_empty_texture(CAM_WIDTH, CAM_HEIGHT);
+ vita2d_texture_set_alloc_memblock_type(orig);
+
+ cam_info.size = sizeof(SceCameraInfo);
+ cam_info.format = SCE_CAMERA_FORMAT_ABGR;
+ cam_info.resolution = SCE_CAMERA_RESOLUTION_640_360;
+ cam_info.pitch = vita2d_texture_get_stride(camera_tex) - (CAM_WIDTH << 2);
+ cam_info.sizeIBase = (CAM_WIDTH * CAM_HEIGHT) << 2;
+ cam_info.pIBase = vita2d_texture_get_datap(camera_tex);
+ cam_info.framerate = 30;
+
+ cam_info_read.size = sizeof(SceCameraRead);
+ cam_info_read.mode = 0;
+ if (sceCameraOpen(1, &cam_info) < 0) {
+ qr_enabled = 0;
+ vita2d_free_texture(camera_tex);
+ return -1;
+ }
+
+ thid = sceKernelCreateThread("qr_decode_thread", qr_thread, 0x40, 0x100000, 0, 0, NULL);
+ if (thid >= 0) sceKernelStartThread(thid, 0, NULL);
+ qr_enabled = 1;
+ return 0;
+}
+
+int finishQR() {
+ sceKernelDeleteThread(thid);
+ vita2d_free_texture(camera_tex);
+ sceCameraClose(1);
+ quirc_destroy(qr);
+ return 0;
+}
+
+int startQR() {
+ return sceCameraStart(1);
+}
+
+int stopQR() {
+ int res = sceCameraStop(1);
+
+ int y;
+ for (y = 0; y < CAM_HEIGHT; y++) {
+ int x;
+ for (x = 0; x < CAM_WIDTH; x++) {
+ ((uint32_t *)qr_data)[x + CAM_WIDTH * y] = 0;
+ }
+ }
+
+ return res;
+}
+
+int renderCameraQR(int x, int y) {
+ sceCameraRead(1, &cam_info_read);
+ vita2d_draw_texture(camera_tex, x, y);
+ if (qr_next) {
+ qr_data = (uint32_t *)vita2d_texture_get_datap(camera_tex);
+ qr_next = 0;
+ }
+ return 0;
+}
+
+char *getLastQR() {
+ return data;
+}
+
+char *getLastDownloadQR() {
+ return last_download;
+}
+
+int scannedQR() {
+ return qr_scanned;
+}
+
+void setScannedQR(int s) {
+ qr_scanned = s;
+}
+
+int enabledQR() {
+ return qr_enabled;
}
\ No newline at end of file
diff --git a/qr.h b/qr.h
index fd78a22..79f5bf9 100644
--- a/qr.h
+++ b/qr.h
@@ -1,37 +1,37 @@
-/*
- VitaShell
- Copyright (C) 2015-2018, TheFloW
-
- 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, either version 3 of the License, or
- (at your option) any later version.
-
- 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 for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
-*/
-
-#ifndef __QR_H__
-#define __QR_H__
-
-#include
-
-int qr_scan_thread(SceSize args, void *argp);
-
-int initQR();
-int finishQR();
-int startQR();
-int stopQR();
-int enabledQR();
-int scannedQR();
-int renderCameraQR(int x, int y);
-char *getLastQR();
-char *getLastDownloadQR();
-void setScannedQR(int scanned);
-
+/*
+ VitaShell
+ Copyright (C) 2015-2018, TheFloW
+
+ 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, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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 for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+#ifndef __QR_H__
+#define __QR_H__
+
+#include
+
+int qr_scan_thread(SceSize args, void *argp);
+
+int initQR();
+int finishQR();
+int startQR();
+int stopQR();
+int enabledQR();
+int scannedQR();
+int renderCameraQR(int x, int y);
+char *getLastQR();
+char *getLastDownloadQR();
+void setScannedQR(int scanned);
+
#endif
\ No newline at end of file
diff --git a/refresh.c b/refresh.c
index 001c8a4..1e991d1 100644
--- a/refresh.c
+++ b/refresh.c
@@ -1,438 +1,438 @@
-/*
- VitaShell
- Copyright (C) 2015-2018, TheFloW
- Copyright (C) 2017, VitaSmith
-
- 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, either version 3 of the License, or
- (at your option) any later version.
-
- 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 for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
-*/
-
-#include "main.h"
-#include "init.h"
-#include "io_process.h"
-#include "refresh.h"
-#include "package_installer.h"
-#include "sfo.h"
-#include "file.h"
-#include "message_dialog.h"
-#include "language.h"
-#include "utils.h"
-#include "rif.h"
-
-// Note: The promotion process is *VERY* sensitive to the directories used below
-// Don't change them unless you know what you are doing!
-#define APP_TEMP "ux0:temp/app"
-#define DLC_TEMP "ux0:temp/addcont"
-
-#define MAX_DLC_PER_TITLE 1024
-
-int isCustomHomebrew(const char* path)
-{
- uint32_t work[RIF_SIZE/4];
-
- if (ReadFile(path, work, sizeof(work)) != sizeof(work))
- return 0;
-
- for (int i = 0; i < sizeof(work) / sizeof(uint32_t); i++)
- if (work[i] != 0)
- return 0;
-
- return 1;
-}
-
-int refreshNeeded(const char *app_path)
-{
- char sfo_path[MAX_PATH_LENGTH];
- // TODO: Check app vs dlc from SFO
- int res, is_app = (app_path[6] == 'p');
-
- // Read param.sfo
- snprintf(sfo_path, MAX_PATH_LENGTH - 1, "%s/sce_sys/param.sfo", app_path);
- void *sfo_buffer = NULL;
- int sfo_size = allocateReadFile(sfo_path, &sfo_buffer);
- if (sfo_size < 0) {
- if (sfo_buffer)
- free(sfo_buffer);
- return sfo_size;
- }
-
- // Get title and content ids
- char titleid[12], contentid[50];
- getSfoString(sfo_buffer, "TITLE_ID", titleid, sizeof(titleid));
- getSfoString(sfo_buffer, "CONTENT_ID", contentid, sizeof(contentid));
-
- // Free sfo buffer
- free(sfo_buffer);
-
- // Check if app exists
- if (checkAppExist(titleid)) {
- char rif_name[48];
-
- uint64_t aid;
- sceRegMgrGetKeyBin("/CONFIG/NP", "account_id", &aid, sizeof(uint64_t));
-
- // Check if bounded rif file exits
- _sceNpDrmGetRifName(rif_name, 0, aid);
- if (is_app)
- snprintf(sfo_path, MAX_PATH_LENGTH - 1, "ux0:license/app/%s/%s", titleid, rif_name);
- else
- snprintf(sfo_path, MAX_PATH_LENGTH - 1, "ux0:license/addcont/%s/%s/%s", titleid, &contentid[20], rif_name);
- if (checkFileExist(sfo_path))
- return 0;
-
- // Check if fixed rif file exits
- _sceNpDrmGetFixedRifName(rif_name, 0, 0);
- if (is_app)
- snprintf(sfo_path, MAX_PATH_LENGTH - 1, "ux0:license/app/%s/%s", titleid, rif_name);
- else
- snprintf(sfo_path, MAX_PATH_LENGTH - 1, "ux0:license/addcont/%s/%s/%s", titleid, &contentid[20], rif_name);
- if (checkFileExist(sfo_path))
- return 0;
- }
-
- return 1;
-}
-
-int refreshApp(const char *app_path)
-{
- char work_bin_path[MAX_PATH_LENGTH];
- int res;
-
- snprintf(work_bin_path, MAX_PATH_LENGTH - 1, "%s/sce_sys/package/work.bin", app_path);
-
- // Remove work.bin for custom homebrews
- if (isCustomHomebrew(work_bin_path)) {
- sceIoRemove(work_bin_path);
- } else if (!checkFileExist(work_bin_path)) {
- // If available, restore work.bin from licenses.db
- void *sfo_buffer = NULL;
- char sfo_path[MAX_PATH_LENGTH], contentid[50];
- snprintf(sfo_path, MAX_PATH_LENGTH - 1, "%s/sce_sys/param.sfo", app_path);
- int sfo_size = allocateReadFile(sfo_path, &sfo_buffer);
- if (sfo_size > 0) {
- getSfoString(sfo_buffer, "CONTENT_ID", contentid, sizeof(contentid));
- uint8_t* rif = query_rif(LICENSE_DB, contentid);
- if (rif != NULL) {
- int fh = sceIoOpen(work_bin_path, SCE_O_WRONLY | SCE_O_CREAT, 0777);
- if (fh > 0) {
- sceIoWrite(fh, rif, RIF_SIZE);
- sceIoClose(fh);
- }
- free(rif);
- }
- }
- free(sfo_buffer);
- }
-
- // Promote app/dlc
- res = promoteApp(app_path);
- return (res < 0) ? res : 1;
-}
-
-// target_type should be either SCE_S_IFREG for files or SCE_S_IFDIR for directories
-int parse_dir_with_callback(int target_type, const char* path, void(*callback)(void*, const char*, const char*), void* data)
-{
- SceUID dfd = sceIoDopen(path);
- if (dfd >= 0) {
- int res = 0;
-
- do {
- SceIoDirent dir;
- memset(&dir, 0, sizeof(SceIoDirent));
-
- res = sceIoDread(dfd, &dir);
- if (res > 0) {
- if ((dir.d_stat.st_mode & SCE_S_IFMT) == target_type) {
- callback(data, path, dir.d_name);
- if (cancelHandler()) {
- closeWaitDialog();
- setDialogStep(DIALOG_STEP_CANCELED);
- return -1;
- }
- }
- }
- } while (res > 0);
- sceIoDclose(dfd);
- }
- return 0;
-}
-
-typedef struct {
- int refresh_pass;
- int count;
- int processed;
- int refreshed;
-} refresh_data_t;
-
-typedef struct {
- refresh_data_t *refresh_data;
- char* list[MAX_DLC_PER_TITLE];
- int list_size;
-} dlc_data_t;
-
-typedef struct {
- int copy_pass;
- int count;
- int processed;
- int copied;
- int cur_depth;
- int max_depth;
- uint8_t* rif;
-} license_data_t;
-
-void app_callback(void* data, const char* dir, const char* subdir)
-{
- refresh_data_t *refresh_data = (refresh_data_t*)data;
- char path[MAX_PATH_LENGTH];
-
- if (strcasecmp(subdir, vitashell_titleid) == 0)
- return;
-
- if (refresh_data->refresh_pass) {
- snprintf(path, MAX_PATH_LENGTH - 1, "%s/%s", dir, subdir);
- if (refreshNeeded(path)) {
- // Move the directory to temp for installation
- removePath(APP_TEMP, NULL);
- sceIoRename(path, APP_TEMP);
- if (refreshApp(APP_TEMP) == 1)
- refresh_data->refreshed++;
- else
- // Restore folder on error
- sceIoRename(APP_TEMP, path);
- }
- SetProgress(++refresh_data->processed, refresh_data->count);
- } else {
- refresh_data->count++;
- }
-}
-
-void dlc_callback_inner(void* data, const char* dir, const char* subdir)
-{
- dlc_data_t *dlc_data = (dlc_data_t*)data;
- char path[MAX_PATH_LENGTH];
-
- // Ignore "sce_sys" and "sce_pfs" directories
- if (strncasecmp(subdir, "sce_", 4) == 0)
- return;
-
- if (dlc_data->refresh_data->refresh_pass) {
- snprintf(path, MAX_PATH_LENGTH - 1, "%s/%s", dir, subdir);
- if (dlc_data->list_size < MAX_DLC_PER_TITLE)
- dlc_data->list[dlc_data->list_size++] = strdup(path);
- } else {
- dlc_data->refresh_data->count++;
- }
-}
-
-void dlc_callback_outer(void* data, const char* dir, const char* subdir)
-{
- refresh_data_t *refresh_data = (refresh_data_t*)data;
- dlc_data_t dlc_data;
- dlc_data.refresh_data = refresh_data;
- dlc_data.list_size = 0;
- char path[MAX_PATH_LENGTH];
-
- // Get the title's dlc subdirectories
- int len = snprintf(path, sizeof(path), "%s/%s", dir, subdir);
- parse_dir_with_callback(SCE_S_IFDIR, path, dlc_callback_inner, &dlc_data);
-
- if (refresh_data->refresh_pass) {
- // For dlc, the process happens in two phases to avoid promotion errors:
- // 1. Move all dlc that require refresh out of addcont/title_id
- // 2. Refresh the moved dlc_data
- for (int i = 0; i < dlc_data.list_size; i++) {
- if (refreshNeeded(dlc_data.list[i])) {
- snprintf(path, MAX_PATH_LENGTH - 1, DLC_TEMP "/%s", &dlc_data.list[i][len + 1]);
- removePath(path, NULL);
- sceIoRename(dlc_data.list[i], path);
- } else {
- free(dlc_data.list[i]);
- dlc_data.list[i] = NULL;
- SetProgress(++refresh_data->processed, refresh_data->count);
- }
- }
-
- // Now that the dlc we need are out of addcont/title_id, refresh them
- for (int i = 0; i < dlc_data.list_size; i++) {
- if (dlc_data.list[i] != NULL) {
- snprintf(path, MAX_PATH_LENGTH - 1, DLC_TEMP "/%s", &dlc_data.list[i][len + 1]);
- if (refreshApp(path) == 1)
- refresh_data->refreshed++;
- else
- sceIoRename(path, dlc_data.list[i]);
- SetProgress(++refresh_data->processed, refresh_data->count);
- free(dlc_data.list[i]);
- }
- }
- }
-}
-
-int refresh_thread(SceSize args, void *argp)
-{
- SceUID thid = -1;
- refresh_data_t refresh_data = { 0, 0, 0, 0 };
-
- // Lock power timers
- powerLock();
-
- // Set progress to 0%
- sceMsgDialogProgressBarSetValue(SCE_MSG_DIALOG_PROGRESSBAR_TARGET_BAR_DEFAULT, 0);
- sceKernelDelayThread(DIALOG_WAIT); // Needed to see the percentage
-
- // Get the app count
- if (parse_dir_with_callback(SCE_S_IFDIR, "ux0:app", app_callback, &refresh_data) < 0)
- goto EXIT;
-
- // Get the dlc count
- if (parse_dir_with_callback(SCE_S_IFDIR, "ux0:addcont", dlc_callback_outer, &refresh_data) < 0)
- goto EXIT;
-
- // Update thread
- thid = createStartUpdateThread(refresh_data.count, 0);
-
- // Make sure we have the temp directories we need
- sceIoMkdir("ux0:temp", 0006);
- sceIoMkdir("ux0:temp/addcont", 0006);
- refresh_data.refresh_pass = 1;
-
- // Refresh apps
- if (parse_dir_with_callback(SCE_S_IFDIR, "ux0:app", app_callback, &refresh_data) < 0)
- goto EXIT;
-
- // Refresh dlc
- if (parse_dir_with_callback(SCE_S_IFDIR, "ux0:addcont", dlc_callback_outer, &refresh_data) < 0)
- goto EXIT;
-
- sceIoRmdir("ux0:temp/addcont");
-
- // Set progress to 100%
- sceMsgDialogProgressBarSetValue(SCE_MSG_DIALOG_PROGRESSBAR_TARGET_BAR_DEFAULT, 100);
- sceKernelDelayThread(COUNTUP_WAIT);
-
- // Close
- closeWaitDialog();
-
- infoDialog(language_container[REFRESHED], refresh_data.refreshed);
-
-EXIT:
- if (thid >= 0)
- sceKernelWaitThreadEnd(thid, NULL, NULL);
-
- // Unlock power timers
- powerUnlock();
-
- return sceKernelExitDeleteThread(0);
-}
-
-// Note: This is currently not optimized AT ALL.
-// Ultimately, we want to use a single transaction and avoid trying to
-// re-insert rifs that are already present.
-void license_file_callback(void* data, const char* dir, const char* file)
-{
- license_data_t *license_data = (license_data_t*)data;
- char path[MAX_PATH_LENGTH];
-
- // Ignore non rif content
- if ((strlen(file) < 4) || (strcasecmp(&file[strlen(file) - 4], ".rif") != 0))
- return;
- if (license_data->copy_pass) {
- snprintf(path, sizeof(path), "%s/%s", dir, file);
- SceUID fd = sceIoOpen(path, SCE_O_RDONLY, 0777);
- if (fd > 0) {
- int read = sceIoRead(fd, license_data->rif, RIF_SIZE);
- if (read == RIF_SIZE) {
- if (insert_rif(LICENSE_DB, license_data->rif) == 0)
- license_data->copied++;
- }
- sceIoClose(fd);
- }
- SetProgress(++license_data->processed, license_data->count);
- } else {
- license_data->count++;
- }
-}
-
-void license_dir_callback(void* data, const char* dir, const char* subdir)
-{
- license_data_t *license_data = (license_data_t*)data;
- char path[MAX_PATH_LENGTH];
-
- snprintf(path, sizeof(path), "%s/%s", dir, subdir);
- if (++license_data->cur_depth == license_data->max_depth)
- parse_dir_with_callback(SCE_S_IFREG, path, license_file_callback, data);
- else
- parse_dir_with_callback(SCE_S_IFDIR, path, license_dir_callback, data);
- license_data->cur_depth--;
-}
-
-int license_thread(SceSize args, void *argp)
-{
- SceUID thid = -1;
- license_data_t license_data = { 0, 0, 0, 0, 0, 1, malloc(RIF_SIZE) };
-
- if (license_data.rif == NULL)
- goto EXIT;
-
- // Lock power timers
- powerLock();
-
- // Set progress to 0%
- sceMsgDialogProgressBarSetValue(SCE_MSG_DIALOG_PROGRESSBAR_TARGET_BAR_DEFAULT, 0);
- sceKernelDelayThread(DIALOG_WAIT); // Needed to see the percentage
-
- // NB: ux0:license access requires elevated permisions
- if (parse_dir_with_callback(SCE_S_IFDIR, "ux0:license/app", license_dir_callback, &license_data) < 0)
- goto EXIT;
- license_data.max_depth++;
- if (parse_dir_with_callback(SCE_S_IFDIR, "ux0:license/addcont", license_dir_callback, &license_data) < 0)
- goto EXIT;
-
- // Update thread
- thid = createStartUpdateThread(license_data.count, 0);
-
- // Create the DB if needed
- SceUID fd = sceIoOpen(LICENSE_DB, SCE_O_RDONLY, 0777);
- if (fd > 0) {
- sceIoClose(fd);
- } else if (create_db(LICENSE_DB, LICENSE_DB_SCHEMA) != 0) {
- goto EXIT;
- }
-
- // Insert the licenses
- license_data.copy_pass = 1;
- license_data.max_depth = 1;
- if (parse_dir_with_callback(SCE_S_IFDIR, "ux0:license/app", license_dir_callback, &license_data) < 0)
- goto EXIT;
- license_data.max_depth++;
- if (parse_dir_with_callback(SCE_S_IFDIR, "ux0:license/addcont", license_dir_callback, &license_data) < 0)
- goto EXIT;
-
- // Set progress to 100%
- sceMsgDialogProgressBarSetValue(SCE_MSG_DIALOG_PROGRESSBAR_TARGET_BAR_DEFAULT, 100);
- sceKernelDelayThread(COUNTUP_WAIT);
-
- // Close
- closeWaitDialog();
-
- infoDialog(language_container[IMPORTED_LICENSES], license_data.copied);
-
-EXIT:
- if (thid >= 0)
- sceKernelWaitThreadEnd(thid, NULL, NULL);
-
- // Unlock power timers
- powerUnlock();
-
- free(license_data.rif);
- return sceKernelExitDeleteThread(0);
-}
+/*
+ VitaShell
+ Copyright (C) 2015-2018, TheFloW
+ Copyright (C) 2017, VitaSmith
+
+ 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, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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 for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+#include "main.h"
+#include "init.h"
+#include "io_process.h"
+#include "refresh.h"
+#include "package_installer.h"
+#include "sfo.h"
+#include "file.h"
+#include "message_dialog.h"
+#include "language.h"
+#include "utils.h"
+#include "rif.h"
+
+// Note: The promotion process is *VERY* sensitive to the directories used below
+// Don't change them unless you know what you are doing!
+#define APP_TEMP "ux0:temp/app"
+#define DLC_TEMP "ux0:temp/addcont"
+
+#define MAX_DLC_PER_TITLE 1024
+
+int isCustomHomebrew(const char* path)
+{
+ uint32_t work[RIF_SIZE/4];
+
+ if (ReadFile(path, work, sizeof(work)) != sizeof(work))
+ return 0;
+
+ for (int i = 0; i < sizeof(work) / sizeof(uint32_t); i++)
+ if (work[i] != 0)
+ return 0;
+
+ return 1;
+}
+
+int refreshNeeded(const char *app_path)
+{
+ char sfo_path[MAX_PATH_LENGTH];
+ // TODO: Check app vs dlc from SFO
+ int res, is_app = (app_path[6] == 'p');
+
+ // Read param.sfo
+ snprintf(sfo_path, MAX_PATH_LENGTH - 1, "%s/sce_sys/param.sfo", app_path);
+ void *sfo_buffer = NULL;
+ int sfo_size = allocateReadFile(sfo_path, &sfo_buffer);
+ if (sfo_size < 0) {
+ if (sfo_buffer)
+ free(sfo_buffer);
+ return sfo_size;
+ }
+
+ // Get title and content ids
+ char titleid[12], contentid[50];
+ getSfoString(sfo_buffer, "TITLE_ID", titleid, sizeof(titleid));
+ getSfoString(sfo_buffer, "CONTENT_ID", contentid, sizeof(contentid));
+
+ // Free sfo buffer
+ free(sfo_buffer);
+
+ // Check if app exists
+ if (checkAppExist(titleid)) {
+ char rif_name[48];
+
+ uint64_t aid;
+ sceRegMgrGetKeyBin("/CONFIG/NP", "account_id", &aid, sizeof(uint64_t));
+
+ // Check if bounded rif file exits
+ _sceNpDrmGetRifName(rif_name, 0, aid);
+ if (is_app)
+ snprintf(sfo_path, MAX_PATH_LENGTH - 1, "ux0:license/app/%s/%s", titleid, rif_name);
+ else
+ snprintf(sfo_path, MAX_PATH_LENGTH - 1, "ux0:license/addcont/%s/%s/%s", titleid, &contentid[20], rif_name);
+ if (checkFileExist(sfo_path))
+ return 0;
+
+ // Check if fixed rif file exits
+ _sceNpDrmGetFixedRifName(rif_name, 0, 0);
+ if (is_app)
+ snprintf(sfo_path, MAX_PATH_LENGTH - 1, "ux0:license/app/%s/%s", titleid, rif_name);
+ else
+ snprintf(sfo_path, MAX_PATH_LENGTH - 1, "ux0:license/addcont/%s/%s/%s", titleid, &contentid[20], rif_name);
+ if (checkFileExist(sfo_path))
+ return 0;
+ }
+
+ return 1;
+}
+
+int refreshApp(const char *app_path)
+{
+ char work_bin_path[MAX_PATH_LENGTH];
+ int res;
+
+ snprintf(work_bin_path, MAX_PATH_LENGTH - 1, "%s/sce_sys/package/work.bin", app_path);
+
+ // Remove work.bin for custom homebrews
+ if (isCustomHomebrew(work_bin_path)) {
+ sceIoRemove(work_bin_path);
+ } else if (!checkFileExist(work_bin_path)) {
+ // If available, restore work.bin from licenses.db
+ void *sfo_buffer = NULL;
+ char sfo_path[MAX_PATH_LENGTH], contentid[50];
+ snprintf(sfo_path, MAX_PATH_LENGTH - 1, "%s/sce_sys/param.sfo", app_path);
+ int sfo_size = allocateReadFile(sfo_path, &sfo_buffer);
+ if (sfo_size > 0) {
+ getSfoString(sfo_buffer, "CONTENT_ID", contentid, sizeof(contentid));
+ uint8_t* rif = query_rif(LICENSE_DB, contentid);
+ if (rif != NULL) {
+ int fh = sceIoOpen(work_bin_path, SCE_O_WRONLY | SCE_O_CREAT, 0777);
+ if (fh > 0) {
+ sceIoWrite(fh, rif, RIF_SIZE);
+ sceIoClose(fh);
+ }
+ free(rif);
+ }
+ }
+ free(sfo_buffer);
+ }
+
+ // Promote app/dlc
+ res = promoteApp(app_path);
+ return (res < 0) ? res : 1;
+}
+
+// target_type should be either SCE_S_IFREG for files or SCE_S_IFDIR for directories
+int parse_dir_with_callback(int target_type, const char* path, void(*callback)(void*, const char*, const char*), void* data)
+{
+ SceUID dfd = sceIoDopen(path);
+ if (dfd >= 0) {
+ int res = 0;
+
+ do {
+ SceIoDirent dir;
+ memset(&dir, 0, sizeof(SceIoDirent));
+
+ res = sceIoDread(dfd, &dir);
+ if (res > 0) {
+ if ((dir.d_stat.st_mode & SCE_S_IFMT) == target_type) {
+ callback(data, path, dir.d_name);
+ if (cancelHandler()) {
+ closeWaitDialog();
+ setDialogStep(DIALOG_STEP_CANCELED);
+ return -1;
+ }
+ }
+ }
+ } while (res > 0);
+ sceIoDclose(dfd);
+ }
+ return 0;
+}
+
+typedef struct {
+ int refresh_pass;
+ int count;
+ int processed;
+ int refreshed;
+} refresh_data_t;
+
+typedef struct {
+ refresh_data_t *refresh_data;
+ char* list[MAX_DLC_PER_TITLE];
+ int list_size;
+} dlc_data_t;
+
+typedef struct {
+ int copy_pass;
+ int count;
+ int processed;
+ int copied;
+ int cur_depth;
+ int max_depth;
+ uint8_t* rif;
+} license_data_t;
+
+void app_callback(void* data, const char* dir, const char* subdir)
+{
+ refresh_data_t *refresh_data = (refresh_data_t*)data;
+ char path[MAX_PATH_LENGTH];
+
+ if (strcasecmp(subdir, vitashell_titleid) == 0)
+ return;
+
+ if (refresh_data->refresh_pass) {
+ snprintf(path, MAX_PATH_LENGTH - 1, "%s/%s", dir, subdir);
+ if (refreshNeeded(path)) {
+ // Move the directory to temp for installation
+ removePath(APP_TEMP, NULL);
+ sceIoRename(path, APP_TEMP);
+ if (refreshApp(APP_TEMP) == 1)
+ refresh_data->refreshed++;
+ else
+ // Restore folder on error
+ sceIoRename(APP_TEMP, path);
+ }
+ SetProgress(++refresh_data->processed, refresh_data->count);
+ } else {
+ refresh_data->count++;
+ }
+}
+
+void dlc_callback_inner(void* data, const char* dir, const char* subdir)
+{
+ dlc_data_t *dlc_data = (dlc_data_t*)data;
+ char path[MAX_PATH_LENGTH];
+
+ // Ignore "sce_sys" and "sce_pfs" directories
+ if (strncasecmp(subdir, "sce_", 4) == 0)
+ return;
+
+ if (dlc_data->refresh_data->refresh_pass) {
+ snprintf(path, MAX_PATH_LENGTH - 1, "%s/%s", dir, subdir);
+ if (dlc_data->list_size < MAX_DLC_PER_TITLE)
+ dlc_data->list[dlc_data->list_size++] = strdup(path);
+ } else {
+ dlc_data->refresh_data->count++;
+ }
+}
+
+void dlc_callback_outer(void* data, const char* dir, const char* subdir)
+{
+ refresh_data_t *refresh_data = (refresh_data_t*)data;
+ dlc_data_t dlc_data;
+ dlc_data.refresh_data = refresh_data;
+ dlc_data.list_size = 0;
+ char path[MAX_PATH_LENGTH];
+
+ // Get the title's dlc subdirectories
+ int len = snprintf(path, sizeof(path), "%s/%s", dir, subdir);
+ parse_dir_with_callback(SCE_S_IFDIR, path, dlc_callback_inner, &dlc_data);
+
+ if (refresh_data->refresh_pass) {
+ // For dlc, the process happens in two phases to avoid promotion errors:
+ // 1. Move all dlc that require refresh out of addcont/title_id
+ // 2. Refresh the moved dlc_data
+ for (int i = 0; i < dlc_data.list_size; i++) {
+ if (refreshNeeded(dlc_data.list[i])) {
+ snprintf(path, MAX_PATH_LENGTH - 1, DLC_TEMP "/%s", &dlc_data.list[i][len + 1]);
+ removePath(path, NULL);
+ sceIoRename(dlc_data.list[i], path);
+ } else {
+ free(dlc_data.list[i]);
+ dlc_data.list[i] = NULL;
+ SetProgress(++refresh_data->processed, refresh_data->count);
+ }
+ }
+
+ // Now that the dlc we need are out of addcont/title_id, refresh them
+ for (int i = 0; i < dlc_data.list_size; i++) {
+ if (dlc_data.list[i] != NULL) {
+ snprintf(path, MAX_PATH_LENGTH - 1, DLC_TEMP "/%s", &dlc_data.list[i][len + 1]);
+ if (refreshApp(path) == 1)
+ refresh_data->refreshed++;
+ else
+ sceIoRename(path, dlc_data.list[i]);
+ SetProgress(++refresh_data->processed, refresh_data->count);
+ free(dlc_data.list[i]);
+ }
+ }
+ }
+}
+
+int refresh_thread(SceSize args, void *argp)
+{
+ SceUID thid = -1;
+ refresh_data_t refresh_data = { 0, 0, 0, 0 };
+
+ // Lock power timers
+ powerLock();
+
+ // Set progress to 0%
+ sceMsgDialogProgressBarSetValue(SCE_MSG_DIALOG_PROGRESSBAR_TARGET_BAR_DEFAULT, 0);
+ sceKernelDelayThread(DIALOG_WAIT); // Needed to see the percentage
+
+ // Get the app count
+ if (parse_dir_with_callback(SCE_S_IFDIR, "ux0:app", app_callback, &refresh_data) < 0)
+ goto EXIT;
+
+ // Get the dlc count
+ if (parse_dir_with_callback(SCE_S_IFDIR, "ux0:addcont", dlc_callback_outer, &refresh_data) < 0)
+ goto EXIT;
+
+ // Update thread
+ thid = createStartUpdateThread(refresh_data.count, 0);
+
+ // Make sure we have the temp directories we need
+ sceIoMkdir("ux0:temp", 0006);
+ sceIoMkdir("ux0:temp/addcont", 0006);
+ refresh_data.refresh_pass = 1;
+
+ // Refresh apps
+ if (parse_dir_with_callback(SCE_S_IFDIR, "ux0:app", app_callback, &refresh_data) < 0)
+ goto EXIT;
+
+ // Refresh dlc
+ if (parse_dir_with_callback(SCE_S_IFDIR, "ux0:addcont", dlc_callback_outer, &refresh_data) < 0)
+ goto EXIT;
+
+ sceIoRmdir("ux0:temp/addcont");
+
+ // Set progress to 100%
+ sceMsgDialogProgressBarSetValue(SCE_MSG_DIALOG_PROGRESSBAR_TARGET_BAR_DEFAULT, 100);
+ sceKernelDelayThread(COUNTUP_WAIT);
+
+ // Close
+ closeWaitDialog();
+
+ infoDialog(language_container[REFRESHED], refresh_data.refreshed);
+
+EXIT:
+ if (thid >= 0)
+ sceKernelWaitThreadEnd(thid, NULL, NULL);
+
+ // Unlock power timers
+ powerUnlock();
+
+ return sceKernelExitDeleteThread(0);
+}
+
+// Note: This is currently not optimized AT ALL.
+// Ultimately, we want to use a single transaction and avoid trying to
+// re-insert rifs that are already present.
+void license_file_callback(void* data, const char* dir, const char* file)
+{
+ license_data_t *license_data = (license_data_t*)data;
+ char path[MAX_PATH_LENGTH];
+
+ // Ignore non rif content
+ if ((strlen(file) < 4) || (strcasecmp(&file[strlen(file) - 4], ".rif") != 0))
+ return;
+ if (license_data->copy_pass) {
+ snprintf(path, sizeof(path), "%s/%s", dir, file);
+ SceUID fd = sceIoOpen(path, SCE_O_RDONLY, 0777);
+ if (fd > 0) {
+ int read = sceIoRead(fd, license_data->rif, RIF_SIZE);
+ if (read == RIF_SIZE) {
+ if (insert_rif(LICENSE_DB, license_data->rif) == 0)
+ license_data->copied++;
+ }
+ sceIoClose(fd);
+ }
+ SetProgress(++license_data->processed, license_data->count);
+ } else {
+ license_data->count++;
+ }
+}
+
+void license_dir_callback(void* data, const char* dir, const char* subdir)
+{
+ license_data_t *license_data = (license_data_t*)data;
+ char path[MAX_PATH_LENGTH];
+
+ snprintf(path, sizeof(path), "%s/%s", dir, subdir);
+ if (++license_data->cur_depth == license_data->max_depth)
+ parse_dir_with_callback(SCE_S_IFREG, path, license_file_callback, data);
+ else
+ parse_dir_with_callback(SCE_S_IFDIR, path, license_dir_callback, data);
+ license_data->cur_depth--;
+}
+
+int license_thread(SceSize args, void *argp)
+{
+ SceUID thid = -1;
+ license_data_t license_data = { 0, 0, 0, 0, 0, 1, malloc(RIF_SIZE) };
+
+ if (license_data.rif == NULL)
+ goto EXIT;
+
+ // Lock power timers
+ powerLock();
+
+ // Set progress to 0%
+ sceMsgDialogProgressBarSetValue(SCE_MSG_DIALOG_PROGRESSBAR_TARGET_BAR_DEFAULT, 0);
+ sceKernelDelayThread(DIALOG_WAIT); // Needed to see the percentage
+
+ // NB: ux0:license access requires elevated permisions
+ if (parse_dir_with_callback(SCE_S_IFDIR, "ux0:license/app", license_dir_callback, &license_data) < 0)
+ goto EXIT;
+ license_data.max_depth++;
+ if (parse_dir_with_callback(SCE_S_IFDIR, "ux0:license/addcont", license_dir_callback, &license_data) < 0)
+ goto EXIT;
+
+ // Update thread
+ thid = createStartUpdateThread(license_data.count, 0);
+
+ // Create the DB if needed
+ SceUID fd = sceIoOpen(LICENSE_DB, SCE_O_RDONLY, 0777);
+ if (fd > 0) {
+ sceIoClose(fd);
+ } else if (create_db(LICENSE_DB, LICENSE_DB_SCHEMA) != 0) {
+ goto EXIT;
+ }
+
+ // Insert the licenses
+ license_data.copy_pass = 1;
+ license_data.max_depth = 1;
+ if (parse_dir_with_callback(SCE_S_IFDIR, "ux0:license/app", license_dir_callback, &license_data) < 0)
+ goto EXIT;
+ license_data.max_depth++;
+ if (parse_dir_with_callback(SCE_S_IFDIR, "ux0:license/addcont", license_dir_callback, &license_data) < 0)
+ goto EXIT;
+
+ // Set progress to 100%
+ sceMsgDialogProgressBarSetValue(SCE_MSG_DIALOG_PROGRESSBAR_TARGET_BAR_DEFAULT, 100);
+ sceKernelDelayThread(COUNTUP_WAIT);
+
+ // Close
+ closeWaitDialog();
+
+ infoDialog(language_container[IMPORTED_LICENSES], license_data.copied);
+
+EXIT:
+ if (thid >= 0)
+ sceKernelWaitThreadEnd(thid, NULL, NULL);
+
+ // Unlock power timers
+ powerUnlock();
+
+ free(license_data.rif);
+ return sceKernelExitDeleteThread(0);
+}
diff --git a/sfo.c b/sfo.c
index 0ed2158..8269bab 100644
--- a/sfo.c
+++ b/sfo.c
@@ -1,194 +1,194 @@
-/*
- VitaShell
- Copyright (C) 2015-2018, TheFloW
-
- 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, either version 3 of the License, or
- (at your option) any later version.
-
- 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 for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
-*/
-
-#include "main.h"
-#include "archive.h"
-#include "file.h"
-#include "text.h"
-#include "hex.h"
-#include "message_dialog.h"
-#include "theme.h"
-#include "language.h"
-#include "utils.h"
-#include "sfo.h"
-
-int getSfoValue(void *buffer, const char *name, uint32_t *value) {
- SfoHeader *header = (SfoHeader *)buffer;
- SfoEntry *entries = (SfoEntry *)((uint32_t)buffer + sizeof(SfoHeader));
-
- if (header->magic != SFO_MAGIC)
- return VITASHELL_ERROR_INVALID_MAGIC;
-
- int i;
- for (i = 0; i < header->count; i++) {
- if (strcmp(buffer + header->keyofs + entries[i].nameofs, name) == 0) {
- *value = *(uint32_t *)(buffer + header->valofs + entries[i].dataofs);
- return 0;
- }
- }
-
- return VITASHELL_ERROR_NOT_FOUND;
-}
-
-int getSfoString(void *buffer, const char *name, char *string, int length) {
- SfoHeader *header = (SfoHeader *)buffer;
- SfoEntry *entries = (SfoEntry *)((uint32_t)buffer + sizeof(SfoHeader));
-
- if (header->magic != SFO_MAGIC)
- return VITASHELL_ERROR_INVALID_MAGIC;
-
- int i;
- for (i = 0; i < header->count; i++) {
- if (strcmp(buffer + header->keyofs + entries[i].nameofs, name) == 0) {
- memset(string, 0, length);
- strncpy(string, buffer + header->valofs + entries[i].dataofs, length);
- string[length - 1] = '\0';
- return 0;
- }
- }
-
- return VITASHELL_ERROR_NOT_FOUND;
-}
-
-int setSfoValue(void *buffer, const char *name, uint32_t value) {
- SfoHeader *header = (SfoHeader *)buffer;
- SfoEntry *entries = (SfoEntry *)((uint32_t)buffer + sizeof(SfoHeader));
-
- if (header->magic != SFO_MAGIC)
- return VITASHELL_ERROR_INVALID_MAGIC;
-
- int i;
- for (i = 0; i < header->count; i++) {
- if (strcmp(buffer + header->keyofs + entries[i].nameofs, name) == 0) {
- *(uint32_t *)(buffer + header->valofs + entries[i].dataofs) = value;
- return 0;
- }
- }
-
- return VITASHELL_ERROR_NOT_FOUND;
-}
-
-int setSfoString(void *buffer, const char *name, const char *string) {
- SfoHeader *header = (SfoHeader *)buffer;
- SfoEntry *entries = (SfoEntry *)((uint32_t)buffer + sizeof(SfoHeader));
-
- if (header->magic != SFO_MAGIC)
- return VITASHELL_ERROR_INVALID_MAGIC;
-
- int i;
- for (i = 0; i < header->count; i++) {
- if (strcmp(buffer + header->keyofs + entries[i].nameofs, name) == 0) {
- strcpy(buffer + header->valofs + entries[i].dataofs, string);
- return 0;
- }
- }
-
- return VITASHELL_ERROR_NOT_FOUND;
-}
-
-int SFOReader(const char *file) {
- uint8_t *buffer = memalign(4096, BIG_BUFFER_SIZE);
- if (!buffer)
- return VITASHELL_ERROR_NO_MEMORY;
-
- int size = 0;
-
- if (isInArchive()) {
- size = ReadArchiveFile(file, buffer, BIG_BUFFER_SIZE);
- } else {
- size = ReadFile(file, buffer, BIG_BUFFER_SIZE);
- }
-
- if (size <= 0) {
- free(buffer);
- return size;
- }
-
- SfoHeader *sfo_header = (SfoHeader *)buffer;
- if (sfo_header->magic != SFO_MAGIC)
- return VITASHELL_ERROR_INVALID_MAGIC;
-
- int base_pos = 0, rel_pos = 0;
-
- while (1) {
- readPad();
-
- if (pressed_pad[PAD_CANCEL]) {
- break;
- }
-
- if (hold_pad[PAD_UP] || hold2_pad[PAD_LEFT_ANALOG_UP]) {
- if (rel_pos > 0) {
- rel_pos--;
- } else if (base_pos > 0) {
- base_pos--;
- }
- } else if (hold_pad[PAD_DOWN] || hold2_pad[PAD_LEFT_ANALOG_DOWN]) {
- if ((rel_pos + 1) < sfo_header->count) {
- if ((rel_pos + 1) < MAX_POSITION) {
- rel_pos++;
- } else if ((base_pos + rel_pos + 1) < sfo_header->count) {
- base_pos++;
- }
- }
- }
-
- // Start drawing
- startDrawing(bg_text_image);
-
- // Draw shell info
- drawShellInfo(file);
-
- // Draw scroll bar
- drawScrollBar(base_pos, sfo_header->count);
-
- int i;
- for (i = 0; i < MAX_ENTRIES && (base_pos + i) < sfo_header->count; i++) {
- SfoEntry *entries = (SfoEntry *)(buffer + sizeof(SfoHeader) + (sizeof(SfoEntry) * (i + base_pos)));
-
- uint32_t color = (rel_pos == i) ? TEXT_FOCUS_COLOR : TEXT_COLOR;
-
- char *name = (char *)buffer + sfo_header->keyofs + entries->nameofs;
- pgf_draw_textf(SHELL_MARGIN_X, START_Y + (FONT_Y_SPACE * i), color, "%s", name);
-
- char string[128];
-
- void *data = (void *)buffer + sfo_header->valofs + entries->dataofs;
- switch (entries->type) {
- case PSF_TYPE_BIN:
- break;
-
- case PSF_TYPE_STR:
- snprintf(string, sizeof(string), "%s", (char *)data);
- break;
-
- case PSF_TYPE_VAL:
- snprintf(string, sizeof(string), "0x%X", *(unsigned int *)data);
- break;
- }
-
- pgf_draw_textf(ALIGN_RIGHT(INFORMATION_X, pgf_text_width(string)), START_Y + (FONT_Y_SPACE * i), color, string);
- }
-
- // End drawing
- endDrawing();
- }
-
- free(buffer);
- return 0;
-}
+/*
+ VitaShell
+ Copyright (C) 2015-2018, TheFloW
+
+ 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, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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 for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+#include "main.h"
+#include "archive.h"
+#include "file.h"
+#include "text.h"
+#include "hex.h"
+#include "message_dialog.h"
+#include "theme.h"
+#include "language.h"
+#include "utils.h"
+#include "sfo.h"
+
+int getSfoValue(void *buffer, const char *name, uint32_t *value) {
+ SfoHeader *header = (SfoHeader *)buffer;
+ SfoEntry *entries = (SfoEntry *)((uint32_t)buffer + sizeof(SfoHeader));
+
+ if (header->magic != SFO_MAGIC)
+ return VITASHELL_ERROR_INVALID_MAGIC;
+
+ int i;
+ for (i = 0; i < header->count; i++) {
+ if (strcmp(buffer + header->keyofs + entries[i].nameofs, name) == 0) {
+ *value = *(uint32_t *)(buffer + header->valofs + entries[i].dataofs);
+ return 0;
+ }
+ }
+
+ return VITASHELL_ERROR_NOT_FOUND;
+}
+
+int getSfoString(void *buffer, const char *name, char *string, int length) {
+ SfoHeader *header = (SfoHeader *)buffer;
+ SfoEntry *entries = (SfoEntry *)((uint32_t)buffer + sizeof(SfoHeader));
+
+ if (header->magic != SFO_MAGIC)
+ return VITASHELL_ERROR_INVALID_MAGIC;
+
+ int i;
+ for (i = 0; i < header->count; i++) {
+ if (strcmp(buffer + header->keyofs + entries[i].nameofs, name) == 0) {
+ memset(string, 0, length);
+ strncpy(string, buffer + header->valofs + entries[i].dataofs, length);
+ string[length - 1] = '\0';
+ return 0;
+ }
+ }
+
+ return VITASHELL_ERROR_NOT_FOUND;
+}
+
+int setSfoValue(void *buffer, const char *name, uint32_t value) {
+ SfoHeader *header = (SfoHeader *)buffer;
+ SfoEntry *entries = (SfoEntry *)((uint32_t)buffer + sizeof(SfoHeader));
+
+ if (header->magic != SFO_MAGIC)
+ return VITASHELL_ERROR_INVALID_MAGIC;
+
+ int i;
+ for (i = 0; i < header->count; i++) {
+ if (strcmp(buffer + header->keyofs + entries[i].nameofs, name) == 0) {
+ *(uint32_t *)(buffer + header->valofs + entries[i].dataofs) = value;
+ return 0;
+ }
+ }
+
+ return VITASHELL_ERROR_NOT_FOUND;
+}
+
+int setSfoString(void *buffer, const char *name, const char *string) {
+ SfoHeader *header = (SfoHeader *)buffer;
+ SfoEntry *entries = (SfoEntry *)((uint32_t)buffer + sizeof(SfoHeader));
+
+ if (header->magic != SFO_MAGIC)
+ return VITASHELL_ERROR_INVALID_MAGIC;
+
+ int i;
+ for (i = 0; i < header->count; i++) {
+ if (strcmp(buffer + header->keyofs + entries[i].nameofs, name) == 0) {
+ strcpy(buffer + header->valofs + entries[i].dataofs, string);
+ return 0;
+ }
+ }
+
+ return VITASHELL_ERROR_NOT_FOUND;
+}
+
+int SFOReader(const char *file) {
+ uint8_t *buffer = memalign(4096, BIG_BUFFER_SIZE);
+ if (!buffer)
+ return VITASHELL_ERROR_NO_MEMORY;
+
+ int size = 0;
+
+ if (isInArchive()) {
+ size = ReadArchiveFile(file, buffer, BIG_BUFFER_SIZE);
+ } else {
+ size = ReadFile(file, buffer, BIG_BUFFER_SIZE);
+ }
+
+ if (size <= 0) {
+ free(buffer);
+ return size;
+ }
+
+ SfoHeader *sfo_header = (SfoHeader *)buffer;
+ if (sfo_header->magic != SFO_MAGIC)
+ return VITASHELL_ERROR_INVALID_MAGIC;
+
+ int base_pos = 0, rel_pos = 0;
+
+ while (1) {
+ readPad();
+
+ if (pressed_pad[PAD_CANCEL]) {
+ break;
+ }
+
+ if (hold_pad[PAD_UP] || hold2_pad[PAD_LEFT_ANALOG_UP]) {
+ if (rel_pos > 0) {
+ rel_pos--;
+ } else if (base_pos > 0) {
+ base_pos--;
+ }
+ } else if (hold_pad[PAD_DOWN] || hold2_pad[PAD_LEFT_ANALOG_DOWN]) {
+ if ((rel_pos + 1) < sfo_header->count) {
+ if ((rel_pos + 1) < MAX_POSITION) {
+ rel_pos++;
+ } else if ((base_pos + rel_pos + 1) < sfo_header->count) {
+ base_pos++;
+ }
+ }
+ }
+
+ // Start drawing
+ startDrawing(bg_text_image);
+
+ // Draw shell info
+ drawShellInfo(file);
+
+ // Draw scroll bar
+ drawScrollBar(base_pos, sfo_header->count);
+
+ int i;
+ for (i = 0; i < MAX_ENTRIES && (base_pos + i) < sfo_header->count; i++) {
+ SfoEntry *entries = (SfoEntry *)(buffer + sizeof(SfoHeader) + (sizeof(SfoEntry) * (i + base_pos)));
+
+ uint32_t color = (rel_pos == i) ? TEXT_FOCUS_COLOR : TEXT_COLOR;
+
+ char *name = (char *)buffer + sfo_header->keyofs + entries->nameofs;
+ pgf_draw_textf(SHELL_MARGIN_X, START_Y + (FONT_Y_SPACE * i), color, "%s", name);
+
+ char string[128];
+
+ void *data = (void *)buffer + sfo_header->valofs + entries->dataofs;
+ switch (entries->type) {
+ case PSF_TYPE_BIN:
+ break;
+
+ case PSF_TYPE_STR:
+ snprintf(string, sizeof(string), "%s", (char *)data);
+ break;
+
+ case PSF_TYPE_VAL:
+ snprintf(string, sizeof(string), "0x%X", *(unsigned int *)data);
+ break;
+ }
+
+ pgf_draw_textf(ALIGN_RIGHT(INFORMATION_X, pgf_text_width(string)), START_Y + (FONT_Y_SPACE * i), color, string);
+ }
+
+ // End drawing
+ endDrawing();
+ }
+
+ free(buffer);
+ return 0;
+}
diff --git a/sfo.h b/sfo.h
index b94720f..10c9299 100644
--- a/sfo.h
+++ b/sfo.h
@@ -1,53 +1,53 @@
-/*
- VitaShell
- Copyright (C) 2015-2018, TheFloW
-
- 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, either version 3 of the License, or
- (at your option) any later version.
-
- 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 for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
-*/
-
-
-#ifndef __SFO_H__
-#define __SFO_H__
-
-#define SFO_MAGIC 0x46535000
-
-#define PSF_TYPE_BIN 0
-#define PSF_TYPE_STR 2
-#define PSF_TYPE_VAL 4
-
-typedef struct SfoHeader {
- uint32_t magic;
- uint32_t version;
- uint32_t keyofs;
- uint32_t valofs;
- uint32_t count;
-} __attribute__((packed)) SfoHeader;
-
-typedef struct SfoEntry {
- uint16_t nameofs;
- uint8_t alignment;
- uint8_t type;
- uint32_t valsize;
- uint32_t totalsize;
- uint32_t dataofs;
-} __attribute__((packed)) SfoEntry;
-
-int getSfoValue(void *buffer, const char *name, uint32_t *value);
-int getSfoString(void *buffer, const char *name, char *string, int length);
-int setSfoValue(void *buffer, const char *name, uint32_t value);
-int setSfoString(void *buffer, const char *name, const char *string);
-
-int SFOReader(const char *file);
-
+/*
+ VitaShell
+ Copyright (C) 2015-2018, TheFloW
+
+ 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, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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 for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+
+#ifndef __SFO_H__
+#define __SFO_H__
+
+#define SFO_MAGIC 0x46535000
+
+#define PSF_TYPE_BIN 0
+#define PSF_TYPE_STR 2
+#define PSF_TYPE_VAL 4
+
+typedef struct SfoHeader {
+ uint32_t magic;
+ uint32_t version;
+ uint32_t keyofs;
+ uint32_t valofs;
+ uint32_t count;
+} __attribute__((packed)) SfoHeader;
+
+typedef struct SfoEntry {
+ uint16_t nameofs;
+ uint8_t alignment;
+ uint8_t type;
+ uint32_t valsize;
+ uint32_t totalsize;
+ uint32_t dataofs;
+} __attribute__((packed)) SfoEntry;
+
+int getSfoValue(void *buffer, const char *name, uint32_t *value);
+int getSfoString(void *buffer, const char *name, char *string, int length);
+int setSfoValue(void *buffer, const char *name, uint32_t value);
+int setSfoString(void *buffer, const char *name, const char *string);
+
+int SFOReader(const char *file);
+
#endif
\ No newline at end of file