2 * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 using System.Reflection;
19 using System.Collections.Generic;
21 using System.Runtime.InteropServices;
22 using Tizen.Internals.Errors;
24 namespace Tizen.Applications
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.
33 /// <since_tizen> 3 </since_tizen>
34 public class Bundle : IDisposable
36 private SafeBundleHandle _handle;
37 private bool _disposed = false;
38 private readonly HashSet<string> _keys;
41 /// The bundle constructor.
43 /// <exception cref="System.InvalidOperationException">Thrown when out of memory.</exception>
46 /// Tizen.Applications.Bundle bundle = new Tizen.Applications.Bundle();
49 /// <since_tizen> 3 </since_tizen>
52 _handle = Interop.Bundle.Create();
53 BundleErrorFactory.CheckAndThrowException(ErrorFacts.GetLastResult(), _handle);
54 _keys = new HashSet<string>();
58 /// The bundle constructor.
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)
67 throw new ArgumentNullException("handle");
72 throw new ArgumentNullException("handle", "handle is invalid");
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) =>
82 Interop.Bundle.Foreach(_handle, iterator, IntPtr.Zero);
83 if ((BundleErrorFactory.BundleError)ErrorFacts.GetLastResult() == BundleErrorFactory.BundleError.InvalidParameter)
85 throw new ArgumentException("Invalid parameter - cannot create bundle instance");
89 private enum BundleTypeProperty
96 private enum BundleType
100 String = 1 | BundleTypeProperty.Measurable,
101 StringArray = String | BundleTypeProperty.Array | BundleTypeProperty.Measurable,
103 ByteArray = Byte | BundleTypeProperty.Array
107 /// The number of items in a bundle object.
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);
116 /// <since_tizen> 3 </since_tizen>
126 /// The keys in a bundle object.
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)
137 /// Console.WriteLine(key);
141 /// <since_tizen> 3 </since_tizen>
142 public IEnumerable<string> Keys
151 /// Gets the SafeBundleHandle instance.
153 /// <since_tizen> 3 </since_tizen>
154 public SafeBundleHandle SafeBundleHandle
156 get { return _handle; }
160 /// Releases any unmanaged resources used by this object.
162 /// <since_tizen> 3 </since_tizen>
163 public void Dispose()
166 GC.SuppressFinalize(this);
170 /// Checks whether the bundle contains an item with a specified key.
172 /// <param name="key">The key to check for.</param>
173 /// <returns>true if the bundle contains the key, false otherwise.</returns>
176 /// Tizen.Applications.Bundle bundle = new Tizen.Applications.Bundle();
177 /// bundle.AddItem("string", "a_string");
178 /// if (bundle.Contains("string"))
180 /// string aValue = bundle.GetItem<string>("string");
181 /// Console.WriteLine(aValue);
185 /// <since_tizen> 3 </since_tizen>
186 public bool Contains(string key)
188 return _keys.Contains(key);
192 /// Adds an item into the bundle.
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>
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);
206 /// <since_tizen> 3 </since_tizen>
207 public void AddItem(string key, byte[] value)
211 throw new ArgumentNullException("value");
213 AddItem(key, value, 0, value.Length);
217 /// Adds an item into the bundle.
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>
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);
234 /// <since_tizen> 3 </since_tizen>
235 public void AddItem(string key, byte[] value, int offset, int count)
237 if (!_keys.Contains(key))
241 throw new ArgumentNullException("value");
245 throw new ArgumentOutOfRangeException("offset", offset, "Cannot be less than 0");
247 if (offset > value.Length - 1)
249 throw new ArgumentOutOfRangeException("offset", offset, "Greater than last index of array");
253 throw new ArgumentOutOfRangeException("count", count, "Must be at least 1");
255 if (offset + count > value.Length)
257 throw new ArgumentException("The count is too large for the specified offset");
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);
266 throw new ArgumentException("Key already exists", "key");
271 /// Adds an item into the bundle.
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>
279 /// Tizen.Applications.Bundle bundle = new Tizen.Applications.Bundle();
280 /// bundle.AddItem("string", "a_string");
283 /// <since_tizen> 3 </since_tizen>
284 public void AddItem(string key, string value)
286 if (!_keys.Contains(key))
288 int ret = Interop.Bundle.AddString(_handle, key, value);
289 BundleErrorFactory.CheckAndThrowException(ret, _handle);
294 throw new ArgumentException("Key already exists", "key");
299 /// Adds an item into the bundle.
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>
307 /// Tizen.Applications.Bundle bundle = new Tizen.Applications.Bundle();
308 /// string[] stringArray = { "a", "b", "c" };
309 /// bundle.AddItem("string_array", stringArray);
312 /// <since_tizen> 3 </since_tizen>
313 public void AddItem(string key, IEnumerable<string> value)
315 if (!_keys.Contains(key))
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);
324 throw new ArgumentException("Key already exists", "key");
329 /// Gets the value of a bundle item with a specified key.
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>
337 /// Tizen.Applications.Bundle bundle = new Tizen.Applications.Bundle();
338 /// bundle.AddItem("string", "a_string");
339 /// if (bundle.Contains("string"))
341 /// object aValue = bundle.GetItem("string");
342 /// if (bundle.Is<string>("string");)
344 /// string aString = (string)aValue;
345 /// Console.WriteLine(aString);
350 /// <since_tizen> 3 </since_tizen>
351 public object GetItem(string key)
353 if (_keys.Contains(key))
355 int type = Interop.Bundle.GetType(_handle, key);
356 BundleErrorFactory.CheckAndThrowException(ErrorFacts.GetLastResult(), _handle);
359 case (int)BundleType.String:
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)
369 case (int)BundleType.StringArray:
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);
378 case (int)BundleType.Byte:
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);
389 throw new ArgumentException("Key does not exist in the bundle", "key");
394 throw new ArgumentException("Key does not exist in the bundle (may be null or empty string)", "key");
399 /// Gets the value of a bundle item with a specified key.
400 /// Note that this is a generic method.
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>
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<string>("string_array"))
415 /// Console.WriteLine("It is a string");
416 /// Console.WriteLine(bundle.GetItem<string>("string_array"));
418 /// else if (bundle.Is<string[]>("string_array"))
420 /// Console.WriteLine("It is a string[]");
421 /// string[] anArray = bundle.GetItem<string[]>("string_array");
422 /// foreach (string value in anArray)
424 /// Console.WriteLine(value);
429 /// <since_tizen> 3 </since_tizen>
430 public T GetItem<T>(string key)
432 return (T)GetItem(key);
436 /// Gets the value of a bundle item with a specified key.
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>
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))
450 /// Console.WriteLine("First item in the byte array: {0}", aByteArray[0]);
454 /// <since_tizen> 3 </since_tizen>
455 public bool TryGetItem(string key, out byte[] value)
457 if (_keys.Contains(key) && Interop.Bundle.GetType(_handle, key) == (int)BundleType.Byte)
459 value = GetItem<byte[]>(key);
464 if (_keys.Contains(key) && ErrorFacts.GetLastResult() == (int)BundleErrorFactory.BundleError.InvalidParameter)
466 throw new InvalidOperationException("Invalid bundle instance (object may have been disposed or released)");
468 value = default(byte[]);
474 /// Gets the value of a bundle item with a specified key.
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>
482 /// Tizen.Applications.Bundle bundle = new Tizen.Applications.Bundle();
483 /// bundle.AddItem("string", "a_string");
485 /// if (bundle.TryGetItem("string", out aString))
487 /// Console.WriteLine(aString);
491 /// <since_tizen> 3 </since_tizen>
492 public bool TryGetItem(string key, out string value)
494 if (_keys.Contains(key) && Interop.Bundle.GetType(_handle, key) == (int)BundleType.String)
496 value = GetItem<string>(key);
501 if (_keys.Contains(key) && ErrorFacts.GetLastResult() == (int)BundleErrorFactory.BundleError.InvalidParameter)
503 throw new InvalidOperationException("Invalid bundle instance (object may have been disposed or released)");
505 value = default(string);
511 /// Gets the value of a bundle item with a specified key.
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>
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<string> aStringEnumerable;
523 /// if (bundle.TryGetItem("string", out aStringEnumerable))
525 /// foreach (string value in aStringEnumerable)
527 /// Console.WriteLine(value);
532 /// <since_tizen> 3 </since_tizen>
533 public bool TryGetItem(string key, out IEnumerable<string> value)
535 if (_keys.Contains(key) && Interop.Bundle.GetType(_handle, key) == (int)BundleType.StringArray)
537 value = GetItem<IEnumerable<string>>(key);
542 if (_keys.Contains(key) && ErrorFacts.GetLastResult() == (int)BundleErrorFactory.BundleError.InvalidParameter)
544 throw new InvalidOperationException("Invalid bundle instance (object may have been disposed or released)");
546 value = default(IEnumerable<string>);
552 /// Checks whether an item is of a specific type.
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>
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<string[]>("string_array"))
566 /// Console.WriteLine("It is a string[]");
567 /// string[] anArray = bundle.GetItem<string[]>("string_array");
568 /// foreach (string value in anArray)
570 /// Console.WriteLine(value);
575 /// <since_tizen> 3 </since_tizen>
576 public bool Is<T>(string key)
578 if (_keys.Contains(key))
580 int type = Interop.Bundle.GetType(_handle, key);
583 case (int)BundleType.String:
584 return typeof(string) == typeof(T);
586 case (int)BundleType.StringArray:
587 return typeof(T).GetTypeInfo().IsAssignableFrom(typeof(string[]).GetTypeInfo());
589 case (int)BundleType.Byte:
590 return typeof(byte[]) == typeof(T);
593 throw new ArgumentException("Key does not exist in the bundle", "key");
598 throw new ArgumentException("Key does not exist in the bundle (may be null or empty string)", "key");
603 /// Removes a bundle item with a specific key from a Bundle.
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>
611 /// Tizen.Applications.Bundle bundle = new Tizen.Applications.Bundle();
612 /// bundle.AddItem("string", "a_string");
613 /// if (bundle.Contains("string"))
615 /// if (bundle.RemoveItem("string"))
617 /// Console.WriteLine("Removed");
622 /// <since_tizen> 3 </since_tizen>
623 public bool RemoveItem(string key)
625 if (_keys.Contains(key))
627 int ret = Interop.Bundle.RemoveItem(_handle, key);
628 if (ret == (int)BundleErrorFactory.BundleError.KeyNotAvailable)
632 BundleErrorFactory.CheckAndThrowException(ret, _handle);
643 /// Decodes an encoded bundle data.
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>
650 /// Tizen.Applications.Bundle bundle = new Tizen.Applications.Bundle();
651 /// string bundleRaw = bundle.Encode();
652 /// Bundle data = bundle.Decode(bundleRaw);
655 /// <since_tizen> 3 </since_tizen>
656 public static Bundle Decode(string bundleRaw)
658 SafeBundleHandle handle;
660 handle = Interop.Bundle.BundleDecode(bundleRaw, bundleRaw.Length);
661 if (ErrorFacts.GetLastResult() == (int)BundleErrorFactory.BundleError.InvalidParameter)
663 throw new ArgumentException("Invalid bundle raw");
666 return new Bundle(handle);
670 /// Encodes bundle to string.
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>
676 /// Tizen.Applications.Bundle bundle = new Tizen.Applications.Bundle();
677 /// string bundleRaw = bundle.Encode();
680 /// <since_tizen> 3 </since_tizen>
681 public string Encode()
686 Interop.Bundle.BundleEncode(_handle, out bundleRaw, out len);
687 if (ErrorFacts.GetLastResult() == (int)BundleErrorFactory.BundleError.InvalidParameter)
689 throw new InvalidOperationException("Invalid bundle");
696 /// Releases any unmanaged resources used by this object. Can also dispose any other disposable objects.
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)
706 if (_handle != null && !_handle.IsInvalid)
715 /// Destructor of the bundle class.
722 static private void IntPtrToStringArray(IntPtr unmanagedArray, int size, out string[] managedArray)
724 managedArray = new string[size];
725 IntPtr[] IntPtrArray = new IntPtr[size];
727 Marshal.Copy(unmanagedArray, IntPtrArray, 0, size);
729 for (int iterator = 0; iterator < size; iterator++)
731 managedArray[iterator] = Marshal.PtrToStringAnsi(IntPtrArray[iterator]);
736 internal static class BundleErrorFactory
738 internal enum BundleError
740 None = ErrorCode.None,
741 OutOfMemory = ErrorCode.OutOfMemory,
742 InvalidParameter = ErrorCode.InvalidParameter,
743 KeyNotAvailable = ErrorCode.KeyNotAvailable,
744 KeyExists = -0x01180000 | 0x01
747 static internal void CheckAndThrowException(int error, SafeBundleHandle handle)
749 if ((BundleError)error == BundleError.None)
753 else if ((BundleError)error == BundleError.OutOfMemory)
755 throw new InvalidOperationException("Out of memory");
757 else if ((BundleError)error == BundleError.InvalidParameter)
759 if (handle.IsInvalid)
761 throw new InvalidOperationException("Invalid bundle instance (object may have been disposed or released)");
763 throw new ArgumentException("Invalid parameter");
765 else if ((BundleError)error == BundleError.KeyNotAvailable)
767 throw new ArgumentException("Key does not exist in the bundle");
769 else if ((BundleError)error == BundleError.KeyExists)
771 throw new ArgumentException("Key already exists");