You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
277 lines
6.5 KiB
277 lines
6.5 KiB
/*
|
|
* R G I T E R . H
|
|
*
|
|
* Range iterator
|
|
*/
|
|
|
|
#ifndef _EX_RGITER_H_
|
|
#define _EX_RGITER_H_
|
|
|
|
#pragma warning(disable:4200) // zero-sized array
|
|
|
|
// Ranges --------------------------------------------------------------------
|
|
//
|
|
enum {
|
|
|
|
RANGE_TOTAL_UNKNOWN = 0xFFFFFFFF,
|
|
RANGE_NOT_PRESENT = 0xFFFFFFFF,
|
|
RANGE_UNKNOWN = 0,
|
|
RANGE_ROW,
|
|
RANGE_URL,
|
|
RANGE_FIND
|
|
};
|
|
|
|
// Range Items ---------------------------------------------------------------
|
|
//
|
|
// There are two different range item formats.
|
|
//
|
|
// row/byte ranges = DWRGITEM;
|
|
// url/find ranges = SZRGITEM;
|
|
//
|
|
typedef struct _dwrgitem
|
|
{
|
|
DWORD dwFirst; // first row/byte of a range
|
|
DWORD dwLast; // last row/byte of a range
|
|
|
|
} DWRGITEM;
|
|
|
|
typedef struct _szrgitem
|
|
{
|
|
LONG lcRows; // count of rows to return
|
|
DWORD cb; // length, in bytes of item including NULL and padding
|
|
WCHAR wsz[]; // item padded out to align as needed
|
|
|
|
} SZRGITEM;
|
|
|
|
typedef struct _rgitem
|
|
{
|
|
DWORD uRT; // range type
|
|
SCODE sc;
|
|
|
|
union {
|
|
|
|
DWRGITEM dwrgi; // item for byte and row ranges
|
|
SZRGITEM szrgi; // item for url and find ranges
|
|
};
|
|
|
|
} RGITEM, *PRGITEM;
|
|
|
|
inline
|
|
DWORD CbRangeItem (const RGITEM * prgi)
|
|
{
|
|
Assert (prgi);
|
|
DWORD cb = sizeof(RGITEM);
|
|
if ((RANGE_URL == prgi->uRT) || (RANGE_FIND == prgi->uRT))
|
|
cb += prgi->szrgi.cb;
|
|
|
|
return cb;
|
|
}
|
|
|
|
// Range Classes -------------------------------------------------------------
|
|
//
|
|
// There are two classes for dealing with ranges. A class that constructs the
|
|
// range item array (a range parser), and a class that iterates over a range
|
|
// array.
|
|
//
|
|
// It is important to note that the CRangeParser only is used to parse the HTTP
|
|
// "Range" header. This header does not support the syntax of url and/or find
|
|
// ranges, so the parser only builds items of type "bytes" and/or "rows".
|
|
//
|
|
// Since both of these share the same format (DWRGITEM), and it is a fixed size,
|
|
// there are some simplifying assumptions that can be made without adding too
|
|
// much complexity to the parser.
|
|
//
|
|
// Both parser and iterator share a common base...
|
|
//
|
|
class CRangeBase
|
|
{
|
|
protected:
|
|
|
|
// Count of ranges parsed out.
|
|
//
|
|
DWORD m_cRGList;
|
|
|
|
// Index of the range that is currently being parsed and/or processed
|
|
//
|
|
DWORD m_iCur;
|
|
RGITEM * m_prgi;
|
|
|
|
// An array of ranges of size m_cRCList. As noted above, this array is
|
|
// built up from items that were parsed from the HTTP header, and can
|
|
// then be assumed to be a fixed size based on the count of ranges. This
|
|
// is an important aspect of the CRangeParser.
|
|
//
|
|
auto_heap_ptr<BYTE> m_pbData;
|
|
DWORD m_cbSize;
|
|
|
|
// Collapsing unknown ranges
|
|
//
|
|
void CollapseUnknown();
|
|
|
|
// NOT IMPLEMENTED
|
|
//
|
|
CRangeBase& operator=( const CRangeBase& );
|
|
CRangeBase( const CRangeBase& );
|
|
|
|
public:
|
|
|
|
~CRangeBase();
|
|
CRangeBase()
|
|
: m_cRGList(0),
|
|
m_cbSize(0),
|
|
m_iCur(0),
|
|
m_prgi(0)
|
|
|
|
{
|
|
}
|
|
|
|
// Range fixup. There are some cases where ranges need to be fixed up
|
|
// to match the actual amount of bytes/rows available. Note that this
|
|
// only impacts byte and/or row ranges.
|
|
//
|
|
SCODE ScFixupRanges (DWORD dwCount);
|
|
|
|
// Advances through the rangGet the next range.
|
|
//
|
|
const RGITEM * PrgiNextRange();
|
|
|
|
// Rewind to the first range.
|
|
//
|
|
void Rewind()
|
|
{
|
|
m_iCur = 0;
|
|
m_prgi = NULL;
|
|
}
|
|
|
|
// Check for more ranges
|
|
//
|
|
BOOL FMoreRanges () const { return m_iCur < m_cRGList; }
|
|
|
|
// Check if a range present or not
|
|
//
|
|
BOOL FRangePresent (DWORD dw) const { return RANGE_NOT_PRESENT != dw; }
|
|
|
|
// Gets the total number of ranges.
|
|
//
|
|
ULONG UlTotalRanges() const { return m_cRGList; }
|
|
|
|
// Return the range array, with count and size.
|
|
//
|
|
RGITEM * PrgRangeArray(
|
|
/* [out] */ ULONG * pulCount,
|
|
/* [out] */ ULONG * pulSize,
|
|
/* [in] */ BOOL fTakeOwnership)
|
|
{
|
|
Assert (pulCount);
|
|
Assert (pulSize);
|
|
|
|
RGITEM * prgi = reinterpret_cast<RGITEM*>
|
|
(fTakeOwnership ? m_pbData.relinquish() : m_pbData.get());
|
|
|
|
*pulCount = m_cRGList;
|
|
*pulSize = m_cbSize;
|
|
return prgi;
|
|
}
|
|
};
|
|
|
|
class CRangeParser : public CRangeBase
|
|
{
|
|
private:
|
|
|
|
// NOT IMPLEMENTED
|
|
//
|
|
CRangeParser& operator=( const CRangeParser& );
|
|
CRangeParser( const CRangeParser& );
|
|
|
|
public:
|
|
|
|
CRangeParser() {}
|
|
~CRangeParser();
|
|
|
|
// Takes a range header and builds an array of ranges. Calls
|
|
// ScParseRangeHdr() to perform syntax checking, then validates
|
|
// the ranges against the entity size.
|
|
//
|
|
SCODE ScParseByteRangeHdr (LPCWSTR pwszRgHeader, DWORD dwSize);
|
|
|
|
// Take a range header and builds an array of ranges. Performs
|
|
// syntax checking.
|
|
//
|
|
SCODE ScParseRangeHdr (LPCWSTR pwszRgHeader, LPCWSTR pwszRangeUnit);
|
|
};
|
|
|
|
class CRangeIter : public CRangeBase
|
|
{
|
|
private:
|
|
|
|
// NOT IMPLEMENTED
|
|
//
|
|
CRangeIter& operator=( const CRangeIter& );
|
|
CRangeIter( const CRangeIter& );
|
|
|
|
public:
|
|
|
|
CRangeIter() {}
|
|
~CRangeIter();
|
|
|
|
// Initialize a range iteration object based off of an existing
|
|
// range data blob. In this case, the blob is copied and not consumed
|
|
// by the call.
|
|
//
|
|
SCODE ScInit (ULONG cRGList, const RGITEM * prgRGList, ULONG cbSize);
|
|
|
|
// Initialize a range iteration object based off of an existing
|
|
// range data blob. In this case, the blob is consumed by the new
|
|
// object.
|
|
//
|
|
SCODE ScInit (CRangeParser& crp)
|
|
{
|
|
RGITEM * prgi = crp.PrgRangeArray (&m_cRGList,
|
|
&m_cbSize,
|
|
TRUE /* fTakeOwnership */);
|
|
|
|
m_pbData = reinterpret_cast<BYTE*>(prgi);
|
|
|
|
// Rewind all the state.
|
|
//
|
|
Rewind();
|
|
|
|
return S_OK;
|
|
}
|
|
};
|
|
|
|
// Range Parsing -------------------------------------------------------------
|
|
//
|
|
SCODE
|
|
ScParseOneWideRange (
|
|
/* [in] */ LPCWSTR pwsz,
|
|
/* [out] */ DWORD * pdwStart,
|
|
/* [out] */ DWORD * pdwEnd);
|
|
|
|
// Range support -------------------------------------------------------------
|
|
//
|
|
// Helper function to tell whether a range is a special range (0,0xffffffff)
|
|
// which is used to represent the rows(bytes)=-n range on a zero sized response
|
|
// body.
|
|
//
|
|
inline
|
|
BOOL FSpecialRangeForZeroSizedBody (RGITEM * prgItem)
|
|
{
|
|
Assert (prgItem);
|
|
|
|
return ((RANGE_ROW == prgItem->uRT)
|
|
&& (0 == prgItem->dwrgi.dwFirst)
|
|
&& (RANGE_NOT_PRESENT == prgItem->dwrgi.dwLast));
|
|
}
|
|
|
|
// Range emitting ------------------------------------------------------------
|
|
//
|
|
SCODE ScGenerateContentRange (
|
|
/* [in] */ LPCSTR pszRangeUnit,
|
|
/* [in] */ const RGITEM * prgRGList,
|
|
/* [in] */ ULONG cRanges,
|
|
/* [in] */ ULONG cbRanges,
|
|
/* [in] */ ULONG ulTotal,
|
|
/* [out] */ LPSTR *ppszContentRange);
|
|
|
|
#endif // _EX_RGITER_H_
|