Add mii and miiimg services (#402)

This commit is contained in:
XorTroll 2020-04-17 01:28:53 +02:00 committed by GitHub
parent 0b93435a44
commit 763b1694ec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 395 additions and 55 deletions

View File

@ -109,6 +109,8 @@ extern "C" {
#include "switch/services/grc.h" #include "switch/services/grc.h"
#include "switch/services/friends.h" #include "switch/services/friends.h"
#include "switch/services/notif.h" #include "switch/services/notif.h"
#include "switch/services/mii.h"
#include "switch/services/miiimg.h"
#include "switch/display/binder.h" #include "switch/display/binder.h"
#include "switch/display/parcel.h" #include "switch/display/parcel.h"

View File

@ -0,0 +1,176 @@
/**
* @file mii.h
* @brief Mii services (mii:*) IPC wrapper.
* @author XorTroll
* @copyright libnx Authors
*/
#pragma once
#include "../types.h"
#include "../sf/service.h"
typedef enum {
MiiServiceType_System = 0, ///< Initializes mii:e.
MiiServiceType_User = 1, ///< Initializes mii:u.
} MiiServiceType;
/// Mii age.
typedef enum {
MiiAge_Young = 0, ///< Young
MiiAge_Normal = 1, ///< Normal
MiiAge_Old = 2, ///< Old
MiiAge_All = 3, ///< All of them
} MiiAge;
/// Mii gender.
typedef enum {
MiiGender_Male = 0, ///< Male
MiiGender_Female = 1, ///< Female
MiiGender_All = 2, ///< Both of them
} MiiGender;
/// Mii face color.
typedef enum {
MiiFaceColor_Black = 0, ///< Black
MiiFaceColor_White = 1, ///< White
MiiFaceColor_Asian = 2, ///< Asian
MiiFaceColor_All = 3, ///< All of them
} MiiFaceColor;
// Mii source flag.
typedef enum {
MiiSourceFlag_Database = BIT(0), ///< Miis created by the user
MiiSourceFlag_Default = BIT(1), ///< Default console miis
MiiSourceFlag_All = MiiSourceFlag_Database | MiiSourceFlag_Default, ///< All of them
} MiiSourceFlag;
// Mii special key code
typedef enum {
MiiSpecialKeyCode_Normal = 0, ///< Normal miis
MiiSpecialKeyCode_Special = 0xA523B78F, ///< Special miis
} MiiSpecialKeyCode;
typedef struct {
Service s;
} MiiDatabase;
// Mii create ID.
typedef struct {
Uuid uuid;
} MiiCreateId;
// Mii data structure.
typedef struct {
MiiCreateId create_id;
u16 mii_name[10+1]; ///< utf-16be, null-terminated
u8 unk_x26;
u8 mii_color;
u8 mii_sex;
u8 mii_height;
u8 mii_width;
u8 unk_x2b[2];
u8 mii_face_shape;
u8 mii_face_color;
u8 mii_wrinkles_style;
u8 mii_makeup_style;
u8 mii_hair_style;
u8 mii_hair_color;
u8 mii_has_hair_flipped;
u8 mii_eye_style;
u8 mii_eye_color;
u8 mii_eye_size;
u8 mii_eye_thickness;
u8 mii_eye_angle;
u8 mii_eye_pos_x;
u8 mii_eye_pos_y;
u8 mii_eyebrow_style;
u8 mii_eyebrow_color;
u8 mii_eyebrow_size;
u8 mii_eyebrow_thickness;
u8 mii_eyebrow_angle;
u8 mii_eyebrow_pos_x;
u8 mii_eyebrow_pos_y;
u8 mii_nose_style;
u8 mii_nose_size;
u8 mii_nose_pos;
u8 mii_mouth_style;
u8 mii_mouth_color;
u8 mii_mouth_size;
u8 mii_mouth_thickness;
u8 mii_mouth_pos;
u8 mii_facial_hair_color;
u8 mii_beard_style;
u8 mii_mustache_style;
u8 mii_mustache_size;
u8 mii_mustache_pos;
u8 mii_glasses_style;
u8 mii_glasses_color;
u8 mii_glasses_size;
u8 mii_glasses_pos;
u8 mii_has_mole;
u8 mii_mole_size;
u8 mii_mole_pos_x;
u8 mii_mole_pos_y;
u8 unk_x57;
} MiiCharInfo;
/// Initialize mii.
Result miiInitialize(MiiServiceType service_type);
/// Exit mii.
void miiExit(void);
/// Gets the Service object for the actual mii service session.
Service* miiGetServiceSession(void);
/**
* @brief Opens a mii database.
* @param[in] key_code Mii key code filter.
* @param[out] out Database.
*/
Result miiOpenDatabase(MiiDatabase *out, MiiSpecialKeyCode key_code);
/**
* @brief Returns whether the mii database is updated.
* @param[in] db Database.
* @param[in] flag Source flag.
* @param[out] out_updated Whether the mii database is updated.
*/
Result miiDatabaseIsUpdated(MiiDatabase *db, bool *out_updated, MiiSourceFlag flag);
/**
* @brief Returns whether the mii database is full.
* @param[in] db Database.
* @param[out] out_full Whether the mii database is full.
*/
Result miiDatabaseIsFull(MiiDatabase *db, bool *out_full);
/**
* @brief Returns number of miis in the database with the specified source flag.
* @param[in] db Database.
* @param[in] flag Source flag.
* @param[out] out_count Out mii count.
*/
Result miiDatabaseGetCount(MiiDatabase *db, s32 *out_count, MiiSourceFlag flag);
/**
* @brief Reads mii charinfo data from the specified source flag.
* @param[in] db Database.
* @param[in] flag Source flag.
* @param[out] out_infos Output mii charinfo array.
* @param[in] count Number of mii chainfos to read.
* @param[out] total_out Number of mii charinfos which were actually read.
*/
Result miiDatabaseGet1(MiiDatabase *db, MiiSourceFlag flag, MiiCharInfo *out_infos, s32 count, s32 *total_out);
/**
* @brief Generates a random mii charinfo (doesn't register it in the console database).
* @param[in] db Database.
* @param[in] age Mii's age.
* @param[in] gender Mii's gender.
* @param[in] face_color Mii's face color.
* @param[out] out_info Out mii charinfo data.
*/
Result miiDatabaseBuildRandom(MiiDatabase *db, MiiAge age, MiiGender gender, MiiFaceColor face_color, MiiCharInfo *out_info);
/// Closes a mii database.
void miiDatabaseClose(MiiDatabase *db);

View File

@ -0,0 +1,71 @@
/**
* @file miiimg.h
* @brief Mii image (miiimg) service IPC wrapper.
* @author XorTroll
* @copyright libnx Authors
*/
#pragma once
#include "../types.h"
#include "../sf/service.h"
#include "../services/mii.h"
/// Image ID.
typedef struct {
Uuid uuid;
} MiiimgImageId;
/// Image attribute.
typedef struct {
MiiimgImageId image_id; ///< Image ID.
MiiCreateId create_id; ///< Mii's create ID.
u32 unk;
u16 mii_name[10+1]; ///< utf-16be, null-terminated
} PACKED MiiimgImageAttribute;
/// Initialize miiimg.
Result miiimgInitialize(void);
/// Exit miiimg.
void miiimgExit(void);
/// Gets the Service object for the actual miiimg service session.
Service* miiimgGetServiceSession(void);
/**
* @brief Reloads the image database.
*/
Result miiimgReload(void);
/**
* @brief Gets the number of mii images in the database.
* @param[out] out_count Mii image count.
*/
Result miiimgGetCount(s32 *out_count);
/**
* @brief Gets whether the image database is empty.
* @param[out] out_empty Whether the database is empty.
*/
Result miiimgIsEmpty(bool *out_empty);
/**
* @brief Gets whether the image database is full.
* @param[out] out_empty Whether the database is full.
*/
Result miiimgIsFull(bool *out_full);
/**
* @brief Gets the image attribute for the specified image index.
* @param[in] index Image index.
* @param[out] out_attr Out image attribute.
*/
Result miiimgGetAttribute(s32 index, MiiimgImageAttribute *out_attr);
/**
* @brief Loads the image data (raw RGBA8) for the specified image ID.
* @note Server doesn't seem to check the image buffer size, but 0x40000 is the optimal size.
* @param[in] id Input image ID.
* @param[out] out_image Out iamge buffer.
* @param[in] out_image_size Out image buffer size.
*/
Result miiimgLoadImage(MiiimgImageId id, void* out_image, size_t out_image_size);

View File

@ -8,6 +8,7 @@
#pragma once #pragma once
#include "../types.h" #include "../types.h"
#include "../sf/service.h" #include "../sf/service.h"
#include "../services/mii.h"
/// NfpServiceType /// NfpServiceType
typedef enum { typedef enum {
@ -72,61 +73,7 @@ typedef struct {
} PACKED NfpModelInfo; } PACKED NfpModelInfo;
typedef struct { typedef struct {
u8 unk_x0[0x10]; // Hash? MiiCharInfo mii;
u16 mii_name[10+1]; ///< utf-16be, null-terminated
u8 unk_x26;
u8 mii_color;
u8 mii_sex;
u8 mii_height;
u8 mii_width;
u8 unk_x2b[2];
u8 mii_face_shape;
u8 mii_face_color;
u8 mii_wrinkles_style;
u8 mii_makeup_style;
u8 mii_hair_style;
u8 mii_hair_color;
u8 mii_has_hair_flipped;
u8 mii_eye_style;
u8 mii_eye_color;
u8 mii_eye_size;
u8 mii_eye_thickness;
u8 mii_eye_angle;
u8 mii_eye_pos_x;
u8 mii_eye_pos_y;
u8 mii_eyebrow_style;
u8 mii_eyebrow_color;
u8 mii_eyebrow_size;
u8 mii_eyebrow_thickness;
u8 mii_eyebrow_angle;
u8 mii_eyebrow_pos_x;
u8 mii_eyebrow_pos_y;
u8 mii_nose_style;
u8 mii_nose_size;
u8 mii_nose_pos;
u8 mii_mouth_style;
u8 mii_mouth_color;
u8 mii_mouth_size;
u8 mii_mouth_thickness;
u8 mii_mouth_pos;
u8 mii_facial_hair_color;
u8 mii_beard_style;
u8 mii_mustache_style;
u8 mii_mustache_size;
u8 mii_mustache_pos;
u8 mii_glasses_style;
u8 mii_glasses_color;
u8 mii_glasses_size;
u8 mii_glasses_pos;
u8 mii_has_mole;
u8 mii_mole_size;
u8 mii_mole_pos_x;
u8 mii_mole_pos_y;
u8 unk_x57;
} PACKED NfpMiiCharInfo;
typedef struct {
NfpMiiCharInfo mii;
u16 first_write_year; u16 first_write_year;
u8 first_write_month; u8 first_write_month;
u8 first_write_day; u8 first_write_day;

80
nx/source/services/mii.c Normal file
View File

@ -0,0 +1,80 @@
#define NX_SERVICE_ASSUME_NON_DOMAIN
#include "service_guard.h"
#include "services/mii.h"
static MiiServiceType g_miiServiceType;
static Service g_miiSrv;
NX_GENERATE_SERVICE_GUARD_PARAMS(mii, (MiiServiceType service_type), (service_type));
Result _miiInitialize(MiiServiceType service_type) {
Result rc = MAKERESULT(Module_Libnx, LibnxError_BadInput);
g_miiServiceType = service_type;
switch (g_miiServiceType) {
case MiiServiceType_System:
rc = smGetService(&g_miiSrv, "mii:e");
break;
case MiiServiceType_User:
rc = smGetService(&g_miiSrv, "mii:u");
break;
}
return rc;
}
void _miiCleanup(void) {
serviceClose(&g_miiSrv);
}
Service* miiGetServiceSession(void) {
return &g_miiSrv;
}
Result miiOpenDatabase(MiiDatabase *out, MiiSpecialKeyCode key_code) {
u32 in = (u32)key_code;
return serviceDispatchIn(&g_miiSrv, 0, in,
.out_num_objects = 1,
.out_objects = &out->s,
);
}
Result miiDatabaseIsUpdated(MiiDatabase *db, bool *out_updated, MiiSourceFlag flag) {
u32 in = (u32)flag;
u8 tmp = 0;
Result rc = serviceDispatchInOut(&db->s, 0, in, tmp);
if (R_SUCCEEDED(rc) && out_updated) *out_updated = tmp & 1;
return rc;
}
Result miiDatabaseIsFull(MiiDatabase *db, bool *out_full) {
u8 tmp = 0;
Result rc = serviceDispatchOut(&db->s, 1, tmp);
if (R_SUCCEEDED(rc) && out_full) *out_full = tmp & 1;
return rc;
}
Result miiDatabaseGetCount(MiiDatabase *db, s32 *out_count, MiiSourceFlag flag) {
u32 in = (u32)flag;
return serviceDispatchInOut(&db->s, 2, in, *out_count);
}
Result miiDatabaseGet1(MiiDatabase *db, MiiSourceFlag flag, MiiCharInfo *out_infos, s32 count, s32 *total_out) {
u32 in = (u32)flag;
return serviceDispatchInOut(&db->s, 4, in, *total_out,
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
.buffers = { { out_infos, count * sizeof(MiiCharInfo) } },
);
}
Result miiDatabaseBuildRandom(MiiDatabase *db, MiiAge age, MiiGender gender, MiiFaceColor face_color, MiiCharInfo *out_info) {
const struct {
u32 age;
u32 gender;
u32 face_color;
} in = { age, gender, face_color };
return serviceDispatchInOut(&db->s, 6, in, *out_info);
}
void miiDatabaseClose(MiiDatabase *db) {
serviceClose(&db->s);
}

View File

@ -0,0 +1,64 @@
#define NX_SERVICE_ASSUME_NON_DOMAIN
#include "service_guard.h"
#include "services/miiimg.h"
#include "runtime/hosversion.h"
static Service g_miiimgSrv;
NX_GENERATE_SERVICE_GUARD(miiimg);
static Result _miiimgInitializeCmd(u8 in, u8 *out) {
return serviceDispatchInOut(&g_miiimgSrv, 0, in, *out);
}
Result _miiimgInitialize(void) {
if (hosversionBefore(5,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
Result rc = smGetService(&g_miiimgSrv, "miiimg");
if (R_SUCCEEDED(rc)) {
u8 tmp;
rc = _miiimgInitializeCmd(1, &tmp);
}
return rc;
}
void _miiimgCleanup(void) {
serviceClose(&g_miiimgSrv);
}
Service* miiimgGetServiceSession(void) {
return &g_miiimgSrv;
}
Result miiimgReload(void) {
return serviceDispatch(&g_miiimgSrv, 10);
}
Result miiimgGetCount(s32 *out_count) {
return serviceDispatchOut(&g_miiimgSrv, 11, *out_count);
}
Result miiimgIsEmpty(bool *out_empty) {
u8 tmp = 0;
Result rc = serviceDispatchOut(&g_miiimgSrv, 12, tmp);
if (R_SUCCEEDED(rc) && out_empty) *out_empty = tmp & 1;
return rc;
}
Result miiimgIsFull(bool *out_full) {
u8 tmp = 0;
Result rc = serviceDispatchOut(&g_miiimgSrv, 13, tmp);
if (R_SUCCEEDED(rc) && out_full) *out_full = tmp & 1;
return rc;
}
Result miiimgGetAttribute(s32 index, MiiimgImageAttribute *out_attr) {
return serviceDispatchInOut(&g_miiimgSrv, 14, index, *out_attr);
}
Result miiimgLoadImage(MiiimgImageId id, void* out_image, size_t out_image_size) {
return serviceDispatchIn(&g_miiimgSrv, 15, id,
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
.buffers = { { out_image, out_image_size } },
);
}