Fix static analysis issues
[platform/core/base/bundle.git] / src / bundle-internal.cc
1 /*
2  * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "bundle-internal.h"
18
19 #include <errno.h>
20 #include <glib.h>
21
22 #include <algorithm>
23 #include <cstring>
24 #include <utility>
25
26 #include "include/bundle.h"
27
28 #include "exception-internal.h"
29
30 namespace tizen_base {
31 namespace internal {
32
33 static const int CHECKSUM_LENGTH = 32;
34
35 Bundle::Bundle(unsigned char* raw, int size, bool base64) {
36   if (size < 0)
37     THROW(BUNDLE_ERROR_INVALID_PARAMETER);
38
39   int ret;
40   if (base64)
41     ret = Decode(raw, static_cast<size_t>(size));
42   else
43     ret = DecodeRaw(raw, static_cast<size_t>(size));
44   if (ret != BUNDLE_ERROR_NONE)
45     THROW(ret);
46 }
47
48 Bundle::Bundle(int argc, char** argv) {
49   int ret = Import(argc, argv);
50   if (ret != BUNDLE_ERROR_NONE)
51     THROW(ret);
52 }
53
54 Bundle::Bundle(const Bundle& b) {
55   map_ = b.map_;
56   list_ = b.list_;
57 }
58
59 Bundle& Bundle::operator = (const Bundle& b) {
60   if (this != &b) {
61     map_ = b.map_;
62     list_ = b.list_;
63   }
64   return *this;
65 }
66
67 Bundle::Bundle(Bundle&& b) noexcept {
68   map_ = std::move(b.map_);
69   list_ = std::move(b.list_);
70 }
71
72 Bundle& Bundle::operator = (Bundle&& b) noexcept {
73   if (this != &b) {
74     map_ = std::move(b.map_);
75     list_ = std::move(b.list_);
76   }
77   return *this;
78 }
79
80 bool Bundle::operator == (const Bundle& b) {
81   if (this == &b)
82     return true;
83
84   if (map_.size() != b.map_.size())
85     return false;
86
87   for (const auto& kv : map_) {
88     auto& lhs = kv.second;
89     auto iter = b.map_.find(lhs->GetKey());
90     if (iter == b.map_.end())
91       return false;
92
93     auto& rhs = iter->second;
94     if (!(lhs == rhs))
95       return false;
96   }
97
98   return true;
99 }
100
101 void Bundle::Remove(const std::string& key) {
102   auto iter = map_.find(key);
103   if (iter == map_.end())
104     THROW(BUNDLE_ERROR_KEY_NOT_AVAILABLE);
105
106   list_.remove(iter->second);
107   map_.erase(iter);
108 }
109
110 void Bundle::Add(std::shared_ptr<KeyInfo> key_info) {
111   auto iter = map_.find(key_info->GetKey());
112   if (iter != map_.end())
113     THROW(BUNDLE_ERROR_KEY_EXISTS);
114
115   map_[key_info->GetKey()] = key_info;
116   list_.push_back(std::move(key_info));
117 }
118
119 void Bundle::Set(const std::string& key, int index,
120     std::vector<unsigned char> value) {
121   auto iter = map_.find(key);
122   if (iter == map_.end())
123     THROW(BUNDLE_ERROR_KEY_NOT_AVAILABLE);
124
125   int ret = iter->second->SetValue(index, value);
126   if (ret != BUNDLE_ERROR_NONE)
127     THROW(ret);
128 }
129
130 std::shared_ptr<KeyInfo>& Bundle::Get(const std::string& key) {
131   auto iter = map_.find(key.c_str());
132   if (iter == map_.end())
133     THROW(BUNDLE_ERROR_KEY_NOT_AVAILABLE);
134
135   return iter->second;
136 }
137
138 int Bundle::GetSize() {
139   return map_.size();
140 }
141
142 int Bundle::GetType(const std::string& key) {
143   auto iter = map_.find(key);
144   if (iter == map_.end())
145     THROW(BUNDLE_ERROR_KEY_NOT_AVAILABLE);
146
147   return iter->second->GetType();
148 }
149
150 unsigned char* Bundle::Encode() {
151   int size = 0;
152   unsigned char* raw;
153   try {
154     raw = EncodeRaw(&size);
155   } catch (const Exception& e) {
156     THROW(e.GetErrorCode());
157   }
158
159   std::unique_ptr<unsigned char, decltype(std::free)*> raw_ptr(raw, std::free);
160   char* encoded_data = reinterpret_cast<char*>(
161       g_base64_encode(reinterpret_cast<guchar*>(raw),
162         static_cast<gsize>(size)));
163   if (encoded_data == nullptr)
164     THROW(BUNDLE_ERROR_OUT_OF_MEMORY);
165
166   return reinterpret_cast<unsigned char*>(encoded_data);
167 }
168
169 int Bundle::Decode(unsigned char* raw, size_t size) {
170   unsigned char* d_str = new (std::nothrow) unsigned char[(size / 4) * 3 + 3];
171   if (d_str == nullptr)
172     return BUNDLE_ERROR_OUT_OF_MEMORY;
173
174   std::unique_ptr<unsigned char[]> d_ptr(d_str);
175   gint state = 0;
176   guint save = 0;
177   size_t d_len_raw = static_cast<size_t>(g_base64_decode_step(
178       reinterpret_cast<char*>(raw), size, d_str, &state, &save));
179   if (d_len_raw < CHECKSUM_LENGTH)
180     return BUNDLE_ERROR_OUT_OF_MEMORY;
181
182   return DecodeRaw(d_str, d_len_raw);
183 }
184
185 unsigned char* Bundle::EncodeRaw(int* size) {
186   std::vector<unsigned char> bytes;
187   for (const auto& key_info : list_) {
188     auto encoded_bytes = key_info->Encode();
189     bytes.insert(bytes.end(),
190         std::make_move_iterator(encoded_bytes.begin()),
191         std::make_move_iterator(encoded_bytes.end()));
192   }
193
194   gchar* checksum = g_compute_checksum_for_string(
195       G_CHECKSUM_MD5, reinterpret_cast<gchar*>(&bytes[0]),
196       static_cast<gssize>(bytes.size()));
197   if (checksum == nullptr)
198     THROW(BUNDLE_ERROR_OUT_OF_MEMORY);
199
200   std::unique_ptr<gchar, decltype(g_free)*> ptr(checksum, g_free);
201   unsigned char* p = reinterpret_cast<unsigned char*>(checksum);
202   bytes.insert(bytes.begin(), p, p + CHECKSUM_LENGTH);
203
204   unsigned char* raw = static_cast<unsigned char*>(malloc(bytes.size()));
205   if (raw == nullptr)
206     THROW(BUNDLE_ERROR_OUT_OF_MEMORY);
207
208   std::copy(std::make_move_iterator(bytes.begin()),
209       std::make_move_iterator(bytes.end()), raw);
210   *size = static_cast<int>(bytes.size());
211   return raw;
212 }
213
214 int Bundle::DecodeRaw(unsigned char* raw, size_t size) {
215   char* extract_checksum = new (std::nothrow) char[CHECKSUM_LENGTH + 1];
216   if (extract_checksum == nullptr)
217     return BUNDLE_ERROR_OUT_OF_MEMORY;
218
219   std::unique_ptr<char[]> extract_ptr(extract_checksum);
220   unsigned char* d_str = raw;
221   size_t d_len_raw = size;
222   strncpy(extract_checksum, reinterpret_cast<char*>(d_str), CHECKSUM_LENGTH);
223   extract_checksum[CHECKSUM_LENGTH] = '\0';
224
225   gchar* compute_checksum = g_compute_checksum_for_string(G_CHECKSUM_MD5,
226       reinterpret_cast<gchar*>(d_str + CHECKSUM_LENGTH),
227       d_len_raw - CHECKSUM_LENGTH);
228   if (compute_checksum == nullptr)
229     return BUNDLE_ERROR_OUT_OF_MEMORY;
230
231   std::unique_ptr<gchar, decltype(g_free)*> compute_ptr(compute_checksum,
232       g_free);
233   if (strcmp(extract_checksum, static_cast<char*>(compute_checksum)) != 0)
234     return BUNDLE_ERROR_INVALID_PARAMETER;
235
236   unsigned char* d_r = d_str + CHECKSUM_LENGTH;
237   size_t d_len = d_len_raw - CHECKSUM_LENGTH;
238
239   unsigned int reader = 0;
240   std::vector<unsigned char> bytes(d_r, d_r + d_len);
241
242   while (reader < bytes.size()) {
243     std::size_t total_size = -1;
244     unsigned char* p = reinterpret_cast<unsigned char*>(&total_size);
245     std::copy(&bytes[reader], &bytes[reader] + sizeof(total_size), p);
246
247     std::vector<unsigned char> encoded_bytes(
248         &bytes[reader], &bytes[reader] + total_size);
249     reader += total_size;
250
251     KeyInfo* new_key_info;
252     try {
253       new_key_info = new KeyInfo(std::move(encoded_bytes));
254     } catch (const Exception& e) {
255       return e.GetErrorCode();
256     } catch (const std::bad_alloc& ba) {
257       return BUNDLE_ERROR_OUT_OF_MEMORY;
258     }
259
260     auto key_info = std::shared_ptr<KeyInfo>(new_key_info);
261     auto iter = map_.find(key_info->GetKey());
262     if (iter != map_.end())
263       continue;
264
265     map_[key_info->GetKey()] = key_info;
266     list_.push_back(std::move(key_info));
267   }
268
269   return BUNDLE_ERROR_NONE;
270 }
271
272 const std::unordered_map<std::string, std::shared_ptr<KeyInfo>>&
273 Bundle::GetMap() const {
274   return map_;
275 }
276
277 std::vector<std::string> Bundle::Export() {
278   std::vector<std::string> argv(2);
279   for (const auto& key_info : list_) {
280     argv.push_back(key_info->GetKey());
281
282     auto encoded_bytes = key_info->Encode();
283     auto* p = reinterpret_cast<unsigned char*>(&encoded_bytes[0]);
284     auto* base64_bytes = g_base64_encode(p, encoded_bytes.size());
285     if (base64_bytes == nullptr)
286       THROW(BUNDLE_ERROR_OUT_OF_MEMORY);
287
288     std::unique_ptr<gchar, decltype(g_free)*> base64_bytes_ptr(base64_bytes,
289         g_free);
290     argv.push_back(base64_bytes);
291   }
292
293   return argv;
294 }
295
296 int Bundle::Import(int argc, char** argv) {
297   if (argc < 2)
298     return BUNDLE_ERROR_NONE;
299
300   if (!argv[1] || std::strcmp(argv[1], TAG_IMPORT_EXPORT_CHECK)) {
301     for (int idx = 1; idx + 1 < argc; idx += 2) {
302       auto* p = reinterpret_cast<unsigned char*>(argv[idx +1]);
303       auto len = strlen(argv[idx + 1]) + 1;
304       std::vector<unsigned char> value(p, p + len);
305
306       KeyInfo* new_key_info;
307       try {
308         new_key_info = new KeyInfo(Type::String, argv[idx], std::move(value));
309       } catch (const Exception& e) {
310         return e.GetErrorCode();
311       } catch (const std::bad_alloc& ba) {
312         return BUNDLE_ERROR_OUT_OF_MEMORY;
313       }
314
315       auto key_info = std::shared_ptr<KeyInfo>(new_key_info);
316       auto iter = map_.find(key_info->GetKey());
317       if (iter != map_.end())
318         continue;
319
320       map_[key_info->GetKey()] = key_info;
321       list_.push_back(key_info);
322     }
323     return BUNDLE_ERROR_NONE;
324   }
325
326   for (int idx = 2; idx + 1 < argc; idx += 2) {
327     gsize out_len = 0;
328     auto* bytes = g_base64_decode(argv[idx + 1], &out_len);
329     if (bytes == nullptr)
330       return BUNDLE_ERROR_OUT_OF_MEMORY;
331
332     std::unique_ptr<guchar, decltype(g_free)*> bytes_ptr(bytes, g_free);
333
334     if (out_len < sizeof(std::size_t))
335       continue;
336
337     auto* p = reinterpret_cast<unsigned char*>(bytes);
338     std::vector<unsigned char> decoded_bytes(p, p + (out_len + 1));
339
340     KeyInfo* new_key_info;
341     try {
342       new_key_info = new KeyInfo(std::move(decoded_bytes));
343     } catch (const Exception& e) {
344       return e.GetErrorCode();
345     } catch (const std::bad_alloc& ba) {
346       return BUNDLE_ERROR_OUT_OF_MEMORY;
347     }
348
349     auto key_info = std::shared_ptr<KeyInfo>(new_key_info);
350     auto iter = map_.find(key_info->GetKey());
351     if (iter != map_.end())
352       continue;
353
354     map_[key_info->GetKey()] = key_info;
355     list_.push_back(std::move(key_info));
356   }
357
358   return BUNDLE_ERROR_NONE;
359 }
360
361 }  // namespace internal
362 }  // namespace tizen_base