'NSString initWithFormat' can't print chinese correctly - ios

std::string title = "中文";
NSString* str = [[NSString alloc] initWithFormat: #"test 中文 %s", title.c_str()]; // test 中文 ‰∏≠Êñá
I will get messy code. Can't I use %s to insert chinese in iOS ? How can I get correct result.
The real scene is the nativeLog.
void nativeLog2(std::string format, va_list args)
{
NSString* str = [[NSString alloc] initWithFormat: [[NSString alloc] initWithUTF8String:format.c_str()] arguments:args];
NSLog(str);
}
void nativeLog(std::string format, ...)
{
va_list args;
va_start(args, format);
nativeLog2(format, args);
va_end(args);
}
std::string title = "中文";
nativeLog("test 中文 %s", title.c_str()); // test 中文 ‰∏≠Êñá

Related

iOS Obj-C convert byte array to plist to string

Argh, I'm going nuts.
I've got the following function which I am trying to log with a custom logger
CFWriteStreamWrite(CFWriteStreamRef stream, const UInt8 *buffer,
CFIndex bufferLength) {
NSData *data = [[NSData alloc] initWithBytes:buffer length: bufferLength];
NSString *errorDesc = nil;
NSPropertyListFormat format;
NSString * str = (NSString*)[NSPropertyListSerialization
propertyListFromData:data
mutabilityOption:NSPropertyListMutableContainersAndLeaves
format:&format
errorDescription:&errorDesc];
custom_log(CF, "CFURLCreateWithString: %s", str);
}
When I use my custom logger I get rubbish output
CFURLCreateWithString: < °3€
But when using NSLog, everything works fine,
Feb 10 00:36:39: {
bundleID = "com.test.testapp";
pid = 2852;
}
Custom Logger
EXPORT void custom_log(unsigned int facility, const char *msg, ...) {
if (minLogLevel <= INFO) {
char *msgBuffer;
va_list args;
va_start(args, msg);
vasprintf(&msgBuffer, msg, args);
va_end(args);
dispatch_async(logQueue, ^{
write(facility, INFO, msgBuffer);
});
}
}
Please tell me where I'm going wrong, I have spent the past 3 hours trying to convert to different data types. No luck.
Also, is it possible to get the output from NSLog into a string and then I'll just pass it to my logger instead?
One of the problems that you might be experiencing here is that NSString is not the same as the c_str that your vasprintf method is likely expecting to substitute for %s.
To compound this issue, I'm pretty sure you can't directly convert NSPropertyListSerialization to NSString, though I didn't test it myself. You might be looking for such an alternative instead:
NSString * str = [NSString stringWithFormat:#"%#", [NSPropertyListSerialization
propertyListFromData:data
mutabilityOption:NSPropertyListMutableContainersAndLeaves
format:&format
errorDescription:&errorDesc]];
custom_log(CF, "CFURLCreateWithString: %s", [str UTF8String]);
Of course, since you're already compositing a string, why not just do it all in the same place?
NSString * str = [NSString stringWithFormat:#"CFURLCreateWithString: %#", [NSPropertyListSerialization
propertyListFromData:data
mutabilityOption:NSPropertyListMutableContainersAndLeaves
format:&format
errorDescription:&errorDesc]];
custom_log(CF, [str UTF8String]);
As a fun side project, you might consider doing something like this in your main.mm. Replace stderr with stdout if you want more than just error stuff:
#if COPY_NSLOG_TO_CUSTOM
typedef int (*MyStdWriter)(void *, const char *, int);
static MyStdWriter _oldStdWrite;
int __customStderrWrite(void *inFD, const char *buffer, int size) {
if (minLogLevel <= INFO) {
// write to your custom stream here.
}
return _oldStdWrite(inFD, buffer, size);
}
void __copyNSLogToCustom(void) {
_oldStdWrite = stderr->_write;
stderr->_write = __customStderrWrite;
}
#endif
int main(int argc, char *argv[]) {
#if COPY_NSLOG_TO_CUSTOM
__copyNSLogToCustom();
#endif
// ...
}

