1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     sample_nsalist.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:$
14  *---------------------------------------------------------------------------*/
15 
16 #include <string.h>
17 #include <sstream>
18 
19 #include <nn/fs.h>
20 #include <nn/boss.h>
21 #include <nn/boss/boss_NsaList.h>
22 #include <nn/fs/fs_Parameters.h>
23 #include <nn/ac.h>
24 #include <nn/applet.h>
25 #include <nn/ndm.h>
26 
27 #define RESULT_SUCCESS_ASSERT NN_UTIL_PANIC_IF_FAILED
28 
29 #define NN_BOSS_RESULT_HANDLING(result, target)            \
30     do {                                                   \
31         if(result.IsFailure())                             \
32         {                                                  \
33             NN_LOG("result is err(%08x).(%s)\n", result.GetPrintableBits(), target);        \
34         }                                                  \
35     } while (0)
36 
37 namespace {
InitializeNetwork(void)38     nn::Result InitializeNetwork(void)
39     {
40         nn::Result result;
41         nn::ac::Config config;
42 
43         nn::fs::Initialize();
44         result = nn::ac::Initialize();
45         NN_UTIL_PANIC_IF_FAILED(result);
46 
47         // Create parameters for connection request
48         result = nn::ac::CreateDefaultConfig( &config );
49         if (result.IsFailure())
50         {
51             NN_UTIL_PANIC_IF_FAILED(nn::ac::Finalize());
52             return result;
53         }
54 
55         // Issue connection request
56         result = nn::ac::Connect( config );
57         if (result.IsFailure())
58         {
59             NN_UTIL_PANIC_IF_FAILED(nn::ac::Finalize());
60             return result;
61         }
62 
63         return nn::ResultSuccess();
64     }
65 
FinalizeNetwork(void)66     nn::Result FinalizeNetwork(void)
67     {
68         nn::Result result;
69 
70         // Create parameters for connection request
71         result = nn::ac::Close();
72         NN_UTIL_RETURN_IF_FAILED(result);
73 
74         result = nn::ac::Finalize();
75         NN_UTIL_PANIC_IF_FAILED(result);
76 
77         return nn::ResultSuccess();
78     }
79 
DumpNsdBody(u8 * pBodyBuf,size_t payloadLength)80     void DumpNsdBody(u8* pBodyBuf, size_t payloadLength)
81     {
82     #ifndef NN_SWITCH_DISABLE_DEBUG_PRINT
83         NN_LOG("---NSD Body Dump(Payload-Length=%d)---\n", payloadLength);
84         int hexCheckCount = 0;
85         for(int i = 0; i < payloadLength; ++i)
86         {
87             NN_LOG("%02x ", pBodyBuf[i]);
88             ++hexCheckCount;
89             if(hexCheckCount == 16)
90             {
91                 NN_LOG("\n");
92                 hexCheckCount = 0;
93             }
94         }
95     #else
96         NN_UNUSED_VAR(pBodyBuf);
97         NN_UNUSED_VAR(payloadLength);
98     #endif
99     }
100 }
101 
102 // Expanded save data ID
103 // Expanded save data is required to use NADL tasks. The expanded save data ID specifies which expanded save data to use and is unique across all applications.
104 // The expanded save data region is also used to store downloaded NSA lists.
105 const bit32 APP_EXT_STORAGE_ID         = 0x00000011;
106 
107 
108 // Task ID
109 // Both a BOSS code and a task ID must be specified when you get an NSA list.
110 const char8 DOWNLOAD_TASK_ID[] = "flist";                            /* Please see man pages for details */
111 const char  BOSS_CODE[]        = "9x4m4dJwyBBlUc3g";                 /* BOSS code */
112 
113 /* ------------------------------------------------------------------------
114    This sample code gets a task's NSA list from the server, and then uses an NADL task to download the files in that list.
115    For more details, see sample_nadl_simple, which uses the same process of downloading files through an NADL task.
116    ------------------------------------------------------------------------ */
sampleNSAListExecute()117 void sampleNSAListExecute()
118 {
119     // Create an instance of nn::boss::NsaList
120     nn::boss::NsaList nsaList("test:/filelist.txt");
121 
122     // Download the NSA list
123     {
124         // Specify a BOSS code and a task ID to download the NSA list.
125         nn::Result result = nsaList.Download(BOSS_CODE, DOWNLOAD_TASK_ID);
126         if (result.IsFailure())
127         {
128             NN_LOG_ERROR("nn::boss::NsaList::Download failed(0x%08x)\n", result.GetPrintableBits());
129             NN_UTIL_PANIC_IF_FAILED(result);
130         }
131     }
132 
133     // Check for errors related to downloading an NSA list
134     {
135         if (nsaList.GetResult() != nn::boss::TASK_SUCCESS)
136         {
137             NN_LOG_ERROR("nn::boss::NsaList::Download failed\n");
138             NN_LOG_ERROR("nn::boss::NsaList::GetResult(%d)\n", nsaList.GetResult());
139         }
140     }
141 
142     // Get the NSA list's Digest value
143     /*
144     {
145         const u32 DIGEST_BUF_SIZE = 40+1;
146         u8 digestBuf[DIGEST_BUF_SIZE] = {0};
147         nn::Result result = nsaList.GetDigest(digestBuf, DIGEST_BUF_SIZE);
148         if(result.IsFailure())
149         {
150             // Error
151             NN_LOG_ERROR("nn::boss::NsaList::GetDigest failed(0x%08x)\n", result.GetPrintableBits());
152             NN_UTIL_PANIC_IF_FAILED(result);
153         }
154         NN_LOG("NSA List Digest : %s\n", (char *)digestBuf);
155     }
156     */
157 
158     // Determine whether the NSA list is valid
159     const u32 WORK_BUF_SIZE = 256;
160     u8 workBuf[WORK_BUF_SIZE];
161     {
162         memset(workBuf, 0, WORK_BUF_SIZE);
163         if (!nsaList.CheckValidity((void *)workBuf, WORK_BUF_SIZE))
164         {
165             // Error
166             NN_LOG_ERROR("nn::boss::NsaList::CheckValidity failed\n");
167         }
168     }
169 
170     // Parse the downloaded NSA list
171     u32 numNsaList = 0;
172     const u32 NSA_LIST_LENGTH = 10;
173     nn::boss::NsaList::NsaInformation nsaListInfo[NSA_LIST_LENGTH];
174     {
175         memset(workBuf, 0, WORK_BUF_SIZE);
176         s32 parseResult = nsaList.Parse(&numNsaList, nsaListInfo, NSA_LIST_LENGTH, (void *)workBuf, WORK_BUF_SIZE);
177         if (parseResult < 0)
178         {
179             // Error
180             NN_LOG_ERROR("nn::boss::NsaList::Parse failed(%d)\n", parseResult);
181         }
182     }
183 
184     // Display the content of the downloaded NSA list
185     for (int i = 0; i < numNsaList; i++)
186     {
187         NN_LOG("----- NSA List %d -----\n", i+1);
188         NN_LOG(" FileName        : %s\n", nsaListInfo[i].fileName);
189         NN_LOG(" FileSize        : %d\n", nsaListInfo[i].fileSize);
190         NN_LOG(" UpdateEpochTime : %d\n", nsaListInfo[i].updateEpochTime);
191         NN_LOG(" Attribute1      : %s\n", nsaListInfo[i].attribute1);
192         NN_LOG(" Attribute2      : %s\n", nsaListInfo[i].attribute2);
193         NN_LOG(" Attribute2      : %s\n", nsaListInfo[i].attribute3);
194         NN_LOG(" Caption         : %s\n", nsaListInfo[i].caption);
195         NN_LOG("----------------------\n");
196     }
197 
198 
199     ////////////////////////////////////////////////////////////////////////////
200     //
201     // Download the (NSA) file in the obtained NSA list
202     // This uses the same basic processing as sample_nadl_simple.
203     //
204     ////////////////////////////////////////////////////////////////////////////
205 
206     //Register BOSS storage.
207     const size_t NADL_STORAGE_SIZE         = 3*1024*1024;   //The amount of the expanded save data region to use as BOSS storage.
208     {
209         nn::Result result = nn::boss::GetStorageInfo();
210         if(result == nn::boss::ResultStorageNotFound())
211         {
212             NN_LOG("[BOSS Sample]RegisterStorage BOSS Storage.\n");
213             result = nn::boss::RegisterStorage(APP_EXT_STORAGE_ID, NADL_STORAGE_SIZE);
214         }
215         NN_BOSS_RESULT_HANDLING(result, "boss::RegisterStorage");
216     }
217 
218     //Opt-out settings (The following code sets and accesses the local opt-out flag.)
219     /*
220     {
221         //Set the opt-out flag
222         bool optoutValue = true;
223         nn::Result result = nn::boss::SetOptoutFlag(optoutValue);
224         NN_BOSS_RESULT_HANDLING(result, "nn::boss::SetOptoutFlag");
225 
226         // Access the opt-out flag
227         result = nn::boss::GetOptoutFlag(&optoutValue);
228         NN_LOG("[BOSS Sample]Optout value is %d\n", optoutValue);
229         NN_BOSS_RESULT_HANDLING(result, "nn::boss::GetOptoutFlag");
230     }
231     */
232 
233 
234     // Register and run the NADL task
235     // This downloads the files in the NSA list using an immediate execution task.
236     {
237         const char8 TASK_TARGET_URL[] = "https://npdl.cdn.nintendowifi.net/p01/nsa/9x4m4dJwyBBlUc3g/flist/file1"; /* Please see man pages for details */
238         //const char8 TASK_TARGET_URL[] = "https://npdl.cdn.nintendowifi.net/p01/nsa/9x4m4dJwyBBlUc3g/flist/file2"; /**< The task's target URL. This downloads file2 from the files in the NSA list. */
239         //const char8 TASK_TARGET_URL[] = "https://npdl.cdn.nintendowifi.net/p01/nsa/9x4m4dJwyBBlUc3g/flist/file3"; /**< The task's target URL. This downloads file3 from the files in the NSA list. */
240 
241         // Register the NADL task
242         // You don't need to specify an execution interval or execution count for immediate execution tasks.
243         nn::boss::TaskPolicy dPolicy;
244 
245         nn::boss::NsaDownloadAction dAction;
246         nn::Result result = dAction.Initialize(TASK_TARGET_URL);
247         NN_BOSS_RESULT_HANDLING(result, "NsaDownloadAction::Initialize");
248 
249         //result = dAction.SetApInfo( nn::boss::APINFOTYPE_APGROUP|nn::boss::APINFOTYPE_APAREA|nn::boss::APINFOTYPE_AP ); // Configure AP information to be given to HTTP queries, as necessary.
250         //result = dAction.AddHeaderField(pLabel, pValue); // Set a unique HTTP request header, as necessary.
251 
252         // Task for immediate execution
253         // Because the task for immediate execution uses the dedicated task ID "FGONLYT," there is no need to set the task ID with Initialize.
254         //
255         nn::boss::FgOnlyTask dFgOnlyTask;
256 
257         // Register a task for immediate execution.
258         NN_LOG("[BOSS Sample]Regist FG Only Task.\n");
259         result = nn::boss::RegisterImmediateTask(&dFgOnlyTask, &dAction, &dPolicy);
260         NN_BOSS_RESULT_HANDLING(result, "RegisterImmediateTask");
261 
262         //Wait for NADL download data
263         //// Get a data download notification event from the BOSS daemon
264         nn::os::Event arriveEvent(false);
265         result = nn::boss::RegisterNewArrivalEvent(&arriveEvent);
266         NN_BOSS_RESULT_HANDLING(result, "Task::RegisterNewArrivalEvent");
267 
268         // Immediate task execution
269         // FgOnlyTask can only use immediate execution in the foreground.
270         NN_LOG("[BOSS Sample]Start FG Only Task.\n");
271         result = dFgOnlyTask.StartImmediate();
272         NN_BOSS_RESULT_HANDLING(result, "FgOnlyTask::StartImmediate");
273 
274         //// Wait for new data to be downloaded.
275         NN_LOG("[BOSS Sample]Wait NSA data arrive....\n");
276         arriveEvent.Wait();
277         NN_LOG("[BOSS Sample]Recognize NSA data arrive\n");
278 
279         //// You can also wait for a task to complete rather than for data to be downloaded. (By "waiting for a task to complete," we mean "waiting for the next task to finish executing." This does not refer to running for the full execution count.)
280         //// When waiting for data download, even if a task is executed, if there is no connection with the server, if the data already exists,
281         //// or if the downloaded data is invalid (decoding process or signature verification fails), the data is discarded and the process cannot return from Wait.
282         //// If you run a task and wait for it to complete, WaitFinish will exit when the task completes even if it had an error.
283         //// Use each method where it suits the purpose.
284         //result = dTask.WaitFinish(); // Wait for the task to complete. (Without a timeout. This will wait indefinitely until processing is complete.)
285         //result = dTask.WaitFinish(nn::fnd::TimeSpan::FromSeconds(60)); // Wait for the task to complete. (With a timeout. ResultWaitfinishTimeout returns when processing does not complete within the specified time.)
286         //// Another way to wait for a task to complete is to poll on the task state using the Task::GetState function.
287         //// After you have detected that the task has completed, you can use the following functions to get information on the completed task.
288         //// Task::GetResult for the execution result
289         //// Task::GetCommErrorCode for the HTTP communication status code run by the task
290         //// Task::GetError for detailed information on task errors
291 
292 
293         /* ------------------------------------------------------------------------
294          * When a file in the NSA list is downloaded, often that data is processed by the application immediately, but if there are multiple instances of NS data existing in BOSS storage already, there is no way for the application to determine which data was just downloaded.
295          *
296          *
297          * For that reason, process the NS data in BOSS storage before getting the file and clear out BOSS storage.
298          *
299          * The following code assumes that the BOSS storage is empty.
300          *
301          * To download a file from the NSA list while leaving the existing NS data in BOSS storage, set the data version and private data type when registering the NSA list file (data) so that it can be distinguished from other NS data when getting NS data.
302          *
303          *
304          *
305            ------------------------------------------------------------------------ */
306 
307 
308         //Processing to download data.
309         //// Before you get a list of data IDs, the application's "update indicator flag" is on.
310         {
311             bool arriveFlag = false;
312             NN_UNUSED_VAR(arriveFlag);//Because this variable is exclusively used for output with NN_LOG, configure it to be unusable in Release builds.
313             result = nn::boss::GetNewArrivalFlag(&arriveFlag);
314             NN_BOSS_RESULT_HANDLING(result, "GetNewArrivalFlag");
315             NN_LOG("[BOSS Sample](Before Read Data, NewArrivalFlag is %d.)\n", arriveFlag);
316         }
317 
318         //// Get a serial ID list for the downloaded data. (You can use the first argument to GetNsDataIdList to filter the data that is obtained.)
319         u32 idBuf;                                       // Buffer for storing serial IDs. This is prepared by the application.
320         nn::boss::NsDataIdList serialIdList(&idBuf, 1);  // Download a file in the NSA list and get a single instance of NS data.
321         serialIdList.Initialize();
322 
323 
324         while (1)
325         {
326             result = nn::boss::GetNsDataIdList(nn::boss::DATA_TYPE_APPDATA|0xffff, &serialIdList); //If you only want to get extra data for the application.
327             if (result == nn::boss::ResultNsDataListUpdated())
328             {
329                 // If ResultNsDataListUpdated is returned, this indicates that NS data is added to or deleted from BOSS storage during the process of getting a list of IDs. Initialize the list and attempt to get a list of serial IDs from the beginning.
330                 serialIdList.Initialize();
331                 continue;
332             }
333 
334             break;
335         }
336 
337         if ((result.IsFailure()) && (result != nn::boss::ResultNsDataListSizeShortage()))
338         {
339             //Any error other than ResultNsDataListUpdated, ResultNsDataListSizeShortage, or ResultSuccess is an unexpected error.
340             //ResultNsDataListSizeShortage() indicates that a list of IDs was obtained successfully, but the IDs could not all be stored in an NsDataIdList (the operation must be repeated). ResultSuccess() indicates that a list of IDs was obtained successfully (all of the IDs were obtained).
341             NN_BOSS_RESULT_HANDLING(result, "boss::GetNsDataIdList");
342         }
343 
344         //Application-specific processing for downloaded data. (This demo dumps the header information and body data for all downloaded data.)
345         NN_LOG("[BOSS Sample]Dump NSD data.\n\n");
346         NN_LOG("===NSD (SerialID = %d)===\n", serialIdList.GetNsDataId(0));
347 
348         nn::boss::NsData contentData;
349         result = contentData.Initialize(serialIdList.GetNsDataId(0));
350         NN_BOSS_RESULT_HANDLING(result, "NsData::Initialize");
351 
352         //Check the header
353         {
354             nn::fs::TitleId titlleID = 0;
355             result = contentData.GetHeaderInfo(nn::boss::NSD_TITLEID, &titlleID, sizeof(titlleID));
356             NN_BOSS_RESULT_HANDLING(result, "NsData::GetHeaderInfo");
357             NN_LOG("TitleID = %llx\n",titlleID);
358 
359             u32 headerInfo = 0;
360             result = contentData.GetHeaderInfo(nn::boss::NSD_SERIALID, &headerInfo, sizeof(headerInfo));
361             NN_BOSS_RESULT_HANDLING(result, "NsData::GetHeaderInfo");
362             NN_LOG("Content SerialID = %d\n",headerInfo);
363 
364             result = contentData.GetHeaderInfo(nn::boss::NSD_LENGTH, &headerInfo, sizeof(headerInfo));
365             NN_BOSS_RESULT_HANDLING(result, "NsData::GetHeaderInfo");
366             NN_LOG("Payload Length = %d\n",headerInfo);
367 
368             result = contentData.GetHeaderInfo(nn::boss::NSD_VERSION, &headerInfo, sizeof(headerInfo));
369             NN_BOSS_RESULT_HANDLING(result, "NsData::GetHeaderInfo");
370             NN_LOG("Content version = %d\n",headerInfo);
371 
372             result = contentData.GetHeaderInfo(nn::boss::NSD_FLAGS, &headerInfo, sizeof(headerInfo));
373             NN_BOSS_RESULT_HANDLING(result, "NsData::GetHeaderInfo");
374             NN_LOG("Content Flags = %d\n",headerInfo);
375 
376             result = contentData.GetHeaderInfo(nn::boss::NSD_DATATYPE, &headerInfo, sizeof(headerInfo));
377             RESULT_SUCCESS_ASSERT(result);
378             NN_BOSS_RESULT_HANDLING(result, "NsData::GetHeaderInfo");
379             NN_LOG("Content DataType = %d\n",headerInfo);
380         }
381 
382         //Check the data
383         {
384             NN_LOG("---Dump Data---\n");
385             u8 dDataBuf[4*1024];
386             memset(dDataBuf, 0, sizeof(dDataBuf));
387             size_t readSize = 0;
388             u32 readCount = 0;
389             do
390             {
391                 ++readCount;
392                 NN_LOG("(Read %d)\n", readCount);
393                 readSize = contentData.ReadData(reinterpret_cast<u8*>(dDataBuf), sizeof(dDataBuf));
394                 NN_BOSS_RESULT_HANDLING(result, "NsData::ReadData");
395                 DumpNsdBody(dDataBuf, readSize);
396             }while(readSize != 0);
397         }
398 
399         //Get and set data attribute information
400         {
401             u32 setInfo = 0x100;
402             result = contentData.SetAdditionalInfo(setInfo);
403             NN_BOSS_RESULT_HANDLING(result, "NsData::SetAdditionalInfo");
404 
405             u32 getInfo;
406             result = contentData.GetAdditionalInfo(&getInfo);
407             NN_BOSS_RESULT_HANDLING(result, "NsData::SetAdditionalInfo");
408             NN_LOG("[BOSS Sample]AdditionalInfo = %d(Set Info = %d)\n", setInfo, setInfo);
409         }
410 
411         /*
412          * You can also use the data's already-read flag.
413          * Unlike the application's "update indicator flag" obtained by the RegisterNewArrivalEvent function, the data's already-read flag is used for the application to manage unprocessed data.
414          * The flag is off when data is downloaded and stays off as long as the application does not explicitly turn it on.
415          * Use this when the application manages unprocessed data.
416          * NOTE: The GetNewDataNsDataIdList function returns a list of data for which this flag is off. You can use this for different purposes than GetNsDataIdList, which returns a list of all data regardless of their flags.
417          */
418         {
419             bool nsdReadFlag = true;
420             result = contentData.GetReadFlag(&nsdReadFlag);
421             NN_BOSS_RESULT_HANDLING(result, "NsData::GetReadFlag");
422             NN_LOG("[BOSS Sample]NSD Read Flag = %d\n", nsdReadFlag);
423 
424             if(nsdReadFlag == false)
425             {
426                 //Turn the flag on. (The data's already-read flag does not change unless the application sets it.)
427                 result = contentData.SetReadFlag(true);
428                 NN_BOSS_RESULT_HANDLING(result, "NsData::SetNewFrag");
429             }
430         }
431 
432         //Delete data
433         /*
434         {
435             result = contentData.Delete();
436             NN_BOSS_RESULT_HANDLING(result, "NsData::Delete");
437         }
438         */
439 
440 
441         //After you get a list of data IDs, the application's "update indicator flag" is off.
442         {
443             bool arriveFlag = false;
444             result = nn::boss::GetNewArrivalFlag(&arriveFlag);
445             NN_BOSS_RESULT_HANDLING(result, "GetNewArrivalFlag");
446             NN_LOG("[BOSS Sample](After Read Data, NewArrivalFlag is %d.)\n", arriveFlag);
447         }
448 
449         //If you turn on the already-read flag for all data, the GetNewDataNsDataIdList function will get an empty list (because it gets a list of data for which the already-read flag is off).
450         {
451             result = nn::boss::GetNewDataNsDataIdList(nn::boss::DATA_TYPE_ALL, &serialIdList);
452             NN_BOSS_RESULT_HANDLING(result, "GetNewDataNsDataIdList");
453             NN_LOG("[BOSS Sample](After NSD read flag on, New NSD number is = %d)\n", serialIdList.GetSize());
454         }
455 
456     }
457 
458 }
459 
nnMain()460 extern "C" void nnMain()
461 {
462     // Call only the nn::applet::Enable function to also allow execution from the HOME Menu
463     // HOME Menu transitions, POWER Button presses, and sleep are all unsupported
464     nn::applet::Enable();
465 
466     /* =======================================================================
467            Pre-processing
468                  Note: Network configuration process or other processes. You do not need to implement this if the process has already been run when BOSS is used.
469        ======================================================================== */
470     //Initialize the BOSS library
471     {
472         nn::Result result = nn::boss::Initialize();
473         NN_BOSS_RESULT_HANDLING(result, "boss::Initialize");
474     }
475 
476     //Change settings so that the application runs BOSS in the background when we are not sleeping
477     {
478         // Initialize the NDM library
479         nn::Result result = nn::ndm::Initialize();
480         NN_BOSS_RESULT_HANDLING(result, "ndm::Initialize()");
481 
482         // Resume BOSS
483         result = nn::ndm::Resume(nn::ndm::DN_BOSS);
484         NN_BOSS_RESULT_HANDLING(result, "ndm::Resume()");
485     }
486 
487     // Create the expanded save data
488     // Save the downloaded NSA list in the expanded save data region.
489     {
490         const char extSaveDataMountName[] = "test:";
491         nn::fs::Initialize();
492         {
493             nn::Result result = nn::fs::MountExtSaveData(extSaveDataMountName, APP_EXT_STORAGE_ID);
494             if(result.IsFailure())
495             {
496                 if(nn::fs::ResultNotFormatted::Includes(result)        ||
497                    nn::fs::ResultBadFormat::Includes(result)           ||
498                    nn::fs::ResultVerificationFailed::Includes(result))
499                 {
500                     nn::fs::DeleteExtSaveData(APP_EXT_STORAGE_ID);
501                 }
502 
503                 if(nn::fs::ResultNotFound::Includes(result)             ||
504                    nn::fs::ResultNotFormatted::Includes(result)         ||
505                    nn::fs::ResultBadFormat::Includes(result)            ||
506                    nn::fs::ResultVerificationFailed::Includes(result))
507                 {
508                     NN_LOG("Create ExtSaveData(ID=%lx)\n", APP_EXT_STORAGE_ID);
509 
510                     //In SDK 0.14, icon data of some kind must be specified to fs::CreateExtSaveData.
511                     u8 iconData[] = {0x01};
512                     result = nn::fs::CreateExtSaveData(APP_EXT_STORAGE_ID, iconData, sizeof(iconData), 10, 100);
513                     if(result.IsFailure())
514                     {
515                         NN_LOG_ERROR("CreateExtSaveData failed(%08x)\n", result.GetPrintableBits());
516                         NN_UTIL_PANIC_IF_FAILED(result);
517                     }
518                     result = nn::fs::MountExtSaveData(extSaveDataMountName, APP_EXT_STORAGE_ID);
519                     NN_UTIL_PANIC_IF_FAILED(result);
520                 }
521                 else
522                 {
523                     NN_LOG_ERROR("MountExtSaveData failed(%08x)\n", result.GetPrintableBits());
524                     NN_UTIL_PANIC_IF_FAILED(result);
525                 }
526             }
527         }
528     }
529 
530     NN_LOG("Initializing network.\n");
531 
532     // Connect to the network.
533     // The NSA list is downloaded in the foreground, so you must connect to the network beforehand.
534     {
535         nn::Result result = InitializeNetwork();
536         NN_UTIL_PANIC_IF_FAILED(result);
537     }
538 
539     NN_LOG("BOSS Sample (NSA List Simple) Start\n");
540 
541     // Get the NSA list and download the files in the list
542     sampleNSAListExecute();
543 
544     NN_LOG("BOSS Sample (NSA List Simple) END\n");
545 
546     /* =======================================================================
547            Clean up
548                  Note: Network termination processing and other processing. If BOSS will still be used later, this does not need to be run.
549        ======================================================================== */
550     NN_LOG("Finalizing network.\n");
551     {
552         nn::Result result = FinalizeNetwork();
553         NN_UTIL_PANIC_IF_FAILED(result);
554     }
555 
556     //Unregister BOSS storage if BOSS features will not be used later.
557     //(Note that once it is unregistered, you will no longer be able to run NADL tasks or read data from BOSS storage.)
558     /*
559     {
560         nn::Result result = nn::boss::UnregisterStorage();
561         NN_UTIL_PANIC_IF_FAILED(result);
562     }
563     */
564 
565     //Finalize the NDM library
566     {
567         nn::Result result = nn::ndm::Finalize();
568         NN_BOSS_RESULT_HANDLING(result, "ndm::Finalize()");
569         //When the program exits, pause/resume settings are also restored
570     }
571 
572     //Shut down the library
573     {
574         nn::Result result = nn::boss::Finalize();
575         NN_UTIL_PANIC_IF_FAILED(result);
576     }
577 
578     NN_LOG("END\n");
579 }
580 
581 
582