Loading...
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
/*
 * Copyright (c) 2000-2019 Apple Inc. All rights reserved.
 *
 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
 *
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apple Public Source License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. The rights granted to you under the License
 * may not be used to create, or enable the creation or redistribution of,
 * unlawful or unlicensed copies of an Apple operating system, or to
 * circumvent, violate, or enable the circumvention or violation of, any
 * terms of an Apple operating system software license agreement.
 *
 * Please obtain a copy of the License at
 * http://www.opensource.apple.com/apsl/ and read it before using this file.
 *
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 *
 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
 */
/* IOData.h created by rsulack on Wed 17-Sep-1997 */
/* IOData.h converted to C++ by gvdl on Fri 1998-10-30 */

#ifndef _OS_OSDATA_H
#define _OS_OSDATA_H

#include <libkern/c++/OSObject.h>
#include <libkern/c++/OSPtr.h>
#include <os/base.h>

#if KERNEL_PRIVATE
#include <kern/kalloc.h>
#endif

class OSData;
class OSString;

typedef OSData* OSDataPtr;
typedef OSData const* OSDataConstPtr;

/*!
 * @header
 *
 * @abstract
 * This header declares the OSData container class.
 */


/*!
 * @class OSData
 *
 * @abstract
 * OSData wraps an array of bytes in a C++ object
 * for use in Libkern collections.
 *
 * @discussion
 * OSData represents an array of bytes as a Libkern C++ object.
 * OSData objects are mutable:
 * You can add bytes to them and
 * overwrite portions of the byte array.
 *
 * <b>Use Restrictions</b>
 *
 * With very few exceptions in the I/O Kit, all Libkern-based C++
 * classes, functions, and macros are <b>unsafe</b>
 * to use in a primary interrupt context.
 * Consult the I/O Kit documentation related to primary interrupts
 * for more information.
 *
 * OSData provides no concurrency protection;
 * it's up to the usage context to provide any protection necessary.
 * Some portions of the I/O Kit, such as
 * @link //apple_ref/doc/class/IORegistryEntry IORegistryEntry@/link,
 * handle synchronization via defined member functions for setting
 * properties.
 */
class OSData : public OSObject
{
	friend class OSSerialize;

