1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     os_DeliverArg.cpp
4 
5   Copyright (C)2010 Nintendo Co., Ltd.  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   $Rev: 23962 $
14  *---------------------------------------------------------------------------*/
15 
16 #include <string>
17 #include <nn/os.h>
18 #include <nn/util.h>
19 #include <nn/assert.h>
20 
21 #include <nn/os/os_DeliverArg.h>
22 
23 //---------------------------------------------------------------------------
24 
25 namespace
26 {
27     const u16 crc16_table[16] =
28     {
29         0x0000, 0xCC01, 0xD801, 0x1400,
30         0xF001, 0x3C00, 0x2800, 0xE401,
31         0xA001, 0x6C00, 0x7800, 0xB401,
32         0x5000, 0x9C01, 0x8801, 0x4400
33     };
34 
CalcCRC16withIv(u16 iv,const void * buf,u32 size)35     u16 CalcCRC16withIv(u16 iv, const void* buf, u32 size)
36     {
37         u16 r1;
38         u16 total = iv;
39         u8* data = (u8*)buf;
40 
41         while (size-- > 0)
42         {
43             // 下位 4bit
44             r1 = crc16_table[total & 0xf];
45             total = (total >> 4) & 0x0fff;
46             total = total ^ r1 ^ crc16_table[*data & 0xf];
47 
48             // 上位 4bit
49             r1 = crc16_table[total & 0xf];
50             total = (total >> 4) & 0x0fff;
51             total = total ^ r1 ^ crc16_table[(*data >> 4) & 0xf];
52 
53             data++;
54         }
55         return total;
56     }
57 
GetArgcCore(const char * p)58     s32 GetArgcCore(const char* p)
59     {
60         s32 n = 0;
61         for (; *p; p++, n++)
62         {
63             while (*p)
64             {
65                 p++;
66             }
67         }
68         return n;
69     }
70 
GetArgvCore(const char * p,int n)71     const char* GetArgvCore(const char* p, int n)
72     {
73         NN_TASSERT_(n >= 0);
74         for (; *p && n > 0; p++, n--)
75         {
76             while (*p)
77             {
78                 p++;
79             }
80         }
81         return (*p) ? p : NULL;
82     }
83 }
84 
85 namespace nn { namespace os {
86 
InitializeForEnc(DeliverArgInfo * pInfo,s32 nBinSize)87 void DeliverArg::InitializeForEnc(DeliverArgInfo* pInfo, s32 nBinSize)
88 {
89     NN_TASSERT_(2 <= (NN_OS_DELIVER_ARG_BUFFER_SIZE-nBinSize) && nBinSize >= 0);
90     NN_TASSERT_(pInfo != NULL);
91 
92     m_pInfo = pInfo;
93 
94     // バッファの初期化
95     ::std::memset(m_pInfo, 0, NN_OS_DELIVER_ARG_INFO_SIZE);
96 
97     // パラメータの初期化
98     m_State = BUFFER_STATE_ACCESSIBLE | BUFFER_STATE_WRITABLE;
99     m_pInfo->argBufferSize = (u16)(NN_OS_DELIVER_ARG_BUFFER_SIZE - nBinSize);
100     m_pInfo->binarySize = 0;
101 
102     // ポインタの初期化
103     m_pBuf = m_pInfo->buf;
104     *(m_pBuf + 0) = '\0';
105     *(m_pBuf + 1) = '\0';
106 }
107 
InitializeForDec(DeliverArgInfo * pInfo)108 void DeliverArg::InitializeForDec(DeliverArgInfo* pInfo)
109 {
110     NN_TASSERT_(pInfo != NULL);
111 
112     m_pInfo = pInfo;
113 
114     // パラメータの初期化
115     m_State = BUFFER_STATE_ACCESSIBLE | BUFFER_STATE_WRITABLE;
116 }
117 
SetString(const char * pString)118 nn::Result DeliverArg::SetString(const char* pString)
119 {
120     // BufferState の確認
121     if ((m_State & BUFFER_STATE_WRITABLE) == 0)
122     {
123         return ResultDeliverArgNotReady();
124     }
125 
126     // バッファ長の確認
127     s32 length = ::std::strlen(pString);
128     if (length > m_pInfo->argBufferSize - (m_pBuf - m_pInfo->buf) - 2)
129     {
130         return ResultDeliverArgOverSize();
131     }
132 
133     // 引数文字列のコピー
134     ::std::strcpy((char*)m_pBuf, pString);
135     m_pBuf += length;
136     *m_pBuf++ = '\0';
137     *m_pBuf   = '\0';
138 
139     return ResultSuccess();
140 }
141 
SetString(const char * pString,char cs)142 nn::Result DeliverArg::SetString(const char* pString, char cs)
143 {
144     int length;
145     const char* endp;
146 
147     // BufferState の確認
148     if ((m_State & BUFFER_STATE_WRITABLE) == 0)
149     {
150         return ResultDeliverArgNotReady();
151     }
152 
153     while (true)
154     {
155         // セパレータのスキップ
156         while (*pString == cs)
157         {
158             pString++;
159         }
160 
161         // NULL なら終了
162         if (*pString == '\0')
163         {
164             break;
165         }
166 
167         // セパレータの検索
168         endp = pString;
169         while (*endp != cs && *endp != '\0')
170         {
171             endp++;
172         }
173         length = endp - pString;
174 
175         // バッファサイズの確認
176         if (length > m_pInfo->argBufferSize - (m_pBuf - m_pInfo->buf) - 2)
177         {
178             return ResultDeliverArgOverSize();
179         }
180 
181         // 文字列のコピー
182         while(pString != endp)
183         {
184             *m_pBuf++ = *(u8*)pString++;
185         }
186         *m_pBuf++ = '\0';
187         *m_pBuf   = '\0';
188     }
189 
190     return ResultSuccess();
191 }
192 
SetBinary(const void * pBinary,s32 nSize)193 nn::Result DeliverArg::SetBinary(const void* pBinary, s32 nSize)
194 {
195     // BufferState の確認
196     if ((m_State & BUFFER_STATE_WRITABLE) == 0)
197     {
198         return ResultDeliverArgNotReady();
199     }
200 
201     // バッファ長の確認
202     if (nSize > NN_OS_DELIVER_ARG_BUFFER_SIZE - m_pInfo->argBufferSize - m_pInfo->binarySize)
203     {
204         return ResultDeliverArgOverSize();
205     }
206 
207     // バイナリデータのコピー
208     u8* pDest = &m_pInfo->buf[m_pInfo->argBufferSize + m_pInfo->binarySize];
209     ::std::memcpy(pDest, pBinary, nSize);
210     m_pInfo->binarySize += (u16)nSize;
211 
212     return ResultSuccess();
213 }
214 
ConvertToArguments(const char * pString,char cs,char * pBuffer,s32 nBufferSize)215 void DeliverArg::ConvertToArguments(const char *pString, char cs, char *pBuffer, s32 nBufferSize)
216 {
217     char   *p = pBuffer;
218     char   *pEnd = pBuffer + nBufferSize;
219     bool    isQuoted = false;
220 
221     while (true)
222     {
223         // セパレータのスキップ
224         while (*pString == cs && p < pEnd)
225         {
226             pString++;
227         }
228 
229         // 引数文字列を格納
230         while (*pString && p < pEnd)
231         {
232             // quote かどうかの確認
233             if (*pString == '\"')
234             {
235                 isQuoted = (isQuoted == false);
236                 pString++;
237                 continue;
238             }
239 
240             // セパレータが見つかれば break
241             else if (*pString == cs && isQuoted == false)
242             {
243                 break;
244             }
245 
246             *p++ = *pString++;
247         }
248 
249         // バッファ終端なら終了
250         if (p >= pEnd)
251         {
252             *(pEnd - 2) = '\0';
253             *(pEnd - 1) = '\0';
254             break;
255         }
256 
257         // 文字列の終端なら終了
258         if (*pString == '\0')
259         {
260             while ((p + 1) >= pEnd)
261             {
262                 p--;
263             }
264             *p++ = '\0';
265             *p = '\0';
266             break;
267         }
268 
269         // セパレータなら '\0' を挿入して続行
270         if (*pString == cs)
271         {
272             *p++ = '\0';
273         }
274     }
275 
276     // 終了
277     if (p < pEnd)
278     {
279         *p++ = '\0';
280     }
281 }
282 
SetTitleId(bit64 titleId)283 void DeliverArg::SetTitleId(bit64 titleId)
284 {
285     m_TitleId = titleId;
286 }
287 
SetMakerCode(bit16 makerCode)288 void DeliverArg::SetMakerCode(bit16 makerCode)
289 {
290     m_MakerCode = makerCode;
291 }
292 
Encode(void)293 nn::Result DeliverArg::Encode(void)
294 {
295     // BufferState の確認
296     if ((m_State & BUFFER_STATE_ACCESSIBLE) == 0)
297     {
298         return ResultDeliverArgNotReady();
299     }
300 
301     // makerCode, titleId の設定
302     m_pInfo->makerCode = m_MakerCode;
303     m_pInfo->titleId   = m_TitleId;
304 
305     // flag の設定
306     m_pInfo->flag = NN_OS_DELIVER_ARG_FLAG_ENCODE | NN_OS_DELIVER_ARG_FLAG_VALID;
307 
308     // CRC の計算
309     m_pInfo->crc = 0;
310     m_pInfo->crc = CalcCRC16withIv(0xffff, reinterpret_cast<const void*>(m_pInfo), sizeof(DeliverArgInfo));
311 
312     return ResultSuccess();
313 }
314 
Decode(void)315 nn::Result DeliverArg::Decode(void)
316 {
317     // DeliverArg の有効性の確認
318     if (IsValid() == false)
319     {
320         return ResultDeliverArgNotReady();
321     }
322 
323     // バッファの確認
324     if (m_pInfo == NULL)
325     {
326         return ResultDeliverArgNotReady();
327     }
328 
329     // CRC チェック
330     u16 crc = m_pInfo->crc;
331     m_pInfo->crc = 0;
332     m_pInfo->crc = CalcCRC16withIv(0xffff, reinterpret_cast<const void*>(m_pInfo), sizeof(DeliverArgInfo));
333 
334     if (crc != m_pInfo->crc)
335     {
336         SetStateInvalid();
337         return ResultInvalidDeliverArg();
338     }
339 
340     // エンコードフラグの解除
341     m_pInfo->flag &= ~NN_OS_DELIVER_ARG_FLAG_ENCODE;
342 
343     // BufferState の更新
344     m_State = BUFFER_STATE_ACCESSIBLE;
345 
346     return ResultSuccess();
347 }
348 
GetState(void)349 u32 DeliverArg::GetState(void)
350 {
351     return m_State;
352 }
353 
SetState(u32 state)354 void DeliverArg::SetState(u32 state)
355 {
356     m_State = state;
357 }
358 
SetStateInvalid(void)359 void DeliverArg::SetStateInvalid(void)
360 {
361     m_State = BUFFER_STATE_INVALID;
362 }
363 
GetBinarySize(void)364 s32 DeliverArg::GetBinarySize(void)
365 {
366     if ((m_State & BUFFER_STATE_ACCESSIBLE) == 0)
367     {
368         return -1;
369     }
370 
371     return m_pInfo->binarySize;
372 }
373 
GetBinary(void * pBinary,int * pSize,int nMaxSize)374 nn::Result DeliverArg::GetBinary(void* pBinary, int* pSize, int nMaxSize)
375 {
376     nn::Result result;
377     s32 nCopySize;
378 
379     // BufferState の確認
380     if ((m_State & BUFFER_STATE_ACCESSIBLE) == 0)
381     {
382         return ResultDeliverArgNotReady();
383     }
384 
385     // バッファ長の確認
386     if (nMaxSize < m_pInfo->binarySize)
387     {
388         result = ResultDeliverArgOverSize();
389         nCopySize = nMaxSize;
390     }
391     else
392     {
393         result = ResultSuccess();
394         nCopySize = m_pInfo->binarySize;
395     }
396 
397     // バイナリデータのコピー
398     ::std::memcpy(pBinary, &m_pInfo->buf[m_pInfo->argBufferSize], nCopySize);
399     if (pSize)
400     {
401         *pSize = nCopySize;
402     }
403 
404     return result;
405 }
406 
GetTitleId(void)407 bit64 DeliverArg::GetTitleId(void)
408 {
409     return (m_State & BUFFER_STATE_ACCESSIBLE) ? m_pInfo->titleId : 0;
410 }
411 
GetGameCode(void)412 bit32 DeliverArg::GetGameCode(void)
413 {
414     return (m_State & BUFFER_STATE_ACCESSIBLE) ? *(reinterpret_cast<u32*>(&m_pInfo->titleId)) : 0;
415 }
416 
GetMakerCode(void)417 bit16 DeliverArg::GetMakerCode(void)
418 {
419     return (m_State & BUFFER_STATE_ACCESSIBLE) ? m_pInfo->makerCode : 0;
420 }
421 
IsValid(void)422 bool DeliverArg::IsValid(void)
423 {
424     return (m_pInfo->flag & NN_OS_DELIVER_ARG_FLAG_VALID) ? true : false;
425 }
426 
IsEncoded(void)427 bool DeliverArg::IsEncoded(void)
428 {
429     return (m_pInfo->flag & (NN_OS_DELIVER_ARG_FLAG_ENCODE | NN_OS_DELIVER_ARG_FLAG_VALID)) ? true : false;
430 }
431 
SetSysParam(bit16 param)432 nn::Result DeliverArg::SetSysParam(bit16 param)
433 {
434     if (m_pInfo && (m_State & BUFFER_STATE_WRITABLE) == 0)
435     {
436         return ResultDeliverArgNotReady();
437     }
438     m_pInfo->sysParam = param;
439     return ResultSuccess();
440 }
441 
GetSysParam(void)442 u16 DeliverArg::GetSysParam(void)
443 {
444     if (m_pInfo && (m_State & BUFFER_STATE_ACCESSIBLE) == 0)
445     {
446         return 0;
447     }
448     return m_pInfo->sysParam;
449 }
450 
GetArgc(void)451 s32 DeliverArg::GetArgc(void)
452 {
453     if (m_pInfo && m_State == BUFFER_STATE_ACCESSIBLE)
454     {
455         return GetArgcCore(reinterpret_cast<const char*>(m_pInfo->buf)) + 1;
456     }
457     return 0;
458 }
459 
GetArgv(int n)460 const char* DeliverArg::GetArgv(int n)
461 {
462     static const char* procName = "main";
463     NN_TASSERT_(n >= 0);
464 
465     if (m_pInfo && m_State == BUFFER_STATE_ACCESSIBLE)
466     {
467         return (n == 0) ? procName: GetArgvCore(reinterpret_cast<const char*>(m_pInfo->buf), n - 1);
468     }
469     return NULL;
470 }
471 
472 }} // namespace nn::os
473