cede80664fc1b3b6f2c29c69e33e939d8dca3f81
[shibboleth/sp.git] / shibsp / attribute / ExtensibleAttribute.cpp
1 /*
2  *  Copyright 2009 Internet2
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /**
18  * shibsp/attribute/ExtensibleAttribute.cpp
19  *
20  * An Attribute whose values are arbitrary structures.
21  */
22
23 #include "internal.h"
24 #include "SPConfig.h"
25 #include "attribute/ExtensibleAttribute.h"
26 #include "util/SPConstants.h"
27
28 using namespace shibsp;
29 using namespace xmltooling;
30 using namespace std;
31
32 namespace shibsp {
33     SHIBSP_DLLLOCAL Attribute* ExtensibleAttributeFactory(DDF& in) {
34         return new ExtensibleAttribute(in);
35     }
36 };
37
38 ExtensibleAttribute::ExtensibleAttribute(const vector<string>& ids, const char* formatter) : Attribute(ids)
39 {
40     m_obj = Attribute::marshall();
41     m_obj.name("Extensible");
42     m_obj.addmember("_formatter").string(formatter);
43 }
44
45 ExtensibleAttribute::ExtensibleAttribute(DDF& in) : Attribute(in), m_obj(in.copy())
46 {
47 }
48
49 ExtensibleAttribute::~ExtensibleAttribute()
50 {
51     m_obj.destroy();
52 }
53
54 DDF ExtensibleAttribute::getValues()
55 {
56     return m_obj.first();
57 }
58
59 size_t ExtensibleAttribute::valueCount() const
60 {
61     return m_obj.first().integer();
62 }
63
64 void ExtensibleAttribute::clearSerializedValues()
65 {
66     m_serialized.clear();
67 }
68
69 const char* ExtensibleAttribute::getString(size_t index) const
70 {
71     return m_obj.first()[static_cast<unsigned long>(index)].string();
72 }
73
74 const char* ExtensibleAttribute::getScope(size_t index) const
75 {
76     return NULL;
77 }
78
79 void ExtensibleAttribute::removeValue(size_t index)
80 {
81     Attribute::removeValue(index);
82     DDF vals = m_obj.first();
83     if (index < static_cast<size_t>(vals.integer()))
84         vals[static_cast<unsigned long>(index)].remove().destroy();
85 }
86
87 const vector<string>& ExtensibleAttribute::getSerializedValues() const
88 {
89     if (m_serialized.empty()) {
90         const char* formatter = m_obj["_formatter"].string();
91         if (formatter) {
92             string msg = formatter;
93             DDF val = m_obj.first().first();
94             while (!val.isnull()) {
95
96                 static const char* legal="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890_.[]";
97
98                 m_serialized.push_back(string());
99                 string& processed = m_serialized.back();
100
101                 string::size_type i=0,start=0;
102                 while (start!=string::npos && start<msg.length() && (i=msg.find("$",start))!=string::npos) {
103                     if (i>start)
104                         processed += msg.substr(start,i-start); // append everything in between
105                     start=i+1;                                  // move start to the beginning of the token name
106                     i=msg.find_first_not_of(legal,start);       // find token delimiter
107                     if (i==start) {                             // append a non legal character
108                        processed+=msg[start++];
109                        continue;
110                     }
111                     
112                     string tag = msg.substr(start,(i==string::npos) ? i : i-start);
113                     if (tag == "_string" && val.string()) {
114                         processed += val.string();
115                         start=i;
116                     }
117                     else {
118                         DDF child = val.getmember(tag.c_str());
119                         if (child.string())
120                             processed += child.string();
121                         else if (child.isstruct() && child["_string"].string())
122                             processed += child["_string"].string();
123                         start=i;
124                     }
125                 }
126                 if (start!=string::npos && start<msg.length())
127                     processed += msg.substr(start,i);    // append rest of string
128
129                 val = m_obj.first().next();
130             }
131         }
132     }
133     return Attribute::getSerializedValues();
134 }
135
136 DDF ExtensibleAttribute::marshall() const
137 {
138     if (!isCaseSensitive())
139         m_obj.addmember("case_insensitive");
140     if (isInternal())
141         m_obj.addmember("internal");
142     return m_obj.copy();
143 }