// Copyright (c) Microsoft Corporation.  All rights reserved.

cpp_quote( "// Copyright (c) Microsoft Corporation.  All rights reserved." )
cpp_quote( "" )

import "oaidl.idl";
import "ocidl.idl";

cpp_quote( "#include <SpecStrings.h>" )

#ifndef ALGIDDEF
#define ALGIDDEF
typedef unsigned int ALG_ID;
#endif

interface IDpxJob;
interface IDpxContainer;
interface IDpxFile;
interface IDpxContainerDirectoryEntry;
interface IDpxDownloadProvider;
interface IDpxDownloadCallback;

interface IEnumDpxContainers;
interface IEnumDpxFiles;
interface IEnumDpxContainerDirectoryEntries;


typedef enum
{
    DPX_RESUME_AND_DOWNLOAD   = 0x0000,    // perform end-to-end extract/download as needed
    DPX_RESUME_UNTIL_DOWNLOAD = 0x0001,    // proceed until download is needed, then stop
                                          //   (can then use download provider directly)
    DPX_RESUME_AND_DOWNLOAD_FALLBACK = 0x0002, // perform end to end extraction and use only fallbacks
}
DPX_RESUME_TYPE;


#define DPX_MAX_HASH_SIZE 64    // 512 bits is largest supported hash algorithm
cpp_quote( "#define DPX_MAX_HASH_SIZE 64" )

typedef struct
{
    ALG_ID AlgorithmId;
    UINT   HashSize;
    [length_is( HashSize )] BYTE HashData[ DPX_MAX_HASH_SIZE ];
}
DPX_HASH;


typedef struct
{
    UINT64 Offset;
    UINT64 Length;
}
DPX_BYTE_RANGE;


typedef enum
{
    DPX_PHASE_JOB_IDLE       = 0x0000,   // job in suspended state. job is waiting
                                         // to be resumed.
    DPX_PHASE_DOWNLOAD_INDEX = 0x0010,   // downloading container file index
    DPX_PHASE_INVENTORY      = 0x0020,   // searching for delta basis files
    DPX_PHASE_DOWNLOAD_FILES = 0x0030,   // downloading container file contents
    DPX_PHASE_EXPAND_FILES   = 0x0040,   // expanding/verifying downloaded data
    DPX_PHASE_JOB_INPROGRESS = 0x0050,   // job is in progress

    DPX_PHASE_JOB_COMPLETE   = 0x7F00,   // most recent Resume returned S_OK
    DPX_PHASE_JOB_CANCELLED  = 0xFFFE,   // job cancelled
    DPX_PHASE_JOB_FAILURE    = 0xFFFF,   // job unsuccessful
}
DPX_PROGRESS_PHASE;


typedef struct
{
    UINT64 Completed;
    UINT64 Remaining;    //  (Completed/(Completed+Remaining)) == Percent
}
DPX_PROGRESS_REMAIN;


typedef struct
{
    DPX_PROGRESS_REMAIN Inventory;  // one tick for each FindNext or byte scanned
    DPX_PROGRESS_REMAIN Download;   // one tick for each byte downloaded
    DPX_PROGRESS_REMAIN Expansion;  // one tick for each downloaded byte processed
    DPX_PROGRESS_REMAIN Files;      // one tick for each target file completed
    DPX_PROGRESS_REMAIN Overall;    // sum of above
    DPX_PROGRESS_PHASE  ePhase;     // current phase
}
DPX_PROGRESS;


[ uuid( ddc1b711-0e55-452f-838e-d1505b866e2b ), object, pointer_default( unique ) ]
interface IDpxJob : IUnknown
{
    //
    //  TargetPath is the local file system directory under which extracted
    //  files should be created, specified at Job creation.  Files created
    //  under this directory may include relative subdirectory names or even
    //  stream names.  Files and subdirectories will be created with inherited
    //  ACL from TargetPath and owner from the thread calling
    //  IDpxDownloadCallback.  During the course of extraction, additional
    //  temporary files might be created in the TargetPath but will be deleted
    //  when the job completes.  If the job is cancelled or destroyed before
    //  completing, these temporary files may not be automatically deleted.
    //

