1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     lyt_ArcResourceAccessor.cpp
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 #include "precompiled.h"
19 #include <nw/lyt/lyt_ArcResourceAccessor.h>
20 #include <nw/lyt/lyt_Resources.h>
21 #include <cctype>
22 #include <cwchar>
23 
24 namespace nw
25 {
26 namespace lyt
27 {
28 
29 namespace
30 {
31 
32 /*!--------------------------------------------------------------------------*
33   @brief        文字列を小文字として比較します。
34 
35   @param[in]    string1 比較対象の文字列です。
36   @param[in]    string2 比較対象の文字列です。
37 
38   @return       比較結果を返します。
39  *---------------------------------------------------------------------------*/
40 inline
41 int
wcsicmp(const wchar_t * string1,const wchar_t * string2)42 wcsicmp(
43     const wchar_t *string1,
44     const wchar_t *string2)
45 {
46 #ifdef NW_COMPILER_MSVC
47     return ::_wcsicmp(string1, string2);
48 #else
49     return std::wcscasecmp(string1, string2);
50 #endif
51 }
52 
53 /*!--------------------------------------------------------------------------*
54   @brief        文字列をコピーします。
55 
56                 src 文字列を コピーし、必ず nul の終端文字を追加します。
57                 destCount が src文字列の長さより小さい場合は切り詰めてコピーされますが、
58                 必ず nul 終端文字が挿入されます。
59 
60   @tparam       文字の型です。
61 
62   @param[in]    dest コピー先のバッファのアドレスです。
63   @param[in]    destCount コピー先のバッファサイズです。
64   @param[in]    src コピー元の文字列のアドレスです。
65 
66   @return       コピーした文字数を返します。
67  *---------------------------------------------------------------------------*/
68 size_t
strncpy(wchar_t * dest,std::size_t destCount,const char * src)69 strncpy(
70     wchar_t*        dest,
71     std::size_t     destCount,
72     const char*     src
73 )
74 {
75     NW_ASSERT(destCount > 0);
76 
77     --destCount;    // 終端文字分減らす
78     size_t length = 0;
79     while (length < destCount && *src != '\0')
80     {
81         *dest = *src;
82         ++dest;
83         ++src;
84         ++length;
85     }
86 
87     *dest = L'\0';
88 
89     return length;
90 }
91 
92 
93 /*---------------------------------------------------------------------------*
94   @brief 指定されたリソース名を持つリソースをファイル情報テーブルから
95   探し出します。
96 
97   @param pArcHandle ARCHandleオブジェクトへのポインタ。
98   @param resName リソース名へのポインタ。
99 
100   @return リソースが見つかれば、そのリソースのファイル情報エントリへの
101   インデックスを返します。
102  *---------------------------------------------------------------------------*/
103 s32
FindNameResource(ARCHandle * pArcHandle,const wchar_t * resName)104 FindNameResource(
105     ARCHandle* pArcHandle,
106     const wchar_t* resName
107 )
108 {
109     s32 entryNum = -1;
110 
111     ARCDir          dir;
112     bool bSuccess = ARCOpenDir(pArcHandle, L".", &dir);
113     NW_UNUSED_VARIABLE(bSuccess);
114     NW_ASSERT(bSuccess);
115 
116     ARCDirEntry     dirEntry;
117 
118     while (ARCReadDir(&dir, &dirEntry))
119     {
120         if (dirEntry.isDir)
121         {
122             bSuccess = ARCChangeDir(pArcHandle, dirEntry.name);
123             NW_ASSERT(bSuccess);
124             entryNum = FindNameResource(pArcHandle, resName);
125             bSuccess = ARCChangeDir(pArcHandle, L"..");
126             NW_ASSERT(bSuccess);
127             if (entryNum != -1)
128             {
129                 break;
130             }
131         }
132         else
133         {
134             if (wcsicmp(resName, dirEntry.name) == 0)
135             {
136                 entryNum = s32(dirEntry.entryNum);
137                 break;
138             }
139         }
140     }
141 
142     bSuccess = ARCCloseDir(&dir);
143     NW_ASSERT(bSuccess);
144 
145     return entryNum;
146 }
147 
148 void*
GetResourceSub(ARCHandle * pArcHandle,const wchar_t * resRootDir,nw::lyt::ResType resType,const wchar_t * name,u32 * pSize)149 GetResourceSub(
150     ARCHandle* pArcHandle,
151     const wchar_t* resRootDir,
152     nw::lyt::ResType resType,
153     const wchar_t* name,
154     u32* pSize
155 )
156 {
157     s32 entryNum = -1;
158 
159     if (-1 != ARCConvertPathToEntrynum(pArcHandle, resRootDir))
160     {
161         if (ARCChangeDir(pArcHandle, resRootDir)) // リソースのルートディレクトリに移動
162         {
163             if (resType == 0)   // リソースタイプが省略されている場合
164             {
165                 entryNum = FindNameResource(pArcHandle, name);
166             }
167             else                // リソースタイプが指定されている場合
168             {
169                 wchar_t resTypeStr[5];
170                 resTypeStr[0] = u8(resType >> 24);
171                 resTypeStr[1] = u8(resType >> 16);
172                 resTypeStr[2] = u8(resType >>  8);
173                 resTypeStr[3] = u8(resType >>  0);
174                 resTypeStr[4] = 0;
175 
176                 if (-1 != ARCConvertPathToEntrynum(pArcHandle, resTypeStr))
177                 {
178                     if (ARCChangeDir(pArcHandle, resTypeStr))
179                     {
180                         entryNum = ARCConvertPathToEntrynum(pArcHandle, name);
181 
182                         bool bSuccess = ARCChangeDir(pArcHandle, L"..");    // 元に戻す
183                         NW_ASSERT(bSuccess);
184                     }
185                 }
186             }
187 
188             bool bSuccess = ARCChangeDir(pArcHandle, L"..");    // 元に戻す
189             NW_ASSERT(bSuccess);
190         }
191     }
192 
193     if (entryNum != -1)
194     {
195         ARCFileInfo arcFileInfo;
196         bool bSuccess = ARCFastOpen(pArcHandle, entryNum, &arcFileInfo);
197         NW_ASSERT(bSuccess);
198         void* resPtr = ARCGetStartAddrInMem(&arcFileInfo);
199         if (pSize)
200         {
201             *pSize = ARCGetLength(&arcFileInfo);
202         }
203         ARCClose(&arcFileInfo);
204 
205         return resPtr;
206     }
207 
208     return NULL;
209 }
210 
211 }   // namespace
212 
ArcResourceAccessor()213 ArcResourceAccessor::ArcResourceAccessor()
214 :   m_ArcBuf(0)
215 {
216 }
217 
218 bool
Attach(void * archiveStart,const char * resourceRootDirectory)219 ArcResourceAccessor::Attach(
220     void*       archiveStart,
221     const char* resourceRootDirectory
222 )
223 {
224     NW_ASSERT(! IsAttached());
225     NW_NULL_ASSERT(archiveStart);
226     NW_NULL_ASSERT(resourceRootDirectory);
227 
228     bool bSuccess = ARCInitHandle(archiveStart, &m_ArcHandle);
229     if (! bSuccess)
230     {
231         return false;
232     }
233 
234     m_ArcBuf = archiveStart;
235     // ルートディレクトリ文字列のコピー
236     const int dstBufCount = sizeof(m_ResRootDir) / sizeof(m_ResRootDir[0]);
237     strncpy(m_ResRootDir, dstBufCount, resourceRootDirectory);
238 
239     return true;
240 }
241 
242 void*
Detach()243 ArcResourceAccessor::Detach()
244 {
245     NW_ASSERT(IsAttached());
246 
247     void* ret = m_ArcBuf;
248     m_ArcBuf = 0;
249     return ret;
250 }
251 
252 void*
GetResource(ResType resType,const char * name,u32 * pSize)253 ArcResourceAccessor::GetResource(
254     ResType     resType,
255     const char* name,
256     u32*        pSize
257 )
258 {
259     const int dstBufCount = sizeof(m_ResNameWork) / sizeof(m_ResNameWork[0]);
260     strncpy(m_ResNameWork, dstBufCount, name);
261     return GetResourceSub(&m_ArcHandle, m_ResRootDir, resType, m_ResNameWork, pSize);
262 }
263 
264 bool
Set(void * archiveStart,const char * resourceRootDirectory)265 ArcResourceLink::Set(
266     void*       archiveStart,
267     const char* resourceRootDirectory
268 )
269 {
270     NW_NULL_ASSERT(archiveStart);
271     NW_NULL_ASSERT(resourceRootDirectory);
272 
273     bool bSuccess = ARCInitHandle(archiveStart, &m_ArcHandle);
274     if (! bSuccess)
275     {
276         return false;
277     }
278 
279     // ルートディレクトリ文字列のコピー
280     const int dstBufCount = sizeof(m_ResRootDir) / sizeof(m_ResRootDir[0]);
281     strncpy(m_ResRootDir, dstBufCount, resourceRootDirectory);
282 
283     return true;
284 }
285 
286 const void*
GetArchiveDataStart() const287 ArcResourceLink::GetArchiveDataStart() const
288 {
289     return m_ArcHandle.archiveStartAddr;
290 }
291 
292 font::Font*
GetFont(const char * name)293 ArcResourceAccessor::GetFont(const char *name)
294 {
295     font::Font* pFont = m_FontList.FindFontByName(name);
296 
297     if (pFont == NULL)
298     {
299         pFont = this->LoadFont(name);
300 
301         if (pFont != NULL)
302         {
303             (void)m_FontList.RegistFont(name, pFont, true);
304         }
305     }
306 
307     return pFont;
308 }
309 
310 FontKey
RegistFont(const char * name,font::Font * pFont)311 ArcResourceAccessor::RegistFont(const char* name, font::Font* pFont)
312 {
313     return m_FontList.RegistFont(name, pFont, false);
314 }
315 
316 void
UnregistFont(FontKey key)317 ArcResourceAccessor::UnregistFont(FontKey key)
318 {
319     m_FontList.UnregistFont(key);
320 }
321 
322 const TextureInfo
GetTexture(const char * name)323 ArcResourceAccessor::GetTexture(const char *name)
324 {
325     TextureInfo texInfo = m_TextureList.FindTextureByName(name);
326     if (texInfo.IsValid())
327     {
328         return texInfo;
329     }
330     else
331     {
332         texInfo = this->LoadTexture(name);
333 
334         if (texInfo.IsValid())
335         {
336             (void) m_TextureList.RegistTexture(name, texInfo);
337         }
338 
339         return texInfo;
340     }
341 }
342 
343 TextureKey
RegistTexture(const char * name,const TextureInfo & textureInfo)344 ArcResourceAccessor::RegistTexture(const char* name, const TextureInfo& textureInfo)
345 {
346     return m_TextureList.RegistTexture(name, textureInfo);
347 }
348 
349 void
UnregistTexture(TextureKey key)350 ArcResourceAccessor::UnregistTexture(TextureKey key)
351 {
352     m_TextureList.UnregistTexture(key);
353 }
354 
MultiArcResourceAccessor()355 MultiArcResourceAccessor::MultiArcResourceAccessor()
356 {
357 }
358 
~MultiArcResourceAccessor()359 MultiArcResourceAccessor::~MultiArcResourceAccessor()
360 {
361     DetachAll();
362 }
363 
364 void
Attach(ArcResourceLink * pLink)365 MultiArcResourceAccessor::Attach(ArcResourceLink* pLink)
366 {
367     NW_NULL_ASSERT(pLink);
368 
369     m_ArcList.PushBack(pLink);
370 }
371 
372 ArcResourceLink*
Detach(const void * archiveStart)373 MultiArcResourceAccessor::Detach(const void* archiveStart)
374 {
375     NW_NULL_ASSERT(archiveStart);
376 
377     for (internal::ArcResourceList::Iterator it = m_ArcList.GetBeginIter(); it != m_ArcList.GetEndIter(); ++it)
378     {
379         if (archiveStart == it->GetArchiveDataStart())
380         {
381             ArcResourceLink* ret = &(*it);
382             m_ArcList.Erase(it);
383             return ret;
384         }
385     }
386 
387     return 0;
388 }
389 
390 void
Detach(ArcResourceLink * pLink)391 MultiArcResourceAccessor::Detach(ArcResourceLink* pLink)
392 {
393     NW_NULL_ASSERT(pLink);
394 
395     m_ArcList.Erase(pLink);
396 }
397 
398 void
DetachAll()399 MultiArcResourceAccessor::DetachAll()
400 {
401     m_ArcList.Clear();
402 }
403 
404 void*
GetResource(ResType resType,const char * name,u32 * pSize)405 MultiArcResourceAccessor::GetResource(
406     ResType     resType,
407     const char* name,
408     u32*        pSize
409 )
410 {
411     const int dstBufCount = sizeof(m_ResNameWork) / sizeof(m_ResNameWork[0]);
412     strncpy(m_ResNameWork, dstBufCount, name);
413 
414     for (internal::ArcResourceList::Iterator it = m_ArcList.GetBeginIter(); it != m_ArcList.GetEndIter(); ++it)
415     {
416         ARCHandle* pArcHandle = it->GetArcHandle();
417         if (void* resPtr = GetResourceSub(pArcHandle, it->GetResRootDir(), resType, m_ResNameWork, pSize))
418         {
419             return resPtr;
420         }
421     }
422 
423     return NULL;
424 }
425 
426 font::Font*
GetFont(const char * name)427 MultiArcResourceAccessor::GetFont(const char *name)
428 {
429     font::Font* pFont = m_FontList.FindFontByName(name);
430 
431     if (pFont == NULL)
432     {
433         pFont = this->LoadFont(name);
434 
435         if (pFont != NULL)
436         {
437             (void)m_FontList.RegistFont(name, pFont, true);
438         }
439     }
440 
441     return pFont;
442 }
443 
444 FontKey
RegistFont(const char * name,font::Font * pFont)445 MultiArcResourceAccessor::RegistFont(const char* name, font::Font* pFont)
446 {
447     return m_FontList.RegistFont(name, pFont, false);
448 }
449 
450 void
UnregistFont(FontKey key)451 MultiArcResourceAccessor::UnregistFont(FontKey key)
452 {
453     m_FontList.UnregistFont(key);
454 }
455 
456 const TextureInfo
GetTexture(const char * name)457 MultiArcResourceAccessor::GetTexture(const char *name)
458 {
459     TextureInfo texInfo = m_TextureList.FindTextureByName(name);
460     if (texInfo.IsValid())
461     {
462         return texInfo;
463     }
464     else
465     {
466         texInfo = this->LoadTexture(name);
467 
468         if (texInfo.IsValid())
469         {
470             (void) m_TextureList.RegistTexture(name, texInfo);
471         }
472 
473         return texInfo;
474     }
475 }
476 
477 TextureKey
RegistTexture(const char * name,const TextureInfo & textureInfo)478 MultiArcResourceAccessor::RegistTexture(const char* name, const TextureInfo& textureInfo)
479 {
480     return m_TextureList.RegistTexture(name, textureInfo);
481 }
482 
483 void
UnregistTexture(TextureKey key)484 MultiArcResourceAccessor::UnregistTexture(TextureKey key)
485 {
486     m_TextureList.UnregistTexture(key);
487 }
488 
489 }   // namespace lyt
490 }   // namespace nw
491