mirror of
https://github.com/switchbrew/switch-tools.git
synced 2025-08-13 03:39:24 +02:00
Merge branch 'master' of https://github.com/switchbrew/switch-tools
This commit is contained in:
commit
73ce462b53
@ -2,7 +2,7 @@
|
|||||||
# Process this file with autoconf to produce a configure script.
|
# Process this file with autoconf to produce a configure script.
|
||||||
|
|
||||||
AC_PREREQ(2.61)
|
AC_PREREQ(2.61)
|
||||||
AC_INIT([switch-tools],[1.6.0],[https://github.com/switchbrew/switch-tools/issues])
|
AC_INIT([switch-tools],[1.7.0],[https://github.com/switchbrew/switch-tools/issues])
|
||||||
AC_CONFIG_SRCDIR([src/build_pfs0.c])
|
AC_CONFIG_SRCDIR([src/build_pfs0.c])
|
||||||
|
|
||||||
AM_INIT_AUTOMAKE([subdir-objects])
|
AM_INIT_AUTOMAKE([subdir-objects])
|
||||||
|
@ -31,7 +31,7 @@ typedef struct {
|
|||||||
u8 Unk;
|
u8 Unk;
|
||||||
u8 Flags;
|
u8 Flags;
|
||||||
KipSegment Segments[6];
|
KipSegment Segments[6];
|
||||||
u32 Capabilities[0x20];
|
u32 Capabilities[0x20];
|
||||||
} KipHeader;
|
} KipHeader;
|
||||||
|
|
||||||
uint8_t* ReadEntireFile(const char* fn, size_t* len_out) {
|
uint8_t* ReadEntireFile(const char* fn, size_t* len_out) {
|
||||||
@ -132,10 +132,11 @@ int cJSON_GetBooleanOptional(const cJSON *obj, const char *field, int *out) {
|
|||||||
fprintf(stderr, "Unknown boolean value in %s.\n", field);
|
fprintf(stderr, "Unknown boolean value in %s.\n", field);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} else {
|
return 1;
|
||||||
|
} else {
|
||||||
*out = 0;
|
*out = 0;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int cJSON_GetU64(const cJSON *obj, const char *field, u64 *out) {
|
int cJSON_GetU64(const cJSON *obj, const char *field, u64 *out) {
|
||||||
@ -202,7 +203,7 @@ int ParseKipConfiguration(const char *json, KipHeader *kip_hdr) {
|
|||||||
status = 0;
|
status = 0;
|
||||||
goto PARSE_CAPS_END;
|
goto PARSE_CAPS_END;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse name. */
|
/* Parse name. */
|
||||||
const cJSON *title_name = cJSON_GetObjectItemCaseSensitive(npdm_json, "name");
|
const cJSON *title_name = cJSON_GetObjectItemCaseSensitive(npdm_json, "name");
|
||||||
if (cJSON_IsString(title_name) && (title_name->valuestring != NULL)) {
|
if (cJSON_IsString(title_name) && (title_name->valuestring != NULL)) {
|
||||||
@ -212,13 +213,24 @@ int ParseKipConfiguration(const char *json, KipHeader *kip_hdr) {
|
|||||||
status = 0;
|
status = 0;
|
||||||
goto PARSE_CAPS_END;
|
goto PARSE_CAPS_END;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse title_id. */
|
/* Parse title_id. */
|
||||||
if (!cJSON_GetU64(npdm_json, "title_id", &kip_hdr->TitleId)) {
|
if (!cJSON_GetU64(npdm_json, "title_id", &kip_hdr->TitleId)) {
|
||||||
status = 0;
|
status = 0;
|
||||||
goto PARSE_CAPS_END;
|
goto PARSE_CAPS_END;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Parse use secure memory. */
|
||||||
|
/* This field is optional, and defaults to true (set before this function is called). */
|
||||||
|
int use_secure_memory = 1;
|
||||||
|
if (cJSON_GetBooleanOptional(npdm_json, "use_secure_memory", &use_secure_memory)) {
|
||||||
|
if (use_secure_memory) {
|
||||||
|
kip_hdr->Flags |= 0x20;
|
||||||
|
} else {
|
||||||
|
kip_hdr->Flags &= ~0x20;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Parse main_thread_stack_size. */
|
/* Parse main_thread_stack_size. */
|
||||||
u64 stack_size = 0;
|
u64 stack_size = 0;
|
||||||
if (!cJSON_GetU64(npdm_json, "main_thread_stack_size", &stack_size)) {
|
if (!cJSON_GetU64(npdm_json, "main_thread_stack_size", &stack_size)) {
|
||||||
@ -231,7 +243,7 @@ int ParseKipConfiguration(const char *json, KipHeader *kip_hdr) {
|
|||||||
goto PARSE_CAPS_END;
|
goto PARSE_CAPS_END;
|
||||||
}
|
}
|
||||||
kip_hdr->Segments[1].Attribute = (u32)(stack_size & 0xFFFFFFFF);
|
kip_hdr->Segments[1].Attribute = (u32)(stack_size & 0xFFFFFFFF);
|
||||||
|
|
||||||
/* Parse various config. */
|
/* Parse various config. */
|
||||||
if (!cJSON_GetU8(npdm_json, "main_thread_priority", &kip_hdr->MainThreadPriority)) {
|
if (!cJSON_GetU8(npdm_json, "main_thread_priority", &kip_hdr->MainThreadPriority)) {
|
||||||
status = 0;
|
status = 0;
|
||||||
@ -319,13 +331,13 @@ int ParseKipConfiguration(const char *json, KipHeader *kip_hdr) {
|
|||||||
u64 syscall_value = 0;
|
u64 syscall_value = 0;
|
||||||
cJSON_ArrayForEach(cur_syscall, value) {
|
cJSON_ArrayForEach(cur_syscall, value) {
|
||||||
if (cJSON_IsNumber(cur_syscall)) {
|
if (cJSON_IsNumber(cur_syscall)) {
|
||||||
syscall_value = (u64)cur_syscall->valueint;
|
syscall_value = (u64)cur_syscall->valueint;
|
||||||
} else if (!cJSON_IsString(cur_syscall) || !cJSON_GetU64(value, cur_syscall->string, &syscall_value)) {
|
} else if (!cJSON_IsString(cur_syscall) || !cJSON_GetU64(value, cur_syscall->string, &syscall_value)) {
|
||||||
fprintf(stderr, "Error: Syscall entries must be integers or hex strings.\n");
|
fprintf(stderr, "Error: Syscall entries must be integers or hex strings.\n");
|
||||||
status = 0;
|
status = 0;
|
||||||
goto PARSE_CAPS_END;
|
goto PARSE_CAPS_END;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (syscall_value >= 0x80) {
|
if (syscall_value >= 0x80) {
|
||||||
fprintf(stderr, "Error: All syscall entries must be numbers in [0, 0x7F]\n");
|
fprintf(stderr, "Error: All syscall entries must be numbers in [0, 0x7F]\n");
|
||||||
status = 0;
|
status = 0;
|
||||||
@ -369,7 +381,7 @@ int ParseKipConfiguration(const char *json, KipHeader *kip_hdr) {
|
|||||||
desc = (u32)((map_address >> 12) & 0x00FFFFFFULL);
|
desc = (u32)((map_address >> 12) & 0x00FFFFFFULL);
|
||||||
desc |= is_ro << 24;
|
desc |= is_ro << 24;
|
||||||
kip_hdr->Capabilities[cur_cap++] = (u32)((desc << 7) | (0x003F));
|
kip_hdr->Capabilities[cur_cap++] = (u32)((desc << 7) | (0x003F));
|
||||||
|
|
||||||
desc = (u32)((map_size >> 12) & 0x00FFFFFFULL);
|
desc = (u32)((map_size >> 12) & 0x00FFFFFFULL);
|
||||||
is_io ^= 1;
|
is_io ^= 1;
|
||||||
desc |= is_io << 24;
|
desc |= is_io << 24;
|
||||||
@ -433,7 +445,7 @@ int ParseKipConfiguration(const char *json, KipHeader *kip_hdr) {
|
|||||||
}
|
}
|
||||||
u64 kern_ver = 0;
|
u64 kern_ver = 0;
|
||||||
if (cJSON_IsNumber(value)) {
|
if (cJSON_IsNumber(value)) {
|
||||||
kern_ver = (u64)value->valueint;
|
kern_ver = (u64)value->valueint;
|
||||||
} else if (!cJSON_IsString(value) || !cJSON_GetU64FromObjectValue(value, &kern_ver)) {
|
} else if (!cJSON_IsString(value) || !cJSON_GetU64FromObjectValue(value, &kern_ver)) {
|
||||||
fprintf(stderr, "Error: Kernel version must be integer or hex strings.\n");
|
fprintf(stderr, "Error: Kernel version must be integer or hex strings.\n");
|
||||||
status = 0;
|
status = 0;
|
||||||
@ -481,11 +493,11 @@ int ParseKipConfiguration(const char *json, KipHeader *kip_hdr) {
|
|||||||
goto PARSE_CAPS_END;
|
goto PARSE_CAPS_END;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (u32 i = cur_cap; i < 0x20; i++) {
|
for (u32 i = cur_cap; i < 0x20; i++) {
|
||||||
kip_hdr->Capabilities[i] = 0xFFFFFFFF;
|
kip_hdr->Capabilities[i] = 0xFFFFFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = 1;
|
status = 1;
|
||||||
PARSE_CAPS_END:
|
PARSE_CAPS_END:
|
||||||
cJSON_Delete(npdm_json);
|
cJSON_Delete(npdm_json);
|
||||||
@ -506,14 +518,14 @@ int main(int argc, char* argv[]) {
|
|||||||
fprintf(stderr, "Bad compile environment!\n");
|
fprintf(stderr, "Bad compile environment!\n");
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t json_len;
|
size_t json_len;
|
||||||
uint8_t* json = ReadEntireFile(argv[2], &json_len);
|
uint8_t* json = ReadEntireFile(argv[2], &json_len);
|
||||||
if (json == NULL) {
|
if (json == NULL) {
|
||||||
fprintf(stderr, "Failed to read descriptor json!\n");
|
fprintf(stderr, "Failed to read descriptor json!\n");
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ParseKipConfiguration(json, &kip_hdr)) {
|
if (!ParseKipConfiguration(json, &kip_hdr)) {
|
||||||
fprintf(stderr, "Failed to parse kip configuration!\n");
|
fprintf(stderr, "Failed to parse kip configuration!\n");
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
@ -569,17 +581,17 @@ int main(int argc, char* argv[]) {
|
|||||||
fprintf(stderr, "Invalid ELF: expected 3 loadable phdrs and a bss!\n");
|
fprintf(stderr, "Invalid ELF: expected 3 loadable phdrs and a bss!\n");
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
kip_hdr.Segments[i].DstOff = dst_off;
|
kip_hdr.Segments[i].DstOff = dst_off;
|
||||||
|
|
||||||
// .bss is special
|
// .bss is special
|
||||||
if (i == 3) {
|
if (i == 3) {
|
||||||
tmpsize = (phdr->p_filesz + 0xFFF) & ~0xFFF;
|
tmpsize = (phdr->p_filesz + 0xFFF) & ~0xFFF;
|
||||||
if ( phdr->p_memsz > tmpsize) {
|
if ( phdr->p_memsz > tmpsize) {
|
||||||
kip_hdr.Segments[i].DecompSz = ((phdr->p_memsz - tmpsize) + 0xFFF) & ~0xFFF;
|
kip_hdr.Segments[i].DecompSz = ((phdr->p_memsz - tmpsize) + 0xFFF) & ~0xFFF;
|
||||||
} else {
|
} else {
|
||||||
kip_hdr.Segments[i].DecompSz = 0;
|
kip_hdr.Segments[i].DecompSz = 0;
|
||||||
}
|
}
|
||||||
kip_hdr.Segments[i].CompSz = 0;
|
kip_hdr.Segments[i].CompSz = 0;
|
||||||
break;
|
break;
|
||||||
@ -592,13 +604,13 @@ int main(int argc, char* argv[]) {
|
|||||||
if (buf[i] == NULL) {
|
if (buf[i] == NULL) {
|
||||||
fprintf(stderr, "Out of memory!\n");
|
fprintf(stderr, "Out of memory!\n");
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(buf[i], 0, kip_hdr.Segments[i].DecompSz);
|
memset(buf[i], 0, kip_hdr.Segments[i].DecompSz);
|
||||||
|
|
||||||
memcpy(buf[i], &elf[phdr->p_offset], phdr->p_filesz);
|
memcpy(buf[i], &elf[phdr->p_offset], phdr->p_filesz);
|
||||||
cmp[i] = BLZ_Code(buf[i], phdr->p_filesz, &kip_hdr.Segments[i].CompSz, BLZ_BEST);
|
cmp[i] = BLZ_Code(buf[i], phdr->p_filesz, &kip_hdr.Segments[i].CompSz, BLZ_BEST);
|
||||||
|
|
||||||
file_off += kip_hdr.Segments[i].CompSz;
|
file_off += kip_hdr.Segments[i].CompSz;
|
||||||
dst_off += kip_hdr.Segments[i].DecompSz;
|
dst_off += kip_hdr.Segments[i].DecompSz;
|
||||||
dst_off = (dst_off + 0xFFF) & ~0xFFF;
|
dst_off = (dst_off + 0xFFF) & ~0xFFF;
|
||||||
@ -610,7 +622,7 @@ int main(int argc, char* argv[]) {
|
|||||||
fprintf(stderr, "Failed to open output file!\n");
|
fprintf(stderr, "Failed to open output file!\n");
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO check retvals
|
// TODO check retvals
|
||||||
|
|
||||||
for (i=0; i<3; i++)
|
for (i=0; i<3; i++)
|
||||||
|
134
src/npdmtool.c
134
src/npdmtool.c
@ -19,9 +19,15 @@ typedef uint8_t u8;
|
|||||||
/* FAC, FAH need to be tightly packed. */
|
/* FAC, FAH need to be tightly packed. */
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
typedef struct {
|
typedef struct {
|
||||||
u32 Version;
|
u8 Version;
|
||||||
|
u8 CoiCount;
|
||||||
|
u8 SdoiCount;
|
||||||
|
u8 pad;
|
||||||
u64 Perms;
|
u64 Perms;
|
||||||
u8 _0xC[0x20];
|
u64 CoiMin;
|
||||||
|
u64 CoiMax;
|
||||||
|
u64 SdoiMin;
|
||||||
|
u64 SdoiMax;
|
||||||
} FilesystemAccessControl;
|
} FilesystemAccessControl;
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
@ -29,10 +35,10 @@ typedef struct {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
u32 Version;
|
u32 Version;
|
||||||
u64 Perms;
|
u64 Perms;
|
||||||
u32 _0xC;
|
u32 CoiOffset;
|
||||||
u32 _0x10;
|
u32 CoiSize;
|
||||||
u32 _0x14;
|
u32 SdoiOffset;
|
||||||
u32 _0x18;
|
u32 SdoiSize;
|
||||||
} FilesystemAccessHeader;
|
} FilesystemAccessHeader;
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
@ -76,7 +82,8 @@ typedef struct {
|
|||||||
u8 _0xD;
|
u8 _0xD;
|
||||||
u8 MainThreadPriority;
|
u8 MainThreadPriority;
|
||||||
u8 DefaultCpuId;
|
u8 DefaultCpuId;
|
||||||
u64 _0x10;
|
u32 _0x10;
|
||||||
|
u32 SystemResourceSize;
|
||||||
u32 ProcessCategory;
|
u32 ProcessCategory;
|
||||||
u32 MainThreadStackSize;
|
u32 MainThreadStackSize;
|
||||||
char Name[0x10];
|
char Name[0x10];
|
||||||
@ -219,6 +226,32 @@ int cJSON_GetU64(const cJSON *obj, const char *field, u64 *out) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int cJSON_GetU32(const cJSON *obj, const char *field, u32 *out) {
|
||||||
|
const cJSON *config = cJSON_GetObjectItemCaseSensitive(obj, field);
|
||||||
|
if (cJSON_IsString(config) && (config->valuestring != NULL)) {
|
||||||
|
char *endptr = NULL;
|
||||||
|
*out = strtoul(config->valuestring, &endptr, 16);
|
||||||
|
if (config->valuestring == endptr) {
|
||||||
|
fprintf(stderr, "Failed to get %s (empty string)\n", field);
|
||||||
|
return 0;
|
||||||
|
} else if (errno == ERANGE) {
|
||||||
|
fprintf(stderr, "Failed to get %s (value out of range)\n", field);
|
||||||
|
return 0;
|
||||||
|
} else if (errno == EINVAL) {
|
||||||
|
fprintf(stderr, "Failed to get %s (not base16 string)\n", field);
|
||||||
|
return 0;
|
||||||
|
} else if (errno) {
|
||||||
|
fprintf(stderr, "Failed to get %s (unknown error)\n", field);
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Failed to get %s (field not present).\n", field);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int cJSON_GetU64FromObjectValue(const cJSON *config, u64 *out) {
|
int cJSON_GetU64FromObjectValue(const cJSON *config, u64 *out) {
|
||||||
if (cJSON_IsString(config) && (config->valuestring != NULL)) {
|
if (cJSON_IsString(config) && (config->valuestring != NULL)) {
|
||||||
char *endptr = NULL;
|
char *endptr = NULL;
|
||||||
@ -257,6 +290,10 @@ int CreateNpdm(const char *json, void **dst, u32 *dst_size) {
|
|||||||
const cJSON *service = NULL;
|
const cJSON *service = NULL;
|
||||||
const cJSON *services = NULL;
|
const cJSON *services = NULL;
|
||||||
const cJSON *fsaccess = NULL;
|
const cJSON *fsaccess = NULL;
|
||||||
|
const cJSON *cois = NULL;
|
||||||
|
const cJSON *coi = NULL;
|
||||||
|
const cJSON *sdois = NULL;
|
||||||
|
const cJSON *sdoi = NULL;
|
||||||
|
|
||||||
int status = 0;
|
int status = 0;
|
||||||
cJSON *npdm_json = cJSON_Parse(json);
|
cJSON *npdm_json = cJSON_Parse(json);
|
||||||
@ -305,6 +342,9 @@ int CreateNpdm(const char *json, void **dst, u32 *dst_size) {
|
|||||||
status = 0;
|
status = 0;
|
||||||
goto NPDM_BUILD_END;
|
goto NPDM_BUILD_END;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cJSON_GetU32(npdm_json, "system_resource_size", &header.SystemResourceSize); // optional
|
||||||
|
|
||||||
if (!cJSON_GetU8(npdm_json, "process_category", (u8 *)&header.ProcessCategory)) {
|
if (!cJSON_GetU8(npdm_json, "process_category", (u8 *)&header.ProcessCategory)) {
|
||||||
status = 0;
|
status = 0;
|
||||||
goto NPDM_BUILD_END;
|
goto NPDM_BUILD_END;
|
||||||
@ -370,20 +410,88 @@ int CreateNpdm(const char *json, void **dst, u32 *dst_size) {
|
|||||||
status = 0;
|
status = 0;
|
||||||
goto NPDM_BUILD_END;
|
goto NPDM_BUILD_END;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cJSON_GetU64(fsaccess, "content_owner_id_min", &fac->CoiMin);
|
||||||
|
cJSON_GetU64(fsaccess, "content_owner_id_max", &fac->CoiMax);
|
||||||
|
|
||||||
|
cois = cJSON_GetObjectItemCaseSensitive(fsaccess, "content_owner_ids");
|
||||||
|
if (cJSON_IsArray(cois)) {
|
||||||
|
int idx = 0;
|
||||||
|
u64 *content_owner_id = (u64 *)((u8 *)fac + sizeof(FilesystemAccessControl));
|
||||||
|
cJSON_ArrayForEach(coi, cois) {
|
||||||
|
if (!cJSON_GetU64FromObjectValue(coi, content_owner_id)) {
|
||||||
|
status = 0;
|
||||||
|
goto NPDM_BUILD_END;
|
||||||
|
}
|
||||||
|
++content_owner_id;
|
||||||
|
++idx;
|
||||||
|
}
|
||||||
|
fac->CoiCount = idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
cJSON_GetU64(fsaccess, "save_data_owner_id_min", &fac->SdoiMin);
|
||||||
|
cJSON_GetU64(fsaccess, "save_data_owner_id_max", &fac->SdoiMax);
|
||||||
|
|
||||||
|
sdois = cJSON_GetObjectItemCaseSensitive(fsaccess, "save_data_owner_ids");
|
||||||
|
if (cJSON_IsArray(sdois)) {
|
||||||
|
int idx = 0;
|
||||||
|
u64 *save_data_owner_id = (u64 *)((u8 *)fac + sizeof(FilesystemAccessControl) + fac->CoiCount * sizeof(u64));
|
||||||
|
cJSON_ArrayForEach(sdoi, sdois) {
|
||||||
|
if (!cJSON_GetU64FromObjectValue(sdoi, save_data_owner_id)) {
|
||||||
|
status = 0;
|
||||||
|
goto NPDM_BUILD_END;
|
||||||
|
}
|
||||||
|
++save_data_owner_id;
|
||||||
|
++idx;
|
||||||
|
}
|
||||||
|
fac->SdoiCount = idx;
|
||||||
|
}
|
||||||
|
|
||||||
acid->FacOffset = sizeof(NpdmAcid);
|
acid->FacOffset = sizeof(NpdmAcid);
|
||||||
acid->FacSize = sizeof(FilesystemAccessControl);
|
acid->FacSize = sizeof(FilesystemAccessControl) + fac->CoiCount * sizeof(u64) + fac->SdoiCount * sizeof(u64);
|
||||||
acid->SacOffset = (acid->FacOffset + acid->FacSize + 0xF) & ~0xF;
|
acid->SacOffset = (acid->FacOffset + acid->FacSize + 0xF) & ~0xF;
|
||||||
|
|
||||||
/* Fah. */
|
/* Fah. */
|
||||||
FilesystemAccessHeader *fah = (FilesystemAccessHeader *)((u8 *)aci0 + sizeof(NpdmAci0));
|
FilesystemAccessHeader *fah = (FilesystemAccessHeader *)((u8 *)aci0 + sizeof(NpdmAci0));
|
||||||
fah->Version = 1;
|
fah->Version = 1;
|
||||||
fah->Perms = fac->Perms;
|
fah->Perms = fac->Perms;
|
||||||
fah->_0xC = 0x1C;
|
fah->CoiOffset = sizeof(FilesystemAccessHeader);
|
||||||
fah->_0x14 = 0x1C;
|
fah->CoiSize = fac->CoiCount ? 4 + fac->CoiCount * sizeof(u64) : 0;
|
||||||
|
fah->SdoiOffset = fah->CoiOffset + fah->CoiSize;
|
||||||
|
fah->SdoiSize = fac->SdoiCount ? 4 + fac->SdoiCount * sizeof(u64) : 0;
|
||||||
|
|
||||||
|
if (fac->CoiCount) {
|
||||||
|
u32 *count = (u32 *)((u8 *)fah + fah->CoiOffset);
|
||||||
|
*count = fac->CoiCount;
|
||||||
|
|
||||||
|
u64 *id = (u64 *)((u8 *)count + sizeof(u32));
|
||||||
|
cJSON_ArrayForEach(coi, cois) {
|
||||||
|
if (!cJSON_GetU64FromObjectValue(coi, id)) {
|
||||||
|
status = 0;
|
||||||
|
goto NPDM_BUILD_END;
|
||||||
|
}
|
||||||
|
++id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fac->SdoiCount) {
|
||||||
|
u32 *count = (u32 *)((u8 *)fah + fah->SdoiOffset);
|
||||||
|
*count = fac->SdoiCount;
|
||||||
|
|
||||||
|
u64 *id = (u64 *)((u8 *)count + sizeof(u32));
|
||||||
|
cJSON_ArrayForEach(sdoi, sdois) {
|
||||||
|
if (!cJSON_GetU64FromObjectValue(sdoi, id)) {
|
||||||
|
status = 0;
|
||||||
|
goto NPDM_BUILD_END;
|
||||||
|
}
|
||||||
|
++id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
aci0->FahOffset = sizeof(NpdmAci0);
|
aci0->FahOffset = sizeof(NpdmAci0);
|
||||||
aci0->FahSize = sizeof(FilesystemAccessHeader);
|
aci0->FahSize = sizeof(FilesystemAccessHeader) + fah->CoiSize + fah->SdoiSize;
|
||||||
aci0->SacOffset = (aci0->FahOffset + aci0->FahSize + 0xF) & ~0xF;
|
aci0->SacOffset = (aci0->FahOffset + aci0->FahSize + 0xF) & ~0xF;
|
||||||
|
|
||||||
/* Sac. */
|
/* Sac. */
|
||||||
u8 *sac = (u8*)aci0 + aci0->SacOffset;
|
u8 *sac = (u8*)aci0 + aci0->SacOffset;
|
||||||
u32 sac_size = 0;
|
u32 sac_size = 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user