    HRESULT GetTargetPath( [out] LPWSTR* TargetPath );  // FreeMemory

    //
    //  An extract job consists of one or more containers, which are packages
    //  containing one or more files (e.g., .cab, .psf, .wim).  A container
    //  has a single source path, usually a URL or local filename, but is
    //  interpreted only by the download provider.  AddContainer with same
    //  ContainerPath as an already existing container object will return
    //  interface pointer to the existing container object.  For each
    //  container, specify which files from the container are desired for
    //  download/extraction.  See IDpxContainer for more details on specifying
    //  individual files within each container.
    //

    HRESULT AddContainer(
                [in]  LPCWSTR ContainerPath,
                [out] IDpxContainer ** ppContainer
                );

    HRESULT EnumContainers(
                [out] IEnumDpxContainers ** ppEnumContainers
                );

    //
    //  Caller may optionally specify a download provider.  If caller does not
    //  specify a download provider, a default download provider will be used
    //  that supports local file system and UNC through CreateFile/ReadFile.
    //
    //  Since this is a pointer, it is ignored during SaveJobState, so
    //  caller must SetDownloadProvider after DpxRestoreJob before calling
    //  Resume to continue the job.
    //
    //  Attempt to change the download provider during an active job will fail,
    //  but can be done while job is suspended.  If provider is changed while
    //  job is suspended, any in-progress downloads will be abandoned.
    //
    //  SetDownloadProvider( NULL ) will reset to default download provider.
    //

    HRESULT SetDownloadProvider( [in, unique] IDpxDownloadProvider*   pDownloadProvider );
    HRESULT GetDownloadProvider( [out]        IDpxDownloadProvider** ppDownloadProvider );

    //
    //  Extract jobs are always created in the suspended state.  After
    //  populating the job with all the desired files to extract/download,
    //  call Resume to begin the evaluation and optional download.  If caller
    //  specifies DPX_RESUME_WITH_DOWNLOAD, the download provider's Resume
    //  method will be called after the download is computed and will not
    //  return to caller until job is complete or an error occurs.  If caller
    //  specifies DPX_RESUME_UNTIL_DOWNLOAD, the download provider's Resume
    //  will not be called, and this Resume call will return to caller with
    //  E_PENDING after populating download provider job or S_OK if the job
    //  is complete without requiring additional download.  If Resume returns
    //  E_PENDING, it is caller's responsibility to Resume the download
    //  provider directly.
    //

    HRESULT Resume( DPX_RESUME_TYPE eResumeType );

    //
    //  Suspend may be called by another thread to cause Resume to stop
    //  within short period of time and return (BUGBUG) DPX_E_SUSPENDED.
    //  After Resume returns, caller may call Resume again to continue
    //  the job.
    //

    HRESULT Suspend();

    //
    //  Cancel may be called to destructively end a job.  Unlike Suspend,
    //  Cancel will destroy all the outstanding downloads and job state,
    //  and will leave any already downloaded, extracted, and validated
    //  target files in the target directory.
    //

    HRESULT Cancel();

    //
    //  GetProgress can be used to poll job progress.  See description of
    //  DPX_PROGRESS structure for more info.  Job progress is summation of
    //  all underlying container extractions progress and download provider
    //  progress.
    //

    HRESULT GetProgress( [out] DPX_PROGRESS * pProgress );

    //
    //  While a job is in suspended state, SaveJobState can be used to
    //  save the current state of a job in a format that can be stored to disk
    //  and later resumed through DpxRestoreJob.
    //

    HRESULT SaveJobState();

    //
    //  Caller's may store context value for each node in the PackageExtractJob
    //  hierarchy, useful only to the caller.  This value is preserved across
    //  Save/DpxRestoreJob.
    //

    HRESULT SetUserValue( [in]  UINT64   UserValue );
    HRESULT GetUserValue( [out] UINT64* pUserValue );

