mirror of
https://github.com/astronautlevel2/Anemone3DS.git
synced 2026-01-24 08:42:43 -05:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0a23b20f6e | |||
| a8cc3ebfc3 | |||
| b1454bf2a1 | |||
| 1a2efdc129 | |||
| e613a525a5 |
@@ -30,7 +30,7 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "badges.h"
|
#include "badges.h"
|
||||||
|
|
||||||
#define ILLEGAL_CHARS "><\"?;:/\\+,.|[=]*"
|
#define ILLEGAL_CHARS "><\"?;:/\\+,.|[=]*\n\r"
|
||||||
|
|
||||||
extern FS_Archive ArchiveSD;
|
extern FS_Archive ArchiveSD;
|
||||||
extern FS_Archive ArchiveHomeExt;
|
extern FS_Archive ArchiveHomeExt;
|
||||||
|
|||||||
@@ -29,9 +29,10 @@
|
|||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
ssize_t strulen(const u16 *, ssize_t);
|
void replace_chars(u16 *input, char *remove, u16 with);
|
||||||
|
size_t strulen(const u16 *, ssize_t);
|
||||||
void struacat(u16 * input, const char * addition);
|
void struacat(u16 * input, const char * addition);
|
||||||
void printu(u16 * input);
|
void printu(u16 * input);
|
||||||
u16 * strucat(u16 * destination, const u16 * source);
|
size_t strucat(u16 * destination, const u16 * source);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
108
source/badges.c
108
source/badges.c
@@ -115,7 +115,7 @@ u64 getShortcut(char *filename)
|
|||||||
if (sscanf(p1, "%08x", &lowpath) != 1) return shortcut;
|
if (sscanf(p1, "%08x", &lowpath) != 1) return shortcut;
|
||||||
|
|
||||||
shortcut = 0x0004001000000000 + lowpath;
|
shortcut = 0x0004001000000000 + lowpath;
|
||||||
DEBUG("Shortcut %llu found for %s\n", shortcut, filename);
|
DEBUG("Shortcut %16llx found for %s\n", shortcut, filename);
|
||||||
return shortcut;
|
return shortcut;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,7 +237,7 @@ int install_badge_dir(FS_DirectoryEntry set_dir, int *badge_count, int set_id)
|
|||||||
strucat(path, badge_files[i].name);
|
strucat(path, badge_files[i].name);
|
||||||
if (!memcmp(set_icon, badge_files[i].name, 16))
|
if (!memcmp(set_icon, badge_files[i].name, 16))
|
||||||
{
|
{
|
||||||
DEBUG("Found set icon\n");
|
DEBUG("Found set icon for folder set %d\n", set_id);
|
||||||
icon_size = file_to_buf(fsMakePath(PATH_UTF16, path), ArchiveSD, &icon_buf);
|
icon_size = file_to_buf(fsMakePath(PATH_UTF16, path), ArchiveSD, &icon_buf);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -299,6 +299,7 @@ int install_badge_dir(FS_DirectoryEntry set_dir, int *badge_count, int set_id)
|
|||||||
badgeMngBuffer[0x3D8 + set_index/8] |= 0 << (set_index % 8);
|
badgeMngBuffer[0x3D8 + set_index/8] |= 0 << (set_index % 8);
|
||||||
end:
|
end:
|
||||||
free(badge_files);
|
free(badge_files);
|
||||||
|
FSDIR_Close(folder);
|
||||||
return badges_in_set;
|
return badges_in_set;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -349,17 +350,24 @@ SetNode * extract_sets(char *badgeMngBuffer, Handle backupDataHandle)
|
|||||||
|
|
||||||
if (cursor->set_id != 0xEFBE) // 0xEFBE is GYTB Set ID; GYTB doesn't properly create sets, so skip
|
if (cursor->set_id != 0xEFBE) // 0xEFBE is GYTB Set ID; GYTB doesn't properly create sets, so skip
|
||||||
{
|
{
|
||||||
|
DEBUG("Processing icon for set %lu at index %lu\n", cursor->set_id, cursor->set_index);
|
||||||
u16 utf16SetName[0x46] = {0};
|
u16 utf16SetName[0x46] = {0};
|
||||||
FSFILE_Read(backupDataHandle, NULL, cursor->set_index * 16 * 0x8A, utf16SetName, 0x8A);
|
FSFILE_Read(backupDataHandle, NULL, cursor->set_index * 16 * 0x8A, utf16SetName, 0x8A);
|
||||||
|
replace_chars(utf16SetName, ILLEGAL_CHARS, u'-');
|
||||||
u16 set_path[256] = {0};
|
u16 set_path[256] = {0};
|
||||||
struacat(set_path, "/3ds/" APP_TITLE "/BadgeBackups/");
|
struacat(set_path, "/3ds/" APP_TITLE "/BadgeBackups/");
|
||||||
strucat(set_path, utf16SetName);
|
size_t set_name_len = strucat(set_path, utf16SetName);
|
||||||
|
if (!set_name_len)
|
||||||
|
{
|
||||||
|
struacat(set_path, "Unknown Set");
|
||||||
|
}
|
||||||
FSUSER_CreateDirectory(ArchiveSD, fsMakePath(PATH_UTF16, set_path), FS_ATTRIBUTE_DIRECTORY);
|
FSUSER_CreateDirectory(ArchiveSD, fsMakePath(PATH_UTF16, set_path), FS_ATTRIBUTE_DIRECTORY);
|
||||||
memset(icon_alpha_buf, 255, 64 * 64 * 0.5);
|
memset(icon_alpha_buf, 255, 64 * 64 * 0.5);
|
||||||
FSFILE_Read(backupDataHandle, NULL, 0x250F80 + cursor->set_index * 0x2000, icon_rgb_buf, 0x2000);
|
FSFILE_Read(backupDataHandle, NULL, 0x250F80 + cursor->set_index * 0x2000, icon_rgb_buf, 0x2000);
|
||||||
char filename[256] = {0};
|
char filename[256] = {0};
|
||||||
utf16_to_utf8((u8 *) filename, set_path, 256);
|
utf16_to_utf8((u8 *) filename, set_path, 256);
|
||||||
strcat(filename, "/_seticon.png");
|
strcat(filename, "/_seticon.png");
|
||||||
|
DEBUG("%s\n", filename);
|
||||||
rgb565ToPngFile(filename, icon_rgb_buf, icon_alpha_buf, 48, 48);
|
rgb565ToPngFile(filename, icon_rgb_buf, icon_alpha_buf, 48, 48);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -396,7 +404,9 @@ Result extract_badges(void)
|
|||||||
free(badgeMngBuffer);
|
free(badgeMngBuffer);
|
||||||
free(badge_rgb_buf);
|
free(badge_rgb_buf);
|
||||||
free(badge_alpha_buf);
|
free(badge_alpha_buf);
|
||||||
throw_error(language.badges.extdata_locked, ERROR_LEVEL_WARNING);
|
char err_string[128] = {0};
|
||||||
|
sprintf(err_string, language.badges.extdata_locked, res);
|
||||||
|
throw_error(err_string, ERROR_LEVEL_WARNING);
|
||||||
DEBUG("backupDataHandle open failed\n");
|
DEBUG("backupDataHandle open failed\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -422,6 +432,7 @@ Result extract_badges(void)
|
|||||||
|
|
||||||
u16 utf16Name[0x46] = {0};
|
u16 utf16Name[0x46] = {0};
|
||||||
FSFILE_Read(backupDataHandle, NULL, 0x35E80 + i * 16 * 0x8A, utf16Name, 0x8A);
|
FSFILE_Read(backupDataHandle, NULL, 0x35E80 + i * 16 * 0x8A, utf16Name, 0x8A);
|
||||||
|
replace_chars(utf16Name, ILLEGAL_CHARS, u'-');
|
||||||
char utf8Name[256] = {0};
|
char utf8Name[256] = {0};
|
||||||
res = utf16_to_utf8((u8 *) utf8Name, utf16Name, 256);
|
res = utf16_to_utf8((u8 *) utf8Name, utf16Name, 256);
|
||||||
|
|
||||||
@@ -435,8 +446,11 @@ Result extract_badges(void)
|
|||||||
{
|
{
|
||||||
u16 utf16SetName[0x46] = {0};
|
u16 utf16SetName[0x46] = {0};
|
||||||
FSFILE_Read(backupDataHandle, NULL, set_index * 16 * 0x8A, utf16SetName, 0x8A);
|
FSFILE_Read(backupDataHandle, NULL, set_index * 16 * 0x8A, utf16SetName, 0x8A);
|
||||||
|
replace_chars(utf16SetName, ILLEGAL_CHARS, u'-');
|
||||||
char utf8SetName[128] = {0};
|
char utf8SetName[128] = {0};
|
||||||
res = utf16_to_utf8((u8 *) utf8SetName, utf16SetName, 128);
|
res = utf16_to_utf8((u8 *) utf8SetName, utf16SetName, 128);
|
||||||
|
if (!res)
|
||||||
|
strncpy(utf8SetName, "Unknown Set", 128);
|
||||||
DEBUG("UTF-8 Set Name: %s; ID: %lx\n", utf8SetName, badgeSetId);
|
DEBUG("UTF-8 Set Name: %s; ID: %lx\n", utf8SetName, badgeSetId);
|
||||||
sprintf(dir, "/3ds/" APP_TITLE "/BadgeBackups/%s", utf8SetName);
|
sprintf(dir, "/3ds/" APP_TITLE "/BadgeBackups/%s", utf8SetName);
|
||||||
}
|
}
|
||||||
@@ -461,16 +475,94 @@ Result extract_badges(void)
|
|||||||
free(badge_rgb_buf);
|
free(badge_rgb_buf);
|
||||||
free(badge_alpha_buf);
|
free(badge_alpha_buf);
|
||||||
free_list(head);
|
free_list(head);
|
||||||
|
FSFILE_Close(backupDataHandle);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result backup_badges_fast(void)
|
||||||
|
{
|
||||||
|
char *badgeMng = NULL;
|
||||||
|
|
||||||
|
DEBUG("writing badge data: making files...\n");
|
||||||
|
char mng_path[128] = "/3ds/" APP_TITLE "/BadgeMngFile.dat";
|
||||||
|
char data_path[128] = "/3ds/" APP_TITLE "/BadgeData.dat";
|
||||||
|
DEBUG("mng_path: %s, data_path: %s\n", mng_path, data_path);
|
||||||
|
|
||||||
|
Handle dataHandle = 0;
|
||||||
|
Handle sdHandle = 0;
|
||||||
|
|
||||||
|
DEBUG("loading existing badge mng file...\n");
|
||||||
|
u32 mngRead = file_to_buf(fsMakePath(PATH_ASCII, "/BadgeMngFile.dat"), ArchiveBadgeExt, &badgeMng);
|
||||||
|
DEBUG("loading existing badge data file\n");
|
||||||
|
Result res = FSUSER_OpenFile(&dataHandle, ArchiveBadgeExt, fsMakePath(PATH_ASCII, "/BadgeData.dat"), FS_OPEN_READ, 0);
|
||||||
|
if (mngRead != BADGE_MNG_SIZE || R_FAILED(res))
|
||||||
|
{
|
||||||
|
char err_string[128] = {0};
|
||||||
|
sprintf(err_string, language.badges.extdata_locked, res);
|
||||||
|
throw_error(err_string, ERROR_LEVEL_WARNING);
|
||||||
|
if (badgeMng) free(badgeMng);
|
||||||
|
if (dataHandle) FSFILE_Close(dataHandle);
|
||||||
|
FSFILE_Close(sdHandle);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
remake_file(fsMakePath(PATH_ASCII, mng_path), ArchiveSD, BADGE_MNG_SIZE);
|
||||||
|
|
||||||
|
FSUSER_CreateFile(ArchiveSD, fsMakePath(PATH_ASCII, data_path), 0, BADGE_DATA_SIZE);
|
||||||
|
FSUSER_OpenFile(&sdHandle, ArchiveSD, fsMakePath(PATH_ASCII, data_path), FS_OPEN_WRITE, 0);
|
||||||
|
|
||||||
|
DEBUG("writing badge data: writing BadgeMngFile...\n");
|
||||||
|
res = buf_to_file(mngRead, fsMakePath(PATH_ASCII, mng_path), ArchiveSD, badgeMng);
|
||||||
|
if (R_FAILED(res))
|
||||||
|
{
|
||||||
|
DEBUG("Failed to write badgemngfile: 0x%08lx\n", res);
|
||||||
|
free(badgeMng);
|
||||||
|
FSFILE_Close(dataHandle);
|
||||||
|
FSFILE_Close(sdHandle);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
DEBUG("writing badge data: writing badgedata...\n");
|
||||||
|
char *buf = malloc(0x10000);
|
||||||
|
u64 size = BADGE_DATA_SIZE;
|
||||||
|
u64 cur = 0;
|
||||||
|
while (size > 0)
|
||||||
|
{
|
||||||
|
u32 read = 0;
|
||||||
|
res = FSFILE_Read(dataHandle, &read, cur, buf, min(0x10000, size));
|
||||||
|
res = FSFILE_Write(sdHandle, NULL, cur, buf, read, FS_WRITE_FLUSH);
|
||||||
|
size -= read;
|
||||||
|
cur += read;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(badgeMng);
|
||||||
|
free(buf);
|
||||||
|
FSFILE_Close(dataHandle);
|
||||||
|
FSFILE_Close(sdHandle);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
Result install_badges(void)
|
Result install_badges(void)
|
||||||
{
|
{
|
||||||
Handle handle = 0;
|
Handle handle = 0;
|
||||||
Handle folder = 0;
|
Handle folder = 0;
|
||||||
Result res = 0;
|
Result res = 0;
|
||||||
draw_loading_bar(0, 1, INSTALL_BADGES);
|
draw_loading_bar(0, 1, INSTALL_BADGES);
|
||||||
|
{
|
||||||
|
char testpath[128] = "/3ds/" APP_TITLE "/BadgeData.dat";
|
||||||
|
if (R_FAILED(res = FSUSER_OpenFile(&handle, ArchiveSD, fsMakePath(PATH_ASCII, testpath), FS_OPEN_READ, 0)))
|
||||||
|
{
|
||||||
|
if (R_SUMMARY(res) == RS_NOTFOUND)
|
||||||
|
{
|
||||||
|
res = backup_badges_fast();
|
||||||
|
if (R_FAILED(res)) return res;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
DEBUG("????: 0x%08lx\n", res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handle) FSFILE_Close(handle);
|
||||||
|
|
||||||
DEBUG("Initializing ACT\n");
|
DEBUG("Initializing ACT\n");
|
||||||
res = actInit();
|
res = actInit();
|
||||||
@@ -551,7 +643,9 @@ Result install_badges(void)
|
|||||||
if (R_FAILED(res))
|
if (R_FAILED(res))
|
||||||
{
|
{
|
||||||
badgeDataHandle = 0;
|
badgeDataHandle = 0;
|
||||||
throw_error(language.badges.extdata_locked, ERROR_LEVEL_WARNING);
|
char err_string[128] = {0};
|
||||||
|
sprintf(err_string, language.badges.extdata_locked, res);
|
||||||
|
throw_error(err_string, ERROR_LEVEL_WARNING);
|
||||||
DEBUG("badgeDataHandle open failed\n");
|
DEBUG("badgeDataHandle open failed\n");
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
@@ -682,7 +776,9 @@ Result install_badges(void)
|
|||||||
if (res)
|
if (res)
|
||||||
{
|
{
|
||||||
DEBUG("Error writing badge manage data! %lx\n", res);
|
DEBUG("Error writing badge manage data! %lx\n", res);
|
||||||
throw_error(language.badges.extdata_locked, ERROR_LEVEL_WARNING);
|
char err_string[128] = {0};
|
||||||
|
sprintf(err_string, language.badges.extdata_locked, res);
|
||||||
|
throw_error(err_string, ERROR_LEVEL_WARNING);
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -113,7 +113,6 @@ Result open_archives(void)
|
|||||||
FSUSER_CreateDirectory(ArchiveSD, fsMakePath(PATH_ASCII, "/3ds/" APP_TITLE), FS_ATTRIBUTE_DIRECTORY);
|
FSUSER_CreateDirectory(ArchiveSD, fsMakePath(PATH_ASCII, "/3ds/" APP_TITLE), FS_ATTRIBUTE_DIRECTORY);
|
||||||
FSUSER_CreateDirectory(ArchiveSD, fsMakePath(PATH_ASCII, "/3ds/" APP_TITLE "/cache"), FS_ATTRIBUTE_DIRECTORY);
|
FSUSER_CreateDirectory(ArchiveSD, fsMakePath(PATH_ASCII, "/3ds/" APP_TITLE "/cache"), FS_ATTRIBUTE_DIRECTORY);
|
||||||
FSUSER_CreateDirectory(ArchiveSD, fsMakePath(PATH_ASCII, "/3ds/" APP_TITLE "/BadgeBackups"), FS_ATTRIBUTE_DIRECTORY);
|
FSUSER_CreateDirectory(ArchiveSD, fsMakePath(PATH_ASCII, "/3ds/" APP_TITLE "/BadgeBackups"), FS_ATTRIBUTE_DIRECTORY);
|
||||||
FSUSER_CreateDirectory(ArchiveSD, fsMakePath(PATH_ASCII, "/3ds/" APP_TITLE "/BadgeBackups/Unknown Set"), FS_ATTRIBUTE_DIRECTORY);
|
|
||||||
|
|
||||||
u32 homeMenuPath[3] = {MEDIATYPE_SD, archive2, 0};
|
u32 homeMenuPath[3] = {MEDIATYPE_SD, archive2, 0};
|
||||||
home.type = PATH_BINARY;
|
home.type = PATH_BINARY;
|
||||||
@@ -229,7 +228,7 @@ u32 file_to_buf(FS_Path path, FS_Archive archive, char ** buf)
|
|||||||
Result res = 0;
|
Result res = 0;
|
||||||
if (R_FAILED(res = FSUSER_OpenFile(&file, archive, path, FS_OPEN_READ, 0)))
|
if (R_FAILED(res = FSUSER_OpenFile(&file, archive, path, FS_OPEN_READ, 0)))
|
||||||
{
|
{
|
||||||
DEBUG("file_to_buf failed - 0x%08ld\n", res);
|
DEBUG("file_to_buf failed - 0x%08lx\n", res);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -505,7 +504,8 @@ void remake_file(FS_Path path, FS_Archive archive, u32 size)
|
|||||||
FSFILE_Close(handle);
|
FSFILE_Close(handle);
|
||||||
FSUSER_DeleteFile(archive, path);
|
FSUSER_DeleteFile(archive, path);
|
||||||
}
|
}
|
||||||
FSUSER_CreateFile(archive, path, 0, size);
|
Result res = FSUSER_CreateFile(archive, path, 0, size);
|
||||||
|
DEBUG("Remake file res: 0x%08lx\n", res);
|
||||||
char * buf = calloc(size, 1);
|
char * buf = calloc(size, 1);
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -429,7 +429,7 @@ const Language_s language_english = {
|
|||||||
},
|
},
|
||||||
.badges =
|
.badges =
|
||||||
{
|
{
|
||||||
.extdata_locked = "Ext Data Locked\nTry pressing the Home Button and then returning\nto Anemone3DS, or using the CIA version instead."
|
.extdata_locked = "Ext Data Locked\nTry pressing the Home Button and then returning\nto Anemone3DS, or using the CIA version instead.\nDebug: 0x%08lx"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -835,7 +835,7 @@ const Language_s language_spanish = {
|
|||||||
},
|
},
|
||||||
.badges =
|
.badges =
|
||||||
{
|
{
|
||||||
.extdata_locked = "Datos Adicionales Bloqueados\nIntenta presionando el botón Home y vuelve a\nAnemone3DS, o usa la version CIA en su lugar."
|
.extdata_locked = "Datos Adicionales Bloqueados\nIntenta presionando el botón Home y vuelve a\nAnemone3DS, o usa la version CIA en su lugar.\nDebug: 0x%08lx"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1242,7 +1242,7 @@ const Language_s language_french = {
|
|||||||
},
|
},
|
||||||
.badges =
|
.badges =
|
||||||
{
|
{
|
||||||
.extdata_locked = "L'archive des badges est vérouillée.\nEssayez de redémarrer Anemone3DS,\nou utilisez la version CIA."
|
.extdata_locked = "L'archive des badges est vérouillée.\nEssayez de redémarrer Anemone3DS,\nou utilisez la version CIA.\nDebug: 0x%08lx"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1648,7 +1648,7 @@ const Language_s language_portuguese = {
|
|||||||
},
|
},
|
||||||
.badges =
|
.badges =
|
||||||
{
|
{
|
||||||
.extdata_locked = "Ext Data Bloqueado\nTente apertar o botão HOME e retornar\nao Anemone3DS, ou use a versão CIA."
|
.extdata_locked = "Ext Data Bloqueado\nTente apertar o botão HOME e retornar\nao Anemone3DS, ou use a versão CIA.\nDebug: 0x%08lx"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -2057,7 +2057,7 @@ const Language_s language_korean = {
|
|||||||
},
|
},
|
||||||
.badges =
|
.badges =
|
||||||
{
|
{
|
||||||
.extdata_locked = "Ext Data Locked\nTry pressing the Home Button\nand then returning to Anemone3DS,\nor using the CIA version instead."
|
.extdata_locked = "Ext Data Locked\nTry pressing the Home Button\nand then returning to Anemone3DS,\nor using the CIA version instead.\nDebug: 0x%08lx"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,18 @@
|
|||||||
|
|
||||||
#include "unicode.h"
|
#include "unicode.h"
|
||||||
|
|
||||||
ssize_t strulen(const u16 * input, ssize_t max_len)
|
void replace_chars(u16 *input, char *remove, u16 with)
|
||||||
|
{
|
||||||
|
for (u16 *cursor = input; *cursor != '\0'; cursor++)
|
||||||
|
{
|
||||||
|
if (strchr(remove, (char) (*cursor & 0xFF)))
|
||||||
|
{
|
||||||
|
*cursor = with;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t strulen(const u16 * input, ssize_t max_len)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < max_len; i++) if (input[i] == 0) return i;
|
for (int i = 0; i < max_len; i++) if (input[i] == 0) return i;
|
||||||
return max_len;
|
return max_len;
|
||||||
@@ -55,13 +66,13 @@ void printu(u16 * input)
|
|||||||
free(buf);
|
free(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 * strucat(u16 * destination, const u16 * source)
|
size_t strucat(u16 * destination, const u16 * source)
|
||||||
{
|
{
|
||||||
ssize_t dest_len = strulen(destination, 0x106);
|
size_t dest_len = strulen(destination, 0x106);
|
||||||
|
|
||||||
ssize_t source_len = strulen(source, 0x106);
|
size_t source_len = strulen(source, 0x106);
|
||||||
|
|
||||||
memcpy(&destination[dest_len], source, source_len * sizeof(u16));
|
memcpy(&destination[dest_len], source, source_len * sizeof(u16));
|
||||||
destination[min(dest_len + source_len, 0x106 - 1)] = 0;
|
destination[min(dest_len + source_len, 0x106 - 1)] = 0;
|
||||||
return destination;
|
return source_len;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user