1 // Copyright (c) 2017, Google Inc.
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
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 // * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 #include "common/long_string_dictionary.h"
31
32 #include <assert.h>
33 #include <string.h>
34
35 #include <algorithm>
36 #include <string>
37
38 #include "common/simple_string_dictionary.h"
39
40 #define arraysize(f) (sizeof(f) / sizeof(*f))
41
42 namespace {
43 // Suffixes for segment keys.
44 const char* const kSuffixes[] = {"__1", "__2", "__3", "__4", "__5", "__6",
45 "__7", "__8", "__9", "__10"};
46 #if !defined(NDEBUG)
47 // The maximum suffix string length.
48 const size_t kMaxSuffixLength = 4;
49 #endif
50 } // namespace
51
52 namespace google_breakpad {
53
54 using std::string;
55
SetKeyValue(const char * key,const char * value)56 void LongStringDictionary::SetKeyValue(const char* key, const char* value) {
57 assert(key);
58 if (!key)
59 return;
60
61 RemoveKey(key);
62
63 if (!value) {
64 return;
65 }
66
67 // Key must not be an empty string.
68 assert(key[0] != '\0');
69 if (key[0] == '\0')
70 return;
71
72 // If the value is not valid for segmentation, forwards the key and the value
73 // to SetKeyValue of SimpleStringDictionary and returns.
74 size_t value_length = strlen(value);
75 if (value_length <= (value_size - 1)) {
76 SimpleStringDictionary::SetKeyValue(key, value);
77 return;
78 }
79
80 size_t key_length = strlen(key);
81 assert(key_length + kMaxSuffixLength <= (key_size - 1));
82
83 char segment_key[key_size];
84 char segment_value[value_size];
85
86 strcpy(segment_key, key);
87
88 const char* remain_value = value;
89 size_t remain_value_length = strlen(value);
90
91 for (unsigned long i = 0; i < arraysize(kSuffixes); i++) {
92 if (remain_value_length == 0) {
93 return;
94 }
95
96 strcpy(segment_key + key_length, kSuffixes[i]);
97
98 size_t segment_value_length =
99 std::min(remain_value_length, value_size - 1);
100
101 strncpy(segment_value, remain_value, segment_value_length);
102 segment_value[segment_value_length] = '\0';
103
104 remain_value += segment_value_length;
105 remain_value_length -= segment_value_length;
106
107 SimpleStringDictionary::SetKeyValue(segment_key, segment_value);
108 }
109 }
110
RemoveKey(const char * key)111 bool LongStringDictionary::RemoveKey(const char* key) {
112 assert(key);
113 if (!key)
114 return false;
115
116 if (SimpleStringDictionary::RemoveKey(key)) {
117 return true;
118 }
119
120 size_t key_length = strlen(key);
121 assert(key_length + kMaxSuffixLength <= (key_size - 1));
122
123 char segment_key[key_size];
124 strcpy(segment_key, key);
125
126 unsigned long i = 0;
127 for (; i < arraysize(kSuffixes); i++) {
128 strcpy(segment_key + key_length, kSuffixes[i]);
129 if (!SimpleStringDictionary::RemoveKey(segment_key)) {
130 break;
131 }
132 }
133 return i != 0;
134 }
135
GetValueForKey(const char * key) const136 const string LongStringDictionary::GetValueForKey(const char* key) const {
137 assert(key);
138 if (!key)
139 return "";
140
141 // Key must not be an empty string.
142 assert(key[0] != '\0');
143 if (key[0] == '\0')
144 return "";
145
146 const char* value = SimpleStringDictionary::GetValueForKey(key);
147 if (value)
148 return string(value);
149
150 size_t key_length = strlen(key);
151 assert(key_length + kMaxSuffixLength <= (key_size - 1));
152
153 bool found_segment = false;
154 char segment_key[key_size];
155 string return_value;
156
157 strcpy(segment_key, key);
158 for (unsigned long i = 0; i < arraysize(kSuffixes); i++) {
159 strcpy(segment_key + key_length, kSuffixes[i]);
160
161 const char* segment_value =
162 SimpleStringDictionary::GetValueForKey(segment_key);
163
164 if (segment_value != NULL) {
165 found_segment = true;
166 return_value.append(segment_value);
167 } else {
168 break;
169 }
170 }
171
172 if (found_segment) {
173 return return_value;
174 }
175 return "";
176 }
177
178 } // namespace google_breakpad
179