The purpose of the `ChunkBuffer` code below is to designate a "chunk" from a given input file and to loop that chunk (if needed).

Its operation is similar to the following pseudocode, with the important difference that the real code uses a heap-allocated buffer for performance:

```c
chunk c;

chunk_init(&c, input_file, begin_offset, size_of_chunk);

while (/* still need to read bytes */)
{
    byte b = chunk_next_byte(&c); // may loop to `begin_offset`
}

```

The `ChunkBuffer` code is non-portable and meant for use in Windows programs, and was written in a style close to that of the Windows API.

My main goals regarding this code review:

1. Find coding mistakes (incorrect buffering, memory leaks, etc.)
2. Enhance the Windows API style of the code.

```c
// enable Unicode support within the Windows API
#define UNICODE
#define _UNICODE

// skip the inclusion of certain internal headers
#define WIN32_LEAN_AND_MEAN

#include <windows.h>

typedef struct
{
    BOOL            fError;             ///< ChunkBuffer's error flag.
    HANDLE          hHeap;              ///< Handle of the heap to allocate memory from.
    HANDLE          hFile;              ///< Handle of the file to be read.
    LPBYTE          lpbBuffer;          ///< Buffer of bytes read.
    LARGE_INTEGER   liOffset;           ///< User-specified start offset in the file where the chunk begins.
    LARGE_INTEGER   liLength;           ///< User-specified chunk size in bytes.
    SIZE_T          cbBufferSize;       ///< User-specified size for the internal byte buffer.
    SIZE_T          index;              ///< Index of the current byte.
    SIZE_T          cbAvailable;        ///< Bytes available in the internal byte buffer.
    LARGE_INTEGER   liRemaining;        ///< Bytes remaining in the chunk.
} CHUNKBUFFER, *PCHUNKBUFFER;

typedef const CHUNKBUFFER * PCCHUNKBUFFER;

void ChunkBuffer_Init(
    PCHUNKBUFFER pCB,
    HANDLE hHeap, HANDLE hFile,
    LARGE_INTEGER liOffset,
    LARGE_INTEGER liLength,
    SIZE_T cbBufferSize);

void ChunkBuffer_Free(PCHUNKBUFFER pCB);
BOOL ChunkBuffer_Error(PCCHUNKBUFFER pCB);
BYTE ChunkBuffer_NextByte(PCHUNKBUFFER pCB);

///
/// @brief Initializes a ChunkBuffer.
/// @param [out] pCB        ChunkBuffer to initialize.
/// @param hHeap            Handle of the heap to allocate memory from.
/// @param hFile            Handle of the file to read data from.
/// @param liOffset         User-specified start offset in the file where the chunk begins.
/// @param liLength         User-specified chunk size in bytes.
/// @param cbBufferSize     User-specified size for the internal byte buffer.
///
void ChunkBuffer_Init(
    PCHUNKBUFFER pCB,
    HANDLE hHeap,
    HANDLE hFile,
    LARGE_INTEGER liOffset,
    LARGE_INTEGER liLength,
    SIZE_T cbBufferSize)
{
    pCB->hHeap          = hHeap;
    pCB->hFile          = hFile;
    pCB->liOffset       = liOffset;
    pCB->liLength       = liLength;
    pCB->cbBufferSize   = cbBufferSize;
    pCB->fError         = FALSE;
    pCB->lpbBuffer      = NULL;
    pCB->index          = 0;
    pCB->cbAvailable    = 0;
    pCB->liRemaining    = liLength;
}

///
/// @brief Frees the resources allocated by a ChunkBuffer.
/// @note This function does not close the handle of the file
///  associated with the ChunkBuffer; this is on purpose.
/// @param [in,out] pCB     ChunkBuffer to deinitialize.
///
void ChunkBuffer_Free(PCHUNKBUFFER pCB)
{
    if (pCB->lpbBuffer != NULL)
        HeapFree(pCB->hHeap, 0, pCB->lpbBuffer);

    pCB->hHeap      = INVALID_HANDLE_VALUE;
    pCB->hFile      = INVALID_HANDLE_VALUE;
    pCB->lpbBuffer  = NULL;
}

///
/// @brief Returns the ChunkBuffer's error flag.
/// @param [in] pCB         ChunkBuffer to inspect.
/// @returns Whether or not the ChunkBuffer is in an error state.
/// @retval TRUE            An error occurred.
/// @retval FALSE           No errors occurred.
///
BOOL ChunkBuffer_Error(PCCHUNKBUFFER pCB)
{
    return pCB->fError;
}

///
/// @brief Retrieves the next byte in the ChunkBuffer.
/// @param [in,out] pCB     ChunkBuffer to read.
/// @returns The next byte.
///
BYTE ChunkBuffer_NextByte(PCHUNKBUFFER pCB)
{
#define SET_FERROR_IF(x)    if (x)  {   \
    pCB->fError = TRUE;                 \
    return 0;                           \
} else (void)0

    if (pCB->fError) // the ChunkBuffer is in an error state
        return 0;

    // allocate memory for the internal byte buffer, if needed;
    // and if so, then also read data from the file
    if (pCB->lpbBuffer == NULL)
    {
        const LPBYTE    lpbTemp     = HeapAlloc(pCB->hHeap, 0, pCB->cbBufferSize);
        const SIZE_T    cbMinChunk  = (SIZE_T)min((LONGLONG)pCB->cbBufferSize, pCB->liLength.QuadPart);

        SET_FERROR_IF(lpbTemp == NULL);
        pCB->lpbBuffer = lpbTemp;
        SET_FERROR_IF(!SetFilePointerEx(pCB->hFile, pCB->liOffset, NULL, FILE_BEGIN));
        SET_FERROR_IF(!ReadFile(pCB->hFile, pCB->lpbBuffer, cbMinChunk, &pCB->cbAvailable, NULL));
        pCB->liRemaining.QuadPart -= pCB->cbAvailable;
    }

    if (pCB->index == pCB->cbAvailable) // may need to read from the file again
    {
        // only read new data if the user-specified chunk length is greater than
        // that of the internal buffer; otherwise all data is already available
        if ((LONGLONG)pCB->cbBufferSize < pCB->liLength.QuadPart)
        {
            if (pCB->liRemaining.QuadPart == 0) // reached the end of the user-specified chunk
            {
                SET_FERROR_IF(!SetFilePointerEx(pCB->hFile, pCB->liOffset, NULL, FILE_BEGIN));
                pCB->liRemaining = pCB->liLength;
            }

            const SIZE_T cbMinSize = (SIZE_T)min((LONGLONG)pCB->cbBufferSize, pCB->liRemaining.QuadPart);

            SET_FERROR_IF(!ReadFile(pCB->hFile, pCB->lpbBuffer, cbMinSize, &pCB->cbAvailable, NULL));

            if (pCB->cbAvailable == 0) // end of key file was reached
            {
                SET_FERROR_IF(!SetFilePointerEx(pCB->hFile, pCB->liOffset, NULL, FILE_BEGIN));
                SET_FERROR_IF(!ReadFile(pCB->hFile, pCB->lpbBuffer, cbMinSize, &pCB->cbAvailable, NULL));
            }

            pCB->liRemaining.QuadPart -= pCB->cbAvailable;
        }

        pCB->index = 0;
    }

    return pCB->lpbBuffer[pCB->index++];
#undef SET_FERROR_IF
}

//
// Basic usage preparations
//

#if 0

    CHUNKBUFFER     cb;
    HANDLE          heap        = GetProcessHeap();
    HANDLE          input_file  = CreateFile(/* ... */);
    LARGE_INTEGER   begin;      // ...
    LARGE_INTEGER   size;       // ...

    #define BUFFER_SIZE     4096

    ChunkBuffer_Init(&cb, heap, input_file, begin, size, BUFFER_SIZE);
    BYTE b = ChunkBuffer_NextByte(&cb);
    ChunkBuffer_Free(&cb);

#endif

```