[Bundle] Separate exceptions for invalid handle (#1413)
[platform/core/csapi/tizenfx.git] / src / Tizen.Applications.Common / Tizen.Applications / Bundle.cs
1 /*
2  * Copyright (c) 2016 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 using System;
18 using System.Reflection;
19 using System.Collections.Generic;
20 using System.Linq;
21 using System.Runtime.InteropServices;
22 using Tizen.Internals.Errors;
23
24 namespace Tizen.Applications
25 {
26     /// <summary>
27     /// A bundle object represents a bundle.
28     /// A bundle holds items (key-value pairs) and can be used with other Tizen APIs.
29     /// Keys can be used to access values.
30     /// This class is accessed by using a constructor to create a new instance of this object.
31     /// A bundle instance is not guaranteed to be thread safe if the instance is modified by multiple threads.
32     /// </summary>
33     /// <since_tizen> 3 </since_tizen>
34     public class Bundle : IDisposable
35     {
36         private SafeBundleHandle _handle;
37         private bool _disposed = false;
38         private readonly HashSet<string> _keys;
39
40         /// <summary>
41         /// The bundle constructor.
42         /// </summary>
43         /// <exception cref="System.InvalidOperationException">Thrown when out of memory.</exception>
44         /// <example>
45         /// <code>
46         /// Tizen.Applications.Bundle bundle = new Tizen.Applications.Bundle();
47         /// </code>
48         /// </example>
49         /// <since_tizen> 3 </since_tizen>
50         public Bundle()
51         {
52             _handle = Interop.Bundle.Create();
53             BundleErrorFactory.CheckAndThrowException(ErrorFacts.GetLastResult(), _handle);
54             _keys = new HashSet<string>();
55         }
56
57         /// <summary>
58         /// The bundle constructor.
59         /// </summary>
60         /// <param name="handle">The SafeBundleHandle instance.</param>
61         /// <exception cref="System.ArgumentNullException">Thrown when the handle is null or invalid.</exception>
62         /// <since_tizen> 3 </since_tizen>
63         public Bundle(SafeBundleHandle handle)
64         {
65             if (handle == null)
66             {
67                 throw new ArgumentNullException("handle");
68             }
69
70             if (handle.IsInvalid)
71             {
72                 throw new ArgumentNullException("handle", "handle is invalid");
73             }
74
75             _handle = Interop.Bundle.DangerousClone(handle.DangerousGetHandle());
76             _keys = new HashSet<string>();
77             Interop.Bundle.Iterator iterator = (string key, int type, IntPtr keyval, IntPtr userData) =>
78             {
79                 _keys.Add(key);
80             };
81
82             Interop.Bundle.Foreach(_handle, iterator, IntPtr.Zero);
83             if ((BundleErrorFactory.BundleError)ErrorFacts.GetLastResult() == BundleErrorFactory.BundleError.InvalidParameter)
84             {
85                 throw new ArgumentException("Invalid parameter - cannot create bundle instance");
86             }
87         }
88
89         private enum BundleTypeProperty
90         {
91             Array = 0x0100,
92             Primitive = 0x0200,
93             Measurable = 0x0400
94         }
95
96         private enum BundleType
97         {
98             None = -1,
99             Any = 0,
100             String = 1 | BundleTypeProperty.Measurable,
101             StringArray = String | BundleTypeProperty.Array | BundleTypeProperty.Measurable,
102             Byte = 2,
103             ByteArray = Byte | BundleTypeProperty.Array
104         }
105
106         /// <summary>
107         /// The number of items in a bundle object.
108         /// </summary>
109         /// <example>
110         /// <code>
111         /// Tizen.Applications.Bundle bundle = new Tizen.Applications.Bundle();
112         /// bundle.AddItem("string", "a_string");
113         /// Console.WriteLine("There are {0} items in the bundle", bundle.Count);
114         /// </code>
115         /// </example>
116         /// <since_tizen> 3 </since_tizen>
117         public int Count
118         {
119             get
120             {
121                 return _keys.Count;
122             }
123         }
124
125         /// <summary>
126         /// The keys in a bundle object.
127         /// </summary>
128         /// <example>
129         /// <code>
130         /// Tizen.Applications.Bundle bundle = new Tizen.Applications.Bundle();
131         /// bundle.AddItem("string1", "a_string1");
132         /// bundle.AddItem("string2", "a_string2");
133         /// bundle.AddItem("string3", "a_string3");
134         /// Console.WriteLine("The bundle contains the following keys:");
135         /// foreach(string key in bundle.Keys)
136         /// {
137         ///     Console.WriteLine(key);
138         /// }
139         /// </code>
140         /// </example>
141         /// <since_tizen> 3 </since_tizen>
142         public IEnumerable<string> Keys
143         {
144             get
145             {
146                 return _keys;
147             }
148         }
149
150         /// <summary>
151         /// Gets the SafeBundleHandle instance.
152         /// </summary>
153         /// <since_tizen> 3 </since_tizen>
154         public SafeBundleHandle SafeBundleHandle
155         {
156             get { return _handle; }
157         }
158
159         /// <summary>
160         /// Releases any unmanaged resources used by this object.
161         /// </summary>
162         /// <since_tizen> 3 </since_tizen>
163         public void Dispose()
164         {
165             Dispose(true);
166             GC.SuppressFinalize(this);
167         }
168
169         /// <summary>
170         /// Checks whether the bundle contains an item with a specified key.
171         /// </summary>
172         /// <param name="key">The key to check for.</param>
173         /// <returns>true if the bundle contains the key, false otherwise.</returns>
174         /// <example>
175         /// <code>
176         /// Tizen.Applications.Bundle bundle = new Tizen.Applications.Bundle();
177         /// bundle.AddItem("string", "a_string");
178         /// if (bundle.Contains("string"))
179         /// {
180         ///     string aValue = bundle.GetItem&lt;string&gt;("string");
181         ///     Console.WriteLine(aValue);
182         /// }
183         /// </code>
184         /// </example>
185         /// <since_tizen> 3 </since_tizen>
186         public bool Contains(string key)
187         {
188             return _keys.Contains(key);
189         }
190
191         /// <summary>
192         /// Adds an item into the bundle.
193         /// </summary>
194         /// <param name="key">The key to identify the item with. If an item with the key already exists in the bundle, this method will not succeed.</param>
195         /// <param name="value">The value of the item.</param>
196         /// <exception cref="System.ArgumentException">Thrown when the key already exists or when there is an invalid parameter.</exception>
197         /// <exception cref="System.ArgumentNullException">Thrown when a value is null.</exception>
198         /// <exception cref="System.InvalidOperationException">Thrown when out of memory or when the bundle instance has been disposed.</exception>
199         /// <example>
200         /// <code>
201         /// Tizen.Applications.Bundle bundle = new Tizen.Applications.Bundle();
202         /// byte[] byteArray = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
203         /// bundle.AddItem("byte_array", byteArray);
204         /// </code>
205         /// </example>
206         /// <since_tizen> 3 </since_tizen>
207         public void AddItem(string key, byte[] value)
208         {
209             if (value == null)
210             {
211                 throw new ArgumentNullException("value");
212             }
213             AddItem(key, value, 0, value.Length);
214         }
215
216         /// <summary>
217         /// Adds an item into the bundle.
218         /// </summary>
219         /// <param name="key">The key to identify the item with. If an item with the key already exists in the bundle, this method will not succeed.</param>
220         /// <param name="value">The value of the item.</param>
221         /// <param name="offset">The zero-based byte offset in value from which to add to the bundle.</param>
222         /// <param name="count">The maximum number of bytes to add to the bundle starting with offset.</param>
223         /// <exception cref="System.ArgumentOutOfRangeException">Thrown when the offset or count is out of range.</exception>
224         /// <exception cref="System.ArgumentException">Thrown when the key already exists or when there is an invalid parameter.</exception>
225         /// <exception cref="System.ArgumentNullException">Thrown when a value is null.</exception>
226         /// <exception cref="System.InvalidOperationException">Thrown when out of memory or when the bundle instance has been disposed.</exception>
227         /// <example>
228         /// <code>
229         /// Tizen.Applications.Bundle bundle = new Tizen.Applications.Bundle();
230         /// byte[] byteArray = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
231         /// bundle.AddItem("byte_array", byteArray, 2, 3);
232         /// </code>
233         /// </example>
234         /// <since_tizen> 3 </since_tizen>
235         public void AddItem(string key, byte[] value, int offset, int count)
236         {
237             if (!_keys.Contains(key))
238             {
239                 if (value == null)
240                 {
241                     throw new ArgumentNullException("value");
242                 }
243                 if (offset < 0)
244                 {
245                     throw new ArgumentOutOfRangeException("offset", offset, "Cannot be less than 0");
246                 }
247                 if (offset > value.Length - 1)
248                 {
249                     throw new ArgumentOutOfRangeException("offset", offset, "Greater than last index of array");
250                 }
251                 if (count < 1)
252                 {
253                     throw new ArgumentOutOfRangeException("count", count, "Must be at least 1");
254                 }
255                 if (offset + count > value.Length)
256                 {
257                     throw new ArgumentException("The count is too large for the specified offset");
258                 }
259                 // Code is in Interop file because it is unsafe
260                 int ret = Interop.Bundle.UnsafeCode.AddItem(_handle, key, value, offset, count);
261                 BundleErrorFactory.CheckAndThrowException(ret, _handle);
262                 _keys.Add(key);
263             }
264             else
265             {
266                 throw new ArgumentException("Key already exists", "key");
267             }
268         }
269
270         /// <summary>
271         /// Adds an item into the bundle.
272         /// </summary>
273         /// <param name="key">The key to identify the item with. If an item with the key already exists in the bundle, this method will not succeed.</param>
274         /// <param name="value">The value of the item.</param>
275         /// <exception cref="System.ArgumentException">Thrown when the key already exists or when there is an invalid parameter.</exception>
276         /// <exception cref="System.InvalidOperationException">Thrown when out of memory or when the bundle instance has been disposed.</exception>
277         /// <example>
278         /// <code>
279         /// Tizen.Applications.Bundle bundle = new Tizen.Applications.Bundle();
280         /// bundle.AddItem("string", "a_string");
281         /// </code>
282         /// </example>
283         /// <since_tizen> 3 </since_tizen>
284         public void AddItem(string key, string value)
285         {
286             if (!_keys.Contains(key))
287             {
288                 int ret = Interop.Bundle.AddString(_handle, key, value);
289                 BundleErrorFactory.CheckAndThrowException(ret, _handle);
290                 _keys.Add(key);
291             }
292             else
293             {
294                 throw new ArgumentException("Key already exists", "key");
295             }
296         }
297
298         /// <summary>
299         /// Adds an item into the bundle.
300         /// </summary>
301         /// <param name="key">The key to identify the item with. If an item with the key already exists in the bundle, this method will not succeed.</param>
302         /// <param name="value">The value of the item.</param>
303         /// <exception cref="System.ArgumentException">Thrown when the key already exists or when there is an invalid parameter.</exception>
304         /// <exception cref="System.InvalidOperationException">Thrown when out of memory or when the bundle instance has been disposed.</exception>
305         /// <example>
306         /// <code>
307         /// Tizen.Applications.Bundle bundle = new Tizen.Applications.Bundle();
308         /// string[] stringArray = { "a", "b", "c" };
309         /// bundle.AddItem("string_array", stringArray);
310         /// </code>
311         /// </example>
312         /// <since_tizen> 3 </since_tizen>
313         public void AddItem(string key, IEnumerable<string> value)
314         {
315             if (!_keys.Contains(key))
316             {
317                 string[] valueArray = value.Select(v => v == null ? string.Empty : v).ToArray();
318                 int ret = Interop.Bundle.AddStringArray(_handle, key, valueArray, valueArray.Count());
319                 BundleErrorFactory.CheckAndThrowException(ret, _handle);
320                 _keys.Add(key);
321             }
322             else
323             {
324                 throw new ArgumentException("Key already exists", "key");
325             }
326         }
327
328         /// <summary>
329         /// Gets the value of a bundle item with a specified key.
330         /// </summary>
331         /// <param name="key">The key of the bundle item whose value is desired.</param>
332         /// <returns>The value of the bundle item.</returns>
333         /// <exception cref="System.ArgumentException">Thrown when the key does not exist or when there is an invalid parameter.</exception>
334         /// <exception cref="System.InvalidOperationException">Thrown when the bundle instance has been disposed.</exception>
335         /// <example>
336         /// <code>
337         /// Tizen.Applications.Bundle bundle = new Tizen.Applications.Bundle();
338         /// bundle.AddItem("string", "a_string");
339         /// if (bundle.Contains("string"))
340         /// {
341         ///     object aValue = bundle.GetItem("string");
342         ///     if (bundle.Is&lt;string&gt;("string");)
343         ///     {
344         ///         string aString = (string)aValue;
345         ///         Console.WriteLine(aString);
346         ///     }
347         /// }
348         /// </code>
349         /// </example>
350         /// <since_tizen> 3 </since_tizen>
351         public object GetItem(string key)
352         {
353             if (_keys.Contains(key))
354             {
355                 int type = Interop.Bundle.GetType(_handle, key);
356                 BundleErrorFactory.CheckAndThrowException(ErrorFacts.GetLastResult(), _handle);
357                 switch (type)
358                 {
359                     case (int)BundleType.String:
360                         // get string
361                         IntPtr stringPtr;
362                         int retString = Interop.Bundle.GetString(_handle, key, out stringPtr);
363                         BundleErrorFactory.CheckAndThrowException(retString, _handle);
364                         string stringValue = Marshal.PtrToStringAnsi(stringPtr);
365                         if (stringValue == null)
366                             return string.Empty;
367                         return stringValue;
368
369                     case (int)BundleType.StringArray:
370                         // get string array
371                         int stringArraySize;
372                         IntPtr stringArrayPtr = Interop.Bundle.GetStringArray(_handle, key, out stringArraySize);
373                         BundleErrorFactory.CheckAndThrowException(ErrorFacts.GetLastResult(), _handle);
374                         string[] stringArray;
375                         IntPtrToStringArray(stringArrayPtr, stringArraySize, out stringArray);
376                         return stringArray;
377
378                     case (int)BundleType.Byte:
379                         // get byte array
380                         IntPtr byteArrayPtr;
381                         int byteArraySize;
382                         int retByte = Interop.Bundle.GetByte(_handle, key, out byteArrayPtr, out byteArraySize);
383                         BundleErrorFactory.CheckAndThrowException(retByte, _handle);
384                         byte[] byteArray = new byte[byteArraySize];
385                         Marshal.Copy(byteArrayPtr, byteArray, 0, byteArraySize);
386                         return byteArray;
387
388                     default:
389                         throw new ArgumentException("Key does not exist in the bundle", "key");
390                 }
391             }
392             else
393             {
394                 throw new ArgumentException("Key does not exist in the bundle (may be null or empty string)", "key");
395             }
396         }
397
398         /// <summary>
399         /// Gets the value of a bundle item with a specified key.
400         /// Note that this is a generic method.
401         /// </summary>
402         /// <typeparam name="T">The generic type to return.</typeparam>
403         /// <param name="key">The key of the bundle item whose value is desired.</param>
404         /// <returns>The value of the bundle item if it is of the specified generic type.</returns>
405         /// <exception cref="System.ArgumentException">Thrown when the key does not exist or when there is an invalid parameter.</exception>
406         /// <exception cref="System.InvalidCastException">Thrown when the value of the bundle item cannot be converted to the specified generic type.</exception>
407         /// <exception cref="System.InvalidOperationException">Thrown when the bundle instance has been disposed.</exception>
408         /// <example>
409         /// <code>
410         /// Tizen.Applications.Bundle bundle = new Tizen.Applications.Bundle();
411         /// string[] stringArray = { "a", "b", "c" };
412         /// bundle.AddItem("string_array", stringArray);
413         /// if (bundle.Is&lt;string&gt;("string_array"))
414         /// {
415         ///     Console.WriteLine("It is a string");
416         ///     Console.WriteLine(bundle.GetItem&lt;string&gt;("string_array"));
417         /// }
418         /// else if (bundle.Is&lt;string[]&gt;("string_array"))
419         /// {
420         ///     Console.WriteLine("It is a string[]");
421         ///     string[] anArray = bundle.GetItem&lt;string[]&gt;("string_array");
422         ///     foreach (string value in anArray)
423         ///     {
424         ///         Console.WriteLine(value);
425         ///     }
426         /// }
427         /// </code>
428         /// </example>
429         /// <since_tizen> 3 </since_tizen>
430         public T GetItem<T>(string key)
431         {
432             return (T)GetItem(key);
433         }
434
435         /// <summary>
436         /// Gets the value of a bundle item with a specified key.
437         /// </summary>
438         /// <param name="key">The key of the bundle item whose value is desired.</param>
439         /// <param name="value">The value of the bundle item. If the key does not exist or the type of this parameter is incorrect, it is the default value for the value parameter type.</param>
440         /// <returns>true if an item with the key exists and if the value is the same type as the output value parameter, false otherwise.</returns>
441         /// <exception cref="System.InvalidOperationException">Thrown when the bundle instance has been disposed.</exception>
442         /// <example>
443         /// <code>
444         /// Tizen.Applications.Bundle bundle = new Tizen.Applications.Bundle();
445         /// byte[] byteArray = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
446         /// bundle.AddItem("byte_array", byteArray);
447         /// byte[] aByteArray;
448         /// if (bundle.TryGetItem("byte_array", out aByteArray))
449         /// {
450         ///     Console.WriteLine("First item in the byte array: {0}", aByteArray[0]);
451         /// }
452         /// </code>
453         /// </example>
454         /// <since_tizen> 3 </since_tizen>
455         public bool TryGetItem(string key, out byte[] value)
456         {
457             if (_keys.Contains(key) && Interop.Bundle.GetType(_handle, key) == (int)BundleType.Byte)
458             {
459                 value = GetItem<byte[]>(key);
460                 return true;
461             }
462             else
463             {
464                 if (_keys.Contains(key) && ErrorFacts.GetLastResult() == (int)BundleErrorFactory.BundleError.InvalidParameter)
465                 {
466                     throw new InvalidOperationException("Invalid bundle instance (object may have been disposed or released)");
467                 }
468                 value = default(byte[]);
469                 return false;
470             }
471         }
472
473         /// <summary>
474         /// Gets the value of a bundle item with a specified key.
475         /// </summary>
476         /// <param name="key">The key of the bundle item whose value is desired.</param>
477         /// <param name="value">The value of the bundle item. If the key does not exist or the type of this parameter is incorrect, it is the default value for the value parameter type.</param>
478         /// <returns>true if an item with the key exists and if the value is the same type as the output value parameter, false otherwise.</returns>
479         /// <exception cref="System.InvalidOperationException">Thrown when the bundle instance has been disposed.</exception>
480         /// <example>
481         /// <code>
482         /// Tizen.Applications.Bundle bundle = new Tizen.Applications.Bundle();
483         /// bundle.AddItem("string", "a_string");
484         /// string aString;
485         /// if (bundle.TryGetItem("string", out aString))
486         /// {
487         ///     Console.WriteLine(aString);
488         /// }
489         /// </code>
490         /// </example>
491         /// <since_tizen> 3 </since_tizen>
492         public bool TryGetItem(string key, out string value)
493         {
494             if (_keys.Contains(key) && Interop.Bundle.GetType(_handle, key) == (int)BundleType.String)
495             {
496                 value = GetItem<string>(key);
497                 return true;
498             }
499             else
500             {
501                 if (_keys.Contains(key) && ErrorFacts.GetLastResult() == (int)BundleErrorFactory.BundleError.InvalidParameter)
502                 {
503                     throw new InvalidOperationException("Invalid bundle instance (object may have been disposed or released)");
504                 }
505                 value = default(string);
506                 return false;
507             }
508         }
509
510         /// <summary>
511         /// Gets the value of a bundle item with a specified key.
512         /// </summary>
513         /// <param name="key">The key of the bundle item whose value is desired.</param>
514         /// <param name="value">The value of the bundle item. If the key does not exist or the type of this parameter is incorrect, it is the default value for the value parameter type.</param>
515         /// <returns>true if an item with the key exists and if the value is the same type as the output value parameter, false otherwise.</returns>
516         /// <exception cref="System.InvalidOperationException">Thrown when the bundle instance has been disposed.</exception>
517         /// <example>
518         /// <code>
519         /// Tizen.Applications.Bundle bundle = new Tizen.Applications.Bundle();
520         /// string[] stringArray = { "a", "b", "c" };
521         /// bundle.AddItem("string_array", stringArray);
522         /// System.Collections.Generic.IEnumerable&lt;string&gt; aStringEnumerable;
523         /// if (bundle.TryGetItem("string", out aStringEnumerable))
524         /// {
525         ///     foreach (string value in aStringEnumerable)
526         ///     {
527         ///         Console.WriteLine(value);
528         ///     }
529         /// }
530         /// </code>
531         /// </example>
532         /// <since_tizen> 3 </since_tizen>
533         public bool TryGetItem(string key, out IEnumerable<string> value)
534         {
535             if (_keys.Contains(key) && Interop.Bundle.GetType(_handle, key) == (int)BundleType.StringArray)
536             {
537                 value = GetItem<IEnumerable<string>>(key);
538                 return true;
539             }
540             else
541             {
542                 if (_keys.Contains(key) && ErrorFacts.GetLastResult() == (int)BundleErrorFactory.BundleError.InvalidParameter)
543                 {
544                     throw new InvalidOperationException("Invalid bundle instance (object may have been disposed or released)");
545                 }
546                 value = default(IEnumerable<string>);
547                 return false;
548             }
549         }
550
551         /// <summary>
552         /// Checks whether an item is of a specific type.
553         /// </summary>
554         /// <typeparam name="T">The generic type to check for.</typeparam>
555         /// <param name="key">The key whose type wants to be checked.</param>
556         /// <returns>true if the item is of the specified type, false otherwise.</returns>
557         /// <exception cref="System.ArgumentException">Thrown when the key does not exist or when there is an invalid parameter.</exception>
558         /// <exception cref="System.InvalidOperationException">Thrown when the bundle instance has been disposed.</exception>
559         /// <example>
560         /// <code>
561         /// Tizen.Applications.Bundle bundle = new Tizen.Applications.Bundle();
562         /// string[] stringArray = { "a", "b", "c" };
563         /// bundle.AddItem("string_array", stringArray);
564         /// if (bundle.Is&lt;string[]&gt;("string_array"))
565         /// {
566         ///     Console.WriteLine("It is a string[]");
567         ///     string[] anArray = bundle.GetItem&lt;string[]&gt;("string_array");
568         ///     foreach (string value in anArray)
569         ///     {
570         ///         Console.WriteLine(value);
571         ///     }
572         /// }
573         /// </code>
574         /// </example>
575         /// <since_tizen> 3 </since_tizen>
576         public bool Is<T>(string key)
577         {
578             if (_keys.Contains(key))
579             {
580                 int type = Interop.Bundle.GetType(_handle, key);
581                 switch (type)
582                 {
583                     case (int)BundleType.String:
584                         return typeof(string) == typeof(T);
585
586                     case (int)BundleType.StringArray:
587                         return typeof(T).GetTypeInfo().IsAssignableFrom(typeof(string[]).GetTypeInfo());
588
589                     case (int)BundleType.Byte:
590                         return typeof(byte[]) == typeof(T);
591
592                     default:
593                         throw new ArgumentException("Key does not exist in the bundle", "key");
594                 }
595             }
596             else
597             {
598                 throw new ArgumentException("Key does not exist in the bundle (may be null or empty string)", "key");
599             }
600         }
601
602         /// <summary>
603         /// Removes a bundle item with a specific key from a Bundle.
604         /// </summary>
605         /// <param name="key">The key of the item to delete.</param>
606         /// <returns>true if the item is successfully found and removed, false otherwise (even if the item is not found).</returns>
607         /// <exception cref="System.ArgumentException">Thrown when there is an invalid parameter.</exception>
608         /// <exception cref="System.InvalidOperationException">Thrown when the bundle instance has been disposed.</exception>
609         /// <example>
610         /// <code>
611         /// Tizen.Applications.Bundle bundle = new Tizen.Applications.Bundle();
612         /// bundle.AddItem("string", "a_string");
613         /// if (bundle.Contains("string"))
614         /// {
615         ///     if (bundle.RemoveItem("string"))
616         ///     {
617         ///         Console.WriteLine("Removed");
618         ///     }
619         /// }
620         /// </code>
621         /// </example>
622         /// <since_tizen> 3 </since_tizen>
623         public bool RemoveItem(string key)
624         {
625             if (_keys.Contains(key))
626             {
627                 int ret = Interop.Bundle.RemoveItem(_handle, key);
628                 if (ret == (int)BundleErrorFactory.BundleError.KeyNotAvailable)
629                 {
630                     return false;
631                 }
632                 BundleErrorFactory.CheckAndThrowException(ret, _handle);
633                 _keys.Remove(key);
634                 return true;
635             }
636             else
637             {
638                 return false;
639             }
640         }
641
642         /// <summary>
643         /// Decodes an encoded bundle data.
644         /// </summary>
645         /// <param name="bundleRaw">The encoded bundle data. bundleRaw should be the returned value of Tizen.Applications.Bundle.Encode, otherwise this method will not succeed.</param>
646         /// <returns>Decoded Bundle object.</returns>
647         /// <exception cref="System.ArgumentException">Thrown when there is an invalid parameter.</exception>
648         /// <example>
649         /// <code>
650         /// Tizen.Applications.Bundle bundle = new Tizen.Applications.Bundle();
651         /// string bundleRaw = bundle.Encode();
652         /// Bundle data = bundle.Decode(bundleRaw);
653         /// </code>
654         /// </example>
655         /// <since_tizen> 3 </since_tizen>
656         public static Bundle Decode(string bundleRaw)
657         {
658             SafeBundleHandle handle;
659
660             handle = Interop.Bundle.BundleDecode(bundleRaw, bundleRaw.Length);
661             if (ErrorFacts.GetLastResult() == (int)BundleErrorFactory.BundleError.InvalidParameter)
662             {
663                 throw new ArgumentException("Invalid bundle raw");
664             }
665
666             return new Bundle(handle);
667         }
668
669         /// <summary>
670         /// Encodes bundle to string.
671         /// </summary>
672         /// <returns>Encoded bundle data in string.</returns>
673         /// <exception cref="System.InvalidOperationException">Thrown when out of memory or when the bundle instance has been disposed.</exception>
674         /// <example>
675         /// <code>
676         /// Tizen.Applications.Bundle bundle = new Tizen.Applications.Bundle();
677         /// string bundleRaw = bundle.Encode();
678         /// </code>
679         /// </example>
680         /// <since_tizen> 3 </since_tizen>
681         public string Encode()
682         {
683             string bundleRaw;
684             int len;
685
686             Interop.Bundle.BundleEncode(_handle, out bundleRaw, out len);
687             if (ErrorFacts.GetLastResult() == (int)BundleErrorFactory.BundleError.InvalidParameter)
688             {
689                 throw new InvalidOperationException("Invalid bundle");
690             }
691
692             return bundleRaw;
693         }
694
695         /// <summary>
696         /// Releases any unmanaged resources used by this object. Can also dispose any other disposable objects.
697         /// </summary>
698         /// <param name="disposing">If true, disposes any disposable objects. If false, does not dispose disposable objects.</param>
699         /// <since_tizen> 3 </since_tizen>
700         protected virtual void Dispose(bool disposing)
701         {
702             if (!_disposed)
703             {
704                 if (disposing)
705                 {
706                     if (_handle != null && !_handle.IsInvalid)
707                         _handle.Dispose();
708                 }
709
710                 _disposed = true;
711             }
712         }
713
714         /// <summary>
715         /// Destructor of the bundle class.
716         /// </summary>
717         ~Bundle()
718         {
719             Dispose(false);
720         }
721
722         static private void IntPtrToStringArray(IntPtr unmanagedArray, int size, out string[] managedArray)
723         {
724             managedArray = new string[size];
725             IntPtr[] IntPtrArray = new IntPtr[size];
726
727             Marshal.Copy(unmanagedArray, IntPtrArray, 0, size);
728
729             for (int iterator = 0; iterator < size; iterator++)
730             {
731                 managedArray[iterator] = Marshal.PtrToStringAnsi(IntPtrArray[iterator]);
732             }
733         }
734     }
735
736     internal static class BundleErrorFactory
737     {
738         internal enum BundleError
739         {
740             None = ErrorCode.None,
741             OutOfMemory = ErrorCode.OutOfMemory,
742             InvalidParameter = ErrorCode.InvalidParameter,
743             KeyNotAvailable = ErrorCode.KeyNotAvailable,
744             KeyExists = -0x01180000 | 0x01
745         }
746
747         static internal void CheckAndThrowException(int error, SafeBundleHandle handle)
748         {
749             if ((BundleError)error == BundleError.None)
750             {
751                 return;
752             }
753             else if ((BundleError)error == BundleError.OutOfMemory)
754             {
755                 throw new InvalidOperationException("Out of memory");
756             }
757             else if ((BundleError)error == BundleError.InvalidParameter)
758             {
759                 if (handle.IsInvalid)
760                 {
761                     throw new InvalidOperationException("Invalid bundle instance (object may have been disposed or released)");
762                 }
763                 throw new ArgumentException("Invalid parameter");
764             }
765             else if ((BundleError)error == BundleError.KeyNotAvailable)
766             {
767                 throw new ArgumentException("Key does not exist in the bundle");
768             }
769             else if ((BundleError)error == BundleError.KeyExists)
770             {
771                 throw new ArgumentException("Key already exists");
772             }
773         }
774     }
775 }