NSDictionary+FBUtf8SafeDictionary.m 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. /**
  2. * Copyright (c) 2015-present, Facebook, Inc.
  3. * All rights reserved.
  4. *
  5. * This source code is licensed under the BSD-style license found in the
  6. * LICENSE file in the root directory of this source tree. An additional grant
  7. * of patent rights can be found in the PATENTS file in the same directory.
  8. */
  9. #import "NSDictionary+FBUtf8SafeDictionary.h"
  10. const unichar REPLACER = 0xfffd;
  11. @implementation NSString (FBUtf8SafeString)
  12. - (instancetype)fb_utf8SafeStringWithReplacement:(unichar)replacement
  13. {
  14. if ([self canBeConvertedToEncoding:NSUTF8StringEncoding]) {
  15. return self;
  16. }
  17. NSData *data = [self dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
  18. NSString *convertedString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
  19. NSMutableString *result = [NSMutableString string];
  20. NSString *replacementStr = [NSString stringWithCharacters:&replacement length:1];
  21. NSUInteger originalIdx = 0;
  22. NSUInteger convertedIdx = 0;
  23. while (originalIdx < [self length] && convertedIdx < [convertedString length]) {
  24. unichar originalChar = [self characterAtIndex:originalIdx];
  25. unichar convertedChar = [convertedString characterAtIndex:convertedIdx];
  26. if (originalChar == convertedChar) {
  27. [result appendString:[NSString stringWithCharacters:&originalChar length:1]];
  28. originalIdx++;
  29. convertedIdx++;
  30. continue;
  31. }
  32. while (originalChar != convertedChar && originalIdx < [self length]) {
  33. [result appendString:replacementStr];
  34. originalChar = [self characterAtIndex:++originalIdx];
  35. }
  36. }
  37. return result.copy;
  38. }
  39. @end
  40. @implementation NSArray (FBUtf8SafeArray)
  41. - (instancetype)fb_utf8SafeArray
  42. {
  43. NSMutableArray *result = [NSMutableArray array];
  44. for (id item in self) {
  45. if ([item isKindOfClass:NSString.class]) {
  46. [result addObject:[(NSString *)item fb_utf8SafeStringWithReplacement:REPLACER]];
  47. } else if ([item isKindOfClass:NSDictionary.class]) {
  48. [result addObject:[(NSDictionary *)item fb_utf8SafeDictionary]];
  49. } else if ([item isKindOfClass:NSArray.class]) {
  50. [result addObject:[(NSArray *)item fb_utf8SafeArray]];
  51. } else {
  52. [result addObject:item];
  53. }
  54. }
  55. return result.copy;
  56. }
  57. @end
  58. @implementation NSDictionary (FBUtf8SafeDictionary)
  59. - (instancetype)fb_utf8SafeDictionary
  60. {
  61. NSMutableDictionary *result = [self mutableCopy];
  62. for (id key in self) {
  63. id value = result[key];
  64. if ([value isKindOfClass:NSString.class]) {
  65. result[key] = [(NSString *)value fb_utf8SafeStringWithReplacement:REPLACER];
  66. } else if ([value isKindOfClass:NSArray.class]) {
  67. result[key] = [(NSArray *)value fb_utf8SafeArray];
  68. } else if ([value isKindOfClass:NSDictionary.class]) {
  69. result[key] = [(NSDictionary *)value fb_utf8SafeDictionary];
  70. }
  71. }
  72. return result.copy;
  73. }
  74. @end