    //
    //  Caller may provide named options with string values that may be
    //  referenced later by container manifests and otherwise affect job
    //  processing.  OptionName is case insensitive, OptionValue case is
    //  preserved.  Setting NULL or empty OptionValue is acceptable and
    //  GetOptionValue will return S_OK with NULL pOptionValue for these.
    //  GetOptionValue will fail if the named value does not exist.
    //

    HRESULT SetOptionValue( [in] LPCWSTR OptionName, [in, unique] LPCWSTR OptionValue );
    HRESULT GetOptionValue( [in] LPCWSTR OptionName, [out] LPWSTR* pOptionValue );

    //
    //  Memory allocated as return parameters from methods on this interface
    //  should be freed by the caller using this interface-specific local
    //  FreeMemory method before Release of the allocating object.
    //

    [local] void FreeMemory( [in] void* Allocation );

}


[ uuid( ddc1b712-0e55-452f-838e-d1505b866e2b ), object, pointer_default(unique) ]
interface IDpxContainer : IUnknown
{
    //
    //  IDpxContainer exposes a ContainerPath property which is interpreted
    //  only by download provider of parent extract job.  Usually this is URL
    //  or local/UNC filename, but is interpreted only by the specified
    //  download provider.  It can be simply a filename without a path if
    //  the download provider knows how to translate that to full path for the
    //  actual download.  The ContainerPath must be unique for each container
    //  within a job.
    //

    HRESULT SetContainerPath( [in]  LPCWSTR  ContainerPath );
    HRESULT GetContainerPath( [out] LPWSTR* pContainerPath );   // FreeMemory

    //
    //  Caller adds specific files to the extract job prior to "starting" the
    //  extract job.  Caller may specify additional files to extract after a
    //  job has been started, and also after a job has completed.  See the
    //  IDpxFile interface for more information on specifying files.
    //  Caller can first call EnumDirectoryEntries and then add some
    //  or all of the files to the job or use ExtractAllFiles for "wildcard"
    //  extraction.  Additional files can be added to the job at
    //  any time, even after job has been completed.  After files are added, caller
    //  must perform Resume again.  AddFileToExtract with same SourceFileName and
    //  TargetFileName as an already existing file object will return interface
    //  pointer to the existing file object.  AddFileToExtract with same
    //  TargetFileName (explicit or implied) as an already existing file object
    //  with a different SourceFileName will fail with E_BUGBUG.
    //

    HRESULT AddFileToExtract(
                [in]         LPCWSTR   SourceFileName,  // within container
                [in, unique] LPCWSTR   TargetFileName,  // if different
                [in, unique] DPX_HASH* TargetFileHash   // if verify desired
                );

    HRESULT AddFileToExtract2(
                [in]         LPCWSTR SourceFileName,    // within container
                [in, unique] LPCWSTR TargetFileName,    // if different
                [out]        IDpxFile ** ppFile
                );

    //
    //  Alternative to specifying individual files to extract, may call
    //  ExtractAllFiles, which automatically AddFileToExtract every file
    //  in the container index, once the container index is provided or
    //  downloaded.
    //

    HRESULT ExtractAllFiles();

    //
    //  EnumFilesToExtract returns enumerator that can return each file
    //  added to this container for extraction.  If ExtractAllFiles is
    //  used, the files can only be enumerated after ProvideContainerIndex
    //  is called, or after the index is automatically downloaded.
    //

    HRESULT EnumFilesToExtract(
                [out] IEnumDpxFiles ** ppEnumFiles
                );

    //
    //  There are four security validation models for package extraction when
    //  downloading from an untrusted source or over an untrusted medium.
    //
    //    1) Provide complete trusted container index at start of job
    //    2) Provide trusted hash of container index to be downloaded
    //    3) Provide trusted hash of each individual file to be extracted
    //    4) No Validation
    //
    //  Some containers, such as raw .cab, do not contain individual file hashes
    //  inside the container index, so the caller must specify individual file
    //  hashes if the caller wants PackageExtractJob to perform the validation.
    //  Some containers, such as .psf, optionally provide individual file
    //  hashes inside the container index, so only a trusted hash of the
    //  container index is required to validate trust for each extracted file.
    //  Likewise, if caller provides .psf index through ProvideContainerIndex,
    //  and the index contains individual file hashes, the extracted files are
    //  validated to the same level of trust as the provided container index.
    //  Generally, a content authoring scheme should conform to one of these
    //  four models, three of which provide validation during the extract job,
    //  the other requring the caller to separately validate the files after
    //  extraction.  Based on the model, the client for that content should
    //  choose one of ProvideContainerIndex, SetExpectedContainerIndexHash,
    //  SetExpectedHash on each target file, or perform separate validation
    //  after the job is complete if validation is required.
    //

