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