1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
|
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "base/apple/scoped_objc_class_swizzler.h"
#include <string.h>
#include "base/check_op.h"
#include "base/compiler_specific.h"
namespace base::apple {
ScopedObjCClassSwizzler::ScopedObjCClassSwizzler(Class target,
Class source,
SEL selector)
: old_selector_impl_(nullptr), new_selector_impl_(nullptr) {
Init(target, source, selector, selector);
}
ScopedObjCClassSwizzler::ScopedObjCClassSwizzler(Class target,
SEL original,
SEL alternate)
: old_selector_impl_(nullptr), new_selector_impl_(nullptr) {
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() const {
// 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, UNSAFE_TODO(strcmp(old_types, new_types)));
if (!old_types || !new_types || UNSAFE_TODO(strcmp(old_types, new_types))) {
old_selector_impl_ = new_selector_impl_ = nullptr;
return;
}
method_exchangeImplementations(old_selector_impl_, new_selector_impl_);
}
} // namespace base::apple
|