    HRESULT SetExpectedContainerIndexHash( [in]  DPX_HASH *   pExpectedHash );
    HRESULT GetExpectedContainerIndexHash( [out] DPX_HASH ** ppExpectedHash );  // FreeMemory

    HRESULT ProvideContainerIndex(
                [in] UINT IndexSize,
                [in, size_is( IndexSize )] BYTE IndexData[]
                );

    HRESULT ProvideContainerIndexByFile(
                [in] LPCWSTR IndexFileName  // can open with CreateFileW
                );

    //
    //  EnumDirectoryEntries is used if caller needs to query the contents
    //  of a container, usually to determine the set of filenames to specify
    //  for extraction.  If the set of filenames to extract is known, then
    //  EnumDirectoryEntries is not necessary.  If EnumDirectoryEntries is
    //  called before the container index has been downloaded or provided, it
    //  will return E_NOTAVAILABLE.
    //

    HRESULT EnumDirectoryEntries(
                [out] IEnumDpxContainerDirectoryEntries ** ppEnumEntries
                );

    //
    //  Remove will remove a container and all its files from the parent
    //  extract job.  Any files for this container that have already been
    //  downloaded and validated will not be deleted from the TargetPath.
    //  Removing a container after job has started might result in larger
    //  download.  After calling Remove, caller must Release the object.
    //

    HRESULT Remove();

    //
    //  Caller's may store context value for each node in the PackageExtractJob
    //  hierarchy, useful only to the caller.  This value is preserved across
    //  Save/DpxRestoreJob.
    //

    HRESULT SetUserValue( [in]  UINT64   UserValue );
    HRESULT GetUserValue( [out] UINT64* pUserValue );

    //
    //  Memory allocated as return parameters from methods on this interface
    //  should be freed by the caller using this interface-specific local
    //  FreeMemory method before Release of the allocating object.
    //

    [local] void FreeMemory( [in] void* Allocation );

}


[ uuid( ddc1b713-0e55-452f-838e-d1505b866e2b ), object, pointer_default(unique) ]
interface IDpxFile : IUnknown
{
    //
    //  IDpxContainer::AddFileToExtract2 returns pointer to this interface.
    //  File objects have a SourceFileName and optional TargetFileName if
    //  different than the SourceFileName.  GetTargetFileName will return same
    //  value as GetSourceFileName if file object created with NULL
    //  TargetFileName.  File objects within a job are unique by TargetFileName
    //  in the job's TargetPath.  Multiple file objects may exist using same
    //  SourceFileName from same or different containers, allowing single
    //  source file to be extracted to multiple target files.  Attempt to add a
    //  file with same TargetFileName [explicit or implied] as an existing file
    //  with same SourceFileName will simply reference existing file object.
    //  Attempt to add a file with same TargetFileName as an existing file with
    //  different SourceFileName will fail.  TargetFileName can contain a
    //  relative path from the TargetPath but cannot contain "." or ".." path
    //  components. Subdirectories within the TargetPath will be created as
    //  necessary during extraction.
    //

    HRESULT GetSourceFileName( [out] LPWSTR * pSourceFileName );   // FreeMemory
    HRESULT GetTargetFileName( [out] LPWSTR * pTargetFileName );   // FreeMemory

    //
    //  SetExpectedHash can be used to validate trust for the extracted
    //  files, especially when the source is over a network or the internet.
    //  If an extracted file fails the hash check, it will be re-requested
    //  at least once before failing the job completely.
    //

