ExportPackageList (
  IN HII_DATABASE_PRIVATE_DATA          *Private,
  IN EFI_HII_HANDLE                     Handle,
  IN HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList,
  IN OUT UINTN                          *UsedSize,
  IN UINTN                              BufferSize,
  OUT EFI_HII_PACKAGE_LIST_HEADER       *Buffer
  )
{
  EFI_STATUS                          Status;
  UINTN                               ResultSize;
  EFI_HII_PACKAGE_HEADER              EndofPackageList;

  ASSERT (Private != NULL && PackageList != NULL && UsedSize != NULL);
  ASSERT (Private->Signature == HII_DATABASE_PRIVATE_DATA_SIGNATURE);
  ASSERT (IsHiiHandleValid (Handle));

  if (BufferSize > 0 && Buffer == NULL ) {
    return EFI_INVALID_PARAMETER;
  }

  //
  // Copy the package list header
  // ResultSize indicates the length of the exported bytes of this package list
  //
  ResultSize = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
  if (ResultSize + *UsedSize <= BufferSize) {
    CopyMem ((VOID *) Buffer, PackageList, ResultSize);
  }
  //
  // Copy the packages and invoke EXPORT_PACK notify functions if exists.
  //
  Status = ExportGuidPackages (
             Private,
             Handle,
             PackageList,
             *UsedSize,
             BufferSize,
             (VOID *) ((UINT8 *) Buffer + ResultSize),
             &ResultSize
             );
  if (EFI_ERROR (Status)) {
    return Status;
  }
  Status = ExportFormPackages (
             Private,
             Handle,
             PackageList,
             *UsedSize,
             BufferSize,
             (VOID *) ((UINT8 *) Buffer + ResultSize),
             &ResultSize
             );
  if (EFI_ERROR (Status)) {
    return Status;
  }
  Status = ExportKeyboardLayoutPackages (
             Private,
             Handle,
             PackageList,
             *UsedSize,
             BufferSize,
             (VOID *) ((UINT8 *) Buffer + ResultSize),
             &ResultSize
             );
  if (EFI_ERROR (Status)) {
    return Status;
  }
  Status = ExportStringPackages (
             Private,
             Handle,
             PackageList,
             *UsedSize,
             BufferSize,
             (VOID *) ((UINT8 *) Buffer + ResultSize),
             &ResultSize
             );
  if (EFI_ERROR (Status)) {
    return Status;
  }
  Status = ExportFontPackages (
             Private,
             Handle,
             PackageList,
             *UsedSize,
             BufferSize,
             (VOID *) ((UINT8 *) Buffer + ResultSize),
             &ResultSize
             );
  if (EFI_ERROR (Status)) {
    return Status;
  }
  Status = ExportImagePackages (
             Private,
             Handle,
             PackageList,
             *UsedSize,
             BufferSize,
             (VOID *) ((UINT8 *) Buffer + ResultSize),
             &ResultSize
             );
  if (EFI_ERROR (Status)) {
    return Status;
  }
  Status = ExportSimpleFontPackages (
             Private,
             Handle,
             PackageList,
             *UsedSize,
             BufferSize,
             (VOID *) ((UINT8 *) Buffer + ResultSize),
             &ResultSize
             );
  if (EFI_ERROR (Status)) {
    return Status;
  }
  Status = ExportDevicePathPackage (
             Private,
             Handle,
             PackageList,
             *UsedSize,
             BufferSize,
             (VOID *) ((UINT8 *) Buffer + ResultSize),
             &ResultSize
             );
  if (EFI_ERROR (Status)) {
    return Status;
  }
  //
  // Append the package list end.
  //
  EndofPackageList.Length = sizeof (EFI_HII_PACKAGE_HEADER);
  EndofPackageList.Type   = EFI_HII_PACKAGE_END;
  if (ResultSize + *UsedSize + sizeof (EFI_HII_PACKAGE_HEADER) <= BufferSize) {
    CopyMem (
      (VOID *) ((UINT8 *) Buffer + ResultSize),
      (VOID *) &EndofPackageList,
      sizeof (EFI_HII_PACKAGE_HEADER)
      );
  }

  *UsedSize += ResultSize + sizeof (EFI_HII_PACKAGE_HEADER);

  return EFI_SUCCESS;
}