Index: base/mac/scoped_objc_class_swizzler.mm |
diff --git a/base/mac/scoped_objc_class_swizzler.mm b/base/mac/scoped_objc_class_swizzler.mm |
new file mode 100644 |
index 0000000000000000000000000000000000000000..20e5c569ae49696b0f01ac7d621a7be871fd7186 |
--- /dev/null |
+++ b/base/mac/scoped_objc_class_swizzler.mm |
@@ -0,0 +1,71 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#import "base/mac/scoped_objc_class_swizzler.h" |
+ |
+#include <string.h> |
+ |
+#include "base/logging.h" |
+ |
+namespace base { |
+namespace mac { |
+ |
+ScopedObjCClassSwizzler::ScopedObjCClassSwizzler(Class target, |
+ Class source, |
+ SEL selector) |
+ : old_selector_impl_(NULL), new_selector_impl_(NULL) { |
+ Init(target, source, selector, selector); |
+} |
+ |
+ScopedObjCClassSwizzler::ScopedObjCClassSwizzler(Class target, |
+ SEL original, |
+ SEL alternate) |
+ : old_selector_impl_(NULL), new_selector_impl_(NULL) { |
+ Init(target, target, original, alternate); |
+} |
+ |
+ScopedObjCClassSwizzler::~ScopedObjCClassSwizzler() { |
+ if (old_selector_impl_ && new_selector_impl_) |
+ method_exchangeImplementations(old_selector_impl_, new_selector_impl_); |
+} |
+ |
+IMP ScopedObjCClassSwizzler::GetOriginalImplementation() { |
+ // Note that while the swizzle is in effect the "new" method is actually |
+ // pointing to the original implementation, since they have been swapped. |
+ return method_getImplementation(new_selector_impl_); |
+} |
+ |
+void ScopedObjCClassSwizzler::Init(Class target, |
+ Class source, |
+ SEL original, |
+ SEL alternate) { |
+ old_selector_impl_ = class_getInstanceMethod(target, original); |
+ new_selector_impl_ = class_getInstanceMethod(source, alternate); |
+ if (!old_selector_impl_ && !new_selector_impl_) { |
+ // Try class methods. |
+ old_selector_impl_ = class_getClassMethod(target, original); |
+ new_selector_impl_ = class_getClassMethod(source, alternate); |
+ } |
+ |
+ DCHECK(old_selector_impl_); |
+ DCHECK(new_selector_impl_); |
+ if (!old_selector_impl_ || !new_selector_impl_) |
+ return; |
+ |
+ // The argument and return types must match exactly. |
+ const char* old_types = method_getTypeEncoding(old_selector_impl_); |
+ const char* new_types = method_getTypeEncoding(new_selector_impl_); |
+ DCHECK(old_types); |
+ DCHECK(new_types); |
+ DCHECK_EQ(0, strcmp(old_types, new_types)); |
+ if (!old_types || !new_types || strcmp(old_types, new_types)) { |
+ old_selector_impl_ = new_selector_impl_ = NULL; |
+ return; |
+ } |
+ |
+ method_exchangeImplementations(old_selector_impl_, new_selector_impl_); |
+} |
+ |
+} // namespace mac |
+} // namespace base |