// <copyright company="APX Labs, Inc.">
|
// Copyright (c) APX Labs, Inc. All rights reserved.
|
// </copyright>
|
//
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
//
|
// http://www.apache.org/licenses/LICENSE-2.0
|
//
|
// Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
// limitations under the License.
|
|
using System;
|
using System.Collections;
|
using System.Collections.Generic;
|
using System.Diagnostics;
|
using System.Runtime.InteropServices;
|
using Java.Interop;
|
|
namespace ApxLabs.FastAndroidCamera
|
{
|
/// <summary>
|
/// A wrapper around a Java array that reads elements directly from the pointer instead of through expensive JNI calls.
|
/// </summary>
|
public sealed class FastJavaByteArray : IList<byte>, IDisposable
|
{
|
private JniObjectReference _javaRef;
|
|
#region Constructors
|
|
/// <summary>
|
/// Creates a new FastJavaByteArray with the given number of bytes reserved.
|
/// </summary>
|
/// <param name="length">Number of bytes to reserve</param>
|
public FastJavaByteArray(int length)
|
{
|
if (length <= 0)
|
throw new ArgumentOutOfRangeException();
|
|
JniObjectReference localRef = JniEnvironment.Arrays.NewByteArray(length);
|
if (!localRef.IsValid)
|
throw new OutOfMemoryException();
|
|
// Retain a global reference to the byte array.
|
_javaRef = localRef.NewGlobalRef();
|
Count = length;
|
|
bool isCopy = false;
|
unsafe
|
{
|
// Get the pointer to the byte array using the global Handle
|
Raw = (byte*)JniEnvironment.Arrays.GetByteArrayElements(_javaRef, &isCopy);
|
}
|
}
|
|
/// <summary>
|
/// Creates a FastJavaByteArray wrapper around an existing Java/JNI byte array
|
/// </summary>
|
/// <param name="handle">Native Java array handle</param>
|
/// <param name="readOnly">Whether to consider this byte array read-only</param>
|
public FastJavaByteArray(IntPtr handle, bool readOnly = true)
|
{
|
if (handle == IntPtr.Zero)
|
throw new ArgumentNullException("handle");
|
|
IsReadOnly = readOnly;
|
|
// Retain a global reference to the byte array.
|
_javaRef = new JniObjectReference(handle).NewGlobalRef();
|
Count = JniEnvironment.Arrays.GetArrayLength(_javaRef);
|
|
bool isCopy = false;
|
unsafe
|
{
|
// Get a pinned pointer to the byte array using the global Handle
|
Raw = (byte*)JniEnvironment.Arrays.GetByteArrayElements(_javaRef, &isCopy);
|
}
|
}
|
|
#endregion
|
|
#region Dispose Pattern
|
|
/// <summary>
|
/// Releases unmanaged resources and performs other cleanup operations before the
|
/// <see cref="T:ApxLabs.FastAndroidCamera.FastJavaByteArray"/> is reclaimed by garbage collection.
|
/// </summary>
|
~FastJavaByteArray()
|
{
|
Dispose(false);
|
}
|
|
/// <summary>
|
/// Releases all resource used by the <see cref="T:ApxLabs.FastAndroidCamera.FastJavaByteArray"/> object.
|
/// </summary>
|
/// <remarks>Call <see cref="Dispose"/> when you are finished using the
|
/// <see cref="T:ApxLabs.FastAndroidCamera.FastJavaByteArray"/>. The <see cref="Dispose"/> method leaves the
|
/// <see cref="T:ApxLabs.FastAndroidCamera.FastJavaByteArray"/> in an unusable state. After calling
|
/// <see cref="Dispose"/>, you must release all references to the
|
/// <see cref="T:ApxLabs.FastAndroidCamera.FastJavaByteArray"/> so the garbage collector can reclaim the memory that
|
/// the <see cref="T:ApxLabs.FastAndroidCamera.FastJavaByteArray"/> was occupying.</remarks>
|
public void Dispose()
|
{
|
Dispose(true);
|
GC.SuppressFinalize(this);
|
}
|
|
private void Dispose(bool disposing)
|
{
|
if (!_javaRef.IsValid)
|
return;
|
|
unsafe
|
{
|
// tell Java that we're done with this array
|
JniEnvironment.Arrays.ReleaseByteArrayElements(_javaRef, (sbyte*)Raw, JniReleaseArrayElementsMode.Default);
|
}
|
|
if (disposing)
|
{
|
JniObjectReference.Dispose(ref _javaRef);
|
}
|
}
|
|
#endregion
|
|
#region IList<byte> Properties
|
|
/// <summary>
|
/// Count of bytes
|
/// </summary>
|
public int Count { get; private set; }
|
|
/// <summary>
|
/// Gets a value indicating whether this byte array is read only.
|
/// </summary>
|
/// <value><c>true</c> if read only; otherwise, <c>false</c>.</value>
|
public bool IsReadOnly
|
{
|
get;
|
private set;
|
}
|
|
/// <summary>
|
/// Indexer
|
/// </summary>
|
/// <param name="index">Index of byte</param>
|
/// <returns>Byte at the given index</returns>
|
public byte this[int index]
|
{
|
get
|
{
|
if (index < 0 || index >= Count)
|
{
|
throw new ArgumentOutOfRangeException();
|
}
|
byte retval;
|
unsafe
|
{
|
retval = Raw[index];
|
}
|
return retval;
|
}
|
set
|
{
|
if (IsReadOnly)
|
{
|
throw new NotSupportedException("This FastJavaByteArray is read-only");
|
}
|
|
if (index < 0 || index >= Count)
|
{
|
throw new ArgumentOutOfRangeException();
|
}
|
unsafe
|
{
|
Raw[index] = value;
|
}
|
}
|
}
|
|
#endregion
|
|
#region IList<byte> Methods
|
|
/// <summary>
|
/// Adds a single byte to the list. Not supported
|
/// </summary>
|
/// <param name="item">byte to add</param>
|
public void Add(byte item)
|
{
|
throw new NotSupportedException("FastJavaByteArray is fixed length");
|
}
|
|
/// <summary>
|
/// Not supported
|
/// </summary>
|
public void Clear()
|
{
|
throw new NotSupportedException("FastJavaByteArray is fixed length");
|
}
|
|
/// <summary>
|
/// Returns true if the item is found int he array
|
/// </summary>
|
/// <param name="item">Item to find</param>
|
/// <returns>True if the item is found</returns>
|
public bool Contains(byte item)
|
{
|
return IndexOf(item) >= 0;
|
}
|
|
/// <summary>
|
/// Copies the contents of the FastJavaByteArray into a byte array
|
/// </summary>
|
/// <param name="array">The array to copy to.</param>
|
/// <param name="arrayIndex">The zero-based index into the destination array where CopyTo should start.</param>
|
public void CopyTo(byte[] array, int arrayIndex)
|
{
|
unsafe
|
{
|
Marshal.Copy(new IntPtr(Raw), array, arrayIndex, Math.Min(Count, array.Length - arrayIndex));
|
}
|
}
|
|
/// <summary>
|
/// Retreives enumerator
|
/// </summary>
|
/// <returns>Enumerator</returns>
|
[DebuggerHidden]
|
public IEnumerator<byte> GetEnumerator()
|
{
|
return new FastJavaByteArrayEnumerator(this);
|
}
|
|
/// <summary>
|
/// Retreives enumerator
|
/// </summary>
|
/// <returns>Enumerator</returns>
|
[DebuggerHidden]
|
IEnumerator IEnumerable.GetEnumerator()
|
{
|
return new FastJavaByteArrayEnumerator(this);
|
}
|
|
/// <summary>
|
/// Gets the first index of the given value
|
/// </summary>
|
/// <param name="item">Item to search for</param>
|
/// <returns>Index of found item</returns>
|
public int IndexOf(byte item)
|
{
|
for (int i = 0; i < Count; ++i)
|
{
|
byte current;
|
unsafe
|
{
|
current = Raw[i];
|
}
|
if (current == item)
|
return i;
|
}
|
return -1;
|
}
|
|
/// <summary>
|
/// Not supported
|
/// </summary>
|
/// <param name="index"></param>
|
/// <param name="item"></param>
|
public void Insert(int index, byte item)
|
{
|
throw new NotSupportedException("FastJavaByteArray is fixed length");
|
}
|
|
/// <summary>
|
/// Not supported
|
/// </summary>
|
/// <param name="item"></param>
|
/// <returns></returns>
|
public bool Remove(byte item)
|
{
|
throw new NotSupportedException("FastJavaByteArray is fixed length");
|
}
|
|
/// <summary>
|
/// Not supported
|
/// </summary>
|
/// <param name="index"></param>
|
public void RemoveAt(int index)
|
{
|
throw new NotSupportedException("FastJavaByteArray is fixed length");
|
}
|
|
#endregion
|
|
#region Public Properties
|
|
/// <summary>
|
/// Gets the raw pointer to the underlying data.
|
/// </summary>
|
public unsafe byte* Raw { get; private set; }
|
|
/// <summary>
|
/// Gets the handle of the Java reference to the array.
|
/// </summary>
|
/// <value>The handle.</value>
|
public IntPtr Handle
|
{
|
get { return _javaRef.Handle; }
|
}
|
|
#endregion
|
}
|
}
|