]> git.proxmox.com Git - mirror_edk2.git/blame - EdkCompatibilityPkg/Compatibility/FrameworkHiiToUefiHiiThunk/Package.c
Fix typo.
[mirror_edk2.git] / EdkCompatibilityPkg / Compatibility / FrameworkHiiToUefiHiiThunk / Package.c
CommitLineData
4259256b 1/**@file\r
2\r
3 This file contains the keyboard processing code to the HII database.\r
4\r
5Copyright (c) 2006 - 2008, Intel Corporation\r
6All rights reserved. This program and the accompanying materials\r
7are licensed and made available under the terms and conditions of the BSD License\r
8which accompanies this distribution. The full text of the license may be found at\r
9http://opensource.org/licenses/bsd-license.php\r
10\r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16\r
17#include "HiiDatabase.h"\r
18\r
19\r
20EFI_STATUS\r
21GetIfrAndStringPackNum (\r
22 IN CONST EFI_HII_PACKAGES *Packages,\r
23 UINTN *IfrPackNum,\r
24 UINTN *StringPackNum\r
25 )\r
26{\r
27 UINTN Index;\r
28 TIANO_AUTOGEN_PACKAGES_HEADER **TianoAutogenPackageHdrArray;\r
29\r
30 ASSERT (Packages != NULL);\r
31 ASSERT (IfrPackNum != NULL);\r
32 ASSERT (StringPackNum != NULL);\r
33\r
34 *IfrPackNum = 0;\r
35 *StringPackNum = 0;\r
36\r
37 TianoAutogenPackageHdrArray = (TIANO_AUTOGEN_PACKAGES_HEADER **) (((UINT8 *) &Packages->GuidId) + sizeof (Packages->GuidId));\r
38 for (Index = 0; Index < Packages->NumberOfPackages; Index++) {\r
39 //\r
40 // BugBug: The current UEFI HII build tool generate a binary in the format defined in: \r
41 // TIANO_AUTOGEN_PACKAGES_HEADER. We assume that all packages generated in\r
42 // this binary is with same package type. So the returned IfrPackNum and StringPackNum\r
43 // may not be the exact number of valid package number in the binary generated \r
44 // by HII Build tool.\r
45 //\r
46 switch (TianoAutogenPackageHdrArray[Index]->PackageHeader.Type) {\r
47 case EFI_HII_PACKAGE_FORM:\r
48 *IfrPackNum += 1;\r
49 break;\r
50 case EFI_HII_PACKAGE_STRINGS:\r
51 *StringPackNum += 1;\r
52 break;\r
53\r
54 case EFI_HII_PACKAGE_SIMPLE_FONTS:\r
55 break;\r
56\r
57 //\r
58 // The following fonts are invalid for a module that using Framework to UEFI thunk layer.\r
59 //\r
60 case EFI_HII_PACKAGE_KEYBOARD_LAYOUT:\r
61 case EFI_HII_PACKAGE_FONTS:\r
62 case EFI_HII_PACKAGE_IMAGES:\r
63 default:\r
64 ASSERT (FALSE);\r
65 return EFI_INVALID_PARAMETER;\r
66 break;\r
67 }\r
68 }\r
69\r
70 return EFI_SUCCESS;\r
71}\r
72\r
73EFI_STATUS \r
74LibExportPackageLists (\r
75 IN EFI_HII_HANDLE UefiHiiHandle,\r
76 OUT EFI_HII_PACKAGE_LIST_HEADER **PackageListHeader,\r
77 OUT UINTN *PackageListSize\r
78 )\r
79{\r
80 EFI_STATUS Status;\r
81 UINTN Size;\r
82 EFI_HII_PACKAGE_LIST_HEADER *PackageListHdr;\r
83\r
84 ASSERT (PackageListSize != NULL);\r
85 ASSERT (PackageListHeader != NULL);\r
86\r
87 Size = 0;\r
88 PackageListHdr = NULL;\r
59336178 89 Status = mHiiDatabase->ExportPackageLists (\r
90 mHiiDatabase,\r
4259256b 91 UefiHiiHandle,\r
92 &Size,\r
93 PackageListHdr\r
94 );\r
95 ASSERT_EFI_ERROR (Status == EFI_BUFFER_TOO_SMALL);\r
96 if (Status == EFI_BUFFER_TOO_SMALL) {\r
97 PackageListHdr = AllocateZeroPool (Size);\r
98 ASSERT (PackageListHdr != NULL);\r
99 \r
100 if (PackageListHeader == NULL) {\r
101 return EFI_OUT_OF_RESOURCES;\r
102 } else {\r
59336178 103 Status = mHiiDatabase->ExportPackageLists (\r
104 mHiiDatabase,\r
4259256b 105 UefiHiiHandle,\r
106 &Size,\r
107 PackageListHdr\r
108 );\r
109 ASSERT_EFI_ERROR (Status);\r
110 }\r
111 }\r
112\r
113 if (!EFI_ERROR (Status)) {\r
114 *PackageListHeader = PackageListHdr;\r
115 *PackageListSize = Size;\r
116 }\r
117\r
118 return Status;\r
119}\r
120\r
121BOOLEAN\r
122IsOnlyStringPackagesInPackageList (\r
123 IN CONST EFI_HII_PACKAGE_LIST_HEADER *StringPackageListHeader\r
124 )\r
125{\r
126 EFI_HII_PACKAGE_HEADER *PackageHeader;\r
127\r
128 PackageHeader = (EFI_HII_PACKAGE_HEADER *) (StringPackageListHeader + 1);\r
129\r
130 while (PackageHeader->Type != EFI_HII_PACKAGE_END) {\r
131 PackageHeader = (EFI_HII_PACKAGE_HEADER *) (PackageHeader );\r
132 }\r
133}\r
134 \r
135\r
136EFI_STATUS\r
137InsertStringPackagesToIfrPackageList (\r
138 IN CONST EFI_HII_PACKAGE_LIST_HEADER *StringPackageListHeader,\r
139 IN EFI_HII_HANDLE UefiHiiHandle \r
140 )\r
141{\r
142 EFI_STATUS Status;\r
59336178 143 Status = mHiiDatabase->UpdatePackageList (\r
144 mHiiDatabase,\r
4259256b 145 UefiHiiHandle,\r
146 StringPackageListHeader\r
147 );\r
148\r
149 return Status;\r
150}\r
151\r
152\r
153/**\r
154 Removes a node from a doubly linked list, and returns the node that follows\r
155 the removed node.\r
156\r
157 Removes the node Entry from a doubly linked list. It is up to the caller of\r
158 this function to release the memory used by this node if that is required. On\r
159 exit, the node following Entry in the doubly linked list is returned. If\r
160 Entry is the only node in the linked list, then the head node of the linked\r
161 list is returned.\r
162\r
163 If Entry is NULL, then ASSERT().\r
164 If Entry is the head node of an empty list, then ASSERT().\r
165 If PcdMaximumLinkedListLength is not zero, and the number of nodes in the\r
166 linked list containing Entry, including the Entry node, is greater than\r
167 or equal to PcdMaximumLinkedListLength, then ASSERT().\r
168\r
169 @param Entry A pointer to a node in a linked list\r
170\r
171 @return Entry\r
172\r
173**/\r
174EFI_STATUS\r
175AddStringPackagesToMatchingIfrPackageList (\r
176 IN EFI_HII_THUNK_PRIVATE_DATA *Private,\r
177 IN CONST EFI_HII_PACKAGE_LIST_HEADER *StringPackageListHeader\r
178 )\r
179{\r
180 EFI_STATUS Status;\r
181 LIST_ENTRY *ListEntry;\r
182 HII_TRHUNK_HANDLE_MAPPING_DATABASE_ENTRY *HandleMapEntry;\r
183\r
184 for (ListEntry = Private->HiiThunkHandleMappingDBListHead.ForwardLink;\r
185 ListEntry != &Private->HiiThunkHandleMappingDBListHead;\r
186 ListEntry = ListEntry->ForwardLink\r
187 ) {\r
188 HandleMapEntry = HII_TRHUNK_HANDLE_MAPPING_DATABASE_ENTRY_FROM_LISTENTRY (ListEntry);\r
189 if (CompareGuid (&StringPackageListHeader->PackageListGuid, &HandleMapEntry->TagGuid)) {\r
190 Status = InsertStringPackagesToIfrPackageList (StringPackageListHeader, HandleMapEntry->UefiHiiHandle);\r
191 }\r
192 }\r
193 \r
194 return EFI_NOT_FOUND;\r
195}\r
196EFI_HII_PACKAGE_LIST_HEADER *\r
197PrepareUefiPackageListFromFrameworkHiiPackages (\r
198 IN CONST EFI_HII_PACKAGES *Packages,\r
199 IN CONST EFI_GUID *GuidId OPTIONAL\r
200 )\r
201{\r
202 UINTN NumberOfPackages;\r
203 EFI_HII_PACKAGE_LIST_HEADER *PackageListHeader;\r
204 UINT8 *PackageListData;\r
205 UINT32 PackageListLength;\r
206 UINT32 PackageLength;\r
207 EFI_HII_PACKAGE_HEADER PackageHeader;\r
208 UINTN Index;\r
209 TIANO_AUTOGEN_PACKAGES_HEADER **TianoAutogenPackageHdrArray;\r
210\r
211 TianoAutogenPackageHdrArray = (TIANO_AUTOGEN_PACKAGES_HEADER **) ((UINT8 *) &Packages->GuidId + sizeof (Packages->GuidId));\r
212 NumberOfPackages = Packages->NumberOfPackages;\r
213\r
214 PackageListLength = sizeof (EFI_HII_PACKAGE_LIST_HEADER);\r
215\r
216 for (Index = 0; Index < NumberOfPackages; Index++) {\r
217 CopyMem (&PackageLength, &TianoAutogenPackageHdrArray[Index]->BinaryLength, sizeof (UINT32));\r
99a83b4c 218 //\r
219 //TIANO_AUTOGEN_PACKAGES_HEADER.BinaryLength include the BinaryLength itself.\r
220 //\r
221 PackageListLength += (PackageLength - sizeof(UINT32)); \r
4259256b 222 }\r
223\r
224 //\r
225 // Include the lenght of EFI_HII_PACKAGE_END\r
226 //\r
227 PackageListLength += sizeof (EFI_HII_PACKAGE_HEADER);\r
228 PackageListHeader = AllocateZeroPool (PackageListLength);\r
229 ASSERT (PackageListHeader != NULL);\r
230 if (GuidId == NULL) {\r
231 CopyMem (&PackageListHeader->PackageListGuid, Packages->GuidId, sizeof (EFI_GUID));\r
232 } else {\r
233 CopyMem (&PackageListHeader->PackageListGuid, GuidId, sizeof (EFI_GUID));\r
234 }\r
235 PackageListHeader->PackageLength = PackageListLength;\r
236\r
237 PackageListData = ((UINT8 *) PackageListHeader) + sizeof (EFI_HII_PACKAGE_LIST_HEADER);\r
238\r
239 for (Index = 0; Index < NumberOfPackages; Index++) {\r
240 CopyMem (&PackageLength, &(TianoAutogenPackageHdrArray[Index]->BinaryLength), sizeof (UINT32));\r
241 PackageLength -= sizeof (UINT32);\r
242 CopyMem (PackageListData, &(TianoAutogenPackageHdrArray[Index]->PackageHeader), PackageLength);\r
243 PackageListData += PackageLength;\r
244 }\r
245\r
246 //\r
247 // Append EFI_HII_PACKAGE_END\r
248 //\r
249 PackageHeader.Type = EFI_HII_PACKAGE_END;\r
250 PackageHeader.Length = sizeof (EFI_HII_PACKAGE_HEADER);\r
251 CopyMem (PackageListData, &PackageHeader, PackageHeader.Length);\r
252\r
253 return PackageListHeader; \r
254}\r
255\r
59336178 256VOID\r
257GenerateGuidId (\r
258 IN CONST EFI_GUID * InGuid,\r
259 OUT EFI_GUID * OutGuid\r
4259256b 260 )\r
261{\r
4259256b 262 UINT64 MonotonicCount;\r
263\r
59336178 264 CopyMem (OutGuid, InGuid, sizeof (EFI_GUID));\r
4259256b 265 \r
266 gBS->GetNextMonotonicCount (&MonotonicCount);\r
267 //\r
268 // Use Monotonic Count as a psedo random number generator.\r
269 //\r
59336178 270 *((UINT64 *) OutGuid) = *((UINT64 *) OutGuid) + MonotonicCount;\r
4259256b 271}\r
272\r
273EFI_STATUS\r
274FindAndAddStringPackageToIfrPackageList(\r
275 EFI_HII_THUNK_PRIVATE_DATA *Private,\r
276 EFI_GUID *GuidId,\r
277 EFI_HII_HANDLE UefiIfrHiiHandle\r
278 )\r
279{\r
280 EFI_STATUS Status;\r
281 LIST_ENTRY *ListEntry;\r
282 HII_TRHUNK_HANDLE_MAPPING_DATABASE_ENTRY *HandleMapEntry;\r
283 EFI_HII_PACKAGE_LIST_HEADER *StringPackageListHeader;\r
284 UINTN Size;\r
285\r
286 for (ListEntry = Private->HiiThunkHandleMappingDBListHead.ForwardLink;\r
287 ListEntry != &Private->HiiThunkHandleMappingDBListHead;\r
288 ListEntry = ListEntry->ForwardLink\r
289 ) {\r
290 HandleMapEntry = HII_TRHUNK_HANDLE_MAPPING_DATABASE_ENTRY_FROM_LISTENTRY (ListEntry);\r
291 if (CompareGuid (GuidId, &HandleMapEntry->TagGuid) && (!HandleMapEntry->DoesPackageListImportStringPackages)) {\r
292 Status = LibExportPackageLists (HandleMapEntry->UefiHiiHandle, &StringPackageListHeader, &Size);\r
293 ASSERT_EFI_ERROR (Status);\r
294\r
295 //\r
296 // Add Function to only get only String Packages from the Package List\r
297 //\r
298\r
299 Status = InsertStringPackagesToIfrPackageList (StringPackageListHeader, UefiIfrHiiHandle);\r
300 ASSERT_EFI_ERROR (Status);\r
301 \r
302 FreePool (StringPackageListHeader);\r
303 return EFI_SUCCESS;\r
304 }\r
305 }\r
306\r
307 return EFI_NOT_FOUND;\r
308\r
309}\r
310\r
59336178 311CONST EFI_GUID mAGuid = \r
312 { 0x14f95e01, 0xd562, 0x432e, { 0x84, 0x4a, 0x95, 0xa4, 0x39, 0x5, 0x10, 0x7e } };\r
313\r
4259256b 314EFI_STATUS\r
315UefiRegisterPackageList(\r
316 EFI_HII_THUNK_PRIVATE_DATA *Private,\r
317 EFI_HII_PACKAGES *Packages,\r
318 FRAMEWORK_EFI_HII_HANDLE *Handle\r
319 )\r
320{\r
321 EFI_STATUS Status;\r
322 UINTN StringPackNum;\r
323 UINTN IfrPackNum;\r
324 EFI_HII_PACKAGE_LIST_HEADER *UefiPackageListHeader;\r
325 HII_TRHUNK_HANDLE_MAPPING_DATABASE_ENTRY *HandleMappingEntry;\r
59336178 326 EFI_GUID GuidId;\r
4259256b 327 EFI_HANDLE UefiHiiDriverHandle;\r
328\r
4259256b 329 UefiHiiDriverHandle = NULL;\r
ea58467b 330 UefiPackageListHeader = NULL;\r
4259256b 331\r
332 Status = GetIfrAndStringPackNum (Packages, &IfrPackNum, &StringPackNum);\r
333 ASSERT_EFI_ERROR (Status);\r
59336178 334 //\r
5391c4f1 335 // Thunk Layer only handle the following combinations of IfrPack, StringPkg and FontPack.\r
336 // Thunk Layer only allow zero or one IfrPack in the Package List.\r
59336178 337 //\r
338 if (IfrPackNum > 1) {\r
339 return EFI_UNSUPPORTED;\r
340 }\r
4259256b 341\r
342 HandleMappingEntry = AllocateZeroPool (sizeof (*HandleMappingEntry));\r
343 ASSERT (HandleMappingEntry != NULL);\r
344 \r
345 HandleMappingEntry->Signature = HII_TRHUNK_HANDLE_MAPPING_DATABASE_ENTRY_SIGNATURE;\r
ea58467b 346 Status = AssignHiiHandle (Private, &HandleMappingEntry->FrameworkHiiHandle);\r
347 if (EFI_ERROR (Status)) {\r
348 goto Done;\r
349 }\r
59336178 350\r
351 //\r
352 // Packages->GuidId may be NULL. In such case, caller of FramworkHii->NewPack is registering\r
353 // package with StringPack and IfrPack.\r
354 //\r
355 if (Packages->GuidId == NULL) {\r
356 Packages->GuidId = &GuidId;\r
357 GenerateGuidId (&mAGuid, Packages->GuidId);\r
358 }\r
359 \r
4259256b 360 CopyGuid (&HandleMappingEntry->TagGuid, Packages->GuidId);\r
361\r
362 if ((StringPackNum == 0) && (IfrPackNum != 0)) {\r
363 //\r
364 // UEFI HII database does not allow two package list with the same GUID.\r
365 // In Framework HII implementation, Packages->GuidId is used as an identifier to associate \r
366 // a PackageList with only IFR to a Package list the with String package.\r
367 //\r
59336178 368 GenerateGuidId (Packages->GuidId, &GuidId);\r
4259256b 369 }\r
370\r
371 //\r
372 // UEFI HII require EFI_HII_CONFIG_ACCESS_PROTOCOL to be installed on a EFI_HANDLE, so\r
5391c4f1 373 // that Setup Utility can load the Buffer Storage using this protocol.\r
4259256b 374 //\r
375 if (IfrPackNum != 0) {\r
ebbd2793 376 InstallDefaultUefiConfigAccessProtocol (Packages, &UefiHiiDriverHandle, HandleMappingEntry);\r
4259256b 377 }\r
59336178 378 UefiPackageListHeader = PrepareUefiPackageListFromFrameworkHiiPackages (Packages, &GuidId);\r
379 Status = mHiiDatabase->NewPackageList (\r
380 mHiiDatabase,\r
4259256b 381 UefiPackageListHeader, \r
382 UefiHiiDriverHandle,\r
383 &HandleMappingEntry->UefiHiiHandle\r
384 );\r
385 ASSERT_EFI_ERROR (Status);\r
386 if (EFI_ERROR (Status)) {\r
387 goto Done;\r
388 }\r
389 \r
390 if (IfrPackNum == 0) {\r
391 if (StringPackNum != 0) {\r
392 //\r
393 // Look for a package list with IFR Pack which has already registed with HII Database\r
394 //\r
395 HandleMappingEntry->IsPackageListWithOnlyStringPackages = TRUE;\r
396 Status = AddStringPackagesToMatchingIfrPackageList (\r
397 Private,\r
398 UefiPackageListHeader\r
399 );\r
400\r
401 if (!EFI_ERROR (Status) || Status == EFI_NOT_FOUND) {\r
402\r
403 if (Status == EFI_NOT_FOUND) {\r
404 Status = EFI_SUCCESS;\r
405 }\r
406 }\r
407 }\r
408 } else {\r
409 if (StringPackNum == 0) {\r
410 //\r
411 // Register the Package List to UEFI HII first.\r
412 //\r
413 Status = FindAndAddStringPackageToIfrPackageList (\r
414 Private,\r
415 Packages->GuidId,\r
416 HandleMappingEntry->UefiHiiHandle\r
417 );\r
418 ASSERT_EFI_ERROR (Status);\r
419 if (!EFI_ERROR (Status)) {\r
420 HandleMappingEntry->DoesPackageListImportStringPackages = TRUE;\r
421 }\r
422 }\r
423 }\r
424\r
425 if (!EFI_ERROR (Status)) {\r
426 InsertTailList (&Private->HiiThunkHandleMappingDBListHead, &HandleMappingEntry->List);\r
427 }\r
428\r
429Done:\r
430 if (EFI_ERROR (Status)) {\r
431 FreePool (HandleMappingEntry);\r
432 } else {\r
433 *Handle = HandleMappingEntry->FrameworkHiiHandle;\r
434 }\r
435\r
ea58467b 436 SafeFreePool (UefiPackageListHeader);\r
4259256b 437 \r
438 return Status;\r
439}\r
440\r
ea58467b 441BOOLEAN mInFrameworkHiiNewPack = FALSE;\r
442\r
4259256b 443EFI_STATUS\r
444EFIAPI\r
445HiiNewPack (\r
446 IN EFI_HII_PROTOCOL *This,\r
447 IN EFI_HII_PACKAGES *Packages,\r
448 OUT FRAMEWORK_EFI_HII_HANDLE *Handle\r
449 )\r
450/*++\r
451\r
452Routine Description:\r
453\r
454 Extracts the various packs from a package list.\r
455\r
456Arguments:\r
457\r
458 This - Pointer of HII protocol.\r
459 Packages - Pointer of HII packages.\r
460 Handle - Handle value to be returned.\r
461\r
462Returns:\r
463\r
464 EFI_SUCCESS - Pacakges has added to HII database successfully.\r
465 EFI_INVALID_PARAMETER - Invalid parameter.\r
466\r
467--*/\r
468{\r
469 EFI_STATUS Status;\r
470 EFI_HII_THUNK_PRIVATE_DATA *Private;\r
471\r
472 if (Handle == NULL) {\r
473 return EFI_INVALID_PARAMETER;\r
474 }\r
475\r
476 if (Packages == NULL) {\r
477 return EFI_INVALID_PARAMETER;\r
478 }\r
479\r
ea58467b 480 //\r
481 // We use a simple Global variable to inform NewPackNotify\r
482 // that the package list registered here is already registered\r
483 // in the HII Thunk Layer. So NewPackNotify does not need to\r
484 // call RegisterUefiHiiHandle () to registered it.\r
485 //\r
486 mInFrameworkHiiNewPack = TRUE;\r
487\r
4259256b 488 Private = EFI_HII_THUNK_PRIVATE_DATA_FROM_THIS(This);\r
489\r
490 Status = UefiRegisterPackageList (\r
491 Private,\r
492 Packages,\r
493 Handle\r
494 );\r
495\r
ea58467b 496 mInFrameworkHiiNewPack = FALSE;\r
497\r
4259256b 498 return Status;\r
499}\r
500\r
501EFI_STATUS\r
502EFIAPI\r
503HiiRemovePack (\r
504 IN EFI_HII_PROTOCOL *This,\r
505 IN FRAMEWORK_EFI_HII_HANDLE Handle\r
506 )\r
507/*++\r
508\r
509Routine Description:\r
510 Removes the various packs from a Handle\r
511\r
512Arguments:\r
513\r
514Returns:\r
515\r
516--*/\r
517{\r
518 EFI_STATUS Status;\r
519 EFI_HII_THUNK_PRIVATE_DATA *Private;\r
4259256b 520 HII_TRHUNK_HANDLE_MAPPING_DATABASE_ENTRY *HandleMapEntry;\r
99a83b4c 521 EFI_DEVICE_PATH_PROTOCOL *Path;\r
4259256b 522\r
523 Private = EFI_HII_THUNK_PRIVATE_DATA_FROM_THIS(This);\r
524\r
99a83b4c 525 HandleMapEntry = FrameworkHiiHandleToMapDatabaseEntry (Private, Handle);\r
4259256b 526\r
99a83b4c 527 if (HandleMapEntry->UefiHiiHandle != NULL) {\r
59336178 528 Status = mHiiDatabase->RemovePackageList (\r
529 mHiiDatabase,\r
99a83b4c 530 HandleMapEntry->UefiHiiHandle\r
531 );\r
532 ASSERT_EFI_ERROR (Status);\r
533\r
534 Status = gBS->HandleProtocol (\r
535 HandleMapEntry->UefiHiiHandle,\r
536 &gEfiDevicePathProtocolGuid,\r
537 &Path\r
538 );\r
539\r
540 if (!EFI_ERROR (Status)) {\r
541 Status = gBS->UninstallProtocolInterface (\r
542 HandleMapEntry->UefiHiiHandle,\r
543 &gEfiDevicePathProtocolGuid,\r
544 Path\r
545 );\r
546 if (!EFI_ERROR (Status)) {\r
547 FreePool (Path);\r
548 }\r
4259256b 549 }\r
99a83b4c 550\r
551 RemoveEntryList (&HandleMapEntry->List);\r
552\r
553 FreePool (HandleMapEntry);\r
554 return Status;\r
4259256b 555 }\r
556\r
557 return EFI_NOT_FOUND;\r
558}\r