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