	OSDeclareDefaultStructors(OSData);

#if APPLE_KEXT_ALIGN_CONTAINERS

protected:
	unsigned int   length;
	unsigned int   capacity;
	unsigned int   capacityIncrement;
	void         * OS_PTRAUTH_SIGNED_PTR("OSData.data") data;

#else /* APPLE_KEXT_ALIGN_CONTAINERS */

protected:
	void         * OS_PTRAUTH_SIGNED_PTR("OSData.data") data;
	unsigned int   length;
	unsigned int   capacity;
	unsigned int   capacityIncrement;

#endif /* APPLE_KEXT_ALIGN_CONTAINERS */

#ifdef XNU_KERNEL_PRIVATE
/* Available within xnu source only */
public:
	typedef void (*DeallocFunction)(void * ptr, unsigned int length);
protected:
	struct ExpansionData {
		DeallocFunction deallocFunction;
		bool            disableSerialization;
	};
#else /* XNU_KERNEL_PRIVATE */
private:
	typedef void (*DeallocFunction)(void * ptr, unsigned int length);
protected:
	struct ExpansionData;
#endif /* XNU_KERNEL_PRIVATE */

/* Reserved for future use. (Internal use only)  */
	ExpansionData * reserved;

public:

/*!
 * @function withCapacity
 *
 * @abstract
 * Creates and initializes an empty instance of OSData.
 *
 * @param capacity  The initial capacity of the OSData object in bytes.
 *
 * @result
 * An instance of OSData with a reference count of 1;
 * <code>NULL</code> on failure.
 *
 * @discussion
 * <code>capacity</code> may be zero.
 * The OSData object will allocate a buffer internally
 * when necessary, and will grow as needed to accommodate more bytes
 * (<i>unlike</i> @link //apple_ref/doc/uid/20001498 CFMutableData@/link,
 * for which a nonzero initial capacity is a hard limit).
 */
	static OSPtr<OSData> withCapacity(unsigned int capacity __xnu_data_size);


/*!
 * @function withBytes
 *
 * @abstract
 * Creates and initializes an instance of OSData
 * with a copy of the provided data buffer.
 *
 * @param bytes     The buffer of data to copy.
 * @param numBytes  The length of <code>bytes</code>.
 *
 * @result
 * An instance of OSData containing a copy of the provided byte array,
 * with a reference count of 1;
 * <code>NULL</code> on failure.
 *
 * @discussion
 * The new OSData object will grow as needed to accommodate more bytes
 * (<i>unlike</i> @link //apple_ref/doc/uid/20001498 CFMutableData@/link,
 * for which a nonzero initial capacity is a hard limit).
 */
	static OSPtr<OSData> withBytes(
		const void   * bytes,
		unsigned int   numBytes __xnu_data_size);


#if KERNEL_PRIVATE
/*!
 * @function withValue
 *
 * @abstract
 * Creates and initializes an instance of OSData
 * with a copy of the provided value of a concrete type.
 *
 * @param value     The instance of a value to copy.
 *
 * @result
 * An instance of OSData containing a copy of the provided value's data,
 * with a reference count of 1;
 * <code>NULL</code> on failure.
 *
 * @discussion
 * The new OSData object will grow as needed to accommodate more bytes
 * (<i>unlike</i> @link //apple_ref/doc/uid/20001498 CFMutableData@/link,
 * for which a nonzero initial capacity is a hard limit).
 */
	template <typename T>
	static OSPtr<OSData>
	withValue(const T& value)
	{
		validateValueType<T, kValueCopy>();
		return withBytes(&value, sizeof(T));
	}
#endif // KERNEL_PRIVATE


/*!
 * @function withBytesNoCopy
 *
 * @abstract
 * Creates and initializes an instance of OSData
 * that shares the provided data buffer.
 *
 * @param bytes     The buffer of data to represent.
 * @param numBytes  The length of <code>bytes</code>.
 *
 * @result
 * A instance of OSData that shares the provided byte array,
 * with a reference count of 1;
 * <code>NULL</code> on failure.
 *
 * @discussion
 * An OSData object created with this function
 * does not claim ownership
 * of the data buffer, but shares it with the caller.
 * When the caller determines that the OSData object has actually been freed,
 * it can safely dispose of the data buffer.
 * Conversely, if it frees the shared data buffer,
 * it must not attempt to use the OSData object and should release it.
 *
 * An OSData object created with shared external data cannot append bytes,
 * but you can get the byte pointer and
 * modify bytes within the shared buffer.
 */
	static OSPtr<OSData> withBytesNoCopy(
		void         * bytes,
		unsigned int   numBytes);


#if KERNEL_PRIVATE
/*!
 * @function withValueNoCopy
 *
 * @abstract
 * Creates and initializes an instance of OSData
 * that shares the provided value of a concrete type.
 *
 * @param value     The instance of a value to represent.
 *
 * @result
 * A instance of OSData that shares the provided value's data,
 * with a reference count of 1;
 * <code>NULL</code> on failure.
 *
 * @discussion
 * An OSData object created with this function does not claim ownership
 * of the data of the value, but shares it with the caller.
 * When the caller determines that the OSData object has actually been freed,
 * it can safely dispose of the data buffer.
 * Conversely, if the lifetime of the data's shared value instance ends,
 * it must not attempt to use the OSData object and should release it.
 *
 * An OSData object created with shared external data cannot append bytes,
 * but you can get the byte pointer and
 * modify bytes within the shared buffer.
 */
	template <typename T>
	static OSPtr<OSData>
	withValueNoCopy(T& value)
	{
		validateValueType<T, kValueNoCopy>();
		return withBytesNoCopy(&value, sizeof(T));
	}

#if __cplusplus >= 201103L
	/* rvalue overload is deleted for the NoCopy variation to
	 * disallow holding a dangling pointer to a temporary value */
	template <typename T>
	static OSPtr<OSData> withValueNoCopy(T&& value) = delete;
#endif
#endif // KERNEL_PRIVATE


/*!
 * @function withData
 *
 * @abstract
 * Creates and initializes an instance of OSData
 * with contents copied from another OSData object.
 *
 * @param inData An OSData object that provides the initial data.
 *
 * @result
 * An instance of OSData containing a copy of the data in <code>inData</code>,
 * with a reference count of 1;
 * <code>NULL</code> on failure.
 *
 * @discussion
 * The new OSData object will grow as needed to accommodate more bytes
 * (<i>unlike</i> @link //apple_ref/doc/uid/20001498 CFMutableData@/link,
 * for which a nonzero initial capacity is a hard limit).
 */
	static OSPtr<OSData> withData(const OSData * inData);


/*!
 * @function withData
 *
 * @abstract
 * Creates and initializes an instance of OSData
 * with contents copied from a range within another OSData object.
 *
 * @param inData    An OSData object that provides the initial data.
 * @param start     The starting index from which bytes will be copied.
 * @param numBytes  The number of bytes to be copied from <code>start</code>.
 *
 * @result
 * An instance of OSData containing a copy
 * of the specified data range from <code>inData</code>,
 * with a reference count of 1;
 * <code>NULL</code> on failure.
 *
 * @discussion
 * The new OSData object will grow as needed to accommodate more bytes
 * (<i>unlike</i> @link //apple_ref/doc/uid/20001498 CFMutableData@/link,
 * for which a nonzero initial capacity is a hard limit).
 */
	static OSPtr<OSData> withData(
		const OSData * inData,
		unsigned int   start,
		unsigned int   numBytes);


/*!
 * @function initWithCapacity
 *
 * @abstract
 * Initializes an instance of OSData.
 *
 * @param capacity The initial capacity of the OSData object in bytes.
 *
 * @result
 * <code>true</code> on success, <code>false</code> on failure.
 *
 * @discussion
 * Not for general use. Use the static instance creation method
 * <code>@link
 * //apple_ref/cpp/clm/OSData/withCapacity/staticOSData*\/(unsignedint)
 * withCapacity@/link</code> instead.
 *
 * <code>capacity</code> may be zero.
 * The OSData object will allocate a buffer internally
 * when necessary, and will grow as needed to accommodate more bytes
 * (<i>unlike</i> @link //apple_ref/doc/uid/20001498 CFMutableData@/link,
 * for which a nonzero initial capacity is a hard limit).
 */
	virtual bool initWithCapacity(unsigned int capacity __xnu_data_size);


/*!
 * @function initWithBytes
 *
 * @abstract
 * Initializes an instance of OSData
 * with a copy of the provided data buffer.
 *
 * @param bytes     The buffer of data to copy.
 * @param numBytes  The length of <code>bytes</code>.
 *
 * @result
 * <code>true</code> on success, <code>false</code> on failure.
 *
 * @discussion
 * Not for general use. Use the static instance creation method
 * <code>@link withBytes withBytes@/link</code> instead.
 *
 * The new OSData object will grow as needed to accommodate more bytes
 * (<i>unlike</i> @link //apple_ref/doc/uid/20001498 CFMutableData@/link,
 * for which a nonzero initial capacity is a hard limit).
 */
	virtual bool initWithBytes(
		const void   * bytes,
		unsigned int   numBytes __xnu_data_size);


#if KERNEL_PRIVATE
/*!
 * @function initWithValue
 *
 * @abstract
 * Initializes an instance of OSData
 * with a copy of the provided value of a concrete type.
 *
 * @param value     The instance of a value to copy.
 *
 * @result
 * <code>true</code> on success, <code>false</code> on failure.
 *
 * @discussion
 * Not for general use. Use the static instance creation method
 * <code>@link withValue withValue@/link</code> instead.
 *
 * The new OSData object will grow as needed to accommodate more bytes
 * (<i>unlike</i> @link //apple_ref/doc/uid/20001498 CFMutableData@/link,
 * for which a nonzero initial capacity is a hard limit).
 */
	template <typename T>
	bool
	initWithValue(const T& value)
	{
		validateValueType<T, kValueCopy>();
		return initWithBytes(&value, sizeof(T));
	}
#endif // KERNEL_PRIVATE


/*!
 * @function initWithBytesNoCopy
 *
 * @abstract
 * Initializes an instance of OSData
 * to share the provided data buffer.
 *
 * @param bytes     The buffer of data to represent.
 * @param numBytes  The length of <code>bytes</code>.
 *
 * @result
 * <code>true</code> on success, <code>false</code> on failure.
 *
 * @discussion
 * Not for general use. Use the static instance creation method
 * <code>@link withBytesNoCopy withBytesNoCopy@/link</code> instead.
 *
 * An OSData object initialized with this function
 * does not claim ownership
 * of the data buffer, but merely shares it with the caller.
 *
 * An OSData object created with shared external data cannot append bytes,
 * but you can get the byte pointer and
 * modify bytes within the shared buffer.
 */
	virtual bool initWithBytesNoCopy(
		void         * bytes,
		unsigned int   numBytes);


#if KERNEL_PRIVATE
/*!
 * @function initWithValueNoCopy
 *
 * @abstract
 * Initializes an instance of OSData
 * to share the provided value of a concrete type.
 *
 * @param value     The instance of a value to represent.
 *
 * @result
 * <code>true</code> on success, <code>false</code> on failure.
 *
 * @discussion
 * Not for general use. Use the static instance creation method
 * <code>@link withValueNoCopy withValueNoCopy@/link</code> instead.
 *
 * An OSData object initialized with this function does not claim ownership
 * of the data of the value, but merely shares it with the caller.
 *
 * An OSData object created with shared external data cannot append bytes,
 * but you can get the byte pointer and
 * modify bytes within the shared buffer.
 */
	template <typename T>
	bool
	initWithValueNoCopy(T& value)
	{
		validateValueType<T, kValueNoCopy>();
		return initWithBytesNoCopy(&value, sizeof(T));
	}

#if __cplusplus >= 201103L
	/* rvalue overload is deleted for the NoCopy variation to
	 * disallow holding a dangling pointer to a temporary value */
	template <typename T>
	bool initWithValueNoCopy(T&& value) = delete;
#endif
#endif // KERNEL_PRIVATE


/*!
 * @function initWithData
 *
 * @abstract
 * Creates and initializes an instance of OSData
 * with contents copied from another OSData object.
 *
 * @param inData An OSData object that provides the initial data.
 *
 * @result
 * <code>true</code> on success, <code>false</code> on failure.
 *
 * @discussion
 * Not for general use. Use the static instance creation method
 * <code>@link
 * //apple_ref/cpp/clm/OSData/withData/staticOSData*\/(constOSData*)
 * withData(OSData *)@/link</code>
 * instead.
 *
 * The new OSData object will grow as needed to accommodate more bytes
 * (<i>unlike</i> @link //apple_ref/doc/uid/20001498 CFMutableData@/link,
 * for which a nonzero initial capacity is a hard limit).
 */
	virtual bool initWithData(const OSData * inData);


/*!
 * @function initWithData
 *
 * @abstract
 * Initializes an instance of OSData
 * with contents copied from a range within another OSData object.
 *
 * @param inData    An OSData object that provides the initial data.
 * @param start     The starting index from which bytes will be copied.
 * @param numBytes  The number of bytes to be copied from <code>start</code>.
 *
 * @result
 * Returns <code>true</code> on success, <code>false</code> on failure.
 *
 * @discussion
 * Not for general use. Use the static instance creation method
 * <code>@link
 * //apple_ref/cpp/clm/OSData/withData/staticOSData*\/(constOSData*,unsignedint,unsignedint)
 * withData(OSData *, unsigned int, unsigned int)@/link</code>
 * instead.
 *
 * The new OSData object will grow as needed to accommodate more bytes
 * (<i>unlike</i> @link //apple_ref/doc/uid/20001498 CFMutableData@/link,
 * for which a nonzero initial capacity is a hard limit).
 */
	virtual bool initWithData(
		const OSData * inData,
		unsigned int   start,
		unsigned int   numBytes);


/*!
 * @function free
 *
 * @abstract
 * Deallocates or releases any resources
 * used by the OSData instance.
 *
 * @discussion
 * This function should not be called directly;
 * use
 * <code>@link
 * //apple_ref/cpp/instm/OSObject/release/virtualvoid/()
 * release@/link</code>
 * instead.
 */
	virtual void free() APPLE_KEXT_OVERRIDE;


/*!
 * @function getLength
 *
 * @abstract
 * Returns the number of bytes in or referenced by the OSData object.
 *
 * @result
 * The number of bytes in or referenced by the OSData object.
 */
	virtual unsigned int getLength() const;


/*!
 * @function getCapacity
 *
 * @abstract
 * Returns the total number of bytes the OSData can store without reallocating.
 *
 * @result
 * The total number bytes the OSData can store without reallocating.
 *
 * @discussion
 * OSData objects grow when full to accommodate additional bytes.
 * See
 * <code>@link
 * //apple_ref/cpp/instm/OSData/getCapacityIncrement/virtualunsignedint/()
 * getCapacityIncrement@/link</code>
 * and
 * <code>@link
 * //apple_ref/cpp/instm/OSData/ensureCapacity/virtualunsignedint/(unsignedint)
 * ensureCapacity@/link</code>.
 *
 * OSData objects created or initialized to use a shared buffer
 * do not make use of this attribute, and return -1 from this function.
 */
	virtual unsigned int getCapacity() const;


/*!
 * @function getCapacityIncrement
 *
 * @abstract
 * Returns the storage increment of the OSData object.
 *
 * @result
 * The storage increment of the OSData object.
 *
 * @discussion
 * An OSData object allocates storage for bytes in multiples
 * of the capacity increment.
 *
 * OSData objects created or initialized to use a shared buffer
 * do not make use of this attribute.
 */
	virtual unsigned int getCapacityIncrement() const;


/*!
 * @function setCapacityIncrement
 *
 * @abstract
 * Sets the storage increment of the array.
 *
 * @result
 * The original storage increment of the array.
 *
 * @discussion
 * An OSArray allocates storage for objects in multiples
 * of the capacity increment.
 *
 * OSData objects created or initialized to use a shared buffer
 * do not make use of this attribute.
 */
	virtual unsigned int setCapacityIncrement(unsigned increment);


// xx-review: does not check for capacity == EXTERNAL

/*!
 * @function ensureCapacity
 *
 * @abstract
 * Ensures the array has enough space
 * to store the requested number of bytes.
 *
 * @param newCapacity The total number of bytes the OSData object
 *                    should be able to store.
 *
 * @result
 * Returns the new capacity of the OSData object,
 * which may be different from the number requested
 * (if smaller, reallocation of storage failed).
 *
 * @discussion
 * This function immediately resizes the OSData's buffer, if necessary,
 * to accommodate at least <code>newCapacity</code> bytes.
 * If <code>newCapacity</code> is not greater than the current capacity,
 * or if an allocation error occurs, the original capacity is returned.
 *
 * There is no way to reduce the capacity of an OSData.
 *
 * An OSData object created "NoCopy" does not allow resizing.
 */
	virtual unsigned int ensureCapacity(unsigned int newCapacity);

#ifdef XNU_KERNEL_PRIVATE
/*!
 * @function clipForCopyout
 *
 * @abstract
 * Clips the backing store of an atomic OSData in order
 * to make it usable with copyoutkdata().
 */
	bool clipForCopyout();
#endif /* XNU_KERNEL_PRIVATE */

/*!
 * @function appendBytes
 *
 * @abstract
 * Appends a buffer of bytes to the OSData object's internal data buffer.
 *
 * @param bytes     A pointer to the data to append.
 *                  If <code>bytes</code> is <code>NULL</code>
 *                  then a zero-filled buffer of length <code>numBytes</code>
 *                  is appended.
 * @param numBytes  The number of bytes from <code>bytes</code> to append.
 *
 * @result
 * <code>true</code> if the new data was successfully added,
 * <code>false</code> on failure.
 *
 * @discussion
 * This function immediately resizes the OSData's buffer, if necessary,
 * to accommodate the new total size.
 *
 * An OSData object created "NoCopy" does not allow bytes
 * to be appended.
 */
	virtual bool appendBytes(
		const void   * bytes,
		unsigned int   numBytes __xnu_data_size);


#if KERNEL_PRIVATE
/*!
 * @function appendValue
 *
 * @abstract
 * Appends a copy of the provided value of a concrete type to the
 * OSData object's internal data buffer.
 *
 * @param value     The instance of a value to copy.
 *
 * @result
 * <code>true</code> if the new data was successfully added,
 * <code>false</code> on failure.
 *
 * @discussion
 * This function immediately resizes the OSData's buffer, if necessary,
 * to accommodate the new total size.
 *
 * An OSData object created "NoCopy" does not allow bytes
 * to be appended.
 */
	template <typename T>
	bool
	appendValue(const T& value)
	{
		validateValueType<T, kValueCopy>();
		return appendBytes(&value, sizeof(T));
	}
#endif // KERNEL_PRIVATE


/*!
 * @function appendBytes
 *
 * @abstract
 * Appends the data contained in another OSData object.
 *
 * @param aDataObj  The OSData object whose contents will be appended.
 *
 * @result
 * <code>true</code> if the new data was successfully added,
 * <code>false</code> on failure.
 *
 * @discussion
 * This function immediately resizes the OSData's buffer, if necessary,
 * to accommodate the new total size.
 *
 * An OSData object created "NoCopy" does not allow bytes
 * to be appended.
 */
	virtual bool appendBytes(const OSData * aDataObj);


/*!
 * @function getBytesNoCopy
 *
 * @abstract
 * Returns a pointer to the OSData object's internal data buffer.
 *
 * @result
 * A pointer to the OSData object's internal data buffer.
 *
 * @discussion
 * You can modify the existing contents of an OSData object
 * via this function.
 * It works with OSData objects that have their own data buffers
 * as well as with OSData objects that have shared buffers.
 *
 * If you append bytes or characters to an OSData object,
 * it may have to reallocate its internal storage,
 * rendering invalid an extrated pointer to that storage.
 */
	__xnu_returns_data_pointer
	virtual const void * getBytesNoCopy() const;


/*!
 * @function getBytesNoCopy
 *
 * @abstract
 * Returns a pointer into the OSData object's internal data buffer
 * with a given offset and length.
 *
 * @param start    The offset from the base of the internal data buffer.
 * @param numBytes The length of the  window.
 *
 * @result
 * A pointer to the bytes in the specified range
 * within the OSData object,
 * or 0 if that range does not lie completely
 * within the object's buffer.
 *
 * @discussion
 * You can modify the existing contents of an OSData object
 * via this function.
 * It works with OSData objects that have their own data buffers
 * as well as with OSData objects that have shared buffers.
 *
 * If you append bytes or characters to an OSData object,
 * it may have to reallocate its internal storage,
 * rendering invalid an extrated pointer to that storage.
 */
	__xnu_returns_data_pointer
	virtual const void * getBytesNoCopy(
		unsigned int start,
		unsigned int numBytes) const;


/*!
 * @function isEqualTo
 *
 * @abstract
 * Tests the equality of two OSData objects.
 *
 * @param aDataObj The OSData object being compared against the receiver.
 *
 * @result
 * <code>true</code> if the two OSData objects are equivalent,
 * <code>false</code> otherwise.
 *
 * @discussion
 * Two OSData objects are considered equal
 * if they have same length and if their
 * byte buffers hold the same contents.
 */
	virtual bool isEqualTo(const OSData * aDataObj) const;


/*!
 * @function isEqualTo
 *
 * @abstract
 * Tests the equality of an OSData object's contents
 * to a C array of bytes.
 *
 * @param bytes    A pointer to the bytes to compare.
 * @param numBytes The number of bytes to compare.
 *
 * @result
 * <code>true</code> if the data buffers are equal
 * over the given length,
 * <code>false</code> otherwise.
 */
	virtual bool isEqualTo(
		const void   * bytes,
		unsigned int   numBytes) const;


/*!
 * @function isEqualTo
 *
 * @abstract
 * Tests the equality of an OSData object to an arbitrary object.
 *
 * @param anObject The object to be compared against the receiver.
 *
 * @result
 * <code>true</code> if the two objects are equivalent,
 * <code>false</code> otherwise.
 *
 * @discussion
 * An OSData is considered equal to another object
 * if that object is derived from OSData
 * and contains the equivalent bytes of the same length.
 */
	virtual bool isEqualTo(const OSMetaClassBase * anObject) const APPLE_KEXT_OVERRIDE;


/*!
 * @function isEqualTo
 *
 * @abstract
 * Tests the equality of an OSData object to an OSString.
 *
 * @param aString  The string object to be compared against the receiver.
 *
 * @result
 * <code>true</code> if the two objects are equivalent,
 * <code>false</code> otherwise.
 *
 * @discussion
 * This function compares the bytes of the OSData object
 * against those of the OSString,
 * accounting for the possibility that an OSData
 * might explicitly include a nul
 * character as part of its total length.
 * Thus, for example, an OSData object containing
 * either the bytes <'u', 's', 'b', '\0'>
 * or  <'u', 's', 'b'>
 * will compare as equal to the OSString containing "usb".
 */
	virtual bool isEqualTo(const OSString * aString) const;


/*!
 * @function serialize
 *
 * @abstract
 * Archives the receiver into the provided
 * @link //apple_ref/doc/class/IORegistryEntry OSSerialize@/link object.
 *
 * @param serializer The OSSerialize object.
 *
 * @result
 * <code>true</code> if serialization succeeds, <code>false</code> if not.
 */
	virtual bool serialize(OSSerialize * serializer) const APPLE_KEXT_OVERRIDE;


/*!
 * @function appendByte
 *
 * @abstract
 * Appends a single byte value
 * to the OSData object's internal data buffer
 * a specified number of times.
 *
 * @param byte     The byte value to append.
 * @param numBytes The number of copies of <code>byte</code> to append.
 *
 * @result
 * <code>true</code> if the new data was successfully added,
 * <code>false</code> if not.
 *
 * @discussion
 * This function immediately resizes the OSData's buffer, if necessary,
 * to accommodate the new total size.
 *
 * An OSData object created "NoCopy" does not allow bytes
 * to be appended.
 */
	virtual bool appendByte(
		unsigned char byte,
		unsigned int  numBytes);


