1 // This is a part of the Active Template Library.
2 // Copyright (C) Microsoft Corporation
3 // All rights reserved.
5 // This source code is only intended as a supplement to the
6 // Active Template Library Reference and related
7 // electronic documentation provided with the library.
8 // See these sources for detailed information regarding the
9 // Active Template Library product.
11 #ifndef __ATLSTENCIL_H__
12 #define __ATLSTENCIL_H__
21 #ifdef ATL_DEBUG_STENCILS
22 #include <atlsrvres.h>
24 #ifndef ATL_STENCIL_MAX_ERROR_LEN
25 #define ATL_STENCIL_MAX_ERROR_LEN 256
27 #endif // ATL_DEBUG_STENCILS
33 #ifndef _ATL_NO_DEFAULT_LIBS
34 #pragma comment(lib, "shlwapi.lib")
35 #endif // !_ATL_NO_DEFAULT_LIBS
37 #pragma warning( push )
38 #pragma warning(disable: 4127) // conditional expression is constant
39 #pragma warning(disable: 4511) // copy constructor could not be generated
40 #pragma warning(disable: 4512) // assignment operator could not be generated
41 #pragma warning(disable: 4702) // assignment operator could not be generated
42 #pragma warning(disable: 4625) // copy constructor could not be generated because a base class copy constructor is inaccessible
43 #pragma warning(disable: 4626) // assignment operator could not be generated because a base class assignment operator is inaccessible
44 #pragma warning(disable: 4191) // unsafe conversion from 'functionptr1' to 'functionptr2'
47 #pragma pack(push,_ATL_PACKING)
51 // These tags are token tags for the standard tag replacer implementation
52 extern __declspec(selectany
) const DWORD STENCIL_TEXTTAG
= 0x00000000;
53 extern __declspec(selectany
) const DWORD STENCIL_REPLACEMENT
= 0x00000001;
54 extern __declspec(selectany
) const DWORD STENCIL_ITERATORSTART
= 0x00000002;
55 extern __declspec(selectany
) const DWORD STENCIL_ITERATOREND
= 0x00000003;
56 extern __declspec(selectany
) const DWORD STENCIL_CONDITIONALSTART
= 0x00000004;
57 extern __declspec(selectany
) const DWORD STENCIL_CONDITIONALELSE
= 0x00000005;
58 extern __declspec(selectany
) const DWORD STENCIL_CONDITIONALEND
= 0x00000006;
59 extern __declspec(selectany
) const DWORD STENCIL_STENCILINCLUDE
= 0x00000007;
60 extern __declspec(selectany
) const DWORD STENCIL_STATICINCLUDE
= 0x00000008;
61 extern __declspec(selectany
) const DWORD STENCIL_LOCALE
= 0x00000009;
62 extern __declspec(selectany
) const DWORD STENCIL_CODEPAGE
= 0x0000000a;
64 // The base for user defined token types
65 extern __declspec(selectany
) const DWORD STENCIL_USER_TOKEN_BASE
= 0x00001000;
67 // Symbols to use in error handling in the stencil processor
68 #define STENCIL_INVALIDINDEX 0xFFFFFFFF
69 #define STENCIL_INVALIDOFFSET 0xFFFFFFFF
72 #define STENCIL_SUCCESS HTTP_SUCCESS
73 #define STENCL_FAIL HTTP_FAIL
75 #define STENCIL_BASIC_MAP 0
76 #define STENCIL_ATTR_MAP 1
78 #ifndef ATL_MAX_METHOD_NAME_LEN
79 #define ATL_MAX_METHOD_NAME_LEN 64
82 #ifndef ATL_MAX_BLOCK_STACK
83 #define ATL_MAX_BLOCK_STACK 128
86 template <class TBase
, typename T
>
87 struct CTagReplacerMethodsEx
89 typedef HTTP_CODE (TBase::*REPLACE_FUNC
)();
90 typedef HTTP_CODE (TBase::*REPLACE_FUNC_EX
)(T
*);
91 typedef HTTP_CODE (TBase::*PARSE_FUNC
)(IAtlMemMgr
*, LPCSTR
, T
**);
92 typedef HTTP_CODE (TBase::*REPLACE_FUNC_EX_V
)(void *);
93 typedef HTTP_CODE (TBase::*PARSE_FUNC_V
)(IAtlMemMgr
*, LPCSTR
, void**);
95 static REPLACE_FUNC_EX_V
CheckRepl(REPLACE_FUNC p
) throw()
97 return (REPLACE_FUNC_EX_V
) p
;
100 static REPLACE_FUNC_EX_V
CheckReplEx(REPLACE_FUNC_EX p
) throw()
102 return (REPLACE_FUNC_EX_V
) p
;
105 static PARSE_FUNC_V
CheckParse(PARSE_FUNC p
) throw()
107 return (PARSE_FUNC_V
) p
;
111 template <class TBase
>
112 struct CTagReplacerMethods
116 HTTP_CODE (TBase::*pfnMethodEx
)(void *);
117 HTTP_CODE (TBase::*pfnMethod
)();
119 HTTP_CODE (TBase::*pfnParse
)(IAtlMemMgr
*pMemMgr
, LPCSTR
, void **);
122 #define REPLACEMENT_ENTRY_DEFAULT 0
123 #define REPLACEMENT_ENTRY_ARGS 1
125 template <class TBase
>
126 struct CTagReplacerMethodEntry
128 int nType
; // REPLACEMENT_ENTRY_*
130 CTagReplacerMethods
<TBase
> Methods
;
134 #define BEGIN_REPLACEMENT_METHOD_MAP(className)\
136 void GetReplacementMethodMap(const ATL::CTagReplacerMethodEntry<className> ** ppOut) const\
138 typedef className __className;\
139 static const ATL::CTagReplacerMethodEntry<className> methods[] = {
141 #define REPLACEMENT_METHOD_ENTRY(methodName, methodFunc)\
142 { 0, methodName, { ATL::CTagReplacerMethodsEx<__className, void>::CheckRepl(&__className::methodFunc), NULL } },
144 #define REPLACEMENT_METHOD_ENTRY_EX(methodName, methodFunc, paramType, parseFunc)\
145 { 1, methodName, { ATL::CTagReplacerMethodsEx<__className, paramType>::CheckReplEx(&__className::methodFunc), ATL::CTagReplacerMethodsEx<__className, paramType>::CheckParse(&__className::parseFunc) } },
147 #define REPLACEMENT_METHOD_ENTRY_EX_STR(methodName, methodFunc) \
148 { 1, methodName, { ATL::CTagReplacerMethodsEx<__className, char>::CheckReplEx(&__className::methodFunc), ATL::CTagReplacerMethodsEx<__className, char>::CheckParse(&__className::DefaultParseString) } },
150 #define END_REPLACEMENT_METHOD_MAP()\
151 { 0, NULL, NULL } };\
155 #define BEGIN_ATTR_REPLACEMENT_METHOD_MAP(className)\
157 void GetAttrReplacementMethodMap(const CTagReplacerMethodEntry<className> ** ppOut) const\
159 typedef className __className;\
160 static const ATL::CTagReplacerMethodEntry<className> methods[] = {
162 #define END_ATTR_REPLACEMENT_METHOD_MAP()\
163 { NULL, NULL, NULL } };\
168 class ITagReplacerImpl
: public ITagReplacer
171 IWriteStream
*m_pStream
;
174 typedef HTTP_CODE (T::*REPLACEMENT_METHOD
)();
175 typedef HTTP_CODE (T::*REPLACEMENT_METHOD_EX
)(void *pvParam
);
177 ITagReplacerImpl() throw()
182 IWriteStream
*SetStream(IWriteStream
*pStream
)
184 IWriteStream
*pRetStream
= m_pStream
;
189 // Looks up the replacement method offset. Optionally, it will
190 // look up the replacement method and object offset of an alternate
192 HTTP_CODE
FindReplacementOffset(
194 DWORD
*pdwMethodOffset
,
195 LPCSTR szHandlerName
,
196 DWORD
*pdwHandlerOffset
,
197 DWORD
*pdwMap
, void **ppvParam
, IAtlMemMgr
*pMemMgr
)
199 ATLENSURE(szMethodName
!= NULL
);
200 ATLENSURE(pdwMethodOffset
!= NULL
);
201 ATLENSURE((szHandlerName
== NULL
&& pdwHandlerOffset
== NULL
) ||
202 (szHandlerName
!= NULL
&& pdwHandlerOffset
!= NULL
));
203 ATLENSURE(pdwMap
!= NULL
);
204 ATLENSURE(ppvParam
!= NULL
);
205 ATLENSURE(pMemMgr
!= NULL
);
207 // we at least have to be looking up a method offset
208 if (!pdwMethodOffset
|| !szMethodName
)
209 return AtlsHttpError(500, ISE_SUBERR_UNEXPECTED
);
211 *pdwMethodOffset
= STENCIL_INVALIDOFFSET
;
212 HTTP_CODE hcErr
= HTTP_FAIL
;
213 T
*pT
= static_cast<T
*>(this);
215 char szName
[ATL_MAX_METHOD_NAME_LEN
+1];
217 // if a handler name was supplied, we will try to
218 // find a different object to handle the method
219 if (szHandlerName
&& *szHandlerName
)
221 if (!pdwHandlerOffset
)
222 return AtlsHttpError(500, ISE_SUBERR_UNEXPECTED
);
224 hcErr
= pT
->GetHandlerOffset(szHandlerName
, pdwHandlerOffset
);
225 // got the alternate handler, now look up the method offset on
229 CComPtr
<ITagReplacer
> spAltTagReplacer
;
230 hcErr
= pT
->GetReplacementObject(*pdwHandlerOffset
, &spAltTagReplacer
);
232 hcErr
= spAltTagReplacer
->FindReplacementOffset(szMethodName
, pdwMethodOffset
,
233 NULL
, NULL
, pdwMap
, ppvParam
, pMemMgr
);
240 if (!SafeStringCopy(szName
, szMethodName
))
242 return AtlsHttpError(500, ISE_SUBERR_LONGMETHODNAME
);
246 char *szLeftPar
= strchr(szName
, '(');
252 char *szRightPar
= strchr(szLeftPar
, ')');
254 return AtlsHttpError(500, ISE_SUBERR_UNEXPECTED
);
258 szMethodName
= szName
;
262 // No handler name is specified, so we look up the method name in
263 // T's replacement method map
264 const CTagReplacerMethodEntry
<T
> *pEntry
= NULL
;
265 pT
->GetReplacementMethodMap(&pEntry
);
267 hcErr
= FindReplacementOffsetInMap(szMethodName
, pdwMethodOffset
, pEntry
);
268 if (hcErr
!= HTTP_SUCCESS
)
270 pT
->GetAttrReplacementMethodMap(&pEntry
);
271 hcErr
= FindReplacementOffsetInMap(szMethodName
, pdwMethodOffset
, pEntry
);
272 if (hcErr
== HTTP_SUCCESS
)
273 *pdwMap
= STENCIL_ATTR_MAP
;
277 *pdwMap
= STENCIL_BASIC_MAP
;
280 // This assert will be triggered if arguments are passed to a replacement method that doesn't handle them
281 ATLASSERT( szLeftPar
== NULL
|| (szLeftPar
!= NULL
&& (pEntry
!= NULL
&& pEntry
[*pdwMethodOffset
].Methods
.pfnParse
!= NULL
)) );
283 if (hcErr
== HTTP_SUCCESS
&& pEntry
&& pEntry
[*pdwMethodOffset
].Methods
.pfnParse
)
284 hcErr
= (pT
->*pEntry
[*pdwMethodOffset
].Methods
.pfnParse
)(pMemMgr
, szLeftPar
, ppvParam
);
288 HTTP_CODE
FindReplacementOffsetInMap(
290 LPDWORD pdwMethodOffset
,
291 const CTagReplacerMethodEntry
<T
> *pEntry
) throw()
296 const CTagReplacerMethodEntry
<T
> *pEntryHead
= pEntry
;
298 while (pEntry
->szMethodName
)
300 if (strcmp(pEntry
->szMethodName
, szMethodName
) == 0)
302 if (pEntry
->Methods
.pfnMethod
)
304 *pdwMethodOffset
= (DWORD
)(pEntry
-pEntryHead
);
315 // Used to render a single replacement tag into a stream.
316 // Looks up a pointer to a member function in user code by offseting into the users
317 // replacement map. Much faster than the other overload of this function since
318 // no string compares are performed.
319 HTTP_CODE
RenderReplacement(DWORD dwFnOffset
, DWORD dwObjOffset
, DWORD dwMap
, void *pvParam
)
321 HTTP_CODE hcErr
= HTTP_FAIL
;
322 T
*pT
= static_cast<T
*>(this);
324 // if we were not passed an object offset, then we assume
325 // that the function at dwFnOffset is in T's replacement
327 if (dwObjOffset
== STENCIL_INVALIDOFFSET
)
329 // call a function in T's replacement map
330 ATLASSERT(dwFnOffset
!= STENCIL_INVALIDOFFSET
);
331 const CTagReplacerMethodEntry
<T
> *pEntry
= NULL
;
332 if (dwMap
== STENCIL_BASIC_MAP
)
333 pT
->GetReplacementMethodMap(&pEntry
);
335 pT
->GetAttrReplacementMethodMap(&pEntry
);
338 if (pEntry
[dwFnOffset
].nType
== REPLACEMENT_ENTRY_DEFAULT
)
340 REPLACEMENT_METHOD pfn
= NULL
;
341 pfn
= pEntry
[dwFnOffset
].Methods
.pfnMethod
;
345 hcErr
= (pT
->*pfn
)();
348 else if (pEntry
[dwFnOffset
].nType
== REPLACEMENT_ENTRY_ARGS
)
350 REPLACEMENT_METHOD_EX pfn
= NULL
;
351 pfn
= pEntry
[dwFnOffset
].Methods
.pfnMethodEx
;
355 hcErr
= (pT
->*pfn
)(pvParam
);
360 // unknown entry type
367 // otherwise, we were passed an object offset. The object
368 // offset is a dword ID that T can use to look up the
369 // ITagReplacer* of a tag replacer that will render this
371 CComPtr
<ITagReplacer
> spAltReplacer
= NULL
;
372 if (!pT
->GetReplacementObject(dwObjOffset
, &spAltReplacer
))
374 spAltReplacer
->SetStream(m_pStream
);
375 hcErr
= spAltReplacer
->RenderReplacement(dwFnOffset
, STENCIL_INVALIDOFFSET
, dwMap
, pvParam
);
381 // Default GetHandlerOffset, does nothing
382 HTTP_CODE
GetHandlerOffset(LPCSTR
/*szHandlerName*/, DWORD
* pdwOffset
)
389 // Default GetReplacementObject, does nothing
390 HTTP_CODE
GetReplacementObject(DWORD
/*dwObjOffset*/, ITagReplacer
**ppReplacer
)
397 void GetReplacementMethodMap(const CTagReplacerMethodEntry
<T
> ** ppOut
) const
399 static const CTagReplacerMethodEntry
<T
> methods
[] = { { NULL
, NULL
} };
403 void GetAttrReplacementMethodMap(const CTagReplacerMethodEntry
<T
> **ppOut
) const
405 static const CTagReplacerMethodEntry
<T
> methods
[] = { { NULL
, NULL
} };
409 HRESULT
GetContext(REFIID
, void**)
411 return E_NOINTERFACE
;
414 virtual HINSTANCE
GetResourceInstance()
416 return GetModuleHandle(NULL
);
419 HTTP_CODE
DefaultParseString(IAtlMemMgr
*pMemMgr
, LPCSTR szParams
, char **ppParam
) throw(...)
421 ATLENSURE( pMemMgr
!= NULL
);
422 ATLENSURE( szParams
!= NULL
);
423 ATLENSURE( ppParam
!= NULL
);
425 size_t nLen
= strlen(szParams
);
429 *ppParam
= (char *) pMemMgr
->Allocate(nLen
);
431 Checked::memcpy_s(*ppParam
, nLen
, szParams
, nLen
);
433 return AtlsHttpError(500, ISE_SUBERR_OUTOFMEM
);
439 HTTP_CODE
DefaultParseUChar(IAtlMemMgr
*pMemMgr
, LPCSTR szParams
, unsigned char **ppParam
) throw(...)
441 ATLENSURE( pMemMgr
!= NULL
);
442 ATLENSURE( szParams
!= NULL
);
443 ATLENSURE( ppParam
!= NULL
);
445 *ppParam
= (unsigned char *) pMemMgr
->Allocate(sizeof(unsigned char));
449 **ppParam
= (unsigned char) strtoul(szParams
, &szEnd
, 10);
453 return AtlsHttpError(500, ISE_SUBERR_OUTOFMEM
);
458 HTTP_CODE
DefaultParseShort(IAtlMemMgr
*pMemMgr
, LPCSTR szParams
, short **ppParam
) throw(...)
460 ATLENSURE( pMemMgr
!= NULL
);
461 ATLENSURE( szParams
!= NULL
);
462 ATLENSURE( ppParam
!= NULL
);
464 *ppParam
= (short *) pMemMgr
->Allocate(sizeof(short));
467 **ppParam
= (short)atoi(szParams
);
471 return AtlsHttpError(500, ISE_SUBERR_OUTOFMEM
);
476 HTTP_CODE
DefaultParseUShort(IAtlMemMgr
*pMemMgr
, LPCSTR szParams
, unsigned short **ppParam
) throw(...)
478 ATLENSURE( pMemMgr
!= NULL
);
479 ATLENSURE( szParams
!= NULL
);
480 ATLENSURE( ppParam
!= NULL
);
482 *ppParam
= (unsigned short *) pMemMgr
->Allocate(sizeof(short));
486 **ppParam
= (unsigned short) strtoul(szParams
, &szEnd
, 10);
490 return AtlsHttpError(500, ISE_SUBERR_OUTOFMEM
);
495 HTTP_CODE
DefaultParseInt(IAtlMemMgr
*pMemMgr
, LPCSTR szParams
, int **ppParam
) throw(...)
497 ATLENSURE( pMemMgr
!= NULL
);
498 ATLENSURE( szParams
!= NULL
);
499 ATLENSURE( ppParam
!= NULL
);
501 *ppParam
= (int *) pMemMgr
->Allocate(sizeof(int));
504 **ppParam
= atoi(szParams
);
508 return AtlsHttpError(500, ISE_SUBERR_OUTOFMEM
);
513 HTTP_CODE
DefaultParseUInt(IAtlMemMgr
*pMemMgr
, LPCSTR szParams
, unsigned int **ppParam
) throw(...)
515 ATLENSURE( pMemMgr
!= NULL
);
516 ATLENSURE( szParams
!= NULL
);
517 ATLENSURE( ppParam
!= NULL
);
519 *ppParam
= (unsigned int *) pMemMgr
->Allocate(sizeof(unsigned int));
523 **ppParam
= strtoul(szParams
, &szEnd
, 10);
527 return AtlsHttpError(500, ISE_SUBERR_OUTOFMEM
);
532 HTTP_CODE
DefaultParseInt64(IAtlMemMgr
*pMemMgr
, LPCSTR szParams
, __int64
**ppParam
) throw(...)
534 ATLENSURE( pMemMgr
!= NULL
);
535 ATLENSURE( szParams
!= NULL
);
536 ATLENSURE( ppParam
!= NULL
);
538 *ppParam
= (__int64
*) pMemMgr
->Allocate(sizeof(__int64
));
541 **ppParam
= _atoi64(szParams
);
545 return AtlsHttpError(500, ISE_SUBERR_OUTOFMEM
);
550 HTTP_CODE
DefaultParseUInt64(IAtlMemMgr
*pMemMgr
, LPCSTR szParams
, unsigned __int64
**ppParam
) throw(...)
552 ATLENSURE( pMemMgr
!= NULL
);
553 ATLENSURE( szParams
!= NULL
);
554 ATLENSURE( ppParam
!= NULL
);
556 *ppParam
= (unsigned __int64
*) pMemMgr
->Allocate(sizeof(unsigned __int64
));
560 **ppParam
= _strtoui64(szParams
, &szEnd
, 10);
564 return AtlsHttpError(500, ISE_SUBERR_OUTOFMEM
);
569 HTTP_CODE
DefaultParseBool(IAtlMemMgr
*pMemMgr
, LPCSTR szParams
, bool **ppParam
) throw(...)
571 ATLENSURE( pMemMgr
!= NULL
);
572 ATLENSURE( szParams
!= NULL
);
573 ATLENSURE( ppParam
!= NULL
);
575 *ppParam
= (bool *) pMemMgr
->Allocate(sizeof(bool));
578 if (!_strnicmp(szParams
, "true", sizeof("true")-sizeof('\0')))
585 return AtlsHttpError(500, ISE_SUBERR_OUTOFMEM
);
591 HTTP_CODE
DefaultParseDouble(IAtlMemMgr
*pMemMgr
, LPCSTR szParams
, double **ppParam
) throw(...)
593 ATLENSURE( pMemMgr
!= NULL
);
594 ATLENSURE( szParams
!= NULL
);
595 ATLENSURE( ppParam
!= NULL
);
597 *ppParam
= (double *) pMemMgr
->Allocate(sizeof(double));
600 **ppParam
= atof(szParams
);
604 return AtlsHttpError(500, ISE_SUBERR_OUTOFMEM
);
609 HTTP_CODE
DefaultParseFloat(IAtlMemMgr
*pMemMgr
, LPCSTR szParams
, float **ppParam
) throw(...)
611 ATLENSURE( pMemMgr
!= NULL
);
612 ATLENSURE( szParams
!= NULL
);
613 ATLENSURE( ppParam
!= NULL
);
615 errno_t errnoValue
= 0;
616 *ppParam
= (float *) pMemMgr
->Allocate(sizeof(float));
619 errno_t saveErrno
= Checked::get_errno();
620 Checked::set_errno(0);
621 **ppParam
= (float) atof(szParams
);
622 errnoValue
= Checked::get_errno();
623 Checked::set_errno(saveErrno
);
627 return AtlsHttpError(500, ISE_SUBERR_OUTOFMEM
);
629 if ((**ppParam
== -HUGE_VAL
) || (**ppParam
== HUGE_VAL
) || (errnoValue
== ERANGE
))
637 inline LPCSTR
SkipSpace(LPCSTR sz
, WORD nCodePage
) throw()
642 while (isspace(static_cast<unsigned char>(*sz
)))
643 sz
= CharNextExA(nCodePage
, sz
, 0);
647 inline LPCSTR
RSkipSpace(LPCSTR pStart
, LPCSTR sz
, WORD nCodePage
) throw()
649 if (sz
== NULL
|| pStart
== NULL
)
652 while (isspace(static_cast<unsigned char>(*sz
)) && sz
!= pStart
)
653 sz
= CharPrevExA(nCodePage
, pStart
, sz
, 0);
659 // The stencil class will create an array of these tokens during the parse
660 // phase and use them during rendering to render the stencil
663 LPCSTR pStart
; // Start of fragment to be rendered
664 LPCSTR pEnd
; // End of fragment to be rendered
665 DWORD type
; // Type of token
666 DWORD dwFnOffset
; // Offset into the replacement map for the handler function.
668 DWORD dwObjOffset
; // An identifier for the caller to use in identifiying the
669 // object that will render this token.
670 CHAR szHandlerName
[ATL_MAX_HANDLER_NAME_LEN
+ 1]; // Name of handler object.
671 CHAR szMethodName
[ATL_MAX_METHOD_NAME_LEN
+ 1]; // Name of handler method.
672 DWORD dwLoopIndex
; // Offset into array of StencilTokens of the other loop tag
680 // The CStencil class is used to map in a stencil from a file or resource
681 // and parse the stencil into an array of StencilTokens. We then render
682 // the stencil from the array of tokens. This class's parse and render
683 // functions depend on an IReplacementHandlerLookup interface pointer to be
684 // passed so it can retrieve the IReplacementHandler interface pointer of the
685 // handler object that will be called to render replacement tags
687 public IMemoryCacheClient
690 LPCSTR m_pBufferStart
; // Beginning of CHAR buffer that holds the stencil.
691 // For mapped files this is the beginning of the mapping.
692 LPCSTR m_pBufferEnd
; // End of CHAR buffer that holds the stencil.
693 CAtlArray
<StencilToken
> m_arrTokens
; //An array of tokens.
694 FILETIME m_ftLastModified
; // Last modified time (0 for resource)
695 FILETIME m_ftLastChecked
; // Last time we retrieved last modified time (0 for resource)
696 HCACHEITEM m_hCacheItem
;
698 BOOL m_bUseLocaleACP
;
699 char m_szDllPath
[MAX_PATH
];
700 char m_szHandlerName
[ATL_MAX_HANDLER_NAME_LEN
+1]; // Room for the path, the handler
701 // the '/' and the '\0'
702 #ifdef ATL_DEBUG_STENCILS
705 char m_szError
[ATL_STENCIL_MAX_ERROR_LEN
];
707 LPCSTR m_szStartLine
;
711 bool operator==(const ParseError
& that
) const throw()
713 return (m_nLineNumber
== that
.m_nLineNumber
);
717 CSimpleArray
<ParseError
> m_Errors
;
718 HINSTANCE m_hResInst
;
720 class CParseErrorProvider
: public ITagReplacerImpl
<CParseErrorProvider
>,
721 public CComObjectRootEx
<CComSingleThreadModel
>
724 BEGIN_COM_MAP(CParseErrorProvider
)
725 COM_INTERFACE_ENTRY(ITagReplacer
)
727 CSimpleArray
<ParseError
> *m_pErrors
;
730 CParseErrorProvider() throw() :
736 void Initialize(CSimpleArray
<ParseError
> *pErrors
) throw()
741 HTTP_CODE
OnGetNextError() throw()
744 if (m_nCurrentError
>= m_pErrors
->GetSize() ||
745 m_nCurrentError
< 0 )
747 m_nCurrentError
= -1;
754 HTTP_CODE
OnGetErrorLineNumber() throw(...)
756 if (m_pErrors
->GetSize() == 0)
758 if (m_nCurrentError
> m_pErrors
->GetSize() ||
762 CWriteStreamHelper
c(m_pStream
);
763 if (!c
.Write((*m_pErrors
)[m_nCurrentError
].m_nLineNumber
))
769 HTTP_CODE
OnGetErrorText() throw(...)
771 if (m_pErrors
->GetSize() == 0)
773 if (m_nCurrentError
> m_pErrors
->GetSize() ||
777 CWriteStreamHelper
c(m_pStream
);
779 if (!c
.Write(static_cast<LPCSTR
>((*m_pErrors
)[m_nCurrentError
].m_szError
)))
785 HTTP_CODE
OnGetErrorLine() throw(...)
787 ATLASSUME(m_pStream
!= NULL
);
789 if (m_pErrors
->GetSize() == 0)
791 if (m_nCurrentError
> m_pErrors
->GetSize() ||
795 m_pStream
->WriteStream((*m_pErrors
)[m_nCurrentError
].m_szStartLine
,
796 (int)((*m_pErrors
)[m_nCurrentError
].m_szEndLine
- (*m_pErrors
)[m_nCurrentError
].m_szStartLine
), NULL
);
801 BEGIN_REPLACEMENT_METHOD_MAP(CParseErrorProvider
)
802 REPLACEMENT_METHOD_ENTRY("GetNextError", OnGetNextError
)
803 REPLACEMENT_METHOD_ENTRY("GetErrorText", OnGetErrorText
)
804 REPLACEMENT_METHOD_ENTRY("GetErrorLine", OnGetErrorLine
)
805 REPLACEMENT_METHOD_ENTRY("GetErrorLineNumber", OnGetErrorLineNumber
)
806 END_REPLACEMENT_METHOD_MAP()
810 bool m_bErrorsOccurred
;
813 class CSaveThreadLocale
817 CSaveThreadLocale() throw()
819 m_locale
= GetThreadLocale();
821 ~CSaveThreadLocale() throw()
823 SetThreadLocale(m_locale
);
827 HTTP_CODE
LoadFromResourceInternal(HINSTANCE hInstRes
, HRSRC hRsrc
) throw()
829 ATLASSERT( hRsrc
!= NULL
);
831 HGLOBAL hgResource
= NULL
;
832 hgResource
= LoadResource(hInstRes
, hRsrc
);
838 DWORD dwSize
= SizeofResource(hInstRes
, hRsrc
);
841 m_pBufferStart
= (LPSTR
)LockResource(hgResource
);
842 if (m_pBufferStart
!= NULL
)
844 m_pBufferEnd
= m_pBufferStart
+dwSize
;
849 // failed to load resource
855 ITagReplacer
*m_pReplacer
;
856 IAtlMemMgr
*m_pMemMgr
;
857 static CCRTHeap m_crtHeap
;
859 inline BOOL
CheckTag(LPCSTR szTag
, DWORD dwTagLen
, LPCSTR szStart
, DWORD dwLen
) throw()
861 if (dwLen
< dwTagLen
)
864 if (memcmp(szStart
, szTag
, dwTagLen
))
867 if (isspace(static_cast<unsigned char>(szStart
[dwTagLen
])) || szStart
[dwTagLen
] == '}')
873 inline void FindTagArgs(LPCSTR
& szstart
, LPCSTR
& szend
, int nKeywordChars
) throw()
875 // this function should only be called after finding a valid tag
876 // the first two characters of szstart should be {{
877 ATLASSERT(szstart
[0] == '{' && szstart
[1] == '{');
880 szstart
+= 2; // move past {{
881 szstart
= SkipSpace(szstart
, m_nCodePage
); // move past whitespace
882 szstart
+= nKeywordChars
; // move past keyword
883 szstart
= SkipSpace(szstart
, m_nCodePage
); // move past whitespace after keyword
885 szend
-=2; // chop off }}
886 szend
= RSkipSpace(szstart
, szend
, m_nCodePage
); // chop of trailing whitespace
889 DWORD
CheckTopAndPop(DWORD
*pBlockStack
, DWORD
*pdwTop
, DWORD dwToken
) throw()
892 return STENCIL_INVALIDINDEX
;
893 if (m_arrTokens
[pBlockStack
[*pdwTop
]].type
== dwToken
)
895 *pdwTop
= (*pdwTop
) - 1;
896 return pBlockStack
[(*pdwTop
)+1];
898 return STENCIL_INVALIDINDEX
;
901 DWORD
PushToken(DWORD
*pBlockStack
, DWORD
*pdwTop
, DWORD dwIndex
) throw()
903 if (*pdwTop
< (ATL_MAX_BLOCK_STACK
-1))
905 *pdwTop
= (*pdwTop
) + 1;
906 pBlockStack
[*pdwTop
] = dwIndex
;
910 dwIndex
= STENCIL_INVALIDINDEX
;
918 enum PARSE_TOKEN_RESULT
{ INVALID_TOKEN
, NORMAL_TOKEN
, RESERVED_TOKEN
};
920 CStencil(IAtlMemMgr
*pMemMgr
=NULL
) throw()
922 m_pBufferStart
= NULL
;
925 m_ftLastModified
.dwLowDateTime
= 0;
926 m_ftLastModified
.dwHighDateTime
= 0;
927 m_ftLastChecked
.dwLowDateTime
= 0;
928 m_ftLastChecked
.dwHighDateTime
= 0;
929 m_arrTokens
.SetCount(0, 128);
930 m_nCodePage
= CP_ACP
;
931 m_bUseLocaleACP
= TRUE
;
932 m_szHandlerName
[0] = '\0';
933 m_szDllPath
[0] = '\0';
936 m_pMemMgr
= &m_crtHeap
;
937 #ifdef ATL_DEBUG_STENCILS
940 m_bErrorsOccurred
= false;
945 virtual ~CStencil() throw()
950 #ifdef ATL_DEBUG_STENCILS
952 bool RenderErrors(IWriteStream
*pStream
) throw(...)
959 CComObjectStackEx
<CParseErrorProvider
> Errors
;
961 Errors
.Initialize(&m_Errors
);
962 CStencil ErrorStencil
;
964 if (m_hResInst
!= NULL
)
966 CFixedStringT
<CStringA
, 256> strErrorStencil
;
969 if (strErrorStencil
.LoadString(m_hResInst
, IDS_STENCIL_ERROR_STENCIL
) == FALSE
)
979 HTTP_CODE hcRet
= ErrorStencil
.LoadFromString(strErrorStencil
, strErrorStencil
.GetLength());
981 if (hcRet
== HTTP_SUCCESS
)
983 if (ErrorStencil
.ParseReplacements(static_cast<ITagReplacer
*>(&Errors
)) != false)
985 ErrorStencil
.FinishParseReplacements();
986 if (ErrorStencil
.ParseSuccessful() != false)
988 hcRet
= ErrorStencil
.Render(static_cast<ITagReplacer
*>(&Errors
), pStream
);
990 if (HTTP_ERROR_CODE(hcRet
) < 400)
1002 void SetErrorResource(HINSTANCE hResInst
)
1004 m_hResInst
= hResInst
;
1007 bool ParseSuccessful()
1009 return (m_Errors
.GetSize() == 0);
1012 bool AddErrorInternal(LPCSTR szErrorText
, LPCSTR szPosition
) throw()
1015 LPCSTR szStartLine
= NULL
;
1016 LPCSTR szPtr
= m_pBufferStart
;
1017 while (szPtr
< szPosition
)
1021 szStartLine
= szPtr
+ 1;
1025 LPSTR szNext
= CharNextExA(m_nCodePage
, szPtr
, 0);
1026 if (szNext
== szPtr
)
1032 LPCSTR szEndLine
= szPtr
;
1038 LPSTR szNext
= CharNextExA(m_nCodePage
, szPtr
, 0);
1039 if (szNext
== szPtr
)
1047 SafeStringCopy(p
.m_szError
, szErrorText
);
1048 p
.m_szPosition
= szPosition
;
1049 p
.m_nLineNumber
= nLineNum
;
1050 p
.m_szStartLine
= szStartLine
;
1051 p
.m_szEndLine
= szEndLine
;
1053 return (m_Errors
.Add(p
) == TRUE
);
1056 bool AddError(UINT uID
, LPCSTR szPosition
) throw()
1058 if (m_hResInst
!= NULL
)
1062 CFixedStringT
<CStringA
, 256> strRes
;
1063 if (strRes
.LoadString(m_hResInst
, uID
) != FALSE
)
1065 return AddErrorInternal(strRes
, szPosition
);
1072 return AddErrorInternal("Could not load resource for error string", szPosition
);
1075 bool AddReplacementError(LPCSTR szReplacement
, LPCSTR szPosition
) throw()
1077 if (m_hResInst
!= NULL
)
1081 CFixedStringT
<CStringA
, 256> strRes
;
1082 if (strRes
.LoadString(m_hResInst
, IDS_STENCIL_UNRESOLVED_REPLACEMENT
) != FALSE
)
1084 CFixedStringT
<CStringA
, 256> strErrorText
;
1085 strErrorText
.Format(strRes
, szReplacement
);
1086 return AddErrorInternal(strErrorText
, szPosition
);
1090 return AddErrorInternal("Could not load resource for error string", szPosition
);
1104 bool ParseSuccessful()
1106 return !m_bErrorsOccurred
;
1109 bool AddError(UINT
/*uID*/, LPCSTR
/*szPosition*/) throw()
1111 m_bErrorsOccurred
= true;
1115 bool AddReplacementError(LPCSTR
/*szReplacement*/, LPCSTR
/*szPosition*/) throw()
1117 m_bErrorsOccurred
= true;
1121 void SetErrorResource(HINSTANCE
) throw()
1127 // Call Uninitialize if you want to re-use an already initialized CStencil
1128 void Uninitialize() throw()
1130 int nSize
= (int) m_arrTokens
.GetCount();
1131 for (int nIndex
= 0; nIndex
< nSize
; nIndex
++)
1133 if (m_arrTokens
[nIndex
].bDynamicAlloc
)
1134 delete [] m_arrTokens
[nIndex
].pStart
;
1135 if (m_arrTokens
[nIndex
].dwData
!= 0 && m_arrTokens
[nIndex
].type
!= STENCIL_LOCALE
)
1136 m_pMemMgr
->Free((void *) m_arrTokens
[nIndex
].dwData
);
1139 m_arrTokens
.RemoveAll();
1140 if ((m_ftLastModified
.dwLowDateTime
|| m_ftLastModified
.dwHighDateTime
) && m_pBufferStart
)
1142 delete [] m_pBufferStart
;
1144 m_pBufferStart
= NULL
;
1145 m_pBufferEnd
= NULL
;
1148 void GetLastModified(FILETIME
*pftLastModified
)
1150 ATLENSURE(pftLastModified
);
1151 *pftLastModified
= m_ftLastModified
;
1154 void GetLastChecked(FILETIME
*pftLastChecked
)
1156 ATLENSURE(pftLastChecked
);
1157 *pftLastChecked
= m_ftLastChecked
;
1160 void SetLastChecked(FILETIME
*pftLastChecked
)
1162 ATLENSURE(pftLastChecked
);
1163 m_ftLastChecked
= *pftLastChecked
;
1166 HCACHEITEM
GetCacheItem()
1168 return m_hCacheItem
;
1171 void SetCacheItem(HCACHEITEM hCacheItem
)
1173 ATLASSUME(m_hCacheItem
== NULL
);
1174 m_hCacheItem
= hCacheItem
;
1177 bool GetHandlerName(__out_ecount_z(nPathLen
) LPSTR szDllPath
, __in
size_t nPathLen
, __out_ecount_z(nHandlerNameLen
) LPSTR szHandlerName
, __in
size_t nHandlerNameLen
) throw()
1179 if(strlen(m_szDllPath
) >= nPathLen
)
1184 if(strlen(m_szHandlerName
) >= nHandlerNameLen
)
1189 if(0 != strcpy_s(szDllPath
, nPathLen
, m_szDllPath
))
1194 if(0 != strcpy_s(szHandlerName
, nHandlerNameLen
, m_szHandlerName
))
1202 // Adds a token to the token array, handler name, method name
1203 // and handler function offset are optional
1204 ATL_NOINLINE DWORD
AddToken(
1208 LPCSTR szHandlerName
= NULL
,
1209 LPCSTR szMethodName
= NULL
,
1210 DWORD dwFnOffset
= STENCIL_INVALIDOFFSET
,
1211 DWORD dwObjOffset
= STENCIL_INVALIDOFFSET
,
1212 DWORD_PTR dwData
= 0,
1214 BOOL bDynamicAlloc
= 0) throw()
1218 memset(&t
, 0x00, sizeof(t
));
1223 t
.dwLoopIndex
= STENCIL_INVALIDINDEX
;
1224 t
.dwFnOffset
= dwFnOffset
;
1225 t
.dwObjOffset
= dwObjOffset
;
1228 t
.bDynamicAlloc
= bDynamicAlloc
;
1230 // this should never assert unless the user has overriden something incorrectly
1231 if ((szHandlerName
!= NULL
) && (*szHandlerName
))
1233 ATLVERIFY( SafeStringCopy(t
.szHandlerName
, szHandlerName
) );
1235 if ((szMethodName
!= NULL
) && (*szMethodName
))
1237 ATLVERIFY( SafeStringCopy(t
.szMethodName
, szMethodName
) );
1242 return (DWORD
) m_arrTokens
.Add(t
);
1246 return STENCIL_INVALIDINDEX
;
1250 HTTP_CODE
LoadFromFile(LPCSTR szFileName
) throw()
1252 HRESULT hr
= E_FAIL
;
1253 ULONGLONG dwLen
= 0;
1258 hr
= file
.Create(CA2CTEX
<MAX_PATH
>(szFileName
), GENERIC_READ
, FILE_SHARE_READ
, OPEN_EXISTING
);
1259 if (FAILED(hr
) || GetFileType(file
) != FILE_TYPE_DISK
)
1260 return AtlsHttpError(500, ISE_SUBERR_STENCIL_LOAD_FAIL
); // couldn't load SRF!
1262 if (GetFileTime(file
, NULL
, NULL
, &m_ftLastModified
))
1264 if (SUCCEEDED(file
.GetSize(dwLen
)))
1266 ATLASSERT(!m_pBufferStart
);
1268 GetSystemTimeAsFileTime(&m_ftLastChecked
);
1270 m_pBufferStart
= NULL
;
1271 CAutoVectorPtr
<char> buffer
;
1272 if (!buffer
.Allocate((size_t) dwLen
))
1273 return AtlsHttpError(500, ISE_SUBERR_OUTOFMEM
); // out of memory
1276 hr
= file
.Read(buffer
, (DWORD
) dwLen
, dwRead
);
1278 return AtlsHttpError(500, ISE_SUBERR_READFILEFAIL
); // ReadFile failed
1280 m_pBufferStart
= buffer
.Detach();
1281 m_pBufferEnd
= m_pBufferStart
+ dwRead
;
1287 return AtlsHttpError(500, ISE_SUBERR_OUTOFMEM
);
1290 return HTTP_SUCCESS
;
1293 // loads a stencil from the specified resource.
1294 HTTP_CODE
LoadFromResource(HINSTANCE hInstRes
, LPCSTR szID
, LPCSTR szType
= NULL
) throw()
1298 szType
= (LPCSTR
) RT_HTML
;
1301 HRSRC hRsrc
= FindResourceA(hInstRes
, szID
, szType
);
1304 return LoadFromResourceInternal(hInstRes
, hRsrc
);
1310 HTTP_CODE
LoadFromResourceEx(HINSTANCE hInstRes
, LPCSTR szID
, WORD wLanguage
, LPCSTR szType
= NULL
) throw()
1314 szType
= (LPCSTR
) RT_HTML
;
1317 HRSRC hRsrc
= FindResourceExA(hInstRes
, szType
, szID
, wLanguage
);
1320 return LoadFromResourceInternal(hInstRes
, hRsrc
);
1326 // loads a stencil from the specified resource
1327 HTTP_CODE
LoadFromResource(HINSTANCE hInstRes
, UINT nId
, LPCSTR szType
= NULL
) throw()
1329 return LoadFromResource(hInstRes
, MAKEINTRESOURCEA(nId
), szType
);
1332 HTTP_CODE
LoadFromResourceEx(HINSTANCE hInstRes
, UINT nId
, WORD wLanguage
, LPCSTR szType
= NULL
) throw()
1334 return LoadFromResourceEx(hInstRes
, MAKEINTRESOURCEA(nId
), wLanguage
, szType
);
1337 // loads a stencil from a string
1338 HTTP_CODE
LoadFromString(LPCSTR szString
, DWORD dwSize
) throw()
1340 m_pBufferStart
= szString
;
1341 m_pBufferEnd
= m_pBufferStart
+dwSize
;
1342 return HTTP_SUCCESS
;
1345 // Cracks the loaded stencil into an array of StencilTokens in preparation for
1346 // rendering. LoadStencil must be called prior to calling this function.
1347 virtual bool ParseReplacements(ITagReplacer
* pReplacer
) throw(...)
1349 return ParseReplacementsFromBuffer(pReplacer
, GetBufferStart(), GetBufferEnd());
1352 virtual bool FinishParseReplacements() throw(...)
1354 DWORD dwSize
= (DWORD
) m_arrTokens
.GetCount();
1355 for (DWORD dwIndex
= 0; dwIndex
< dwSize
; dwIndex
++)
1357 StencilToken
& token
= m_arrTokens
[dwIndex
];
1358 bool bUnclosedBlock
= ((token
.type
== STENCIL_CONDITIONALSTART
||
1359 token
.type
== STENCIL_CONDITIONALELSE
||
1360 token
.type
== STENCIL_ITERATORSTART
) &&
1361 token
.dwLoopIndex
== STENCIL_INVALIDINDEX
);
1362 if ((token
.szMethodName
[0] && token
.dwFnOffset
== STENCIL_INVALIDOFFSET
) || bUnclosedBlock
)
1364 if (bUnclosedBlock
||
1365 m_pReplacer
->FindReplacementOffset(
1366 token
.szMethodName
, &token
.dwFnOffset
,
1367 token
.szHandlerName
, &token
.dwObjOffset
,
1368 &token
.dwMap
, (void **)(&token
.dwData
), m_pMemMgr
) != HTTP_SUCCESS
)
1370 if (bUnclosedBlock
&& token
.type
== STENCIL_CONDITIONALSTART
)
1372 AddError(IDS_STENCIL_UNCLOSEDBLOCK_IF
, token
.pStart
);
1374 else if (bUnclosedBlock
&& token
.type
== STENCIL_CONDITIONALELSE
)
1376 AddError(IDS_STENCIL_UNCLOSEDBLOCK_ELSE
, token
.pStart
);
1378 else if (bUnclosedBlock
&& token
.type
== STENCIL_ITERATORSTART
)
1380 AddError(IDS_STENCIL_UNCLOSEDBLOCK_WHILE
, token
.pStart
);
1384 AddReplacementError(token
.szMethodName
, token
.pStart
);
1387 // unresolved replacement, convert it to a text token
1388 token
.type
= STENCIL_TEXTTAG
;
1390 // convert all linked tokens to text tokens as well
1391 // this includes: endif, else, endwhile
1392 DWORD dwLoopIndex
= token
.dwLoopIndex
;
1393 while (dwLoopIndex
!= dwIndex
&& dwLoopIndex
!= STENCIL_INVALIDINDEX
)
1395 m_arrTokens
[dwLoopIndex
].type
= STENCIL_TEXTTAG
;
1396 dwLoopIndex
= m_arrTokens
[dwLoopIndex
].dwLoopIndex
;
1402 return ParseSuccessful();
1405 virtual bool Parse(ITagReplacer
*pReplacer
) throw( ... )
1407 if (ParseReplacements(pReplacer
))
1409 return FinishParseReplacements();
1415 DWORD
ParseReplacement( LPCSTR szTokenStart
,
1417 DWORD dwTokenType
= STENCIL_REPLACEMENT
,
1418 DWORD dwKeywordLen
= 0) throw()
1420 // hold on to the start and end pointers (before removing curlies and whitespace)
1421 // this is needed so that we can convert the token to a text token if the method
1422 // is not resolved (in FinishParseReplacements)
1423 LPCSTR szStart
= szTokenStart
;
1424 LPCSTR szEnd
= szTokenEnd
;
1426 FindTagArgs(szTokenStart
, szTokenEnd
, dwKeywordLen
);
1428 char szMethodName
[ATL_MAX_METHOD_NAME_LEN
+1];
1429 char szHandlerName
[ATL_MAX_HANDLER_NAME_LEN
+1];
1432 //look up the handler name, method name and handler interface
1433 if (HTTP_SUCCESS
== GetHandlerAndMethodNames(szTokenStart
, szTokenEnd
,
1434 szMethodName
, ATL_MAX_METHOD_NAME_LEN
+1,
1435 szHandlerName
, ATL_MAX_HANDLER_NAME_LEN
+1))
1436 dwIndex
= AddToken(szStart
, szEnd
, dwTokenType
,
1437 szHandlerName
, szMethodName
,
1438 STENCIL_INVALIDINDEX
, STENCIL_INVALIDINDEX
,
1439 0, STENCIL_BASIC_MAP
);
1441 dwIndex
= STENCIL_INVALIDINDEX
;
1445 DWORD
ParseWhile(LPCSTR szTokenStart
, LPCSTR szTokenEnd
, DWORD
*pBlockStack
, DWORD
*pdwTop
) throw()
1447 DWORD dwIndex
= ParseReplacement(szTokenStart
, szTokenEnd
, STENCIL_ITERATORSTART
, sizeof("while")-1);
1448 if (dwIndex
== STENCIL_INVALIDINDEX
)
1450 return PushToken(pBlockStack
, pdwTop
, dwIndex
);
1453 DWORD
ParseEndWhile(LPCSTR szTokenStart
, LPCSTR szTokenEnd
, DWORD
*pBlockStack
, DWORD
*pdwTop
) throw()
1455 DWORD dwTopIndex
= CheckTopAndPop(pBlockStack
, pdwTop
, STENCIL_ITERATORSTART
);
1456 if (dwTopIndex
== STENCIL_INVALIDINDEX
)
1458 AddError(IDS_STENCIL_UNOPENEDBLOCK_ENDWHILE
, szTokenStart
);
1462 DWORD dwIndex
= AddToken(szTokenStart
, szTokenEnd
, STENCIL_ITERATOREND
);
1463 if (dwIndex
!= STENCIL_INVALIDINDEX
)
1465 m_arrTokens
[dwTopIndex
].dwLoopIndex
= dwIndex
;
1466 m_arrTokens
[dwIndex
].dwLoopIndex
= dwTopIndex
;
1471 DWORD
ParseIf(LPCSTR szTokenStart
, LPCSTR szTokenEnd
, DWORD
*pBlockStack
, DWORD
*pdwTop
) throw()
1473 DWORD dwIndex
= ParseReplacement(szTokenStart
, szTokenEnd
, STENCIL_CONDITIONALSTART
, sizeof("if")-1);
1474 if (dwIndex
== STENCIL_INVALIDINDEX
)
1476 return PushToken(pBlockStack
, pdwTop
, dwIndex
);
1479 DWORD
ParseElse(LPCSTR szTokenStart
, LPCSTR szTokenEnd
, DWORD
*pBlockStack
, DWORD
*pdwTop
) throw()
1481 DWORD dwTopIndex
= CheckTopAndPop(pBlockStack
, pdwTop
, STENCIL_CONDITIONALSTART
);
1482 if (dwTopIndex
== STENCIL_INVALIDINDEX
)
1484 AddError(IDS_STENCIL_UNOPENEDBLOCK_ELSE
, szTokenStart
);
1488 DWORD dwIndex
= AddToken(szTokenStart
, szTokenEnd
, STENCIL_CONDITIONALELSE
);
1489 if (dwIndex
!= STENCIL_INVALIDINDEX
)
1491 m_arrTokens
[dwTopIndex
].dwLoopIndex
= dwIndex
;
1493 return PushToken(pBlockStack
, pdwTop
, dwIndex
);
1498 DWORD
ParseEndIf(LPCSTR szTokenStart
, LPCSTR szTokenEnd
, DWORD
*pBlockStack
, DWORD
*pdwTop
) throw()
1500 DWORD dwTopIndex
= CheckTopAndPop(pBlockStack
, pdwTop
, STENCIL_CONDITIONALSTART
);
1501 if (dwTopIndex
== STENCIL_INVALIDINDEX
)
1503 dwTopIndex
= CheckTopAndPop(pBlockStack
, pdwTop
, STENCIL_CONDITIONALELSE
);
1504 if (dwTopIndex
== STENCIL_INVALIDINDEX
)
1506 AddError(IDS_STENCIL_UNOPENEDBLOCK_ENDIF
, szTokenStart
);
1510 DWORD dwIndex
= AddToken(szTokenStart
, szTokenEnd
, STENCIL_CONDITIONALEND
);
1511 if (dwIndex
!= STENCIL_INVALIDINDEX
)
1513 m_arrTokens
[dwTopIndex
].dwLoopIndex
= dwIndex
;
1518 DWORD
ParseLocale(LPCSTR szTokenStart
, LPCSTR szTokenEnd
) throw()
1520 LPCSTR szstart
= szTokenStart
;
1521 LPCSTR szend
= szTokenEnd
;
1522 LCID locale
= 0xFFFFFFFF;
1523 FindTagArgs(szstart
, szend
, 6);
1524 #ifndef ATL_NO_MLANG
1525 if (isdigit(static_cast<unsigned char>(szstart
[0])))
1527 locale
= (LCID
) atoi(szstart
);
1533 CComPtr
<IMultiLanguage
> pML
;
1534 hr
= pML
.CoCreateInstance(__uuidof(CMultiLanguage
), NULL
, CLSCTX_INPROC_SERVER
);
1537 ATLTRACE(atlTraceStencil
, 0, _T("Couldn't create CMultiLanguage object. check MLANG installation."));
1538 AddError(IDS_STENCIL_MLANG_COCREATE
, szTokenStart
);
1542 CStringW
str(szstart
, (int)((szend
-szstart
)+1));
1544 #ifdef __IMultiLanguage2_INTERFACE_DEFINED__
1546 // use IMultiLanguage2 if possible
1547 CComPtr
<IMultiLanguage2
> spML2
;
1548 hr
= pML
.QueryInterface(&spML2
);
1549 if (FAILED(hr
) || !spML2
.p
)
1550 hr
= pML
->GetLcidFromRfc1766(&locale
, CComBSTR(str
));
1552 hr
= spML2
->GetLcidFromRfc1766(&locale
, CComBSTR(str
));
1554 #else // __IMultiLanguage2_INTERFACE_DEFINED__
1556 hr
= pML
->GetLcidFromRfc1766(&locale
, CComBSTR(str
));
1558 #endif // __IMultiLanguage2_INTERFACE_DEFINED__
1562 AddError(IDS_STENCIL_MLANG_LCID
, szTokenStart
);
1566 locale
= 0xFFFFFFFF;
1569 locale
= (LCID
) atoi(szstart
);
1572 if (m_bUseLocaleACP
)
1575 if (GetLocaleInfo(locale
, LOCALE_IDEFAULTANSICODEPAGE
, szACP
, 7) != 0)
1577 m_nCodePage
= (WORD
) _ttoi(szACP
);
1581 AddError(IDS_STENCIL_MLANG_GETLOCALE
, szTokenStart
);
1584 DWORD dwCurrentTokenIndex
= STENCIL_INVALIDINDEX
;
1585 if (locale
!= 0xFFFFFFFF)
1586 dwCurrentTokenIndex
= AddToken(NULL
, NULL
, STENCIL_LOCALE
,
1587 NULL
, NULL
, STENCIL_INVALIDOFFSET
, STENCIL_INVALIDOFFSET
, locale
);
1589 return STENCIL_INVALIDINDEX
;
1590 return dwCurrentTokenIndex
;
1593 DWORD
ParseCodepage(LPCSTR szTokenStart
, LPCSTR szTokenEnd
) throw()
1595 LPCSTR szstart
= szTokenStart
;
1596 LPCSTR szend
= szTokenEnd
;
1597 WORD nCodePage
= 0xFFFF;
1599 FindTagArgs(szstart
, szend
, 8);
1600 #ifndef ATL_NO_MLANG
1601 if (isdigit(static_cast<unsigned char>(szstart
[0])))
1603 nCodePage
= (WORD
) atoi(szstart
);
1609 CComPtr
<IMultiLanguage
> pML
;
1610 hr
= pML
.CoCreateInstance(__uuidof(CMultiLanguage
), NULL
, CLSCTX_INPROC_SERVER
);
1613 ATLTRACE(atlTraceStencil
, 0, _T("Couldn't create CMultiLanguage object. check MLANG installation."));
1614 AddError(IDS_STENCIL_MLANG_COCREATE
, szTokenStart
);
1618 CStringW
str(szstart
, (int)((szend
-szstart
)+1));
1621 #ifdef __IMultiLanguage2_INTERFACE_DEFINED__
1623 // use IMultiLanguage2 if possible
1624 CComPtr
<IMultiLanguage2
> spML2
;
1625 hr
= pML
.QueryInterface(&spML2
);
1626 if (FAILED(hr
) || !spML2
.p
)
1627 hr
= pML
->GetCharsetInfo(CComBSTR(str
), &info
);
1629 hr
= spML2
->GetCharsetInfo(CComBSTR(str
), &info
);
1631 #else // __IMultiLanguage2_INTERFACE_DEFINED__
1633 hr
= pML
->GetCharsetInfo(CComBSTR(str
), &info
);
1635 #endif // __IMultiLanguage2_INTERFACE_DEFINED__
1637 // for most character sets, uiCodePage and uiInternetEncoding
1638 // are the same. UTF-8 is the exception that we're concerned about.
1639 // for that character set, we want uiInternetEncoding (65001 - UTF-8)
1640 // instead of uiCodePage (1200 - UCS-2)
1643 nCodePage
= (WORD
) info
.uiInternetEncoding
;
1647 AddError(IDS_STENCIL_MLANG_GETCHARSET
, szTokenStart
);
1654 nCodePage
= (WORD
) atoi(szstart
);
1656 if (nCodePage
!= 0xFFFF)
1657 m_nCodePage
= nCodePage
;
1658 m_bUseLocaleACP
= FALSE
;
1660 return STENCIL_INVALIDINDEX
;
1663 PARSE_TOKEN_RESULT
ParseHandler(LPCSTR szTokenStart
, LPCSTR szTokenEnd
) throw()
1665 LPCSTR szstart
= szTokenStart
;
1666 LPCSTR szend
= szTokenEnd
;
1668 if (m_szHandlerName
[0] && m_szDllPath
[0])
1669 return RESERVED_TOKEN
; // already found the handler and path dll names
1671 FindTagArgs(szstart
, szend
, 7);
1672 size_t nlen
= (szend
-szstart
)+1;
1673 char szHandlerDllName
[MAX_PATH
+ ATL_MAX_HANDLER_NAME_LEN
+ 1];
1674 if (nlen
< MAX_PATH
+ ATL_MAX_HANDLER_NAME_LEN
+ 1)
1676 Checked::memcpy_s(szHandlerDllName
, MAX_PATH
+ ATL_MAX_HANDLER_NAME_LEN
+ 1, szstart
, szend
-szstart
+1);
1677 szHandlerDllName
[szend
-szstart
+1] = '\0';
1679 DWORD dwDllPathLen
= MAX_PATH
;
1680 DWORD dwHandlerNameLen
= ATL_MAX_HANDLER_NAME_LEN
+1;
1682 if (!_AtlCrackHandler(szHandlerDllName
, m_szDllPath
, &dwDllPathLen
, m_szHandlerName
, &dwHandlerNameLen
))
1684 AddError(IDS_STENCIL_INVALID_HANDLER
, szTokenStart
);
1685 return INVALID_TOKEN
;
1689 return RESERVED_TOKEN
;
1692 virtual PARSE_TOKEN_RESULT
ParseToken(LPCSTR szTokenStart
, LPCSTR szTokenEnd
, DWORD
*pBlockStack
, DWORD
*pdwTop
)
1694 LPCSTR pStart
= szTokenStart
;
1695 pStart
+= 2; //skip curlies
1696 pStart
= SkipSpace(pStart
, m_nCodePage
);
1697 DWORD dwLen
= (DWORD
)(szTokenEnd
- szTokenStart
);
1699 DWORD dwIndex
= STENCIL_INVALIDINDEX
;
1700 PARSE_TOKEN_RESULT ret
= RESERVED_TOKEN
;
1702 if (CheckTag("endwhile", 8, pStart
, dwLen
))
1703 dwIndex
= ParseEndWhile(szTokenStart
, szTokenEnd
, pBlockStack
, pdwTop
);
1704 else if (CheckTag("while", 5, pStart
, dwLen
))
1705 dwIndex
= ParseWhile(szTokenStart
, szTokenEnd
, pBlockStack
, pdwTop
);
1706 else if (CheckTag("endif", 5, pStart
, dwLen
))
1707 dwIndex
= ParseEndIf(szTokenStart
, szTokenEnd
, pBlockStack
, pdwTop
);
1708 else if (CheckTag("else", 4, pStart
, dwLen
))
1709 dwIndex
= ParseElse(szTokenStart
, szTokenEnd
, pBlockStack
, pdwTop
);
1710 else if (CheckTag("if", 2, pStart
, dwLen
))
1711 dwIndex
= ParseIf(szTokenStart
, szTokenEnd
, pBlockStack
, pdwTop
);
1712 else if (CheckTag("locale", 6, pStart
, dwLen
))
1713 dwIndex
= ParseLocale(szTokenStart
, szTokenEnd
);
1714 else if (CheckTag("handler", 7, pStart
, dwLen
))
1716 return ParseHandler(szTokenStart
, szTokenEnd
);
1718 else if (CheckTag("codepage", 8, pStart
, dwLen
))
1720 ParseCodepage(szTokenStart
, szTokenEnd
);
1721 return RESERVED_TOKEN
;
1725 dwIndex
= ParseReplacement(szTokenStart
, szTokenEnd
, STENCIL_REPLACEMENT
);
1726 if (dwIndex
== STENCIL_INVALIDINDEX
)
1727 return INVALID_TOKEN
;
1731 if (dwIndex
== STENCIL_INVALIDINDEX
)
1732 return INVALID_TOKEN
;
1736 virtual bool ParseReplacementsFromBuffer(ITagReplacer
* pReplacer
, LPCSTR pStart
, LPCSTR pEnd
)
1738 LPCSTR szCurr
= pStart
;
1739 DWORD BlockStack
[ATL_MAX_BLOCK_STACK
];
1742 m_pReplacer
= pReplacer
;
1744 DWORD dwCurrentTokenIndex
= 0;
1749 AddError(IDS_STENCIL_NULLPARAM
, NULL
);
1753 LPCSTR szEnd
= pEnd
;
1754 if (szEnd
<= szCurr
)
1757 AddError(IDS_STENCIL_INVALIDSTRING
, NULL
);
1761 while(szCurr
< szEnd
)
1763 //mark the start of this block, then find the end of the block
1764 //the end is denoted by an opening curly
1765 LPCSTR szStart
= szCurr
;
1766 while (szCurr
< szEnd
&& (*szCurr
!= '{' || szCurr
[1] != '{'))
1768 LPSTR szNext
= CharNextExA(m_nCodePage
, szCurr
, 0);
1769 if (szNext
== szCurr
)
1772 AddError(IDS_STENCIL_EMBEDDED_NULL
, NULL
);
1778 //special case for the last text block, if there is one
1779 if (szCurr
>= szEnd
)
1781 // add the last token. This is everything after the last
1782 // double curly block, which is text.
1783 dwCurrentTokenIndex
= AddToken(szStart
, szEnd
-1, STENCIL_TEXTTAG
);
1787 //if there are any characters between szStart and szCurr inclusive,
1788 //copy them to a text token.
1789 if (szCurr
-1 >= szStart
)
1790 dwCurrentTokenIndex
= AddToken(szStart
, szCurr
-1, STENCIL_TEXTTAG
);
1792 if (dwCurrentTokenIndex
== STENCIL_INVALIDINDEX
)
1794 AddError(IDS_STENCIL_OUTOFMEMORY
, pStart
);
1798 //find the end of the tag
1801 szCurr
+= 2; // Skip over the two '{' s
1802 while (szCurr
< szEnd
)
1804 if (szCurr
[0] == '}' && szCurr
[1] == '}')
1806 else if (szCurr
[0] == '{')
1809 LPSTR szNext
= CharNextExA(m_nCodePage
, szCurr
, 0);
1810 if (szNext
== szCurr
)
1813 AddError(IDS_STENCIL_EMBEDDED_NULL
, NULL
);
1819 if (szCurr
>= szEnd
)
1821 AddError(IDS_STENCIL_UNMATCHED_TAG_START
, szStart
);
1822 if (AddToken(szStart
, szCurr
-1, STENCIL_TEXTTAG
) == STENCIL_INVALIDINDEX
)
1824 AddError(IDS_STENCIL_OUTOFMEMORY
, pStart
);
1831 if (szCurr
[0] == '{')
1833 if (szCurr
[1] != '{')
1837 AddError(IDS_STENCIL_MISMATCHED_TAG_START
, szStart
);
1838 if (AddToken(szStart
, szCurr
-1, STENCIL_TEXTTAG
) == STENCIL_INVALIDINDEX
)
1840 AddError(IDS_STENCIL_OUTOFMEMORY
, pStart
);
1847 szEndTag
= CharNextExA(m_nCodePage
, szCurr
, 0);
1848 if (szEndTag
== szCurr
)
1851 AddError(IDS_STENCIL_EMBEDDED_NULL
, NULL
);
1855 PARSE_TOKEN_RESULT ret
= ParseToken(szStart
, szEndTag
, BlockStack
, &dwTop
);
1857 if (ret
== INVALID_TOKEN
)
1859 dwCurrentTokenIndex
= AddToken(szStart
, szEndTag
, STENCIL_TEXTTAG
);
1860 if (dwCurrentTokenIndex
== STENCIL_INVALIDINDEX
)
1862 AddError(IDS_STENCIL_OUTOFMEMORY
, pStart
);
1866 szCurr
= CharNextExA(m_nCodePage
, szEndTag
, 0);
1870 szCurr
= CharNextExA(m_nCodePage
, szEndTag
, 0);
1871 if (szEndTag
== szCurr
)
1874 AddError(IDS_STENCIL_EMBEDDED_NULL
, NULL
);
1878 if (ret
== RESERVED_TOKEN
)
1880 if (szCurr
< szEnd
&& *szCurr
== '\n')
1882 else if ((szCurr
+1 < szEnd
&& *szCurr
== '\r' && *(szCurr
+1) == '\n'))
1890 HTTP_CODE
GetHandlerAndMethodNames(
1893 __out_ecount_z(nMethodNameLen
) LPSTR pszMethodName
,
1894 __in
size_t nMethodNameLen
,
1895 __out_ecount_z(nHandlerNameLen
) LPSTR pszHandlerName
,
1896 __in
size_t nHandlerNameLen
) throw()
1901 ATLASSERT(pEnd
> pStart
);
1903 if (!pszMethodName
|| !pszHandlerName
|| nMethodNameLen
< 1 || nHandlerNameLen
< 1)
1906 AddError(IDS_STENCIL_BAD_PARAMETER
, pStart
);
1907 return AtlsHttpError(500, ISE_SUBERR_UNEXPECTED
);
1911 *pszMethodName
= '\0';
1912 *pszHandlerName
= '\0';
1913 CHAR szMethodString
[ATL_MAX_METHOD_NAME_LEN
+ ATL_MAX_HANDLER_NAME_LEN
+1];
1914 HTTP_CODE hcErr
= HTTP_SUCCESS
;
1916 // copy the method string
1918 size_t nMethodLen
= (pEnd
-pStart
)+1;
1919 if (nMethodLen
>= (ATL_MAX_METHOD_NAME_LEN
+ ATL_MAX_HANDLER_NAME_LEN
+1))
1921 AddError(IDS_STENCIL_METHODNAME_TOO_LONG
, pStart
);
1922 return AtlsHttpError(500, ISE_SUBERR_LONGMETHODNAME
);
1925 Checked::memcpy_s(szMethodString
, ATL_MAX_METHOD_NAME_LEN
+ ATL_MAX_HANDLER_NAME_LEN
+1, pStart
, nMethodLen
);
1926 szMethodString
[nMethodLen
] = '\0';
1929 // now crack the method string and get the handler
1930 // id and function name
1932 LPSTR szParen
= strchr(szMethodString
, '(');
1933 LPSTR szDot
= strchr(szMethodString
, '.');
1934 if (szDot
&& (!szParen
|| (szDot
< szParen
)))
1940 if (strlen(szDot
) < nMethodNameLen
)
1941 Checked::strcpy_s(pszMethodName
, nMethodNameLen
, szDot
);
1944 AddError(IDS_STENCIL_METHODNAME_TOO_LONG
, pStart
+ (szDot
- szMethodString
));
1945 hcErr
= AtlsHttpError(500, ISE_SUBERR_LONGMETHODNAME
);
1947 // copy handler name
1950 if (strlen(szMethodString
) < nHandlerNameLen
)
1951 Checked::strcpy_s(pszHandlerName
, nHandlerNameLen
, szMethodString
);
1954 AddError(IDS_STENCIL_HANDLERNAME_TOO_LONG
, pStart
);
1955 hcErr
= AtlsHttpError(500, ISE_SUBERR_LONGHANDLERNAME
);
1961 // only a method name so just copy it.
1962 if (strlen(szMethodString
) < nMethodNameLen
)
1963 Checked::strcpy_s(pszMethodName
, nMethodNameLen
, szMethodString
);
1966 AddError(IDS_STENCIL_METHODNAME_TOO_LONG
, pStart
);
1967 hcErr
= AtlsHttpError(500, ISE_SUBERR_LONGMETHODNAME
);
1973 virtual HTTP_CODE
Render(
1974 ITagReplacer
*pReplacer
,
1975 IWriteStream
*pWriteStream
,
1976 CStencilState
* pState
= NULL
) const throw(...)
1978 ATLENSURE(pReplacer
!= NULL
);
1979 ATLENSURE(pWriteStream
!= NULL
);
1981 HTTP_CODE hcErrorCode
= HTTP_SUCCESS
;
1983 DWORD dwArraySize
= GetTokenCount();
1985 // set up locale info
1986 CSaveThreadLocale lcidSave
;
1990 dwIndex
= pState
->dwIndex
;
1992 // restore the locale if we're restarting rendering
1993 if (pState
->locale
!= CP_ACP
)
1994 SetThreadLocale(pState
->locale
);
1997 pReplacer
->SetStream(pWriteStream
);
1998 while (dwIndex
< dwArraySize
)
2000 // RenderToken advances dwIndex appropriately for us.
2001 dwIndex
= RenderToken(dwIndex
, pReplacer
, pWriteStream
, &hcErrorCode
, pState
);
2003 if (dwIndex
== STENCIL_INVALIDINDEX
||
2004 hcErrorCode
!= HTTP_SUCCESS
)
2008 if (IsAsyncStatus(hcErrorCode
))
2010 ATLASSERT( pState
!= NULL
); // state is required for async
2012 pState
->dwIndex
= dwIndex
;
2014 // lcidSave destructor will restore the locale info in case it was changed
2019 inline BOOL
IsValidIndex(DWORD dwIndex
) const throw()
2021 if (dwIndex
== STENCIL_INVALIDINDEX
)
2023 if (dwIndex
< GetTokenCount())
2029 virtual DWORD
RenderToken(
2031 ITagReplacer
*pReplacer
,
2032 IWriteStream
*pWriteStream
,
2033 HTTP_CODE
*phcErrorCode
,
2034 CStencilState
* pState
= NULL
) const throw(...)
2036 ATLENSURE(pReplacer
!= NULL
);
2037 ATLENSURE(pWriteStream
!= NULL
);
2039 const StencilToken
* pToken
= GetToken(dwIndex
);
2040 DWORD dwNextToken
= 0;
2041 HTTP_CODE hcErrorCode
= HTTP_SUCCESS
;
2044 return STENCIL_INVALIDINDEX
;
2046 switch (pToken
->type
)
2048 case STENCIL_TEXTTAG
:
2050 pWriteStream
->WriteStream(pToken
->pStart
,
2051 (int)((pToken
->pEnd
-pToken
->pStart
)+1), NULL
);
2052 dwNextToken
= dwIndex
+1;
2055 case STENCIL_ITERATORSTART
:
2057 HTTP_CODE hcErr
= STENCIL_SUCCESS
;
2059 #ifdef ATL_DEBUG_STENCILS
2060 // A 'while' token has to at least be followed by an endwhile!
2061 if (!IsValidIndex(dwIndex
+1))
2063 // This should have been caught at parse time
2064 dwNextToken
= STENCIL_INVALIDINDEX
;
2065 hcErrorCode
= AtlsHttpError(500, ISE_SUBERR_STENCIL_INVALIDINDEX
);
2070 // End of loop should be valid
2071 if (!IsValidIndex(pToken
->dwLoopIndex
))
2073 // This should have been caught at parse time
2074 dwNextToken
= STENCIL_INVALIDINDEX
;
2075 hcErrorCode
= AtlsHttpError(500, ISE_SUBERR_STENCIL_MISMATCHWHILE
);
2080 if (pToken
->dwFnOffset
== STENCIL_INVALIDOFFSET
)
2082 // This should have been caught at parse time
2083 dwNextToken
= STENCIL_INVALIDINDEX
;
2084 hcErrorCode
= AtlsHttpError(500, ISE_SUBERR_STENCIL_INVALIDFUNCOFFSET
);
2088 #endif // ATL_DEBUG_STENCILS
2090 DWORD dwLoopIndex
= pToken
->dwLoopIndex
; // points to the end of the loop
2092 // Call the replacement method
2093 // if it returns HTTP_SUCCESS, enter the loop
2094 // if it returns HTTP_S_FALSE, terminate the loop
2095 hcErr
= pReplacer
->RenderReplacement(pToken
->dwFnOffset
,
2096 pToken
->dwObjOffset
, pToken
->dwMap
, (void *) pToken
->dwData
);
2098 if (hcErr
== HTTP_SUCCESS
)
2100 dwNextToken
= dwIndex
+1;
2101 hcErrorCode
= HTTP_SUCCESS
;
2103 else if (hcErr
== HTTP_S_FALSE
)
2105 dwNextToken
= dwLoopIndex
+1;
2106 hcErrorCode
= HTTP_SUCCESS
;
2110 dwNextToken
= STENCIL_INVALIDINDEX
;
2111 hcErrorCode
= hcErr
;
2116 case STENCIL_REPLACEMENT
:
2118 #ifdef ATL_DEBUG_STENCILS
2119 if (pToken
->dwFnOffset
== STENCIL_INVALIDOFFSET
)
2121 // This should have been caught at parse time
2123 dwNextToken
= STENCIL_INVALIDINDEX
;
2124 hcErrorCode
= AtlsHttpError(500, ISE_SUBERR_STENCIL_INVALIDFUNCOFFSET
);
2127 #endif // ATL_DEBUG_STENCILS
2129 hcErrorCode
= pReplacer
->RenderReplacement(pToken
->dwFnOffset
,
2130 pToken
->dwObjOffset
, pToken
->dwMap
, (void *)pToken
->dwData
);
2132 if (IsAsyncContinueStatus(hcErrorCode
))
2133 dwNextToken
= dwIndex
; // call the tag again after we get back
2136 dwNextToken
= dwIndex
+ 1;
2138 // when returned from a handler, these indicate that the handler is done
2139 // and that we should move on to the next handler when called back
2140 if (hcErrorCode
== HTTP_SUCCESS_ASYNC_DONE
)
2141 hcErrorCode
= HTTP_SUCCESS_ASYNC
;
2142 else if (hcErrorCode
== HTTP_SUCCESS_ASYNC_NOFLUSH_DONE
)
2143 hcErrorCode
= HTTP_SUCCESS_ASYNC_NOFLUSH
;
2147 case STENCIL_ITERATOREND
:
2149 dwNextToken
= pToken
->dwLoopIndex
;
2150 hcErrorCode
= HTTP_SUCCESS
;
2151 ATLASSERT(GetToken(dwNextToken
)->type
== STENCIL_ITERATORSTART
);
2154 case STENCIL_CONDITIONALSTART
:
2156 #ifdef ATL_DEBUG_STENCILS
2157 if (pToken
->type
== STENCIL_CONDITIONALSTART
&& pToken
->dwFnOffset
== STENCIL_INVALIDOFFSET
)
2159 // This should have been caught at parse time
2161 dwNextToken
= STENCIL_INVALIDINDEX
;
2162 hcErrorCode
= AtlsHttpError(500, ISE_SUBERR_STENCIL_INVALIDFUNCOFFSET
);
2166 if (pToken
->dwLoopIndex
== STENCIL_INVALIDINDEX
)
2168 // This should have been caught at parse time
2170 dwNextToken
= STENCIL_INVALIDINDEX
;
2171 hcErrorCode
= AtlsHttpError(500, ISE_SUBERR_STENCIL_MISMATCHIF
);
2174 #endif // ATL_DEBUG_STENCILS
2176 DWORD dwLoopIndex
= pToken
->dwLoopIndex
; // points to the end of the loop
2179 // Call the replacement method.
2180 // If it returns HTTP_SUCCESS, we render everything up to
2181 // the end of the conditional.
2182 // if it returns HTTP_S_FALSE, the condition is not met and we
2183 // render the else part if it exists or jump past the endif otherwise
2184 hcErr
= pReplacer
->RenderReplacement(pToken
->dwFnOffset
,
2185 pToken
->dwObjOffset
, pToken
->dwMap
, (void *)pToken
->dwData
);
2187 if (hcErr
== HTTP_SUCCESS
)
2189 dwNextToken
= dwIndex
+1;
2190 hcErrorCode
= HTTP_SUCCESS
;
2192 else if (hcErr
== HTTP_S_FALSE
)
2194 dwNextToken
= dwLoopIndex
+1;
2195 hcErrorCode
= HTTP_SUCCESS
;
2199 dwNextToken
= STENCIL_INVALIDINDEX
;
2200 hcErrorCode
= hcErr
;
2205 case STENCIL_CONDITIONALELSE
:
2207 #ifdef ATL_DEBUG_STENCILS
2208 if (pToken
->dwLoopIndex
== STENCIL_INVALIDINDEX
)
2210 // This should have been caught at parse time
2212 dwNextToken
= STENCIL_INVALIDINDEX
;
2213 hcErrorCode
= AtlsHttpError(500, ISE_SUBERR_STENCIL_MISMATCHIF
);
2216 #endif // ATL_DEBUG_STENCILS
2218 dwNextToken
= pToken
->dwLoopIndex
+1;
2219 hcErrorCode
= HTTP_SUCCESS
;
2222 case STENCIL_CONDITIONALEND
:
2224 dwNextToken
= dwIndex
+1;
2225 hcErrorCode
= HTTP_SUCCESS
;
2228 case STENCIL_LOCALE
:
2232 pState
->locale
= (LCID
) pToken
->dwData
;
2234 SetThreadLocale((LCID
) pToken
->dwData
);
2235 dwNextToken
= dwIndex
+ 1;
2241 dwNextToken
= STENCIL_INVALIDINDEX
;
2242 hcErrorCode
= AtlsHttpError(500, ISE_SUBERR_STENCIL_UNEXPECTEDTYPE
);
2247 ATLASSERT(dwNextToken
!= dwIndex
|| IsAsyncContinueStatus(hcErrorCode
));
2250 *phcErrorCode
= hcErrorCode
;
2255 DWORD
GetTokenCount() const throw()
2257 return (DWORD
) m_arrTokens
.GetCount();
2260 const StencilToken
* GetToken(DWORD dwIndex
) const throw()
2262 return &(m_arrTokens
[dwIndex
]);
2265 StencilToken
* GetToken(DWORD dwIndex
) throw()
2267 return &(m_arrTokens
[dwIndex
]);
2270 LPCSTR
GetBufferStart() const throw()
2272 return m_pBufferStart
;
2275 LPCSTR
GetBufferEnd() const throw()
2277 return m_pBufferEnd
;
2280 WORD
GetCodePage() const throw()
2285 // IMemoryCacheClient
2286 STDMETHOD(QueryInterface
)(REFIID riid
, void **ppv
)
2291 if (InlineIsEqualGUID(riid
, __uuidof(IUnknown
)) ||
2292 InlineIsEqualGUID(riid
, __uuidof(IMemoryCacheClient
)))
2294 *ppv
= static_cast<IMemoryCacheClient
*>(this);
2299 return E_NOINTERFACE
;
2302 STDMETHOD_(ULONG
, AddRef
)()
2307 STDMETHOD_(ULONG
, Release
)()
2312 STDMETHOD(Free
)(const void *pData
)
2317 ATLASSERT(*((void **) pData
) == static_cast<void*>(this));
2323 }; // class CStencil
2325 struct StencilIncludeInfo
2328 CHAR m_szQueryString
[ATL_URL_MAX_URL_LENGTH
+1];
2329 CHAR m_szFileName
[MAX_PATH
];
2333 class CIncludeServerContext
:
2334 public CComObjectRootEx
<CComMultiThreadModel
>,
2335 public CWrappedServerContext
2338 BEGIN_COM_MAP(CIncludeServerContext
)
2339 COM_INTERFACE_ENTRY(IHttpServerContext
)
2342 IWriteStream
* m_pStream
;
2343 const StencilIncludeInfo
* m_pIncludeInfo
;
2345 CIncludeServerContext() throw()
2348 m_pIncludeInfo
= NULL
;
2352 IWriteStream
*pStream
,
2353 IHttpServerContext
* pServerContext
,
2354 const StencilIncludeInfo
* pIncludeInfo
) throw()
2356 ATLASSERT(pStream
!= NULL
);
2357 ATLASSERT(pServerContext
!= NULL
);
2358 ATLASSERT(pIncludeInfo
!= NULL
);
2359 m_pStream
= pStream
;
2360 m_spParent
= pServerContext
;
2361 m_pIncludeInfo
= pIncludeInfo
;
2364 void Initialize(CIncludeServerContext
*pOtherContext
)
2366 ATLENSURE(pOtherContext
!= NULL
);
2367 m_pStream
= pOtherContext
->m_pStream
;
2368 m_spParent
= pOtherContext
->m_spParent
;
2369 m_pIncludeInfo
= pOtherContext
->m_pIncludeInfo
;
2372 LPCSTR
GetRequestMethod()
2377 LPCSTR
GetQueryString()
2379 ATLASSUME(m_pIncludeInfo
!= NULL
);
2380 return m_pIncludeInfo
->m_szQueryString
;
2383 LPCSTR
GetPathTranslated()
2385 ATLASSUME(m_pIncludeInfo
!= NULL
);
2386 return m_pIncludeInfo
->m_szFileName
;
2389 LPCSTR
GetScriptPathTranslated()
2391 ATLASSUME(m_pIncludeInfo
!= NULL
);
2392 return m_pIncludeInfo
->m_szFileName
;
2395 DWORD
GetTotalBytes()
2400 DWORD
GetAvailableBytes()
2405 BYTE
*GetAvailableData()
2410 LPCSTR
GetContentType()
2415 BOOL
WriteClient(void *pvBuffer
, DWORD
*pdwBytes
)
2417 ATLASSUME(m_pStream
!= NULL
);
2418 ATLENSURE(pvBuffer
!= NULL
);
2419 ATLENSURE(pdwBytes
!= NULL
);
2424 hr
= m_pStream
->WriteStream((LPCSTR
) pvBuffer
, *pdwBytes
, pdwBytes
);
2431 return SUCCEEDED(hr
);
2434 BOOL
ReadClient(void * /*pvBuffer*/, DWORD
* /*pdwSize*/)
2439 BOOL
AsyncReadClient(void * /*pvBuffer*/, DWORD
* /*pdwSize*/)
2444 BOOL
SendRedirectResponse(LPCSTR
/*pszRedirectURL*/)
2449 BOOL
SendResponseHeader(
2450 LPCSTR
/*pszHeader*/,
2451 LPCSTR
/*pszStatusCode*/,
2457 BOOL
DoneWithSession(DWORD
/*dwHttpStatusCode*/)
2462 BOOL
RequestIOCompletion(PFN_HSE_IO_COMPLETION
/*pfn*/, DWORD
* /*pdwContext*/)
2466 }; // class CIncludeServerContext
2468 class CIDServerContext
:
2469 public CComObjectRootEx
<CComMultiThreadModel
>,
2470 public CWrappedServerContext
2473 CHttpResponse
*m_pResponse
;
2474 CHttpRequest
*m_pRequest
;
2476 BEGIN_COM_MAP(CIDServerContext
)
2477 COM_INTERFACE_ENTRY(IHttpServerContext
)
2480 CIDServerContext() throw()
2481 : m_pResponse(NULL
), m_pRequest(NULL
)
2486 CHttpResponse
*pResponse
,
2487 CHttpRequest
*pRequest
) throw()
2489 ATLASSERT(pResponse
!= NULL
);
2490 ATLASSERT(pRequest
!= NULL
);
2491 m_pResponse
= pResponse
;
2492 m_pRequest
= pRequest
;
2498 HRESULT hr
= m_pRequest
->GetServerContext(&m_spParent
);
2499 return (SUCCEEDED(hr
));
2502 LPCSTR
GetRequestMethod()
2504 ATLASSUME(m_pRequest
!= NULL
);
2505 return m_pRequest
->GetMethodString();
2508 LPCSTR
GetQueryString()
2510 ATLASSUME(m_pRequest
!= NULL
);
2511 return m_pRequest
->GetQueryString();
2514 LPCSTR
GetPathInfo()
2516 ATLASSUME(m_pRequest
!= NULL
);
2517 return m_pRequest
->GetPathInfo();
2520 LPCSTR
GetPathTranslated()
2522 ATLASSUME(m_pRequest
!= NULL
);
2523 return m_pRequest
->GetPathTranslated();
2526 DWORD
GetTotalBytes()
2528 ATLASSUME(m_pRequest
!= NULL
);
2529 return m_pRequest
->GetTotalBytes();
2532 DWORD
GetAvailableBytes()
2534 ATLASSUME(m_pRequest
!= NULL
);
2535 return m_pRequest
->GetAvailableBytes();
2538 BYTE
*GetAvailableData()
2540 ATLASSUME(m_pRequest
!= NULL
);
2541 return m_pRequest
->GetAvailableData();
2544 LPCSTR
GetContentType()
2546 ATLASSUME(m_pRequest
!= NULL
);
2547 return m_pRequest
->GetContentType();
2550 LPCSTR
GetScriptPathTranslated()
2552 ATLASSUME(m_pRequest
!= NULL
);
2553 return m_pRequest
->GetScriptPathTranslated();
2556 BOOL
WriteClient(void *pvBuffer
, DWORD
*pdwBytes
)
2558 ATLASSUME(m_pResponse
!= NULL
);
2559 return m_pResponse
->WriteLen((LPCSTR
)pvBuffer
, *pdwBytes
);
2562 BOOL
ReadClient(void *pvBuffer
, DWORD
*pdwSize
)
2564 ATLASSUME(m_pRequest
!= NULL
);
2565 return m_pRequest
->ReadData((LPSTR
)pvBuffer
, pdwSize
);
2568 BOOL
SendRedirectResponse(LPCSTR pszRedirectURL
)
2570 ATLASSUME(m_pResponse
!= NULL
);
2571 return m_pResponse
->Redirect(pszRedirectURL
);
2576 PFN_HSE_IO_COMPLETION pfn
,
2578 LPCSTR szStatusCode
,
2579 DWORD dwBytesToWrite
,
2587 ATLASSUME(m_pResponse
!= NULL
);
2588 ATLASSUME(m_spParent
!= NULL
);
2590 m_pResponse
->Flush();
2591 return m_spParent
->TransmitFile(hFile
, pfn
, pContext
, szStatusCode
,
2592 dwBytesToWrite
, dwOffset
, pvHead
, dwHeadLen
, pvTail
, dwTailLen
, dwFlags
);
2595 }; // class CIDServerContext
2599 // CHtmlStencil is a specialization of CStencil. CHtmlStencil adds the following
2600 // capabilities to CStencil:
2602 // Support for rendering {{include }} tags
2603 // The {{include }} tags specify another stencil to be included in-place during
2604 // stencil rendering. The {{include }} tag takes a single parameter which is the
2605 // URL of the stencil to include. That URL can optionally include parameters.
2607 // {{include mystencil.srf?param1=value1}}
2609 // We also grab the handler name and the name of any subhandlers. The syntax for the
2610 // handler specification is:
2611 // {{handler MyDynamicHandler.dll/Default}}
2612 // which would cause the MyDynamicHandler.dll to be loaded. Once loaded, the stencil
2613 // processor will ask for the IReplacementHandler interface of the object named "Default".
2615 // Additional handlers can be specified after the default handler. An example of an
2616 // additional handler would be:
2617 // {{subhandler OtherHandler MyOtherHandler.dll/Default}}
2618 // would cause the MyOtherHandler.dll to be loaded. Once loaded, the stencil processor will
2619 // ask for the IReplacementHandler interface of the object named "Default" and use it in
2620 // processing the stencil anywhere it sees a stencil tag of the form
2621 // {{OtherHandler.RenderReplacement}}
2625 typedef CFixedStringT
<CStringA
, MAX_PATH
> PathStrType
;
2626 typedef CFixedStringT
<CStringA
, ATL_MAX_HANDLER_NAME_LEN
+1> HdlrNameStrType
;
2627 PathStrType strDllPath
;
2628 HdlrNameStrType strHandlerName
;
2630 CStringPair()throw()
2634 CStringPair(PathStrType
&strDllPath_
, HdlrNameStrType
&strHandlerName_
) throw(...)
2635 :strDllPath(strDllPath_
), strHandlerName(strHandlerName_
)
2639 CStringPair(CStringA
&strDllPath_
, CStringA
&strHandlerName_
) throw(...)
2640 :strDllPath(strDllPath_
), strHandlerName(strHandlerName_
)
2645 class CStringPairElementTraits
:
2646 public CElementTraitsBase
< CStringPair
>
2650 static ULONG
HashStr( ULONG nHash
, CStringElementTraits
<CStringA
>::INARGTYPE str
)
2652 ATLENSURE( str
!= NULL
);
2653 const CStringA::XCHAR
* pch
= str
;
2656 nHash
= (nHash
<<5)+nHash
+(*pch
);
2664 static ULONG
Hash( INARGTYPE pair
) throw()
2666 ULONG nHash
= HashStr(0, pair
.strDllPath
);
2667 return HashStr(nHash
, pair
.strHandlerName
);
2670 static bool CompareElements( INARGTYPE pair1
, INARGTYPE pair2
) throw()
2672 return( (pair1
.strDllPath
== pair2
.strDllPath
) && (pair1
.strHandlerName
== pair2
.strHandlerName
) );
2675 static int CompareElementsOrdered( INARGTYPE pair1
, INARGTYPE pair2
) throw()
2677 return( pair1
.strDllPath
.Compare( pair2
.strDllPath
) );
2681 class CHtmlStencil
: public CStencil
2685 ATL_NOINLINE HTTP_CODE
RenderInclude(
2686 ITagReplacer
*pReplacer
,
2687 const StencilToken
*pToken
,
2688 IWriteStream
*pWriteStream
,
2689 CStencilState
*pState
) const
2691 ATLASSUME(m_spServiceProvider
);
2692 CComPtr
<IHttpServerContext
> spServerContext
;
2693 CComPtr
<IHttpRequestLookup
> spLookup
;
2694 if (FAILED(pReplacer
->GetContext(__uuidof(IHttpServerContext
), (VOID
**) &spServerContext
)))
2696 return AtlsHttpError(500, 0);
2698 if (FAILED(pReplacer
->GetContext(__uuidof(IHttpRequestLookup
), (VOID
**) &spLookup
)))
2700 return AtlsHttpError(500, 0);
2702 return RenderInclude(m_spServiceProvider
, pWriteStream
,
2703 (StencilIncludeInfo
*)pToken
->dwData
, spServerContext
, spLookup
,
2707 ATL_NOINLINE HTTP_CODE
NoCachePage(ITagReplacer
*pReplacer
) const
2709 CComPtr
<IHttpServerContext
> spContext
;
2710 HRESULT hr
= pReplacer
->GetContext(__uuidof(IHttpServerContext
), (void **)&spContext
);
2711 if (hr
== S_OK
&& spContext
)
2713 CComQIPtr
<IPageCacheControl
> spControl
;
2714 spControl
= spContext
;
2716 spControl
->Cache(FALSE
);
2718 return HTTP_SUCCESS
;
2722 // CAllocIncludeAsyncContext is an unsupported implementation detail of RenderInclude
2723 class CAllocIncludeAsyncContext
:
2724 public CAllocContextBase
2727 CAllocIncludeAsyncContext(CIncludeServerContext
*pBase
) :
2732 HTTP_CODE
Alloc(IHttpServerContext
**ppNewContext
)
2736 return AtlsHttpError(500, ISE_SUBERR_UNEXPECTED
);
2737 *ppNewContext
= NULL
;
2738 CComObjectNoLock
<CIncludeServerContext
>* pNewServerContext
= NULL
;
2739 ATLTRY(pNewServerContext
= new CComObjectNoLock
<CIncludeServerContext
>);
2740 if (pNewServerContext
== NULL
)
2741 return AtlsHttpError(500, ISE_SUBERR_OUTOFMEM
);
2742 pNewServerContext
->Initialize(m_pBase
);
2743 pNewServerContext
->AddRef();
2744 *ppNewContext
= pNewServerContext
;
2745 return HTTP_SUCCESS
;
2749 CIncludeServerContext
*m_pBase
;
2750 }; // CAllocIncludeAsyncContext
2753 ATL_NOINLINE HTTP_CODE
RenderInclude(
2754 IServiceProvider
*pServiceProvider
,
2755 IWriteStream
*pWriteStream
,
2756 const StencilIncludeInfo
*pIncludeInfo
,
2757 IHttpServerContext
*pServerContext
,
2758 IHttpRequestLookup
*pLookup
,
2759 CStencilState
* pState
= NULL
) const throw(...)
2761 CComObjectStackEx
<CIncludeServerContext
> serverContext
;
2762 serverContext
.Initialize(pWriteStream
, pServerContext
, pIncludeInfo
);
2763 CAllocIncludeAsyncContext
AsyncAllocObj(&serverContext
);
2764 return _AtlRenderInclude(static_cast<IHttpServerContext
*>(&serverContext
),
2765 pIncludeInfo
->m_szFileName
,
2766 pIncludeInfo
->m_szQueryString
,
2776 CAtlMap
<CStringA
, CStringPair
,
2777 CStringElementTraits
<CStringA
>, CStringPairElementTraits
> m_arrExtraHandlers
;
2778 CHAR m_szBaseDir
[MAX_PATH
];
2779 CComPtr
<IServiceProvider
> m_spServiceProvider
;
2780 CComPtr
<IIsapiExtension
> m_spExtension
;
2781 CComPtr
<IStencilCache
> m_spStencilCache
;
2782 CComPtr
<IDllCache
> m_spDllCache
;
2785 typedef CAtlMap
<CStringA
, CStringPair
,
2786 CStringElementTraits
<CStringA
>, CStringPairElementTraits
> mapType
;
2787 typedef CStencil baseType
;
2789 CHtmlStencil(IAtlMemMgr
*pMemMgr
=NULL
) throw() :
2795 void Initialize(IServiceProvider
*pProvider
) throw(...)
2797 ATLENSURE(pProvider
);
2798 if (m_spServiceProvider
)
2799 m_spServiceProvider
.Release();
2801 m_spServiceProvider
= pProvider
;
2803 pProvider
->QueryService(__uuidof(IDllCache
), __uuidof(IDllCache
), (void **) &m_spDllCache
);
2806 pProvider
->QueryInterface(__uuidof(IIsapiExtension
), (void **) &m_spExtension
);
2809 BOOL
GetIncludeInfo(LPCSTR szParamBegin
, LPCSTR szParamEnd
, StencilIncludeInfo
*pInfo
) const
2811 ATLENSURE(szParamBegin
!= NULL
);
2812 ATLENSURE(szParamEnd
!= NULL
);
2813 ATLENSURE(pInfo
!= NULL
);
2815 LPCSTR szQueryBegin
= szParamBegin
;
2817 while (*szQueryBegin
&& *szQueryBegin
!= '?' && *szQueryBegin
!= '}')
2819 LPSTR szNext
= CharNextExA(GetCodePage(), szQueryBegin
, 0);
2820 if (szNext
== szQueryBegin
)
2825 szQueryBegin
= szNext
;
2828 CFixedStringT
<CStringA
, MAX_PATH
> strPath
;
2832 DWORD dwPrefixLen
= 0;
2833 if (*szParamBegin
== '"')
2837 if (!IsFullPathA(szParamBegin
))
2839 if (*szParamBegin
!= '\\')
2841 strPath
= m_szBaseDir
;
2845 LPCSTR szBackslash
= strchr(m_szBaseDir
, '\\');
2848 #pragma warning(push)
2849 #pragma warning(disable: 6204)
2850 /* prefast noise VSW 492749 */
2851 strPath
.SetString(m_szBaseDir
, (int)(szBackslash
-m_szBaseDir
));
2852 #pragma warning(pop)
2856 strPath
= m_szBaseDir
;
2859 dwPrefixLen
= strPath
.GetLength();
2862 if (*szQueryBegin
=='?')
2864 size_t nMinus
= (*(szQueryBegin
-1) == '"') ? 1 : 0;
2865 strPath
.Append(szParamBegin
, (int)(szQueryBegin
-szParamBegin
-nMinus
));
2866 if ((szParamEnd
-szQueryBegin
) > ATL_URL_MAX_PATH_LENGTH
|| ((szParamEnd
- szQueryBegin
) < 0))
2868 // query string is too long
2871 Checked::memcpy_s(pInfo
->m_szQueryString
, ATL_URL_MAX_URL_LENGTH
+1, szQueryBegin
+ 1, szParamEnd
- szQueryBegin
);
2872 pInfo
->m_szQueryString
[szParamEnd
- szQueryBegin
] = '\0';
2876 pInfo
->m_szQueryString
[0] = '\0';
2877 size_t nAdd
= (*szParamEnd
== '"') ? 0 : 1;
2878 strPath
.Append(szParamBegin
, (int)(szParamEnd
- szParamBegin
+ nAdd
));
2887 if (strPath
.GetLength() > MAX_PATH
-1)
2893 // strPath is <= MAX_PATH-1
2894 return PathCanonicalizeA(pInfo
->m_szFileName
, strPath
);
2897 DWORD
ParseInclude(LPCSTR szTokenStart
, LPCSTR szTokenEnd
) throw(...)
2899 ATLENSURE(szTokenStart
!= NULL
);
2900 ATLENSURE(szTokenEnd
!= NULL
);
2902 LPCSTR szStart
= szTokenStart
;
2903 LPCSTR szEnd
= szTokenEnd
;
2905 FindTagArgs(szStart
, szEnd
, 7);
2907 CFixedStringT
<CStringA
, MAX_PATH
> strFileNameRelative
;
2908 CFixedStringT
<CString
, MAX_PATH
> strFileName
;
2912 strFileNameRelative
.SetString(szStart
, (int)(szEnd
-szStart
+ 1));
2914 if (!IsFullPathA(strFileNameRelative
))
2916 CFixedStringT
<CStringA
, MAX_PATH
> strTemp
;
2917 if (*((LPCSTR
)strFileNameRelative
) != '\\')
2919 strTemp
= m_szBaseDir
;
2923 LPCSTR szBackslash
= strchr(m_szBaseDir
, '\\');
2926 #pragma warning(push)
2927 #pragma warning(disable: 6204)
2928 #pragma warning(disable: 6535)
2929 /* prefast noise VSW 492749 */
2930 /* prefast noise VSW 493256 */
2931 strTemp
.SetString(m_szBaseDir
, (int)(szBackslash
-m_szBaseDir
));
2932 #pragma warning(pop)
2936 strTemp
= m_szBaseDir
;
2940 strTemp
.Append(strFileNameRelative
, strFileNameRelative
.GetLength());
2941 CFixedStringT
<CString
, MAX_PATH
> strConv
= (LPCTSTR
) CA2CT(strTemp
);
2942 LPTSTR szFileBuf
= strFileName
.GetBuffer(strConv
.GetLength()+1);
2943 if (szFileBuf
== NULL
)
2945 AddError(IDS_STENCIL_OUTOFMEMORY
, szTokenStart
);
2946 return AddToken(szTokenStart
, szTokenEnd
, STENCIL_TEXTTAG
);
2949 if (!PathCanonicalize(szFileBuf
, strConv
))
2951 return STENCIL_INVALIDINDEX
;
2954 strFileName
.ReleaseBuffer();
2958 strFileName
= CA2CTEX
<MAX_PATH
>(strFileNameRelative
);
2963 AddError(IDS_STENCIL_OUTOFMEMORY
, szTokenStart
);
2964 return AddToken(szTokenStart
, szTokenEnd
, STENCIL_TEXTTAG
);
2967 LPCTSTR szFileName
= strFileName
;
2969 LPCTSTR szDot
= NULL
;
2970 LPCTSTR szExtra
= _tcschr(szFileName
, '?');
2973 szExtra
= _tcschr(szFileName
, '#');
2976 szDot
= _tcsrchr(szFileName
, '.');
2980 if (szExtra
!= NULL
)
2982 // there is some extra information
2983 LPCTSTR szDotTmp
= szFileName
;
2987 szDotTmp
= _tcschr(szDotTmp
+1, '.');
2988 } while (szDotTmp
&& szDotTmp
< szExtra
);
2991 if (!szDot
|| *szDot
!= '.')
2993 AddError(IDS_STENCIL_UNEXPECTED
, szTokenStart
);
2994 return AddToken(szTokenStart
, szTokenEnd
, STENCIL_TEXTTAG
);
2997 LPCTSTR szExtEnd
= szDot
;
3002 if (!*szExtEnd
|| *szExtEnd
== '/' || *szExtEnd
== '\\' || *szExtEnd
== '?' || *szExtEnd
== '#' || *szExtEnd
== '"')
3006 if (szDot
&& (size_t)(szExtEnd
-szDot
) == _tcslen(c_tAtlDLLExtension
) &&
3007 !_tcsnicmp(szDot
, c_tAtlDLLExtension
, _tcslen(c_tAtlDLLExtension
)))
3010 DWORD dwIndex
= AddToken(szStart
, szEnd
, STENCIL_STENCILINCLUDE
);
3011 if (dwIndex
== STENCIL_INVALIDINDEX
)
3013 AddError(IDS_STENCIL_OUTOFMEMORY
, szTokenStart
);
3014 return AddToken(szTokenStart
, szTokenEnd
, STENCIL_TEXTTAG
);
3016 StencilIncludeInfo
*pInfo
= (StencilIncludeInfo
*)m_pMemMgr
->Allocate(sizeof(StencilIncludeInfo
));
3019 return STENCIL_INVALIDINDEX
;
3022 if (!GetIncludeInfo(szStart
, szEnd
, pInfo
))
3024 return STENCIL_INVALIDINDEX
;
3027 GetToken(dwIndex
)->dwData
= (DWORD_PTR
) pInfo
;
3030 else if (szDot
&& (size_t)(szExtEnd
-szDot
) == _tcslen(c_tAtlSRFExtension
) &&
3031 !_tcsnicmp(szDot
, c_tAtlSRFExtension
, _tcslen(c_tAtlSRFExtension
)))
3034 DWORD dwIndex
= AddToken(szStart
, szEnd
, STENCIL_STENCILINCLUDE
);
3035 if (dwIndex
== STENCIL_INVALIDINDEX
)
3037 AddError(IDS_STENCIL_OUTOFMEMORY
, szTokenStart
);
3038 return AddToken(szTokenStart
, szTokenEnd
, STENCIL_TEXTTAG
);
3040 StencilIncludeInfo
*pInfo
= (StencilIncludeInfo
*)m_pMemMgr
->Allocate(sizeof(StencilIncludeInfo
));
3043 return STENCIL_INVALIDINDEX
;
3046 if (!GetIncludeInfo(szStart
, szEnd
, pInfo
))
3048 return STENCIL_INVALIDINDEX
;
3051 GetToken(dwIndex
)->dwData
= (DWORD_PTR
) pInfo
;
3056 // Assume static content
3059 HRESULT hr
= file
.Create(szFileName
, GENERIC_READ
, FILE_SHARE_READ
, OPEN_EXISTING
);
3060 if (FAILED(hr
) || GetFileType(file
) != FILE_TYPE_DISK
)
3064 AddError(IDS_STENCIL_INCLUDE_ERROR
, szTokenStart
);
3068 AddError(IDS_STENCIL_INCLUDE_INVALID
, szTokenStart
);
3070 return AddToken(szTokenStart
, szTokenEnd
, STENCIL_TEXTTAG
);
3073 CAutoVectorPtr
<CHAR
> szBufferStart
;
3074 LPSTR szBufferEnd
= NULL
;
3075 ULONGLONG dwLen
= 0;
3076 if (FAILED(file
.GetSize(dwLen
)))
3078 return AddToken(szTokenStart
, szTokenEnd
, STENCIL_TEXTTAG
);
3081 if (!szBufferStart
.Allocate((size_t) dwLen
))
3083 AddError(IDS_STENCIL_OUTOFMEMORY
, szTokenStart
);
3084 return AddToken(szTokenStart
, szTokenEnd
, STENCIL_TEXTTAG
);
3088 if (FAILED(file
.Read(szBufferStart
, (DWORD
) dwLen
, dwRead
)))
3090 return AddToken(szTokenStart
, szTokenEnd
, STENCIL_TEXTTAG
);
3093 szBufferEnd
= szBufferStart
+ dwRead
-1;
3095 DWORD dwIndex
= AddToken(szBufferStart
, szBufferEnd
, STENCIL_STATICINCLUDE
);
3096 if (dwIndex
!= STENCIL_INVALIDINDEX
)
3098 GetToken(dwIndex
)->bDynamicAlloc
= TRUE
;
3099 szBufferStart
.Detach();
3106 PARSE_TOKEN_RESULT
ParseSubhandler(LPCSTR szTokenStart
, LPCSTR szTokenEnd
) throw()
3108 ATLASSERT(szTokenStart
!= NULL
);
3109 ATLASSERT(szTokenEnd
!= NULL
);
3111 LPCSTR szStart
= szTokenStart
;
3112 LPCSTR szEnd
= szTokenEnd
;
3114 // move to the start of the arguments
3115 // (the first char past 'subhandler'
3116 FindTagArgs(szStart
, szEnd
, 10);
3118 // skip any space to bring us to the start
3119 // of the id for the subhandler.
3120 szStart
= SkipSpace(szStart
, GetCodePage());
3122 // id names cannot contain spaces. Mark the
3123 // beginning and end if the subhandler id
3124 LPCSTR szIdStart
= szStart
;
3125 while (!isspace(static_cast<unsigned char>(*szStart
)) && *szStart
!= '}')
3127 if (!isalnum(static_cast<unsigned char>(*szStart
)))
3129 // id names can only contain alphanumeric characters
3130 return INVALID_TOKEN
;
3133 LPSTR szNext
= CharNextExA(GetCodePage(), szStart
, 0);
3134 if (szNext
== szStart
)
3137 AddError(IDS_STENCIL_EMBEDDED_NULL
, NULL
);
3138 return INVALID_TOKEN
;
3142 LPCSTR szIdEnd
= szStart
;
3144 // skip space to bring us to the beginning of the
3145 // the dllpath/handlername
3146 szStart
= SkipSpace(szStart
, GetCodePage());
3148 // everything up to the end if the tag is
3149 // part of the dllpath/handlername
3150 LPCSTR szHandlerStart
= szStart
;
3151 while (*szStart
!= '}')
3153 LPCSTR szNext
= CharNextExA(GetCodePage(), szStart
, 0);
3154 if (szNext
== szStart
)
3157 AddError(IDS_STENCIL_EMBEDDED_NULL
, NULL
);
3158 return INVALID_TOKEN
;
3162 LPCSTR szHandlerEnd
= szStart
;
3166 CStringPair::HdlrNameStrType
strName(szIdStart
, (int)(szIdEnd
-szIdStart
));
3167 CStringPair::PathStrType
strPath(szHandlerStart
, (int)(szHandlerEnd
-szHandlerStart
));
3169 CStringPair::PathStrType strDllPath
;
3170 CStringPair::HdlrNameStrType strHandlerName
;
3171 DWORD dwDllPathLen
= MAX_PATH
;
3172 DWORD dwHandlerNameLen
= ATL_MAX_HANDLER_NAME_LEN
+1;
3174 LPSTR szDllPath
= strDllPath
.GetBuffer(dwDllPathLen
);
3175 LPSTR szHandlerName
= strHandlerName
.GetBuffer(dwHandlerNameLen
);
3177 if (!_AtlCrackHandler(strPath
, szDllPath
, &dwDllPathLen
, szHandlerName
, &dwHandlerNameLen
))
3179 strDllPath
.ReleaseBuffer();
3180 strHandlerName
.ReleaseBuffer();
3181 AddError(IDS_STENCIL_INVALID_SUBHANDLER
, szTokenStart
);
3182 return INVALID_TOKEN
;
3185 strDllPath
.ReleaseBuffer(dwDllPathLen
);
3186 strHandlerName
.ReleaseBuffer(dwHandlerNameLen
);
3188 m_arrExtraHandlers
.SetAt(strName
, CStringPair(strDllPath
, strHandlerName
));
3192 AddError(IDS_STENCIL_OUTOFMEMORY
, NULL
);
3193 return INVALID_TOKEN
;
3195 return RESERVED_TOKEN
;
3198 virtual PARSE_TOKEN_RESULT
ParseToken(LPCSTR szTokenStart
, LPCSTR szTokenEnd
, DWORD
*pBlockStack
, DWORD
*pdwTop
)
3200 ATLASSERT(szTokenStart
!= NULL
);
3201 ATLASSERT(szTokenEnd
!= NULL
);
3203 LPCSTR pStart
= szTokenStart
;
3204 pStart
+= 2; //skip curlies
3205 pStart
= SkipSpace(pStart
, GetCodePage());
3206 DWORD dwLen
= (DWORD
)(szTokenEnd
- szTokenStart
);
3208 DWORD dwIndex
= STENCIL_INVALIDINDEX
;
3210 if (CheckTag("include", sizeof("include")-1, pStart
, dwLen
))
3212 dwIndex
= ParseInclude(szTokenStart
, szTokenEnd
);
3214 else if (dwLen
> 3 && !memcmp("!--", pStart
, 3))
3216 return RESERVED_TOKEN
;
3218 else if (dwLen
> 2 && !memcmp("//", pStart
, 2))
3220 return RESERVED_TOKEN
;
3222 else if (CheckTag("subhandler", sizeof("subhandler")-1, pStart
, dwLen
))
3224 return ParseSubhandler(szTokenStart
, szTokenEnd
);
3228 return CStencil::ParseToken(szTokenStart
, szTokenEnd
, pBlockStack
, pdwTop
);
3230 if (dwIndex
== STENCIL_INVALIDINDEX
)
3232 return INVALID_TOKEN
;
3234 return RESERVED_TOKEN
;
3237 mapType
* GetExtraHandlers() throw()
3239 return &m_arrExtraHandlers
;
3242 BOOL
SetBaseDirFromFile(LPCSTR szBaseDir
)
3244 if (!SafeStringCopy(m_szBaseDir
, szBaseDir
))
3249 LPSTR szSlash
= strrchr(m_szBaseDir
, '\\');
3257 *m_szBaseDir
= '\0';
3270 ITagReplacer
* pReplacer
,
3271 IWriteStream
*pWriteStream
,
3272 HTTP_CODE
*phcErrorCode
,
3273 CStencilState
* pState
= NULL
) const throw(...)
3275 DWORD dwNextToken
= STENCIL_INVALIDINDEX
;
3276 HTTP_CODE hcErrorCode
= HTTP_SUCCESS
;
3277 const StencilToken
* pToken
= GetToken(dwIndex
);
3280 if (pToken
->type
== STENCIL_STENCILINCLUDE
)
3282 hcErrorCode
= RenderInclude(pReplacer
, pToken
, pWriteStream
, pState
);
3283 if (hcErrorCode
== HTTP_SUCCESS
|| IsAsyncDoneStatus(hcErrorCode
))
3285 dwNextToken
= dwIndex
+1;
3287 else if (IsAsyncContinueStatus(hcErrorCode
))
3289 dwNextToken
= dwIndex
;
3292 else if (pToken
->type
== STENCIL_STATICINCLUDE
)
3294 pWriteStream
->WriteStream(pToken
->pStart
,
3295 (int)((pToken
->pEnd
-pToken
->pStart
)+1), NULL
);
3296 dwNextToken
= dwIndex
+1;
3300 dwNextToken
= baseType::RenderToken(dwIndex
, pReplacer
,
3301 pWriteStream
, &hcErrorCode
, pState
);
3305 if (hcErrorCode
== HTTP_SUCCESS_NO_CACHE
)
3307 hcErrorCode
= NoCachePage(pReplacer
);
3312 *phcErrorCode
= hcErrorCode
;
3316 }; // class CHtmlStencil
3319 __declspec(selectany
) CCRTHeap
CStencil::m_crtHeap
;
3323 // This class manages CStencil based objects for HTTP requests. This class will retrieve
3324 // CStencil based objects from the stencil cache, store CStencil based objects in the
3325 // stencil cache and allocate and initialize CStencil based objects on a per reqeust
3326 // basis. Typically, one instance of this class is created for each HTTP request. The
3327 // instance is destroyed once the request has been completed.
3328 template <class THandler
, class StencilType
=CHtmlStencil
>
3329 class CHtmlTagReplacer
:
3330 public ITagReplacerImpl
<THandler
>
3333 typedef StencilType StencilType
;
3335 CSimpleArray
<HINSTANCE
> m_hInstHandlers
;
3336 typedef CAtlMap
<CStringA
, IRequestHandler
*, CStringElementTraits
<CStringA
> > mapType
;
3338 StencilType
*m_pLoadedStencil
;
3340 CComPtr
<IStencilCache
> m_spStencilCache
;
3342 AtlServerRequest m_RequestInfo
;
3347 CHtmlTagReplacer() throw() :
3348 m_pLoadedStencil(NULL
)
3350 memset(&m_RequestInfo
, 0x00, sizeof(m_RequestInfo
));
3351 m_nCodePage
= CP_THREAD_ACP
;
3354 ~CHtmlTagReplacer() throw()
3356 // you should call FreeHandlers before
3357 // the object is destructed
3358 ATLASSUME(m_hInstHandlers
.GetSize() == 0);
3361 HTTP_CODE
Initialize(AtlServerRequest
*pRequestInfo
, IHttpServerContext
*pSafeSrvCtx
=NULL
) throw(...)
3363 ATLASSERT(pRequestInfo
!= NULL
);
3365 CComPtr
<IServiceProvider
> spServiceProvider
;
3366 THandler
*pT
= static_cast<THandler
*>(this);
3367 HRESULT hr
= pT
->GetContext(__uuidof(IServiceProvider
), (void **)&spServiceProvider
);
3371 spServiceProvider
->QueryService(__uuidof(IStencilCache
), __uuidof(IStencilCache
), (void **) &m_spStencilCache
);
3372 if (!m_spStencilCache
)
3378 // copy the AtlServerRequest into the safe version
3379 Checked::memcpy_s(&m_RequestInfo
, sizeof(m_RequestInfo
), pRequestInfo
, sizeof(m_RequestInfo
));
3381 // override appropriate fields
3382 m_RequestInfo
.cbSize
= sizeof(m_RequestInfo
);
3383 m_RequestInfo
.pServerContext
= pSafeSrvCtx
;
3385 return HTTP_SUCCESS
;
3388 HTTP_CODE
LoadStencilResource(
3389 HINSTANCE hInstResource
,
3390 LPCSTR szResourceID
,
3391 LPCSTR szResourceType
= NULL
, LPCSTR szStencilName
=NULL
) throw(...)
3393 if (!szResourceType
)
3394 szResourceType
= (LPCSTR
) (RT_HTML
);
3395 // look up stencil in cache
3396 HTTP_CODE hcErr
= HTTP_SUCCESS
;
3398 // check the cache first
3399 StencilType
*pStencil
= FindCacheStencil(szStencilName
? szStencilName
: szResourceID
);
3402 // create a new stencil
3403 pStencil
= GetNewCacheStencil();
3406 return AtlsHttpError(500,ISE_SUBERR_OUTOFMEM
);
3409 THandler
*pT
= static_cast<THandler
*>(this);
3410 LPCSTR szFileName
= pT
->m_spServerContext
->GetScriptPathTranslated();
3415 if (!pStencil
->SetBaseDirFromFile(szFileName
))
3420 pStencil
->SetErrorResource(GetResourceInstance());
3422 // load the stencil and parse its replacements
3423 if (HTTP_SUCCESS
== pStencil
->LoadFromResource(hInstResource
,
3424 szResourceID
, szResourceType
))
3428 if (!pStencil
->ParseReplacements(this))
3430 return AtlsHttpError(500, ISE_SUBERR_BADSRF
);
3433 hcErr
= FinishLoadStencil(pStencil
, NULL
);
3436 #ifdef ATL_DEBUG_STENCILS
3437 pStencil
->FinishParseReplacements();
3439 if (!pStencil
->FinishParseReplacements())
3441 return AtlsHttpError(500, ISE_SUBERR_BADSRF
);
3443 #endif // ATL_DEBUG_STENCILS
3456 // if everything went OK, put the stencil in the stencil cache.
3459 hcErr
= CacheStencil(szStencilName
? szStencilName
: szResourceID
, pStencil
);
3462 if (pStencil
&& hcErr
) // something went wrong, free the stencil data
3464 FreeCacheStencil(pStencil
);
3469 hcErr
= FinishLoadStencil(pStencil
);
3475 HTTP_CODE
LoadStencilResource(HINSTANCE hInstResource
, UINT nID
, LPCSTR szResourceType
= NULL
) throw(...)
3477 if (!szResourceType
)
3478 szResourceType
= (LPCSTR
) RT_HTML
;
3480 int nResult
= sprintf_s(szName
, sizeof(szName
), "%p/%u", hInstResource
, nID
);
3481 if ((nResult
< 0) || (nResult
== sizeof(szName
)))
3485 return LoadStencilResource(hInstResource
, MAKEINTRESOURCEA(nID
), szResourceType
, szName
);
3488 HTTP_CODE
LoadStencil(LPCSTR szFileName
, IHttpRequestLookup
* pLookup
= NULL
) throw(...)
3495 HTTP_CODE hcErr
= HTTP_FAIL
;
3496 // try to find the stencil in the cache
3497 StencilType
*pStencil
= FindCacheStencil(szFileName
);
3501 // not in cache. Create a new one
3502 pStencil
= GetNewCacheStencil();
3505 return AtlsHttpError(500, ISE_SUBERR_OUTOFMEM
); // out of memory!
3508 if (!pStencil
->SetBaseDirFromFile(szFileName
))
3513 pStencil
->SetErrorResource(GetResourceInstance());
3516 hcErr
= pStencil
->LoadFromFile(szFileName
);
3521 if (!pStencil
->ParseReplacements(static_cast<ITagReplacer
*>(this)))
3523 return AtlsHttpError(500, ISE_SUBERR_BADSRF
);
3526 hcErr
= FinishLoadStencil(pStencil
, pLookup
);
3529 #ifdef ATL_DEBUG_STENCILS
3530 pStencil
->FinishParseReplacements();
3532 if (!pStencil
->FinishParseReplacements())
3534 return AtlsHttpError(500, ISE_SUBERR_BADSRF
);
3536 #endif // ATL_DEBUG_STENCILS
3545 // if everything is OK, cache the stencil
3548 hcErr
= CacheStencil(szFileName
, pStencil
);
3551 if (pStencil
&& hcErr
) // something went wrong, free stencil data
3552 FreeCacheStencil(pStencil
);
3556 hcErr
= FinishLoadStencil(pStencil
, pLookup
);
3561 HTTP_CODE
RenderStencil(IWriteStream
* pStream
, CStencilState
* pState
= NULL
) throw(...)
3563 if (!m_pLoadedStencil
)
3564 return AtlsHttpError(500, ISE_SUBERR_UNEXPECTED
);
3566 WORD nCodePage
= m_pLoadedStencil
->GetCodePage();
3567 if (nCodePage
!= CP_ACP
)
3568 m_nCodePage
= nCodePage
;
3570 HTTP_CODE hcErr
= HTTP_FAIL
;
3572 hcErr
= m_pLoadedStencil
->Render(static_cast<ITagReplacer
*>(this),
3575 if (!IsAsyncStatus(hcErr
) && m_pLoadedStencil
->GetCacheItem())
3576 m_spStencilCache
->ReleaseStencil(m_pLoadedStencil
->GetCacheItem());
3584 void FreeHandlers() throw(...)
3586 POSITION pos
= m_Handlers
.GetStartPosition();
3589 m_Handlers
.GetValueAt(pos
)->UninitializeHandler();
3590 m_Handlers
.GetNextValue(pos
)->Release();
3592 m_Handlers
.RemoveAll();
3594 int nLen
= m_hInstHandlers
.GetSize();
3597 THandler
*pT
= static_cast<THandler
*>(this);
3598 CComPtr
<IDllCache
> spDllCache
;
3599 pT
->m_spServiceProvider
->QueryService(__uuidof(IDllCache
), __uuidof(IDllCache
),
3600 (void **)&spDllCache
);
3601 for (int i
=0; i
<nLen
; i
++)
3603 spDllCache
->Free(m_hInstHandlers
[i
]);
3605 m_hInstHandlers
.RemoveAll();
3609 StencilType
* GetNewCacheStencil() throw(...)
3611 StencilType
*pStencil
= NULL
;
3612 THandler
*pT
= static_cast<THandler
*>(this);
3613 IAtlMemMgr
*pMemMgr
;
3614 if (FAILED(pT
->m_spServiceProvider
->QueryService(__uuidof(IAtlMemMgr
), __uuidof(IAtlMemMgr
), (void **)&pMemMgr
)))
3617 ATLTRY(pStencil
= new StencilType(pMemMgr
));
3618 if (pStencil
!= NULL
)
3620 pStencil
->Initialize(pT
->m_spServiceProvider
);
3625 HTTP_CODE
CacheStencil(
3627 StencilType
* pStencilData
) throw()
3629 THandler
*pT
= static_cast<THandler
*>(this);
3630 HRESULT hr
= E_FAIL
;
3632 HCACHEITEM hCacheItem
= NULL
;
3634 hr
= m_spStencilCache
->CacheStencil(szName
,
3636 sizeof(StencilType
*),
3639 static_cast<IMemoryCacheClient
*>(pStencilData
));
3641 if (hr
== S_OK
&& hCacheItem
)
3645 pStencilData
->SetCacheItem(hCacheItem
);
3653 return (hr
== S_OK
) ? HTTP_SUCCESS
: HTTP_FAIL
;
3656 StencilType
*FindCacheStencil(LPCSTR szName
) throw()
3658 if (!szName
|| !m_spStencilCache
)
3661 StencilType
*pStencilData
= NULL
;
3663 HCACHEITEM hStencil
;
3665 if (m_spStencilCache
->LookupStencil(szName
, &hStencil
) != S_OK
)
3668 m_spStencilCache
->GetStencil(hStencil
, reinterpret_cast<void **>(&pStencilData
));
3670 return pStencilData
;
3673 void FreeCacheStencil(StencilType
* pStencilData
)
3675 ATLASSERT( pStencilData
!= NULL
);
3682 IMemoryCacheClient
*pMemCacheClient
= static_cast<IMemoryCacheClient
*>(pStencilData
);
3684 if(!pMemCacheClient
)
3691 pMemCacheClient
->Free(pStencilData
);
3698 HTTP_CODE
GetHandlerOffset(LPCSTR szHandlerName
, DWORD
* pdwOffset
)
3703 mapType::CPair
*p
= m_Handlers
.Lookup(szHandlerName
);
3707 POSITION pos
= m_Handlers
.GetStartPosition();
3710 const mapType::CPair
*p1
= m_Handlers
.GetNext(pos
);
3713 *pdwOffset
= dwIndex
;
3714 return HTTP_SUCCESS
;
3724 HTTP_CODE
GetReplacementObject(DWORD dwObjOffset
, ITagReplacer
**ppReplacer
)
3726 HRESULT hr
= E_FAIL
;
3728 POSITION pos
= m_Handlers
.GetStartPosition();
3729 for (DWORD dwIndex
=0; dwIndex
< dwObjOffset
; dwIndex
++)
3730 m_Handlers
.GetNext(pos
);
3732 ATLASSERT(pos
!= NULL
);
3734 IRequestHandler
*pHandler
= NULL
;
3735 pHandler
= m_Handlers
.GetValueAt(pos
);
3737 ATLENSURE(pHandler
!= NULL
);
3739 hr
= pHandler
->QueryInterface(__uuidof(ITagReplacer
), (void**)ppReplacer
);
3744 return HTTP_SUCCESS
;
3747 // This is where we would actually load any extra request
3748 // handlers the HTML stencil might have parsed for us.
3749 HTTP_CODE
FinishLoadStencil(StencilType
*pStencil
, IHttpRequestLookup
* pLookup
= NULL
) throw(...)
3751 THandler
*pT
= static_cast<THandler
*>(this);
3752 ATLASSERT(pStencil
);
3754 return AtlsHttpError(500, ISE_SUBERR_UNEXPECTED
); // unexpected condition
3755 m_pLoadedStencil
= pStencil
;
3756 //load extra handlers if there are any
3757 StencilType::mapType
*pExtraHandlersMap
=
3758 pStencil
->GetExtraHandlers();
3760 if (pExtraHandlersMap
)
3762 POSITION pos
= pExtraHandlersMap
->GetStartPosition();
3765 IRequestHandler
*pHandler
;
3766 HINSTANCE hInstHandler
;
3769 pExtraHandlersMap
->GetNextAssoc(pos
, name
, path
);
3771 hInstHandler
= NULL
;
3772 HTTP_CODE hcErr
= pT
->m_spExtension
->LoadRequestHandler(path
.strDllPath
, path
.strHandlerName
,
3773 pT
->m_spServerContext
,
3780 //map the name to the pointer to request handler
3781 m_Handlers
.SetAt(name
, pHandler
);
3782 //store HINSTANCE of handler
3783 m_hInstHandlers
.Add(hInstHandler
);
3792 hcErr
= pHandler
->InitializeChild(&m_RequestInfo
, pT
->m_spServiceProvider
, pLookup
);
3793 if (hcErr
!= HTTP_SUCCESS
)
3802 return HTTP_SUCCESS
;
3804 }; // class CHtmlTagReplacer
3808 // This is the base class for all user request handlers. This class implements
3809 // the IReplacementHandler interface whose methods will be called to render HTML
3810 // into a stream. The stream will be returned as the HTTP response upon completion
3811 // of the HTTP request.
3812 template < class THandler
,
3813 class ThreadModel
=CComSingleThreadModel
,
3814 class TagReplacerType
=CHtmlTagReplacer
<THandler
>
3816 class CRequestHandlerT
:
3817 public TagReplacerType
,
3818 public CComObjectRootEx
<ThreadModel
>,
3819 public IRequestHandlerImpl
<THandler
>
3822 CStencilState m_state
;
3823 CComObjectStackEx
<CIDServerContext
> m_SafeSrvCtx
;
3824 typedef CRequestHandlerT
<THandler
, ThreadModel
, TagReplacerType
> _requestHandler
;
3827 BEGIN_COM_MAP(_requestHandler
)
3828 COM_INTERFACE_ENTRY(IRequestHandler
)
3829 COM_INTERFACE_ENTRY(ITagReplacer
)
3832 // public CRequestHandlerT members
3833 CHttpResponse m_HttpResponse
;
3834 CHttpRequest m_HttpRequest
;
3835 ATLSRV_REQUESTTYPE m_dwRequestType
;
3836 AtlServerRequest
* m_pRequestInfo
;
3838 CRequestHandlerT() throw()
3840 m_hInstHandler
= NULL
;
3842 m_pRequestInfo
= NULL
;
3845 ~CRequestHandlerT() throw()
3849 FreeHandlers(); // free handlers held by CTagReplacer
3856 void ClearResponse() throw()
3858 m_HttpResponse
.ClearResponse();
3860 // Where user initialization should take place
3861 HTTP_CODE
ValidateAndExchange()
3863 return HTTP_SUCCESS
; // continue processing request
3866 // Where user Uninitialization should take place
3867 HTTP_CODE
Uninitialize(HTTP_CODE hcError
)
3872 HTTP_CODE
InitializeInternal(AtlServerRequest
*pRequestInfo
, IServiceProvider
*pProvider
)
3874 // Initialize our internal references to required services
3875 m_pRequestInfo
= pRequestInfo
;
3876 m_state
.pParentInfo
= pRequestInfo
;
3877 m_hInstHandler
= pRequestInfo
->hInstDll
;
3878 m_spServerContext
= pRequestInfo
->pServerContext
;
3879 m_spServiceProvider
= pProvider
;
3880 return HTTP_SUCCESS
;
3883 HTTP_CODE
InitializeHandler(
3884 AtlServerRequest
*pRequestInfo
,
3885 IServiceProvider
*pProvider
)
3887 HTTP_CODE hcErr
= HTTP_FAIL
;
3888 ATLASSERT(pRequestInfo
);
3889 ATLASSERT(pProvider
);
3891 THandler
* pT
= static_cast<THandler
*>(this);
3892 hcErr
= pT
->InitializeInternal(pRequestInfo
, pProvider
);
3895 m_HttpResponse
.Initialize(m_spServerContext
);
3896 hcErr
= pT
->CheckValidRequest();
3900 if (m_HttpRequest
.Initialize(m_spServerContext
,
3904 if (m_SafeSrvCtx
.Initialize(&m_HttpResponse
, &m_HttpRequest
))
3906 hcErr
= TagReplacerType::Initialize(pRequestInfo
, &m_SafeSrvCtx
);
3909 hcErr
= pT
->ValidateAndExchange();
3918 HTTP_CODE
InitializeChild(
3919 AtlServerRequest
*pRequestInfo
,
3920 IServiceProvider
*pProvider
,
3921 IHttpRequestLookup
*pRequestLookup
)
3923 ATLASSERT(pRequestInfo
);
3924 ATLASSERT(pProvider
);
3926 THandler
*pT
= static_cast<THandler
*>(this);
3927 HTTP_CODE hcErr
= pT
->InitializeInternal(pRequestInfo
, pProvider
);
3933 // initialize with the pRequestLookup
3934 if(!m_HttpResponse
.Initialize(pRequestLookup
))
3939 // Initialize with the IHttpServerContext if it exists
3940 // the only time this is different than the previous call to
3941 // initialize is if the user passes a different IHttpServerContext
3942 // in pRequestInfo than the one extracted from pRequestLookup.
3943 if (m_spServerContext
)
3945 if(!m_HttpResponse
.Initialize(m_spServerContext
))
3950 hcErr
= pT
->CheckValidRequest();
3956 // initialize with the pRequestLookup to chain query parameters
3957 m_HttpRequest
.Initialize(pRequestLookup
);
3959 // initialize with the m_spServerContext to get additional query params
3961 if (m_spServerContext
)
3963 m_HttpRequest
.Initialize(m_spServerContext
);
3967 m_HttpResponse
.SetBufferOutput(false); // child cannot buffer
3969 // initialize the safe server context
3970 if (!m_SafeSrvCtx
.Initialize(&m_HttpResponse
, &m_HttpRequest
))
3975 hcErr
= TagReplacerType::Initialize(pRequestInfo
, &m_SafeSrvCtx
);
3981 return pT
->ValidateAndExchange();
3984 // HandleRequest is called to perform default processing of HTTP requests. Users
3985 // can override this function in their derived classes if they need to perform
3986 // specific initialization prior to processing this request or want to change the
3987 // way the request is processed.
3988 HTTP_CODE
HandleRequest(
3989 AtlServerRequest
*pRequestInfo
,
3990 IServiceProvider
* /*pServiceProvider*/)
3992 ATLENSURE(pRequestInfo
);
3994 THandler
*pT
= static_cast<THandler
*>(this);
3995 HTTP_CODE hcErr
= HTTP_SUCCESS
;
3997 if (pRequestInfo
->dwRequestState
== ATLSRV_STATE_BEGIN
)
3999 m_dwRequestType
= pRequestInfo
->dwRequestType
;
4001 if (pRequestInfo
->dwRequestType
==ATLSRV_REQUEST_STENCIL
)
4003 LPCSTR szFileName
= pRequestInfo
->pServerContext
->GetScriptPathTranslated();
4006 hcErr
= pT
->LoadStencil(szFileName
, static_cast<IHttpRequestLookup
*>(&m_HttpRequest
));
4009 else if (pRequestInfo
->dwRequestState
== ATLSRV_STATE_CONTINUE
)
4010 m_HttpResponse
.ClearContent();
4012 #ifdef ATL_DEBUG_STENCILS
4013 if (m_pLoadedStencil
&& !m_pLoadedStencil
->ParseSuccessful())
4015 // An error or series of errors occurred in parsing the stencil
4018 m_pLoadedStencil
->RenderErrors(static_cast<IWriteStream
*>(&m_HttpResponse
));
4027 if (hcErr
== HTTP_SUCCESS
&& m_pLoadedStencil
)
4029 // if anything other than HTTP_SUCCESS is returned during
4030 // the rendering of replacement tags, we return that value
4032 hcErr
= pT
->RenderStencil(static_cast<IWriteStream
*>(&m_HttpResponse
), &m_state
);
4034 if (hcErr
== HTTP_SUCCESS
&& !m_HttpResponse
.Flush(TRUE
))
4038 if (IsAsyncFlushStatus(hcErr
))
4040 pRequestInfo
->pszBuffer
= LPCSTR(m_HttpResponse
.m_strContent
);
4041 pRequestInfo
->dwBufferLen
= m_HttpResponse
.m_strContent
.GetLength();
4044 if (pRequestInfo
->dwRequestState
== ATLSRV_STATE_BEGIN
|| IsAsyncDoneStatus(hcErr
))
4045 return pT
->Uninitialize(hcErr
);
4047 else if (!IsAsyncStatus(hcErr
))
4048 m_HttpResponse
.ClearContent();
4053 HTTP_CODE
ServerTransferRequest(LPCSTR szRequest
, bool bContinueAfterTransfer
=false,
4054 WORD nCodePage
= 0, CStencilState
*pState
= NULL
) throw(...)
4056 return m_spExtension
->TransferRequest(
4058 m_spServiceProvider
,
4059 static_cast<IWriteStream
*>(&m_HttpResponse
),
4060 static_cast<IHttpRequestLookup
*>(&m_HttpRequest
),
4062 nCodePage
== 0 ? m_nCodePage
: nCodePage
,
4063 bContinueAfterTransfer
,
4067 inline DWORD
MaxFormSize()
4069 return DEFAULT_MAX_FORM_SIZE
;
4072 inline DWORD
FormFlags()
4074 return ATL_FORM_FLAG_IGNORE_FILES
;
4077 // Override this function to check if the request
4078 // is valid. This function is called after m_HttpResponse
4079 // has been initialized, so you can use it if you need
4080 // to return an error to the client. This is also a
4081 // good place to initialize any internal class data needed
4082 // to handle the request. CRequestHandlerT::CheckValidRequest
4083 // is called after CRequestHandlerT::InitializeInternal is
4084 // called, so your override of this method will have access to
4085 // m_pRequestInfo (this request's AtlServerRequest structure),
4086 // m_hInstHandler (the HINSTANCE of this handler dll),
4087 // m_spServerContext (the IHttpServerContext interface for this request),
4088 // m_spServiceProvider (the IServiceProvider interface for this request).
4089 // You should call CRequestHandlerT::CheckValidRequest in your override
4090 // if you override this function.
4092 // Note that m_HttpRequest has not been initialized, so
4093 // you cannot use it. This function is intended to
4094 // do simple checking throught IHttpServerContext to avoid
4095 // expensive initialization of m_HttpRequest.
4096 HTTP_CODE
CheckValidRequest()
4098 LPCSTR szMethod
= NULL
;
4099 ATLASSUME(m_pRequestInfo
);
4100 szMethod
= m_pRequestInfo
->pServerContext
->GetRequestMethod();
4101 if (strcmp(szMethod
, "GET") && strcmp(szMethod
, "POST") && strcmp(szMethod
, "HEAD"))
4102 return HTTP_NOT_IMPLEMENTED
;
4104 return HTTP_SUCCESS
;
4107 HRESULT
GetContext(REFIID riid
, void** ppv
)
4111 if (InlineIsEqualGUID(riid
, __uuidof(IHttpServerContext
)))
4113 return m_spServerContext
.CopyTo((IHttpServerContext
**)ppv
);
4115 if (InlineIsEqualGUID(riid
, __uuidof(IHttpRequestLookup
)))
4117 *ppv
= static_cast<IHttpRequestLookup
*>(&m_HttpRequest
);
4118 m_HttpRequest
.AddRef();
4121 if (InlineIsEqualGUID(riid
, __uuidof(IServiceProvider
)))
4123 *ppv
= m_spServiceProvider
;
4124 m_spServiceProvider
.p
->AddRef();
4127 return E_NOINTERFACE
;
4130 HINSTANCE
GetResourceInstance()
4132 if (m_pRequestInfo
!= NULL
)
4134 return m_pRequestInfo
->hInstDll
;
4140 template <typename Interface
>
4141 HRESULT
GetContext(Interface
** ppInterface
) throw(...)
4143 return GetContext(__uuidof(Interface
), reinterpret_cast<void**>(ppInterface
));
4145 }; // class CRequestHandlerT
4150 #pragma warning( pop )
4152 #endif // __ATLSTENCIL_H__