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