exc_bad_instruction exc_i386_invop when i sending va_list to my other function

I am developing for iphone.
I have log function, and this one works great
void _log_p(NSString* format, ...)
{
va_list argList;
va_start(argList, format);
NSString* text = [[NSString alloc] initWithFormat:format arguments:argList];
va_end(argList);
}
But when i try to send argList to another function i get exc_bad_instruction exc_i386_invop
void _log(LogLevel level, NSString* format,...)
{
va_list argList;
va_start(argList, format);
NSString* text = [[NSString alloc] initWithFormat:format arguments:argList];
va_end(argList);
}
void _log_p(NSString* format, ...)
{
va_list argList;
va_start(argList, format);
_log(LogLevelPublic, format, argList);
va_end(argList);
}
on the line NSString* text = [[NSString alloc] initWithFormat:format arguments:argList];
What am i doing wrong ?
In general, it is not possible to forward variadic arguments. See: http://c-faq.com/varargs/handoff.html

Store accented word into Sqlite - iOS

I coulnd not find a solution.
I store data into a local SQLITE DB. Everything works except for accented words.
As in the figure.
However, if I try to store accented word by using SqliteManager (Firefox plugin) everything works. In conclusion: when I store accented word by using my app, strange chars appear.
I use the following code to write data (same for read). Basically, all strings are UTF8 encoded.
-(NSInteger)writeData:(NSDictionary* )data table:(NSString* )table
{
sqlite3_stmt *sqlStatement;
NSMutableArray *columns = [[NSMutableArray alloc] init];
NSMutableArray *values = [[NSMutableArray alloc] init];
NSMutableDictionary *temp = [[NSMutableDictionary alloc] initWithDictionary:data];
#try {
assert([data count] != 0);
if ([[data allKeys] count] == 0) return 1;
[temp removeObjectForKey:#"id"];
[columns addObjectsFromArray:[temp allKeys]];
NSString *cols = [columns componentsJoinedByString:#","];
NSMutableString *colNames = [[NSMutableString alloc] initWithString:
[NSString stringWithFormat:#"INSERT INTO %s (",[table UTF8String]]];
[colNames appendString:cols];
[colNames appendString:#")"];
// VALUES FOR INSERT
[values addObjectsFromArray:[temp allValues] ];
NSMutableString *s = [[NSMutableString alloc] init];
for(int i = 0; i < [values count]; i++)
{
[s setString:[NSString stringWithFormat:#"%#",[values objectAtIndex:i]]];
const char* currentValue = [s UTF8String];
[values setObject:[NSString stringWithFormat:#"\"%s\"",currentValue] atIndexedSubscript:i];
}
NSString *vals = [values componentsJoinedByString:#","];
NSMutableString *valNames = [[NSMutableString alloc] initWithString:#" VALUES ("];
[valNames appendString:vals];
[valNames appendString:#")"];
[colNames appendString:valNames];
const char *sql = [colNames UTF8String];
#ifdef DEBUG
NSLog(#"avvDB writeDATA insert string %#",colNames);
#endif
if(sqlite3_prepare(db, sql, -1, &sqlStatement, NULL) != SQLITE_OK)
{
NSLog(#"Problem with prepare statement write %s",sqlite3_errmsg(db));
return 0;
}
if (sqlite3_exec(db, sql, NULL, NULL, NULL) == SQLITE_OK)
{
// NSLog(#"Last id %llu %s",sqlite3_last_insert_rowid(db),sqlite3_errmsg(db));
}
}// end try
#catch(NSException* e)
{
NSLog(#"Eccezione in write %#",[e reason]);
}
#finally {
sqlite3_reset(sqlStatement);
sqlite3_finalize(sqlStatement);
sqlStatement = nil;
return sqlite3_last_insert_rowid(db);
}
}
The %s operator does not support unicode characters. As the String Format Specifiers of the String Programming Guide says, it is "Null-terminated array of 8-bit unsigned characters."
Frankly, for other reasons, you shouldn't be using stringWithFormat anyway (what if one of the strings had a quotation mark in it ... your SQL statement would fail; you're even exposed to SQL injection attacks). You should be using a ? placeholder instead (with no quotation marks), and then call sqlite3_bind_text for each of the parameters you want to bind to the respective question mark (note, sqlite3_bind_xxx functions use a 1-based index, unlike sqlite3_column_xxx which use a 0-based index).

Encrypt data with RSA public key not giving expected results

I'm trying to encrypt data with an RSA public key using openssl.
I have the Java implementation of what I need to do in Objective-C.
Here's what I have so far:
- (RSA *)rsaFromExponent:(NSString *)exponent modulus:(NSString *)modulus
{
RSA *rsa_pub = RSA_new();
const char *N = [modulus UTF8String];
const char *E = [exponent UTF8String];
if (!BN_hex2bn(&rsa_pub->n, N))
{
// TODO
}
printf("N: %s\n", N);
printf("n: %s\n", BN_bn2dec(rsa_pub->n));
if (!BN_hex2bn(&rsa_pub->e, E))
{
// TODO
}
printf("E: %s\n", E);
printf("e: %s\n", BN_bn2dec(rsa_pub->e));
return rsa_pub;
}
- (NSString *)cleanString:(NSString *)input
{
NSString *output = input;
output = [output stringByReplacingOccurrencesOfString:#"<" withString:#""];
output = [output stringByReplacingOccurrencesOfString:#">" withString:#""];
output = [output stringByReplacingOccurrencesOfString:#" " withString:#""];
return output;
}
// main code
NSString *exponentB64 = #"AQAB";
NSString *modulusB64 = #"AKDbnFpblq7LHfWDfGTR48B34MKaHQosMwVu8cCc6fH2pZ8Ypx/OgzG6VJlKHXeELtlo5tddBSJpwnkEQdvkkmwuOpCkacTTLon6EHqX4WwFW+waqHxmj419SxiDDlo9tsbg7vfFIMpKyGzq1zvTAN3TroW+MxogZfZD3/N6dNTzvBoXe/Ca1e/zVwYXKbiegLMjNwsruz/WvuMiNKTK4U3GEmb0gIODd1shAH10ube8Nrz/e1u9kr25VQ+7kZAFjnkPTp2AvNGYHQt35m1TRMQhTylVwTZqFkHC/jMt7WxuS8q7ftjM828wa1fEWTgWYrdkzmqZSK5CHBYSys/N1Ws=";
// 1. decode base64 (http://projectswithlove.com/projects/NSData_Base64.zip)
NSData *exponent = [NSData dataFromBase64String:exponentB64];
NSData *modulus = [NSData dataFromBase64String:modulusB64];
NSString *exponentHex = [self cleanString:[exponent description]];
NSString *modulusHex = [self cleanString:[modulus description]];
// 2. create RSA public key
RSA *rsa_pub = [self rsaFromExponent:exponentHex modulus:modulusHex];
NSString *user = #"TEST";
// 3. encode base 64
NSData *userData = [user dataUsingEncoding:NSASCIIStringEncoding];
NSString *userB64String = [userData base64EncodedString];
// 4. encrypt
const unsigned char *from = (const unsigned char *)[userB64String cStringUsingEncoding:NSASCIIStringEncoding];
int flen = strlen((const char *)from);
unsigned char *to = (unsigned char *) malloc(RSA_size(rsa_pub));
int padding = RSA_PKCS1_PADDING;
int result = RSA_public_encrypt(flen, from, to, rsa_pub, padding);
if (-1 == result)
{
NSLog(#"WAT?");
}
else
{
NSLog(#"from: %s", from); // echo VEVTVA==
NSLog(#"to: %s", to); // echo something strange with characters like: ~™Ÿû—...
}
// 5. encode base 64
NSString *cipherString = [NSString stringWithCString:(const char *)to
encoding:NSASCIIStringEncoding];
NSData *cipherData = [cipherString dataUsingEncoding:NSASCIIStringEncoding];
NSString *cipherDataB64 = [cipherData base64EncodedString];
NSLog(#"user encrypted b64: %#", cipherDataB64); // echo null :-(
In Java, I have no problem to base64 encode the encrypted data.
I'm sure I'm doing something wrong but I don't know where because it's not something I do everyday.
Or if you know another way to do this with iOS frameworks like Security.framework.
Thanks in advance.
Someone else helped me figure it out. I don't know why but I was assuming that the output buffer from RSA_public_encrypt function would be an ascii string. Though it's just bytes as the documentation says too. The char * type often leads me to think it's gonna store a string (it's so wrong I think it's the last time I make this kind of error).
So from step 5:
// 5. encode base 64
NSData *cipherData = [NSData dataWithBytes:(const void *)to length:result];
NSString *cipherDataB64 = [cipherData base64EncodedString];
NSLog(#"user encrypted b64: %#", cipherDataB64); // now echo the expected value

Converting an Sha256 hashed value into NSString

I have a requirement to integrate with a web service that serves as a login. The hash needs to be generated on the client. I am able to produce the correct hash as NSMutableData, but then I need to convert it to a string, without the spaces or brackets produced when the NSMutableData object is rendered as a string in the output console. I have read several posts, all seeming to say the same thing:
NSString *newstring = [[NSString alloc] initWithDSata:dataToConvert encoding:NSUTF8StringEncoding];
Unfortunately, this doesnt work for me. Using NSUTF8StringEncoding returns null. NSASCIIStringEncoding is even worse.
Here is my code:
NSString *password = [NSString stringWithFormat:#"%#%#", kPrefix, [self.txtPassword text]];
NSLog(#"PLAIN: %#", password);
NSData *data = [password dataUsingEncoding:NSASCIIStringEncoding];
NSMutableData *sha256Out = [NSMutableData dataWithLength:CC_SHA256_DIGEST_LENGTH];
CC_SHA256(data.bytes, data.length, sha256Out.mutableBytes);
NSString *preppedPassword = [[NSString alloc] initWithData:sha256Out encoding:NSASCIIStringEncoding];
NSLog(#"HASH: %#\n", preppedPassword);
How can I convert the NSMutableData to string?
My problem is that I need to from this
<7e8df5b3 17c99263 e4fe6220 bb75b798 4a41de45 44464ba8 06266397 f165742e>
to this
7e8df5b317c99263e4fe6220bb75b7984a41de4544464ba806266397f165742e
See How to convert an NSData into an NSString Hex string?
I use a slightly modified version myself:
#implementation NSData (Hex)
- (NSString *)hexRepresentationWithSpaces:(BOOL)spaces uppercase:(BOOL)uppercase {
const unsigned char *bytes = (const unsigned char *)[self bytes];
NSUInteger nbBytes = [self length];
// If spaces is true, insert a space every this many input bytes (twice this many output characters).
static const NSUInteger spaceEveryThisManyBytes = 4UL;
// If spaces is true, insert a line-break instead of a space every this many spaces.
static const NSUInteger lineBreakEveryThisManySpaces = 4UL;
const NSUInteger lineBreakEveryThisManyBytes = spaceEveryThisManyBytes * lineBreakEveryThisManySpaces;
NSUInteger strLen = 2 * nbBytes + (spaces ? nbBytes / spaceEveryThisManyBytes : 0);
NSMutableString *hex = [[NSMutableString alloc] initWithCapacity:strLen];
for (NSUInteger i = 0; i < nbBytes; ) {
if (uppercase) {
[hex appendFormat:#"%02X", bytes[i]];
} else {
[hex appendFormat:#"%02x", bytes[i]];
}
// We need to increment here so that the every-n-bytes computations are right.
++i;
if (spaces) {
if (i % lineBreakEveryThisManyBytes == 0) {
[hex appendString:#"\n"];
} else if (i % spaceEveryThisManyBytes == 0) {
[hex appendString:#" "];
}
}
}
return hex;
}
#end

Resources