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