unicode assignment failing in NSString? - objective-c

The following fails for both unichar assignments?
unsigned int c = 0x0001d122;
[NSString stringWithFormat:#"\U%#", [NSString stringWithFormat:#"%08X", c]];
[NSString stringWithFormat:#"\U%08X", c];
I am trying to do this programmatically (adding in the "\U" makes things difficult as seen above):
nssSymbol = #"\U0001d122"; \\this works... but need to be able to vary 'c'

As shown by Ken Thomases answer you can create a string from bytes, however you must know the endianness of your machine or use the endian conversion routines.
For example, on an Intel Mac which is little endian you can use:
uint32_t c = 0x0001d122;
NSString* s = [[NSString alloc] initWithBytes:&c
length:sizeof(c)
encoding:NSUTF32LittleEndianStringEncoding];
If you don't wish to code in knowledge of the systems endianness you can use the conversion routines. For example:
uint32_t c = EndianU32_NtoB(0x0001d122); // convert from native endianness to big endian
NSString* s = [[NSString alloc] initWithBytes:&c
length:sizeof(c)
encoding:NSUTF32BigEndianStringEncoding];
HTH

The handling of the \Unnnnnnnn construct in a string literal is done at compile time. You can't build the construct at run time and have it interpreted. That's not how things work.
You could do:
uint32_t c = 0x0001d122;
NSString* s = [[NSString alloc] initWithBytes:&c length:sizeof(c) encoding:NSUTF32LittleEndianStringEncoding];

Related

Can stringEncodingForData:encodingOptions:convertedString:usedLossyConversion: return NSUTF16StringEncoding or NSUTF32StringEncoding?

I'd like to know if calling stringEncodingForData:encodingOptions:convertedString:usedLossyConversion: can return NSUTF16StringEncoding, NSUTF32StringEncoding or any of their variants?
The reason I'm asking is because of this documentation note on cStringUsingEncoding::
Special Considerations
UTF-16 and UTF-32 are not considered to be C string encodings, and should not be used with this method—the results of passing NSUTF16StringEncoding, NSUTF32StringEncoding, or any of their variants are undefined.
So I understand that creating a C string with UTF-16 or UTF-32 is unsupported, but I'm not sure if attempting String Encoding Detection with stringEncodingForData:encodingOptions:convertedString:usedLossyConversion: may return UTF-16 and UTF-32 or not.
An example scenario, (adapted from SSZipArchive.m), may be:
// name is a null-terminated C string built with `fread` from stdio.h:
char *name = (char *)malloc(size_name + 1);
size_t read = fread(name, 1, size_name + 1, file);
name[size_name] = '\0';
// dataName is the data object of name
NSData *dataName = [NSData dataWithBytes:(const void *)name length:sizeof(unsigned char) * size_name];
// stringName is the string object of dataName
NSString *stringName = nil;
NSStringEncoding encoding = [NSString stringEncodingForData:dataName encodingOptions:nil convertedString:&stringName usedLossyConversion:nil];
In the above code, can encoding be NSUTF16StringEncoding, NSUTF32StringEncoding or any of their variants?
Platforms: macOS 10.10+, iOS 8.0+, watchOS 2.0+, tvOS 9.0+.
Yes, if the string is encoded using one of those encodings. The notes about C strings are specific to C strings. An NSString is not a C string, and the method you're describing doesn't work on C strings; it works on arbitrary data that may be encoded in a wide variety of ways.
As an example:
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
#autoreleasepool {
NSData *data = [#"test" dataUsingEncoding:NSUTF16StringEncoding];
NSStringEncoding encoding = [NSString stringEncodingForData:data
encodingOptions:nil
convertedString:nil
usedLossyConversion:nil];
NSLog(#"%ld == %ld", (unsigned long)encoding,
(unsigned long)NSUTF16StringEncoding);
}
return 0;
}
// Output: 10 == 10
This said, in your specific example, if name is really what it says it is, "a null-terminated C string," then it could never be UTF-16, because C strings cannot be encoded in UTF-16. C strings are \0 terminated, and \0 is a very common character in UTF-16. Without seeing more code, however, I would not gamble on whether that comment is accurate.
If your real question here is "given an arbitrary c-string-safe encoding, is it possible that stringEncodingForData: will return a not-c-string-safe encoding," then the answer is "yes, it could, and it's definitely not promised that it won't even if it doesn't today." If you need to prevent that, I recommend using NSStringEncodingDetectionSuggestedEncodingsKey and ...UseOnlySuggestedEncodingsKey to force it to be an encoding you can handle. (You could also use ...DisallowedEncodingsKey to prevent specific multi-byte encodings, but that wouldn't be as robust.)

How to replace a char in an an char array? Xcode

i got the following char array in Objective-C (Xcode):
char *incomeMessage;
NSString *str = [[NSString alloc] initWithBytes:data.bytes length:data.length encoding:NSUTF8StringEncoding];
incomeMessage = [str UTF8String];
NSLog(#"%c", incomeMessage[0]);
NSLog(#"%c", incomeMessage[1]);
NSLog(#"%c", incomeMessage[2]);
NSLog(#"%c", incomeMessage[3]);
NSLog(#"%c", incomeMessage[4]);
NSLog(#"%c", incomeMessage[5]);
For example I get some results like this in console:
"3
2
6
1
8
4"
Now i want to replace the char in incomeMessage[2] by 4:
incomeMessage[2] = '4';
But then it gives me the error:
EXC_BAD_ACCESS
Do you have an idea, how to solve the problem?
According to the reference documentation, UTF8String returns a read-only (const char*) reference to the string data.
The reference material goes on to note:
This C string is a pointer to a structure inside the string object,
which may have a lifetime shorter than the string object and will
certainly not have a longer lifetime. Therefore, you should copy the C
string if it needs to be stored outside of the memory context in which
you use this property.
So I'd suggest following their advice and creating a copy of the array and then performing your modifications against that.
For example: http://ideone.com/mhjwZW
You might have better luck with something like:
NSString* str = [[NSString alloc] initWithBytes:data.bytes length:data.length encoding:NSUTF8StringEncoding];
char* incomeMessage = malloc([str lengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 1);
strcpy(incomeMessage, [str UTF8String]);
//now you can change things
incomeMessage[2] = '4';
//do this when you're done
free(incomeMessage);
Although, is there any particular reason why you want to use a C-string/character array as opposed to an NSMutableString? I think you might find replaceCharactersInRange:withString: a better approach generally. See also: stringByReplacingCharactersInRange:withString:.
i got the following char array in Objective-C (Xcode)
You don't, you know. All you have is a pointer. You have not set aside any actual memory; there is no array there.
incomeMessage = [str UTF8String];
All you've done in that line is repoint the pointer incomeMessage at your string's UTF8String. A string's UTF8String is immutable. Note this passage in the docs:
you should copy the C string if it needs to be stored outside of the memory context in which you use this property.
So basically, if you want to write into an array of char, your first task should be to make an array of char.

Cipher A Message, And Then Decode It in Objective-C

I can't think of a better way to describe it, so here it is.
I'm working on a program, very simply, that you input a message you want encoded, it takes it and makes it into a coded message, such as taking 'easy' and, for example, translating it into 'gcua' (achieved by moving each letter forward two in the alphabet)
Then, the person on the receiving end could stick it into the program and it would bring it back to the original text. I'm obviously thinking something a little more complicated than moving the letters up two or something, but, I digress.
I have some really.. REALLY basic code for this. The problem I'm having is breaking each letter of the message up to apply the encoding, then putting it back together.
I'm not asking for the program, I'm more so asking of how to get up to the point of being able to encode the message. (ex. putting the string into a format possible to encode). It isn't intended to be anything elaborate, just very simple, straight to the point.
Here's a basic outline (Thanks to those who helped troubleshoot):
int main (int argc, const char * argv[]) {
#autoreleasepool {
char choice, yes = 'y', no = 'n', buf[1024];
NSString *plainText, *encrypted, *decoded;
NSLog(#"Encode (Y) or Decode (N)");
scanf("%c", &choice);
choice = tolower(choice);
if (choice == yes) {
scanf("%1024s", buf);
plainText = [NSString stringWithCString:buf encoding:NSUTF8StringEncoding];
} else if (choice == no) {
}
}
return 0;
}
%c implies a char* argument, but you are passing char**.
You should make your variables char, not a char*:
char choice, yes = 'y', no = 'n';
It would also make sense to convert choice to lower case before comparing to y and n, because you ask end-users to enter uppercase Y or N
scanf("%c", &choice);
choice = tolower(choice);
EDIT in response to the edit of the question: You cannot use %s to read a value into NSString. You should use char buf[MAX], and limit the length in the scanf:
char buf[1024];
scanf("%1024s", buf);
plainText = [NSString stringWithCString:buf encoding:NSUTF8StringEncoding];
The %s specification to scanf tells it to read into an array of char that you have already allocated. But you are passing a nil pointer to NSString instead.
Try something like this:
NSData *data = [[NSFileHandle fileHandleWithStandardInput] readDataToEndOfFile];
plainText = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

Translating C to Obj-C file reading code

I have this file which I need to read the first bytes to check the information.
I don't need to load the whole file, only the beginning..
The code in C is, more or less, what follows. It is a big code, so I just wrote the basic functionality here.
Now I want to make it 100% Objective-C, but I cannot find a way to do it properly.
FILE *f;
char *buf;
f = fopen ("/Users/foo/Desktop/theFile.fil", "rb");
if(f) {
fseek(f , 0 , SEEK_END);
size = ftell(f);
rewind (f);
buf = (char*) malloc (sizeof(char)*size);
switch( ntohl(*(uint32 *)buf) ) {
case 0x28BA61CE:
case 0x28BA4E50:
NSLog(#"Message");
break;
}
fclose(f);
free (buf);
The most close I got to this is what follows:
NSData *test = [[NSData alloc] initWithContentsOfFile:filePath];
This gets me all the binary, but anyway, I got stuck. Better try to start all over..
Any help appreciated!
Well, valid C code is valid Objective-C code. So this is already in Objective-C.
What's your actual goal? What are you trying to do with the file? Is there a reason you can't use NSData?
C code is already Obj-C. It's perfectly reasonable to just use what you're already doing. But if you're dead-set on using Obj-C objects to perform this, you want to take a look at NSInputStream.
The most close I got to this is what follows:
NSData *test = [[NSData alloc] initWithContentsOfFile:filePath];
This gets me all the binary, but anyway, I got stuck.
It's not clear where you're stuck, because that's the (simplest) correct way to read a file in one big slurp in Cocoa. You've successfully read the file; there's nothing more to do for that.
If you're looking to proceed to the switch statement, the pointer to the bytes that it read is [test bytes]. That's the pointer that you will want to assign to buf. See the NSData documentation.
Well.. I sorted that out.. And did what follows.
Cheers and thanks for the help!
NSString *filePath = [[NSString alloc] initWithFormat:#"/Users/foo/Desktop/theFile.fil"];
NSData *data = [NSData dataWithContentsOfFile:filePath];
NSUInteger len = [data length];
Byte *byteData = (Byte*)malloc(len);
memcpy(byteData, [data bytes], len);
NSNumber *size = [[NSNumber alloc] initWithUnsignedLong:len/2^20];
NSLog(#"%#", size);
switch( ntohl(*(uint32 *)byteData) ) {
case 0x28BA61CE:
case 0x28BA4E50:
NSLog(#"Message");
break;
}
[size release];
[filePath release];

How to convert NSString to C string?

I know that this question is a possible duplicate, but even after looking at some Google tutorials and questions even on this forum none of them gives me a decent answer about this subject.
I have:
NSString *str = #"text";
And I would like to do something like:
char cstring [512] = str;
(this only shows what I want to do, after looking at Apple's NSString Class Ref I didn't even think about using it).
Up to now I have:
char command [512] = [[NSString stringWithFormat:#"text"] cStringUsingEncoding:NSUTF8StringEncoding];
Still, with that I get errors.
Any solution?
try const char *command = [str UTF8String];
A c string is returned as a pointer, not as an array of characters. To use it, you can change your variable to a pointer.
const char *command = [theString cStringUsingEncoding:NSUTF8StringEncoding];
Since you want the UTF8 encoding, you can use the UTF8String convenience method.
const char *command = [theString UTF8String];
If you need the data to be stored in a character array, you can use the getCString:maxLength:encoding: method, passing the array as the buffer. This will allow you to store the string directly to the buffer, and will tell you if the buffer is too small.
char command[512];
if(![theString getCString:command maxLength:sizeof(command)/sizeof(*command) encoding:NSUTF8StringEncoding]) {
NSLog(#"Command buffer too small");
}