/*++ Copyright (c) 2001 Microsoft Corporation Module Name: chunkflt.hxx Abstract: Contains a filter for encoding and decoding chunked transfers. Contents: BaseFilter FILTER_LIST ChunkDecodeContext ChunkFilter Author: Oliver Wallace (oliverw) 13-Feb-2001 Revision History: 13-Feb-2001 oliverw Created --*/ // Base class meant for when additional filters will be available. class BaseFilter { public: virtual HRESULT Reset(DWORD_PTR dwContext) { return E_NOTIMPL; } virtual HRESULT Decode( IN DWORD_PTR dwContext, IN OUT LPBYTE pInBuffer, IN DWORD dwInBufSize, IN OUT LPBYTE *ppOutBuffer, IN OUT LPDWORD pdwOutBufSize, OUT LPDWORD pdwBytesRead, OUT LPDWORD pdwBytesWritten ) { return E_NOTIMPL; } virtual HRESULT Encode( DWORD_PTR dwContext, IN OUT LPBYTE pInBuffer, IN DWORD dwInBufSize, IN OUT LPBYTE *ppOutBuffer, IN OUT LPDWORD pdwOutBufSize, OUT LPDWORD pdwBytesRead, OUT LPDWORD pdwBytesWritten ) { return E_NOTIMPL; } virtual HRESULT RegisterContext(OUT DWORD_PTR *pdwContext) { return E_NOTIMPL; } virtual HRESULT UnregisterContext(IN DWORD_PTR dwContext) { return E_NOTIMPL; } virtual BOOL IsFinished(IN DWORD_PTR dwContext) { return FALSE; } }; typedef struct FILTER_LIST_ENTRY { DWORD_PTR dwContext; // Registered context associated with pFilter BaseFilter *pFilter; // Data Filter used to encode/decode dwContext FILTER_LIST_ENTRY *pNext; } FILTER_LIST_ENTRY, * LPFILTER_LIST_ENTRY; class FILTER_LIST { /*++ Class Description: The FILTER_LIST class defines the data filter list used to encode/decode data when sending/receiving data. Post v5, this will need some extensions: - Make this a priority list to accommodate mroe flexible encoding order. - Implement Encode method to process upload filters once support is added. - Add smartness to Encode/Decode methods to buffer data. --*/ public: FILTER_LIST() { _pFilterEntry = NULL; _uFilterCount = 0; } ~FILTER_LIST() { ClearList(); } // Always inserts as the beginning of the list BOOL Insert(IN BaseFilter *pFilter, IN DWORD_PTR dwContext); VOID ClearList(); DWORD Decode( IN OUT LPBYTE pInBuffer, IN DWORD dwInBufSize, IN OUT LPBYTE *ppOutBuffer, IN OUT LPDWORD pdwOutBufSize, OUT LPDWORD pdwBytesRead, OUT LPDWORD pdwBytesWritten ); // Right now, there should never be more than just the chunk filter. BOOL IsFinished() { if (_pFilterEntry) return _pFilterEntry->pFilter->IsFinished(_pFilterEntry->dwContext); else return FALSE; } private: LPFILTER_LIST_ENTRY _pFilterEntry; UINT _uFilterCount; }; // Chunk filter state table, data and object prototypes. // Various token flags to describe the current byte being parsed. // // NOTE: Make sure you update the global table in chunkflt.cxx // if this list is modified. typedef enum { CHUNK_TOKEN_DIGIT = 0, CHUNK_TOKEN_CR, CHUNK_TOKEN_LF, CHUNK_TOKEN_COLON, CHUNK_TOKEN_DATA, CHUNK_TOKEN_LAST = CHUNK_TOKEN_DATA } CHUNK_TOKEN_VALUE; // NOTE: Do NOT update this without updating the table in chunkflt.cxx // which maps tokens for the current state to the next state. typedef enum { CHUNK_DECODE_STATE_START = 0, CHUNK_DECODE_STATE_SIZE, CHUNK_DECODE_STATE_SIZE_CRLF, CHUNK_DECODE_STATE_EXT, CHUNK_DECODE_STATE_DATA, CHUNK_DECODE_STATE_DATA_CRLF, CHUNK_DECODE_STATE_FOOTER_NAME, CHUNK_DECODE_STATE_FOOTER_VALUE, CHUNK_DECODE_STATE_FINAL_CRLF, CHUNK_DECODE_STATE_ERROR, CHUNK_DECODE_STATE_FINISHED, CHUNK_DECODE_STATE_LAST = CHUNK_DECODE_STATE_FINISHED } CHUNK_DECODE_STATE, *LPCHUNK_DECODE_STATE; class ChunkDecodeContext { private: CHUNK_DECODE_STATE m_eDecodeState; DWORD m_dwParsedSize; friend class ChunkFilter; public: ChunkDecodeContext() { Reset(); } // TODO: Consider subclassing contexts because they share common // properties/methods that could be virtual (e.g. Get/SetState). CHUNK_DECODE_STATE GetState() { return m_eDecodeState; } VOID SetState(CHUNK_DECODE_STATE eNewState) { m_eDecodeState = eNewState; } VOID Reset() { m_eDecodeState = CHUNK_DECODE_STATE_START; m_dwParsedSize = 0; } }; class ChunkFilter : public BaseFilter { public: // TODO: Provide an init method that is chunked-specific // (e.g. set size for chunked uploads) HRESULT Reset(DWORD_PTR dwContext); HRESULT Decode( IN DWORD_PTR dwContext, IN OUT LPBYTE pInBuffer, IN DWORD dwInBufSize, IN OUT LPBYTE *ppOutBuffer, IN OUT LPDWORD pdwOutBufSize, OUT LPDWORD pdwBytesRead, OUT LPDWORD pdwBytesWritten ); HRESULT Encode( IN DWORD_PTR dwContext, IN OUT LPBYTE pInBuffer, IN DWORD dwInBufSize, OUT LPBYTE *ppOutBuffer, OUT LPDWORD pdwOutBufSize, OUT LPDWORD pdwBytesRead, OUT LPDWORD pdwBytesWritten ); HRESULT RegisterContext(OUT DWORD_PTR *pdwContext); HRESULT UnregisterContext(IN DWORD_PTR dwContext); BOOL IsFinished(IN DWORD_PTR dwContext) { if (dwContext) return ((reinterpret_cast(dwContext))->GetState() == CHUNK_DECODE_STATE_FINISHED ? TRUE : FALSE); else return FALSE; } };