Set fourth file version digit to signify rebuild.
[shibboleth/cpp-xmltooling.git] / xmltooling / util / PathResolver.cpp
1 /**
2  * Licensed to the University Corporation for Advanced Internet
3  * Development, Inc. (UCAID) under one or more contributor license
4  * agreements. See the NOTICE file distributed with this work for
5  * additional information regarding copyright ownership.
6  *
7  * UCAID licenses this file to you under the Apache License,
8  * Version 2.0 (the "License"); you may not use this file except
9  * in compliance with the License. You may obtain a copy of the
10  * License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing,
15  * software distributed under the License is distributed on an
16  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
17  * either express or implied. See the License for the specific
18  * language governing permissions and limitations under the License.
19  */
20
21 /**
22  * PathResolver.cpp
23  *
24  * Resolves local filenames into absolute pathnames.
25  */
26
27 #include "internal.h"
28 #include "exceptions.h"
29 #include "util/PathResolver.h"
30
31 #ifdef WIN32
32 # include <Shlobj.h>
33 #endif
34
35 using namespace xmltooling;
36 using namespace std;
37
38 PathResolver::PathResolver() : m_defaultPackage(PACKAGE_NAME), m_defaultPrefix("/usr")
39 {
40     setLibDir("/usr/lib");
41     setLogDir("/var/log");
42     setXMLDir("/usr/share/xml");
43     setRunDir("/var/run");
44     setCfgDir("/etc");
45     setCacheDir("/var/cache");
46 }
47
48 PathResolver::~PathResolver()
49 {
50 }
51
52 void PathResolver::setDefaultPackageName(const char* pkgname)
53 {
54     m_defaultPackage = pkgname;
55 }
56
57 void PathResolver::setDefaultPrefix(const char* prefix)
58 {
59     m_defaultPrefix = prefix;
60 }
61
62 void PathResolver::setLibDir(const char* dir)
63 {
64     m_lib = dir;
65 }
66
67 void PathResolver::setLogDir(const char* dir)
68 {
69     m_log = dir;
70 }
71
72 void PathResolver::setXMLDir(const char* dir)
73 {
74     m_xml = dir;
75 }
76
77 void PathResolver::setRunDir(const char* dir)
78 {
79     m_run = dir;
80 }
81
82 void PathResolver::setCfgDir(const char* dir)
83 {
84     m_cfg = dir;
85 }
86
87 void PathResolver::setCacheDir(const char* dir)
88 {
89     m_cache = dir;
90 }
91
92 bool PathResolver::isAbsolute(const char* s) const
93 {
94     switch (*s) {
95         case 0:
96             return false;
97         case '/':
98         case '\\':
99             return true;
100         case '.':
101             return (*(s+1) == '.' || *(s+1) == '/' || *(s+1) == '\\');
102     }
103     return *(s+1) == ':';
104 }
105
106 const string& PathResolver::resolve(string& s, file_type_t filetype, const char* pkgname, const char* prefix) const
107 {
108 #ifdef WIN32
109     // Check for possible environment variable(s).
110     if (s.find('%') != string::npos) {
111         // This is an ugly workaround for Windows XP/2003, which don't support the PROGRAMDATA variable.
112         if (!getenv("PROGRAMDATA") && s.find("%PROGRAMDATA%") != string::npos) {
113             char appdatapath[MAX_PATH + 2];
114             if (SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdatapath) == S_OK) {
115                 s.replace(s.find("%PROGRAMDATA%"), 13, appdatapath);
116             }
117         }
118         char expbuf[MAX_PATH + 2];
119         DWORD cnt = ExpandEnvironmentStrings(s.c_str(), expbuf, sizeof(expbuf));
120         if (cnt != 0 && cnt <= sizeof(expbuf))
121             s = expbuf;
122     }
123 #endif
124
125     if (!isAbsolute(s.c_str())) {
126         switch (filetype) {
127             case XMLTOOLING_LIB_FILE:
128                 s = m_lib + '/' + (pkgname ? pkgname : m_defaultPackage) + '/' + s;
129                 if (!isAbsolute(m_lib.c_str()))
130                     s = string(prefix ? prefix : m_defaultPrefix) + '/' + s;
131                 break;
132
133             case XMLTOOLING_LOG_FILE:
134                 s = m_log + '/' + (pkgname ? pkgname : m_defaultPackage) + '/' + s;
135                 if (!isAbsolute(m_log.c_str())) {
136                     if (prefix || m_defaultPrefix != "/usr")
137                         s = string(prefix ? prefix : m_defaultPrefix) + '/' + s;
138                     else
139                         s = string("/") + s;
140                 }
141                 break;
142
143             case XMLTOOLING_XML_FILE:
144                 s = m_xml + '/' + (pkgname ? pkgname : m_defaultPackage) + '/' + s;
145                 if (!isAbsolute(m_xml.c_str()))
146                     s = string(prefix ? prefix : m_defaultPrefix) + '/' + s;
147                 break;
148
149             case XMLTOOLING_RUN_FILE:
150                 s = m_run + '/' + (pkgname ? pkgname : m_defaultPackage) + '/' + s;
151                 if (!isAbsolute(m_run.c_str())) {
152                     if (prefix || m_defaultPrefix != "/usr")
153                         s = string(prefix ? prefix : m_defaultPrefix) + '/' + s;
154                     else
155                         s = string("/") + s;
156                 }
157                 break;
158
159             case XMLTOOLING_CFG_FILE:
160                 s = m_cfg + '/' + (pkgname ? pkgname : m_defaultPackage) + '/' + s;
161                 if (!isAbsolute(m_cfg.c_str())) {
162                     if (prefix || m_defaultPrefix != "/usr")
163                         s = string(prefix ? prefix : m_defaultPrefix) + '/' + s;
164                     else
165                         s = string("/") + s;
166                 }
167                 break;
168
169             case XMLTOOLING_CACHE_FILE:
170                 s = m_cache + '/' + (pkgname ? pkgname : m_defaultPackage) + '/' + s;
171                 if (!isAbsolute(m_cache.c_str())) {
172                     if (prefix || m_defaultPrefix != "/usr")
173                         s = string(prefix ? prefix : m_defaultPrefix) + '/' + s;
174                     else
175                         s = string("/") + s;
176                 }
177                 break;
178
179             default:
180                 throw XMLToolingException("Unknown file type to resolve.");
181         }
182     }
183     return s;
184 }