util/ParserPool.h \
util/ReplayCache.h \
util/StorageService.h \
+ util/TemplateEngine.h \
util/Threads.h \
util/XMLConstants.h \
util/XMLHelper.h \
util/ParserPool.cpp \
util/ReplayCache.cpp \
util/StorageService.cpp \
+ util/TemplateEngine.cpp \
util/XMLConstants.cpp \
util/XMLHelper.cpp \
validation/ValidatorSuite.cpp \
#include "util/NDC.h"
#include "util/ReplayCache.h"
#include "util/StorageService.h"
+#include "util/TemplateEngine.h"
#include "util/XMLConstants.h"
#include "validation/ValidatorSuite.h"
m_replayCache = replayCache;
}
+void XMLToolingConfig::setTemplateEngine(TemplateEngine* templateEngine)
+{
+ delete m_templateEngine;
+ m_templateEngine = templateEngine;
+}
+
bool XMLToolingInternalConfig::init()
{
#ifdef _DEBUG
delete m_replayCache;
m_replayCache = NULL;
+
+ delete m_templateEngine;
+ m_templateEngine = NULL;
for (vector<void*>::reverse_iterator i=m_libhandles.rbegin(); i!=m_libhandles.rend(); i++) {
#if defined(WIN32)
class XMLTOOL_API ReplayCache;
class XMLTOOL_API StorageService;
+ class XMLTOOL_API TemplateEngine;
class XMLTOOL_API TrustEngine;
class XMLTOOL_API XSECCryptoX509CRL;
/** Global ReplayCache instance. */
ReplayCache* m_replayCache;
+
+ /** Global TemplateEngine instance. */
+ TemplateEngine* m_templateEngine;
public:
virtual ~XMLToolingConfig() {}
ReplayCache* getReplayCache() const {
return m_replayCache;
}
+
+ /**
+ * Sets the global TemplateEngine instance.
+ * This method must be externally synchronized with any code that uses the object.
+ * Any previously set object is destroyed.
+ *
+ * @param templateEngine new TemplateEngine instance to store
+ */
+ void setTemplateEngine(TemplateEngine* templateEngine);
+
+ /**
+ * Returns the global TemplateEngine instance.
+ *
+ * @return global TemplateEngine or NULL
+ */
+ TemplateEngine* getTemplateEngine() const {
+ return m_templateEngine;
+ }
/**
* List of catalog files to load into validating parser pool at initialization time.
--- /dev/null
+/*
+ * Copyright 2001-2006 Internet2
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * TemplateEngine.cpp
+ *
+ * Simple template replacement engine.
+ */
+
+#include "internal.h"
+#include "util/TemplateEngine.h"
+
+#include <ctime>
+
+using namespace xmltooling;
+using namespace std;
+
+void TemplateEngine::setTagPrefix(const char* tagPrefix)
+{
+ keytag = string("<") + tagPrefix + " ";
+ iftag = string("<") + tagPrefix + "if ";
+ ifnottag = string("<") + tagPrefix + "ifnot ";
+ ifendtag = string("</") + tagPrefix + "if>";
+ ifnotendtag = string("</") + tagPrefix + "ifnot>";
+}
+
+void TemplateEngine::html_encode(ostream& os, const char* start) const
+{
+ while (start && *start) {
+ switch (*start) {
+ case '<': os << "<"; break;
+ case '>': os << ">"; break;
+ case '"': os << """; break;
+ case '#': os << "#"; break;
+ case '%': os << "%"; break;
+ case '&': os << "&"; break;
+ case '\'': os << "'"; break;
+ case '(': os << "("; break;
+ case ')': os << ")"; break;
+ case ':': os << ":"; break;
+ case '[': os << "["; break;
+ case '\\': os << "\"; break;
+ case ']': os << "]"; break;
+ case '`': os << "`"; break;
+ case '{': os << "{"; break;
+ case '}': os << "}"; break;
+ default: os << *start;
+ }
+ start++;
+ }
+}
+
+void TemplateEngine::trimspace(string& s) const
+{
+ string::size_type end = s.size() - 1, start = 0;
+
+ // Trim stuff on right.
+ while (end > 0 && !isgraph(s[end])) end--;
+
+ // Trim stuff on left.
+ while (start < end && !isgraph(s[start])) start++;
+
+ // Modify the string.
+ s = s.substr(start, end - start + 1);
+}
+
+void TemplateEngine::process(
+ bool visible,
+ const string& buf,
+ const char*& lastpos,
+ ostream& os,
+ const map<string,string>& parameters,
+ const XMLToolingException* e
+ ) const
+{
+ // Create a timestamp
+ time_t now = time(NULL);
+#ifdef HAVE_CTIME_R
+ char nowbuf[32];
+ ctime_r(&now);
+#else
+ const char* nowbuf = ctime(&now);
+#endif
+
+ const char* line = buf.c_str();
+ const char* thispos;
+
+ while ((thispos = strchr(lastpos, '<')) != NULL) {
+ // Output the string up to this token.
+ if (visible)
+ os << buf.substr(lastpos-line, thispos-lastpos);
+
+ // Make sure this token matches our tokens.
+#ifdef HAVE_STRCASECMP
+ if (visible && !strncasecmp(thispos, keytag.c_str(), keytag.length()))
+#else
+ if (visible && !_strnicmp(thispos, keytag.c_str(), keytag.length()))
+#endif
+ {
+ // Save this position off.
+ lastpos = thispos + keytag.length();
+
+ // search for the end-tag
+ if ((thispos = strstr(lastpos, "/>")) != NULL) {
+ string key = buf.substr(lastpos-line, thispos-lastpos);
+ trimspace(key);
+
+ map<string,string>::const_iterator i=parameters.find(key);
+ if (i != parameters.end()) {
+ html_encode(os,i->second.c_str());
+ }
+ else if (e) {
+ const char* ep = e->getProperty(key.c_str());
+ if (ep)
+ html_encode(os,ep);
+ }
+ lastpos = thispos + 2; // strlen("/>")
+ }
+ }
+#ifdef HAVE_STRCASECMP
+ else if (!strncasecmp(thispos, iftag.c_str(), iftag.length()))
+#else
+ else if (!_strnicmp(thispos, iftag.c_str(), iftag.length()))
+#endif
+ {
+ // Save this position off.
+ lastpos = thispos + iftag.length();
+
+ // search for the end of this tag
+ if ((thispos = strchr(lastpos, '>')) != NULL) {
+ string key = buf.substr(lastpos-line, thispos-lastpos);
+ trimspace(key);
+ map<string,string>::const_iterator i=parameters.find(key);
+ bool cond=false;
+ if (visible) {
+ if (i != parameters.end())
+ cond=true;
+ else if (e && e->getProperty(key.c_str()))
+ cond=true;
+ }
+ lastpos = thispos + 1; // strlen(">")
+ process(cond, buf, lastpos, os, parameters, e);
+ }
+ }
+#ifdef HAVE_STRCASECMP
+ else if (!strncasecmp(thispos, ifendtag.c_str(), ifendtag.length()))
+#else
+ else if (!_strnicmp(thispos, ifendtag.c_str(), ifendtag.length()))
+#endif
+ {
+ // Save this position off and pop the stack.
+ lastpos = thispos + ifendtag.length();
+ return;
+ }
+#ifdef HAVE_STRCASECMP
+ else if (!strncasecmp(thispos, ifnottag.c_str(), ifnottag.length()))
+#else
+ else if (!_strnicmp(thispos, ifnottag.c_str(), ifnottag.length()))
+#endif
+ {
+ // Save this position off.
+ lastpos = thispos + ifnottag.length();
+
+ // search for the end of this tag
+ if ((thispos = strchr(lastpos, '>')) != NULL) {
+ string key = buf.substr(lastpos-line, thispos-lastpos);
+ trimspace(key);
+ map<string,string>::const_iterator i=parameters.find(key);
+ bool cond=visible;
+ if (visible) {
+ if (i != parameters.end())
+ cond=false;
+ else if (e && e->getProperty(key.c_str()))
+ cond=false;
+ }
+ lastpos = thispos + 1; // strlen(">")
+ process(cond, buf, lastpos, os, parameters, e);
+ }
+ }
+#ifdef HAVE_STRCASECMP
+ else if (!strncasecmp(thispos, ifnotendtag.c_str(), ifnotendtag.length()))
+#else
+ else if (!_strnicmp(thispos, ifnotendtag.c_str(), ifnotendtag.length()))
+#endif
+ {
+ // Save this position off and pop the stack.
+ lastpos = thispos + ifnotendtag.length();
+ return;
+ }
+ else {
+ // Skip it.
+ if (visible)
+ os << '<';
+ lastpos = thispos + 1;
+ }
+ }
+ if (visible)
+ os << buf.substr(lastpos-line);
+}
+
+void TemplateEngine::run(istream& is, ostream& os, const map<string,string>& parameters, const XMLToolingException* e) const
+{
+ string buf,line;
+ while (getline(is, line))
+ buf += line + '\n';
+
+ const char* pos=buf.c_str();
+ process(true, buf, pos, os, parameters, e);
+}
--- /dev/null
+/*
+ * Copyright 2001-2006 Internet2
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file xmltooling/util/TemplateEngine.h
+ *
+ * Simple template replacement engine.
+ */
+
+#ifndef __xmltooling_template_h__
+#define __xmltooling_template_h__
+
+#include <xmltooling/base.h>
+
+#include <map>
+#include <string>
+#include <iostream>
+
+namespace xmltooling {
+
+ /**
+ * Simple template replacement engine. Supports the following:
+ * <ul>
+ * <li> <mlp key/> </li>
+ * <li> <mlpif key> stuff </mlpif></li>
+ * <li> <mlpifnot key> stuff </mlpifnot></li>
+ * </ul>
+ *
+ * The default tag prefix is "mlp". This can be overridden for
+ * compatibility.
+ */
+ class XMLTOOL_API TemplateEngine
+ {
+ MAKE_NONCOPYABLE(TemplateEngine);
+ public:
+
+ TemplateEngine() {
+ setTagPrefix("mlp");
+ }
+
+ virtual ~TemplateEngine() {}
+
+ /**
+ * Sets the tag name to use when locating template replacement tags.
+ *
+ * @param tagPrefix base prefix for tags
+ */
+ void setTagPrefix(const char* tagPrefix);
+
+ /**
+ * Processes template from an input stream and executes replacements and
+ * conditional logic based on parameters.
+ *
+ * @param is input stream providing template
+ * @param os output stream to send results of executing template
+ * @param parameters name/value parameters to plug into template
+ * @param e optional exception to extract parameters from
+ */
+ virtual void run(
+ std::istream& is,
+ std::ostream& os,
+ const std::map<std::string,std::string>& parameters,
+ const XMLToolingException* e=NULL
+ ) const;
+
+ private:
+ void trimspace(std::string& s) const;
+ void html_encode(std::ostream& os, const char* start) const;
+ void process(
+ bool visible,
+ const std::string& buf,
+ const char*& lastpos,
+ std::ostream& os,
+ const std::map<std::string,std::string>& parameters,
+ const XMLToolingException* e
+ ) const;
+
+ std::string keytag,iftag,ifendtag,ifnottag,ifnotendtag;
+ };
+};
+
+#endif /* __xmltooling_template_h__ */
>\r
</File>\r
<File\r
+ RelativePath=".\util\TemplateEngine.cpp"\r
+ >\r
+ </File>\r
+ <File\r
RelativePath=".\util\Win32Threads.cpp"\r
>\r
</File>\r
>\r
</File>\r
<File\r
+ RelativePath=".\util\TemplateEngine.h"\r
+ >\r
+ </File>\r
+ <File\r
RelativePath=".\util\Threads.h"\r
>\r
</File>\r
ExceptionTest.h \
KeyInfoTest.h \
MarshallingTest.h \
+ MemoryStorageServiceTest.h \
UnmarshallingTest.h \
+ TemplateEngineTest.h \
xmltoolingtest.h \
${xmlsec_sources}
--- /dev/null
+/*
+ * Copyright 2001-2006 Internet2
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "XMLObjectBaseTestCase.h"
+
+#include <fstream>
+#include <sstream>
+#include <xmltooling/util/TemplateEngine.h>
+
+class TemplateEngineTest : public CxxTest::TestSuite {
+public:
+ void setUp() {
+ }
+
+ void tearDown() {
+ }
+
+ void testTemplateEngine() {
+ auto_ptr<TemplateEngine> engine(new TemplateEngine());
+
+ map<string,string> p;
+ p["foo1"] = "bar1";
+ p["foo3"] = "bar3";
+
+ string path = data_path + "template.in";
+ ifstream in(path.c_str());
+ ostringstream out;
+
+ engine->run(in,out,p);
+
+ string compstr;
+ path = data_path + "template.out";
+ ifstream compfile(path.c_str());
+ while (getline(compfile,path))
+ compstr += path + '\n';
+
+ TSM_ASSERT_EQUALS("Template output did not match.", out.str(), compstr);
+ }
+};
--- /dev/null
+This is a template containing tags for substitution by the template engine.
+
+<mlp foo1/> <mlp foo2/> <mlp foo3/>
+
+<mlpif foo1><mlp foo3/></mlpif>
+
+<mlpif foo2><mlp foo1/></mlpif>
+
+<mlpif foo1>
+ <mlpifnot foo2>
+ <mlp foo3/>
+ </mlpifnot>
+</mlpif>
--- /dev/null
+This is a template containing tags for substitution by the template engine.
+
+bar1 bar3
+
+bar3
+
+
+
+
+
+ bar3
+
+
>\r
</File>\r
<File\r
+ RelativePath=".\TemplateEngineTest.cpp"\r
+ >\r
+ </File>\r
+ <File\r
RelativePath=".\UnmarshallingTest.cpp"\r
>\r
</File>\r
>\r
<Tool\r
Name="VCCustomBuildTool"\r
- CommandLine="\perl\bin\perl.exe -w \cxxtest\cxxtestgen.pl --part --have-eh --have-std --abort-on-fail -o "$(InputName)".cpp "$(InputPath)""\r
+ CommandLine="\perl\bin\perl.exe -w \cxxtest\cxxtestgen.pl --part --have-eh --have-std --abort-on-fail -o "$(InputName)".cpp "$(InputPath)"
"\r
Outputs=""$(InputName)".cpp"\r
/>\r
</FileConfiguration>\r
>\r
<Tool\r
Name="VCCustomBuildTool"\r
- CommandLine="\perl\bin\perl.exe -w \cxxtest\cxxtestgen.pl --part --have-eh --have-std --abort-on-fail -o "$(InputName)".cpp "$(InputPath)""\r
+ CommandLine="\perl\bin\perl.exe -w \cxxtest\cxxtestgen.pl --part --have-eh --have-std --abort-on-fail -o "$(InputName)".cpp "$(InputPath)"
"\r
Outputs=""$(InputName)".cpp"\r
/>\r
</FileConfiguration>\r
</FileConfiguration>\r
</File>\r
<File\r
+ RelativePath=".\TemplateEngineTest.h"\r
+ >\r
+ <FileConfiguration\r
+ Name="Debug|Win32"\r
+ >\r
+ <Tool\r
+ Name="VCCustomBuildTool"\r
+ CommandLine="\perl\bin\perl.exe -w \cxxtest\cxxtestgen.pl --part --have-eh --have-std --abort-on-fail -o "$(InputName)".cpp "$(InputPath)""\r
+ Outputs=""$(InputName)".cpp"\r
+ />\r
+ </FileConfiguration>\r
+ <FileConfiguration\r
+ Name="Release|Win32"\r
+ >\r
+ <Tool\r
+ Name="VCCustomBuildTool"\r
+ CommandLine="\perl\bin\perl.exe -w \cxxtest\cxxtestgen.pl --part --have-eh --have-std --abort-on-fail -o "$(InputName)".cpp "$(InputPath)""\r
+ Outputs=""$(InputName)".cpp"\r
+ />\r
+ </FileConfiguration>\r
+ </File>\r
+ <File\r
RelativePath=".\UnmarshallingTest.h"\r
>\r
<FileConfiguration\r