From 0116bcecf0b1ebb66be0179a1a8e73670814dee1 Mon Sep 17 00:00:00 2001 From: Michael Heins Date: Thu, 18 May 2017 08:29:53 -0600 Subject: Hex edit for binary columns Implement the ability to edit binary columns as hex data. Check input string for valid hex values; if invalid input, open alert sheet. --- Source/SPDataAdditions.h | 1 + Source/SPDataAdditions.m | 68 +++++++++++++++++++++++++++++++++++++++ Source/SPTableContentDataSource.m | 29 ++++++++++++++++- Source/SPTableContentDelegate.m | 7 ---- 4 files changed, 97 insertions(+), 8 deletions(-) diff --git a/Source/SPDataAdditions.h b/Source/SPDataAdditions.h index cd8374f6..49dcd315 100644 --- a/Source/SPDataAdditions.h +++ b/Source/SPDataAdditions.h @@ -43,6 +43,7 @@ typedef NS_OPTIONS(NSUInteger, SPLineTerminator) { - (NSData *)dataEncryptedWithKey:(NSData *)aesKey IV:(NSData *)iv; - (NSData *)dataDecryptedWithPassword:(NSString *)password; - (NSData *)dataDecryptedWithKey:(NSData *)key; ++ (NSData *)dataWithHexString: (NSString *)hex; - (NSData *)compress; - (NSData *)decompress; diff --git a/Source/SPDataAdditions.m b/Source/SPDataAdditions.m index 53d18274..3a35e081 100644 --- a/Source/SPDataAdditions.m +++ b/Source/SPDataAdditions.m @@ -343,6 +343,74 @@ uint32_t LimitUInt32(NSUInteger i); return hexString; } +static int hexval( char c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + return -1; +} + +// +// Interpret a string of hex digits in 'hex' as hex data, and return +// an NSData representation of the data. Spaces are permitted within +// the string and an initial '0x' or '0X' will be ignored. If bad input +// is detected, nil is returned. +// ++ (NSData *)dataWithHexString: (NSString *)hex +{ + int n = (int)(hex.length + 1); + if (n <= 1) + return nil; // no string or empty string + char c, *str = (char *)malloc( n), *d = str, *e; + const char *s = hex.UTF8String; + // + // Copy input while removing spaces and tabs. + // + do { + c = *s++; + if (c != ' ' && c != '\t') + *d++ = c; + } while (c); + d = str; + if (d[0] == '0' && (d[1] == 'x' || d[1] == 'X')) { + d += 2; // bypass initial 0x or 0X + } + // + // Check for non-hex characters + // + for (e = d; (c = *e); e++) { + if (hexval( c) < 0) { + break; + } + } + n = (int)(e - d); // n = # of hex digits + if (*e) { + // + // Bad hex char at e. Return empty data. Alternative would be to + // convert data up to bad point. + // + free( str); + return nil; + } + int nbytes = (n % 2) ? (n + 1) / 2 : n / 2; + unsigned char *bytes = malloc( nbytes), *b = bytes; + if (n % 2) { + *b++ = hexval( *d++); + } + while (d < e) { + unsigned char v = (hexval( d[0]) << 4) + hexval( d[1]); + *b++ = v; + d += 2; + } + NSData *data = [NSData dataWithBytesNoCopy: bytes length: nbytes freeWhenDone: YES]; + free( str); + return data; +} + /** * Returns the hex representation of the given data. */ diff --git a/Source/SPTableContentDataSource.m b/Source/SPTableContentDataSource.m index 56e8df71..a005cdce 100644 --- a/Source/SPTableContentDataSource.m +++ b/Source/SPTableContentDataSource.m @@ -33,6 +33,7 @@ #import "SPDataStorage.h" #import "SPCopyTable.h" #import "SPTablesList.h" +#import "SPAlertSheets.h" #import #import @@ -177,6 +178,11 @@ return; } + NSInteger columnIndex = [[tableColumn identifier] integerValue]; + NSDictionary *columnDefinition = [[(id )[tableContentView delegate] dataColumnDefinitions] objectAtIndex:columnIndex]; + + NSString *columnType = [columnDefinition objectForKey:@"typegrouping"]; + // Catch editing events in the row and if the row isn't currently being edited, // start an edit. This allows edits including enum changes to save correctly. if (isEditingRow && [tableContentView selectedRow] != currentlyEditingRow) { @@ -192,7 +198,28 @@ NSDictionary *column = NSArrayObjectAtIndex(dataColumns, [[tableColumn identifier] integerValue]); - if (object) { + if ([columnType isEqualToString:@"binary"] && [object isKindOfClass: [NSString class]]) { + // + // This is a binary object being edited as a hex string. (Is there a better + // way to detect this case?) + // Convert the string back to binary, checking for errors. + // + NSData *data = [NSData dataWithHexString: object]; + if (data) { + object = data; + [tableValues replaceObjectInRow:rowIndex column:[[tableColumn identifier] integerValue] withObject:object]; + } + else { + SPOnewayAlertSheet( + NSLocalizedString(@"Error", @"error"), + [tableDocumentInstance parentWindow], + NSLocalizedString(@"Bad hexadecimal data input.", @"Bad hexadecimal data input.") + ); + return; + + } + } + else if (object) { // Restore NULLs if necessary if ([object isEqualToString:[prefs objectForKey:SPNullValue]] && [[column objectForKey:@"null"] boolValue]) { object = [NSNull null]; diff --git a/Source/SPTableContentDelegate.m b/Source/SPTableContentDelegate.m index 186fbfcc..3c437333 100644 --- a/Source/SPTableContentDelegate.m +++ b/Source/SPTableContentDelegate.m @@ -273,13 +273,6 @@ // Retrieve the column definition NSDictionary *columnDefinition = [cqColumnDefinition objectAtIndex:[[tableColumn identifier] integerValue]]; - // TODO: Fix editing of "Display as Hex" columns and remove this (also see above) - if ([self cellValueIsDisplayedAsHexForColumn:[[tableColumn identifier] integerValue]]) { - NSBeep(); - [SPTooltip showWithObject:NSLocalizedString(@"Disable \"Display Binary Data as Hex\" in the View menu to edit this field.",@"Temporary : Tooltip shown when trying to edit a binary field in table content view while it is displayed using HEX conversion")]; - return NO; - } - // Open the editing sheet if required if ([tableContentView shouldUseFieldEditorForRow:rowIndex column:[[tableColumn identifier] integerValue] checkWithLock:NULL]) { -- cgit v1.2.3