In Objective-C, I generate a simple MD5-hash of 'HelloKey', which returns 0FD16658AEE3C52060A39F4EDFB11437. Unfortunately, I could not get a raw return, so I have to work with this string to get a raw MD5-hash (or do you know how I can get a raw result from the start?)
Anyway, in order to convert it to raw, I split it into chunks of 2 chars each, calculate the hex value, and append a char with that value to a string.
Here's the function:
- (NSString *)hex2bin:(NSString *)input{
NSString *output = #"";
for (int i = 0; i < input.length; i+=2){
NSString *component = [input substringWithRange:NSMakeRange(i, 2)];
unsigned int outVal;
NSScanner* scanner = [NSScanner scannerWithString:component];
[scanner scanHexInt:&outVal];
/* if(outVal > 127){
outVal -= 256;
} */
// unsigned char appendage = (char)outVal;
output = [NSString stringWithFormat:#"%#%c", output, outVal];
NSLog(#"component: %# = %d", component, outVal);
}
return output;
}
When I print each outval, I get:
0F = 15
D1 = 209
66 = 102
58 = 88
AE = 174
E3 = 227
C5 = 197
20 = 32
60 = 96
A3 = 163
9F = 159
4E = 78
DF = 223
B1 = 177
14 = 20
37 = 55
However, when I print the string that I get with a special function that tells me the integer values of each character (a function which is shown here):
- (NSString *)str2bin:(NSString *)input{
NSString *output = #"";
for (NSInteger charIdx=0; charIdx < input.length; charIdx++){
char currentChar = [input characterAtIndex:charIdx];
int charNum = [NSNumber numberWithChar:currentChar].intValue;
output = [NSString stringWithFormat:#"%# %d", output, charNum];
}
return output;
}
I get: 15 20 102 88 -58 30 72 32 96 -93 -4 78 2 -79 20 55. You will notice that there are significant differences, like 209 -> 20, 174 -> -58, 227 -> 30. In some cases, the difference is 256, so no harm done. But in other cases, it's not, and I would really like to know what's going wrong. Any tips?
You are doing it wrong, since you are trying to store binary data in NSString, which is UTF8 string.
You should use NSData (or C string) to store binary hash representation.
Related
I have an __NSCFData object. I know what's inside it.
61 70 70 6c 65 2c 74 79 70 68 6f 6f 6e 00 41 52 4d 2c 76 38 00
I tried converting it to a string with initWithData: and stringWithUTF8String: and it gives me "apple,typhoon". The conversion is terminated at 00
The data actually is
61 a
70 p
70 p
6c l
65 e
2c ,
74 t
79 y
70 p
68 h
6f o
6f o
6e n
00 (null)
41 A
52 R
4d M
2c ,
76 v
38 8
00 (null)
How can I properly convert this without loss of information?
The documentation for stringWithUTF8String describes its first parameter as:
A NULL-terminated C array of bytes in UTF8 encoding.
Which is why your conversion stops at the first null byte.
What you appear to have is a collection of C strings packed into a single NSData. You can convert each one individually. Use the NSData methods bytes and length to obtain a pointer to the bytes/first C string and the total number of bytes respectively. The standard C function strlen() will give you the length in bytes of an individual string. Combine these and some simple pointer arithmetic and you can write a loop which converts each string and, for example, stores them all into an array or concatenates them.
If you get stuck implementing the solution ask a new question, show your code, and explain the issue. Someone will undoubtedly help you with the next step.
HTH
In contrast to the intention of some answers, the stored strings in instances of NSString are not 0-terminated. Even there might be problems with writing them out (since underlying C functions for output expects a 0-terminated string), the instances itself can contain a \0:
NSString *zeroIncluded = #"A\0B";
NSLog(#"%ld", [zeroIncluded length]);
// prints 3
To create such an instance you can use methods that have a bytes and a length parameter, i. e. -initWithBytes:length:encoding:. Therefore something like this should work:
NSData *data = …
[[NSString alloc] initWithBytes:[data bytes] length:[data length] encoding:NSUTF8StringEncoding];
However, as intended by CRD, you might check, whether you want to have such a string.
0, or null, is the sentinel value which terminates strings, so you're going to have to deal with it somehow if you want to automatically dump the bytes into a string. If you don't, the string, or things that try to print it, for example, will assume the end of string is reached when reaching the NULL.
Just replace the bytes as they occur with something printable, like a space. Use whatever value works for you.
Example:
// original data you have from somewhere
char something[] = "apple,typhoon\0ARM,v8\0";
NSData *data = [NSData dataWithBytes:something length:sizeof(something)];
// Find each null terminated string in the data
NSMutableArray *strings = [NSMutableArray new];
NSMutableString *temp = [NSMutableString string];
const char *bytes = [data bytes];
for (int i = 0; i < [data length]; i++) {
unsigned char byte = (unsigned char)bytes[i];
if (byte == 0) {
if ([temp length] > 0) {
[strings addObject:temp];
temp = [NSMutableString string];
}
} else {
[temp appendFormat:#"%c", byte];
}
}
// Results
NSLog(#"strings count: %lu", [strings count]);
[strings enumerateObjectsUsingBlock:^(NSString *string, NSUInteger idx, BOOL * _Nonnull stop) {
NSLog(#"%ld: %#", idx, string);
}];
// strings count: 2
// 0: apple,typhoon
// 1: ARM,v8
I am developing in ios objective-c BLE , I receive the BLE data and print by NSLog like the following:
NSData *initialData = [characteristic value];
NSData *startOfFrameData = [initialData subdataWithRange:NSMakeRange(0, 20)];
NSLog(#"StartOfFrameData: %#", startOfFrameData);
The data in the log is like the following:
StartOfFrameData: <04621281 00931012 fed0d499 e92ceaac 3286513e>
But it only has 8 Byte after I convert it to the uint8_t via the following code:
uint8_t *tempData1=(uint8_t *)[startOfFrameData bytes];
NSLog(#"before tempData1:%lu", sizeof(tempData1));
for(int i = 0;i<sizeof(tempData1);i++){
NSLog(#"tempData1[%d] = %x , %d",i,tempData1[i],tempData1[i]);
}
The log show like the following:
tempData1:8
tempData1[0] = f4 , 244
tempData1[1] = 9b , 155
tempData1[2] = b2 , 178
tempData1[3] = 81 , 129
tempData1[4] = 0 , 0
tempData1[5] = 6 , 6
tempData1[6] = 5 , 5
tempData1[7] = 71 , 113
Why it only has 8 Byte after covert to uint_8 ?
Did I missing something? Thanks in advance.
In your for loop you are asking for the size of tempData1. tempData1 is of type uint_8t * which is a pointer. Pointers contain memory addresses and in this case the memory address is 8 bytes.
You should probably iterate up to startOfFrameData.length.
For example:
uint8_t *tempData1 = (uint8_t *)[startOfFrameData bytes];
for(int i = 0; i < startOfFrameData.length; i++){
NSLog(#"tempData1[%d] = %x , %d",i,tempData1[i],tempData1[i]);
}
I have a method that converts integer to two dec Bytes:
- (void)intToBytes:(NSInteger *)integer {
int16_t i = integer;
Byte b0 = (Byte)(i / 256);
Byte b1 = (Byte)(i % 256);
NSLog(#"BYTES: %hhu, %hhu", b0, b1);
}
How could I convert those dec Bytes to hex? Or integer to hex Bytes straightaway?
Try this
NSInteger a = 449;
NSString * hex = [NSString stringWithFormat:#"%x",(unsigned int)a];
Here hex is "1c1"
Is there build in methods for formatting file sizes in Objective C? Or may be you could suggest me some library/source code/etc.?
What I mean is you have some file size that should be displayed something like this depending on given size:
1234 kb
1,2 mb
etc..
Thanks in advance
This one solves the problem quite elegantly:
[NSByteCountFormatter stringFromByteCount:countStyle:]
Example usage:
long long fileSize = 14378165;
NSString *displayFileSize = [NSByteCountFormatter stringFromByteCount:fileSize
countStyle:NSByteCountFormatterCountStyleFile];
NSLog(#"Display file size: %#", displayFileSize);
fileSize = 50291;
displayFileSize = [NSByteCountFormatter stringFromByteCount:fileSize
countStyle:NSByteCountFormatterCountStyleFile];
NSLog(#"Display file size: %#", displayFileSize);
Log output:
Display file size: 14.4 MB
Display file size: 50 KB
The output will be formatted properly according to the device's regional settings.
Available since iOS 6.0 and OS X 10.8.
Here's some code I found lying around. Not terribly efficient, and probably better attached to a category of NSNumberFormatter than NSNumber, and so on, but it seems to work
#interface NSNumber (FormatKibi)
- (NSString *)formatKibi;
#end
#implementation NSNumber (FormatKibi)
- (NSString *)formatKibi {
double value = [self doubleValue];
static const char suffixes[] = { 0, 'k', 'm', 'g', 't' };
int suffix = 0;
if (value <= 10000)
return [[NSString stringWithFormat:#"%5f", value]
substringToIndex:5];
while (value > 9999) {
value /= 1024.0;
++suffix;
if (suffix >= sizeof(suffixes)) return #"!!!!!";
}
return [[[NSString stringWithFormat:#"%4f", value]
substringToIndex:4]
stringByAppendingFormat:#"%c", suffixes[suffix]];
}
#end
I tested it with this:
int main(int argc, char *argv[]) {
for (int i = 1; i != argc; ++i) {
NSNumber *n = [NSNumber numberWithInteger:
[[NSString stringWithUTF8String:argv[i]]
integerValue]];
printf("%s ", [[n formatKibi] UTF8String]);
}
printf("\n");
return 0;
}
Then:
$ ./sizeformat 1 12 123 1234 12345 123456 1234567 12345678 1234567890 123456789012 12345678901234 1234567890123456 123456789012345678
1.000 12.00 123.0 1234. 12.0k 120.k 1205k 11.7m 1177m 114.g 11.2t 1122t !!!!!
Get the file size and then calculate whether it is in bytes or kb or mb
NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:URL error:&attributesError];
NSNumber *fileSizeNumber = [fileAttributes objectForKey:NSFileSize];
long long fileSize = [fileSizeNumber longLongValue];
Then conversion table
1 byte = 8 bits
1 KiB = 1,024 bytes
1 MiB = 1024 kb
1 GiB = 1024 mb
check this link
(This question has been rewritten from an issue with NSTextView following some further research)
UPDATE: You can download a very basic project that displays the issue here:
http://w3style.co.uk/~d11wtq/DocumentApp.tar.gz
(Do a grep -c "\r" file.txt on the file you save to get a line count where \r occurs... repeat for \n).
I've realised all files created by NSDocument have \r is line endings, not the standard \n, even though the NSData my document subclass returns does not contain \r, it only contains \n. Is there a way to configure this?
I thought Macs used UNIX line endings these days, so it seems weird that AppKit is still using the antiquated Mac endings. Weirder is that NSDocument asks for NSData, then rather unkindly corrupts that NSData by transforming the line endings.
The switch to \r is happening after producing NSData, so NSDocument itself is doing some replacements on the bytes:
const char *bytes = [data bytes];
int i, len;
for (i = 0, len = [data length]; i < len; ++i) {
NSLog(#"byte %d = %02x", i, bytes[i]);
}
Outputs (note 0a is the hex value of \n):
> 2010-12-17 12:45:59.076
> MojiBaker[74929:a0f] byte 0 = 66
> 2010-12-17 12:45:59.076
> MojiBaker[74929:a0f] byte 1 = 6f
> 2010-12-17 12:45:59.076
> MojiBaker[74929:a0f] byte 2 = 6f
> 2010-12-17 12:45:59.077
> MojiBaker[74929:a0f] byte 3 = 0a
> 2010-12-17 12:45:59.077
> MojiBaker[74929:a0f] byte 4 = 62
> 2010-12-17 12:45:59.077
> MojiBaker[74929:a0f] byte 5 = 61
> 2010-12-17 12:45:59.077
> MojiBaker[74929:a0f] byte 6 = 72
> 2010-12-17 12:45:59.077
> MojiBaker[74929:a0f] byte 7 = 0a
If NSDocument is going to ask for NSData then it should respect that and not modify it.
Here's the full code from the method: -dataOfType:error: method in my document:
-(NSData *)dataOfType:(NSString *)typeName error:(NSError **)outError {
NSString *string = [textView string];
// DEBUG CODE...
NSArray *unixLines = [string componentsSeparatedByString:#"\n"];
NSArray *windowsLines = [string componentsSeparatedByString:#"\r\n"];
NSArray *macLines = [string componentsSeparatedByString:#"\r"];
NSLog(#"TextView has %d LF, %d CRLF, %d CR", [unixLines count] - 1, [windowsLines count] - 1, [macLines count] - 1);
NSData *data = [NSData dataWithBytes:[string cStringUsingEncoding:NSUTF8StringEncoding]
length:[string lengthOfBytesUsingEncoding:NSUTF8StringEncoding]];
const char *bytes = [data bytes];
int i, len;
for (i = 0, len = [data length]; i < len; ++i) {
NSLog(#"byte %d = %02x", i, bytes[i]);
}
if (data != nil) {
[textView breakUndoCoalescing];
}
return data;
}
NSDocument doesn’t care about line termination; it’s a semi-abstract class, designed to be subclassed. By itself it imposes nothing on a file format.
It’s the particular implementation of an NSDocument subclass - one that happens to read and write plain text - that will care about line termination characters.