NotesとQtでWindows、Mac OS X、Ubuntuのデスクトップアプリ(その5 - LMBCS変換・基本編)
それでは、LMBCSをラップしたクラス、Lmbcsを定義していきます。
<ntlx_global.h> #ifndef NTLX_GLOBAL_H #define NTLX_GLOBAL_H #include <QtCore/qglobal.h> #if defined(NTLX_LIBRARY) # define NTLXSHARED_EXPORT Q_DECL_EXPORT #else # define NTLXSHARED_EXPORT Q_DECL_IMPORT #endif #endif // NTLX_GLOBAL_H
<lmbcs.h> #ifndef NTLX_LMBCS_H #define NTLX_LMBCS_H #include "ntlx_global.h" #include "status.h" #include <QByteArray> namespace ntlx { const int MAX_UNICODE_LEN = (1024 * 42 / 2); class NTLXSHARED_EXPORT Lmbcs : public QByteArray { public: /** * @brief コンストラクタ */ Lmbcs(); /** * @brief コピー元LMBCSの文字列ポインタと長さによるコンストラクタ * @param コピー元LMBCSのポインタ * @param len コピー元LMBCSの長さ、0終端している場合は-1 */ Lmbcs(const char* s, int len = -1); /** * @brief ステータス値からエラーメッセージのLMBCSを生成する * @param status ステータス値 */ Lmbcs(STATUS status); /** * @brief コピーコンストラクタ * @param other コピー元 */ Lmbcs(const Lmbcs& other); /** * @brief 代入演算子 * @param other 代入元 * @return 自身への参照 */ Lmbcs& operator=(const Lmbcs& other); /** * @brief QStringに変換する * @return LMBCSから変換されたQString文字列 */ QString toQString() const; /** * @brief QStringからLmbcsに変換する * @note 変換できる文字列の長さはMAX_UNICODE_LENに制限 * @param qs 変換元のQString * @return QStringから変換されたLmbcsオブジェクト */ static Lmbcs fromQString(const QString& qs); }; } // namespace ntlx #endif // NTLX_LMBCS_H
<lmbcs.cpp> #include "lmbcs.h" #include <QString> #if defined(NT) #pragma pack(push, 1) #endif #include <osmisc.h> #if defined(NT) #pragma pack(pop) #endif namespace ntlx { const WORD UNICODE_BYTE = (sizeof(ushort) / sizeof(char)); Lmbcs::Lmbcs() : QByteArray() { } Lmbcs::Lmbcs(const char *s, int len) : QByteArray(s, len) { } Lmbcs::Lmbcs(STATUS status) : QByteArray() { char buffer[MAXWORD]; WORD lmbcsLen = OSLoadString(0, Status(status).error(), buffer, MAXWORD); *this = Lmbcs(buffer, lmbcsLen); } Lmbcs::Lmbcs(const Lmbcs& other) : QByteArray(other) { } Lmbcs& Lmbcs::operator=(const Lmbcs& other) { if (this == &other) return *this; QByteArray::operator=(other); return *this; } QString Lmbcs::toQString() const { char buffer[MAXWORD]; int unicodeLen = OSTranslate( OS_TRANSLATE_LMBCS_TO_UNICODE , constData(), size() <= (int)MAXWORD ? (WORD)size() : MAXWORD , buffer, MAXWORD ); return QString::fromUtf16(reinterpret_cast<ushort*>(buffer) , unicodeLen / UNICODE_BYTE); } Lmbcs Lmbcs::fromQString(const QString &qs) { char buffer[MAXWORD]; QString input = qs.left(MAX_UNICODE_LEN); const ushort* unicode = input.utf16(); WORD unicodeLen = (WORD)input.size() * UNICODE_BYTE; int lmbcsLen = OSTranslate( OS_TRANSLATE_UNICODE_TO_LMBCS , reinterpret_cast<char*>(const_cast<ushort*>(unicode)) , unicodeLen , buffer, MAXWORD ); return Lmbcs(buffer, lmbcsLen); } } // namespace ntlx
コンストラクタには、以下の4つを用意しました。
- デフォルトコンストラクタ(空のLMBCS)
- LMBCSポインタと長さによるコンストラクタ
- ステータス値によるコンストラクタ
- コピーコンストラクタ
3番目の「ステータス値によるコンストラクタ」は、API関数OSLoadStringを利用したコンストラクタです。OSLoadStringは、指定したモジュール(指定しなければNotes)からエラーコードに対応した文字列をロードします。
<osmisc.h> WORD LNPUBLIC OSLoadString (HMODULE hModule , STATUS StringCode , char far *retBuffer , WORD BufferLength);
hModuleハンドルは、文字列を読み込むリソースDLLで、見つからなければNotesが保有する文字列リソースを検索します。リソースDLLがなかったり、MacやLinuxなどの非Windowsプラットフォームで利用する場合は0を指定します。
StringCodeがステータス値です。ここにはERR()マクロを使ってエラーコードのみにマスクする必要があります。先に定義したntlx::Status::errorメソッドが役に立ちます。
retBufferとBufferLengthは、読み込んだ文字列を書き込む領域とそのサイズを指定します。
戻り値は、実際に書き込んだ文字列の長さになります。
次に、OSTranslateを使ってどのようにLMBCSからQString、QStringからLMBCSに変換しているかを見ていきます。
Unicode(UTF-16)の1文字は、全角半角に関係なく、1文字2バイトです。一方LMBCS日本語は、半角英数字は1バイト、全角と半角カナ文字は3バイトです。UnicodeからLMBCSに変換する場合1/2〜3/2倍になります。そこで、64k÷3×2≒42kを入力Unicodeの最大値とし、文字数としては21,504文字とします。
逆に、LMBCSからUnicodeに変換する場合、2/3〜2倍になるという式は成り立ちますが、LMBCSの文字の区切りを手動で判別するのは大変な手間を要します。そこで今回は、入力LMBCSの最大値はWORD最大値まで使用するものとし、バッファあふれは無視します。
次回は、このLMBCS文字列を適切に区切り、WORD幅より大きいサイズの文字列が扱えないか考察します。(続く)