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 | /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- vim: ft=cpp et ts=4 sw=4: * * Copyright (c) 2023 Apple Inc. All rights reserved. * * @APPLE_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. 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_LICENSE_HEADER_END@ */ /* * This implements a basic bplist00 (aka Binary Plist version 0) encoder. It supports the following functionality * * * Basic Types * * Integer * * String * * Data * * Collection Types * * Array * * Dictionary * * Basic types are builtin plist types supported by the plist00 format. This encoder uniques them to save space * * Collection types are builtin plist types supported by the bplist00 format. This encoder does not bother attempting to unique them * as it is computationally expensive and due to the unique addresses of all the images and segments we know a priori the vast * majority of them will be unique. In some cases where we know two collections will be identical the encoder explicity reuses the collection. * * Usage * * This is not intended to be a general purpose bplist00 encoder, as such it only implements features necessary for dyld. * * All plists generated by this encoder will have a dictionary as their root object * * There is no way to create a detached object, all objects must either be created by explicitly adding an entry to collection * * All dictionary keys must be strings * * There is no validation the dictionaries only have a single instance of a particular key added to them * * There is no support for reading plists or walking back through the created structure */ #ifndef PropertyList_h #define PropertyList_h #include <cstdint> #include <uuid/uuid.h> #include "Vector.h" #include "Defines.h" #include "ByteStream.h" struct VIS_HIDDEN PropertyList { struct Object; using Allocator = lsl::Allocator; using ObjectVector = lsl::Vector<Object*>; PropertyList(Allocator&); void encode(ByteStream&); struct Object { Object() = delete; enum Type : uint64_t { String = 0, Integer = 1, Array = 2, Dictionary = 3, Data = 4 }; void convertToRedirect(uint64_t index); void setIndex(uint64_t index); uint64_t index() const; Type type() const; bool processed() const; void setProcessed(); virtual void emit(uint8_t objectIndexSize, ByteStream& bytes) = 0; virtual void deallocate() = 0; protected: Object(Type type) : _type(type) {} uint64_t _index : 59 = ~1ULL; uint64_t _type : 3 = 0; uint64_t _processed : 1 = 0; uint64_t _isRedirect : 1 = 0; }; struct Data : Object { Data() = delete; ~Data(); Data(Allocator& allocator, uint64_t size); Data(Allocator& allocator, std::span<std::byte> value); virtual void emit(uint8_t objectIndexSize, ByteStream& bytes) override; virtual void deallocate() override; bool operator==(const Data& other) const; std::strong_ordering operator<=>(const Data& other) const; std::span<std::byte> bytes(); private: lsl::Vector<std::byte> _value; }; struct String : Object { String() = delete; ~String(); String(const String&) = delete; String(Allocator& allocator, std::string_view value); // Note: no constructor from "const char*" virtual void emit(uint8_t objectIndexSize, ByteStream& bytes) override; bool emitUnicode(uint8_t objectIndexSize, uint64_t stringSize, ByteStream& bytes) const; virtual void deallocate() override; bool operator==(const String& other) const; std::strong_ordering operator<=>(const String& other) const; private: const char* _value; //FIXME: should this be a std::string_view ? }; struct Array : Object { Array() = delete; Array(Allocator& allocator); ~Array(); std::span<Object*> values(); virtual void emit(uint8_t objectIndexSize, ByteStream& bytes) override; virtual void deallocate() override; template<typename T, class... Args> T& addObject(Args&&... args) { Allocator& allocator = *_values.allocator(); void* storage = allocator.aligned_alloc(alignof(T), sizeof(T)); T* result = new (storage) T(allocator, std::forward<Args>(args)...); _values.push_back(result); return *result; } private: ObjectVector _values; }; struct Dictionary : Object { Dictionary() = delete; Dictionary(Allocator& allocator); std::span<Object*> keys(); std::span<Object*> values(); virtual void emit(uint8_t objectIndexSize, ByteStream& bytes) override; virtual void deallocate() override; template<typename T, class... Args> T& addObjectForKey(std::string_view key, Args&&... args) { Allocator& allocator = *_values.allocator(); void* keyStorage = allocator.aligned_alloc(alignof(struct String), sizeof(struct String)); _keys.push_back(new (keyStorage) struct String(allocator, key)); void* storage = allocator.aligned_alloc(alignof(T), sizeof(T)); T* result = new (storage) T(allocator, std::forward<Args>(args)...); _values.push_back(result); return *result; } void insertObjectForKey(std::string_view key, Object& object) { Allocator& allocator = *_values.allocator(); void* keyStorage = allocator.aligned_alloc(alignof(struct String), sizeof(struct String)); _keys.push_back(new (keyStorage) struct String(allocator, key)); _values.push_back(&object); } private: ObjectVector _keys; ObjectVector _values; }; struct Integer : Object { Integer() = delete; Integer(int64_t value); Integer(Allocator& allocator, int64_t value); virtual void emit(uint8_t objectIndexSize, ByteStream& bytes) override; virtual void deallocate() override; bool operator==(const Integer& other) const; std::strong_ordering operator<=>(const Integer& other) const; protected: int64_t _value; }; struct UUID : Data { UUID(Allocator& allocator, uuid_t uuid); }; struct Bitmap : Data { Bitmap(Allocator& allocator, uint64_t size); void setBit(uint64_t bit); }; template<typename T> struct Flags : PropertyList::Integer { Flags(Allocator& allocator) : PropertyList::Integer(allocator, 0) {} void setFlag(T flag, bool value = true) { assert(flag <= 62); // FIXME: deal with signed integers in PropertyList::Integer if (value) { _value |= flag; } else { _value &= ~flag; } } }; Dictionary& rootDictionary(); private: Allocator& _allocator; Dictionary _rootDictionary; }; #endif /* PropertyList_h */ |