Index: src/OFDNSResolver.m ================================================================== --- src/OFDNSResolver.m +++ src/OFDNSResolver.m @@ -311,17 +311,34 @@ DNSClass: DNSClass preference: preference mailExchange: mailExchange TTL: TTL] autorelease]; } else if (recordType == OF_DNS_RECORD_TYPE_TXT) { - OFData *textData = [OFData dataWithItems: &buffer[i] - count: dataLength]; + OFMutableArray *textStrings = [OFMutableArray array]; + + while (dataLength > 0) { + uint_fast8_t stringLength = buffer[i++]; + dataLength--; + + if (stringLength > dataLength) + @throw [OFInvalidServerReplyException + exception]; + + [textStrings addObject: + [OFData dataWithItems: buffer + i + count: stringLength]]; + + i += stringLength; + dataLength -= stringLength; + } + + [textStrings makeImmutable]; return [[[OFTXTDNSResourceRecord alloc] initWithName: name DNSClass: DNSClass - textData: textData + textStrings: textStrings TTL: TTL] autorelease]; } else if (recordType == OF_DNS_RECORD_TYPE_RP) { size_t j = i; OFString *mailbox = parseName(buffer, length, &j, MAX_ALLOWED_POINTERS); Index: src/OFDNSResourceRecord.h ================================================================== --- src/OFDNSResourceRecord.h +++ src/OFDNSResourceRecord.h @@ -22,10 +22,11 @@ OF_ASSUME_NONNULL_BEGIN /*! @file */ +@class OFArray OF_GENERIC(ObjectType); @class OFData; /*! * @brief The DNS class. */ @@ -588,17 +589,17 @@ * @brief A class representing a TXT DNS resource record. */ OF_SUBCLASSING_RESTRICTED @interface OFTXTDNSResourceRecord: OFDNSResourceRecord { - OFData *_textData; + OFArray OF_GENERIC(OFData *) *_textStrings; } /*! * @brief The text of the resource record. */ -@property (readonly, nonatomic) OFData *textData; +@property (readonly, nonatomic) OFArray OF_GENERIC(OFData *) *textStrings; - (instancetype)initWithName: (OFString *)name DNSClass: (of_dns_class_t)DNSClass recordType: (of_dns_record_type_t)recordType TTL: (uint32_t)TTL OF_UNAVAILABLE; @@ -607,17 +608,17 @@ * @brief Initializes an already allocated OFTXTDNSResourceRecord with the * specified name, class, text data and time to live. * * @param name The name for the resource record * @param DNSClass The class code for the resource record - * @param textData The data for the resource record + * @param textStrings An array of text strings for the resource record * @param TTL The time to live for the resource record * @return An initialized OFTXTDNSResourceRecord */ - (instancetype)initWithName: (OFString *)name DNSClass: (of_dns_class_t)DNSClass - textData: (OFData *)textData + textStrings: (OFArray OF_GENERIC(OFData *) *)textStrings TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; @end #ifdef __cplusplus extern "C" { Index: src/OFDNSResourceRecord.m ================================================================== --- src/OFDNSResourceRecord.m +++ src/OFDNSResourceRecord.m @@ -16,10 +16,11 @@ */ #include "config.h" #import "OFDNSResourceRecord.h" +#import "OFArray.h" #import "OFData.h" #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" @@ -1250,11 +1251,11 @@ self.className, _name, _priority, _weight, _target, _port, _TTL]; } @end @implementation OFTXTDNSResourceRecord -@synthesize textData = _textData; +@synthesize textStrings = _textStrings; - (instancetype)initWithName: (OFString *)name DNSClass: (of_dns_class_t)DNSClass recordType: (of_dns_record_type_t)recordType TTL: (uint32_t)TTL @@ -1262,20 +1263,20 @@ OF_INVALID_INIT_METHOD } - (instancetype)initWithName: (OFString *)name DNSClass: (of_dns_class_t)DNSClass - textData: (OFData *)textData + textStrings: (OFArray OF_GENERIC(OFData *) *)textStrings TTL: (uint32_t)TTL { self = [super initWithName: name DNSClass: DNSClass recordType: OF_DNS_RECORD_TYPE_TXT TTL: TTL]; @try { - _textData = [textData copy]; + _textStrings = [textStrings copy]; } @catch (id e) { [self release]; @throw e; } @@ -1282,11 +1283,11 @@ return self; } - (void)dealloc { - [_textData release]; + [_textStrings release]; [super dealloc]; } - (bool)isEqual: (id)object @@ -1308,12 +1309,12 @@ return false; if (record->_recordType != _recordType) return false; - if (record->_textData != _textData && - ![record->_textData isEqual: _textData]) + if (record->_textStrings != _textStrings && + ![record->_textStrings isEqual: _textStrings]) return false; return true; } @@ -1326,25 +1327,62 @@ OF_HASH_ADD_HASH(hash, _name.hash); OF_HASH_ADD(hash, _DNSClass >> 8); OF_HASH_ADD(hash, _DNSClass); OF_HASH_ADD(hash, _recordType >> 8); OF_HASH_ADD(hash, _recordType); - OF_HASH_ADD_HASH(hash, _textData.hash); + OF_HASH_ADD_HASH(hash, _textStrings.hash); OF_HASH_FINALIZE(hash); return hash; } - (OFString *)description { - return [OFString stringWithFormat: + void *pool = objc_autoreleasePoolPush(); + OFMutableString *text = [OFMutableString string]; + bool first = true; + OFString *ret; + + for (OFData *string in _textStrings) { + const unsigned char *stringItems = string.items; + size_t stringCount = string.count; + + if (first) { + first = false; + [text appendString: @"\""]; + } else + [text appendString: @" \""]; + + for (size_t i = 0; i < stringCount; i++) { + if (stringItems[i] == '\\') + [text appendString: @"\\\\"]; + else if (stringItems[i] == '"') + [text appendString: @"\\\""]; + else if (stringItems[i] < 0x20) + [text appendFormat: @"\\x%02X", stringItems[i]]; + else if (stringItems[i] < 0x7F) + [text appendFormat: @"%c", stringItems[i]]; + else + [text appendFormat: @"\\x%02X", stringItems[i]]; + } + + [text appendString: @"\""]; + } + + ret = [OFString stringWithFormat: @"<%@:\n" @"\tName = %@\n" @"\tClass = %@\n" - @"\tText Data = %@\n" + @"\tText strings = %@\n" @"\tTTL = %" PRIu32 "\n" @">", - self.className, _name, of_dns_class_to_string(_DNSClass), _textData, + self.className, _name, of_dns_class_to_string(_DNSClass), text, _TTL]; + + [ret retain]; + + objc_autoreleasePoolPop(pool); + + return [ret autorelease]; } @end