    HRESULT SetExpectedHash( [in]  DPX_HASH *   pExpectedHash );
    HRESULT GetExpectedHash( [out] DPX_HASH ** ppExpectedHash );   // FreeMemory

    //
    //  Remove will remove a file from its parent extract job.  If the file
    //  has already been downloaded and validated, it will not be deleted
    //  from the TargetPath.  Removing a file after job has started might
    //  result in larger download.  After calling Remove, caller must Release
    //  the object.
    //

    HRESULT Remove();

    //
    //  Caller's may store context value for each node in the PackageExtractJob
    //  hierarchy, useful only to the caller.  This value is preserved across
    //  Save/DpxRestoreJob.
    //

    HRESULT SetUserValue( [in]  UINT64   UserValue );
    HRESULT GetUserValue( [out] UINT64* pUserValue );

    //
    // Gives caller HRESULT status for individual file.
    // Note that HRESULT status is given via output parameter, not via function return value.
    // pStatus will equal one of the following after return:
    // S_OK (file created in target path)
    // E_ABORT (when Remove() is called)
    // E_PENDING (file not removed or created in target path)
    //

    HRESULT GetStatus( [out] HRESULT *pStatus );

    //
    //  Memory allocated as return parameters from methods on this interface
    //  should be freed by the caller using this interface-specific local
    //  FreeMemory method before Release of the allocating object.
    //

    [local] void FreeMemory( [in] void* Allocation );

}


[ uuid( ddc1b715-0e55-452f-838e-d1505b866e2b ), object, pointer_default( unique ) ]
interface IDpxContainerDirectoryEntry : IUnknown
{
    HRESULT GetName( [out] LPWSTR *pDirEntryName );      // FreeMemory

    HRESULT GetHash( [out] DPX_HASH **pDirEntryHash );   // FreeMemory

    HRESULT GetSize( [out] UINT64 *pDirEntrySize );

    HRESULT GetTime( [out] FILETIME *pDirEntryTime );

    [local] void FreeMemory( [in] void* Allocation );
}


[ uuid( ddc1b716-0e55-452f-838e-d1505b866e2b ), object, pointer_default( unique ) ]
interface IDpxDownloadProvider : IUnknown
{
    HRESULT SetProvideDataCallback( [in]  IDpxDownloadCallback*   pProvideData );
    HRESULT GetProvideDataCallback( [out] IDpxDownloadCallback** ppProvideData );

    //
    //  Adding container with no ranges implies entire source file.
    //

    HRESULT AddContainer(
                [in] LPCWSTR ContainerFilePath,
                [in] UINT64  ContainerId
                );

    HRESULT AddRanges(
                [in] UINT64 ContainerId,
                [in] UINT   RangeCount,
                [in, size_is( RangeCount )] DPX_BYTE_RANGE RangeList[]
                );

    HRESULT GetContainers(
                [out] UINT* ContainerCount,
                [out, size_is( , *ContainerCount )] UINT64** ppContainerIdArray // FreeMemory
                );

    HRESULT GetContainerPath(
                [in]  UINT64  ContainerId,
                [out] LPWSTR* ContainerPath                                     // FreeMemory
                );

    HRESULT GetRanges(
                [in]  UINT64  ContainerId,
                [in]  BOOL    IncludeCompletedRanges,
                [out] UINT*   RangeCount,
                [out, size_is( , *RangeCount )] DPX_BYTE_RANGE ** ppRangeArray  // FreeMemory
                );

    HRESULT Resume();
    HRESULT Suspend();
    HRESULT Cancel();

    //
    //  After a job is started with Resume, caller may either poll for progress
    //  to determine completion, or call WaitForCompletion instead.
    //

    HRESULT WaitForCompletion( [in] DWORD TimeoutMilliseconds );

    //
    //  GetProgress can be used to poll download progress.
    //

    HRESULT GetProgress( [out] DPX_PROGRESS_REMAIN * pDownloadProgress );

