I am working on an ancient iOS app for a program that runs off VB6. It is passing strings over in a non unicode format including Hebrew characters which once they are parsed are displayed as "àáðø ãøåøé"
I am assuming it is being encoded in Windows Hebrew.
I can't seem to find anything in the apple documentation that explains how to handle this case. And most searches bring up solutions in Swift, no Obj-C. I tried this:
NSString *hebrewPickup = [pickupText stringByApplyingTransform:NSStringTransformLatinToHebrew reverse:false];
But that just gave me this:
"ðø ַ̃øַ̊øֵ"
I am stumped.
EDIT: Based on JosefZ's comment I have tried to encode back using CP1252, but the issue is that CP1255 is not in the list of NSStringEncodings. But seems like it would solve my issue.
NSData *pickupdata = [pickupText dataUsingEncoding:NSWindowsCP1252StringEncoding];
NSString *convPick = [[NSString alloc] initWithData:pickupdata encoding:NSWindowsCP1254StringEncoding];
NSString *hebrewPickup = [convPick stringByApplyingTransform:NSStringTransformLatinToHebrew reverse:false];
Ok, if any poor soul ends up here, this is how I ended up fixing it. I needed to add some Swift into my Obj-C code. (If only I could magically just rebuild the whole project in Swift instead.)
Here is the info on that: https://developer.apple.com/documentation/swift/imported_c_and_objective-c_apis/importing_swift_into_objective-c
Making use of this Swift Package: https://github.com/Cosmo/ISO8859
I added the following code to a new swift file.
#objc class ConvertString: NSObject {
#objc func convertToHebrew(str:String) -> NSString {
let strData = str.data(using: .windowsCP1252);
let bytes: Data = strData!;
if let test = String(bytes, iso8859Encoding: ISO8859.part8) {
return test as NSString;
}
let test = "";
return test as NSString;
}
}
Then in the Obj-C project I was able to call it like so:
ConvertString *stringConverter = [ConvertString new];
NSString *pickupTextFixed = [stringConverter convertToHebrewWithStr:pickupText];
NSString *deliverTextFixed = [stringConverter convertToHebrewWithStr:deliverText];
Related
This is probably simple enough, but Im not a regular iOS dev but have a decent understanding of Obj-C and Xcode however not so much with Swift yet.
I am playing around with a mapping SDK called Skobbler and downloaded both Swift and iOS examples.
The Swift example gives me some useful text/console logs of directions turn by turn however the Obj-C doesn't and having a tough time exposing them.
The Swift example looks like this
let advices: Array<SKRouteAdvice> = SKRoutingService.sharedInstance().routeAdviceListWithDistanceFormat(SKDistanceFormat.Metric) as! Array<SKRouteAdvice>
for advice: SKRouteAdvice in advices
{
let instructions = advice.adviceInstruction
print(instructions)
}
NSArray<SKRouteAdvice *> *advices = [[SKRoutingService sharedInstance] routeAdviceListWIthDistanceFormat:SKDistanceFormat.Metric];
for (SKRouteAdvice *advice in advices)
{
NSLog(#"%#", instructions);
}
NSArray *advices = [[SKRoutingService sharedInstance]routeAdviceListWithDistanceFormat:SKDistanceFormat.Metric];
for (SKRouteAdvice *advice in advices) {
NSLog(#"%#", [advice adviceInstruction]);
}
as! doesn't need translating - the compiler will just believe you (you might want to add an assert for identical behaviour). The print is replaced with NSLog (#"%#", instructions).
the text that caused the crash is the following:
the error occurred at the following line:
let size = CGSize(width: 250, height: DBL_MAX)
let font = UIFont.systemFontOfSize(16.0)
let attributes = [
NSFontAttributeName:font ,
NSParagraphStyleAttributeName: paraStyle
]
var rect = text.boundingRectWithSize(size, options:.UsesLineFragmentOrigin, attributes: attributes, context: nil)
where text variable contains the inputted string
parastyle is declared as follows:
let paraStyle = NSMutableParagraphStyle()
paraStyle.lineBreakMode = NSLineBreakMode.ByWordWrapping
My initial idea is that the system font can't handle these characters and I need to do an NSCharacterSet, but I'm not sure how to either just ban characters that'll crash my app or make it so i can handle this input (ideal). I don't want to ban emojis/emoticons either.
Thanks!
Not an answer but some information and that possibly provids a way code way to avoid it.
Updated to information from The Register:
The problem isn’t with the Arabic characters themselves, but in how the unicode representing them is processed by CoreText, which is a library of software routines to help apps display text on screens.
The bug causes CoreText to access memory that is invalid, which forces the operating system to kill off the currently running program: which could be your text message app, your terminal, or in the case of the notification screen, a core part of the OS.
From Reddit but this may not be completely correct:
It only works when the message has to be abbreviated with ‘…’. This is usually on the lock screen and main menu of Messages.app.
The words effective and power can be anything as long as they’re on two different lines, which forces the Arabic text farther down the message where some of the letters will be replaced with ‘…’
The crash happens when the first dot replaces part of one of the Arabic characters (they require more than one byte to store) Normally there are safety checks to make sure half characters aren’t stored, but this replacement bypasses those checks for whatever reason.
My solution is the next category:
static NSString *const CRASH_STRING = #"\u0963h \u0963 \u0963";
#implementation NSString (CONEffectivePower)
- (BOOL)isDangerousStringForCurrentOS
{
if (IS_IOS_7_OR_LESS || IS_IOS_8_4_OR_HIGHER) {
return NO;
}
return [self containsEffectivePowerText];
}
- (BOOL)containsEffectivePowerText
{
return [self containsString:CRASH_STRING];
}
#end
Filter all characters to have same directionality. Unfortunately, I'm only aware of such API in Java.
Don't even try. This is a bug in the operating system that will be fixed. It's not your problem. If you try to fix it, you are just wasting your time. And you are very likely to introduce bugs - when you say you "sanitise" input that means you cannot handle some perfectly fine input.
The company I work at develops a multiplatform group video chat.
In Crashlytics report we started noticing that some users are "effectively" trolling iOS users using this famous unicode sequence.
We can't just sit and wait for Apple to fix this bug.
So, I've worked on this problem, this is the shortest crashing sequence I got:
// unichar representation
unichar crashChars[8] = {1585, 1611, 32, 2403, 32, 2403, 32, 2403};
// string representation
NSString *crashString = #"\u0631\u064b \u0963 \u0963 \u0963"
So, I decided to filter out all text messages that contains two U+0963 'ॣ' symbols with one symbol between them (hope you are able to decipher this phrase)
My code from NSString+Extensions category.
static const unichar kDangerousSymbol = 2403;
- (BOOL)isDangerousUnicode {
NSUInteger distance = 0;
NSUInteger charactersFound = 0;
for (NSUInteger i = 0; i < self.length; i++) {
unichar character = [self characterAtIndex:i];
if (charactersFound) {
distance++;
}
if (distance > 2) {
charactersFound = 0;
}
if (kDangerousSymbol == character) {
charactersFound++;
}
if (charactersFound > 1 && distance > 0) {
return YES;
}
}
return NO;
}
Lousy Specta test:
SpecBegin(NSStringExtensions)
describe(#"NSString+Extensions", ^{
//....
it(#"should detect dangerous Unicode sequences", ^{
expect([#"\u0963 \u0963" isDangerousUnicode]).to.beTruthy();
expect([#"\u0631\u064b \u0963 \u0963 \u0963" isDangerousUnicode]).to.beTruthy();
expect([#"\u0631\u064b \u0963 \u0963 \u0963" isDangerousUnicode]).to.beFalsy();
});
//....
});
SpecEnd
I'm not sure if it's OK to "discriminate" messages with too many "devanagari vowel sign vocalic ll".
I'm open to corrections, suggestions, criticism :).
I would love to see a better solution to this problem.
For some reason this line of code is crashing on pre iPhone 6 devices:
var friendMatch = newDict.objectForKey("is_match") as Int
The dictionary is generated from JSON that I receive from an endpoint. The JSON looks like this:
"is_match" = 1;
I've also tried:
var friendMatch: NSNumber = newDict.objectForKey("is_match") as NSNumber
And the app still crashes on that line. The crash log is unhelpful.
Any thoughts on why this is working on iPhone 6 and 6+, but not on older devices?
var friendMatch = newDict.objectForKey("is_match") as Int
You should not be casting unconditionally. Cast conditionally instead:
if let friendMatch = newDict.objectForKey("is_match") as? Int {
// ...
}
Now if the cast fails you won't crash.
Could you add some more code? It could be that you are not properly decoding the NSData JSON into a dictionary.
Also, use literal syntax, it is cleaner and easier to read.
newDict["is_match"]
If you are reading the JSON fine, then before casting it to anything, try adding a println to see the value inside it, or breakpoints.
println(newDict["is_match"])
Post Discussion edit:
Try:
var newInt = newDict["is_match"].toInt()
I've been stuck with this problem for hours. I tried writing the class in Objective C, Swift, logging the output of the Array (Which is not nil and has no problems at all if logged), even using NSURL to use writeToFile. I cleaned the project and tested on iOS Simulator and on an iOS Device. This exact code works in a different class, but not in this one. Any help would be much appreciated...
let paths = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)
var docs: String = paths[0] as String
let responseData = docs.stringByAppendingPathComponent("myOwnData.plist")
let test = self.tweetsArray!.writeToFile(responseData, atomically: true)
println(test)
I tested the code with let array: NSArray = ["abc"] added at the beginning, and it worked.
OP solved it by adding self.tweetsArray = NSArray() at the top.
I have a number of strings that have internet links embedded within them that worked fine until I applied NSLocalizedString to each of them for a localization in Spanish. Now the links in the strings are not recognized or operate as such in my app either for English (the base language) or Spanish.
I have been unable to determine why this is happening and haven't found any reference to this issue online. Is there some special formatting that I have to do to the URL part of my strings when using NSLocalizedString that I didn't have to when using NSString? I would greatly appreciate any help that anyone could offer with a solution to my issue?
Here is an example of one of my NSLocalizedStrings and its use in forming the contentString:
aboutContentText = NSLocalizedString(#"\"The Visitation\", by 1737, Jerónimo Ezquerra (1660-1737), http://commons.wikimedia.org/wiki/File:Jerónimo_Ezquerra_Visitation.jpg\n", #"aboutContentText-2nd Joyful Mystery");
contentString = [[NSMutableAttributedString alloc]
initWithString: aboutContentText attributes: contentAttributes2];
Don't localize the URLs, localize only the text:
NSString *preamble = NSLocalizedString(#"\"The Visitation\", by 1737, Jerónimo Ezquerra (1660-1737)", #"preamble aboutContentText-2nd Joyful Mystery");
NSString *urlString = #"http://commons.wikimedia.org/wiki/File:Jerónimo_Ezquerra_Visitation.jpg";
NSString *aboutContentText = [NSString stringWithFormat:#"%#, %#\n", preamble, urlString];
NSLog(#"aboutContentText: %#", aboutContentText);
NSLog output:
aboutContentText: "The Visitation", by 1737, Jerónimo Ezquerra (1660-1737), http://commons.wikimedia.org/wiki/File:Jerónimo_Ezquerra_Visitation.jpg