CPF/CPF.Mac/Mac/Foundation/NSData.cs
2023-11-21 23:05:03 +08:00

479 lines
13 KiB
C#

using CPF.Mac.ObjCRuntime;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Runtime.InteropServices;
namespace CPF.Mac.Foundation
{
[Register("NSData", true)]
public class NSData : NSObject, IEnumerable, IEnumerable<byte>
{
private class UnmanagedMemoryStreamWithRef : UnmanagedMemoryStream
{
private NSData source;
public unsafe UnmanagedMemoryStreamWithRef(NSData source)
: base((byte*)(void*)source.Bytes, (long)source.Length)
{
this.source = source;
}
protected override void Dispose(bool disposing)
{
source = null;
base.Dispose(disposing);
}
}
private class UnmanagedMemoryStreamWithMutableRef : UnmanagedMemoryStreamWithRef
{
private NSData source;
private IntPtr base_address;
public UnmanagedMemoryStreamWithMutableRef(NSData source)
: base(source)
{
base_address = source.Bytes;
this.source = source;
}
protected override void Dispose(bool disposing)
{
source = null;
base.Dispose(disposing);
}
private static void InvalidOperation()
{
throw new InvalidOperationException("The underlying NSMutableData changed while we were consuming data");
}
public override int Read([In] [Out] byte[] buffer, int offset, int count)
{
if (base_address != source.Bytes)
{
InvalidOperation();
}
return base.Read(buffer, offset, count);
}
public override int ReadByte()
{
if (base_address != source.Bytes)
{
InvalidOperation();
}
return base.ReadByte();
}
public override void Write(byte[] buffer, int offset, int count)
{
if (base_address != source.Bytes)
{
InvalidOperation();
}
base.Write(buffer, offset, count);
}
public override void WriteByte(byte value)
{
if (base_address != source.Bytes)
{
InvalidOperation();
}
base.WriteByte(value);
}
}
private static readonly IntPtr selBytesHandle = Selector.GetHandle("bytes");
private static readonly IntPtr selLengthHandle = Selector.GetHandle("length");
private static readonly IntPtr selSetLength_Handle = Selector.GetHandle("setLength:");
private static readonly IntPtr selDataWithContentsOfURL_Handle = Selector.GetHandle("dataWithContentsOfURL:");
private static readonly IntPtr selDataWithContentsOfURLOptionsError_Handle = Selector.GetHandle("dataWithContentsOfURL:options:error:");
private static readonly IntPtr selDataWithContentsOfFile_Handle = Selector.GetHandle("dataWithContentsOfFile:");
private static readonly IntPtr selDataWithContentsOfFileOptionsError_Handle = Selector.GetHandle("dataWithContentsOfFile:options:error:");
private static readonly IntPtr selDataWithData_Handle = Selector.GetHandle("dataWithData:");
private static readonly IntPtr selDataWithBytesLength_Handle = Selector.GetHandle("dataWithBytes:length:");
private static readonly IntPtr selWriteToFileOptionsError_Handle = Selector.GetHandle("writeToFile:options:error:");
private static readonly IntPtr selWriteToURLOptionsError_Handle = Selector.GetHandle("writeToURL:options:error:");
private static readonly IntPtr selRangeOfDataOptionsRange_Handle = Selector.GetHandle("rangeOfData:options:range:");
private static readonly IntPtr class_ptr = Class.GetHandle("NSData");
public virtual byte this[int idx]
{
get
{
if (idx < 0 || idx >= int.MaxValue || idx > (int)Length)
{
throw new ArgumentException("idx");
}
return Marshal.ReadByte(Bytes, idx);
}
set
{
throw new NotImplementedException("NSData arrays can not be modified, use an NSMUtableData instead");
}
}
public override IntPtr ClassHandle => class_ptr;
public virtual IntPtr Bytes
{
[Export("bytes")]
get
{
if (IsDirectBinding)
{
return Messaging.IntPtr_objc_msgSend(base.Handle, selBytesHandle);
}
return Messaging.IntPtr_objc_msgSendSuper(base.SuperHandle, selBytesHandle);
}
}
public virtual ulong Length
{
[Export("length")]
get
{
if (IsDirectBinding)
{
return Messaging.UInt64_objc_msgSend(base.Handle, selLengthHandle);
}
return Messaging.UInt64_objc_msgSendSuper(base.SuperHandle, selLengthHandle);
}
set
{
throw new NotImplementedException();
}
}
internal NSData(IntPtr handle, bool owns)
: base(handle)
{
if (!owns)
{
Release();
}
}
IEnumerator IEnumerable.GetEnumerator()
{
IntPtr source = Bytes;
int top = (int)Length;
for (int i = 0; i < top; i++)
{
yield return Marshal.ReadByte(source, i);
}
}
IEnumerator<byte> IEnumerable<byte>.GetEnumerator()
{
IntPtr source = Bytes;
int top = (int)Length;
for (int i = 0; i < top; i++)
{
yield return Marshal.ReadByte(source, i);
}
}
public static NSData FromString(string s)
{
if (s == null)
{
throw new ArgumentNullException("s");
}
return new NSString(s).Encode(NSStringEncoding.UTF8);
}
public unsafe static NSData FromArray(byte[] buffer)
{
if (buffer == null)
{
throw new ArgumentNullException("buffer");
}
if (buffer.Length == 0)
{
return FromBytes(IntPtr.Zero, 0uL);
}
fixed (byte* value = &buffer[0])
{
return FromBytes((IntPtr)(void*)value, (uint)buffer.Length);
}
}
public unsafe static NSData FromStream(Stream stream)
{
if (stream == null)
{
throw new ArgumentNullException("stream");
}
if (!stream.CanRead)
{
return null;
}
NSMutableData nSMutableData = null;
long capacity;
try
{
capacity = stream.Length;
}
catch
{
capacity = 8192L;
}
nSMutableData = NSMutableData.FromCapacity((ulong)capacity);
byte[] array = new byte[32768];
try
{
int num;
while ((num = stream.Read(array, 0, array.Length)) != 0)
{
try
{
fixed (byte* value = &array[0])
{
nSMutableData.AppendBytes((IntPtr)(void*)value, (uint)num);
}
}
finally
{
}
}
return nSMutableData;
}
catch
{
return null;
}
}
public virtual Stream AsStream()
{
if (this is NSMutableData)
{
return new UnmanagedMemoryStreamWithMutableRef(this);
}
return new UnmanagedMemoryStreamWithRef(this);
}
public static NSData FromString(string s, NSStringEncoding encoding)
{
return new NSString(s).Encode(encoding);
}
public static implicit operator NSData(string s)
{
return new NSString(s).Encode(NSStringEncoding.UTF8);
}
public NSString ToString(NSStringEncoding encoding)
{
return NSString.FromData(this, encoding);
}
public override string ToString()
{
return ToString(NSStringEncoding.UTF8);
}
public unsafe bool Save(string file, bool auxiliaryFile, out NSError error)
{
IntPtr ptr = default(IntPtr);
IntPtr addr = (IntPtr)(void*)(&ptr);
bool result = _Save(file, (ulong)(auxiliaryFile ? 1 : 0), addr);
error = (NSError)Runtime.GetNSObject(ptr);
return result;
}
public unsafe bool Save(string file, NSDataWritingOptions options, out NSError error)
{
IntPtr ptr = default(IntPtr);
IntPtr addr = (IntPtr)(void*)(&ptr);
bool result = _Save(file, (ulong)options, addr);
error = (NSError)Runtime.GetNSObject(ptr);
return result;
}
public unsafe bool Save(NSUrl url, bool auxiliaryFile, out NSError error)
{
IntPtr ptr = default(IntPtr);
IntPtr addr = (IntPtr)(void*)(&ptr);
bool result = _Save(url, (ulong)(auxiliaryFile ? 1 : 0), addr);
error = (NSError)Runtime.GetNSObject(ptr);
return result;
}
[EditorBrowsable(EditorBrowsableState.Advanced)]
[Export("init")]
public NSData()
: base(NSObjectFlag.Empty)
{
if (IsDirectBinding)
{
base.Handle = Messaging.IntPtr_objc_msgSend(base.Handle, Selector.Init);
}
else
{
base.Handle = Messaging.IntPtr_objc_msgSendSuper(base.SuperHandle, Selector.Init);
}
}
[EditorBrowsable(EditorBrowsableState.Advanced)]
[Export("initWithCoder:")]
public NSData(NSCoder coder)
: base(NSObjectFlag.Empty)
{
if (IsDirectBinding)
{
base.Handle = Messaging.IntPtr_objc_msgSend_IntPtr(base.Handle, Selector.InitWithCoder, coder.Handle);
}
else
{
base.Handle = Messaging.IntPtr_objc_msgSendSuper_IntPtr(base.SuperHandle, Selector.InitWithCoder, coder.Handle);
}
}
[EditorBrowsable(EditorBrowsableState.Advanced)]
public NSData(NSObjectFlag t)
: base(t)
{
}
[EditorBrowsable(EditorBrowsableState.Advanced)]
public NSData(IntPtr handle)
: base(handle)
{
}
[Export("dataWithContentsOfURL:")]
public static NSData FromUrl(NSUrl url)
{
if (url == null)
{
throw new ArgumentNullException("url");
}
return (NSData)Runtime.GetNSObject(Messaging.IntPtr_objc_msgSend_IntPtr(class_ptr, selDataWithContentsOfURL_Handle, url.Handle));
}
[Export("dataWithContentsOfURL:options:error:")]
public static NSData FromUrl(NSUrl url, NSDataReadingOptions mask, out NSError error)
{
if (url == null)
{
throw new ArgumentNullException("url");
}
IntPtr intPtr = Marshal.AllocHGlobal(4);
Marshal.WriteInt32(intPtr, 0);
NSData result = (NSData)Runtime.GetNSObject(Messaging.IntPtr_objc_msgSend_IntPtr_UInt64_IntPtr(class_ptr, selDataWithContentsOfURLOptionsError_Handle, url.Handle, (ulong)mask, intPtr));
IntPtr intPtr2 = Marshal.ReadIntPtr(intPtr);
error = ((intPtr2 != IntPtr.Zero) ? ((NSError)Runtime.GetNSObject(intPtr2)) : null);
Marshal.FreeHGlobal(intPtr);
return result;
}
[Export("dataWithContentsOfFile:")]
public static NSData FromFile(string path)
{
if (path == null)
{
throw new ArgumentNullException("path");
}
IntPtr intPtr = NSString.CreateNative(path);
NSData result = (NSData)Runtime.GetNSObject(Messaging.IntPtr_objc_msgSend_IntPtr(class_ptr, selDataWithContentsOfFile_Handle, intPtr));
NSString.ReleaseNative(intPtr);
return result;
}
[Export("dataWithContentsOfFile:options:error:")]
public static NSData FromFile(string path, NSDataReadingOptions mask, out NSError error)
{
if (path == null)
{
throw new ArgumentNullException("path");
}
IntPtr intPtr = Marshal.AllocHGlobal(4);
Marshal.WriteInt32(intPtr, 0);
IntPtr intPtr2 = NSString.CreateNative(path);
NSData result = (NSData)Runtime.GetNSObject(Messaging.IntPtr_objc_msgSend_IntPtr_UInt64_IntPtr(class_ptr, selDataWithContentsOfFileOptionsError_Handle, intPtr2, (ulong)mask, intPtr));
NSString.ReleaseNative(intPtr2);
IntPtr intPtr3 = Marshal.ReadIntPtr(intPtr);
error = ((intPtr3 != IntPtr.Zero) ? ((NSError)Runtime.GetNSObject(intPtr3)) : null);
Marshal.FreeHGlobal(intPtr);
return result;
}
[Export("dataWithData:")]
public static NSData FromData(NSData source)
{
if (source == null)
{
throw new ArgumentNullException("source");
}
return (NSData)Runtime.GetNSObject(Messaging.IntPtr_objc_msgSend_IntPtr(class_ptr, selDataWithData_Handle, source.Handle));
}
[Export("dataWithBytes:length:")]
public static NSData FromBytes(IntPtr bytes, ulong size)
{
return (NSData)Runtime.GetNSObject(Messaging.IntPtr_objc_msgSend_IntPtr_UInt64(class_ptr, selDataWithBytesLength_Handle, bytes, size));
}
[Export("writeToFile:options:error:")]
public virtual bool _Save(string file, ulong options, IntPtr addr)
{
if (file == null)
{
throw new ArgumentNullException("file");
}
IntPtr intPtr = NSString.CreateNative(file);
bool result = (!IsDirectBinding) ? Messaging.bool_objc_msgSendSuper_IntPtr_UInt64_IntPtr(base.SuperHandle, selWriteToFileOptionsError_Handle, intPtr, options, addr) : Messaging.bool_objc_msgSend_IntPtr_UInt64_IntPtr(base.Handle, selWriteToFileOptionsError_Handle, intPtr, options, addr);
NSString.ReleaseNative(intPtr);
return result;
}
[Export("writeToURL:options:error:")]
public virtual bool _Save(NSUrl url, ulong options, IntPtr addr)
{
if (url == null)
{
throw new ArgumentNullException("url");
}
if (IsDirectBinding)
{
return Messaging.bool_objc_msgSend_IntPtr_UInt64_IntPtr(base.Handle, selWriteToURLOptionsError_Handle, url.Handle, options, addr);
}
return Messaging.bool_objc_msgSendSuper_IntPtr_UInt64_IntPtr(base.SuperHandle, selWriteToURLOptionsError_Handle, url.Handle, options, addr);
}
[Export("rangeOfData:options:range:")]
public virtual NSRange Find(NSData dataToFind, NSDataSearchOptions searchOptions, NSRange searchRange)
{
if (dataToFind == null)
{
throw new ArgumentNullException("dataToFind");
}
if (IsDirectBinding)
{
return Messaging.NSRange_objc_msgSend_IntPtr_UInt64_NSRange(base.Handle, selRangeOfDataOptionsRange_Handle, dataToFind.Handle, (ulong)searchOptions, searchRange);
}
return Messaging.NSRange_objc_msgSendSuper_IntPtr_UInt64_NSRange(base.SuperHandle, selRangeOfDataOptionsRange_Handle, dataToFind.Handle, (ulong)searchOptions, searchRange);
}
}
}