if (plist == null || out == null) {
logger.warn("Encountered empty plist or null outputstream, returning");
return;
}
NSMutableData theData = new NSMutableData();
// write header
theData.appendBytes("bplist00".getBytes());
// add six padded bytes
// do uniquing
// flatten plist into object table
List<EncodedObject> objectList = new ArrayList<EncodedObject>(512);
Map<Object, Long> uniquingTable = new HashMap<Object, Long>(2048);
long theTopObject = encodeObject(plist, objectList, uniquingTable);
// determine ref size
long numberOfObjects = objectList.size();
int refsize = EncodedObject.refSizeForValue(numberOfObjects);
List<Long> objectOffsets = new ArrayList<Long>(objectList.size());
// write the byte
for (EncodedObject object : objectList) {
objectOffsets.add(Long.valueOf(theData.length()));
object.appendToData(theData, refsize);
}
int offsetTableStart = theData.length();
// CF expects intsize to be calculated based on the offset table start position
// and not on the offset of the last object.
int intsize = EncodedObject.refSizeForValue(offsetTableStart);
for (Long offset : objectOffsets) {
theData.appendBytes(EncodedObject.encodeRef(offset, intsize));
}
// add trailer calculations to data
// typedef struct {
// uint8_t _unused[5];
// uint8_t _sortVersion;
// uint8_t _offsetIntSize;
// uint8_t _objectRefSize;
// uint64_t _numObjects;
// uint64_t _topObject;
// uint64_t _offsetTableOffset;
// } CFBinaryPlistTrailer;
theData.appendBytes(new byte[5]);
theData.appendByte((byte) 0x0); // _sortVersion which AFIK is not being used in CF
theData.appendByte((byte) intsize); // _offsetIntSize which byte size for all ints in file
theData.appendByte((byte) refsize); // _objectRefSize which is total # of objects value in bytes
theData.appendBytes(longToByteArray2(numberOfObjects, 8)); // _numObjects which is object count
theData.appendBytes(longToByteArray2(theTopObject, 8)); // _topObject appears to be set to 0 in CF
theData.appendBytes(longToByteArray2(offsetTableStart, 8)); // _offsetTableOffset
// write to stream
try {
theData.writeToStream(out);
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("Failed to write binary property list ", e);
}
}