/*---------------------------------------------------------------------------* Project: Horizon File: cec_MessageBox.h Copyright 2009 Nintendo. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Date:: 2011-01-24#$ $Rev: 33743 $ $Author: sato_yoshinobu $ *---------------------------------------------------------------------------*/ #ifndef __MESSAGE_BOX_H__ #define __MESSAGE_BOX_H__ /* CEC/ | +-- MessageBoxList \-- Message_BOX1/ | | | +-- MessageBoxInfo | \-- InBox/ | | | | | +-- InBoxInfo | | +-- Message1 | | | \-- OutBox/ | | | +-- OutBoxIndex | +-- OutBoxInfo | +-- Message2 | \-- Message_BOX2/ | */ #define CEC_INBOX_SIZE_DEFAULT (512*1024) //! 受信Box サイズ初期値 #define CEC_OUTBOX_SIZE_DEFAULT (512*1024) //! 送信Box サイズ初期値 #define CEC_INBOX_MESSNUM_DEFAULT (99) #define CEC_OUTBOX_MESSNUM_DEFAULT (99) #define CEC_MESSSIZEMAX_DEFAULT (100*1024) #define CEC_BOX_DATA_SIZE_MAX (10*1024) #define CEC_BOXNUMMAX_APPLICATION (12) // 一般アプリケーション用 Box 最大数 #define CEC_BOXNUMMAX_SYSTEM (6) // System アプリケーション用 Box 最大数 #define CEC_BOXNUMMAX_SYSTEM2 (6) // System アプリケーション その2 用 Box 最大数 #define MESSAGE_BOX_NUM_MAX (CEC_BOXNUMMAX_APPLICATION + CEC_BOXNUMMAX_SYSTEM + CEC_BOXNUMMAX_SYSTEM2) #define CEC_BOXDIR_NAMELEN_MAX (16) #include namespace nn { namespace cec { namespace CTR { //! @name MessageBoxFlag //@{ /*! * @typedef MessageBoxFlag * @brief MessageBox の属性を示すフラグです。 */ typedef bit8 MessageBoxFlag; /*! @brief 一般アプリケーション用
デフォルトでこの値が指定されています。 */ static const bit8 MESSAGE_BOX_FLAG_APPLICATION = (0x1); /* @brief System アプリケーション用 */ static const bit8 MESSAGE_BOX_FLAG_SYSTEM = (0x2); /* @brief System アプリケーション用 その2 */ static const bit8 MESSAGE_BOX_FLAG_SYSTEM2 = (0x4); /* @brief 接続時にBOXの存在を通知しない */ static const bit8 MESSAGE_BOX_FLAG_HIDDEN = (0x80); //@} /*! * @enum CecBoxType * @brief 受信BOX/ 送信BOX の種別 */ enum CecBoxType { CEC_BOXTYPE_INBOX = (0x0), //!< 受信BOX CEC_BOXTYPE_OUTBOX = (0x1) //!< 送信BOX }; // 構造体 #define MESSAGEBOXLIST_MAGIC 0x6868 #define CEC_BOX_VERSION 0x00000001 struct MessageBoxList { u16 magic16; NN_PADDING2; u32 CecBoxVersion; u32 DirNum; u8 DirName[MESSAGE_BOX_NUM_MAX][CEC_BOXDIR_NAMELEN_MAX]; }; //ローカル管理用メッセージリスト #define MESSAGEBOXINFO_MAGIC 0x6363 struct MessageBoxInfo { u16 magic16; NN_PADDING2; u32 cecTitleId; // Title固有ID u32 privateId; // アプリがつける固有ID。アクセスする為のキーとなる。 MessageBoxFlag MessageBoxInfoFlag; // MessageBoxInfoのフラグ(Systemなど) bool isActive; NN_PADDING2; char hmacKey[MESSAGE_HMAC_KEYLEN]; // HMACで署名を付けるときに使用するKey u32 MessageBoxInfoSize; // MessageBoxInfoのサイズ(Byte) nn::fnd::DateTimeParameters lastOpened; // アクセス時の時刻を記録 u8 flag1; // アクセス時に変更するフラグ1 未読フラグ u8 flag2; // アクセス時に変更するフラグ2 新着フラグ NN_PADDING2; nn::fnd::DateTimeParameters lastReceived; // 受信時の時刻を記録 u8 reserved[16]; // reserved (名称・iconなどは別ファイルに書く) }; // 送信/受信 ボックス情報ファイル データ構造 /* File : InBoxInfo/OutBoxInfo +----------------------+ | CEC Box Info Header | +----------------------+ -+ | CEC Message Header1 | | +----------------------+ | CecMessageHeader_List | CEC Message Header2 | | +----------------------+ | | CEC Message Header3 | | +----------------------+ | | .......... | | | | | +----------------------+ -+ */ #define CEC_BOXINFO_MAGIC 0x6262 #define CEC_SIZEOF_BOXINFO_HEADER (sizeof(struct CecBoxInfoHeader)) struct CecBoxInfoHeader { u16 magic16; NN_PADDING2; u32 boxInfoSize; // BoxInfoのサイズ u32 boxSizeMax; // MessageBoxのサイズ(Byte)最大値 u32 boxSize; // MessageBoxのサイズ(使用量)(Byte) u32 messNumMax; // ボックスに格納可能な message数 の最大値 u32 messNum; // ボックスに格納されているmessage数 u32 groupNumMax; // ボックスに格納可能な Message Group 数 の最大値 u32 messSizeMax; // 1つのMessageの最大サイズ }; // 送信ボックス Index ファイル (送信順を示す) #define CEC_OUTBOXINDEX_MAGIC 0x6767 struct CecOutBoxIndexHeader { u16 magic16; NN_PADDING2; size_t messageNum; // Message の 個数 }; /*! @brief CEC MessageBox にアクセスするためのクラスです。 Box の作成・削除、Messageの書き込み・読み込み、Boxの情報取得などを行うことができます。
@ref CreateMessageBox でBoxを作成、@ref OpenMessageBox で そのBoxを開くことで、Box内のMessageにアクセスすることが可能になります。
@ref WriteMessage でMessageをBoxに書き込みます。送信BOXに書き込んだMessageが送信されます。 受信したMessageは受信BOXに格納され、 @ref ReadMessage で読み込むことができます。
Boxへのアクセス終了時には @ref CloseMessageBox を呼び出してください。CloseMessageBox/CommitMessageBoxを呼び出したときに変更がコミットされます。コミットする前にプログラムが終了されたときは、それまでの変更は巻き戻される可能性があります。スリープなど、通信の制御がシステムに戻ったときに、変更が巻き戻される可能性もあるため、注意してください。
Open ~ Close までを 1 単位の処理とし、その間をスリープと排他にするのが安全な実装です。

