1// Copyright 2014 The Chromium Authors 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#import "base/mac/scoped_objc_class_swizzler.h" 6 7#include <string.h> 8 9#include "base/check_op.h" 10 11namespace base::mac { 12 13ScopedObjCClassSwizzler::ScopedObjCClassSwizzler(Class target, 14 Class source, 15 SEL selector) 16 : old_selector_impl_(NULL), new_selector_impl_(NULL) { 17 Init(target, source, selector, selector); 18} 19 20ScopedObjCClassSwizzler::ScopedObjCClassSwizzler(Class target, 21 SEL original, 22 SEL alternate) 23 : old_selector_impl_(NULL), new_selector_impl_(NULL) { 24 Init(target, target, original, alternate); 25} 26 27ScopedObjCClassSwizzler::~ScopedObjCClassSwizzler() { 28 if (old_selector_impl_ && new_selector_impl_) 29 method_exchangeImplementations(old_selector_impl_, new_selector_impl_); 30} 31 32IMP ScopedObjCClassSwizzler::GetOriginalImplementation() const { 33 // Note that while the swizzle is in effect the "new" method is actually 34 // pointing to the original implementation, since they have been swapped. 35 return method_getImplementation(new_selector_impl_); 36} 37 38void ScopedObjCClassSwizzler::Init(Class target, 39 Class source, 40 SEL original, 41 SEL alternate) { 42 old_selector_impl_ = class_getInstanceMethod(target, original); 43 new_selector_impl_ = class_getInstanceMethod(source, alternate); 44 if (!old_selector_impl_ && !new_selector_impl_) { 45 // Try class methods. 46 old_selector_impl_ = class_getClassMethod(target, original); 47 new_selector_impl_ = class_getClassMethod(source, alternate); 48 } 49 50 DCHECK(old_selector_impl_); 51 DCHECK(new_selector_impl_); 52 if (!old_selector_impl_ || !new_selector_impl_) 53 return; 54 55 // The argument and return types must match exactly. 56 const char* old_types = method_getTypeEncoding(old_selector_impl_); 57 const char* new_types = method_getTypeEncoding(new_selector_impl_); 58 DCHECK(old_types); 59 DCHECK(new_types); 60 DCHECK_EQ(0, strcmp(old_types, new_types)); 61 if (!old_types || !new_types || strcmp(old_types, new_types)) { 62 old_selector_impl_ = new_selector_impl_ = NULL; 63 return; 64 } 65 66 method_exchangeImplementations(old_selector_impl_, new_selector_impl_); 67} 68 69} // namespace base::mac 70