    //
    //  ClearRequest removes all container files and their requested ranges
    //  from the download provider job.  It is used to re-initialize the
    //  download provider object for multiple download requests during lifetime
    //  of IDpxJob object.
    //

    HRESULT ClearRequest();

    [local] void FreeMemory( [in] void* Allocation );
}


[ uuid( ddc1b717-0e55-452f-838e-d1505b866e2b ), object, pointer_default( unique ) ]
interface IDpxDownloadCallback : IUnknown
{
    //
    //  There are several methods for providing the requested data.  The first
    //  is memory buffer based, the others are file based requiring a path/file
    //  name that can be opened with CreateFileW (shared read access).  The
    //  ProvideRequestedDataByFile method can take a whole container file such
    //  as a local .cab or .psf file, or a file containing individual ranges
    //  whose offsets in the provided file may differ than the original whole
    //  container file.  The OffsetInResponseFile array maps the parallel
    //  array of ranges in the provided file to the offsets in the original
    //  whole file.  The ProvideRequestedDataByPackedRangeFile is similar, but
    //  assumes that the provided file contains packed ranges corresponding
    //  exactly (number, order, and sizes) to the set of ranges requested by
    //  most recent call to Resume.  This facilitates download providers
    //  utilizing BITS which provides response file in this packed format.
    //

    HRESULT ProvideRequestedData(
                [in] UINT64   ContainerId,
                [in] UINT     RangeCount,
                [in, size_is( RangeCount )] DPX_BYTE_RANGE RangeList[],
                [in, size_is( RangeCount )] const BYTE* RangeData[]
                );

    HRESULT ProvideRequestedDataByFile(
                [in] UINT64   ContainerId,
                [in] LPCWSTR  ResponseFilePath,  // can open with CreateFileW
                [in] UINT     RangeCount,
                [in, size_is( RangeCount )] DPX_BYTE_RANGE RangeArray[],
                [in, size_is( RangeCount )] UINT64 OffsetInResponseFile[]
                );

    HRESULT ProvideRequestedDataByPackedRangeFile(
                [in] UINT64   ContainerId,
                [in] LPCWSTR  ResponseFilePath   // can open with CreateFileW
                );

}


[ uuid( ddc1b722-0e55-452f-838e-d1505b866e2b ), object, pointer_default( unique ) ]
interface IEnumDpxContainers : IUnknown
{
    HRESULT Next(
                [in] UINT ItemCount,
                [out, size_is( ItemCount ), length_is( *pFetchedCount )] IDpxContainer **ppContainers,
                [out] UINT * pFetchedCount
                );

    HRESULT Skip( [in] UINT ItemCount );

    HRESULT Reset();

    HRESULT Clone( [out] IEnumDpxContainers **ppEnum );

    HRESULT GetCount( [out] UINT * pItemCount );
}


[ uuid( ddc1b723-0e55-452f-838e-d1505b866e2b ), object, pointer_default( unique ) ]
interface IEnumDpxFiles : IUnknown
{
    HRESULT Next(
                [in] UINT ItemCount,
                [out, size_is( ItemCount ), length_is( *pFetchedCount )] IDpxFile **ppFiles,
                [out] UINT * pFetchedCount
                );

    HRESULT Skip( [in] UINT ItemCount );

    HRESULT Reset();

    HRESULT Clone( [out] IEnumDpxFiles **ppEnum );

    HRESULT GetCount( [out] UINT * pItemCount );
}


[ uuid( ddc1b725-0e55-452f-838e-d1505b866e2b ), object, pointer_default( unique ) ]
interface IEnumDpxContainerDirectoryEntries : IUnknown
{
    HRESULT Next(
                [in] UINT ItemCount,
                [out, size_is( ItemCount ), length_is( *pFetchedCount )] IDpxContainerDirectoryEntry **ppDirectoryEntries,
                [out] UINT * pFetchedCount
                );

    HRESULT Skip( [in] UINT ItemCount );

    HRESULT Reset();

    HRESULT Clone( [out] IEnumDpxContainerDirectoryEntries **ppEnum );

    HRESULT GetCount( [out] UINT * pItemCount );
}






