diff --git a/objectivec/GPBUnknownFieldSet.m b/objectivec/GPBUnknownFieldSet.m index 5fe8ce03c4..10fb80c0c7 100644 --- a/objectivec/GPBUnknownFieldSet.m +++ b/objectivec/GPBUnknownFieldSet.m @@ -154,7 +154,10 @@ static void CopyWorker(__unused const void *key, const void *value, void *contex - (NSString *)description { NSMutableString *description = [NSMutableString stringWithFormat:@"<%@ %p>: TextFormat: {\n", [self class], self]; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" NSString *textFormat = GPBTextFormatForUnknownFieldSet(self, @" "); +#pragma clang diagnostic pop [description appendString:textFormat]; [description appendString:@"}"]; return description; diff --git a/objectivec/GPBUtilities.h b/objectivec/GPBUtilities.h index 9673aa4261..578545df05 100644 --- a/objectivec/GPBUtilities.h +++ b/objectivec/GPBUtilities.h @@ -40,7 +40,9 @@ NSString *GPBTextFormatForMessage(GPBMessage *message, NSString *__nullable line * @return An NSString with the TextFormat of the unknown field set. **/ NSString *GPBTextFormatForUnknownFieldSet(GPBUnknownFieldSet *__nullable unknownSet, - NSString *__nullable lineIndent); + NSString *__nullable lineIndent) + __attribute__((deprecated("Use GPBTextFormatForMessage will include the unknown fields, and " + "GPBUnknownFieldSet it going away."))); /** * Checks if the given field number is set on a message. diff --git a/objectivec/GPBUtilities.m b/objectivec/GPBUtilities.m index ff309860cd..0764c96910 100644 --- a/objectivec/GPBUtilities.m +++ b/objectivec/GPBUtilities.m @@ -5,7 +5,7 @@ // license that can be found in the LICENSE file or at // https://developers.google.com/open-source/licenses/bsd -#import "GPBUtilities_PackagePrivate.h" +#import "GPBUtilities.h" #import @@ -15,6 +15,9 @@ #import "GPBMessage_PackagePrivate.h" #import "GPBUnknownField.h" #import "GPBUnknownFieldSet.h" +#import "GPBUnknownField_PackagePrivate.h" +#import "GPBUnknownFields.h" +#import "GPBUtilities_PackagePrivate.h" // Direct access is use for speed, to avoid even internally declaring things // read/write, etc. The warning is enabled in the project to ensure code calling @@ -1929,6 +1932,78 @@ static void AppendTextFormatForMessageExtensionRange(GPBMessage *message, NSArra } // for..in(activeExtensions) } +static void AppendTextFormatForUnknownFields(GPBUnknownFields *ufs, NSMutableString *toStr, + NSString *lineIndent) { +#if defined(DEBUG) && DEBUG + NSCAssert(!ufs.empty, @"Internal Error: No unknown fields to format."); +#endif + // Extract the fields and sort them by field number. Use a stable sort and sort just by the field + // numbers, that way the output will still show the order the different types were added as well + // as maintaining the order within a give number/type pair (i.e. - repeated fields say in order). + NSMutableArray *sortedFields = [[NSMutableArray alloc] initWithCapacity:ufs.count]; + for (GPBUnknownField *field in ufs) { + [sortedFields addObject:field]; + } + [sortedFields + sortWithOptions:NSSortStable + usingComparator:^NSComparisonResult(GPBUnknownField *field1, GPBUnknownField *field2) { + int32_t fieldNumber1 = field1->number_; + int32_t fieldNumber2 = field2->number_; + if (fieldNumber1 < fieldNumber2) { + return NSOrderedAscending; + } else if (fieldNumber1 > fieldNumber2) { + return NSOrderedDescending; + } else { + return NSOrderedSame; + } + }]; + + NSString *subIndent = nil; + + for (GPBUnknownField *field in sortedFields) { + int32_t fieldNumber = field->number_; + switch (field->type_) { + case GPBUnknownFieldTypeVarint: + [toStr appendFormat:@"%@%d: %llu\n", lineIndent, fieldNumber, field->storage_.intValue]; + break; + case GPBUnknownFieldTypeFixed32: + [toStr appendFormat:@"%@%d: 0x%X\n", lineIndent, fieldNumber, + (uint32_t)field->storage_.intValue]; + break; + case GPBUnknownFieldTypeFixed64: + [toStr appendFormat:@"%@%d: 0x%llX\n", lineIndent, fieldNumber, field->storage_.intValue]; + break; + case GPBUnknownFieldTypeLengthDelimited: + [toStr appendFormat:@"%@%d: ", lineIndent, fieldNumber]; + AppendBufferAsString(field->storage_.lengthDelimited, toStr); + [toStr appendString:@"\n"]; + break; + case GPBUnknownFieldTypeGroup: { + GPBUnknownFields *group = field->storage_.group; + if (group.empty) { + [toStr appendFormat:@"%@%d: {}\n", lineIndent, fieldNumber]; + } else { + [toStr appendFormat:@"%@%d: {\n", lineIndent, fieldNumber]; + if (subIndent == nil) { + subIndent = [lineIndent stringByAppendingString:@" "]; + } + AppendTextFormatForUnknownFields(group, toStr, subIndent); + [toStr appendFormat:@"%@}\n", lineIndent]; + } + } break; + case GPBUnknownFieldTypeLegacy: +#if defined(DEBUG) && DEBUG + NSCAssert( + NO, + @"Internal error: Shouldn't have gotten a legacy field type in the unknown fields."); +#endif + break; + } + } + [subIndent release]; + [sortedFields release]; +} + static void AppendTextFormatForMessage(GPBMessage *message, NSMutableString *toStr, NSString *lineIndent) { GPBDescriptor *descriptor = [message descriptor]; @@ -1951,11 +2026,12 @@ static void AppendTextFormatForMessage(GPBMessage *message, NSMutableString *toS } } - NSString *unknownFieldsStr = GPBTextFormatForUnknownFieldSet(message.unknownFields, lineIndent); - if ([unknownFieldsStr length] > 0) { + GPBUnknownFields *ufs = [[GPBUnknownFields alloc] initFromMessage:message]; + if (ufs.count > 0) { [toStr appendFormat:@"%@# --- Unknown fields ---\n", lineIndent]; - [toStr appendString:unknownFieldsStr]; + AppendTextFormatForUnknownFields(ufs, toStr, lineIndent); } + [ufs release]; } NSString *GPBTextFormatForMessage(GPBMessage *message, NSString *lineIndent) { diff --git a/objectivec/Tests/GPBUtilitiesTests.m b/objectivec/Tests/GPBUtilitiesTests.m index e32fccda46..d05a345523 100644 --- a/objectivec/Tests/GPBUtilitiesTests.m +++ b/objectivec/Tests/GPBUtilitiesTests.m @@ -6,17 +6,16 @@ // https://developers.google.com/open-source/licenses/bsd #import - -#import "GPBUtilities_PackagePrivate.h" - #import -#import "GPBTestUtilities.h" - #import "GPBDescriptor.h" #import "GPBDescriptor_PackagePrivate.h" #import "GPBMessage.h" +#import "GPBTestUtilities.h" +#import "GPBUnknownField.h" #import "GPBUnknownField_PackagePrivate.h" +#import "GPBUtilities.h" +#import "GPBUtilities_PackagePrivate.h" #import "objectivec/Tests/MapUnittest.pbobjc.h" #import "objectivec/Tests/Unittest.pbobjc.h" @@ -168,6 +167,54 @@ [expected release]; } +- (void)testTextFormatUnknownFields { + GPBUnknownFields *ufs = [[[GPBUnknownFields alloc] init] autorelease]; + [ufs addFieldNumber:100 varint:5]; + [ufs addFieldNumber:100 varint:4]; + [ufs addFieldNumber:10 varint:1]; + [ufs addFieldNumber:300 fixed32:0x50]; + [ufs addFieldNumber:300 fixed32:0x40]; + [ufs addFieldNumber:10 fixed32:0x10]; + [ufs addFieldNumber:200 fixed64:0x5000]; + [ufs addFieldNumber:200 fixed64:0x4000]; + [ufs addFieldNumber:10 fixed64:0x1000]; + [ufs addFieldNumber:10 lengthDelimited:DataFromCStr("foo")]; + [ufs addFieldNumber:10 lengthDelimited:DataFromCStr("bar")]; + GPBUnknownFields *group = [ufs addGroupWithFieldNumber:150]; + [group addFieldNumber:2 varint:2]; + [group addFieldNumber:1 varint:1]; + group = [ufs addGroupWithFieldNumber:150]; + [group addFieldNumber:1 varint:1]; + [group addFieldNumber:3 fixed32:0x3]; + [group addFieldNumber:2 fixed64:0x2]; + TestEmptyMessage *message = [TestEmptyMessage message]; + [message mergeUnknownFields:ufs extensionRegistry:nil]; + + NSString *expected = @"# --- Unknown fields ---\n" + @"10: 1\n" + @"10: 0x10\n" + @"10: 0x1000\n" + @"10: \"foo\"\n" + @"10: \"bar\"\n" + @"100: 5\n" + @"100: 4\n" + @"150: {\n" + @" 1: 1\n" + @" 2: 2\n" + @"}\n" + @"150: {\n" + @" 1: 1\n" + @" 2: 0x2\n" + @" 3: 0x3\n" + @"}\n" + @"200: 0x5000\n" + @"200: 0x4000\n" + @"300: 0x50\n" + @"300: 0x40\n"; + NSString *result = GPBTextFormatForMessage(message, nil); + XCTAssertEqualObjects(expected, result); +} + - (void)testSetRepeatedFields { TestAllTypes *message = [TestAllTypes message];