1 /*---------------------------------------------------------------------------*
2 Project: NintendoWare
3 File: ut_ResUtil.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_RESUTIL_H_
19 #define NW_UT_RESUTIL_H_
20
21 #include <nw/types.h>
22 #include <nw/ut/ut_ResTypes.h>
23 #include <nw/ut/ut_Iterator.h>
24 #include <cstring>
25 #include <functional>
26 #include <algorithm>
27
28 #define NW_VALIDITY_ASSERT \
29 NW_ASSERTMSG(IsValid(), "%s::%s: Object not valid.", GetClassName(), __FUNCTION__)
30 #define NW_INDEX_ASSERT( name, idx ) \
31 NW_ASSERT( 0<= (idx) && static_cast<s32>(idx) < static_cast<s32>(Get##name##Count()) )
32
33 #ifdef NW_LITTLE_ENDIAN
34 #define NW_RES_SIGNATURE32(val) \
35 ((((val) & 0x000000FF) << 24) | \
36 (((val) & 0x0000FF00) << 8) | \
37 (((val) & 0x00FF0000) >> 8) | \
38 (((val) & 0xFF000000) >> 24) )
39
40 #define NW_RES_SIGNATURE16(val) \
41 ((((val) & 0x00FF) << 8) | \
42 (((val) & 0xFF00) >> 8))
43
44 #define NW_RES_TYPE_INFO(val) (val)
45 #else
46 #define NW_RES_SIGNATURE32(val) (val)
47 #define NW_RES_SIGNATURE16(val) (val)
48 #define NW_RES_TYPE_INFO(val) \
49 ((((val) & 0x000000FF) << 24) | \
50 (((val) & 0x0000FF00) << 8) | \
51 (((val) & 0x00FF0000) >> 8) | \
52 (((val) & 0xFF000000) >> 24) )
53
54 #endif
55
56 namespace nw {
57 namespace ut {
58
59 //! @name リソースキャスト関連
60 //@{
61
62 //---------------------------------------------------------------------------
63 //! @brief リソース型のオブジェクトを別のリソース型へダイナミックキャストします。
64 //! 全く継承ツリーの異なるクラスのキャストには非対応です。
65 //!
66 //! @tparam TDown キャスト先のリソース型です。
67 //! @tparam TBase キャスト元のリソース型です。
68 //! @param[in] res キャスト元のリソースです。
69 //!
70 //! @return TDown型のリソースアクセサへキャストして返します。
71 //---------------------------------------------------------------------------
72 template<class TDown, class TBase>
73 NW_INLINE TDown
ResDynamicCast(TBase res)74 ResDynamicCast( TBase res )
75 {
76 if (!res.IsValid())
77 {
78 return TDown(NULL);
79 }
80
81 if ((res.GetTypeInfo() & TDown::TYPE_INFO) == TDown::TYPE_INFO)
82 {
83 return TDown(res.ptr());
84 }
85 return TDown(NULL);
86 }
87
88 //---------------------------------------------------------------------------
89 //! @brief リソース型のオブジェクトを別のリソース型へスタティックキャストします。
90 //!
91 //! @tparam TDest キャスト先のリソース型です。
92 //! @tparam TSrc キャスト元のリソース型です。
93 //! @param[in] res キャスト元のリソースです。
94 //!
95 //! @return TDest型のリソースアクセサへキャストして返します。
96 //---------------------------------------------------------------------------
97 template<class TDest, class TSrc>
98 NW_INLINE TDest
ResStaticCast(TSrc res)99 ResStaticCast( TSrc res )
100 {
101 // res.ptr() が NULL の場合は チェックを行わずにそのまま NULL を返します。
102 NW_ASSERT( (! res.IsValid()) || ResDynamicCast<TDest>( res ).IsValid() );
103 return TDest( res.ptr() );
104 }
105
106 //@}
107
108 //! @details :private
109 typedef struct DataBlockHeader
110 {
111 ResU32 signature;
112 ResU32 length;
113 } DataBlockHeader;
114
115 /* ------------------------------------------------------------------------
116 NW_RES_CTOR
117
118 ResCommon<T>を継承するリソースアクセサクラスのコンストラクタを
119 定義するためのマクロ。
120 class_nameにはリソースアクセサクラスのクラス名を入れる。
121 4バイトアラインメントでなくてはならない
122
123 operator==, operator!=はポインタがNULLの場合でも動作させるために
124 ptr()を使わない
125 ------------------------------------------------------------------------ */
126 #define NW_RES_CTOR_ALIGN(class_name, align) \
127 typedef class_name SelfType; /*!< :private */ \
128 typedef class_name##Data ResDataType; /*!< :private */ \
129 \
130 /*! @brief コンストラクタです。*/ \
131 /* ctor */ explicit class_name(const void *p = NULL) \
132 : nw::ut::ResCommon<class_name##Data>(p) { NW_ASSERT(!((u32)p & ((align)-1))); } \
133 /*! 実データへの参照を取得します。*/ \
134 class_name##Data& ref() \
135 { \
136 NW_VALIDITY_ASSERT; return *ptr(); \
137 } \
138 /*! 実データへの const 参照を取得します。*/ \
139 const class_name##Data& ref() const \
140 { \
141 NW_VALIDITY_ASSERT; return *ptr(); \
142 } \
143 /*! クラス名の文字列を取得します。*/ /* */ \
144 static const char* GetClassName() \
145 { \
146 return #class_name; \
147 } \
148 /*! 比較演算子のオーバーロードです。*/ \
149 bool operator==(const class_name& rhs) const { return ptr() == rhs.ptr(); } \
150 /*! 不一致の比較演算子のオーバーロードです。*/ \
151 bool operator!=(const class_name& rhs) const { return ptr() != rhs.ptr(); } \
152
153
154 #define NW_RES_CTOR(class_name) NW_RES_CTOR_ALIGN(class_name, 4)
155
156
157 #define NW_RES_CTOR_INHERIT(class_name, base_name) \
158 typedef class_name SelfType; /*!< :private */ \
159 typedef class_name##Data ResDataType; /*!< :private */ \
160 \
161 /*! @brief コンストラクタです。*/ \
162 /* ctor */ explicit class_name(const void* p = NULL) : base_name(p) {} \
163 \
164 /*! @brief 実データへのポインタを取得します。 */ \
165 ResDataType* ptr() \
166 { \
167 return reinterpret_cast<ResDataType*>(void_ptr()); \
168 } \
169 /*! @brief 実データへの const ポインタを取得します。 */ \
170 const ResDataType* ptr() const \
171 { \
172 return reinterpret_cast<const ResDataType*>(void_ptr()); \
173 } \
174 /*! @brief 実データへの参照を取得します。 */ \
175 ResDataType& ref() \
176 { \
177 NW_NULL_ASSERT(void_ptr()); \
178 return *reinterpret_cast<ResDataType*>(void_ptr()); \
179 } \
180 /*! @brief 実データへの const 参照を取得します。 */ \
181 const ResDataType& ref() const \
182 { \
183 NW_NULL_ASSERT(void_ptr()); \
184 return *reinterpret_cast<const ResDataType*>(void_ptr()); \
185 } \
186 /*! クラス名の文字列を取得します。*/ \
187 static const char* GetClassName() { return #class_name; } \
188 /*! 比較演算子のオーバーロードです。*/ \
189 bool operator==(const class_name& rhs) const { return ptr() == rhs.ptr(); } \
190 /*! 不一致の比較演算子のオーバーロードです。*/ \
191 bool operator!=(const class_name& rhs) const { return ptr() != rhs.ptr(); } \
192
193
194 /*------------------------------------------------------------------------
195 共通部分の定義
196
197 Tを実体化したクラスを継承して使う。おおよそのアクセサの基底クラスにできる
198 データメンバはmpData以外に存在してはならない
199 ------------------------------------------------------------------------*/
200 //--------------------------------------------------------------------------
201 //! @brief リソースアクセサの基底クラスの共通部分定義です。
202 //---------------------------------------------------------------------------
203 class ResCommonBase
204 {
205 private:
206 void* mpData;
207
208 public:
209 //! @brief コンストラクタです。
ResCommonBase(void * p)210 explicit ResCommonBase(void *p) : mpData(p) {}
ResCommonBase(const void * p)211 explicit ResCommonBase(const void* p) : mpData(const_cast<void*>(p)) {}
212
213 //--------------------------------------------------------------------------
214 //! @brief リソースへのポインタが null でないかどうかを判定します。
215 //!
216 //! @return 保持しているリソースへのポインタが null の場合には false、
217 //! null でない場合には true を返します。
218 //---------------------------------------------------------------------------
IsValid()219 bool IsValid() const { return (mpData != NULL); }
220
221 protected:
222 //! @details :private
void_ptr()223 NW_FORCE_INLINE void* void_ptr() { return mpData; }
224 //! @details :private
void_ptr()225 NW_FORCE_INLINE const void* void_ptr() const { return mpData; }
226
227 // 構造体の先頭からofsバイト先のポインタを返します。ofsが0の場合はNULLを返します。
228 //! @details :private
229 template<class X>
ofs_to_ptr(Offset ofs)230 X* ofs_to_ptr(Offset ofs)
231 {
232 // ofsはmpDataから辿るデータであることが多いのでmpDataのチェックはしない
233 u8* p = reinterpret_cast<u8*>(mpData);
234 if (ofs != 0)
235 {
236 return reinterpret_cast<X*>(p + ofs);
237 }
238 else
239 {
240 return NULL;
241 }
242 }
243
244 // 構造体の先頭からofsバイト先のポインタを返します。ofsが0の場合はNULLを返します。
245 //! @details :private
246 template<class X>
ofs_to_ptr(Offset ofs)247 const X* ofs_to_ptr(Offset ofs) const
248 {
249 // ofsはmpDataから辿るデータであることが多いのでmpDataのチェックはしない
250 const u8* p = reinterpret_cast<const u8*>(mpData);
251 if (ofs != 0)
252 {
253 return reinterpret_cast<const X*>(p + ofs);
254 }
255 else
256 {
257 return NULL;
258 }
259 }
260
261 // 構造体の先頭からofsバイト先のポインタを引数にしたアクセサオブジェクトを返します。
262 // ofsが0の場合はNULLを引数にしたアクセサオブジェクトを返します。
263 //! @details :private
264 template<class X>
ofs_to_obj(Offset ofs)265 X ofs_to_obj(Offset ofs)
266 {
267 // ofsはmpDataから辿るデータであることが多いのでmpDataのチェックはしない
268 u8* p = reinterpret_cast<u8*>(mpData);
269 if (ofs != 0)
270 {
271 return X(p + ofs);
272 }
273 else
274 {
275 return X(NULL);
276 }
277 }
278
279 // 構造体の先頭からofsバイト先のポインタを引数にしたアクセサオブジェクトを返します。
280 // ofsが0の場合はNULLを引数にしたアクセサオブジェクトを返します。
281 //! @details :private
282 template<class X>
ofs_to_obj(Offset ofs)283 const X ofs_to_obj(Offset ofs) const
284 {
285 // ofsはmpDataから辿るデータであることが多いのでmpDataのチェックはしない
286 const u8* p = reinterpret_cast<const u8*>(mpData);
287 if (ofs != 0)
288 {
289 return X(const_cast<u8*>(p + ofs));
290 }
291 else
292 {
293 return X(NULL);
294 }
295 }
296
297 // ofs_to_ptrで、ofs!=0であることが保証できる場合に使用できます。
298 //! @details :private
299 template<class X>
ofs_to_ptr_raw(Offset ofs)300 X* ofs_to_ptr_raw(Offset ofs)
301 {
302 NW_ASSERT(ofs != 0);
303 return reinterpret_cast<X*>(reinterpret_cast<u8*>(mpData) + ofs);
304 }
305
306 // ofs_to_ptrで、ofs!=0であることが保証できる場合に使用できます。
307 //! @details :private
308 template<class X>
ofs_to_ptr_raw(Offset ofs)309 const X* ofs_to_ptr_raw(Offset ofs) const
310 {
311 NW_ASSERT(ofs != 0);
312 return reinterpret_cast<const X*>(reinterpret_cast<const u8*>(mpData) + ofs);
313 }
314
315 // 状態を Invalid にします。 参照していたデータの実体の破棄は行ないません。
316 //! @details :private
invalidate()317 void invalidate() { mpData = NULL; }
318 };
319
320
321 //--------------------------------------------------------------------------
322 //! @brief リソースアクセサの基底クラスです。
323 //---------------------------------------------------------------------------
324 template<class T>
325 class ResCommon : public ResCommonBase
326 {
327 public:
328 //! @brief コンストラクタです。
ResCommon(void * p)329 explicit ResCommon(void *p) : ResCommonBase(p) {}
ResCommon(const void * p)330 explicit ResCommon(const void* p) : ResCommonBase(p) {}
331
332 //! @brief バイナリリソースの構造体へのポインタを返します
ptr()333 NW_FORCE_INLINE T* ptr() { return reinterpret_cast<T*>(void_ptr()); }
334
335 //! @brief バイナリリソースの構造体へのポインタを返します
ptr()336 NW_FORCE_INLINE const T* ptr() const { return reinterpret_cast<const T*>(void_ptr()); }
337
338 //! @brief バイナリリソースの構造体へのリファレンスを返します
ref()339 NW_FORCE_INLINE T& ref() { NW_ASSERT(this->IsValid()); return *reinterpret_cast<T*>(void_ptr()); }
340
341 //! @brief バイナリリソースの構造体へのリファレンスを返します
ref()342 NW_FORCE_INLINE const T& ref() const { NW_ASSERT(this->IsValid()); return *reinterpret_cast<const T*>(void_ptr()); }
343 };
344
345 //----------------------------------------
346 //! @name リソース関連
347 //@{
348
349 //---------------------------------------------------------------------------
350 //! @brief リソースの有無を調べて破棄するためのデリーターです。
351 //!
352 //! @tparam 削除するオブジェクトです。
353 //---------------------------------------------------------------------------
354 template<typename TResource>
355 NW_INLINE void
SafeCleanup(TResource res)356 SafeCleanup(
357 TResource res
358 )
359 {
360 if (res.IsValid())
361 {
362 res.Cleanup();
363 }
364 }
365
366 //---------------------------------------------------------------------------
367 //! @brief リソースを破棄するためのデリーターです。
368 //!
369 //! @tparam 削除するオブジェクトです。
370 //---------------------------------------------------------------------------
371 template<typename TObject>
372 struct SafeCleanupper : public std::unary_function<TObject, void>
373 {
374 //! Resourceを破棄します。
operatorSafeCleanupper375 void operator()(TObject res) const
376 {
377 SafeCleanup(res);
378 }
379 };
380
381 //---------------------------------------------------------------------------
382 //! @brief SafeCleanup でコンテナ要素の全てのリソースを破棄するための関数です。
383 //!
384 //! @tparam TArray 削除するリソースの配列型です。
385 //!
386 //! @param[in] array 削除するリソースの配列です。
387 //---------------------------------------------------------------------------
388 template<typename TArray>
389 NW_INLINE void
SafeCleanupAll(TArray array)390 SafeCleanupAll(
391 TArray array
392 )
393 {
394 std::for_each(array.begin(), array.end(), SafeCleanupper<typename TArray::value_type>());
395 }
396
397 //@}
398
399 // 名前クラス
400 //! @details :private
401 struct ResNameData
402 {
403 ResS32 len;
404 char str[4]; // 実際には長さlenの文字列が入っている。末尾は4バイトアラインメントされていて、パディングは0である。
405 };
406
407
408 //--------------------------------------------------------------------------
409 //! @brief 名前リソースを表すクラスです。
410 //---------------------------------------------------------------------------
411 class ResName : public ResCommon<ResNameData>
412 {
413 public:
NW_RES_CTOR(ResName)414 NW_RES_CTOR( ResName )
415
416 //! @brief 文字列の長さを返します
417 s32 GetLength() const { return ref().len; }
418
419 //! @brief 文字列へのポインタを返します
GetName()420 const char* GetName() const { return &ref().str[0]; }
421
422 //! @brief 長さ付き文字列と比較します
Equals(const char * str,size_t len)423 bool Equals(const char* str, size_t len) const
424 { return (GetLength() == len) && (::std::strcmp(GetName(), str) == 0); }
425 };
426
427
428 // ファイル情報クラス
429 //! @details :private
430 struct ResFileData
431 {
432 ResU32 signature;
433 ResU16 byteOrder;
434 ResU16 headerSize;
435 ResU32 revision;
436 ResU32 fileSize;
437 };
438
439 //--------------------------------------------------------------------------
440 //! @brief ファイルリソースを表すクラスです。
441 //---------------------------------------------------------------------------
442 class ResFile : public ResCommon<ResFileData>
443 {
444 private:
445 static const u16 BOM = 0xFEFF;
446 static const u32 SIGNATURE = 'NWFL';
447
448 public:
NW_RES_CTOR(ResFile)449 NW_RES_CTOR( ResFile )
450
451 //! @brief ビッグエンディアンかどうかを取得します。
452 bool IsBigEndian() const
453 {
454 NW_ASSERT( (ref().byteOrder == BOM) || (ref().byteOrder == BOM) );
455 #if defined( NW_SWAP_ENDIAN )
456 return *(u8*)(&ref().byteOrder) == 0xFE;
457 #else
458 return *(u8*)(&ref().byteOrder) == 0xFF;
459 #endif
460 }
461
462 //! @brief リトルエンディアンかどうかを取得します。
IsLittleEndian()463 bool IsLittleEndian() const
464 {
465 NW_ASSERT( (ref().byteOrder == BOM) || (ref().byteOrder == BOM) );
466 #if defined( NW_SWAP_ENDIAN )
467 return *(u8*)(&ref().byteOrder) == 0xFF;
468 #else
469 return *(u8*)(&ref().byteOrder) == 0xFE;
470 #endif
471 }
472
473 //! @brief バイトオーダーがサポート対象であるかをチェックします。
TestByteOrder()474 bool TestByteOrder() const { return ref().byteOrder == BOM; }
475 //! @brief シグニチャが正しいかどうかをチェックします。
TestSignature()476 bool TestSignature() const { return ref().signature == SIGNATURE; }
477
478 //! @brief リビジョンを取得します。
GetRevision()479 u32 GetRevision() const { return ref().revision; }
480
481 //! @brief ファイルサイズを取得します。
GetFileSize()482 u32 GetFileSize() const { return ref().fileSize; }
483
484 //! @brief ファイルヘッダサイズを取得します。
GetHeaderSize()485 u16 GetHeaderSize() const { return ref().headerSize; }
486
487 //! @brief データアドレスを取得します。
GetDataAddress()488 void* GetDataAddress() { return (reinterpret_cast<u8*>(ptr()) + u32(ref().headerSize)); }
489
490 //! @brief データアドレスを const ポインタで取得します。
GetDataAddress()491 const void* GetDataAddress() const { return (reinterpret_cast<const u8*>(ptr()) + u32(ref().headerSize)); }
492 };
493
494 } /* namespace ut */
495 } /* namespace nw */
496
497 #endif /* NW_UT_RESUTIL_H_ */
498