Messageを作成して書き込むとき、Messageに MessageId が付与されます。MessageId はランダムに生成されるユニークな値になっており、この値をキーとして各Messageにアクセスします。

個々のMessageの属性などの情報を、GetMessageXXX 関数で取得することができます。
GetMessageXXX 関数はシステム内部に保持されているMessageリストから情報を取り出すため、 ReadMessage で、Message実体にアクセスするより高速に情報取得できます。この情報は、OpenMessageBoxを呼んだときにシステムから読み出されます。
予期せぬ電源断等で、システムが保持するMessageリストと、Message実体の情報がずれる可能性があります。(MessageIdの取得はできるが、ReadMessage に失敗する等) WriteMessage でMessageの書き込みを行うことでMessageリストの再生成が行われますが、復旧できないような状態に陥ったときは、 DeleteAllMessages , DeleteMessageBox で削除を行ってください。

@ref WriteMessage でMessageを書き込むとき、EULAの同意バージョンチェックが行われます。
チェックには fs の機能を使用しますので、事前にfsライブラリの初期化を行う必要があります。 */ class MessageBox { protected: u32 currentCecTitleId; bool m_Initialized; NN_PADDING3; u8* cecBoxBuf; struct MessageBoxList cecMessageBoxList; struct MessageBoxInfo cecMessageBoxInfo; struct CecBoxInfoHeader cecInboxInfo; CecMessageHeader* cecInboxInfo_body[CEC_INBOX_MESSNUM_DEFAULT]; u8* cecInboxInfoBuf; struct CecBoxInfoHeader cecOutboxInfo; CecMessageHeader* cecOutboxInfo_body[CEC_OUTBOX_MESSNUM_DEFAULT]; u8* cecOutboxInfoBuf; CecOutBoxIndexHeader cecOutboxIndex_header; //u8* cecOutboxIndex[CEC_OUTBOX_MESSNUM_DEFAULT]; CECMessageId cecOutboxIndex[CEC_OUTBOX_MESSNUM_DEFAULT]; // u8* cecOutboxIndexBuf; bool m_BoxAccessible; NN_PADDING3; static bool b_SkipedWriteInboxInfo; static bool b_SkipedWriteOutboxInfo; static struct CecBoxInfoHeader tmp_cecInboxInfo; static struct CecBoxInfoHeader tmp_cecOutboxInfo; public: MessageBox(bool NoInitialize = false); virtual ~MessageBox(); nn::Result Initialize(); nn::Result Finalize(); nn::Result WriteMessageBoxList(); size_t ReadMessageBoxList(); size_t ReadMessageBoxList(void* bufOut, size_t size); u32 GetMessageBoxNum(MessageBoxFlag flag); nn::Result DeleteOldestMessageBox(MessageBoxFlag flag); inline u32 GetCurrentCecTitleId() const{return currentCecTitleId;} //! @name Boxの作成/削除 //@{ /*! @brief MessageBoxを作成します。Box内に 受信BOX と 送信BOX が作成されます。
送信BOX に Message をセットすることで、すれちがい通信時にデータ送信が行われ、受信BOXに相手からのデータが保持されます。 MessageBoxは、NAND領域に作成されます。1アプリにつき、作成できるBOXは1つです。BOXの最大数は12で、これを超える場合は新規にBOXを作成することはできません。
作成した直後はBOXをオープンした状態( @ref OpenMessageBox )になります。
privateId, hmacKey はアクセス可能な範囲を制限する為の値です。アプリ側で値を決めて、設定してください。
privateId はBOXをOpenするために必要なキーで、1本体内に閉じられた値を想定しています。
hmacKey は同一アプリが共通して持つキー(秘密鍵)で、データの改竄・アプリの偽装を防ぐ目的にも使用されます。類推されない値を設定してください。このキーはBOXに保持されます。
複数セーブデータ・複数アプリから同一のBOXにアクセスする必要がある場合は、適切な範囲で共通するキーを作成して設定してください。

この関数を呼ぶと、バックグラウンドで動作している CECデーモンが停止します。
バックグラウンドで行われている通信が中断される可能性があることに注意してください。→ @ref CecControl::StopScanning

すれちがい通信関連で、本体管理画面等で扱われるアイコンには2種類あります。
Boxに付随するアイコン・個々のMessageに付随するアイコンがあり、これらを設定しておく必要があります。
この関数では、Boxのアイコンをセットします。 @param[in] cecTitleId 32ビットの すれちがい通信ID です。 @ref MakeCecTitleId で生成することが可能です。 @param[in] privateId BOXをOpenするために必要なキーとなります。→ @ref OpenMessageBox
BOXにアクセスするアプリが保持している値を使用する必要があります。 @param[in] hmacKey Message を読み出すときに必要なキーを指定します。32文字の文字列で指定します。 通信相手と共通のキー(秘密鍵)である必要があります。
この値は、送受信されるデータの改竄をチェックするために使用されます。送受信されるデータには、このキーを使用して生成された署名が付けられます。
アプリ内で保持している値を使用してください。 @param[in] icon アイコンを指定します。
フォーマット: RGB565 (リトルエンディアン)
サイズ: 48×48 (4.5KBytes)
@param[in] iconSize アイコンのデータサイズを指定します。 @param[in] name アプリ名称を指定します。
文字コード: UTF16-LE
表示サイズ: 全角17文字で表示できる文字数
バッファ最大: 64×2Bytes (NULL終端込み)
@param[in] nameSize アプリ名称のデータサイズを指定します。 @param[in] inboxSizeMax 受信ボックスの最大保存サイズを指定します。受信BOXと送信BOXで合わせて 1MB 以内にする必要があります。デフォルトは 512*1024 バイトです。 @param[in] outboxSizeMax 送信ボックスの最大保存サイズを指定します。受信BOXと送信BOXで合わせて 1MB 以内にする必要があります。デフォルトは 512*1024 バイトです。 @param[in] inboxMessNumMax 受信ボックスの最大保存Message数を指定します。デフォルトは 99 で、この値より多い値を指定することはできません。 @param[in] outboxMessNumMax 送信ボックスの最大保存Message数を指定します。デフォルトは 99 で、この値より多い値を指定することはできません。 @param[in] messageSizeMax Messageの最大サイズを指定します。このサイズを超えるMessageは保存できず、WriteMessage でエラーとなります。 @return nn::Result @retval ResultSuccess 成功しました。 @retval ResultBoxAlreadyExists 既にボックスが存在する為、BOXを作成することができません。
OpenMessageBox == nn::cec::ResultNoData() の状態でこのエラーが 返ってきたときは、CecTitleIdの下位 8bit が異なる BOX が作成されていることが原因の可能性があります。 → @ref MakeCecTitleId , @ref OpenMessageBox @retval ResultBoxNumFull ボックスを作成できる上限に達しています。 新しくボックスを作る場合は、他のタイトルのボックスを 削除する必要があります。 @retval ResultInvalidArgument 引数の指定に誤りがあります。 @retval ResultInvalidData セットしているデータ(アイコン・名称)に問題があります。 @retval ResultTooLarge セットしているデータサイズに問題があります。 @retval ResultStateBusy デーモンがBUSY状態の為、アクセスできません。時間を空けて再アクセスすることで成功する可能性があります。 @retval 上記以外 失敗しました。 */ nn::Result CreateMessageBox( const TitleId cecTitleId, const u32 privateId, const char* hmacKey, void* icon, size_t iconSize, wchar_t* name, size_t nameSize, size_t inboxSizeMax = CEC_INBOX_SIZE_DEFAULT, size_t outboxSizeMax = CEC_OUTBOX_SIZE_DEFAULT, size_t inboxMessNumMax = CEC_INBOX_MESSNUM_DEFAULT, size_t outboxMessNumMax = CEC_OUTBOX_MESSNUM_DEFAULT, size_t messageSizeMax = CEC_MESSSIZEMAX_DEFAULT ); /*! :private @brief MessageBoxを作成します。Box内に 受信BOX と 送信BOX が作成されます。
(最終バージョンでは、アイコンとアプリ名称の設定が必須になります。この形式は過去のバージョンとの互換性のために残されています。) @param[in] cecTitleId すれちがい通信ID @param[in] privateId BOXをOpenするために必要なキーとなります。→ @ref OpenMessageBox
BOXにアクセスするアプリが保持している値を使用する必要があります。 @param[in] hmacKey Message を読み出すときに必要なキーを指定します。32文字の文字列で指定します。 通信相手と共通のキーである必要があります。
この値は、送受信されるデータの改竄をチェックするために使用されます。送受信されるデータには、このキーを使用して生成された署名が付けられます。 アプリ内で保持している値を使用してください。 @param[in] inboxSizeMax 受信ボックスの最大保存サイズを指定します。受信BOXと送信BOXで合わせて 1MB 以内にする必要があります。デフォルトは 512*1024 バイトです。 @param[in] outboxSizeMax 送信ボックスの最大保存サイズを指定します。受信BOXと送信BOXで合わせて 1MB 以内にする必要があります。デフォルトは 512*1024 バイトです。 @param[in] inboxMessNumMax 受信ボックスの最大保存Message数を指定します。デフォルトは 99 で、この値より多い値を指定することはできません。 @param[in] outboxMessNumMax 送信ボックスの最大保存Message数を指定します。デフォルトは 99 で、この値より多い値を指定することはできません。 @param[in] messageSizeMax Messageの最大サイズを指定します。このサイズを超えるMessageは保存できず、WriteMessage でエラーとなります。 @return nn::Result @retval ResultSuccess 成功しました。 @retval ResultBoxAlreadyExists 既にボックスが存在します。 @retval ResultBoxNumFull ボックスを作成できる上限に達しています。 新しくボックスを作る場合は、他のタイトルのボックスを 削除する必要があります。 @retval ResultInvalidArgument 引数の指定に誤りがあります。 @retval ResultInvalidData セットしているデータに問題があります。 @retval ResultStateBusy デーモンがBUSY状態の為、アクセスできません。時間を空けて再アクセスすることで成功する可能性があります。 @retval 上記以外 失敗しました。 */ nn::Result CreateMessageBox( const TitleId cecTitleId, const u32 privateId, const char* hmacKey, size_t inboxSizeMax = CEC_INBOX_SIZE_DEFAULT, size_t outboxSizeMax = CEC_OUTBOX_SIZE_DEFAULT, size_t inboxMessNumMax = CEC_INBOX_MESSNUM_DEFAULT, size_t outboxMessNumMax = CEC_OUTBOX_MESSNUM_DEFAULT, size_t messageSizeMax = CEC_MESSSIZEMAX_DEFAULT ); void CreateInBox(const TitleId cecTitleId); void CreateOutBox(const TitleId cecTitleId); /*! @brief MessageBox を削除します。 @ref OpenMessageBox で開いているBoxを削除します。
@return nn::Result @retval ResultSuccess 成功しました。 @retval ResultNotAuthorized ボックスがOpenされていません。 @retval 上記以外 失敗しました。 */ nn::Result DeleteMessageBox(); /*! @brief MessageBox を削除します。すれちがい通信ID を指定して削除します。 MessageBoxをOpenできないときに強制的に削除するといった用途に使用します。別アプリのMessageBoxを削除しないでください。 @param[in] cecTitleId すれちがい通信ID @return nn::Result @retval ResultSuccess 成功しました。 @retval 上記以外 失敗しました。 */ nn::Result DeleteMessageBox(const TitleId cecTitleId); nn::Result DeleteAllBoxes(); /*! @brief MessageBox を開きます。Box内のMessageにアクセスするために、まずこの関数でBoxを開く必要があります。 この関数を呼ぶと、バックグラウンドで動作している CECデーモンが停止します。
バックグラウンドで行われている通信が中断される可能性があることに注意してください。 → @ref CecControl::StopScanning
Boxへのアクセス終了時には @ref CloseMessageBox を呼び出してください。
この関数を呼んだ後、CloseMessageBoxを呼ぶまでは、CECデーモンは動作を開始しない状態 のままになります。送信メッセージのセット時、受信メッセージの取得時以外は、Open したままの状態にならないようにしてください。
Open ~ Close までを 1 単位の処理とし、その間をスリープと排他にするのが安全な実装です。 @param[in] cecTitleId すれちがい通信ID @param[in] privateId @ref CreateMessageBox でBOXを作成したときに指定した値と同じ値を指定します。 値が異なる場合はアクセスできません。 @return nn::Result @retval ResultSuccess 成功しました。 @retval ResultNoData ボックスが存在しません。 @retval ResultNotAuthorized PrivateIdが異なる為、アクセスできません。 @retval ResultStateBusy デーモンがBUSY状態の為、アクセスできません。時間を空けて再アクセスすることで成功する可能性があります。 @retval 上記以外 失敗しました。 */ nn::Result OpenMessageBox(const TitleId cecTitleId, const u32 privateId); void CloseMessageBox(bool bWithoutCommit); /*! @brief MessageBox を閉じます。以後はMessageへのアクセスはできません。 @ref OpenMessageBox を呼んだときにバックグラウンドのデーモンの動作を停止したときは、この関数を呼ぶと動作開始します。
@ref CommitMessageBox の処理も行われます。MessageBoxへのアクセスが終わったときに呼び出してください。 @return なし */ void CloseMessageBox(); /*! @brief MessageBox が既にOpenされているかを取得します。 @return 既にOpenされていれば true */ bool IsOpened(); //@} /*! @brief MessageBox の 有効/無効 を指定します。無効にされているBOXのデータは送受信されません。 @param[in] active 有効: true / 無効: false @return nn::Result @retval ResultSuccess 成功しました。 @retval ResultStateBusy デーモンがBUSY状態の為、アクセスできません。 @retval 上記以外 失敗しました。 */ nn::Result SetBoxActivate(bool active); /*! @brief MessageBox の 有効/無効 を取得します。無効にされているBOXのデータは送受信されません。 @return 有効: true / 無効: false */ bool GetBoxActivate(); nn::Result ReadMessageBoxInfo(struct MessageBoxInfo* outbuf) const; nn::Result GetBoxInfo(struct CecBoxInfoHeader* boxinfo, CecMessageHeader** boxInfoBody, CecBoxType boxType) const ; nn::Result ReadBoxInfo(struct CecBoxInfoHeader* boxinfo, CecMessageHeader** boxInfoBody, u8* buf, CecBoxType boxType); protected: nn::Result ReadMessageBoxInfo(struct MessageBoxInfo* outbuf, TitleId cecTitleId) const; nn::Result ReadMessageBoxInfo() const; nn::Result WriteMessageBoxInfo(); nn::Result WriteBoxInfo( CecBoxType boxType ,CecBoxInfoHeader& boxInfo , CecMessageHeader** boxInfoBody); nn::Result ReadInBoxInfo(); nn::Result WriteInBoxInfo(); nn::Result ReadOutBoxInfo(); nn::Result WriteOutBoxInfo(); public: //! @name Message操作 //@{ /*! @brief Message を読み出します。 @param[out] cecMessage 読み出し先の @ref Message クラスのオブジェクト @param[out] buf Message のバイナリ列を格納するバッファ @param[in] bufLen バッファのサイズ @param[in] boxType 受信BOX/送信BOXの指定 @param[in] messageId MessageId の指定 @return nn::Result @retval ResultSuccess 成功しました。 @retval ResultStateBusy デーモンがBUSY状態の為、アクセスできません。時間を空けて再アクセスすることで成功する可能性があります。 @retval ResultNotAuthorized ボックスがOpenされていません。 @retval ResultInvalidArgument 引数の指定に誤りがあるため、読み出すことができません。 @retval 上記以外 失敗しました。 */ nn::Result ReadMessage( Message& cecMessage, void* buf, const size_t bufLen, const CecBoxType boxType, const MessageId& messageId); /*! :private @brief Message を読み出します。 @param[out] bufOut Message のバイナリ列を格納するバッファ @param[in] bufLen バッファのサイズ @param[in] boxType 受信BOX/送信BOXの指定 @param[in] messageId MessageId の指定 @return nn::Result */ nn::Result ReadMessage( void* bufOut, const size_t bufLen, const CecBoxType boxType, const MessageId& messageId); /*! @brief Message を本体保存領域に書きこみます。 Messageのサイズが 100KB(ヘッダ・アイコン等を含む) を超える場合、またはBOXの最大保存容量/個数 をオーバーする場合は書き込むことができません。
NAND(保存領域)のブロックサイズは 4KB であるため、Messageのサイズによっては、最大保存容量まで書き込むことができない場合があります。
書き込みの後、CloseMessageBox または CommitMessageBox を呼んだときに、書き込んだデータを確実なものとします。
Messageを書き込むとき、EULAの同意バージョンチェックが行われますので、ROMにアイコンファイル(ICNファイル)を設定していないと ResultNotAgreeEula が返ります。
チェックには fs の機能を使用しますので、事前にfsライブラリの初期化を行う必要があります。 @param[in] cecMessage @ref Message クラスのオブジェクト @param[in] boxType 受信BOX/送信BOXの指定 @param[out] messageIdOut 書き込むときに付与される MessageId が返ります。 @return nn::Result @retval ResultSuccess 成功しました。 @retval ResultNotAuthorized ボックスがOpenされていません。 @retval ResultMessTooLarge Messageが大きすぎます。 @retval ResultBoxSizeFull ボックスの容量をオーバーしています。 @retval ResultBoxMessNumFull ボックスの最大個数をオーバーしています。 @retval ResultNoData Messageに本文/アイコンが設定されていません。 @retval ResultInvalidCombination 送信回数と伝播回数の値が共に2以上に設定されています。 @retval ResultNotAgreeEula EULAに同意されていない、もしくはROMにアイコンファイル(ICNファイル)が設定されていません。 @retval ResultParentalControlCec ParentalControlで許可されていません。 @retval ResultStateBusy デーモンがBUSY状態の為、アクセスできません。時間を空けて再アクセスすることで成功する可能性があります。 @retval 上記以外 失敗しました。 */ nn::Result WriteMessage( const Message& cecMessage,const CecBoxType boxType, MessageId& messageIdOut); /*! @brief Message を本体保存領域に書きこみます。 Messageのサイズが 100KB(ヘッダ・アイコン等を含む) を超える場合、またはBOXの最大保存容量/個数 をオーバーする場合は書き込むことができません。
NAND(保存領域)のブロックサイズは 4KB であるため、Messageのサイズによっては、最大保存容量まで書き込むことができない場合があります。
書き込みの後、CloseMessageBox または CommitMessageBox を呼んだときに、書き込んだデータを確実なものとします。

withWriteBoxInfo を false にすると、内部のMessageリストの更新をスキップします。連続で複数のMessageを書き込むときの処理時間を短くすることができます。リストが更新されていない状態では、GetMessageBoxXXX 関数で正しい情報を取得できなくなるので注意してください。
Messageを書き込むとき、EULAの同意バージョンチェックが行われますので、ROMにアイコンファイル(ICNファイル)を設定していないと ResultNotAgreeEula が返ります。
チェックには fs の機能を使用しますので、事前にfsライブラリの初期化を行う必要があります。 @param[in] cecMessage @ref Message クラスのオブジェクト @param[in] boxType 受信BOX/送信BOXの指定 @param[out] messageIdOut 書き込むときに付与される MessageId が返ります。 @param[in] withWriteBoxInfo false を指定すると、内部のMessageリストの更新をスキップします。 リストは、CommitMessageBox または CloseMessageBox を呼んだときに更新されます。 @return nn::Result @retval ResultSuccess 成功しました。 @retval ResultNotAuthorized ボックスがOpenされていません。 @retval ResultNoData Message/Message本文が設定されていません。 @retval ResultMessTooLarge Messageが大きすぎます。 @retval ResultBoxSizeFull ボックスの容量をオーバーしています。 @retval ResultBoxMessNumFull ボックスの最大個数をオーバーしています。 @retval ResultNoData Messageに本文/アイコンが設定されていません。 @retval ResultInvalidCombination 送信回数と伝播回数の値が共に2以上に設定されています。 @retval ResultNotAgreeEula EULAに同意されていない、もしくはROMにアイコンファイル(ICNファイル)が設定されていません。 @retval ResultParentalControlCec ParentalControlで許可されていません。 @retval ResultStateBusy デーモンがBUSY状態の為、アクセスできません。時間を空けて再アクセスすることで成功する可能性があります。 @retval 上記以外 失敗しました。 */ nn::Result WriteMessage( const Message& cecMessage,const CecBoxType boxType, MessageId& messageIdOut, bool withWriteBoxInfo); nn::Result WriteMessage( const Message& cecMessage,const CecBoxType boxType) { MessageId messageIdOut; return WriteMessage(cecMessage, boxType, messageIdOut); } /*! :private @brief Message を本体保存領域に書きこみます。 Messageのサイズが 100KB を超える場合、またはBOXの最大保存容量/個数 をオーバーする場合は書き込むことができません。
@param[in] message Message のバイナリ列を格納するバッファ @param[in] messageLen バッファのサイズ @param[in] boxType 受信BOX/送信BOXの指定 @param[out] messageIdOut 書き込むときに付与される MessageId が返ります。 @return nn::Result */ nn::Result WriteMessage( const void* message, const size_t messageLen ,const CecBoxType boxType, MessageId& messageIdOut); /*! @brief Message を削除します。 変更の後、CloseMessageBox または CommitMessageBox を呼んだときに、書き込んだデータを確実なものとします。
@param[in] boxType 受信BOX/送信BOXの指定 @param[in] messageId MessageId の指定 @return nn::Result @retval ResultSuccess 成功しました。 @retval ResultNotAuthorized ボックスがOpenされていません。 @retval 上記以外 失敗しました。 */ nn::Result DeleteMessage( const CecBoxType boxType, const MessageId& messageId); /*! @brief Message を削除します。 変更の後、CloseMessageBox または CommitMessageBox を呼んだときに、書き込んだデータを確実なものとします。

withWriteBoxInfo を false にすると、内部のMessageリストの更新をスキップします。連続で複数のMessageを削除するときの処理時間を短くすることができます。リストが更新されていない状態では、GetMessageBoxXXX 関数で正しい情報を取得できなくなるので注意してください。 @param[in] boxType 受信BOX/送信BOXの指定 @param[in] messageId MessageId の指定 @param[in] withWriteBoxInfo false を指定すると、内部のMessageリストの更新をスキップします。 リストは、CommitMessageBox または CloseMessageBox を呼んだときに更新されます。 @return nn::Result @retval ResultSuccess 成功しました。 @retval ResultNotAuthorized ボックスがOpenされていません。 @retval 上記以外 失敗しました。 */ nn::Result DeleteMessage( const CecBoxType boxType, const MessageId& messageId, bool withWriteBoxInfo); /*! @brief Box内の全Message を削除します。 @param[in] boxType 受信BOX/送信BOXの指定 @return nn::Result @retval ResultSuccess 成功しました。 @retval ResultNotAuthorized ボックスがOpenされていません。 @retval 上記以外 失敗しました。 */ nn::Result DeleteAllMessages(const CecBoxType boxType); u32 DeleteSentMessages(); /*! @brief 本体保存領域に書き込んだデータを確実なものとします。 この関数を呼ばずにプログラムが停止した場合、 前回のコミットからこれまでの変更(ボックスの作成、メッセージの書き込み・削除など)は全て巻き戻される可能性があります。
(システムが通信で受信したデータを保存したときにもコミットは行われるので、 この関数でコミットを行わないと必ず前の状態に戻ってしまうというわけではありません。)
スリープ・HOMEメニューへの移行など、通信の制御がシステムに戻った後で、 変更が巻き戻される可能性があるため、注意してください。
@ref CloseMessageBox の呼んだときにもコミットは行われます。 @return nn::Result @retval ResultSuccess 成功しました。 @retval 上記以外 失敗しました。 */ nn::Result CommitMessageBox(); //@} protected: u8 ReadInBoxMessage(void* bufOut, const size_t messageLen, const MessageId& messageId); u8 WriteInBoxMessage(const void* message, const size_t messageLen, MessageId* pMessageIdOut); u8 WriteInBoxMessage(Message& cecMessage, MessageId* pMessageId); u8 DeleteInBoxMessage(const CECMessageId messageId); u8 ReadOutBoxMessage(void* bufOut, const size_t messageLen, const MessageId& messageId); u8 WriteOutBoxMessage(const void* message, const size_t messageLen, MessageId* pMessageIdOut); u8 WriteOutBoxMessage(Message& cecMessage, MessageId* pMessageIdOut); u8 DeleteOutBoxMessage(const MessageId& messageId); nn::Result CheckEulaParentalControl(); public: // Box List //! @name BOX制御・情報取得 //@{ /*! @brief MessageBox に付随するデータを取得します。 @param[in] datatype データ種別を指定します。 @ref CecBoxDataType で指定します。 @param[out] dataBuf バッファを指定します。 @param[in] dataBufSize バッファサイズを指定します。 @return nn::Result @retval ResultSuccess 成功しました。 @retval 上記以外 失敗しました。 */ nn::Result GetMessageBoxData(u32 datatype, void* dataBuf, size_t dataBufSize); /*! @brief MessageBox に付随するデータサイズを取得します。 @param[in] datatype データ種別を指定します。 @ref CecBoxDataType で指定します。 @return データサイズ */ size_t GetMessageBoxDataSize(const u32 datatype); /*! @brief MessageBox に付随するデータをセットします。 @param[in] datatype データ種別を指定します。 @ref CecBoxDataType で指定します。 @param[in] data データを指定します。 @param[in] dataSize データサイズを指定します。最大長は 10KB です。 @return nn::Result @retval ResultSuccess 成功しました。 @retval ResultNotAuthorized ボックスがOpenされていません。 @retval ResultTooLarge データサイズが大きすぎます。 @retval 上記以外 失敗しました。 */ nn::Result SetMessageBoxData(u32 datatype, const void* data, size_t dataSize); /*! @brief MessageBox の名称をセットします。 @param[in] data 本体管理画面等で表示される名称を指定します。
文字コード: UTF16-LE
表示サイズ: 全角17文字で表示できる文字数
バッファ最大: 64×2Bytes (NULL終端込み)
@param[in] dataSize データサイズを指定します。 @return nn::Result @retval ResultSuccess 成功しました。 @retval ResultNotAuthorized ボックスがOpenされていません。 @retval ResultInvalidData データサイズが大きすぎます。 @retval 上記以外 失敗しました。 */ nn::Result SetMessageBoxName(const wchar_t* data, size_t dataSize); /*! @brief MessageBox のアイコンをセットします。 すれちがい通信関連で、本体管理画面等で扱われるアイコンには2種類あります。
Boxに付随するアイコン・個々のMessageに付随するアイコンがあり、これらを設定しておく必要があります。
この関数では、Boxのアイコンをセットします。 @param[in] data 本体管理画面等で表示されるアイコンデータを指定します。
フォーマット: RGB565 (リトルエンディアン)
サイズ: 48×48 (4.5KBytes)
@param[in] dataSize データサイズを指定します。 @return nn::Result @retval ResultSuccess 成功しました。 @retval ResultNotAuthorized ボックスがOpenされていません。 @retval 上記以外 失敗しました。 */ nn::Result SetMessageBoxIcon(const void* data, size_t dataSize); /*! @brief MessageBox の名称を取得します。 @param[out] dataBuf バッファを指定します。
文字コード: UTF16-LE
表示サイズ: 全角17文字で表示できる文字数
バッファ最大: 64×2Bytes (NULL終端込み)
@param[in] dataBufSize バッファサイズを指定します。 @return nn::Result @retval ResultSuccess 成功しました。 @retval 上記以外 失敗しました。 */ nn::Result GetMessageBoxName(wchar_t* dataBuf, size_t dataBufSize); /*! @brief MessageBox のアイコンを取得します。 @param[out] dataBuf バッファを指定します。
フォーマット: RGB565 (リトルエンディアン)
サイズ: 48×48 (4.5KBytes)
@param[in] dataBufSize バッファサイズを指定します。 @return nn::Result @retval ResultSuccess 成功しました。 @retval 上記以外 失敗しました。 */ nn::Result GetMessageBoxIcon(void* dataBuf, size_t dataBufSize); /*-----------------------------------------------*/ //! @name BOX情報取得 //@{ /*! @brief MessageBox の属性 を取得します。 @return @ref MessageBoxFlag */ MessageBoxFlag GetBoxFlag(); u32 GetInBoxSizeMax(); u32 GetInBoxSize(); u32 GetOutBoxSizeMax(); u32 GetOutBoxSize(); /*! @brief 送信 BOX / 受信BOX の容量を取得します。 @param[in] boxType 送信 BOX / 受信BOXの指定 @return 容量の値が返ります。(BOX作成時に指定したものと同じです。) */ u32 GetBoxSizeMax(CecBoxType boxType); /*! @brief 送信 BOX / 受信BOX の使用量を取得します。 @param[in] boxType 送信 BOX / 受信BOXの指定 @return 使用量の値が返ります。 */ u32 GetBoxSize(CecBoxType boxType); /*-----------------------------------------------*/ u32 GetInBoxMessNumMax(); u32 GetInBoxMessNum(); u32 GetOutBoxMessNumMax(); u32 GetOutBoxMessNum(); /*! @brief 送信 BOX / 受信BOX の最大 Message 数を取得します。 @param[in] boxType 送信 BOX / 受信BOXの指定 @return 個数の値が返ります。(BOX作成時に指定したものと同じです。) */ u32 GetBoxMessNumMax(CecBoxType boxType); /*! @brief 送信 BOX / 受信BOX の Message 数を取得します。 @param[in] boxType 送信 BOX / 受信BOXの指定 @return 個数の値が返ります。 */ u32 GetBoxMessNum(CecBoxType boxType); /*-----------------------------------------------*/ u32 GetInBoxGroupNumMax(); u32 GetInBoxGroupNum(); u32 GetOutBoxGroupNumMax(); u32 GetOutBoxGroupNum(); /*! @brief 送信 BOX / 受信BOX の最大 Message Group 数を取得します。 @param[in] boxType 送信 BOX / 受信BOXの指定 @return Message Group 数の値が返ります。(SetBoxGroupNumMax で指定した値です。) */ u32 GetBoxGroupNumMax(CecBoxType boxType); /*! @brief 送信 BOX / 受信BOX の Message Group 数を取得します。 @param[in] boxType 送信 BOX / 受信BOXの指定 @return Message Group 数の値が返ります。 */ u32 GetBoxGroupNum(CecBoxType boxType); /*! @brief 送信 BOX / 受信BOX の 最大 Message Group 数を指定します。
実際にこの値でGroup数が制限されることはありません。
保存可能数としての目安の値です。
受信BOXのサイズ(GetBoxSizeMax(CEC_BOXTYPE_INBOX)) ÷ 1Group のサイズ、
または、 受信BOX の最大 Message 数(GetBoxMessNumMax(CEC_BOXTYPE_INBOX)) ÷ 1GroupのMessage数 の値を指定するのが目安となります。 @param[in] num 最大 Group 数 @param[in] boxType 送信 BOX / 受信BOXの指定 @return nn::Result @retval ResultSuccess 成功しました。 @retval ResultNotAuthorized ボックスがOpenされていません。 @retval ResultInvalidArgument Group数の値が無効です。 @retval 上記以外 失敗しました。 */ nn::Result SetBoxGroupNumMax(u32 num, CecBoxType boxType); nn::Result SetInBoxGroupNumMax(u32 num); nn::Result SetOutBoxGroupNumMax(u32 num); /*-----------------------------------------------*/ //u32 GetInBoxSessionNumMax(); u32 GetInBoxSessionNum(); //u32 GetOutBoxSessionNumMax(); //u32 GetOutBoxSessionNum(); /*! @brief 受信BOX の Session ID 数(=受信した回数)を取得します。 Session ID は、通信相手の検索に入る前に乱数で生成されます。
相手を発見して通信するときに、相手にその ID を渡します。
データ受信側は、相手の Session ID を 受信Message に書き込みます。
1回のすれちがい通信で受信したデータ全てに、同じSession ID が書き込まれます。
GroupIDが同じでも、Session ID が異なる場合は、別の通信で受信したデータであることがわかります。BOX内のMessageの Session 数をカウントすることで、受信した回数を知ることができます。
@param[in] boxType CecBoxType で指定します。CEC_BOXTYPE_INBOX を指定します。 @return Session ID 数の値が返ります。 */ u32 GetBoxSessionNum(CecBoxType boxType); /*-----------------------------------------------*/ //@} #if 1 // BoxInfoReader の Message情報取得部を使用する。重複するため、元々Boxクラスにあった部分を将来的に削除。 //! @name Message情報取得(旧API) //@{ u32 GetInBoxMessHeader(CecMessageHeader& messHeader, const MessageId& messageId); u32 GetInBoxMessHeaderByIndex(CecMessageHeader& messHeader, u32 messIndex); /*! @brief 受信BOXの n 番目 の Message の MessageID を取得します。 GetMessageMessId で取得できる値と同じです。 @param[in] messIndex n 番目 @return @ref CECMessageId が返ります。 */ u8* GetInBoxMessIdByIndex(u32 messIndex); u32 GetOutBoxMessHeader(CecMessageHeader& messHeader, const MessageId& messageId); u32 GetOutBoxMessHeaderByIndex(CecMessageHeader& messHeader, u32 messIndex); /*! @brief 送信BOXの n 番目 の Message の MessageID を取得します。 GetMessageMessId で取得できる値と同じです。 @param[in] messIndex n 番目(n=0が先頭を示します。) @return @ref CECMessageId が返ります。 */ u8* GetOutBoxMessIdByIndex(u32 messIndex); /*! @brief MessageID を指定して Message のサイズを取得します。 GetMessageMessSize で取得できる値と同じです。 @param[in] boxType 送信 BOX / 受信BOXの指定 @param[in] messId MessageId @return サイズの値が返ります。 */ size_t GetMessSizeByMessId(CecBoxType boxType, const MessageId& messageId); size_t GetBodySizeByMessId(CecBoxType boxType, const MessageId& messageId); //@} #endif CecMessageHeader* GetMessHeaderByMessId(const CecBoxType boxType, const MessageId& messId); CecMessageHeader* GetMessHeader(const CecBoxType boxType, const u32 messIndex); bool MessageExists(CecBoxType boxType, const MessageId& messageId); //! @name Message の情報取得 //@{ /*! * @brief BoxのMessageのサイズを取得します。 * @param[in] boxType @ref CecBoxType * @param[in] messIndex n番目のMessage * @return Messageのサイズ */ u32 GetMessageMessSize(const CecBoxType boxType, const u32 messIndex); /*! * @brief BoxのMessageの本文サイズを取得します。 * @param[in] boxType @ref CecBoxType * @param[in] messIndex n番目のMessage * @return Messageの本文サイズ */ u32 GetMessageBodySize(const CecBoxType boxType, const u32 messIndex); /*! * @brief BoxのMessageの Group ID を取得します。 * @param[in] boxType @ref CecBoxType * @param[in] messIndex n番目のMessage * @return Messageの Group ID */ u32 GetMessageGroupId(const CecBoxType boxType, const u32 messIndex); /*! * @brief 受信BoxのMessageの Session ID を取得します。(受信時に付与されるIDです) * @param[in] boxType @ref CecBoxType * @param[in] messIndex n番目のMessage * @return Messageの Session ID */ u32 GetMessageSessionId(const CecBoxType boxType, const u32 messIndex); /*! * @brief BoxのMessageの @ref CecMessageTypeFlag を取得します。 * @param[in] boxType @ref CecBoxType * @param[in] messIndex n番目のMessage * @return @ref CecMessageTypeFlag */ MessageTypeFlag GetMessageMessTypeFlag(const CecBoxType boxType, const u32 messIndex); /*! * @brief BoxのMessageの @ref SendMode を取得します。 * @param[in] boxType @ref CecBoxType * @param[in] messIndex n番目のMessage * @return @ref SendMode */ SendMode GetMessageSendMode(const CecBoxType boxType, const u32 messIndex); /*! * @brief BoxのMessageの 送信回数 を取得します。 * @param[in] boxType @ref CecBoxType * @param[in] messIndex n番目のMessage * @return 送信回数 */ u8 GetMessageSendCount(const CecBoxType boxType, const u32 messIndex); /*! * @brief BoxのMessageの 伝播回数 を取得します。 * @param[in] boxType @ref CecBoxType * @param[in] messIndex n番目のMessage * @return 伝播回数 */ u8 GetMessagePropagationCount(const CecBoxType boxType, const u32 messIndex); /*! :private * @brief BoxのMessageの 未読フラグ を取得します。 * @param[in] boxType @ref CecBoxType * @param[in] messIndex n番目のMessage * @return 未読フラグ */ bit8 GetMessageFlag_Unread(const CecBoxType boxType, const u32 messIndex); /*! :private * @brief BoxのMessageの 新着フラグ を取得します。 * @param[in] boxType @ref CecBoxType * @param[in] messIndex n番目のMessage * @return 新着フラグ */ bit8 GetMessageFlag_New(const CecBoxType boxType, const u32 messIndex); /*! * @brief BoxのMessageの Tag を取得します。 * @param[in] boxType @ref CecBoxType * @param[in] messIndex n番目のMessage * @return Tag */ bit16 GetMessageTag(const CecBoxType boxType, const u32 messIndex); /*! * @brief Boxの受信Messageの 送信日時 を取得します。 * @param[in] boxType @ref CecBoxType * @param[in] messIndex n番目のMessage * @return @ref nn::fnd::DateTimeParameters */ nn::fnd::DateTimeParameters GetMessageSendDate(const CecBoxType boxType, const u32 messIndex); /*! * @brief Boxの受信Messageの 受信日時 を取得します。 * @param[in] boxType @ref CecBoxType * @param[in] messIndex n番目のMessage * @return @ref nn::fnd::DateTimeParameters */ nn::fnd::DateTimeParameters GetMessageRecvDate(const CecBoxType boxType, const u32 messIndex); /*! * @brief BoxのMessageの 作成日時 を取得します。 * @param[in] boxType @ref CecBoxType * @param[in] messIndex n番目のMessage * @return @ref nn::fnd::DateTimeParameters */ nn::fnd::DateTimeParameters GetMessageCreateDate(const CecBoxType boxType, const u32 messIndex); /*! * @brief 交換された Message の 対になる MessageID を取得します。 通信の方式に「交換」を 指定して通信したとき、対になる 送信 Message の MessageID が、受信 Message に記録されます。 * @param[out] messId @ref MessageId * @param[in] boxType @ref CecBoxType * @param[in] messIndex n番目のMessage * @return nn::Result @retval ResultSuccess 成功しました。 @retval ResultNoData MessageIdの値がありません。 @retval 上記以外 失敗しました。 */ nn::Result GetMessageMessIdPair(MessageId* messId, const CecBoxType boxType, const u32 messIndex); MessageId GetMessageMessIdPair(const CecBoxType boxType, const u32 messIndex); /*! * @brief BoxのMessageの MessageID を取得します。 * @param[out] messId @ref MessageId * @param[in] boxType @ref CecBoxType * @param[in] messIndex n番目のMessage * @return nn::Result @retval ResultSuccess 成功しました。 @retval ResultNoData MessageIdの値がありません。 @retval 上記以外 失敗しました。 */ nn::Result GetMessageMessId(MessageId* messId, const CecBoxType boxType, const u32 messIndex); MessageId GetMessageMessId(const CecBoxType boxType, const u32 messIndex); /*! * @brief MessageID から、何番目のMessageであるか(messIndex)を取得します。 * @param[in] boxType @ref CecBoxType * @param[in] messId MessageId * @return messIndex */ u32 GetMessIndex(CecBoxType boxType, MessageId& messId); u32 GetMessIndex(CecBoxType boxType, u8* messId); //@} /*! :private @brief 送信BOX の Message 送信順リストの末尾に MessageID を追加します。 ( @ref WriteMessage で Message をセットした時点で自動的に追加されるので、 通常はこのAPIを使う必要はありません。) @param[in] messageId MessageID を指定します。 @return リストの MessageID 数 が返ります。 */ u32 AppendOutBoxIndex(const MessageId& messageId); /*! :private @brief 送信BOX の Message 送信順リストから MessageID を削除します。 ( Message を削除した時点で自動的にリストから削除されるので、 通常はこのAPIを使う必要はありません。) @param[in] messageId MessageID を指定します。 @return リストの MessageID 数 が返ります。 */ u32 RemoveOutBoxIndex(const MessageId& messageId); /*! @brief 送信BOX の Message 送信順リスト内で、指定した MessageID の Message を末尾に回します。 ( Message を送信した時点で自動的に順番を変更されるので、 通常はこのAPIを使う必要はありません。) @param[in] messageId MessageID を指定します。 @return リストの MessageID 数 が返ります。 */ u32 RoundOutBoxIndex(const MessageId& messageId); u32 ResetOutBoxIndex(); u32 ReadOutBoxIndex(); nn::Result WriteOutBoxIndex(); bool IsAgreeEulaAppRequired(); protected: //IPC virtual nn::Result OpenFile(const u32 cecTitleId, const u32 dataType, const u32 option, size_t* filesize ) const ; virtual nn::Result ReadFile(void* readBuf, size_t readBufLen, size_t* readLen) const; virtual nn::Result WriteFile(const void* writeBuf, const size_t writeBufLen) const; virtual nn::Result ReadMessageFile( u32 cecTitleId, u8 boxType, const u8* pMessId, size_t messIdLen, size_t* pReadLen, u8* pReadBuf, size_t len); virtual nn::Result ReadMessageFileWithHmac( u32 cecTitleId, u8 boxType, const u8* pMessId, size_t messIdLen, size_t* pReadLen, u8* pReadBuf, size_t len, u8* pHmac); virtual nn::Result WriteMessageFile( u32 cecTitleId, u8 boxType, u8* pMessId, size_t messIdLen, const u8* pWriteBuf, size_t len); virtual nn::Result WriteMessageFileWithHmac( u32 cecTitleId, u8 boxType, u8* pMessId, size_t messIdLen, const u8* pWriteBuf, size_t len, u8* pHmac); virtual nn::Result Delete( u32 cecTitleId, u32 dataType, u8 boxType, const u8 pMessId[], size_t messIdLen ); virtual nn::Result SetData(u32 cecTitleId, const u8* pSetBuf, size_t len, u32 option); virtual nn::Result ReadData(u8 *pReadBuf, size_t len, u32 option, const u8 optionData[], size_t optionDataLen); }; } // namespace CTR } // namespace cec } // namespace nn #endif //__MESSAGE_BOX_H__