	void setSerializable(bool serializable);

#ifdef XNU_KERNEL_PRIVATE
/* Available within xnu source only */
public:
#else
private:
#endif
	virtual void setDeallocFunction(DeallocFunction func);
	bool isSerializable(void);

private:
	enum ValueAcquisition {
		kValueCopy,
		kValueNoCopy
	};

#if KERNEL_PRIVATE
#if __cplusplus >= 201103L
	template <typename T, ValueAcquisition acquisition>
	static constexpr int
	validateValueType()
	{
		static_assert(sizeof(T) <= size_t(UINT32_MAX), "value type's size is too large");
		static_assert(__is_trivially_copyable(T) && __is_standard_layout(T),
		    "only trivially copyable types can be contained");
		static_assert(!__is_pointer(T) || (acquisition == kValueNoCopy),
		    "pointers cannot be contained");
		static_assert(KALLOC_TYPE_IS_DATA_ONLY(T) || (acquisition == kValueNoCopy),
		    "only plain data types can be contained (consider using OSValueObject)");
		return 0; // C++11 does not support void-returning constexpr functions
	}
#else
	template <typename T, ValueAcquisition>
	static void
	validateValueType()
	{
	}
#endif
#endif // KERNEL_PRIVATE

private:
	OSMetaClassDeclareReservedUsedX86(OSData, 0);
	OSMetaClassDeclareReservedUnused(OSData, 1);
	OSMetaClassDeclareReservedUnused(OSData, 2);
	OSMetaClassDeclareReservedUnused(OSData, 3);
	OSMetaClassDeclareReservedUnused(OSData, 4);
	OSMetaClassDeclareReservedUnused(OSData, 5);
	OSMetaClassDeclareReservedUnused(OSData, 6);
	OSMetaClassDeclareReservedUnused(OSData, 7);
};

#endif /* !_OS_OSDATA_H */