1 /*---------------------------------------------------------------------------*
2 Project: Horizon
3 File: os_DeliverArg.cpp
4
5 Copyright (C)2009-2012 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: 46347 $
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 // Lower 4 bits
44 r1 = crc16_table[total & 0xf];
45 total = (total >> 4) & 0x0fff;
46 total = total ^ r1 ^ crc16_table[*data & 0xf];
47
48 // Upper 4 bits
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 // Buffer initialization
95 ::std::memset(m_pInfo, 0, NN_OS_DELIVER_ARG_INFO_SIZE);
96
97 // Initialize parameters.
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 // Pointer initialization
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 // Initialize parameters.
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 confirmation
121 if ((m_State & BUFFER_STATE_WRITABLE) == 0)
122 {
123 return ResultDeliverArgNotReady();
124 }
125
126 // Buffer length confirmation
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 // Copy of argument string
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 confirmation
148 if ((m_State & BUFFER_STATE_WRITABLE) == 0)
149 {
150 return ResultDeliverArgNotReady();
151 }
152
153 while (true)
154 {
155 // Separator skip
156 while (*pString == cs)
157 {
158 pString++;
159 }
160
161 // End if NULL
162 if (*pString == '\0')
163 {
164 break;
165 }
166
167 // Search separator
168 endp = pString;
169 while (*endp != cs && *endp != '\0')
170 {
171 endp++;
172 }
173 length = endp - pString;
174
175 // Buffer size confirmation
176 if (length > m_pInfo->argBufferSize - (m_pBuf - m_pInfo->buf) - 2)
177 {
178 return ResultDeliverArgOverSize();
179 }
180
181 // String copy
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 confirmation
196 if ((m_State & BUFFER_STATE_WRITABLE) == 0)
197 {
198 return ResultDeliverArgNotReady();
199 }
200
201 // Buffer length confirmation
202 if (nSize > NN_OS_DELIVER_ARG_BUFFER_SIZE - m_pInfo->argBufferSize - m_pInfo->binarySize)
203 {
204 return ResultDeliverArgOverSize();
205 }
206
207 // Binary data copy
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 // Separator skip
224 while (*pString == cs && p < pEnd)
225 {
226 pString++;
227 }
228
229 // Store argument string
230 while (*pString && p < pEnd)
231 {
232 // Confirm whether quote
233 if (*pString == '\"')
234 {
235 isQuoted = (isQuoted == false);
236 pString++;
237 continue;
238 }
239
240 // break if separator is found
241 else if (*pString == cs && isQuoted == false)
242 {
243 break;
244 }
245
246 *p++ = *pString++;
247 }
248
249 // End if end of buffer
250 if (p >= pEnd)
251 {
252 *(pEnd - 2) = '\0';
253 *(pEnd - 1) = '\0';
254 break;
255 }
256
257 // End if end of string
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 // Insert '\0' and continue if separator
270 if (*pString == cs)
271 {
272 *p++ = '\0';
273 }
274 }
275
276 // Quit
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 confirmation
296 if ((m_State & BUFFER_STATE_ACCESSIBLE) == 0)
297 {
298 return ResultDeliverArgNotReady();
299 }
300
301 // makerCode and titleId settings
302 m_pInfo->makerCode = m_MakerCode;
303 m_pInfo->titleId = m_TitleId;
304
305 // flag settings
306 m_pInfo->flag = NN_OS_DELIVER_ARG_FLAG_ENCODE | NN_OS_DELIVER_ARG_FLAG_VALID;
307
308 // CRC calculation
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 validity confirmation
318 if (IsValid() == false)
319 {
320 return ResultDeliverArgNotReady();
321 }
322
323 // Buffer confirmation
324 if (m_pInfo == NULL)
325 {
326 return ResultDeliverArgNotReady();
327 }
328
329 // Checks 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 // Error code flag release
341 m_pInfo->flag &= ~NN_OS_DELIVER_ARG_FLAG_ENCODE;
342
343 // BufferState update
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 confirmation
380 if ((m_State & BUFFER_STATE_ACCESSIBLE) == 0)
381 {
382 return ResultDeliverArgNotReady();
383 }
384
385 // Buffer length confirmation
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 // Binary data copy
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