rust_macios/foundation/
ns_data.rs

1use block::IntoConcreteBlock;
2use libc::c_void;
3use objc::{msg_send, sel, sel_impl};
4
5use crate::{object, 
6    objective_c_runtime::{
7        macros::{interface_impl},
8        traits::{FromId, PNSObject},
9    },
10    utils::to_bool,
11};
12
13use super::{NSError, NSRange, NSString, UInt, NSURL};
14
15/// Options for methods used to read data objects.
16#[derive(Debug, Clone, Copy)]
17#[repr(u64)]
18pub enum NSDataReadingOptions {
19    MappedIfSafe = 1 << 0,
20    /// A hint indicating the file should not be stored in the file-system caches.
21    Uncached = 1 << 1,
22    /// Hint to map the file in if possible.
23    MappedAlways = 1 << 3,
24}
25
26/// Options for methods used to write data objects.
27#[derive(Debug, Clone, Copy)]
28#[repr(u64)]
29pub enum NSDataWritingOptions {
30    /// An option to write data to an auxiliary file first and then replace the original file with the auxiliary file when the write completes.
31    Atomic = 1,
32    /// An option that attempts to write data to a file and fails with an error if the destination file already exists.
33    WithoutOverwriting = 2,
34    /// An option to not encrypt the file when writing it out.
35    FileProtectionNone = 0x10000000,
36    /// An option to make the file accessible only while the device is unlocked.
37    FileProtectionComplete = 0x20000000,
38    /// An option to allow the file to be accessible after a user first unlocks the device.
39    FileProtectionMask = 0xf0000000,
40    /// An option to allow the file to be accessible while the device is unlocked or the file is already open.
41    FileProtectionCompleteUnlessOpen = 0x30000000,
42    /// An option the system uses when determining the file protection options that the system assigns to the data.
43    FileProtectionCompleteUntilFirstUserAuthentication = 0x40000000,
44}
45
46/// Options for method used to search data objects.
47#[derive(Debug, Clone, Copy)]
48#[repr(u64)]
49pub enum NSDataSearchOptions {
50    /// Search from the end of the data object.
51    SearchBackwards = 1,
52    /// Search is limited to start (or end, if searching backwards) of the data object.
53    SearchAnchored = 2,
54}
55
56/// Options to modify the decoding algorithm used to decode Base64 encoded data.
57#[derive(Debug, Clone, Copy)]
58#[repr(u64)]
59pub enum NSDataBase64DecodingOptions {
60    None = 0,
61    /// Modify the decoding algorithm so that it ignores unknown non-Base-64 bytes, including line ending characters.
62    IgnoreUnknownCharacters = 1,
63}
64
65/// Options for methods used to Base64 encode data.
66#[derive(Debug, Clone, Copy)]
67#[repr(u64)]
68pub enum NSDataBase64EncodingOptions {
69    None = 0,
70    /// Set the maximum line length to 64 characters, after which a line ending is inserted.
71    SixtyFourCharacterLineLength = 1,
72    /// Set the maximum line length to 76 characters, after which a line ending is inserted.
73    SeventySixCharacterLineLength = 1 << 1,
74    /// When a maximum line length is set, specify that the line ending to insert should include a carriage return.
75    EndLineWithCarriageReturn = 1 << 4,
76    /// When a maximum line length is set, specify that the line ending to insert should include a line feed.
77    EndLineWithLineFeed = 1 << 5,
78}
79
80/// An algorithm that indicates how to compress or decompress data.
81#[derive(Debug, Clone, Copy)]
82#[repr(i64)]
83pub enum NSDataCompressionAlgorithm {
84    /// The algorithm offers faster speed and generally achieves better compression than [`NSDataCompressionAlgorithm::Zlib`]. However, it is slower than [`NSDataCompressionAlgorithm::LZ4`] and doesn’t compress as well as [`NSDataCompressionAlgorithm::LZMA`].
85    LZFSE = 0,
86    /// The LZ4 compression algorithm, recommended for fast compression.
87    LZ4,
88    /// The LZMA compression algorithm, recommended for high-compression ratio.
89    LZMA,
90    /// The zlib compression algorithm, recommended for cross-platform compression.
91    Zlib,
92}
93
94object! {
95    /// A static byte buffer in memory.
96    unsafe pub struct NSData;
97}
98
99#[interface_impl(NSObject)]
100impl NSData {
101    /* Creating Data
102     */
103
104    /// Creates an empty data object.
105    #[method]
106    pub fn data() -> Self
107    where
108        Self: Sized + FromId,
109    {
110        unsafe { Self::from_id(msg_send![Self::m_class(), data]) }
111    }
112
113    /// Creates a data object containing a given number of bytes copied from a given buffer.
114    #[method]
115    pub fn data_with_bytes_length(bytes: *const c_void, length: UInt) -> Self
116    where
117        Self: Sized + FromId,
118    {
119        unsafe { Self::from_id(msg_send![Self::m_class(), dataWithBytes: bytes length: length]) }
120    }
121
122    /// Creates a data object that holds a given number of bytes from a given buffer.
123    #[method]
124    pub fn data_with_bytes_no_copy_length(bytes: *mut c_void, length: UInt) -> Self
125    where
126        Self: Sized + FromId,
127    {
128        unsafe {
129            Self::from_id(msg_send![Self::m_class(), dataWithBytesNoCopy: bytes
130                                                                  length: length])
131        }
132    }
133
134    /// Creates a data object that holds a given number of bytes from a given buffer.
135    #[method]
136    pub fn data_with_bytes_no_copy_length_free_when_done(
137        bytes: *mut c_void,
138        length: UInt,
139        b: bool,
140    ) -> Self
141    where
142        Self: Sized + FromId,
143    {
144        unsafe {
145            Self::from_id(
146                msg_send![Self::m_class(), dataWithBytesNoCopy:bytes length:length freeWhenDone:b],
147            )
148        }
149    }
150
151    /// Creates a data object containing the contents of another data object.
152    #[method]
153    pub fn data_with_data(data: NSData) -> Self
154    where
155        Self: Sized + FromId,
156    {
157        unsafe { Self::from_id(msg_send![Self::m_class(), dataWithData: data]) }
158    }
159
160    /// Initializes a data object filled with a given number of bytes copied from a given buffer.
161    #[method]
162    pub fn init_with_bytes_length(&mut self, bytes: *const c_void, length: UInt) -> Self
163    where
164        Self: Sized + FromId,
165    {
166        unsafe { Self::from_id(msg_send![self.m_self(), initWithBytes: bytes length: length]) }
167    }
168
169    /// Initializes a data object filled with a given number of bytes of data from a given buffer.
170    #[method]
171    pub fn init_with_bytes_no_copy_length(&mut self, bytes: *mut c_void, length: UInt) -> Self
172    where
173        Self: Sized + FromId,
174    {
175        unsafe {
176            Self::from_id(msg_send![self.m_self(), initWithBytesNoCopy: bytes length: length])
177        }
178    }
179
180    /// Initializes a data object filled with a given number of bytes of data from a given buffer, with a custom deallocator block.
181    #[method]
182    pub fn init_with_bytes_no_copy_length_deallocator<F>(
183        &mut self,
184        bytes: *mut c_void,
185        length: UInt,
186        deallocator: F,
187    ) -> Self
188    where
189        Self: Sized + FromId,
190        F: IntoConcreteBlock<(*mut c_void, UInt), Ret = ()> + 'static,
191    {
192        let deallocator = deallocator.into_concrete_block();
193        let deallocator = deallocator.copy();
194
195        unsafe {
196            Self::from_id(
197                msg_send![self.m_self(), initWithBytesNoCopy: bytes length: length deallocator: deallocator],
198            )
199        }
200    }
201
202    /// Initializes a newly allocated data object by adding the given number of bytes from the given buffer.
203    #[method]
204    pub fn init_with_bytes_no_copy_length_free_when_done(
205        &mut self,
206        bytes: *mut c_void,
207        length: UInt,
208        b: bool,
209    ) -> Self
210    where
211        Self: Sized + FromId,
212    {
213        unsafe {
214            Self::from_id(
215                msg_send![self.m_self(), initWithBytesNoCopy: bytes length: length freeWhenDone:b],
216            )
217        }
218    }
219
220    /// Initializes a data object with the contents of another data object.
221    #[method]
222    pub fn init_with_data(&mut self, data: &NSData) -> Self
223    where
224        Self: Sized + FromId,
225    {
226        unsafe { Self::from_id(msg_send![self.m_self(), initWithData: data.m_self()]) }
227    }
228
229    /*Reading Data from a File
230     */
231
232    /// Creates a data object by reading every byte from the file at a given path.
233    #[method]
234    pub fn data_with_contents_of_file(path: &NSString) -> Self
235    where
236        Self: Sized + FromId,
237    {
238        unsafe { Self::from_id(msg_send![Self::m_class(), dataWithContentsOfFile: path.m_self()]) }
239    }
240
241    /// Creates a data object by reading every byte from the file at a given path.
242    #[method]
243    pub fn data_with_contents_of_file_options(
244        path: &NSString,
245        read_options_mask: NSDataReadingOptions,
246    ) -> Result<Self, NSError>
247    where
248        Self: Sized + FromId,
249    {
250        let mut error = NSError::m_alloc();
251
252        unsafe {
253            let ptr = Self::from_id(
254                msg_send![Self::m_class(), dataWithContentsOfFile: path.m_self() options: read_options_mask error: &mut error],
255            );
256
257            if error.m_self().is_null() {
258                Ok(ptr)
259            } else {
260                Err(error)
261            }
262        }
263    }
264
265    /// Creates a data object containing the data from the location specified by a given URL.
266    #[method]
267    pub fn data_with_contents_of_url(url: &NSURL) -> Self
268    where
269        Self: Sized + FromId,
270    {
271        unsafe { Self::from_id(msg_send![Self::m_class(), dataWithContentsOfURL: url.m_self()]) }
272    }
273
274    /// Creates a data object containing the data from the location specified by a given URL.
275    #[method]
276    pub fn data_with_contents_of_url_options(
277        url: &NSURL,
278        read_options_mask: NSDataReadingOptions,
279    ) -> Result<Self, NSError>
280    where
281        Self: Sized + FromId,
282    {
283        let mut error = NSError::m_alloc();
284        unsafe {
285            let ptr = Self::from_id(
286                msg_send![Self::m_class(), dataWithContentsOfURL: url.m_self() options: read_options_mask error: &mut error],
287            );
288
289            if error.m_self().is_null() {
290                Ok(ptr)
291            } else {
292                Err(error)
293            }
294        }
295    }
296
297    /// Initializes a data object with the content of the file at a given path.
298    #[method]
299    pub fn init_with_contents_of_file(&mut self, path: &NSString) -> Self
300    where
301        Self: Sized + FromId,
302    {
303        unsafe { Self::from_id(msg_send![self.m_self(), initWithContentsOfFile: path.m_self()]) }
304    }
305
306    /// Initializes a data object with the content of the file at a given path.
307    #[method]
308    pub fn init_with_contents_of_file_options(
309        &mut self,
310        path: &NSString,
311        read_options_mask: NSDataReadingOptions,
312    ) -> Result<Self, NSError>
313    where
314        Self: Sized + FromId,
315    {
316        let mut error = NSError::m_alloc();
317
318        unsafe {
319            let ptr = Self::from_id(
320                msg_send![self.m_self(), initWithContentsOfFile: path.m_self() options: read_options_mask error: &mut error],
321            );
322
323            if error.m_self().is_null() {
324                Ok(ptr)
325            } else {
326                Err(error)
327            }
328        }
329    }
330
331    /// Initializes a data object with the data from the location specified by a given URL.
332    #[method]
333    pub fn init_with_contents_of_url(&mut self, url: &NSURL) -> Self
334    where
335        Self: Sized + FromId,
336    {
337        unsafe { Self::from_id(msg_send![self.m_self(), initWithContentsOfURL: url.m_self()]) }
338    }
339
340    /// Initializes a data object with the data from the location specified by a given URL.
341    #[method]
342    pub fn init_with_contents_of_url_options(
343        &mut self,
344        url: &NSURL,
345        read_options_mask: NSDataReadingOptions,
346    ) -> Result<Self, NSError>
347    where
348        Self: Sized + FromId,
349    {
350        let mut error = NSError::m_alloc();
351
352        unsafe {
353            let ptr = Self::from_id(
354                msg_send![self.m_self(), initWithContentsOfURL: url.m_self() options: read_options_mask error: &mut error],
355            );
356
357            if error.m_self().is_null() {
358                Ok(ptr)
359            } else {
360                Err(error)
361            }
362        }
363    }
364
365    /* Writing Data to a File
366     */
367
368    /// Writes the data object's bytes to the file specified by a given path.
369    #[method]
370    pub fn write_to_file_atomically(&self, path: &NSString, use_auxiliary_file: bool) -> bool {
371        unsafe {
372            to_bool(
373                msg_send![self.m_self(), writeToFile: path.m_self() atomically: use_auxiliary_file],
374            )
375        }
376    }
377
378    /// Writes the data object’s bytes to the file specified by a given path.
379    #[method]
380    pub fn write_to_file_options(
381        &self,
382        path: &NSString,
383        write_options: NSDataWritingOptions,
384    ) -> Result<bool, NSError> {
385        unsafe {
386            let mut error = NSError::m_alloc();
387
388            let ptr = to_bool(
389                msg_send![self.m_self(), writeToFile: path.m_self() options: write_options error: &mut error],
390            );
391
392            if error.m_self().is_null() {
393                Ok(ptr)
394            } else {
395                Err(error)
396            }
397        }
398    }
399
400    /// Writes the data object's bytes to the location specified by a given URL.
401    #[method]
402    pub fn write_to_url_atomically(&self, url: &NSURL, atomically: bool) -> bool {
403        unsafe {
404            to_bool(msg_send![self.m_self(), writeToURL: url.m_self() atomically: atomically])
405        }
406    }
407
408    /// Writes the data object's bytes to the location specified by a given URL.
409    #[method]
410    pub fn write_to_url_options(
411        &self,
412        url: &NSURL,
413        write_options: NSDataWritingOptions,
414    ) -> Result<bool, NSError> {
415        unsafe {
416            let mut error = NSError::m_alloc();
417
418            let ptr = to_bool(
419                msg_send![self.m_self(), writeToURL: url.m_self() options: write_options error: &mut error],
420            );
421
422            if error.m_self().is_null() {
423                Ok(ptr)
424            } else {
425                Err(error)
426            }
427        }
428    }
429
430    /* Encoding and Decoding Base64 Representations
431     */
432
433    /// Initializes a data object with the given Base64 encoded data.
434    #[method]
435    pub fn init_with_base64_encoded_data_options(
436        &mut self,
437        base64_data: &NSData,
438        options: NSDataBase64DecodingOptions,
439    ) -> Self
440    where
441        Self: Sized + FromId,
442    {
443        unsafe {
444            Self::from_id(
445                msg_send![self.m_self(), initWithBase64EncodedData: base64_data.m_self() options: options],
446            )
447        }
448    }
449
450    /// Initializes a data object with the given Base64 encoded string.
451    #[method]
452    pub fn init_with_base64_encoded_string_options(
453        &mut self,
454        base64_string: &NSString,
455        options: NSDataBase64DecodingOptions,
456    ) -> Self
457    where
458        Self: Sized + FromId,
459    {
460        unsafe {
461            Self::from_id(
462                msg_send![self.m_self(), initWithBase64EncodedString: base64_string.m_self() options: options],
463            )
464        }
465    }
466
467    /// Creates a Base64, UTF-8 encoded data object from the string using the given options.
468    #[method]
469    pub fn base64_encoded_data_with_options(&self, options: NSDataBase64EncodingOptions) -> NSData {
470        unsafe {
471            NSData::from_id(msg_send![
472                self.m_self(),
473                base64EncodedDataWithOptions: options
474            ])
475        }
476    }
477
478    /// Creates a Base64 encoded string from the string using the given options.
479    #[method]
480    pub fn base64_encoded_string_with_options(
481        &self,
482        options: NSDataBase64EncodingOptions,
483    ) -> NSString {
484        unsafe {
485            NSString::from_id(msg_send![
486                self.m_self(),
487                base64EncodedStringWithOptions: options
488            ])
489        }
490    }
491
492    /* Accessing Underlying Bytes
493
494    */
495
496    /// A pointer to the data object's contents.
497    #[property]
498    pub fn bytes(&self) -> *const c_void {
499        unsafe { msg_send![self.m_self(), bytes] }
500    }
501
502    /// Enumerates each range of bytes in the data object using a block.
503    #[method]
504    pub fn enumerate_byte_ranges_using_block<F>(&self, block: F)
505    where
506        F: IntoConcreteBlock<(*const c_void, NSRange, *mut bool), Ret = ()> + 'static,
507    {
508        unsafe {
509            let block = block.into_concrete_block();
510            let block = block.copy();
511
512            msg_send![self.m_self(), enumerateByteRangesUsingBlock: block]
513        }
514    }
515
516    /// Copies a number of bytes from the start of the data object into a given buffer.
517    #[method]
518    pub fn get_bytes_length(&self, buffer: *mut c_void, length: UInt) {
519        unsafe { msg_send![self.m_self(), getBytes: buffer length: length] }
520    }
521
522    /// Copies a range of bytes from the data object into a given buffer.
523    #[method]
524    pub fn get_bytes_range(&self, buffer: *mut c_void, range: NSRange) {
525        unsafe { msg_send![self.m_self(), getBytes: buffer range: range] }
526    }
527
528    /* Finding Data
529     */
530
531    /// Returns a new data object containing the data object's bytes that fall within the limits specified by a given range.
532    #[method]
533    pub fn subdata_with_range(&self, range: NSRange) -> NSData {
534        unsafe { NSData::from_id(msg_send![self.m_self(), subdataWithRange: range]) }
535    }
536
537    /// Finds and returns the range of the first occurrence of the given data, within the given range, subject to given options.
538    #[method]
539    pub fn range_of_data_options_range(
540        &self,
541        data_to_find: &NSData,
542        mask: NSDataSearchOptions,
543        search_range: NSRange,
544    ) -> NSRange {
545        unsafe {
546            msg_send![self.m_self(), rangeOfData: data_to_find.m_self() options: mask range:search_range]
547        }
548    }
549
550    /// Returns a Boolean value indicating whether this data object is the same as another.
551    #[method]
552    pub fn is_equal_to_data(&self, other: &NSData) -> bool {
553        unsafe { to_bool(msg_send![self.m_self(), isEqualToData: other.m_self()]) }
554    }
555
556    /// The number of bytes contained by the data object.
557    #[method]
558    pub fn length(&self) -> UInt {
559        unsafe { msg_send![self.m_self(), length] }
560    }
561
562    /* Compressing and Decompressing Data
563     */
564
565    /// Returns a new data object by compressing the data object’s bytes.
566    #[method]
567    pub fn compressed_data_using_algorithm(
568        &self,
569        algorithm: NSDataCompressionAlgorithm,
570    ) -> Result<Self, NSError>
571    where
572        Self: Sized + FromId,
573    {
574        let mut error = NSError::m_alloc();
575
576        unsafe {
577            let ptr = Self::from_id(
578                msg_send![self.m_self(), compressedDataUsingAlgorithm: algorithm error: &mut error],
579            );
580
581            if error.m_self().is_null() {
582                Ok(ptr)
583            } else {
584                Err(error)
585            }
586        }
587    }
588
589    /// Returns a new data object by decompressing data object’s bytes.
590    #[method]
591    pub fn decompressed_data_using_algorithm(
592        &self,
593        algorithm: NSDataCompressionAlgorithm,
594    ) -> Result<Self, NSError>
595    where
596        Self: Sized + FromId,
597    {
598        let mut error = NSError::m_alloc();
599
600        unsafe {
601            let ptr = Self::from_id(
602                msg_send![self.m_self(), decompressedDataUsingAlgorithm: algorithm error: &mut error],
603            );
604
605            if error.m_self().is_null() {
606                Ok(ptr)
607            } else {
608                Err(error)
609            }
610        }
611    }
612}