伝説のツール「NotesPeek」をQtでリメイクする(その13・名前)
Notesが扱うデータの基本型は、テキスト、数値、日時の3つとその複数値です。それ以外については、おおよそ次の3つに分けられます。1つはリッチテキスト、2つめがバイナリ形式、そして3つめが基本型に応用になります。2つめのバイナリ形式は、画像や添付ファイル、@式などがそれにあたります。そして3つめの「基本型の応用」とは、基本型に書式や属性によって意味を持たせたものを指します。
例えば今回のお題「名前」は、「型」という意味では単なる「テキスト」です。しかし、「CN=Taro Yamada/OU=Sales/O=Acme」という「書式」を持つことで「名前型」というデータになります。
Notes APIにおいて、「名前型」はDNという接頭辞で始まる関数を使います。Notes/Domino APIプログラミング―C++とSTLによる実践的プログラミングによると、「Domain Name」(領域名)の略だとあります。一方、APIのリファレンスには「Distinguished Name」(識別名)のように書かれています。訳語からいっても後者ではないかと思います。ただ、残念なことに今回の実装には「Domain Name」の方でクラスを構築してしまったので、次のバージョンでは修正したいと思っています(少々綴りが長いですが)。
識別名クラスには、1つのメンバ変数(Lmbcs型)を保持するシンプルクラスです。ルールとして、このメンバ変数に保存する識別名は常に「基準書式(Canonical)」であることとします。
最初にヘッダーファイルの実装例をご覧ください。
// ntlx/domainname.h #ifndef NTLX_DOMAINNAME_H #define NTLX_DOMAINNAME_H #include <ntlx/lmbcs.h> namespace ntlx { /** * @brief ドメイン名(基準書式名)クラス */ class NTLXSHARED_EXPORT DomainName : public IStatus { public: /** * @brief デフォルトコンストラクタ */ DomainName(); /** * @brief コンストラクタ(LMBCS文字列から) * @param name 書式化する名前文字列(LMBCS) */ DomainName(const Lmbcs& name); /** * @brief コンストラクタ(QString文字列から) * @param name 書式化する名前文字列(QString) */ DomainName(const QString& name); /** * @brief コピーコンストラクタ * @param other コピー元 */ DomainName(const DomainName& other); /** * @brief 代入演算子 * @param other 代入元 * @return 自身への参照 */ DomainName& operator=(const DomainName& other); /** * @brief 文字列が空なら真 * @return 真/偽 */ bool isEmpty() const { return name_.isEmpty(); } /** * @brief 基準書式をLMBCSで返す * @return 基準書式LMBCS */ Lmbcs canonical() const { return name_; } /** * @brief 省略書式をLMBCSで返す * @return 省略書式LMBCS */ Lmbcs abbreviated() const; /** * @brief 代入演算子 * @param name 代入元LMBCS * @return */ DomainName& operator=(const Lmbcs& name); /** * @brief 代入演算子 * @param name 代入元QString * @return */ DomainName& operator=(const QString& name); /** * @brief 等価演算子 * @param lhs 左辺 * @param rhs 右辺 * @return 等価なら真 */ friend bool operator==(const DomainName& lhs, const DomainName& rhs); /** * @brief 不等価演算子 * @param lhs 左辺 * @param rhs 右辺 * @return 不透過なら真 */ friend bool operator!=(const DomainName& lhs, const DomainName& rhs); protected: void canonicalize(const Lmbcs& name); private: Lmbcs name_; }; } // namespace ntlx #endif // NTLX_DOMAINNAME_H
次に、ソースファイルの実装例です。
// domainname.cpp #include "ntlx/domainname.h" #if defined(NT) #pragma pack(push, 1) #endif #include <dname.h> #include <names.h> #if defined(NT) #pragma pack(pop) #endif namespace ntlx { DomainName::DomainName() : IStatus() , name_() { } DomainName::DomainName(const Lmbcs& name) : IStatus() , name_() { canonicalize(name); } DomainName::DomainName(const QString& name) : IStatus() , name_() { canonicalize(Lmbcs::fromQString(name)); } DomainName::DomainName(const DomainName &other) : IStatus() , name_(other.name_) { } DomainName& DomainName::operator=(const DomainName& other) { if (this == &other) return *this; name_ = other.name_; return *this; } Lmbcs DomainName::abbreviated() const { char abbreviate[MAXUSERNAME]; WORD len; lastStatus_ = DNAbbreviate( 0L , nullptr , name_.constData() , abbreviate , MAXUSERNAME , &len ); if (lastStatus().success()) return Lmbcs(abbreviate, len); return Lmbcs(); } void DomainName::canonicalize(const Lmbcs& name) { char buffer[MAXUSERNAME]; WORD len; lastStatus_ = DNCanonicalize( 0L , nullptr , name.constData() , buffer , MAXUSERNAME , &len ); if (lastStatus().success()) name_ = Lmbcs(buffer, len); else name_ = Lmbcs(); } DomainName& DomainName::operator=(const Lmbcs& name) { canonicalize(name); return *this; } DomainName& DomainName::operator=(const QString& name) { canonicalize(Lmbcs::fromQString(name)); return *this; } bool operator==(const DomainName& lhs, const DomainName& rhs) { return lhs.name_ == rhs.name_; } bool operator!=(const DomainName& lhs, const DomainName& rhs) { return !operator==(lhs, rhs); } } // namespace ntlx
ポイントは、abbreviatdメソッドとcanonicalizeメソッドでしょう。
まず、canonicalizeメソッドはLMBCS文字列を受け取って、それを基準書式に変換して内部のメンバ変数に保持します。
次にabbreviatedメソッドは、内部のメンバ変数を省略書式にしてLmbcsとして返します。
他にも識別名には関数が存在しますが、今回はここまでとします。