1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     ut_ResDictionary.h
4 
5   Copyright (C)2009-2010 Nintendo Co., Ltd./HAL Laboratory, Inc.  All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law.  They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Revision: 23585 $
14  *---------------------------------------------------------------------------*/
15 
16 #ifndef NW_UT_RESDICTIONARY_H_
17 #define NW_UT_RESDICTIONARY_H_
18 
19 #include <nw/types.h>
20 #include <nw/ut/ut_ResTypes.h>
21 #include <nw/ut/ut_ResUtil.h>
22 #include <nw/ut/ut_ResArray.h>
23 
24 namespace nw {
25 namespace ut {
26 
27 #if 0
28 // 辞書インターフェイス (テンプレートで実現する場合は、このクラスは継承しない)
29 class IResDic
30 {
31 public:
32     // 辞書データが有効かどうかを返します。
33     virtual bool    IsValid() const = 0;
34 
35     // 辞書に登録されている要素数です。
36     virtual s32     GetCount() const = 0;
37 
38     // インデクスやキー文字列の値から要素を取得します。
39     // 辞書中に指定の要素が見つからなかった場合にはNULLを返します。
40     virtual void*   operator[](int idx) const = 0;
41     virtual void*   operator[](u32 idx) const = 0;
42     virtual void*   operator[](const char* key) const   = 0;
43     virtual void*   operator[](const ResName key) const = 0;
44 
45     // キー文字列の値で辞書を検索し、インデクスを取得します。
46     // 指定のキーが見つからなかった場合には、負の数を返します。
47     virtual s32     GetIndex(const char* key) const  = 0;
48     virtual s32     GetIndex(const ResName n ) const = 0;
49 
50     // インデクス番目の要素のキー文字列を取得します。
51     virtual const ResName GetResName(u32 idx) const  = 0;
52     virtual const char*   GetName(u32 idx) const     = 0;
53 };
54 
55 #endif
56 
57 #if 0
58 // 包含クラスを挟む場合
59 template <class TDic>
60 class ResDic
61 {
62 public:
63     /* ctor */ ResDic(TDic& dic) : m_Dic( dic ) {}
64 
65     bool    IsValid() const { m_Dic.IsValid(); }
66     s32     GetCount() const { return m_Dic.GetCount(); }
67     void*   operator[](int idx) const { return m_Dic[ idx ]; }
68     void*   operator[](u32 idx) const { return m_Dic[ idx ]; }
69     void*   operator[](const char* key) const { return m_Dic[ key ]; }
70     void*   operator[](const ResName key) const { return m_Dic[ key ]; }
71 
72     // キー文字列の値で辞書を検索し、インデクスを取得します。
73     // 指定のキーが見つからなかった場合には、負の数を返します。
74     s32     GetIndex(const char* key) const { return m_Dic.GetIndex( key ); }
75     s32     GetIndex(const ResName n ) const { return m_Dic.GetIndex( n ); }
76 
77     // インデクス番目の要素のキー文字列を取得します。
78     const ResName GetResName(u32 idx) const { return m_Dic.GetResName( idx ); }
79     const char*   GetName(u32 idx) const    { return m_Dic.GetName( idx ); }
80 
81 private:
82     TDic& m_Dic;
83 };
84 #endif
85 
86 
87 //! @details :private
88 // 線形探索辞書
89 struct ResDicLinearData : public DataBlockHeader
90 {
91     Size   numData;
92     struct ResDicNodeData
93     {
94         BinString toName;
95         Offset    ofsData;
96     }
97     data[1]; // numData個ある
98 
GetBeginNodeResDicLinearData99     ResDicNodeData* GetBeginNode() { return data; }
GetBeginNodeResDicLinearData100     const ResDicNodeData* GetBeginNode() const { return data; }
101 };
102 
103 //! @details :private
104 class ResDicLinear : public ResCommon<ResDicLinearData>
105 {
106 public:
NW_RES_CTOR(ResDicLinear)107     NW_RES_CTOR( ResDicLinear )
108 
109     s32  GetCount() const { return ref().numData; }
110 
111     // インデクスやキー文字列の値から要素を取得します。
112     // 辞書中に指定の要素が見つからなかった場合にはNULLを返します。
113     void*   operator[](int idx) const
114     {
115         if ( ! this->IsValid() ) { return NULL; }
116         if ( idx < 0 || s32(ref().numData) <= idx ) { return NULL; }
117         return const_cast<void*>( ref().data[idx].ofsData.to_ptr() );
118     }
119     void*   operator[](u32 idx) const { return operator[](int(idx)); }
120     void*   operator[](const char* key) const
121     {
122         s32 idx = this->GetIndex(key);
123         if ( idx < 0 ) { return NULL; }
124         return const_cast<void*>( ref().data[ idx ].ofsData.to_ptr() );
125     }
126 
127     void*   operator[](const ResName key) const
128     {
129         s32 idx = this->GetIndex(key);
130         if ( idx < 0 ) { return NULL; }
131         return const_cast<void*>( ref().data[ idx ].ofsData.to_ptr() );
132     }
133 
134     // キー文字列の値で辞書を検索し、インデクスを取得します。
135     // 指定のキーが見つからなかった場合には、負の数を返します。
136     s32     GetIndex(const char* key) const;
GetIndex(const ResName key)137     s32     GetIndex(const ResName key) const
138     {
139         if ( (! this->IsValid()) || (! key.IsValid()) ) { return -1; }
140         return this->GetIndex(key.GetName());
141     }
142 
143     // インデクス番目の要素のキー文字列を取得します。
GetResName(u32)144     const ResName GetResName(u32 /*idx*/) const { return ResName(); }
GetName(u32)145     const char*   GetName(u32 /*idx*/) const    { return NULL; }
146 };
147 
148 //! @details :private
149 // パトリシア木探索辞書
150 struct ResDicPatriciaData : public DataBlockHeader
151 {
152     ResU32  numData;
153     struct ResDicNodeData
154     {
155         ResU32 ref;
156         ResU16 idxLeft;
157         ResU16 idxRight;
158         Offset ofsString;
159         Offset ofsData;
160     }
161     data[1]; // numData + 1個ある
162 
GetBeginNodeResDicPatriciaData163     ResDicNodeData* GetBeginNode() { return &data[1]; }
GetBeginNodeResDicPatriciaData164     const ResDicNodeData* GetBeginNode() const { return &data[1]; }
165 };
166 
167 //! @details :private
168 // パトリシア辞書アクセサクラス。
169 class ResDicPatricia : public ResCommon< ResDicPatriciaData >
170 {
171 public:
172     enum { NOT_FOUND = -1 };
173 
174     NW_RES_CTOR( ResDicPatricia );
175 
GetCount()176     s32  GetCount() const { return ref().numData; }
177 
178     void* operator[](int idx) const
179     {
180         if (!this->IsValid()) { return NULL; }
181 
182         NW_MINMAX_ASSERT( idx, 0, static_cast<int>(ref().numData - 1) );
183         // 辞書引き関連についてはconst correctnessを維持しなくても問題ないだろう
184         return const_cast<void*>(ref().data[idx + 1].ofsData.to_ptr());
185     }
186 
187     void* operator[](u32 idx) const { return operator[](int(idx)); }
188 
189     void* operator[](const char* s) const
190     {
191         // sがNULLでもOK
192         if (this->IsValid() && s)
193         {
194             ResDicPatriciaData::ResDicNodeData* x = Get(s, std::strlen(s));
195 
196             // 辞書にはNULLの行き先を仮定しなくてよい
197             if (x)
198             {
199                 return const_cast<void*>(x->ofsData.to_ptr());
200             }
201         }
202 
203         return NULL;
204     }
205 
operator()206     void* operator()(const char* s, size_t len) const
207     {
208         // lenを文字列長として設定しているので文字列がNULLというのはNG
209         NW_NULL_ASSERT(s);
210         if (this->IsValid())
211         {
212             ResDicPatriciaData::ResDicNodeData* x = Get(s, len);
213 
214             // 辞書にはNULLの行き先を仮定しなくてよい
215             if (x)
216             {
217                 return const_cast<void*>(x->ofsData.to_ptr());
218             }
219         }
220         return NULL;
221     }
222 
223     void* operator[](const ResName n) const
224     {
225         // 入力が無効でも止まらないようにする
226         if (IsValid() && n.IsValid())
227         {
228             ResDicPatriciaData::ResDicNodeData* x = Get(n);
229 
230             // 辞書にはNULLの行き先を仮定しなくてよい
231             if (x)
232             {
233                 return const_cast<void*>(x->ofsData.to_ptr());
234             }
235         }
236 
237         return NULL;
238     }
239 
GetIndex(const char * s)240     s32 GetIndex(const char* s) const
241     {
242         // sがNULLでもOK
243         if (IsValid() && s)
244         {
245             size_t len = std::strlen(s);
246             ResDicPatriciaData::ResDicNodeData* x = Get(s, len);
247 
248             if (x)
249             {
250                 return static_cast<s32>(x - &ptr()->data[1]);
251                 // エントリ 0 はルートノードであるので 1 との差を取る
252             }
253         }
254 
255         return -1;
256     }
257 
GetIndex(const ResName n)258     s32 GetIndex(const ResName n) const
259     {
260         // 入力が無効でも止まらないようにする
261         if (IsValid() && n.IsValid())
262         {
263             ResDicPatriciaData::ResDicNodeData* x = Get(n);
264 
265             if (x)
266             {
267                 return static_cast<s32>(x - &ptr()->data[1]);
268                 // エントリ 0 はルートノードであるので 1 との差を取る
269             }
270         }
271 
272         return -1;
273     }
274 
GetResName(u32 idx)275     const ResName GetResName(u32 idx) const
276     {
277         if (!IsValid()) { return ResName(NULL); }
278 
279         NW_MINMAX_ASSERT( idx, 0, ptr()->numData - 1 );
280         return ofs_to_obj<ResName>(ptr()->data[idx + 1].ofsString - s32(sizeof(u32)));
281     }
282 
GetName(u32 idx)283     const char* GetName(u32 idx) const
284     {
285         if (!IsValid()) { return NULL; }
286         return GetResName(idx).GetName();
287     }
288 
GetNumData()289     u32 GetNumData() const
290     {
291         if ( !IsValid() ) { return 0; }
292         return ptr()->numData;
293     }
294 
GetLength()295     u32 GetLength() const { return ref().length; }
296 
297 protected:
298     ResDicPatriciaData::ResDicNodeData* Get(const char* s, size_t len) const;
299     ResDicPatriciaData::ResDicNodeData* Get(const ResName rhs) const;
300 };
301 
302 
303 namespace internal {
304 
305     //---------------------------------------------------------------------------
306     //! @brief        要素が空のパトリシア辞書リソースを生成します。
307     //!
308     //! @param[out]   resData 初期化をするパトリシア辞書構造体へのポインタです。
309     //!
310     //! @return       resData へのポインタを返します。
311     //---------------------------------------------------------------------------
312     inline ResDicPatriciaData*
InitializeResDicPatricia(ResDicPatriciaData * resData)313     InitializeResDicPatricia(ResDicPatriciaData* resData)
314     {
315         resData->signature = NW_RES_SIGNATURE32('DICT');
316         resData->length = sizeof(ResDicPatriciaData);
317         resData->numData = 0;
318         resData->data[0].ref = 0xFFFFFFFF;
319         resData->data[0].idxLeft = 0;
320         resData->data[0].idxRight = 0;
321         resData->data[0].ofsString.set_ptr(NULL);
322         resData->data[0].ofsData.set_ptr(NULL);
323 
324         return resData;
325     }
326 
327 
328 } /* namespace internal */
329 
330 } /* namespace ut */
331 } /* namespace nw */
332 
333 #endif /* NW_UT_RESDICTIONARY_H_ */
334