/core/externals/update-engine/externals/google-toolbox-for-mac/Foundation/GTMObjC2Runtime.m

http://macfuse.googlecode.com/ · Objective C · 163 lines · 101 code · 20 blank · 42 comment · 31 complexity · 42e09ce87bcba77abba15d303e4ddd83 MD5 · raw file

  1. //
  2. // GTMObjC2Runtime.m
  3. //
  4. // Copyright 2007-2008 Google Inc.
  5. //
  6. // Licensed under the Apache License, Version 2.0 (the "License"); you may not
  7. // use this file except in compliance with the License. You may obtain a copy
  8. // of the License at
  9. //
  10. // http://www.apache.org/licenses/LICENSE-2.0
  11. //
  12. // Unless required by applicable law or agreed to in writing, software
  13. // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  14. // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  15. // License for the specific language governing permissions and limitations under
  16. // the License.
  17. //
  18. #import "GTMObjC2Runtime.h"
  19. #if GTM_MACOS_SDK && (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5)
  20. #import <stdlib.h>
  21. #import <string.h>
  22. Class object_getClass(id obj) {
  23. if (!obj) return NULL;
  24. return obj->isa;
  25. }
  26. const char *class_getName(Class cls) {
  27. if (!cls) return "nil";
  28. return cls->name;
  29. }
  30. BOOL class_conformsToProtocol(Class cls, Protocol *protocol) {
  31. // We intentionally don't check cls as it crashes on Leopard so we want
  32. // to crash on Tiger as well.
  33. // I logged
  34. // Radar 5572978 class_conformsToProtocol crashes when arg1 is passed as nil
  35. // because it seems odd that this API won't accept nil for cls considering
  36. // all the other apis will accept nil args.
  37. // If this does get fixed, remember to enable the unit tests.
  38. if (!protocol) return NO;
  39. struct objc_protocol_list *protos;
  40. for (protos = cls->protocols; protos != NULL; protos = protos->next) {
  41. for (long i = 0; i < protos->count; i++) {
  42. if ([protos->list[i] conformsTo:protocol]) {
  43. return YES;
  44. }
  45. }
  46. }
  47. return NO;
  48. }
  49. Class class_getSuperclass(Class cls) {
  50. if (!cls) return NULL;
  51. return cls->super_class;
  52. }
  53. BOOL class_respondsToSelector(Class cls, SEL sel) {
  54. return class_getInstanceMethod(cls, sel) != nil;
  55. }
  56. Method *class_copyMethodList(Class cls, unsigned int *outCount) {
  57. if (!cls) return NULL;
  58. unsigned int count = 0;
  59. void *iterator = NULL;
  60. struct objc_method_list *mlist;
  61. Method *methods = NULL;
  62. if (outCount) *outCount = 0;
  63. while ( (mlist = class_nextMethodList(cls, &iterator)) ) {
  64. if (mlist->method_count == 0) continue;
  65. methods = (Method *)realloc(methods,
  66. sizeof(Method) * (count + mlist->method_count + 1));
  67. if (!methods) {
  68. //Memory alloc failed, so what can we do?
  69. return NULL; // COV_NF_LINE
  70. }
  71. for (int i = 0; i < mlist->method_count; i++) {
  72. methods[i + count] = &mlist->method_list[i];
  73. }
  74. count += mlist->method_count;
  75. }
  76. // List must be NULL terminated
  77. if (methods) {
  78. methods[count] = NULL;
  79. }
  80. if (outCount) *outCount = count;
  81. return methods;
  82. }
  83. SEL method_getName(Method method) {
  84. if (!method) return NULL;
  85. return method->method_name;
  86. }
  87. IMP method_getImplementation(Method method) {
  88. if (!method) return NULL;
  89. return method->method_imp;
  90. }
  91. IMP method_setImplementation(Method method, IMP imp) {
  92. // We intentionally don't test method for nil.
  93. // Leopard fails here, so should we.
  94. // I logged this as Radar:
  95. // 5572981 method_setImplementation crashes if you pass nil for the
  96. // method arg (arg 1)
  97. // because it seems odd that this API won't accept nil for method considering
  98. // all the other apis will accept nil args.
  99. // If this does get fixed, remember to enable the unit tests.
  100. // This method works differently on SnowLeopard than
  101. // on Leopard. If you pass in a nil for IMP on SnowLeopard
  102. // it doesn't change anything. On Leopard it will. Since
  103. // attempting to change a sel to nil is probably an error
  104. // we follow the SnowLeopard way of doing things.
  105. IMP oldImp = NULL;
  106. if (imp) {
  107. oldImp = method->method_imp;
  108. method->method_imp = imp;
  109. }
  110. return oldImp;
  111. }
  112. void method_exchangeImplementations(Method m1, Method m2) {
  113. if (m1 == m2) return;
  114. if (!m1 || !m2) return;
  115. IMP imp2 = method_getImplementation(m2);
  116. IMP imp1 = method_setImplementation(m1, imp2);
  117. method_setImplementation(m2, imp1);
  118. }
  119. struct objc_method_description protocol_getMethodDescription(Protocol *p,
  120. SEL aSel,
  121. BOOL isRequiredMethod,
  122. BOOL isInstanceMethod) {
  123. struct objc_method_description *descPtr = NULL;
  124. // No such thing as required in ObjC1.
  125. if (isInstanceMethod) {
  126. descPtr = [p descriptionForInstanceMethod:aSel];
  127. } else {
  128. descPtr = [p descriptionForClassMethod:aSel];
  129. }
  130. struct objc_method_description desc;
  131. if (descPtr) {
  132. desc = *descPtr;
  133. } else {
  134. bzero(&desc, sizeof(desc));
  135. }
  136. return desc;
  137. }
  138. BOOL sel_isEqual(SEL lhs, SEL rhs) {
  139. // Apple (informally) promises this will work in the future:
  140. // http://twitter.com/#!/gparker/status/2400099786
  141. return (lhs == rhs) ? YES : NO;
  142. }
  143. #endif // GTM_MACOS_SDK && (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5)