1 // Copyright (c) 2018, ETH Zurich and UNC Chapel Hill.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
6 //
7 // * Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 //
10 // * Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 //
14 // * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
15 // its contributors may be used to endorse or promote products derived
16 // from this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
22 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 // POSSIBILITY OF SUCH DAMAGE.
29 //
30 // Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
31
32 #include "util/string.h"
33
34 #include <algorithm>
35 #include <cstdarg>
36 #include <fstream>
37 #include <sstream>
38
39 #include <boost/algorithm/string.hpp>
40
41 namespace colmap {
42 namespace {
43
44 // The StringAppendV function is borrowed from Google under the BSD license:
45 //
46 // Copyright 2012 Google Inc. All rights reserved.
47 // https://developers.google.com/protocol-buffers/
48 //
49 // Redistribution and use in source and binary forms, with or without
50 // modification, are permitted provided that the following conditions are met:
51 //
52 // * Redistributions of source code must retain the above copyright
53 // notice, this list of conditions and the following disclaimer.
54 // * Redistributions in binary form must reproduce the above
55 // copyright notice, this list of conditions and the following disclaimer
56 // in the documentation and/or other materials provided with the
57 // distribution.
58 // * Neither the name of Google Inc. nor the names of its
59 // contributors may be used to endorse or promote products derived from
60 // this software without specific prior written permission.
61 //
62 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
63 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
64 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
65 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
66 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
67 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
68 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
69 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
70 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
71 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
72 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
73
StringAppendV(std::string * dst,const char * format,va_list ap)74 void StringAppendV(std::string* dst, const char* format, va_list ap) {
75 // First try with a small fixed size buffer.
76 static const int kFixedBufferSize = 1024;
77 char fixed_buffer[kFixedBufferSize];
78
79 // It is possible for methods that use a va_list to invalidate
80 // the data in it upon use. The fix is to make a copy
81 // of the structure before using it and use that copy instead.
82 va_list backup_ap;
83 va_copy(backup_ap, ap);
84 int result = vsnprintf(fixed_buffer, kFixedBufferSize, format, backup_ap);
85 va_end(backup_ap);
86
87 if (result < kFixedBufferSize) {
88 if (result >= 0) {
89 // Normal case - everything fits.
90 dst->append(fixed_buffer, result);
91 return;
92 }
93
94 #ifdef _MSC_VER
95 // Error or MSVC running out of space. MSVC 8.0 and higher
96 // can be asked about space needed with the special idiom below:
97 va_copy(backup_ap, ap);
98 result = vsnprintf(nullptr, 0, format, backup_ap);
99 va_end(backup_ap);
100 #endif
101
102 if (result < 0) {
103 // Just an error.
104 return;
105 }
106 }
107
108 // Increase the buffer size to the size requested by vsnprintf,
109 // plus one for the closing \0.
110 const int variable_buffer_size = result + 1;
111 std::unique_ptr<char> variable_buffer(new char[variable_buffer_size]);
112
113 // Restore the va_list before we use it again.
114 va_copy(backup_ap, ap);
115 result =
116 vsnprintf(variable_buffer.get(), variable_buffer_size, format, backup_ap);
117 va_end(backup_ap);
118
119 if (result >= 0 && result < variable_buffer_size) {
120 dst->append(variable_buffer.get(), result);
121 }
122 }
123
IsNotWhiteSpace(const int character)124 bool IsNotWhiteSpace(const int character) {
125 return character != ' ' && character != '\n' && character != '\r' &&
126 character != '\t';
127 }
128
129 } // namespace
130
StringPrintf(const char * format,...)131 std::string StringPrintf(const char* format, ...) {
132 va_list ap;
133 va_start(ap, format);
134 std::string result;
135 StringAppendV(&result, format, ap);
136 va_end(ap);
137 return result;
138 }
139
StringReplace(const std::string & str,const std::string & old_str,const std::string & new_str)140 std::string StringReplace(const std::string& str, const std::string& old_str,
141 const std::string& new_str) {
142 if (old_str.empty()) {
143 return str;
144 }
145 size_t position = 0;
146 std::string mod_str = str;
147 while ((position = mod_str.find(old_str, position)) != std::string::npos) {
148 mod_str.replace(position, old_str.size(), new_str);
149 position += new_str.size();
150 }
151 return mod_str;
152 }
153
StringGetAfter(const std::string & str,const std::string & key)154 std::string StringGetAfter(const std::string& str, const std::string& key) {
155 if (key.empty()) {
156 return str;
157 }
158 std::size_t found = str.rfind(key);
159 if (found != std::string::npos) {
160 return str.substr(found + key.length(), str.length() - (found + key.length()));
161 }
162 return "";
163 }
164
StringSplit(const std::string & str,const std::string & delim)165 std::vector<std::string> StringSplit(const std::string& str,
166 const std::string& delim) {
167 std::vector<std::string> elems;
168 boost::split(elems, str, boost::is_any_of(delim), boost::token_compress_on);
169 return elems;
170 }
171
StringStartsWith(const std::string & str,const std::string & prefix)172 bool StringStartsWith(const std::string& str, const std::string& prefix) {
173 return !prefix.empty() && prefix.size() <= str.size() &&
174 str.substr(0, prefix.size()) == prefix;
175 }
176
StringLeftTrim(std::string * str)177 void StringLeftTrim(std::string* str) {
178 str->erase(str->begin(),
179 std::find_if(str->begin(), str->end(), IsNotWhiteSpace));
180 }
181
StringRightTrim(std::string * str)182 void StringRightTrim(std::string* str) {
183 str->erase(std::find_if(str->rbegin(), str->rend(), IsNotWhiteSpace).base(),
184 str->end());
185 }
186
StringTrim(std::string * str)187 void StringTrim(std::string* str) {
188 StringLeftTrim(str);
189 StringRightTrim(str);
190 }
191
StringToLower(std::string * str)192 void StringToLower(std::string* str) {
193 std::transform(str->begin(), str->end(), str->begin(), ::tolower);
194 }
195
StringToUpper(std::string * str)196 void StringToUpper(std::string* str) {
197 std::transform(str->begin(), str->end(), str->begin(), ::toupper);
198 }
199
StringContains(const std::string & str,const std::string & sub_str)200 bool StringContains(const std::string& str, const std::string& sub_str) {
201 return str.find(sub_str) != std::string::npos;
202 }
203
204 } // namespace colmap
205