+
+
+struct objc_protocolopt_t : objc_stringhash_t {
+ // ...objc_stringhash_t fields...
+ // uint32_t protocolOffsets[capacity]; /* offsets from &capacity to protocol_t */
+
+ objc_stringhash_offset_t *protocolOffsets() { return (objc_stringhash_offset_t *)&offsets()[capacity]; }
+ const objc_stringhash_offset_t *protocolOffsets() const { return (const objc_stringhash_offset_t *)&offsets()[capacity]; }
+
+ void* getProtocol(const char *key) const
+ {
+ uint32_t h = getIndex(key);
+ if (h == INDEX_NOT_FOUND) {
+ return NULL;
+ }
+
+ return (void *)((const char *)this + protocolOffsets()[h]);
+ }
+
+#ifdef SELOPT_WRITE
+
+ size_t size()
+ {
+ return
+ objc_stringhash_t::size() + capacity * sizeof(objc_stringhash_offset_t);
+ }
+
+ void byteswap(bool little_endian)
+ {
+ objc_stringhash_offset_t *o;
+
+ o = protocolOffsets();
+ for (objc_stringhash_offset_t i = 0; i < capacity; i++) {
+ S32(o[i]);
+ }
+
+ objc_stringhash_t::byteswap(little_endian);
+ }
+
+ const char *write(uint64_t base, size_t remaining,
+ string_map& strings, protocol_map& protocols,
+ bool verbose)
+ {
+ const char *err;
+ err = objc_stringhash_t::write(base, remaining, strings);
+ if (err) return err;
+
+ if (size() > remaining) {
+ return "selector section too small (metadata not optimized)";
+ }
+
+ // Set protocol offsets to 0
+ for (uint32_t i = 0; i < capacity; i++) {
+ protocolOffsets()[i] = 0;
+ }
+
+ // Set real protocol offsets
+# define SHIFT (64 - 8*sizeof(objc_stringhash_offset_t))
+ protocol_map::const_iterator c;
+ for (c = protocols.begin(); c != protocols.end(); ++c) {
+ uint32_t h = getIndex(c->first);
+ if (h == INDEX_NOT_FOUND) {
+ return "protocol list busted (metadata not optimized)";
+ }
+
+ int64_t offset = c->second - base;
+ if ((offset<<SHIFT)>>SHIFT != offset) {
+ return "protocol offset too big (metadata not optimized)";
+ }
+
+ protocolOffsets()[h] = (objc_stringhash_offset_t)offset;
+ }
+# undef SHIFT
+
+ return NULL;
+ }
+
+// SELOPT_WRITE
+#endif
+};
+
+