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