Bug 1041775 Part 1: Update Chromium sandbox code to commit 9522fad406dd161400daa518075828e47bd47f60. r=jld,aklotz,glandium

--HG--
rename : security/sandbox/chromium/sandbox/linux/sandbox_export.h => security/sandbox/chromium/sandbox/sandbox_export.h
This commit is contained in:
Bob Owen 2014-11-18 13:48:21 +00:00
Родитель 5b771ca01a
Коммит ba0931eb1d
236 изменённых файлов: 7754 добавлений и 6016 удалений

Просмотреть файл

@ -4,7 +4,7 @@
// This file adds defines about the platform we're currently building on.
// Operating System:
// OS_WIN / OS_MACOSX / OS_LINUX / OS_POSIX (MACOSX or LINUX)
// OS_WIN / OS_MACOSX / OS_LINUX / OS_POSIX (MACOSX or LINUX) / OS_NACL
// Compiler:
// COMPILER_MSVC / COMPILER_GCC
// Processor:
@ -19,37 +19,35 @@
#endif
// A set of macros to use for platform detection.
#if defined(ANDROID)
#if defined(__native_client__)
// __native_client__ must be first, so that other OS_ defines are not set.
#define OS_NACL 1
#elif defined(ANDROID)
#define OS_ANDROID 1
#elif defined(__APPLE__)
#define OS_MACOSX 1
#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
#define OS_IOS 1
#endif // defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
#elif defined(__native_client__)
#define OS_NACL 1
#elif defined(__linux__)
#define OS_LINUX 1
// Use TOOLKIT_GTK on linux if TOOLKIT_VIEWS isn't defined.
#if !defined(TOOLKIT_VIEWS) && defined(USE_X11)
#define TOOLKIT_GTK
#endif
// include a system header to pull in features.h for glibc/uclibc macros.
#include <unistd.h>
#if defined(__GLIBC__) && !defined(__UCLIBC__)
// we really are using glibc, not uClibc pretending to be glibc
#define LIBC_GLIBC
#define LIBC_GLIBC 1
#endif
#elif defined(_WIN32)
#define OS_WIN 1
#define TOOLKIT_VIEWS 1
#elif defined(__FreeBSD__)
#define OS_FREEBSD 1
#define TOOLKIT_GTK
#elif defined(__OpenBSD__)
#define OS_OPENBSD 1
#define TOOLKIT_GTK
#elif defined(__sun)
#define OS_SOLARIS 1
#define TOOLKIT_GTK
#elif defined(__QNXNTO__)
#define OS_QNX 1
#else
#error Please add support for your platform in build/build_config.h
#endif
@ -68,7 +66,7 @@
// more specific macro.
#if defined(OS_MACOSX) || defined(OS_LINUX) || defined(OS_FREEBSD) || \
defined(OS_OPENBSD) || defined(OS_SOLARIS) || defined(OS_ANDROID) || \
defined(OS_NACL)
defined(OS_NACL) || defined(OS_QNX)
#define OS_POSIX 1
#endif
@ -106,8 +104,14 @@
#define ARCH_CPU_ARMEL 1
#define ARCH_CPU_32_BITS 1
#define ARCH_CPU_LITTLE_ENDIAN 1
#elif defined(__aarch64__)
#define ARCH_CPU_ARM_FAMILY 1
#define ARCH_CPU_ARM64 1
#define ARCH_CPU_64_BITS 1
#define ARCH_CPU_LITTLE_ENDIAN 1
#elif defined(__pnacl__)
#define ARCH_CPU_32_BITS 1
#define ARCH_CPU_LITTLE_ENDIAN 1
#elif defined(__MIPSEL__)
#define ARCH_CPU_MIPS_FAMILY 1
#define ARCH_CPU_MIPSEL 1
@ -136,12 +140,6 @@
#error Please add support for your compiler in build/build_config.h
#endif
#if defined(__ARMEL__) && !defined(OS_IOS)
#define WCHAR_T_IS_UNSIGNED 1
#elif defined(__MIPSEL__)
#define WCHAR_T_IS_UNSIGNED 0
#endif
#if defined(OS_ANDROID)
// The compiler thinks std::string::const_iterator and "const char*" are
// equivalent types.

Просмотреть файл

@ -0,0 +1,7 @@
Chromium Commit Directory / File (relative to security/sandbox/)
---------------------------------------- ------------------------------------------------
9522fad406dd161400daa518075828e47bd47f60 build
9522fad406dd161400daa518075828e47bd47f60 chromium
8e2be8d727b46e1f6f1694786dc2161b11146bd4 chromium/base/compiler_specific.h
(Note: above is to keep MSVC2010 support.)
9522fad406dd161400daa518075828e47bd47f60 win

Просмотреть файл

@ -28,7 +28,8 @@
#ifndef BASE_ATOMICOPS_H_
#define BASE_ATOMICOPS_H_
#include "base/basictypes.h"
#include <stdint.h>
#include "build/build_config.h"
#if defined(OS_WIN) && defined(ARCH_CPU_64_BITS)
@ -43,7 +44,7 @@
namespace base {
namespace subtle {
typedef int32 Atomic32;
typedef int32_t Atomic32;
#ifdef ARCH_CPU_64_BITS
// We need to be able to go between Atomic64 and AtomicWord implicitly. This
// means Atomic64 and AtomicWord should be the same type on 64-bit.
@ -133,7 +134,7 @@ Atomic64 Acquire_Load(volatile const Atomic64* ptr);
Atomic64 Release_Load(volatile const Atomic64* ptr);
#endif // ARCH_CPU_64_BITS
} // namespace base::subtle
} // namespace subtle
} // namespace base
// Include our platform specific implementation.
@ -145,8 +146,10 @@ Atomic64 Release_Load(volatile const Atomic64* ptr);
#include "base/atomicops_internals_mac.h"
#elif defined(OS_NACL)
#include "base/atomicops_internals_gcc.h"
#elif defined(COMPILER_GCC) && defined(ARCH_CPU_ARM_FAMILY)
#elif defined(COMPILER_GCC) && defined(ARCH_CPU_ARMEL)
#include "base/atomicops_internals_arm_gcc.h"
#elif defined(COMPILER_GCC) && defined(ARCH_CPU_ARM64)
#include "base/atomicops_internals_arm64_gcc.h"
#elif defined(COMPILER_GCC) && defined(ARCH_CPU_X86_FAMILY)
#include "base/atomicops_internals_x86_gcc.h"
#elif defined(COMPILER_GCC) && defined(ARCH_CPU_MIPS_FAMILY)

Просмотреть файл

@ -8,358 +8,168 @@
#ifndef BASE_ATOMICOPS_INTERNALS_TSAN_H_
#define BASE_ATOMICOPS_INTERNALS_TSAN_H_
#include "base/base_export.h"
// This struct is not part of the public API of this module; clients may not
// use it. (However, it's exported via BASE_EXPORT because clients implicitly
// do use it at link time by inlining these functions.)
// Features of this x86. Values may not be correct before main() is run,
// but are set conservatively.
struct AtomicOps_x86CPUFeatureStruct {
bool has_amd_lock_mb_bug; // Processor has AMD memory-barrier bug; do lfence
// after acquire compare-and-swap.
bool has_sse2; // Processor has SSE2.
};
BASE_EXPORT extern struct AtomicOps_x86CPUFeatureStruct
AtomicOps_Internalx86CPUFeatures;
#define ATOMICOPS_COMPILER_BARRIER() __asm__ __volatile__("" : : : "memory")
#include <sanitizer/tsan_interface_atomic.h>
namespace base {
namespace subtle {
#ifndef TSAN_INTERFACE_ATOMIC_H
#define TSAN_INTERFACE_ATOMIC_H
#ifdef __cplusplus
extern "C" {
#endif
typedef char __tsan_atomic8;
typedef short __tsan_atomic16; // NOLINT
typedef int __tsan_atomic32;
typedef long __tsan_atomic64; // NOLINT
#if defined(__SIZEOF_INT128__) \
|| (__clang_major__ * 100 + __clang_minor__ >= 302)
typedef __int128 __tsan_atomic128;
#define __TSAN_HAS_INT128 1
#else
typedef char __tsan_atomic128;
#define __TSAN_HAS_INT128 0
#endif
typedef enum {
__tsan_memory_order_relaxed,
__tsan_memory_order_consume,
__tsan_memory_order_acquire,
__tsan_memory_order_release,
__tsan_memory_order_acq_rel,
__tsan_memory_order_seq_cst,
} __tsan_memory_order;
__tsan_atomic8 __tsan_atomic8_load(const volatile __tsan_atomic8 *a,
__tsan_memory_order mo);
__tsan_atomic16 __tsan_atomic16_load(const volatile __tsan_atomic16 *a,
__tsan_memory_order mo);
__tsan_atomic32 __tsan_atomic32_load(const volatile __tsan_atomic32 *a,
__tsan_memory_order mo);
__tsan_atomic64 __tsan_atomic64_load(const volatile __tsan_atomic64 *a,
__tsan_memory_order mo);
__tsan_atomic128 __tsan_atomic128_load(const volatile __tsan_atomic128 *a,
__tsan_memory_order mo);
void __tsan_atomic8_store(volatile __tsan_atomic8 *a, __tsan_atomic8 v,
__tsan_memory_order mo);
void __tsan_atomic16_store(volatile __tsan_atomic16 *a, __tsan_atomic16 v,
__tsan_memory_order mo);
void __tsan_atomic32_store(volatile __tsan_atomic32 *a, __tsan_atomic32 v,
__tsan_memory_order mo);
void __tsan_atomic64_store(volatile __tsan_atomic64 *a, __tsan_atomic64 v,
__tsan_memory_order mo);
void __tsan_atomic128_store(volatile __tsan_atomic128 *a, __tsan_atomic128 v,
__tsan_memory_order mo);
__tsan_atomic8 __tsan_atomic8_exchange(volatile __tsan_atomic8 *a,
__tsan_atomic8 v, __tsan_memory_order mo);
__tsan_atomic16 __tsan_atomic16_exchange(volatile __tsan_atomic16 *a,
__tsan_atomic16 v, __tsan_memory_order mo);
__tsan_atomic32 __tsan_atomic32_exchange(volatile __tsan_atomic32 *a,
__tsan_atomic32 v, __tsan_memory_order mo);
__tsan_atomic64 __tsan_atomic64_exchange(volatile __tsan_atomic64 *a,
__tsan_atomic64 v, __tsan_memory_order mo);
__tsan_atomic128 __tsan_atomic128_exchange(volatile __tsan_atomic128 *a,
__tsan_atomic128 v, __tsan_memory_order mo);
__tsan_atomic8 __tsan_atomic8_fetch_add(volatile __tsan_atomic8 *a,
__tsan_atomic8 v, __tsan_memory_order mo);
__tsan_atomic16 __tsan_atomic16_fetch_add(volatile __tsan_atomic16 *a,
__tsan_atomic16 v, __tsan_memory_order mo);
__tsan_atomic32 __tsan_atomic32_fetch_add(volatile __tsan_atomic32 *a,
__tsan_atomic32 v, __tsan_memory_order mo);
__tsan_atomic64 __tsan_atomic64_fetch_add(volatile __tsan_atomic64 *a,
__tsan_atomic64 v, __tsan_memory_order mo);
__tsan_atomic128 __tsan_atomic128_fetch_add(volatile __tsan_atomic128 *a,
__tsan_atomic128 v, __tsan_memory_order mo);
__tsan_atomic8 __tsan_atomic8_fetch_and(volatile __tsan_atomic8 *a,
__tsan_atomic8 v, __tsan_memory_order mo);
__tsan_atomic16 __tsan_atomic16_fetch_and(volatile __tsan_atomic16 *a,
__tsan_atomic16 v, __tsan_memory_order mo);
__tsan_atomic32 __tsan_atomic32_fetch_and(volatile __tsan_atomic32 *a,
__tsan_atomic32 v, __tsan_memory_order mo);
__tsan_atomic64 __tsan_atomic64_fetch_and(volatile __tsan_atomic64 *a,
__tsan_atomic64 v, __tsan_memory_order mo);
__tsan_atomic128 __tsan_atomic128_fetch_and(volatile __tsan_atomic128 *a,
__tsan_atomic128 v, __tsan_memory_order mo);
__tsan_atomic8 __tsan_atomic8_fetch_or(volatile __tsan_atomic8 *a,
__tsan_atomic8 v, __tsan_memory_order mo);
__tsan_atomic16 __tsan_atomic16_fetch_or(volatile __tsan_atomic16 *a,
__tsan_atomic16 v, __tsan_memory_order mo);
__tsan_atomic32 __tsan_atomic32_fetch_or(volatile __tsan_atomic32 *a,
__tsan_atomic32 v, __tsan_memory_order mo);
__tsan_atomic64 __tsan_atomic64_fetch_or(volatile __tsan_atomic64 *a,
__tsan_atomic64 v, __tsan_memory_order mo);
__tsan_atomic128 __tsan_atomic128_fetch_or(volatile __tsan_atomic128 *a,
__tsan_atomic128 v, __tsan_memory_order mo);
__tsan_atomic8 __tsan_atomic8_fetch_xor(volatile __tsan_atomic8 *a,
__tsan_atomic8 v, __tsan_memory_order mo);
__tsan_atomic16 __tsan_atomic16_fetch_xor(volatile __tsan_atomic16 *a,
__tsan_atomic16 v, __tsan_memory_order mo);
__tsan_atomic32 __tsan_atomic32_fetch_xor(volatile __tsan_atomic32 *a,
__tsan_atomic32 v, __tsan_memory_order mo);
__tsan_atomic64 __tsan_atomic64_fetch_xor(volatile __tsan_atomic64 *a,
__tsan_atomic64 v, __tsan_memory_order mo);
__tsan_atomic128 __tsan_atomic128_fetch_xor(volatile __tsan_atomic128 *a,
__tsan_atomic128 v, __tsan_memory_order mo);
__tsan_atomic8 __tsan_atomic8_fetch_nand(volatile __tsan_atomic8 *a,
__tsan_atomic8 v, __tsan_memory_order mo);
__tsan_atomic16 __tsan_atomic16_fetch_nand(volatile __tsan_atomic16 *a,
__tsan_atomic16 v, __tsan_memory_order mo);
__tsan_atomic32 __tsan_atomic32_fetch_nand(volatile __tsan_atomic32 *a,
__tsan_atomic32 v, __tsan_memory_order mo);
__tsan_atomic64 __tsan_atomic64_fetch_nand(volatile __tsan_atomic64 *a,
__tsan_atomic64 v, __tsan_memory_order mo);
__tsan_atomic128 __tsan_atomic128_fetch_nand(volatile __tsan_atomic128 *a,
__tsan_atomic128 v, __tsan_memory_order mo);
int __tsan_atomic8_compare_exchange_weak(volatile __tsan_atomic8 *a,
__tsan_atomic8 *c, __tsan_atomic8 v, __tsan_memory_order mo,
__tsan_memory_order fail_mo);
int __tsan_atomic16_compare_exchange_weak(volatile __tsan_atomic16 *a,
__tsan_atomic16 *c, __tsan_atomic16 v, __tsan_memory_order mo,
__tsan_memory_order fail_mo);
int __tsan_atomic32_compare_exchange_weak(volatile __tsan_atomic32 *a,
__tsan_atomic32 *c, __tsan_atomic32 v, __tsan_memory_order mo,
__tsan_memory_order fail_mo);
int __tsan_atomic64_compare_exchange_weak(volatile __tsan_atomic64 *a,
__tsan_atomic64 *c, __tsan_atomic64 v, __tsan_memory_order mo,
__tsan_memory_order fail_mo);
int __tsan_atomic128_compare_exchange_weak(volatile __tsan_atomic128 *a,
__tsan_atomic128 *c, __tsan_atomic128 v, __tsan_memory_order mo,
__tsan_memory_order fail_mo);
int __tsan_atomic8_compare_exchange_strong(volatile __tsan_atomic8 *a,
__tsan_atomic8 *c, __tsan_atomic8 v, __tsan_memory_order mo,
__tsan_memory_order fail_mo);
int __tsan_atomic16_compare_exchange_strong(volatile __tsan_atomic16 *a,
__tsan_atomic16 *c, __tsan_atomic16 v, __tsan_memory_order mo,
__tsan_memory_order fail_mo);
int __tsan_atomic32_compare_exchange_strong(volatile __tsan_atomic32 *a,
__tsan_atomic32 *c, __tsan_atomic32 v, __tsan_memory_order mo,
__tsan_memory_order fail_mo);
int __tsan_atomic64_compare_exchange_strong(volatile __tsan_atomic64 *a,
__tsan_atomic64 *c, __tsan_atomic64 v, __tsan_memory_order mo,
__tsan_memory_order fail_mo);
int __tsan_atomic128_compare_exchange_strong(volatile __tsan_atomic128 *a,
__tsan_atomic128 *c, __tsan_atomic128 v, __tsan_memory_order mo,
__tsan_memory_order fail_mo);
__tsan_atomic8 __tsan_atomic8_compare_exchange_val(
volatile __tsan_atomic8 *a, __tsan_atomic8 c, __tsan_atomic8 v,
__tsan_memory_order mo, __tsan_memory_order fail_mo);
__tsan_atomic16 __tsan_atomic16_compare_exchange_val(
volatile __tsan_atomic16 *a, __tsan_atomic16 c, __tsan_atomic16 v,
__tsan_memory_order mo, __tsan_memory_order fail_mo);
__tsan_atomic32 __tsan_atomic32_compare_exchange_val(
volatile __tsan_atomic32 *a, __tsan_atomic32 c, __tsan_atomic32 v,
__tsan_memory_order mo, __tsan_memory_order fail_mo);
__tsan_atomic64 __tsan_atomic64_compare_exchange_val(
volatile __tsan_atomic64 *a, __tsan_atomic64 c, __tsan_atomic64 v,
__tsan_memory_order mo, __tsan_memory_order fail_mo);
__tsan_atomic128 __tsan_atomic128_compare_exchange_val(
volatile __tsan_atomic128 *a, __tsan_atomic128 c, __tsan_atomic128 v,
__tsan_memory_order mo, __tsan_memory_order fail_mo);
void __tsan_atomic_thread_fence(__tsan_memory_order mo);
void __tsan_atomic_signal_fence(__tsan_memory_order mo);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // #ifndef TSAN_INTERFACE_ATOMIC_H
inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32 *ptr,
Atomic32 old_value,
Atomic32 new_value) {
inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
Atomic32 old_value,
Atomic32 new_value) {
Atomic32 cmp = old_value;
__tsan_atomic32_compare_exchange_strong(ptr, &cmp, new_value,
__tsan_memory_order_relaxed, __tsan_memory_order_relaxed);
return cmp;
}
inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32 *ptr,
Atomic32 new_value) {
inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
Atomic32 new_value) {
return __tsan_atomic32_exchange(ptr, new_value,
__tsan_memory_order_relaxed);
}
inline Atomic32 Acquire_AtomicExchange(volatile Atomic32 *ptr,
Atomic32 new_value) {
inline Atomic32 Acquire_AtomicExchange(volatile Atomic32* ptr,
Atomic32 new_value) {
return __tsan_atomic32_exchange(ptr, new_value,
__tsan_memory_order_acquire);
}
inline Atomic32 Release_AtomicExchange(volatile Atomic32 *ptr,
Atomic32 new_value) {
inline Atomic32 Release_AtomicExchange(volatile Atomic32* ptr,
Atomic32 new_value) {
return __tsan_atomic32_exchange(ptr, new_value,
__tsan_memory_order_release);
}
inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32 *ptr,
Atomic32 increment) {
inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
Atomic32 increment) {
return increment + __tsan_atomic32_fetch_add(ptr, increment,
__tsan_memory_order_relaxed);
}
inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32 *ptr,
Atomic32 increment) {
inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
Atomic32 increment) {
return increment + __tsan_atomic32_fetch_add(ptr, increment,
__tsan_memory_order_acq_rel);
}
inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32 *ptr,
Atomic32 old_value,
Atomic32 new_value) {
inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
Atomic32 old_value,
Atomic32 new_value) {
Atomic32 cmp = old_value;
__tsan_atomic32_compare_exchange_strong(ptr, &cmp, new_value,
__tsan_memory_order_acquire, __tsan_memory_order_acquire);
return cmp;
}
inline Atomic32 Release_CompareAndSwap(volatile Atomic32 *ptr,
Atomic32 old_value,
Atomic32 new_value) {
inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
Atomic32 old_value,
Atomic32 new_value) {
Atomic32 cmp = old_value;
__tsan_atomic32_compare_exchange_strong(ptr, &cmp, new_value,
__tsan_memory_order_release, __tsan_memory_order_relaxed);
return cmp;
}
inline void NoBarrier_Store(volatile Atomic32 *ptr, Atomic32 value) {
inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
__tsan_atomic32_store(ptr, value, __tsan_memory_order_relaxed);
}
inline void Acquire_Store(volatile Atomic32 *ptr, Atomic32 value) {
inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
__tsan_atomic32_store(ptr, value, __tsan_memory_order_relaxed);
__tsan_atomic_thread_fence(__tsan_memory_order_seq_cst);
}
inline void Release_Store(volatile Atomic32 *ptr, Atomic32 value) {
inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
__tsan_atomic32_store(ptr, value, __tsan_memory_order_release);
}
inline Atomic32 NoBarrier_Load(volatile const Atomic32 *ptr) {
inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
return __tsan_atomic32_load(ptr, __tsan_memory_order_relaxed);
}
inline Atomic32 Acquire_Load(volatile const Atomic32 *ptr) {
inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
return __tsan_atomic32_load(ptr, __tsan_memory_order_acquire);
}
inline Atomic32 Release_Load(volatile const Atomic32 *ptr) {
inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
__tsan_atomic_thread_fence(__tsan_memory_order_seq_cst);
return __tsan_atomic32_load(ptr, __tsan_memory_order_relaxed);
}
inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64 *ptr,
Atomic64 old_value,
Atomic64 new_value) {
inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
Atomic64 old_value,
Atomic64 new_value) {
Atomic64 cmp = old_value;
__tsan_atomic64_compare_exchange_strong(ptr, &cmp, new_value,
__tsan_memory_order_relaxed, __tsan_memory_order_relaxed);
return cmp;
}
inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64 *ptr,
Atomic64 new_value) {
inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
Atomic64 new_value) {
return __tsan_atomic64_exchange(ptr, new_value, __tsan_memory_order_relaxed);
}
inline Atomic64 Acquire_AtomicExchange(volatile Atomic64 *ptr,
Atomic64 new_value) {
inline Atomic64 Acquire_AtomicExchange(volatile Atomic64* ptr,
Atomic64 new_value) {
return __tsan_atomic64_exchange(ptr, new_value, __tsan_memory_order_acquire);
}
inline Atomic64 Release_AtomicExchange(volatile Atomic64 *ptr,
Atomic64 new_value) {
inline Atomic64 Release_AtomicExchange(volatile Atomic64* ptr,
Atomic64 new_value) {
return __tsan_atomic64_exchange(ptr, new_value, __tsan_memory_order_release);
}
inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64 *ptr,
Atomic64 increment) {
inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
Atomic64 increment) {
return increment + __tsan_atomic64_fetch_add(ptr, increment,
__tsan_memory_order_relaxed);
}
inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64 *ptr,
Atomic64 increment) {
inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
Atomic64 increment) {
return increment + __tsan_atomic64_fetch_add(ptr, increment,
__tsan_memory_order_acq_rel);
}
inline void NoBarrier_Store(volatile Atomic64 *ptr, Atomic64 value) {
inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
__tsan_atomic64_store(ptr, value, __tsan_memory_order_relaxed);
}
inline void Acquire_Store(volatile Atomic64 *ptr, Atomic64 value) {
inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
__tsan_atomic64_store(ptr, value, __tsan_memory_order_relaxed);
__tsan_atomic_thread_fence(__tsan_memory_order_seq_cst);
}
inline void Release_Store(volatile Atomic64 *ptr, Atomic64 value) {
inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
__tsan_atomic64_store(ptr, value, __tsan_memory_order_release);
}
inline Atomic64 NoBarrier_Load(volatile const Atomic64 *ptr) {
inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
return __tsan_atomic64_load(ptr, __tsan_memory_order_relaxed);
}
inline Atomic64 Acquire_Load(volatile const Atomic64 *ptr) {
inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
return __tsan_atomic64_load(ptr, __tsan_memory_order_acquire);
}
inline Atomic64 Release_Load(volatile const Atomic64 *ptr) {
inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
__tsan_atomic_thread_fence(__tsan_memory_order_seq_cst);
return __tsan_atomic64_load(ptr, __tsan_memory_order_relaxed);
}
inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64 *ptr,
Atomic64 old_value,
Atomic64 new_value) {
inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
Atomic64 old_value,
Atomic64 new_value) {
Atomic64 cmp = old_value;
__tsan_atomic64_compare_exchange_strong(ptr, &cmp, new_value,
__tsan_memory_order_acquire, __tsan_memory_order_acquire);
return cmp;
}
inline Atomic64 Release_CompareAndSwap(volatile Atomic64 *ptr,
Atomic64 old_value,
Atomic64 new_value) {
inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
Atomic64 old_value,
Atomic64 new_value) {
Atomic64 cmp = old_value;
__tsan_atomic64_compare_exchange_strong(ptr, &cmp, new_value,
__tsan_memory_order_release, __tsan_memory_order_relaxed);
@ -373,6 +183,4 @@ inline void MemoryBarrier() {
} // namespace base::subtle
} // namespace base
#undef ATOMICOPS_COMPILER_BARRIER
#endif // BASE_ATOMICOPS_INTERNALS_TSAN_H_

Просмотреть файл

@ -17,7 +17,6 @@
struct AtomicOps_x86CPUFeatureStruct {
bool has_amd_lock_mb_bug; // Processor has AMD memory-barrier bug; do lfence
// after acquire compare-and-swap.
bool has_sse2; // Processor has SSE2.
};
BASE_EXPORT extern struct AtomicOps_x86CPUFeatureStruct
AtomicOps_Internalx86CPUFeatures;
@ -92,10 +91,6 @@ inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
*ptr = value;
}
#if defined(__x86_64__)
// 64-bit implementations of memory barrier can be simpler, because it
// "mfence" is guaranteed to exist.
inline void MemoryBarrier() {
__asm__ __volatile__("mfence" : : : "memory");
}
@ -105,28 +100,6 @@ inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
MemoryBarrier();
}
#else
inline void MemoryBarrier() {
if (AtomicOps_Internalx86CPUFeatures.has_sse2) {
__asm__ __volatile__("mfence" : : : "memory");
} else { // mfence is faster but not present on PIII
Atomic32 x = 0;
NoBarrier_AtomicExchange(&x, 0); // acts as a barrier on PIII
}
}
inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
if (AtomicOps_Internalx86CPUFeatures.has_sse2) {
*ptr = value;
__asm__ __volatile__("mfence" : : : "memory");
} else {
NoBarrier_AtomicExchange(ptr, value);
// acts as a barrier on PIII
}
}
#endif
inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
ATOMICOPS_COMPILER_BARRIER();
*ptr = value; // An x86 store acts as a release barrier.

Просмотреть файл

@ -9,6 +9,10 @@
#include <windows.h>
#include <intrin.h>
#include "base/macros.h"
#if defined(ARCH_CPU_64_BITS)
// windows.h #defines this (only on x64). This causes problems because the
// public API also uses MemoryBarrier at the public name for this fence. So, on
@ -24,7 +28,7 @@ namespace subtle {
inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
Atomic32 old_value,
Atomic32 new_value) {
LONG result = InterlockedCompareExchange(
LONG result = _InterlockedCompareExchange(
reinterpret_cast<volatile LONG*>(ptr),
static_cast<LONG>(new_value),
static_cast<LONG>(old_value));
@ -33,7 +37,7 @@ inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
Atomic32 new_value) {
LONG result = InterlockedExchange(
LONG result = _InterlockedExchange(
reinterpret_cast<volatile LONG*>(ptr),
static_cast<LONG>(new_value));
return static_cast<Atomic32>(result);
@ -41,7 +45,7 @@ inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
Atomic32 increment) {
return InterlockedExchangeAdd(
return _InterlockedExchangeAdd(
reinterpret_cast<volatile LONG*>(ptr),
static_cast<LONG>(increment)) + increment;
}

Просмотреть файл

@ -31,6 +31,10 @@ enum BasePathKey {
DIR_EXE, // Directory containing FILE_EXE.
DIR_MODULE, // Directory containing FILE_MODULE.
DIR_TEMP, // Temporary directory.
DIR_HOME, // User's root home directory. On Windows this will look
// like "C:\Users\you" (or on XP
// "C:\Document and Settings\you") which isn't necessarily
// a great place to put files.
FILE_EXE, // Path and filename of the current executable.
FILE_MODULE, // Path and filename of the module containing the code for
// the PathService (which could differ from FILE_EXE if the

Просмотреть файл

@ -25,7 +25,6 @@ enum {
DIR_START_MENU, // Usually "C:\Documents and Settings\<user>\
// Start Menu\Programs"
DIR_APP_DATA, // Application Data directory under the user profile.
DIR_PROFILE, // Usually "C:\Documents and settings\<user>.
DIR_LOCAL_APP_DATA_LOW, // Local AppData directory for low integrity level.
DIR_LOCAL_APP_DATA, // "Local Settings\Application Data" directory under
// the user profile.
@ -42,6 +41,7 @@ enum {
// of the Default user.
DIR_TASKBAR_PINS, // Directory for the shortcuts pinned to taskbar via
// base::win::TaskbarPinShortcutLink().
DIR_WINDOWS_FONTS, // Usually C:\Windows\Fonts.
PATH_WIN_END
};

Просмотреть файл

@ -6,21 +6,22 @@
namespace switches {
// If the program includes base/debug/debug_on_start_win.h, the process will
// (on Windows only) start the JIT system-registered debugger on itself and
// will wait for 60 seconds for the debugger to attach to itself. Then a break
// point will be hit.
const char kDebugOnStart[] = "debug-on-start";
// Disables the crash reporting.
const char kDisableBreakpad[] = "disable-breakpad";
// Enable DCHECKs in release mode.
const char kEnableDCHECK[] = "enable-dcheck";
// Indicates that crash reporting should be enabled. On platforms where helper
// processes cannot access to files needed to make this decision, this flag is
// generated internally.
const char kEnableCrashReporter[] = "enable-crash-reporter";
// Generates full memory crash dump.
const char kFullMemoryCrashReport[] = "full-memory-crash-report";
// Force low-end device when set to 1;
// Auto-detect low-end device when set to 2;
// Force non-low-end device when set to other values or empty;
const char kLowEndDeviceMode[] = "low-end-device-mode";
// Suppresses all error dialogs when present.
const char kNoErrorDialogs[] = "noerrdialogs";
@ -49,12 +50,19 @@ const char kWaitForDebugger[] = "wait-for-debugger";
// Sends a pretty-printed version of tracing info to the console.
const char kTraceToConsole[] = "trace-to-console";
// Configure whether chrome://profiler will contain timing information. This
// option is enabled by default. A value of "0" will disable profiler timing,
// while all other values will enable it.
const char kProfilerTiming[] = "profiler-timing";
// Value of the --profiler-timing flag that will disable timing information for
// chrome://profiler.
const char kProfilerTimingDisabledValue[] = "0";
#if defined(OS_POSIX)
// A flag, generated internally for renderer and other helper process command
// lines on Linux and Mac. It tells the helper process to enable crash dumping
// and reporting, because helpers cannot access the files needed to make this
// decision.
const char kEnableCrashReporter[] = "enable-crash-reporter";
// Used for turning on Breakpad crash reporting in a debug environment where
// crash reporting is typically compiled but disabled.
const char kEnableCrashReporterForTesting[] =
"enable-crash-reporter-for-testing";
#endif
} // namespace switches

Просмотреть файл

@ -11,19 +11,21 @@
namespace switches {
extern const char kDebugOnStart[];
extern const char kDisableBreakpad[];
extern const char kEnableDCHECK[];
extern const char kEnableCrashReporter[];
extern const char kFullMemoryCrashReport[];
extern const char kLowEndDeviceMode[];
extern const char kNoErrorDialogs[];
extern const char kProfilerTiming[];
extern const char kProfilerTimingDisabledValue[];
extern const char kTestChildProcess[];
extern const char kTraceToConsole[];
extern const char kV[];
extern const char kVModule[];
extern const char kWaitForDebugger[];
extern const char kTraceToConsole[];
#if defined(OS_POSIX)
extern const char kEnableCrashReporter[];
extern const char kEnableCrashReporterForTesting[];
#endif
} // namespace switches

Просмотреть файл

@ -42,17 +42,17 @@ typedef unsigned long long uint64;
#endif
// DEPRECATED: Please use std::numeric_limits (from <limits>) instead.
const uint8 kuint8max = (( uint8) 0xFF);
const uint16 kuint16max = ((uint16) 0xFFFF);
const uint32 kuint32max = ((uint32) 0xFFFFFFFF);
const uint64 kuint64max = ((uint64) GG_LONGLONG(0xFFFFFFFFFFFFFFFF));
const int8 kint8min = (( int8) 0x80);
const int8 kint8max = (( int8) 0x7F);
const int16 kint16min = (( int16) 0x8000);
const int16 kint16max = (( int16) 0x7FFF);
const int32 kint32min = (( int32) 0x80000000);
const int32 kint32max = (( int32) 0x7FFFFFFF);
const int64 kint64min = (( int64) GG_LONGLONG(0x8000000000000000));
const int64 kint64max = (( int64) GG_LONGLONG(0x7FFFFFFFFFFFFFFF));
const uint8 kuint8max = 0xFF;
const uint16 kuint16max = 0xFFFF;
const uint32 kuint32max = 0xFFFFFFFF;
const uint64 kuint64max = 0xFFFFFFFFFFFFFFFFULL;
const int8 kint8min = -0x7F - 1;
const int8 kint8max = 0x7F;
const int16 kint16min = -0x7FFF - 1;
const int16 kint16max = 0x7FFF;
const int32 kint32min = -0x7FFFFFFF - 1;
const int32 kint32max = 0x7FFFFFFF;
const int64 kint64min = -0x7FFFFFFFFFFFFFFFLL - 1;
const int64 kint64max = 0x7FFFFFFFFFFFFFFFLL;
#endif // BASE_BASICTYPES_H_

Просмотреть файл

@ -65,12 +65,6 @@ Bind(Functor functor) {
typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
typedef typename internal::FunctorTraits<Functor>::RunType RunType;
// Use RunnableType::RunType instead of RunType above because our
// checks should below for bound references need to know what the actual
// functor is going to interpret the argument as.
typedef internal::FunctionTraits<typename RunnableType::RunType>
BoundFunctorTraits;
typedef internal::BindState<RunnableType, RunType, void()> BindState;

Просмотреть файл

@ -12,7 +12,7 @@
//
// ARGUMENT BINDING WRAPPERS
//
// The wrapper functions are base::Unretained(), base::Owned(), bass::Passed(),
// The wrapper functions are base::Unretained(), base::Owned(), base::Passed(),
// base::ConstRef(), and base::IgnoreResult().
//
// Unretained() allows Bind() to bind a non-refcounted class, and to disable

Просмотреть файл

@ -143,8 +143,8 @@
//
// base::Bind(&MyClass::Foo, GetWeakPtr());
//
// The callback will not be issued if the object is destroyed at the time
// it's issued. DANGER: weak pointers are not threadsafe, so don't use this
// The callback will not be run if the object has already been destroyed.
// DANGER: weak pointers are not threadsafe, so don't use this
// when passing between threads!
//
// BINDING A CLASS METHOD WITH MANUAL LIFETIME MANAGEMENT
@ -214,11 +214,16 @@
//
// PASSING PARAMETERS BY REFERENCE
//
// void foo(int arg) { cout << arg << endl }
// Const references are *copied* unless ConstRef is used. Example:
//
// void foo(const int& arg) { printf("%d %p\n", arg, &arg); }
// int n = 1;
// base::Closure has_copy = base::Bind(&foo, n);
// base::Closure has_ref = base::Bind(&foo, base::ConstRef(n));
// n = 2;
// has_ref.Run(); // Prints "2"
// foo(n); // Prints "2 0xaaaaaaaaaaaa"
// has_copy.Run(); // Prints "1 0xbbbbbbbbbbbb"
// has_ref.Run(); // Prints "2 0xaaaaaaaaaaaa"
//
// Normally parameters are copied in the closure. DANGER: ConstRef stores a
// const reference instead, referencing the original parameter. This means
@ -756,7 +761,7 @@ class Callback<R(A1, A2, A3, A4, A5, A6, A7)> : public internal::CallbackBase {
};
// Syntactic sugar to make Callbacks<void(void)> easier to declare since it
// Syntactic sugar to make Callback<void(void)> easier to declare since it
// will be used in a lot of APIs with delayed execution.
typedef Callback<void(void)> Closure;

Просмотреть файл

@ -67,6 +67,20 @@ class BASE_EXPORT CallbackBase {
InvokeFuncStorage polymorphic_invoke_;
};
// A helper template to determine if given type is non-const move-only-type,
// i.e. if a value of the given type should be passed via .Pass() in a
// destructive way.
template <typename T> struct IsMoveOnlyType {
template <typename U>
static YesType Test(const typename U::MoveOnlyTypeForCPP03*);
template <typename U>
static NoType Test(...);
static const bool value = sizeof(Test<T>(0)) == sizeof(YesType) &&
!is_const<T>::value;
};
// This is a typetraits object that's used to take an argument type, and
// extract a suitable type for storing and forwarding arguments.
//
@ -78,7 +92,7 @@ class BASE_EXPORT CallbackBase {
// parameters by const reference. In this case, we end up passing an actual
// array type in the initializer list which C++ does not allow. This will
// break passing of C-string literals.
template <typename T>
template <typename T, bool is_move_only = IsMoveOnlyType<T>::value>
struct CallbackParamTraits {
typedef const T& ForwardType;
typedef T StorageType;
@ -90,7 +104,7 @@ struct CallbackParamTraits {
//
// The ForwardType should only be used for unbound arguments.
template <typename T>
struct CallbackParamTraits<T&> {
struct CallbackParamTraits<T&, false> {
typedef T& ForwardType;
typedef T StorageType;
};
@ -101,14 +115,14 @@ struct CallbackParamTraits<T&> {
// T[n]" does not seem to match correctly, so we are stuck with this
// restriction.
template <typename T, size_t n>
struct CallbackParamTraits<T[n]> {
struct CallbackParamTraits<T[n], false> {
typedef const T* ForwardType;
typedef const T* StorageType;
};
// See comment for CallbackParamTraits<T[n]>.
template <typename T>
struct CallbackParamTraits<T[]> {
struct CallbackParamTraits<T[], false> {
typedef const T* ForwardType;
typedef const T* StorageType;
};
@ -126,26 +140,10 @@ struct CallbackParamTraits<T[]> {
// correctness, because we are implementing a destructive move. A non-const
// reference cannot be used with temporaries which means the result of a
// function or a cast would not be usable with Callback<> or Bind().
//
// TODO(ajwong): We might be able to use SFINAE to search for the existence of
// a Pass() function in the type and avoid the whitelist in CallbackParamTraits
// and CallbackForward.
template <typename T, typename D>
struct CallbackParamTraits<scoped_ptr<T, D> > {
typedef scoped_ptr<T, D> ForwardType;
typedef scoped_ptr<T, D> StorageType;
};
template <typename T, typename R>
struct CallbackParamTraits<scoped_ptr_malloc<T, R> > {
typedef scoped_ptr_malloc<T, R> ForwardType;
typedef scoped_ptr_malloc<T, R> StorageType;
};
template <typename T>
struct CallbackParamTraits<ScopedVector<T> > {
typedef ScopedVector<T> ForwardType;
typedef ScopedVector<T> StorageType;
struct CallbackParamTraits<T, true> {
typedef T ForwardType;
typedef T StorageType;
};
// CallbackForward() is a very limited simulation of C++11's std::forward()
@ -165,18 +163,14 @@ struct CallbackParamTraits<ScopedVector<T> > {
// parameter to another callback. This is to support Callbacks that return
// the movable-but-not-copyable types whitelisted above.
template <typename T>
T& CallbackForward(T& t) { return t; }
template <typename T, typename D>
scoped_ptr<T, D> CallbackForward(scoped_ptr<T, D>& p) { return p.Pass(); }
template <typename T, typename R>
scoped_ptr_malloc<T, R> CallbackForward(scoped_ptr_malloc<T, R>& p) {
return p.Pass();
typename enable_if<!IsMoveOnlyType<T>::value, T>::type& CallbackForward(T& t) {
return t;
}
template <typename T>
ScopedVector<T> CallbackForward(ScopedVector<T>& p) { return p.Pass(); }
typename enable_if<IsMoveOnlyType<T>::value, T>::type CallbackForward(T& t) {
return t.Pass();
}
} // namespace internal
} // namespace base

Просмотреть файл

@ -68,6 +68,28 @@
#endif // COMPILER_MSVC
// The C++ standard requires that static const members have an out-of-class
// definition (in a single compilation unit), but MSVC chokes on this (when
// language extensions, which are required, are enabled). (You're only likely to
// notice the need for a definition if you take the address of the member or,
// more commonly, pass it to a function that takes it as a reference argument --
// probably an STL function.) This macro makes MSVC do the right thing. See
// http://msdn.microsoft.com/en-us/library/34h23df8(v=vs.100).aspx for more
// information. Use like:
//
// In .h file:
// struct Foo {
// static const int kBar = 5;
// };
//
// In .cc file:
// STATIC_CONST_MEMBER_DEFINITION const int Foo::kBar;
#if defined(COMPILER_MSVC)
#define STATIC_CONST_MEMBER_DEFINITION __declspec(selectany)
#else
#define STATIC_CONST_MEMBER_DEFINITION
#endif
// Annotate a variable indicating it's ok if the variable is not used.
// (Typically used to silence a compiler warning when the assignment
// is important for some other reason.)
@ -119,6 +141,10 @@
#define OVERRIDE override
#elif defined(__clang__)
#define OVERRIDE override
#elif defined(COMPILER_GCC) && __cplusplus >= 201103 && \
(__GNUC__ * 10000 + __GNUC_MINOR__ * 100) >= 40700
// GCC 4.7 supports explicit virtual overrides when C++11 support is enabled.
#define OVERRIDE override
#else
#define OVERRIDE
#endif
@ -128,10 +154,14 @@
// Use like:
// virtual void foo() FINAL;
// class B FINAL : public A {};
#if defined(COMPILER_MSVC)
#if defined(__clang__)
#define FINAL final
#elif defined(COMPILER_MSVC)
// TODO(jered): Change this to "final" when chromium no longer uses MSVC 2010.
#define FINAL sealed
#elif defined(__clang__)
#elif defined(COMPILER_GCC) && __cplusplus >= 201103 && \
(__GNUC__ * 10000 + __GNUC_MINOR__ * 100) >= 40700
// GCC 4.7 supports explicit virtual overrides when C++11 support is enabled.
#define FINAL final
#else
#define FINAL
@ -166,12 +196,9 @@
// If available, it would look like:
// __attribute__((format(wprintf, format_param, dots_param)))
// MemorySanitizer annotations.
#ifdef MEMORY_SANITIZER
extern "C" {
void __msan_unpoison(const void *p, unsigned long s);
} // extern "C"
#if defined(MEMORY_SANITIZER) && !defined(OS_NACL)
#include <sanitizer/msan_interface.h>
// Mark a memory region fully initialized.
// Use this to annotate code that deliberately reads uninitialized data, for
@ -181,4 +208,22 @@ void __msan_unpoison(const void *p, unsigned long s);
#define MSAN_UNPOISON(p, s)
#endif // MEMORY_SANITIZER
// Macro useful for writing cross-platform function pointers.
#if !defined(CDECL)
#if defined(OS_WIN)
#define CDECL __cdecl
#else // defined(OS_WIN)
#define CDECL
#endif // defined(OS_WIN)
#endif // !defined(CDECL)
// Macro for hinting that an expression is likely to be false.
#if !defined(UNLIKELY)
#if defined(COMPILER_GCC)
#define UNLIKELY(x) __builtin_expect(!!(x), 0)
#else
#define UNLIKELY(x) (x)
#endif // defined(COMPILER_GCC)
#endif // !defined(UNLIKELY)
#endif // BASE_COMPILER_SPECIFIC_H_

Просмотреть файл

@ -103,7 +103,7 @@ DEFINE_TRIVIAL_HASH(unsigned long long);
}
DEFINE_STRING_HASH(std::string);
DEFINE_STRING_HASH(string16);
DEFINE_STRING_HASH(base::string16);
#undef DEFINE_STRING_HASH
@ -140,7 +140,7 @@ inline std::size_t HashInts32(uint32 value1, uint32 value2) {
hash64 = hash64 * odd_random + shift_random;
std::size_t high_bits = static_cast<std::size_t>(
hash64 >> (sizeof(uint64) - sizeof(std::size_t)));
hash64 >> (8 * (sizeof(uint64) - sizeof(std::size_t))));
return high_bits;
}
@ -175,7 +175,7 @@ inline std::size_t HashInts64(uint64 value1, uint64 value2) {
hash64 = hash64 * odd_random + shift_random;
std::size_t high_bits = static_cast<std::size_t>(
hash64 >> (sizeof(uint64) - sizeof(std::size_t)));
hash64 >> (8 * (sizeof(uint64) - sizeof(std::size_t))));
return high_bits;
}

Просмотреть файл

@ -8,11 +8,18 @@
#include <algorithm>
#include "base/basictypes.h"
#include "build/build_config.h"
#if defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX))
#include "base/file_util.h"
#include "base/lazy_instance.h"
#endif
#if defined(ARCH_CPU_X86_FAMILY)
#if defined(_MSC_VER)
#include <intrin.h>
#include <immintrin.h> // For _xgetbv()
#endif
#endif
@ -33,11 +40,16 @@ CPU::CPU()
has_ssse3_(false),
has_sse41_(false),
has_sse42_(false),
has_avx_(false),
has_avx_hardware_(false),
has_aesni_(false),
has_non_stop_time_stamp_counter_(false),
cpu_vendor_("unknown") {
Initialize();
}
namespace {
#if defined(ARCH_CPU_X86_FAMILY)
#ifndef _MSC_VER
@ -53,16 +65,6 @@ void __cpuid(int cpu_info[4], int info_type) {
);
}
void __cpuidex(int cpu_info[4], int info_type, int info_index) {
__asm__ volatile (
"mov %%ebx, %%edi\n"
"cpuid\n"
"xchg %%edi, %%ebx\n"
: "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
: "a"(info_type), "c"(info_index)
);
}
#else
void __cpuid(int cpu_info[4], int info_type) {
@ -73,18 +75,72 @@ void __cpuid(int cpu_info[4], int info_type) {
);
}
void __cpuidex(int cpu_info[4], int info_type, int info_index) {
__asm__ volatile (
"cpuid \n\t"
: "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
: "a"(info_type), "c"(info_index)
);
#endif
// _xgetbv returns the value of an Intel Extended Control Register (XCR).
// Currently only XCR0 is defined by Intel so |xcr| should always be zero.
uint64 _xgetbv(uint32 xcr) {
uint32 eax, edx;
__asm__ volatile ("xgetbv" : "=a" (eax), "=d" (edx) : "c" (xcr));
return (static_cast<uint64>(edx) << 32) | eax;
}
#endif
#endif // _MSC_VER
#endif // !_MSC_VER
#endif // ARCH_CPU_X86_FAMILY
#if defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX))
// Returns the string found in /proc/cpuinfo under the key "model name" or
// "Processor". "model name" is used in Linux 3.8 and later (3.7 and later for
// arm64) and is shown once per CPU. "Processor" is used in earler versions and
// is shown only once at the top of /proc/cpuinfo regardless of the number CPUs.
std::string ParseCpuInfo() {
const char kModelNamePrefix[] = "model name\t: ";
const char kProcessorPrefix[] = "Processor\t: ";
std::string contents;
ReadFileToString(FilePath("/proc/cpuinfo"), &contents);
DCHECK(!contents.empty());
std::string cpu_brand;
if (!contents.empty()) {
std::istringstream iss(contents);
std::string line;
while (std::getline(iss, line)) {
if (line.compare(0, strlen(kModelNamePrefix), kModelNamePrefix) == 0) {
cpu_brand.assign(line.substr(strlen(kModelNamePrefix)));
break;
}
if (line.compare(0, strlen(kProcessorPrefix), kProcessorPrefix) == 0) {
cpu_brand.assign(line.substr(strlen(kProcessorPrefix)));
break;
}
}
}
return cpu_brand;
}
class LazyCpuInfoValue {
public:
LazyCpuInfoValue() : value_(ParseCpuInfo()) {}
const std::string& value() { return value_; }
private:
const std::string value_;
DISALLOW_COPY_AND_ASSIGN(LazyCpuInfoValue);
};
base::LazyInstance<LazyCpuInfoValue> g_lazy_cpu_brand =
LAZY_INSTANCE_INITIALIZER;
const std::string& CpuBrandInfo() {
return g_lazy_cpu_brand.Get().value();
}
#endif // defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) ||
// defined(OS_LINUX))
} // anonymous namespace
void CPU::Initialize() {
#if defined(ARCH_CPU_X86_FAMILY)
int cpu_info[4] = {-1};
@ -113,14 +169,31 @@ void CPU::Initialize() {
type_ = (cpu_info[0] >> 12) & 0x3;
ext_model_ = (cpu_info[0] >> 16) & 0xf;
ext_family_ = (cpu_info[0] >> 20) & 0xff;
has_mmx_ = (cpu_info[3] & 0x00800000) != 0;
has_sse_ = (cpu_info[3] & 0x02000000) != 0;
has_sse2_ = (cpu_info[3] & 0x04000000) != 0;
has_sse3_ = (cpu_info[2] & 0x00000001) != 0;
has_mmx_ = (cpu_info[3] & 0x00800000) != 0;
has_sse_ = (cpu_info[3] & 0x02000000) != 0;
has_sse2_ = (cpu_info[3] & 0x04000000) != 0;
has_sse3_ = (cpu_info[2] & 0x00000001) != 0;
has_ssse3_ = (cpu_info[2] & 0x00000200) != 0;
has_sse41_ = (cpu_info[2] & 0x00080000) != 0;
has_sse42_ = (cpu_info[2] & 0x00100000) != 0;
has_avx_ = (cpu_info[2] & 0x10000000) != 0;
has_avx_hardware_ =
(cpu_info[2] & 0x10000000) != 0;
// AVX instructions will generate an illegal instruction exception unless
// a) they are supported by the CPU,
// b) XSAVE is supported by the CPU and
// c) XSAVE is enabled by the kernel.
// See http://software.intel.com/en-us/blogs/2011/04/14/is-avx-enabled
//
// In addition, we have observed some crashes with the xgetbv instruction
// even after following Intel's example code. (See crbug.com/375968.)
// Because of that, we also test the XSAVE bit because its description in
// the CPUID documentation suggests that it signals xgetbv support.
has_avx_ =
has_avx_hardware_ &&
(cpu_info[2] & 0x04000000) != 0 /* XSAVE */ &&
(cpu_info[2] & 0x08000000) != 0 /* OSXSAVE */ &&
(_xgetbv(0) & 6) == 6 /* XSAVE enabled by kernel */;
has_aesni_ = (cpu_info[2] & 0x02000000) != 0;
}
// Get the brand string of the cpu.
@ -145,6 +218,8 @@ void CPU::Initialize() {
__cpuid(cpu_info, parameter_containing_non_stop_time_stamp_counter);
has_non_stop_time_stamp_counter_ = (cpu_info[3] & (1 << 8)) != 0;
}
#elif defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX))
cpu_brand_.assign(CpuBrandInfo());
#endif
}

Просмотреть файл

@ -46,6 +46,13 @@ class BASE_EXPORT CPU {
bool has_sse41() const { return has_sse41_; }
bool has_sse42() const { return has_sse42_; }
bool has_avx() const { return has_avx_; }
// has_avx_hardware returns true when AVX is present in the CPU. This might
// differ from the value of |has_avx()| because |has_avx()| also tests for
// operating system support needed to actually call AVX instuctions.
// Note: you should never need to call this function. It was added in order
// to workaround a bug in NSS but |has_avx()| is what you want.
bool has_avx_hardware() const { return has_avx_hardware_; }
bool has_aesni() const { return has_aesni_; }
bool has_non_stop_time_stamp_counter() const {
return has_non_stop_time_stamp_counter_;
}
@ -71,6 +78,8 @@ class BASE_EXPORT CPU {
bool has_sse41_;
bool has_sse42_;
bool has_avx_;
bool has_avx_hardware_;
bool has_aesni_;
bool has_non_stop_time_stamp_counter_;
std::string cpu_vendor_;
std::string cpu_brand_;

Просмотреть файл

@ -14,10 +14,6 @@
namespace base {
namespace debug {
// Starts the registered system-wide JIT debugger to attach it to specified
// process.
BASE_EXPORT bool SpawnDebuggerOnProcess(unsigned process_id);
// Waits wait_seconds seconds for a debugger to attach to the current process.
// When silent is false, an exception is thrown when a debugger is detected.
BASE_EXPORT bool WaitForDebugger(int wait_seconds, bool silent);

Просмотреть файл

@ -5,40 +5,30 @@
#ifndef BASE_DEBUG_LEAK_ANNOTATIONS_H_
#define BASE_DEBUG_LEAK_ANNOTATIONS_H_
#include "base/basictypes.h"
#include "build/build_config.h"
// This file defines macros which can be used to annotate intentional memory
// leaks. Support for annotations is implemented in HeapChecker and
// LeakSanitizer. Annotated objects will be treated as a source of live
// pointers, i.e. any heap objects reachable by following pointers from an
// annotated object will not be reported as leaks.
// leaks. Support for annotations is implemented in LeakSanitizer. Annotated
// objects will be treated as a source of live pointers, i.e. any heap objects
// reachable by following pointers from an annotated object will not be
// reported as leaks.
//
// ANNOTATE_SCOPED_MEMORY_LEAK: all allocations made in the current scope
// will be annotated as leaks.
// ANNOTATE_LEAKING_OBJECT_PTR(X): the heap object referenced by pointer X will
// be annotated as a leak.
//
// Note that HeapChecker will report a fatal error if an object which has been
// annotated with ANNOTATE_LEAKING_OBJECT_PTR is later deleted (but
// LeakSanitizer won't).
#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_NACL) && \
defined(USE_HEAPCHECKER)
#include "third_party/tcmalloc/chromium/src/gperftools/heap-checker.h"
#define ANNOTATE_SCOPED_MEMORY_LEAK \
HeapLeakChecker::Disabler heap_leak_checker_disabler; static_cast<void>(0)
#define ANNOTATE_LEAKING_OBJECT_PTR(X) \
HeapLeakChecker::IgnoreObject(X)
#elif defined(LEAK_SANITIZER) && !defined(OS_NACL)
#if defined(LEAK_SANITIZER) && !defined(OS_NACL)
// Public LSan API from <sanitizer/lsan_interface.h>.
extern "C" {
void __lsan_disable();
void __lsan_enable();
void __lsan_ignore_object(const void *p);
// Invoke leak detection immediately. If leaks are found, the process will exit.
void __lsan_do_leak_check();
} // extern "C"
class ScopedLeakSanitizerDisabler {

Просмотреть файл

@ -14,14 +14,16 @@
#include "base/win/pe_image.h"
#endif // defined(OS_WIN)
#if defined(ENABLE_PROFILING) && !defined(NO_TCMALLOC)
// TODO(peria): Enable profiling on Windows.
#if defined(ENABLE_PROFILING) && !defined(NO_TCMALLOC) && !defined(OS_WIN)
#include "third_party/tcmalloc/chromium/src/gperftools/profiler.h"
#endif
namespace base {
namespace debug {
#if defined(ENABLE_PROFILING) && !defined(NO_TCMALLOC)
// TODO(peria): Enable profiling on Windows.
#if defined(ENABLE_PROFILING) && !defined(NO_TCMALLOC) && !defined(OS_WIN)
static int profile_count = 0;

Просмотреть файл

@ -5,6 +5,8 @@
#ifndef BASE_FILE_DESCRIPTOR_POSIX_H_
#define BASE_FILE_DESCRIPTOR_POSIX_H_
#include "base/files/file.h"
namespace base {
// -----------------------------------------------------------------------------
@ -16,18 +18,21 @@ namespace base {
// above the template specialisation for this structure.
// -----------------------------------------------------------------------------
struct FileDescriptor {
FileDescriptor()
: fd(-1),
auto_close(false) { }
FileDescriptor() : fd(-1), auto_close(false) {}
FileDescriptor(int ifd, bool iauto_close)
: fd(ifd),
auto_close(iauto_close) { }
FileDescriptor(int ifd, bool iauto_close) : fd(ifd), auto_close(iauto_close) {
}
FileDescriptor(File file) : fd(file.TakePlatformFile()), auto_close(true) {}
bool operator==(const FileDescriptor& other) const {
return (fd == other.fd && auto_close == other.auto_close);
}
bool operator!=(const FileDescriptor& other) const {
return !operator==(other);
}
// A comparison operator so that we can use these as keys in a std::map.
bool operator<(const FileDescriptor& other) const {
return other.fd < fd;

Просмотреть файл

@ -25,9 +25,9 @@
#include "base/base_export.h"
#include "base/basictypes.h"
#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/memory/scoped_ptr.h"
#include "base/platform_file.h"
#include "base/strings/string16.h"
#if defined(OS_POSIX)
@ -40,8 +40,6 @@ namespace base {
class Time;
extern bool g_bug108724_debug;
//-----------------------------------------------------------------------------
// Functions that involve filesystem access or modification:
@ -95,10 +93,13 @@ BASE_EXPORT bool Move(const FilePath& from_path, const FilePath& to_path);
// Returns false on failure and sets *error appropriately, if it is non-NULL.
BASE_EXPORT bool ReplaceFile(const FilePath& from_path,
const FilePath& to_path,
PlatformFileError* error);
File::Error* error);
// Copies a single file. Use CopyDirectory to copy directories.
// This function fails if either path contains traversal components ('..').
//
// This function keeps the metadata on Windows. The read only bit on Windows is
// not kept.
BASE_EXPORT bool CopyFile(const FilePath& from_path, const FilePath& to_path);
// Copies the given path, and optionally all subdirectories and their contents
@ -107,6 +108,9 @@ BASE_EXPORT bool CopyFile(const FilePath& from_path, const FilePath& to_path);
// If there are files existing under to_path, always overwrite. Returns true
// if successful, false otherwise. Wildcards on the names are not supported.
//
// This function calls into CopyFile() so the same behavior w.r.t. metadata
// applies.
//
// If you only need to copy a file use CopyFile, it's faster.
BASE_EXPORT bool CopyDirectory(const FilePath& from_path,
const FilePath& to_path,
@ -132,20 +136,30 @@ BASE_EXPORT bool ContentsEqual(const FilePath& filename1,
BASE_EXPORT bool TextContentsEqual(const FilePath& filename1,
const FilePath& filename2);
// Read the file at |path| into |contents|, returning true on success.
// This function fails if the |path| contains path traversal components ('..').
// |contents| may be NULL, in which case this function is useful for its
// side effect of priming the disk cache.
// Useful for unit tests.
// Reads the file at |path| into |contents| and returns true on success and
// false on error. For security reasons, a |path| containing path traversal
// components ('..') is treated as a read error and |contents| is set to empty.
// In case of I/O error, |contents| holds the data that could be read from the
// file before the error occurred.
// |contents| may be NULL, in which case this function is useful for its side
// effect of priming the disk cache (could be used for unit tests).
BASE_EXPORT bool ReadFileToString(const FilePath& path, std::string* contents);
} // namespace base
// -----------------------------------------------------------------------------
namespace file_util {
// Reads the file at |path| into |contents| and returns true on success and
// false on error. For security reasons, a |path| containing path traversal
// components ('..') is treated as a read error and |contents| is set to empty.
// In case of I/O error, |contents| holds the data that could be read from the
// file before the error occurred. When the file size exceeds |max_size|, the
// function returns false with |contents| holding the file truncated to
// |max_size|.
// |contents| may be NULL, in which case this function is useful for its side
// effect of priming the disk cache (could be used for unit tests).
BASE_EXPORT bool ReadFileToString(const FilePath& path,
std::string* contents,
size_t max_size);
#if defined(OS_POSIX)
// Read exactly |bytes| bytes from file descriptor |fd|, storing the result
// in |buffer|. This function is protected against EINTR and partial reads.
// Returns true iff |bytes| bytes have been successfully read from |fd|.
@ -153,15 +167,14 @@ BASE_EXPORT bool ReadFromFD(int fd, char* buffer, size_t bytes);
// Creates a symbolic link at |symlink| pointing to |target|. Returns
// false on failure.
BASE_EXPORT bool CreateSymbolicLink(const base::FilePath& target,
const base::FilePath& symlink);
BASE_EXPORT bool CreateSymbolicLink(const FilePath& target,
const FilePath& symlink);
// Reads the given |symlink| and returns where it points to in |target|.
// Returns false upon failure.
BASE_EXPORT bool ReadSymbolicLink(const base::FilePath& symlink,
base::FilePath* target);
BASE_EXPORT bool ReadSymbolicLink(const FilePath& symlink, FilePath* target);
// Bits ans masks of the file permission.
// Bits and masks of the file permission.
enum FilePermissionBits {
FILE_PERMISSION_MASK = S_IRWXU | S_IRWXG | S_IRWXO,
FILE_PERMISSION_USER_MASK = S_IRWXU,
@ -182,80 +195,77 @@ enum FilePermissionBits {
// Reads the permission of the given |path|, storing the file permission
// bits in |mode|. If |path| is symbolic link, |mode| is the permission of
// a file which the symlink points to.
BASE_EXPORT bool GetPosixFilePermissions(const base::FilePath& path,
int* mode);
BASE_EXPORT bool GetPosixFilePermissions(const FilePath& path, int* mode);
// Sets the permission of the given |path|. If |path| is symbolic link, sets
// the permission of a file which the symlink points to.
BASE_EXPORT bool SetPosixFilePermissions(const base::FilePath& path,
int mode);
#endif // defined(OS_POSIX)
BASE_EXPORT bool SetPosixFilePermissions(const FilePath& path, int mode);
// Return true if the given directory is empty
BASE_EXPORT bool IsDirectoryEmpty(const base::FilePath& dir_path);
#endif // OS_POSIX
// Returns true if the given directory is empty
BASE_EXPORT bool IsDirectoryEmpty(const FilePath& dir_path);
// Get the temporary directory provided by the system.
// WARNING: DON'T USE THIS. If you want to create a temporary file, use one of
// the functions below.
BASE_EXPORT bool GetTempDir(base::FilePath* path);
// Get a temporary directory for shared memory files.
// Only useful on POSIX; redirects to GetTempDir() on Windows.
BASE_EXPORT bool GetShmemTempDir(base::FilePath* path, bool executable);
//
// WARNING: In general, you should use CreateTemporaryFile variants below
// instead of this function. Those variants will ensure that the proper
// permissions are set so that other users on the system can't edit them while
// they're open (which can lead to security issues).
BASE_EXPORT bool GetTempDir(FilePath* path);
// Get the home directory. This is more complicated than just getenv("HOME")
// Get the home directory. This is more complicated than just getenv("HOME")
// as it knows to fall back on getpwent() etc.
BASE_EXPORT base::FilePath GetHomeDir();
//
// You should not generally call this directly. Instead use DIR_HOME with the
// path service which will use this function but cache the value.
// Path service may also override DIR_HOME.
BASE_EXPORT FilePath GetHomeDir();
// Creates a temporary file. The full path is placed in |path|, and the
// function returns true if was successful in creating the file. The file will
// be empty and all handles closed after this function returns.
BASE_EXPORT bool CreateTemporaryFile(base::FilePath* path);
BASE_EXPORT bool CreateTemporaryFile(FilePath* path);
// Same as CreateTemporaryFile but the file is created in |dir|.
BASE_EXPORT bool CreateTemporaryFileInDir(const base::FilePath& dir,
base::FilePath* temp_file);
BASE_EXPORT bool CreateTemporaryFileInDir(const FilePath& dir,
FilePath* temp_file);
// Create and open a temporary file. File is opened for read/write.
// The full path is placed in |path|.
// Returns a handle to the opened file or NULL if an error occurred.
BASE_EXPORT FILE* CreateAndOpenTemporaryFile(base::FilePath* path);
// Like above but for shmem files. Only useful for POSIX.
// The executable flag says the file needs to support using
// mprotect with PROT_EXEC after mapping.
BASE_EXPORT FILE* CreateAndOpenTemporaryShmemFile(base::FilePath* path,
bool executable);
BASE_EXPORT FILE* CreateAndOpenTemporaryFile(FilePath* path);
// Similar to CreateAndOpenTemporaryFile, but the file is created in |dir|.
BASE_EXPORT FILE* CreateAndOpenTemporaryFileInDir(const base::FilePath& dir,
base::FilePath* path);
BASE_EXPORT FILE* CreateAndOpenTemporaryFileInDir(const FilePath& dir,
FilePath* path);
// Create a new directory. If prefix is provided, the new directory name is in
// the format of prefixyyyy.
// NOTE: prefix is ignored in the POSIX implementation.
// If success, return true and output the full path of the directory created.
BASE_EXPORT bool CreateNewTempDirectory(
const base::FilePath::StringType& prefix,
base::FilePath* new_temp_path);
BASE_EXPORT bool CreateNewTempDirectory(const FilePath::StringType& prefix,
FilePath* new_temp_path);
// Create a directory within another directory.
// Extra characters will be appended to |prefix| to ensure that the
// new directory does not have the same name as an existing directory.
BASE_EXPORT bool CreateTemporaryDirInDir(
const base::FilePath& base_dir,
const base::FilePath::StringType& prefix,
base::FilePath* new_dir);
BASE_EXPORT bool CreateTemporaryDirInDir(const FilePath& base_dir,
const FilePath::StringType& prefix,
FilePath* new_dir);
// Creates a directory, as well as creating any parent directories, if they
// don't exist. Returns 'true' on successful creation, or if the directory
// already exists. The directory is only readable by the current user.
// Returns true on success, leaving *error unchanged.
// Returns false on failure and sets *error appropriately, if it is non-NULL.
BASE_EXPORT bool CreateDirectoryAndGetError(const base::FilePath& full_path,
base::PlatformFileError* error);
BASE_EXPORT bool CreateDirectoryAndGetError(const FilePath& full_path,
File::Error* error);
// Backward-compatible convenience method for the above.
BASE_EXPORT bool CreateDirectory(const base::FilePath& full_path);
BASE_EXPORT bool CreateDirectory(const FilePath& full_path);
// Returns the file size. Returns true on success.
BASE_EXPORT bool GetFileSize(const base::FilePath& file_path, int64* file_size);
BASE_EXPORT bool GetFileSize(const FilePath& file_path, int64* file_size);
// Sets |real_path| to |path| with symbolic links and junctions expanded.
// On windows, make sure the path starts with a lettered drive.
@ -263,92 +273,80 @@ BASE_EXPORT bool GetFileSize(const base::FilePath& file_path, int64* file_size);
// a directory or to a nonexistent path. On windows, this function will
// fail if |path| is a junction or symlink that points to an empty file,
// or if |real_path| would be longer than MAX_PATH characters.
BASE_EXPORT bool NormalizeFilePath(const base::FilePath& path,
base::FilePath* real_path);
BASE_EXPORT bool NormalizeFilePath(const FilePath& path, FilePath* real_path);
#if defined(OS_WIN)
// Given a path in NT native form ("\Device\HarddiskVolumeXX\..."),
// return in |drive_letter_path| the equivalent path that starts with
// a drive letter ("C:\..."). Return false if no such path exists.
BASE_EXPORT bool DevicePathToDriveLetterPath(const base::FilePath& device_path,
base::FilePath* drive_letter_path);
BASE_EXPORT bool DevicePathToDriveLetterPath(const FilePath& device_path,
FilePath* drive_letter_path);
// Given an existing file in |path|, set |real_path| to the path
// in native NT format, of the form "\Device\HarddiskVolumeXX\..".
// Returns false if the path can not be found. Empty files cannot
// be resolved with this function.
BASE_EXPORT bool NormalizeToNativeFilePath(const base::FilePath& path,
base::FilePath* nt_path);
BASE_EXPORT bool NormalizeToNativeFilePath(const FilePath& path,
FilePath* nt_path);
#endif
// This function will return if the given file is a symlink or not.
BASE_EXPORT bool IsLink(const base::FilePath& file_path);
BASE_EXPORT bool IsLink(const FilePath& file_path);
// Returns information about the given file path.
BASE_EXPORT bool GetFileInfo(const base::FilePath& file_path,
base::PlatformFileInfo* info);
BASE_EXPORT bool GetFileInfo(const FilePath& file_path, File::Info* info);
// Sets the time of the last access and the time of the last modification.
BASE_EXPORT bool TouchFile(const base::FilePath& path,
const base::Time& last_accessed,
const base::Time& last_modified);
// Set the time of the last modification. Useful for unit tests.
BASE_EXPORT bool SetLastModifiedTime(const base::FilePath& path,
const base::Time& last_modified);
#if defined(OS_POSIX)
// Store inode number of |path| in |inode|. Return true on success.
BASE_EXPORT bool GetInode(const base::FilePath& path, ino_t* inode);
#endif
BASE_EXPORT bool TouchFile(const FilePath& path,
const Time& last_accessed,
const Time& last_modified);
// Wrapper for fopen-like calls. Returns non-NULL FILE* on success.
BASE_EXPORT FILE* OpenFile(const base::FilePath& filename, const char* mode);
BASE_EXPORT FILE* OpenFile(const FilePath& filename, const char* mode);
// Closes file opened by OpenFile. Returns true on success.
BASE_EXPORT bool CloseFile(FILE* file);
// Associates a standard FILE stream with an existing File. Note that this
// functions take ownership of the existing File.
BASE_EXPORT FILE* FileToFILE(File file, const char* mode);
// Truncates an open file to end at the location of the current file pointer.
// This is a cross-platform analog to Windows' SetEndOfFile() function.
BASE_EXPORT bool TruncateFile(FILE* file);
// Reads the given number of bytes from the file into the buffer. Returns
// the number of read bytes, or -1 on error.
BASE_EXPORT int ReadFile(const base::FilePath& filename, char* data, int size);
// Reads at most the given number of bytes from the file into the buffer.
// Returns the number of read bytes, or -1 on error.
BASE_EXPORT int ReadFile(const FilePath& filename, char* data, int max_size);
// Writes the given buffer into the file, overwriting any data that was
// previously there. Returns the number of bytes written, or -1 on error.
BASE_EXPORT int WriteFile(const base::FilePath& filename, const char* data,
BASE_EXPORT int WriteFile(const FilePath& filename, const char* data,
int size);
#if defined(OS_POSIX)
// Append the data to |fd|. Does not close |fd| when done.
BASE_EXPORT int WriteFileDescriptor(const int fd, const char* data, int size);
#endif
// Append the given buffer into the file. Returns the number of bytes written,
// or -1 on error.
BASE_EXPORT int AppendToFile(const base::FilePath& filename,
BASE_EXPORT int AppendToFile(const FilePath& filename,
const char* data, int size);
// Gets the current working directory for the process.
BASE_EXPORT bool GetCurrentDirectory(base::FilePath* path);
BASE_EXPORT bool GetCurrentDirectory(FilePath* path);
// Sets the current working directory for the process.
BASE_EXPORT bool SetCurrentDirectory(const base::FilePath& path);
BASE_EXPORT bool SetCurrentDirectory(const FilePath& path);
// Attempts to find a number that can be appended to the |path| to make it
// unique. If |path| does not exist, 0 is returned. If it fails to find such
// a number, -1 is returned. If |suffix| is not empty, also checks the
// existence of it with the given suffix.
BASE_EXPORT int GetUniquePathNumber(const base::FilePath& path,
const base::FilePath::StringType& suffix);
#if defined(OS_POSIX)
// Creates a directory with a guaranteed unique name based on |path|, returning
// the pathname if successful, or an empty path if there was an error creating
// the directory. Does not create parent directories.
BASE_EXPORT base::FilePath MakeUniqueDirectory(const base::FilePath& path);
#endif
BASE_EXPORT int GetUniquePathNumber(const FilePath& path,
const FilePath::StringType& suffix);
#if defined(OS_POSIX)
// Test that |path| can only be changed by a given user and members of
@ -383,33 +381,6 @@ BASE_EXPORT bool VerifyPathControlledByAdmin(const base::FilePath& path);
// the directory |path|, in the number of FilePath::CharType, or -1 on failure.
BASE_EXPORT int GetMaximumPathComponentLength(const base::FilePath& path);
// A class to handle auto-closing of FILE*'s.
class ScopedFILEClose {
public:
inline void operator()(FILE* x) const {
if (x) {
fclose(x);
}
}
};
typedef scoped_ptr_malloc<FILE, ScopedFILEClose> ScopedFILE;
#if defined(OS_POSIX)
// A class to handle auto-closing of FDs.
class ScopedFDClose {
public:
inline void operator()(int* x) const {
if (x && *x >= 0) {
if (HANDLE_EINTR(close(*x)) < 0)
DPLOG(ERROR) << "close";
}
}
};
typedef scoped_ptr_malloc<int, ScopedFDClose> ScopedFD;
#endif // OS_POSIX
#if defined(OS_LINUX)
// Broad categories of file systems as returned by statfs() on Linux.
enum FileSystemType {
@ -427,10 +398,35 @@ enum FileSystemType {
// Attempts determine the FileSystemType for |path|.
// Returns false if |path| doesn't exist.
BASE_EXPORT bool GetFileSystemType(const base::FilePath& path,
FileSystemType* type);
BASE_EXPORT bool GetFileSystemType(const FilePath& path, FileSystemType* type);
#endif
#if defined(OS_POSIX)
// Get a temporary directory for shared memory files. The directory may depend
// on whether the destination is intended for executable files, which in turn
// depends on how /dev/shmem was mounted. As a result, you must supply whether
// you intend to create executable shmem segments so this function can find
// an appropriate location.
BASE_EXPORT bool GetShmemTempDir(bool executable, FilePath* path);
#endif
} // namespace base
// -----------------------------------------------------------------------------
namespace file_util {
// Functor for |ScopedFILE| (below).
struct ScopedFILEClose {
inline void operator()(FILE* x) const {
if (x)
fclose(x);
}
};
// Automatically closes |FILE*|s.
typedef scoped_ptr<FILE, ScopedFILEClose> ScopedFILE;
} // namespace file_util
// Internal --------------------------------------------------------------------

Просмотреть файл

@ -5,6 +5,7 @@
#include "base/file_util.h"
#include <windows.h>
#include <io.h>
#include <psapi.h>
#include <shellapi.h>
#include <shlobj.h>
@ -14,6 +15,7 @@
#include <limits>
#include <string>
#include "base/files/file_enumerator.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
@ -34,44 +36,6 @@ namespace {
const DWORD kFileShareAll =
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
bool ShellCopy(const FilePath& from_path,
const FilePath& to_path,
bool recursive) {
// WinXP SHFileOperation doesn't like trailing separators.
FilePath stripped_from = from_path.StripTrailingSeparators();
FilePath stripped_to = to_path.StripTrailingSeparators();
ThreadRestrictions::AssertIOAllowed();
// NOTE: I suspect we could support longer paths, but that would involve
// analyzing all our usage of files.
if (stripped_from.value().length() >= MAX_PATH ||
stripped_to.value().length() >= MAX_PATH) {
return false;
}
// SHFILEOPSTRUCT wants the path to be terminated with two NULLs,
// so we have to use wcscpy because wcscpy_s writes non-NULLs
// into the rest of the buffer.
wchar_t double_terminated_path_from[MAX_PATH + 1] = {0};
wchar_t double_terminated_path_to[MAX_PATH + 1] = {0};
#pragma warning(suppress:4996) // don't complain about wcscpy deprecation
wcscpy(double_terminated_path_from, stripped_from.value().c_str());
#pragma warning(suppress:4996) // don't complain about wcscpy deprecation
wcscpy(double_terminated_path_to, stripped_to.value().c_str());
SHFILEOPSTRUCT file_operation = {0};
file_operation.wFunc = FO_COPY;
file_operation.pFrom = double_terminated_path_from;
file_operation.pTo = double_terminated_path_to;
file_operation.fFlags = FOF_NOERRORUI | FOF_SILENT | FOF_NOCONFIRMATION |
FOF_NOCONFIRMMKDIR;
if (!recursive)
file_operation.fFlags |= FOF_NORECURSION | FOF_FILESONLY;
return (SHFileOperation(&file_operation) == 0);
}
} // namespace
FilePath MakeAbsoluteFilePath(const FilePath& input) {
@ -88,11 +52,16 @@ bool DeleteFile(const FilePath& path, bool recursive) {
if (path.value().length() >= MAX_PATH)
return false;
// On XP SHFileOperation will return ERROR_ACCESS_DENIED instead of
// ERROR_FILE_NOT_FOUND, so just shortcut this here.
if (path.empty())
return true;
if (!recursive) {
// If not recursing, then first check to see if |path| is a directory.
// If it is, then remove it with RemoveDirectory.
PlatformFileInfo file_info;
if (file_util::GetFileInfo(path, &file_info) && file_info.is_directory)
File::Info file_info;
if (GetFileInfo(path, &file_info) && file_info.is_directory)
return RemoveDirectory(path.value().c_str()) != 0;
// Otherwise, it's a file, wildcard or non-existant. Try DeleteFile first
@ -107,8 +76,6 @@ bool DeleteFile(const FilePath& path, bool recursive) {
// into the rest of the buffer.
wchar_t double_terminated_path[MAX_PATH + 1] = {0};
#pragma warning(suppress:4996) // don't complain about wcscpy deprecation
if (g_bug108724_debug)
LOG(WARNING) << "copying ";
wcscpy(double_terminated_path, path.value().c_str());
SHFILEOPSTRUCT file_operation = {0};
@ -117,11 +84,7 @@ bool DeleteFile(const FilePath& path, bool recursive) {
file_operation.fFlags = FOF_NOERRORUI | FOF_SILENT | FOF_NOCONFIRMATION;
if (!recursive)
file_operation.fFlags |= FOF_NORECURSION | FOF_FILESONLY;
if (g_bug108724_debug)
LOG(WARNING) << "Performing shell operation";
int err = SHFileOperation(&file_operation);
if (g_bug108724_debug)
LOG(WARNING) << "Done: " << err;
// Since we're passing flags to the operation telling it to be silent,
// it's possible for the operation to be aborted/cancelled without err
@ -132,8 +95,10 @@ bool DeleteFile(const FilePath& path, bool recursive) {
// Some versions of Windows return ERROR_FILE_NOT_FOUND (0x2) when deleting
// an empty directory and some return 0x402 when they should be returning
// ERROR_FILE_NOT_FOUND. MSDN says Vista and up won't return 0x402.
return (err == 0 || err == ERROR_FILE_NOT_FOUND || err == 0x402);
// ERROR_FILE_NOT_FOUND. MSDN says Vista and up won't return 0x402. Windows 7
// can return DE_INVALIDFILES (0x7C) for nonexistent directories.
return (err == 0 || err == ERROR_FILE_NOT_FOUND || err == 0x402 ||
err == 0x7C);
}
bool DeleteFileAfterReboot(const FilePath& path) {
@ -149,7 +114,7 @@ bool DeleteFileAfterReboot(const FilePath& path) {
bool ReplaceFile(const FilePath& from_path,
const FilePath& to_path,
PlatformFileError* error) {
File::Error* error) {
ThreadRestrictions::AssertIOAllowed();
// Try a simple move first. It will only succeed when |to_path| doesn't
// already exist.
@ -164,33 +129,99 @@ bool ReplaceFile(const FilePath& from_path,
return true;
}
if (error)
*error = LastErrorToPlatformFileError(GetLastError());
*error = File::OSErrorToFileError(GetLastError());
return false;
}
bool CopyDirectory(const FilePath& from_path, const FilePath& to_path,
bool recursive) {
// NOTE(maruel): Previous version of this function used to call
// SHFileOperation(). This used to copy the file attributes and extended
// attributes, OLE structured storage, NTFS file system alternate data
// streams, SECURITY_DESCRIPTOR. In practice, this is not what we want, we
// want the containing directory to propagate its SECURITY_DESCRIPTOR.
ThreadRestrictions::AssertIOAllowed();
if (recursive)
return ShellCopy(from_path, to_path, true);
// The following code assumes that from path is a directory.
DCHECK(DirectoryExists(from_path));
// Instead of creating a new directory, we copy the old one to include the
// security information of the folder as part of the copy.
if (!PathExists(to_path)) {
// Except that Vista fails to do that, and instead do a recursive copy if
// the target directory doesn't exist.
if (base::win::GetVersion() >= base::win::VERSION_VISTA)
file_util::CreateDirectory(to_path);
else
ShellCopy(from_path, to_path, false);
// NOTE: I suspect we could support longer paths, but that would involve
// analyzing all our usage of files.
if (from_path.value().length() >= MAX_PATH ||
to_path.value().length() >= MAX_PATH) {
return false;
}
FilePath directory = from_path.Append(L"*.*");
return ShellCopy(directory, to_path, false);
// This function does not properly handle destinations within the source.
FilePath real_to_path = to_path;
if (PathExists(real_to_path)) {
real_to_path = MakeAbsoluteFilePath(real_to_path);
if (real_to_path.empty())
return false;
} else {
real_to_path = MakeAbsoluteFilePath(real_to_path.DirName());
if (real_to_path.empty())
return false;
}
FilePath real_from_path = MakeAbsoluteFilePath(from_path);
if (real_from_path.empty())
return false;
if (real_to_path.value().size() >= real_from_path.value().size() &&
real_to_path.value().compare(0, real_from_path.value().size(),
real_from_path.value()) == 0) {
return false;
}
int traverse_type = FileEnumerator::FILES;
if (recursive)
traverse_type |= FileEnumerator::DIRECTORIES;
FileEnumerator traversal(from_path, recursive, traverse_type);
if (!PathExists(from_path)) {
DLOG(ERROR) << "CopyDirectory() couldn't stat source directory: "
<< from_path.value().c_str();
return false;
}
// TODO(maruel): This is not necessary anymore.
DCHECK(recursive || DirectoryExists(from_path));
FilePath current = from_path;
bool from_is_dir = DirectoryExists(from_path);
bool success = true;
FilePath from_path_base = from_path;
if (recursive && DirectoryExists(to_path)) {
// If the destination already exists and is a directory, then the
// top level of source needs to be copied.
from_path_base = from_path.DirName();
}
while (success && !current.empty()) {
// current is the source path, including from_path, so append
// the suffix after from_path to to_path to create the target_path.
FilePath target_path(to_path);
if (from_path_base != current) {
if (!from_path_base.AppendRelativePath(current, &target_path)) {
success = false;
break;
}
}
if (from_is_dir) {
if (!DirectoryExists(target_path) &&
!::CreateDirectory(target_path.value().c_str(), NULL)) {
DLOG(ERROR) << "CopyDirectory() couldn't create directory: "
<< target_path.value().c_str();
success = false;
}
} else if (!internal::CopyFileUnsafe(current, target_path)) {
DLOG(ERROR) << "CopyDirectory() couldn't create file: "
<< target_path.value().c_str();
success = false;
}
current = traversal.Next();
if (!current.empty())
from_is_dir = traversal.GetInfo().IsDirectory();
}
return success;
}
bool PathExists(const FilePath& path) {
@ -219,19 +250,7 @@ bool DirectoryExists(const FilePath& path) {
return false;
}
} // namespace base
// -----------------------------------------------------------------------------
namespace file_util {
using base::DirectoryExists;
using base::FilePath;
using base::kFileShareAll;
bool GetTempDir(FilePath* path) {
base::ThreadRestrictions::AssertIOAllowed();
wchar_t temp_path[MAX_PATH + 1];
DWORD path_len = ::GetTempPath(MAX_PATH, temp_path);
if (path_len >= MAX_PATH || path_len <= 0)
@ -243,12 +262,25 @@ bool GetTempDir(FilePath* path) {
return true;
}
bool GetShmemTempDir(FilePath* path, bool executable) {
return GetTempDir(path);
FilePath GetHomeDir() {
char16 result[MAX_PATH];
if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PROFILE, NULL, SHGFP_TYPE_CURRENT,
result)) &&
result[0]) {
return FilePath(result);
}
// Fall back to the temporary directory on failure.
FilePath temp;
if (GetTempDir(&temp))
return temp;
// Last resort.
return FilePath(L"C:\\");
}
bool CreateTemporaryFile(FilePath* path) {
base::ThreadRestrictions::AssertIOAllowed();
ThreadRestrictions::AssertIOAllowed();
FilePath temp_file;
@ -263,17 +295,12 @@ bool CreateTemporaryFile(FilePath* path) {
return false;
}
FILE* CreateAndOpenTemporaryShmemFile(FilePath* path, bool executable) {
base::ThreadRestrictions::AssertIOAllowed();
return CreateAndOpenTemporaryFile(path);
}
// On POSIX we have semantics to create and open a temporary file
// atomically.
// TODO(jrg): is there equivalent call to use on Windows instead of
// going 2-step?
FILE* CreateAndOpenTemporaryFileInDir(const FilePath& dir, FilePath* path) {
base::ThreadRestrictions::AssertIOAllowed();
ThreadRestrictions::AssertIOAllowed();
if (!CreateTemporaryFileInDir(dir, path)) {
return NULL;
}
@ -283,14 +310,14 @@ FILE* CreateAndOpenTemporaryFileInDir(const FilePath& dir, FilePath* path) {
return OpenFile(*path, "wb+");
}
bool CreateTemporaryFileInDir(const FilePath& dir,
FilePath* temp_file) {
base::ThreadRestrictions::AssertIOAllowed();
bool CreateTemporaryFileInDir(const FilePath& dir, FilePath* temp_file) {
ThreadRestrictions::AssertIOAllowed();
wchar_t temp_name[MAX_PATH + 1];
if (!GetTempFileName(dir.value().c_str(), L"", 0, temp_name)) {
DPLOG(WARNING) << "Failed to get temporary file name in " << dir.value();
DPLOG(WARNING) << "Failed to get temporary file name in "
<< UTF16ToUTF8(dir.value());
return false;
}
@ -311,7 +338,7 @@ bool CreateTemporaryFileInDir(const FilePath& dir,
bool CreateTemporaryDirInDir(const FilePath& base_dir,
const FilePath::StringType& prefix,
FilePath* new_dir) {
base::ThreadRestrictions::AssertIOAllowed();
ThreadRestrictions::AssertIOAllowed();
FilePath path_to_create;
@ -320,9 +347,9 @@ bool CreateTemporaryDirInDir(const FilePath& base_dir,
// the one exists, keep trying another path name until we reach some limit.
string16 new_dir_name;
new_dir_name.assign(prefix);
new_dir_name.append(base::IntToString16(::base::GetCurrentProcId()));
new_dir_name.append(IntToString16(GetCurrentProcId()));
new_dir_name.push_back('_');
new_dir_name.append(base::IntToString16(base::RandInt(0, kint16max)));
new_dir_name.append(IntToString16(RandInt(0, kint16max)));
path_to_create = base_dir.Append(new_dir_name);
if (::CreateDirectory(path_to_create.value().c_str(), NULL)) {
@ -336,7 +363,7 @@ bool CreateTemporaryDirInDir(const FilePath& base_dir,
bool CreateNewTempDirectory(const FilePath::StringType& prefix,
FilePath* new_temp_path) {
base::ThreadRestrictions::AssertIOAllowed();
ThreadRestrictions::AssertIOAllowed();
FilePath system_temp_dir;
if (!GetTempDir(&system_temp_dir))
@ -346,8 +373,8 @@ bool CreateNewTempDirectory(const FilePath::StringType& prefix,
}
bool CreateDirectoryAndGetError(const FilePath& full_path,
base::PlatformFileError* error) {
base::ThreadRestrictions::AssertIOAllowed();
File::Error* error) {
ThreadRestrictions::AssertIOAllowed();
// If the path exists, we've succeeded if it's a directory, failed otherwise.
const wchar_t* full_path_str = full_path.value().c_str();
@ -361,7 +388,7 @@ bool CreateDirectoryAndGetError(const FilePath& full_path,
DLOG(WARNING) << "CreateDirectory(" << full_path_str << "), "
<< "conflicts with existing file.";
if (error) {
*error = base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY;
*error = File::FILE_ERROR_NOT_A_DIRECTORY;
}
return false;
}
@ -374,14 +401,14 @@ bool CreateDirectoryAndGetError(const FilePath& full_path,
FilePath parent_path(full_path.DirName());
if (parent_path.value() == full_path.value()) {
if (error) {
*error = base::PLATFORM_FILE_ERROR_NOT_FOUND;
*error = File::FILE_ERROR_NOT_FOUND;
}
return false;
}
if (!CreateDirectoryAndGetError(parent_path, error)) {
DLOG(WARNING) << "Failed to create one of the parent directories.";
if (error) {
DCHECK(*error != base::PLATFORM_FILE_OK);
DCHECK(*error != File::FILE_OK);
}
return false;
}
@ -396,7 +423,7 @@ bool CreateDirectoryAndGetError(const FilePath& full_path,
return true;
} else {
if (error)
*error = base::LastErrorToPlatformFileError(error_code);
*error = File::OSErrorToFileError(error_code);
DLOG(WARNING) << "Failed to create directory " << full_path_str
<< ", last error is " << error_code << ".";
return false;
@ -406,155 +433,8 @@ bool CreateDirectoryAndGetError(const FilePath& full_path,
}
}
// TODO(rkc): Work out if we want to handle NTFS junctions here or not, handle
// them if we do decide to.
bool IsLink(const FilePath& file_path) {
return false;
}
bool GetFileInfo(const FilePath& file_path, base::PlatformFileInfo* results) {
base::ThreadRestrictions::AssertIOAllowed();
WIN32_FILE_ATTRIBUTE_DATA attr;
if (!GetFileAttributesEx(file_path.value().c_str(),
GetFileExInfoStandard, &attr)) {
return false;
}
ULARGE_INTEGER size;
size.HighPart = attr.nFileSizeHigh;
size.LowPart = attr.nFileSizeLow;
results->size = size.QuadPart;
results->is_directory =
(attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
results->last_modified = base::Time::FromFileTime(attr.ftLastWriteTime);
results->last_accessed = base::Time::FromFileTime(attr.ftLastAccessTime);
results->creation_time = base::Time::FromFileTime(attr.ftCreationTime);
return true;
}
FILE* OpenFile(const FilePath& filename, const char* mode) {
base::ThreadRestrictions::AssertIOAllowed();
std::wstring w_mode = ASCIIToWide(std::string(mode));
return _wfsopen(filename.value().c_str(), w_mode.c_str(), _SH_DENYNO);
}
FILE* OpenFile(const std::string& filename, const char* mode) {
base::ThreadRestrictions::AssertIOAllowed();
return _fsopen(filename.c_str(), mode, _SH_DENYNO);
}
int ReadFile(const FilePath& filename, char* data, int size) {
base::ThreadRestrictions::AssertIOAllowed();
base::win::ScopedHandle file(CreateFile(filename.value().c_str(),
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_SEQUENTIAL_SCAN,
NULL));
if (!file)
return -1;
DWORD read;
if (::ReadFile(file, data, size, &read, NULL) &&
static_cast<int>(read) == size)
return read;
return -1;
}
int WriteFile(const FilePath& filename, const char* data, int size) {
base::ThreadRestrictions::AssertIOAllowed();
base::win::ScopedHandle file(CreateFile(filename.value().c_str(),
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
0,
NULL));
if (!file) {
DLOG_GETLASTERROR(WARNING) << "CreateFile failed for path "
<< filename.value();
return -1;
}
DWORD written;
BOOL result = ::WriteFile(file, data, size, &written, NULL);
if (result && static_cast<int>(written) == size)
return written;
if (!result) {
// WriteFile failed.
DLOG_GETLASTERROR(WARNING) << "writing file " << filename.value()
<< " failed";
} else {
// Didn't write all the bytes.
DLOG(WARNING) << "wrote" << written << " bytes to "
<< filename.value() << " expected " << size;
}
return -1;
}
int AppendToFile(const FilePath& filename, const char* data, int size) {
base::ThreadRestrictions::AssertIOAllowed();
base::win::ScopedHandle file(CreateFile(filename.value().c_str(),
FILE_APPEND_DATA,
0,
NULL,
OPEN_EXISTING,
0,
NULL));
if (!file) {
DLOG_GETLASTERROR(WARNING) << "CreateFile failed for path "
<< filename.value();
return -1;
}
DWORD written;
BOOL result = ::WriteFile(file, data, size, &written, NULL);
if (result && static_cast<int>(written) == size)
return written;
if (!result) {
// WriteFile failed.
DLOG_GETLASTERROR(WARNING) << "writing file " << filename.value()
<< " failed";
} else {
// Didn't write all the bytes.
DLOG(WARNING) << "wrote" << written << " bytes to "
<< filename.value() << " expected " << size;
}
return -1;
}
// Gets the current working directory for the process.
bool GetCurrentDirectory(FilePath* dir) {
base::ThreadRestrictions::AssertIOAllowed();
wchar_t system_buffer[MAX_PATH];
system_buffer[0] = 0;
DWORD len = ::GetCurrentDirectory(MAX_PATH, system_buffer);
if (len == 0 || len > MAX_PATH)
return false;
// TODO(evanm): the old behavior of this function was to always strip the
// trailing slash. We duplicate this here, but it shouldn't be necessary
// when everyone is using the appropriate FilePath APIs.
std::wstring dir_str(system_buffer);
*dir = FilePath(dir_str).StripTrailingSeparators();
return true;
}
// Sets the current working directory for the process.
bool SetCurrentDirectory(const FilePath& directory) {
base::ThreadRestrictions::AssertIOAllowed();
BOOL ret = ::SetCurrentDirectory(directory.value().c_str());
return ret != 0;
}
bool NormalizeFilePath(const FilePath& path, FilePath* real_path) {
base::ThreadRestrictions::AssertIOAllowed();
ThreadRestrictions::AssertIOAllowed();
FilePath mapped_file;
if (!NormalizeToNativeFilePath(path, &mapped_file))
return false;
@ -567,7 +447,7 @@ bool NormalizeFilePath(const FilePath& path, FilePath* real_path) {
bool DevicePathToDriveLetterPath(const FilePath& nt_device_path,
FilePath* out_drive_letter_path) {
base::ThreadRestrictions::AssertIOAllowed();
ThreadRestrictions::AssertIOAllowed();
// Get the mapping of drive letters to device paths.
const int kDriveMappingSize = 1024;
@ -610,7 +490,7 @@ bool DevicePathToDriveLetterPath(const FilePath& nt_device_path,
}
bool NormalizeToNativeFilePath(const FilePath& path, FilePath* nt_path) {
base::ThreadRestrictions::AssertIOAllowed();
ThreadRestrictions::AssertIOAllowed();
// In Vista, GetFinalPathNameByHandle() would give us the real path
// from a file handle. If we ever deprecate XP, consider changing the
// code below to a call to GetFinalPathNameByHandle(). The method this
@ -664,8 +544,164 @@ bool NormalizeToNativeFilePath(const FilePath& path, FilePath* nt_path) {
return success;
}
// TODO(rkc): Work out if we want to handle NTFS junctions here or not, handle
// them if we do decide to.
bool IsLink(const FilePath& file_path) {
return false;
}
bool GetFileInfo(const FilePath& file_path, File::Info* results) {
ThreadRestrictions::AssertIOAllowed();
WIN32_FILE_ATTRIBUTE_DATA attr;
if (!GetFileAttributesEx(file_path.value().c_str(),
GetFileExInfoStandard, &attr)) {
return false;
}
ULARGE_INTEGER size;
size.HighPart = attr.nFileSizeHigh;
size.LowPart = attr.nFileSizeLow;
results->size = size.QuadPart;
results->is_directory =
(attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
results->last_modified = Time::FromFileTime(attr.ftLastWriteTime);
results->last_accessed = Time::FromFileTime(attr.ftLastAccessTime);
results->creation_time = Time::FromFileTime(attr.ftCreationTime);
return true;
}
FILE* OpenFile(const FilePath& filename, const char* mode) {
ThreadRestrictions::AssertIOAllowed();
std::wstring w_mode = ASCIIToWide(std::string(mode));
return _wfsopen(filename.value().c_str(), w_mode.c_str(), _SH_DENYNO);
}
FILE* FileToFILE(File file, const char* mode) {
if (!file.IsValid())
return NULL;
int fd =
_open_osfhandle(reinterpret_cast<intptr_t>(file.GetPlatformFile()), 0);
if (fd < 0)
return NULL;
file.TakePlatformFile();
FILE* stream = _fdopen(fd, mode);
if (!stream)
_close(fd);
return stream;
}
int ReadFile(const FilePath& filename, char* data, int max_size) {
ThreadRestrictions::AssertIOAllowed();
base::win::ScopedHandle file(CreateFile(filename.value().c_str(),
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_SEQUENTIAL_SCAN,
NULL));
if (!file)
return -1;
DWORD read;
if (::ReadFile(file, data, max_size, &read, NULL))
return read;
return -1;
}
int WriteFile(const FilePath& filename, const char* data, int size) {
ThreadRestrictions::AssertIOAllowed();
base::win::ScopedHandle file(CreateFile(filename.value().c_str(),
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
0,
NULL));
if (!file) {
DPLOG(WARNING) << "CreateFile failed for path "
<< UTF16ToUTF8(filename.value());
return -1;
}
DWORD written;
BOOL result = ::WriteFile(file, data, size, &written, NULL);
if (result && static_cast<int>(written) == size)
return written;
if (!result) {
// WriteFile failed.
DPLOG(WARNING) << "writing file " << UTF16ToUTF8(filename.value())
<< " failed";
} else {
// Didn't write all the bytes.
DLOG(WARNING) << "wrote" << written << " bytes to "
<< UTF16ToUTF8(filename.value()) << " expected " << size;
}
return -1;
}
int AppendToFile(const FilePath& filename, const char* data, int size) {
ThreadRestrictions::AssertIOAllowed();
base::win::ScopedHandle file(CreateFile(filename.value().c_str(),
FILE_APPEND_DATA,
0,
NULL,
OPEN_EXISTING,
0,
NULL));
if (!file) {
DPLOG(WARNING) << "CreateFile failed for path "
<< UTF16ToUTF8(filename.value());
return -1;
}
DWORD written;
BOOL result = ::WriteFile(file, data, size, &written, NULL);
if (result && static_cast<int>(written) == size)
return written;
if (!result) {
// WriteFile failed.
DPLOG(WARNING) << "writing file " << UTF16ToUTF8(filename.value())
<< " failed";
} else {
// Didn't write all the bytes.
DLOG(WARNING) << "wrote" << written << " bytes to "
<< UTF16ToUTF8(filename.value()) << " expected " << size;
}
return -1;
}
// Gets the current working directory for the process.
bool GetCurrentDirectory(FilePath* dir) {
ThreadRestrictions::AssertIOAllowed();
wchar_t system_buffer[MAX_PATH];
system_buffer[0] = 0;
DWORD len = ::GetCurrentDirectory(MAX_PATH, system_buffer);
if (len == 0 || len > MAX_PATH)
return false;
// TODO(evanm): the old behavior of this function was to always strip the
// trailing slash. We duplicate this here, but it shouldn't be necessary
// when everyone is using the appropriate FilePath APIs.
std::wstring dir_str(system_buffer);
*dir = FilePath(dir_str).StripTrailingSeparators();
return true;
}
// Sets the current working directory for the process.
bool SetCurrentDirectory(const FilePath& directory) {
ThreadRestrictions::AssertIOAllowed();
BOOL ret = ::SetCurrentDirectory(directory.value().c_str());
return ret != 0;
}
int GetMaximumPathComponentLength(const FilePath& path) {
base::ThreadRestrictions::AssertIOAllowed();
ThreadRestrictions::AssertIOAllowed();
wchar_t volume_path[MAX_PATH];
if (!GetVolumePathNameW(path.NormalizePathSeparators().value().c_str(),
@ -688,9 +724,8 @@ int GetMaximumPathComponentLength(const FilePath& path) {
return std::min(whole_path_limit, static_cast<int>(max_length));
}
} // namespace file_util
// -----------------------------------------------------------------------------
namespace base {
namespace internal {
bool MoveUnsafe(const FilePath& from_path, const FilePath& to_path) {
@ -736,8 +771,24 @@ bool CopyFileUnsafe(const FilePath& from_path, const FilePath& to_path) {
to_path.value().length() >= MAX_PATH) {
return false;
}
return (::CopyFile(from_path.value().c_str(), to_path.value().c_str(),
false) != 0);
// Unlike the posix implementation that copies the file manually and discards
// the ACL bits, CopyFile() copies the complete SECURITY_DESCRIPTOR and access
// bits, which is usually not what we want. We can't do much about the
// SECURITY_DESCRIPTOR but at least remove the read only bit.
const wchar_t* dest = to_path.value().c_str();
if (!::CopyFile(from_path.value().c_str(), dest, false)) {
// Copy failed.
return false;
}
DWORD attrs = GetFileAttributes(dest);
if (attrs == INVALID_FILE_ATTRIBUTES) {
return false;
}
if (attrs & FILE_ATTRIBUTE_READONLY) {
SetFileAttributes(dest, attrs & ~FILE_ATTRIBUTE_READONLY);
}
return true;
}
bool CopyAndDeleteDirectory(const FilePath& from_path,

Просмотреть файл

@ -189,6 +189,13 @@ class BASE_EXPORT FilePath {
// Returns a vector of all of the components of the provided path. It is
// equivalent to calling DirName().value() on the path's root component,
// and BaseName().value() on each child component.
//
// To make sure this is lossless so we can differentiate absolute and
// relative paths, the root slash will be included even though no other
// slashes will be. The precise behavior is:
//
// Posix: "/foo/bar" -> [ "/", "foo", "bar" ]
// Windows: "C:\foo\bar" -> [ "C:", "\\", "foo", "bar" ]
void GetComponents(std::vector<FilePath::StringType>* components) const;
// Returns true if this FilePath is a strict parent of the |child|. Absolute
@ -224,18 +231,33 @@ class BASE_EXPORT FilePath {
// Returns ".jpg" for path "C:\pics\jojo.jpg", or an empty string if
// the file has no extension. If non-empty, Extension() will always start
// with precisely one ".". The following code should always work regardless
// of the value of path.
// of the value of path. For common double-extensions like .tar.gz and
// .user.js, this method returns the combined extension. For a single
// component, use FinalExtension().
// new_path = path.RemoveExtension().value().append(path.Extension());
// ASSERT(new_path == path.value());
// NOTE: this is different from the original file_util implementation which
// returned the extension without a leading "." ("jpg" instead of ".jpg")
StringType Extension() const;
// Returns the path's file extension, as in Extension(), but will
// never return a double extension.
//
// TODO(davidben): Check all our extension-sensitive code to see if
// we can rename this to Extension() and the other to something like
// LongExtension(), defaulting to short extensions and leaving the
// long "extensions" to logic like base::GetUniquePathNumber().
StringType FinalExtension() const;
// Returns "C:\pics\jojo" for path "C:\pics\jojo.jpg"
// NOTE: this is slightly different from the similar file_util implementation
// which returned simply 'jojo'.
FilePath RemoveExtension() const WARN_UNUSED_RESULT;
// Removes the path's file extension, as in RemoveExtension(), but
// ignores double extensions.
FilePath RemoveFinalExtension() const WARN_UNUSED_RESULT;
// Inserts |suffix| after the file name portion of |path| but before the
// extension. Returns "" if BaseName() == "." or "..".
// Examples:
@ -299,8 +321,8 @@ class BASE_EXPORT FilePath {
// separator.
FilePath StripTrailingSeparators() const WARN_UNUSED_RESULT;
// Returns true if this FilePath contains any attempt to reference a parent
// directory (i.e. has a path component that is ".."
// Returns true if this FilePath contains an attempt to reference a parent
// directory (e.g. has a path component that is "..").
bool ReferencesParent() const;
// Return a Unicode human-readable version of this path.
@ -332,24 +354,6 @@ class BASE_EXPORT FilePath {
// Similar to AsUTF8Unsafe, but returns UTF-16 instead.
string16 AsUTF16Unsafe() const;
// Older Chromium code assumes that paths are always wstrings.
// This function converts wstrings to FilePaths, and is
// useful to smooth porting that old code to the FilePath API.
// It has "Hack" its name so people feel bad about using it.
// http://code.google.com/p/chromium/issues/detail?id=24672
//
// If you are trying to be a good citizen and remove these, ask yourself:
// - Am I interacting with other Chrome code that deals with files? Then
// try to convert the API into using FilePath.
// - Am I interacting with OS-native calls? Then use value() to get at an
// OS-native string format.
// - Am I using well-known file names, like "config.ini"? Then use the
// ASCII functions (we require paths to always be supersets of ASCII).
// - Am I displaying a string to the user in some UI? Then use the
// LossyDisplayName() function, but keep in mind that you can't
// ever use the result of that again as a path.
static FilePath FromWStringHack(const std::wstring& wstring);
// Returns a FilePath object from a path name in UTF-8. This function
// should only be used for cases where you are sure that the input
// string is UTF-8.
@ -370,6 +374,10 @@ class BASE_EXPORT FilePath {
// (if FILE_PATH_USES_WIN_SEPARATORS is true), or do nothing on POSIX systems.
FilePath NormalizePathSeparators() const;
// Normalize all path separattors to given type on Windows
// (if FILE_PATH_USES_WIN_SEPARATORS is true), or do nothing on POSIX systems.
FilePath NormalizePathSeparatorsTo(CharType separator) const;
// Compare two strings in the same way the file system does.
// Note that these always ignore case, even on file systems that are case-
// sensitive. If case-sensitive comparison is ever needed, add corresponding
@ -405,6 +413,15 @@ class BASE_EXPORT FilePath {
const StringType& string2);
#endif
#if defined(OS_ANDROID)
// On android, file selection dialog can return a file with content uri
// scheme(starting with content://). Content uri needs to be opened with
// ContentResolver to guarantee that the app has appropriate permissions
// to access it.
// Returns true if the path is a content uri, or false otherwise.
bool IsContentUri() const;
#endif
private:
// Remove trailing separators from this object. If the path is absolute, it
// will never be stripped any more than to refer to the absolute root

Просмотреть файл

@ -27,6 +27,6 @@ BASE_EXPORT bool IsValidGUID(const std::string& guid);
BASE_EXPORT std::string RandomDataToGUIDString(const uint64 bytes[2]);
#endif
} // namespace guid
} // namespace base
#endif // BASE_GUID_H_

Просмотреть файл

@ -57,7 +57,9 @@ namespace base {
template <typename Type>
struct DefaultLazyInstanceTraits {
static const bool kRegisterOnExit = true;
#ifndef NDEBUG
static const bool kAllowedToAccessOnNonjoinableThread = false;
#endif
static Type* New(void* instance) {
DCHECK_EQ(reinterpret_cast<uintptr_t>(instance) & (ALIGNOF(Type) - 1), 0u)
@ -89,7 +91,9 @@ namespace internal {
template <typename Type>
struct LeakyLazyInstanceTraits {
static const bool kRegisterOnExit = false;
#ifndef NDEBUG
static const bool kAllowedToAccessOnNonjoinableThread = true;
#endif
static Type* New(void* instance) {
ANNOTATE_SCOPED_MEMORY_LEAK;

Просмотреть файл

@ -5,7 +5,10 @@
#include "build/build_config.h"
#if defined(COMPILER_MSVC)
#include <intrin.h>
// MSDN says to #include <intrin.h>, but that breaks the VS2005 build.
extern "C" {
void* _ReturnAddress();
}
#endif
#include "base/location.h"
@ -89,11 +92,11 @@ __declspec(noinline)
BASE_EXPORT const void* GetProgramCounter() {
#if defined(COMPILER_MSVC)
return _ReturnAddress();
#elif defined(COMPILER_GCC)
#elif defined(COMPILER_GCC) && !defined(OS_NACL)
return __builtin_extract_return_addr(__builtin_return_address(0));
#endif // COMPILER_GCC
#else
return NULL;
#endif
}
} // namespace tracked_objects

Просмотреть файл

@ -52,10 +52,6 @@
//
// LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
//
// The above will cause log messages to be output on the 1st, 11th, 21st, ...
// times it is executed. Note that the special COUNTER value is used to
// identify which repetition is happening.
//
// The CHECK(condition) macro is active in both debug and release builds and
// effectively performs a LOG(FATAL) which terminates the process and
// generates a crashdump unless a debugger is attached.
@ -131,18 +127,13 @@
// GetLastError() on Windows and errno on POSIX).
//
// The supported severity levels for macros that allow you to specify one
// are (in increasing order of severity) INFO, WARNING, ERROR, ERROR_REPORT,
// and FATAL.
// are (in increasing order of severity) INFO, WARNING, ERROR, and FATAL.
//
// Very important: logging a message at the FATAL severity level causes
// the program to terminate (after the message is logged).
//
// Note the special severity of ERROR_REPORT only available/relevant in normal
// mode, which displays error dialog without terminating the program. There is
// no error dialog for severity ERROR or below in normal mode.
//
// There is also the special severity of DFATAL, which logs FATAL in
// debug mode, ERROR in normal mode.
// There is the special severity of DFATAL, which logs FATAL in debug mode,
// ERROR in normal mode.
namespace logging {
@ -175,7 +166,7 @@ enum LoggingDestination {
// Indicates that the log file should be locked when being written to.
// Unless there is only one single-threaded process that is logging to
// the log file, the file should be locked during writes to make each
// log outut atomic. Other writers will block.
// log output atomic. Other writers will block.
//
// All processes writing to the log file must have their locking set for it to
// work properly. Defaults to LOCK_LOG_FILE.
@ -185,11 +176,6 @@ enum LogLockingState { LOCK_LOG_FILE, DONT_LOCK_LOG_FILE };
// Defaults to APPEND_TO_OLD_LOG_FILE.
enum OldFileDeletionState { DELETE_OLD_LOG_FILE, APPEND_TO_OLD_LOG_FILE };
enum DcheckState {
DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS,
ENABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS
};
struct BASE_EXPORT LoggingSettings {
// The defaults values are:
//
@ -197,7 +183,6 @@ struct BASE_EXPORT LoggingSettings {
// log_file: NULL
// lock_log: LOCK_LOG_FILE
// delete_old: APPEND_TO_OLD_LOG_FILE
// dcheck_state: DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS
LoggingSettings();
LoggingDestination logging_dest;
@ -207,8 +192,6 @@ struct BASE_EXPORT LoggingSettings {
const PathChar* log_file;
LogLockingState lock_log;
OldFileDeletionState delete_old;
DcheckState dcheck_state;
};
// Define different names for the BaseInitLoggingImpl() function depending on
@ -288,13 +271,6 @@ BASE_EXPORT void SetShowErrorDialogs(bool enable_dialogs);
typedef void (*LogAssertHandlerFunction)(const std::string& str);
BASE_EXPORT void SetLogAssertHandler(LogAssertHandlerFunction handler);
// Sets the Log Report Handler that will be used to notify of check failures
// in non-debug mode. The default handler shows a dialog box and continues
// the execution, however clients can use this function to override with their
// own handling.
typedef void (*LogReportHandlerFunction)(const std::string& str);
BASE_EXPORT void SetLogReportHandler(LogReportHandlerFunction handler);
// Sets the Log Message Handler that gets passed every log message before
// it's sent to other log destinations (if any).
// Returns true to signal that it handled the message and the message
@ -311,9 +287,8 @@ const LogSeverity LOG_VERBOSE = -1; // This is level 1 verbosity
const LogSeverity LOG_INFO = 0;
const LogSeverity LOG_WARNING = 1;
const LogSeverity LOG_ERROR = 2;
const LogSeverity LOG_ERROR_REPORT = 3;
const LogSeverity LOG_FATAL = 4;
const LogSeverity LOG_NUM_SEVERITIES = 5;
const LogSeverity LOG_FATAL = 3;
const LogSeverity LOG_NUM_SEVERITIES = 4;
// LOG_DFATAL is LOG_FATAL in debug mode, ERROR in normal mode
#ifdef NDEBUG
@ -331,9 +306,6 @@ const LogSeverity LOG_DFATAL = LOG_FATAL;
logging::ClassName(__FILE__, __LINE__, logging::LOG_WARNING , ##__VA_ARGS__)
#define COMPACT_GOOGLE_LOG_EX_ERROR(ClassName, ...) \
logging::ClassName(__FILE__, __LINE__, logging::LOG_ERROR , ##__VA_ARGS__)
#define COMPACT_GOOGLE_LOG_EX_ERROR_REPORT(ClassName, ...) \
logging::ClassName(__FILE__, __LINE__, \
logging::LOG_ERROR_REPORT , ##__VA_ARGS__)
#define COMPACT_GOOGLE_LOG_EX_FATAL(ClassName, ...) \
logging::ClassName(__FILE__, __LINE__, logging::LOG_FATAL , ##__VA_ARGS__)
#define COMPACT_GOOGLE_LOG_EX_DFATAL(ClassName, ...) \
@ -345,8 +317,6 @@ const LogSeverity LOG_DFATAL = LOG_FATAL;
COMPACT_GOOGLE_LOG_EX_WARNING(LogMessage)
#define COMPACT_GOOGLE_LOG_ERROR \
COMPACT_GOOGLE_LOG_EX_ERROR(LogMessage)
#define COMPACT_GOOGLE_LOG_ERROR_REPORT \
COMPACT_GOOGLE_LOG_EX_ERROR_REPORT(LogMessage)
#define COMPACT_GOOGLE_LOG_FATAL \
COMPACT_GOOGLE_LOG_EX_FATAL(LogMessage)
#define COMPACT_GOOGLE_LOG_DFATAL \
@ -366,10 +336,9 @@ const LogSeverity LOG_DFATAL = LOG_FATAL;
const LogSeverity LOG_0 = LOG_ERROR;
#endif
// As special cases, we can assume that LOG_IS_ON(ERROR_REPORT) and
// LOG_IS_ON(FATAL) always hold. Also, LOG_IS_ON(DFATAL) always holds
// in debug mode. In particular, CHECK()s will always fire if they
// fail.
// As special cases, we can assume that LOG_IS_ON(FATAL) always holds. Also,
// LOG_IS_ON(DFATAL) always holds in debug mode. In particular, CHECK()s will
// always fire if they fail.
#define LOG_IS_ON(severity) \
((::logging::LOG_ ## severity) >= ::logging::GetMinLogLevel())
@ -438,29 +407,13 @@ const LogSeverity LOG_0 = LOG_ERROR;
SYSLOG_IF(FATAL, !(condition)) << "Assert failed: " #condition ". "
#if defined(OS_WIN)
#define LOG_GETLASTERROR_STREAM(severity) \
#define PLOG_STREAM(severity) \
COMPACT_GOOGLE_LOG_EX_ ## severity(Win32ErrorLogMessage, \
::logging::GetLastSystemErrorCode()).stream()
#define LOG_GETLASTERROR(severity) \
LAZY_STREAM(LOG_GETLASTERROR_STREAM(severity), LOG_IS_ON(severity))
#define LOG_GETLASTERROR_MODULE_STREAM(severity, module) \
COMPACT_GOOGLE_LOG_EX_ ## severity(Win32ErrorLogMessage, \
::logging::GetLastSystemErrorCode(), module).stream()
#define LOG_GETLASTERROR_MODULE(severity, module) \
LAZY_STREAM(LOG_GETLASTERROR_STREAM(severity, module), \
LOG_IS_ON(severity))
// PLOG_STREAM is used by PLOG, which is the usual error logging macro
// for each platform.
#define PLOG_STREAM(severity) LOG_GETLASTERROR_STREAM(severity)
#elif defined(OS_POSIX)
#define LOG_ERRNO_STREAM(severity) \
#define PLOG_STREAM(severity) \
COMPACT_GOOGLE_LOG_EX_ ## severity(ErrnoLogMessage, \
::logging::GetLastSystemErrorCode()).stream()
#define LOG_ERRNO(severity) \
LAZY_STREAM(LOG_ERRNO_STREAM(severity), LOG_IS_ON(severity))
// PLOG_STREAM is used by PLOG, which is the usual error logging macro
// for each platform.
#define PLOG_STREAM(severity) LOG_ERRNO_STREAM(severity)
#endif
#define PLOG(severity) \
@ -469,20 +422,6 @@ const LogSeverity LOG_0 = LOG_ERROR;
#define PLOG_IF(severity, condition) \
LAZY_STREAM(PLOG_STREAM(severity), LOG_IS_ON(severity) && (condition))
#if !defined(NDEBUG)
// Debug builds always include DCHECK and DLOG.
#undef LOGGING_IS_OFFICIAL_BUILD
#define LOGGING_IS_OFFICIAL_BUILD 0
#elif defined(OFFICIAL_BUILD)
// Official release builds always disable and remove DCHECK and DLOG.
#undef LOGGING_IS_OFFICIAL_BUILD
#define LOGGING_IS_OFFICIAL_BUILD 1
#elif !defined(LOGGING_IS_OFFICIAL_BUILD)
// Unless otherwise specified, unofficial release builds include
// DCHECK and DLOG.
#define LOGGING_IS_OFFICIAL_BUILD 0
#endif
// The actual stream used isn't important.
#define EAT_STREAM_PARAMETERS \
true ? (void) 0 : ::logging::LogMessageVoidify() & LOG_STREAM(FATAL)
@ -494,10 +433,10 @@ const LogSeverity LOG_0 = LOG_ERROR;
// We make sure CHECK et al. always evaluates their arguments, as
// doing CHECK(FunctionWithSideEffect()) is a common idiom.
#if LOGGING_IS_OFFICIAL_BUILD
#if defined(OFFICIAL_BUILD) && defined(NDEBUG) && !defined(OS_ANDROID)
// Make all CHECK functions discard their log strings to reduce code
// bloat for official builds.
// bloat for official release builds.
// TODO(akalin): This would be more valuable if there were some way to
// remove BreakDebugger() from the backtrace, perhaps by turning it
@ -594,22 +533,16 @@ DEFINE_CHECK_OP_IMPL(GT, > )
#define CHECK_GE(val1, val2) CHECK_OP(GE, >=, val1, val2)
#define CHECK_GT(val1, val2) CHECK_OP(GT, > , val1, val2)
#if LOGGING_IS_OFFICIAL_BUILD
// In order to have optimized code for official builds, remove DLOGs and
// DCHECKs.
#if defined(NDEBUG)
#define ENABLE_DLOG 0
#define ENABLE_DCHECK 0
#elif defined(NDEBUG)
// Otherwise, if we're a release build, remove DLOGs but not DCHECKs
// (since those can still be turned on via a command-line flag).
#define ENABLE_DLOG 0
#define ENABLE_DCHECK 1
#else
// Otherwise, we're a debug build so enable DLOGs and DCHECKs.
#define ENABLE_DLOG 1
#define ENABLE_DCHECK 1
#endif
#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
#define DCHECK_IS_ON 0
#else
#define DCHECK_IS_ON 1
#endif
// Definitions for DLOG et al.
@ -654,17 +587,6 @@ enum { DEBUG_MODE = ENABLE_DLOG };
#define DLOG(severity) \
LAZY_STREAM(LOG_STREAM(severity), DLOG_IS_ON(severity))
#if defined(OS_WIN)
#define DLOG_GETLASTERROR(severity) \
LAZY_STREAM(LOG_GETLASTERROR_STREAM(severity), DLOG_IS_ON(severity))
#define DLOG_GETLASTERROR_MODULE(severity, module) \
LAZY_STREAM(LOG_GETLASTERROR_STREAM(severity, module), \
DLOG_IS_ON(severity))
#elif defined(OS_POSIX)
#define DLOG_ERRNO(severity) \
LAZY_STREAM(LOG_ERRNO_STREAM(severity), DLOG_IS_ON(severity))
#endif
#define DPLOG(severity) \
LAZY_STREAM(PLOG_STREAM(severity), DLOG_IS_ON(severity))
@ -674,75 +596,40 @@ enum { DEBUG_MODE = ENABLE_DLOG };
// Definitions for DCHECK et al.
#if ENABLE_DCHECK
#if DCHECK_IS_ON
#if defined(NDEBUG)
BASE_EXPORT DcheckState get_dcheck_state();
BASE_EXPORT void set_dcheck_state(DcheckState state);
#if defined(DCHECK_ALWAYS_ON)
#define DCHECK_IS_ON() true
#define COMPACT_GOOGLE_LOG_EX_DCHECK(ClassName, ...) \
COMPACT_GOOGLE_LOG_EX_FATAL(ClassName , ##__VA_ARGS__)
#define COMPACT_GOOGLE_LOG_DCHECK COMPACT_GOOGLE_LOG_FATAL
const LogSeverity LOG_DCHECK = LOG_FATAL;
#else
#else // DCHECK_IS_ON
#define COMPACT_GOOGLE_LOG_EX_DCHECK(ClassName, ...) \
COMPACT_GOOGLE_LOG_EX_ERROR_REPORT(ClassName , ##__VA_ARGS__)
#define COMPACT_GOOGLE_LOG_DCHECK COMPACT_GOOGLE_LOG_ERROR_REPORT
const LogSeverity LOG_DCHECK = LOG_ERROR_REPORT;
#define DCHECK_IS_ON() \
((::logging::get_dcheck_state() == \
::logging::ENABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS) && \
LOG_IS_ON(DCHECK))
#endif // defined(DCHECK_ALWAYS_ON)
#else // defined(NDEBUG)
// On a regular debug build, we want to have DCHECKs enabled.
#define COMPACT_GOOGLE_LOG_EX_DCHECK(ClassName, ...) \
COMPACT_GOOGLE_LOG_EX_FATAL(ClassName , ##__VA_ARGS__)
#define COMPACT_GOOGLE_LOG_DCHECK COMPACT_GOOGLE_LOG_FATAL
const LogSeverity LOG_DCHECK = LOG_FATAL;
#define DCHECK_IS_ON() true
#endif // defined(NDEBUG)
#else // ENABLE_DCHECK
// These are just dummy values since DCHECK_IS_ON() is always false in
// this case.
// These are just dummy values.
#define COMPACT_GOOGLE_LOG_EX_DCHECK(ClassName, ...) \
COMPACT_GOOGLE_LOG_EX_INFO(ClassName , ##__VA_ARGS__)
#define COMPACT_GOOGLE_LOG_DCHECK COMPACT_GOOGLE_LOG_INFO
const LogSeverity LOG_DCHECK = LOG_INFO;
#define DCHECK_IS_ON() false
#endif // ENABLE_DCHECK
#undef ENABLE_DCHECK
#endif // DCHECK_IS_ON
// DCHECK et al. make sure to reference |condition| regardless of
// whether DCHECKs are enabled; this is so that we don't get unused
// variable warnings if the only use of a variable is in a DCHECK.
// This behavior is different from DLOG_IF et al.
#define DCHECK(condition) \
LAZY_STREAM(LOG_STREAM(DCHECK), DCHECK_IS_ON() && !(condition)) \
#define DCHECK(condition) \
LAZY_STREAM(LOG_STREAM(DCHECK), DCHECK_IS_ON && !(condition)) \
<< "Check failed: " #condition ". "
#define DPCHECK(condition) \
LAZY_STREAM(PLOG_STREAM(DCHECK), DCHECK_IS_ON() && !(condition)) \
#define DPCHECK(condition) \
LAZY_STREAM(PLOG_STREAM(DCHECK), DCHECK_IS_ON && !(condition)) \
<< "Check failed: " #condition ". "
// Helper macro for binary operators.
// Don't use this macro directly in your code, use DCHECK_EQ et al below.
#define DCHECK_OP(name, op, val1, val2) \
if (DCHECK_IS_ON()) \
if (DCHECK_IS_ON) \
if (std::string* _result = \
logging::Check##name##Impl((val1), (val2), \
#val1 " " #op " " #val2)) \
@ -776,7 +663,12 @@ const LogSeverity LOG_DCHECK = LOG_INFO;
#define DCHECK_GE(val1, val2) DCHECK_OP(GE, >=, val1, val2)
#define DCHECK_GT(val1, val2) DCHECK_OP(GT, > , val1, val2)
#if defined(NDEBUG) && defined(OS_CHROMEOS)
#define NOTREACHED() LOG(ERROR) << "NOTREACHED() hit in " << \
__FUNCTION__ << ". "
#else
#define NOTREACHED() DCHECK(false)
#endif
// Redefine the standard assert to use our nice log files
#undef assert
@ -792,32 +684,14 @@ const LogSeverity LOG_DCHECK = LOG_INFO;
// above.
class BASE_EXPORT LogMessage {
public:
LogMessage(const char* file, int line, LogSeverity severity, int ctr);
// Two special constructors that generate reduced amounts of code at
// LOG call sites for common cases.
//
// Used for LOG(INFO): Implied are:
// severity = LOG_INFO, ctr = 0
//
// Using this constructor instead of the more complex constructor above
// saves a couple of bytes per call site.
LogMessage(const char* file, int line);
// Used for LOG(severity) where severity != INFO. Implied
// are: ctr = 0
//
// Using this constructor instead of the more complex constructor above
// saves a couple of bytes per call site.
// Used for LOG(severity).
LogMessage(const char* file, int line, LogSeverity severity);
// A special constructor used for check failures. Takes ownership
// of the given string.
// Implied severity = LOG_FATAL
// Used for CHECK_EQ(), etc. Takes ownership of the given string.
// Implied severity = LOG_FATAL.
LogMessage(const char* file, int line, std::string* result);
// A special constructor used for check failures, with the option to
// specify severity. Takes ownership of the given string.
// Used for DCHECK_EQ(), etc. Takes ownership of the given string.
LogMessage(const char* file, int line, LogSeverity severity,
std::string* result);
@ -885,17 +759,12 @@ typedef int SystemErrorCode;
// Alias for ::GetLastError() on Windows and errno on POSIX. Avoids having to
// pull in windows.h just for GetLastError() and DWORD.
BASE_EXPORT SystemErrorCode GetLastSystemErrorCode();
BASE_EXPORT std::string SystemErrorCodeToString(SystemErrorCode error_code);
#if defined(OS_WIN)
// Appends a formatted system message of the GetLastError() type.
class BASE_EXPORT Win32ErrorLogMessage {
public:
Win32ErrorLogMessage(const char* file,
int line,
LogSeverity severity,
SystemErrorCode err,
const char* module);
Win32ErrorLogMessage(const char* file,
int line,
LogSeverity severity,
@ -908,8 +777,6 @@ class BASE_EXPORT Win32ErrorLogMessage {
private:
SystemErrorCode err_;
// Optional name of the module defining the error.
const char* module_;
LogMessage log_message_;
DISALLOW_COPY_AND_ASSIGN(Win32ErrorLogMessage);
@ -960,6 +827,15 @@ BASE_EXPORT std::wstring GetLogFileFullPath();
} // namespace logging
// Note that "The behavior of a C++ program is undefined if it adds declarations
// or definitions to namespace std or to a namespace within namespace std unless
// otherwise specified." --C++11[namespace.std]
//
// We've checked that this particular definition has the intended behavior on
// our implementations, but it's prone to breaking in the future, and please
// don't imitate this in your own definitions without checking with some
// standard library experts.
namespace std {
// These functions are provided as a convenience for logging, which is where we
// use streams (it is against Google style to use streams in other places). It
// is designed to allow you to emit non-ASCII Unicode strings to the log file,
@ -970,6 +846,7 @@ BASE_EXPORT std::ostream& operator<<(std::ostream& out, const wchar_t* wstr);
inline std::ostream& operator<<(std::ostream& out, const std::wstring& wstr) {
return out << wstr.c_str();
}
} // namespace std
// The NOTIMPLEMENTED() macro annotates codepaths which have
// not been implemented yet.

Просмотреть файл

@ -26,9 +26,9 @@
// // ... later, to release the memory:
// AlignedFree(my_array);
//
// Or using scoped_ptr_malloc:
// Or using scoped_ptr:
//
// scoped_ptr_malloc<float, ScopedPtrAlignedFree> my_array(
// scoped_ptr<float, AlignedFreeDeleter> my_array(
// static_cast<float*>(AlignedAlloc(size, alignment)));
#ifndef BASE_MEMORY_ALIGNED_MEMORY_H_
@ -101,9 +101,9 @@ inline void AlignedFree(void* ptr) {
#endif
}
// Helper class for use with scoped_ptr_malloc.
class BASE_EXPORT ScopedPtrAlignedFree {
public:
// Deleter for use with scoped_ptr. E.g., use as
// scoped_ptr<Foo, base::AlignedFreeDeleter> foo;
struct AlignedFreeDeleter {
inline void operator()(void* ptr) const {
AlignedFree(ptr);
}

Просмотреть файл

@ -3,54 +3,12 @@
// found in the LICENSE file.
#include "base/memory/ref_counted.h"
#include "base/logging.h"
#include "base/threading/thread_collision_warner.h"
namespace base {
namespace subtle {
RefCountedBase::RefCountedBase()
: ref_count_(0)
#ifndef NDEBUG
, in_dtor_(false)
#endif
{
}
RefCountedBase::~RefCountedBase() {
#ifndef NDEBUG
DCHECK(in_dtor_) << "RefCounted object deleted without calling Release()";
#endif
}
void RefCountedBase::AddRef() const {
// TODO(maruel): Add back once it doesn't assert 500 times/sec.
// Current thread books the critical section "AddRelease" without release it.
// DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_);
#ifndef NDEBUG
DCHECK(!in_dtor_);
#endif
++ref_count_;
}
bool RefCountedBase::Release() const {
// TODO(maruel): Add back once it doesn't assert 500 times/sec.
// Current thread books the critical section "AddRelease" without release it.
// DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_);
#ifndef NDEBUG
DCHECK(!in_dtor_);
#endif
if (--ref_count_ == 0) {
#ifndef NDEBUG
in_dtor_ = true;
#endif
return true;
}
return false;
}
bool RefCountedThreadSafeBase::HasOneRef() const {
return AtomicRefCountIsOne(
&const_cast<RefCountedThreadSafeBase*>(this)->ref_count_);

Просмотреть файл

@ -10,6 +10,9 @@
#include "base/atomic_ref_count.h"
#include "base/base_export.h"
#include "base/compiler_specific.h"
#ifndef NDEBUG
#include "base/logging.h"
#endif
#include "base/threading/thread_collision_warner.h"
namespace base {
@ -21,13 +24,49 @@ class BASE_EXPORT RefCountedBase {
bool HasOneRef() const { return ref_count_ == 1; }
protected:
RefCountedBase();
~RefCountedBase();
RefCountedBase()
: ref_count_(0)
#ifndef NDEBUG
, in_dtor_(false)
#endif
{
}
void AddRef() const;
~RefCountedBase() {
#ifndef NDEBUG
DCHECK(in_dtor_) << "RefCounted object deleted without calling Release()";
#endif
}
void AddRef() const {
// TODO(maruel): Add back once it doesn't assert 500 times/sec.
// Current thread books the critical section "AddRelease"
// without release it.
// DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_);
#ifndef NDEBUG
DCHECK(!in_dtor_);
#endif
++ref_count_;
}
// Returns true if the object should self-delete.
bool Release() const;
bool Release() const {
// TODO(maruel): Add back once it doesn't assert 500 times/sec.
// Current thread books the critical section "AddRelease"
// without release it.
// DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_);
#ifndef NDEBUG
DCHECK(!in_dtor_);
#endif
if (--ref_count_ == 0) {
#ifndef NDEBUG
in_dtor_ = true;
#endif
return true;
}
return false;
}
private:
mutable int ref_count_;
@ -251,7 +290,11 @@ class scoped_refptr {
}
T* get() const { return ptr_; }
// Allow scoped_refptr<C> to be used in boolean expression
// and comparison operations.
operator T*() const { return ptr_; }
T* operator->() const {
assert(ptr_ != NULL);
return ptr_;

Просмотреть файл

@ -2,10 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Scopers help you manage ownership of a pointer, helping you easily manage the
// a pointer within a scope, and automatically destroying the pointer at the
// end of a scope. There are two main classes you will use, which correspond
// to the operators new/delete and new[]/delete[].
// Scopers help you manage ownership of a pointer, helping you easily manage a
// pointer within a scope, and automatically destroying the pointer at the end
// of a scope. There are two main classes you will use, which correspond to the
// operators new/delete and new[]/delete[].
//
// Example usage (scoped_ptr<T>):
// {
@ -68,11 +68,11 @@
// is different though because we are constructing a temporary on the return
// line and thus can avoid needing to call Pass().
//
// Pass() properly handles upcast in assignment, i.e. you can assign
// scoped_ptr<Child> to scoped_ptr<Parent>:
// Pass() properly handles upcast in initialization, i.e. you can use a
// scoped_ptr<Child> to initialize a scoped_ptr<Parent>:
//
// scoped_ptr<Foo> foo(new Foo());
// scoped_ptr<FooParent> parent = foo.Pass();
// scoped_ptr<FooParent> parent(foo.Pass());
//
// PassAs<>() should be used to upcast return value in return statement:
//
@ -88,7 +88,7 @@
#define BASE_MEMORY_SCOPED_PTR_H_
// This is an implementation designed to match the anticipated future TR2
// implementation of the scoped_ptr class and scoped_ptr_malloc (deprecated).
// implementation of the scoped_ptr class.
#include <assert.h>
#include <stddef.h>
@ -227,7 +227,7 @@ class scoped_ptr_impl {
abort();
// Note that running data_.ptr = p can lead to undefined behavior if
// get_deleter()(get()) deletes this. In order to pevent this, reset()
// get_deleter()(get()) deletes this. In order to prevent this, reset()
// should update the stored pointer before deleting its old value.
//
// However, changing reset() to use that behavior may cause current code to
@ -570,134 +570,6 @@ bool operator!=(T* p1, const scoped_ptr<T, D>& p2) {
return p1 != p2.get();
}
// DEPRECATED: Use scoped_ptr<C, base::FreeDeleter> instead.
//
// scoped_ptr_malloc<> is similar to scoped_ptr<>, but it accepts a
// second template argument, the functor used to free the object.
template<class C, class FreeProc = base::FreeDeleter>
class scoped_ptr_malloc {
MOVE_ONLY_TYPE_FOR_CPP_03(scoped_ptr_malloc, RValue)
public:
// The element type
typedef C element_type;
// Constructor. Defaults to initializing with NULL.
// There is no way to create an uninitialized scoped_ptr.
// The input parameter must be allocated with an allocator that matches the
// Free functor. For the default Free functor, this is malloc, calloc, or
// realloc.
explicit scoped_ptr_malloc(C* p = NULL): ptr_(p) {}
// Constructor. Move constructor for C++03 move emulation of this type.
scoped_ptr_malloc(RValue rvalue)
: ptr_(rvalue.object->release()) {
}
// Destructor. If there is a C object, call the Free functor.
~scoped_ptr_malloc() {
reset();
}
// operator=. Move operator= for C++03 move emulation of this type.
scoped_ptr_malloc& operator=(RValue rhs) {
reset(rhs.object->release());
return *this;
}
// Reset. Calls the Free functor on the current owned object, if any.
// Then takes ownership of a new object, if given.
// this->reset(this->get()) works.
void reset(C* p = NULL) {
if (ptr_ != p) {
if (ptr_ != NULL) {
FreeProc free_proc;
free_proc(ptr_);
}
ptr_ = p;
}
}
// Get the current object.
// operator* and operator-> will cause an assert() failure if there is
// no current object.
C& operator*() const {
assert(ptr_ != NULL);
return *ptr_;
}
C* operator->() const {
assert(ptr_ != NULL);
return ptr_;
}
C* get() const {
return ptr_;
}
// Allow scoped_ptr_malloc<C> to be used in boolean expressions, but not
// implicitly convertible to a real bool (which is dangerous).
typedef C* scoped_ptr_malloc::*Testable;
operator Testable() const { return ptr_ ? &scoped_ptr_malloc::ptr_ : NULL; }
// Comparison operators.
// These return whether a scoped_ptr_malloc and a plain pointer refer
// to the same object, not just to two different but equal objects.
// For compatibility with the boost-derived implementation, these
// take non-const arguments.
bool operator==(C* p) const {
return ptr_ == p;
}
bool operator!=(C* p) const {
return ptr_ != p;
}
// Swap two scoped pointers.
void swap(scoped_ptr_malloc & b) {
C* tmp = b.ptr_;
b.ptr_ = ptr_;
ptr_ = tmp;
}
// Release a pointer.
// The return value is the current pointer held by this object.
// If this object holds a NULL pointer, the return value is NULL.
// After this operation, this object will hold a NULL pointer,
// and will not own the object any more.
C* release() WARN_UNUSED_RESULT {
C* tmp = ptr_;
ptr_ = NULL;
return tmp;
}
private:
C* ptr_;
// no reason to use these: each scoped_ptr_malloc should have its own object
template <class C2, class GP>
bool operator==(scoped_ptr_malloc<C2, GP> const& p) const;
template <class C2, class GP>
bool operator!=(scoped_ptr_malloc<C2, GP> const& p) const;
};
template<class C, class FP> inline
void swap(scoped_ptr_malloc<C, FP>& a, scoped_ptr_malloc<C, FP>& b) {
a.swap(b);
}
template<class C, class FP> inline
bool operator==(C* p, const scoped_ptr_malloc<C, FP>& b) {
return p == b.get();
}
template<class C, class FP> inline
bool operator!=(C* p, const scoped_ptr_malloc<C, FP>& b) {
return p != b.get();
}
// A function to convert T* into scoped_ptr<T>
// Doing e.g. make_scoped_ptr(new FooBarBaz<type>(arg)) is a shorter notation
// for scoped_ptr<FooBarBaz<type> >(new FooBarBaz<type>(arg))

Просмотреть файл

@ -18,7 +18,10 @@ subtle::AtomicWord WaitForInstance(subtle::AtomicWord* instance) {
// the object has been created.
subtle::AtomicWord value;
while (true) {
value = subtle::NoBarrier_Load(instance);
// The load has acquire memory ordering as the thread which reads the
// instance pointer must acquire visibility over the associated data.
// The pairing Release_Store operation is in Singleton::get().
value = subtle::Acquire_Load(instance);
if (value != kBeingCreatedMarker)
break;
PlatformThread::YieldCurrentThread();

Просмотреть файл

@ -63,10 +63,12 @@ struct DefaultSingletonTraits {
// exit. See below for the required call that makes this happen.
static const bool kRegisterAtExit = true;
#ifndef NDEBUG
// Set to false to disallow access on a non-joinable thread. This is
// different from kRegisterAtExit because StaticMemorySingletonTraits allows
// access on non-joinable threads, and gracefully handles this.
static const bool kAllowedToAccessOnNonjoinableThread = false;
#endif
};
@ -76,7 +78,9 @@ struct DefaultSingletonTraits {
template<typename Type>
struct LeakySingletonTraits : public DefaultSingletonTraits<Type> {
static const bool kRegisterAtExit = false;
#ifndef NDEBUG
static const bool kAllowedToAccessOnNonjoinableThread = true;
#endif
};
@ -229,7 +233,9 @@ class Singleton {
base::ThreadRestrictions::AssertSingletonAllowed();
#endif
base::subtle::AtomicWord value = base::subtle::NoBarrier_Load(&instance_);
// The load has acquire memory ordering as the thread which reads the
// instance_ pointer must acquire visibility over the singleton data.
base::subtle::AtomicWord value = base::subtle::Acquire_Load(&instance_);
if (value != 0 && value != base::internal::kBeingCreatedMarker) {
// See the corresponding HAPPENS_BEFORE below.
ANNOTATE_HAPPENS_AFTER(&instance_);
@ -248,6 +254,7 @@ class Singleton {
// synchronization between different threads calling get().
// See the corresponding HAPPENS_AFTER below and above.
ANNOTATE_HAPPENS_BEFORE(&instance_);
// Releases the visibility over instance_ to the readers.
base::subtle::Release_Store(
&instance_, reinterpret_cast<base::subtle::AtomicWord>(newval));

Просмотреть файл

@ -83,7 +83,7 @@ class BASE_EXPORT WeakReference {
public:
// Although Flag is bound to a specific thread, it may be deleted from another
// via base::WeakPtr::~WeakPtr().
class Flag : public RefCountedThreadSafe<Flag> {
class BASE_EXPORT Flag : public RefCountedThreadSafe<Flag> {
public:
Flag();

Просмотреть файл

@ -136,6 +136,16 @@
// choose the one that adheres to the standard.
//
//
// WHY HAVE typedef void MoveOnlyTypeForCPP03
//
// Callback<>/Bind() needs to understand movable-but-not-copyable semantics
// to call .Pass() appropriately when it is expected to transfer the value.
// The cryptic typedef MoveOnlyTypeForCPP03 is added to make this check
// easy and automatic in helper templates for Callback<>/Bind().
// See IsMoveOnlyType template and its usage in base/callback_internal.h
// for more details.
//
//
// COMPARED TO C++11
//
// In C++11, you would implement this functionality using an r-value reference
@ -202,6 +212,7 @@
public: \
operator rvalue_type() { return rvalue_type(this); } \
type Pass() { return type(rvalue_type(this)); } \
typedef void MoveOnlyTypeForCPP03; \
private:
#endif // BASE_MOVE_H_

Просмотреть файл

@ -41,13 +41,23 @@ class BASE_EXPORT PathService {
//
// WARNING: Consumers of PathService::Get may expect paths to be constant
// over the lifetime of the app, so this method should be used with caution.
//
// Unit tests generally should use ScopedPathOverride instead. Overrides from
// one test should not carry over to another.
static bool Override(int key, const base::FilePath& path);
// This function does the same as PathService::Override but it takes an extra
// parameter |create| which guides whether the directory to be overriden must
// This function does the same as PathService::Override but it takes extra
// parameters:
// - |is_absolute| indicates that |path| has already been expanded into an
// absolute path, otherwise MakeAbsoluteFilePath() will be used. This is
// useful to override paths that may not exist yet, since MakeAbsoluteFilePath
// fails for those. Note that MakeAbsoluteFilePath also expands symbolic
// links, even if path.IsAbsolute() is already true.
// - |create| guides whether the directory to be overriden must
// be created in case it doesn't exist already.
static bool OverrideAndCreateIfNeeded(int key,
const base::FilePath& path,
bool is_absolute,
bool create);
// To extend the set of supported keys, you can register a path provider,

Просмотреть файл

@ -1,254 +0,0 @@
// Copyright (c) 2012 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.
#ifndef BASE_PLATFORM_FILE_H_
#define BASE_PLATFORM_FILE_H_
#include "build/build_config.h"
#if defined(OS_WIN)
#include <windows.h>
#endif
#include <string>
#include "base/base_export.h"
#include "base/basictypes.h"
#include "base/files/file_path.h"
#include "base/time/time.h"
namespace base {
// PLATFORM_FILE_(OPEN|CREATE).* are mutually exclusive. You should specify
// exactly one of the five (possibly combining with other flags) when opening
// or creating a file.
// PLATFORM_FILE_(WRITE|APPEND) are mutually exclusive. This is so that APPEND
// behavior will be consistent with O_APPEND on POSIX.
enum PlatformFileFlags {
PLATFORM_FILE_OPEN = 1 << 0, // Opens a file, only if it exists.
PLATFORM_FILE_CREATE = 1 << 1, // Creates a new file, only if it
// does not already exist.
PLATFORM_FILE_OPEN_ALWAYS = 1 << 2, // May create a new file.
PLATFORM_FILE_CREATE_ALWAYS = 1 << 3, // May overwrite an old file.
PLATFORM_FILE_OPEN_TRUNCATED = 1 << 4, // Opens a file and truncates it,
// only if it exists.
PLATFORM_FILE_READ = 1 << 5,
PLATFORM_FILE_WRITE = 1 << 6,
PLATFORM_FILE_APPEND = 1 << 7,
PLATFORM_FILE_EXCLUSIVE_READ = 1 << 8, // EXCLUSIVE is opposite of Windows
// SHARE
PLATFORM_FILE_EXCLUSIVE_WRITE = 1 << 9,
PLATFORM_FILE_ASYNC = 1 << 10,
PLATFORM_FILE_TEMPORARY = 1 << 11, // Used on Windows only
PLATFORM_FILE_HIDDEN = 1 << 12, // Used on Windows only
PLATFORM_FILE_DELETE_ON_CLOSE = 1 << 13,
PLATFORM_FILE_WRITE_ATTRIBUTES = 1 << 14, // Used on Windows only
PLATFORM_FILE_ENUMERATE = 1 << 15, // May enumerate directory
PLATFORM_FILE_SHARE_DELETE = 1 << 16, // Used on Windows only
PLATFORM_FILE_TERMINAL_DEVICE = 1 << 17, // Serial port flags
PLATFORM_FILE_BACKUP_SEMANTICS = 1 << 18, // Used on Windows only
PLATFORM_FILE_EXECUTE = 1 << 19, // Used on Windows only
};
// PLATFORM_FILE_ERROR_ACCESS_DENIED is returned when a call fails because of
// a filesystem restriction. PLATFORM_FILE_ERROR_SECURITY is returned when a
// browser policy doesn't allow the operation to be executed.
enum PlatformFileError {
PLATFORM_FILE_OK = 0,
PLATFORM_FILE_ERROR_FAILED = -1,
PLATFORM_FILE_ERROR_IN_USE = -2,
PLATFORM_FILE_ERROR_EXISTS = -3,
PLATFORM_FILE_ERROR_NOT_FOUND = -4,
PLATFORM_FILE_ERROR_ACCESS_DENIED = -5,
PLATFORM_FILE_ERROR_TOO_MANY_OPENED = -6,
PLATFORM_FILE_ERROR_NO_MEMORY = -7,
PLATFORM_FILE_ERROR_NO_SPACE = -8,
PLATFORM_FILE_ERROR_NOT_A_DIRECTORY = -9,
PLATFORM_FILE_ERROR_INVALID_OPERATION = -10,
PLATFORM_FILE_ERROR_SECURITY = -11,
PLATFORM_FILE_ERROR_ABORT = -12,
PLATFORM_FILE_ERROR_NOT_A_FILE = -13,
PLATFORM_FILE_ERROR_NOT_EMPTY = -14,
PLATFORM_FILE_ERROR_INVALID_URL = -15,
PLATFORM_FILE_ERROR_IO = -16,
// Put new entries here and increment PLATFORM_FILE_ERROR_MAX.
PLATFORM_FILE_ERROR_MAX = -17
};
// This explicit mapping matches both FILE_ on Windows and SEEK_ on Linux.
enum PlatformFileWhence {
PLATFORM_FILE_FROM_BEGIN = 0,
PLATFORM_FILE_FROM_CURRENT = 1,
PLATFORM_FILE_FROM_END = 2
};
// Used to hold information about a given file.
// If you add more fields to this structure (platform-specific fields are OK),
// make sure to update all functions that use it in file_util_{win|posix}.cc
// too, and the ParamTraits<base::PlatformFileInfo> implementation in
// chrome/common/common_param_traits.cc.
struct BASE_EXPORT PlatformFileInfo {
PlatformFileInfo();
~PlatformFileInfo();
// The size of the file in bytes. Undefined when is_directory is true.
int64 size;
// True if the file corresponds to a directory.
bool is_directory;
// True if the file corresponds to a symbolic link.
bool is_symbolic_link;
// The last modified time of a file.
base::Time last_modified;
// The last accessed time of a file.
base::Time last_accessed;
// The creation time of a file.
base::Time creation_time;
};
#if defined(OS_WIN)
typedef HANDLE PlatformFile;
const PlatformFile kInvalidPlatformFileValue = INVALID_HANDLE_VALUE;
PlatformFileError LastErrorToPlatformFileError(DWORD saved_errno);
#elif defined(OS_POSIX)
typedef int PlatformFile;
const PlatformFile kInvalidPlatformFileValue = -1;
PlatformFileError ErrnoToPlatformFileError(int saved_errno);
#endif
// Creates or opens the given file. If |created| is provided, it will be set to
// true if a new file was created [or an old one truncated to zero length to
// simulate a new file, which can happen with PLATFORM_FILE_CREATE_ALWAYS], and
// false otherwise. |error| can be NULL.
//
// This function fails with 'access denied' if the |name| contains path
// traversal ('..') components.
BASE_EXPORT PlatformFile CreatePlatformFile(const FilePath& name,
int flags,
bool* created,
PlatformFileError* error);
// Same as CreatePlatformFile but allows paths with traversal (like \..\)
// components. Use only with extreme care.
BASE_EXPORT PlatformFile CreatePlatformFileUnsafe(const FilePath& name,
int flags,
bool* created,
PlatformFileError* error);
BASE_EXPORT FILE* FdopenPlatformFile(PlatformFile file, const char* mode);
// Closes a file handle. Returns |true| on success and |false| otherwise.
BASE_EXPORT bool ClosePlatformFile(PlatformFile file);
// Changes current position in the file to an |offset| relative to an origin
// defined by |whence|. Returns the resultant current position in the file
// (relative to the start) or -1 in case of error.
BASE_EXPORT int64 SeekPlatformFile(PlatformFile file,
PlatformFileWhence whence,
int64 offset);
// Reads the given number of bytes (or until EOF is reached) starting with the
// given offset. Returns the number of bytes read, or -1 on error. Note that
// this function makes a best effort to read all data on all platforms, so it is
// not intended for stream oriented files but instead for cases when the normal
// expectation is that actually |size| bytes are read unless there is an error.
BASE_EXPORT int ReadPlatformFile(PlatformFile file, int64 offset,
char* data, int size);
// Same as above but without seek.
BASE_EXPORT int ReadPlatformFileAtCurrentPos(PlatformFile file,
char* data, int size);
// Reads the given number of bytes (or until EOF is reached) starting with the
// given offset, but does not make any effort to read all data on all platforms.
// Returns the number of bytes read, or -1 on error.
BASE_EXPORT int ReadPlatformFileNoBestEffort(PlatformFile file, int64 offset,
char* data, int size);
// Same as above but without seek.
BASE_EXPORT int ReadPlatformFileCurPosNoBestEffort(PlatformFile file,
char* data, int size);
// Writes the given buffer into the file at the given offset, overwritting any
// data that was previously there. Returns the number of bytes written, or -1
// on error. Note that this function makes a best effort to write all data on
// all platforms.
// Ignores the offset and writes to the end of the file if the file was opened
// with PLATFORM_FILE_APPEND.
BASE_EXPORT int WritePlatformFile(PlatformFile file, int64 offset,
const char* data, int size);
// Save as above but without seek.
BASE_EXPORT int WritePlatformFileAtCurrentPos(PlatformFile file,
const char* data, int size);
// Save as above but does not make any effort to write all data on all
// platforms. Returns the number of bytes written, or -1 on error.
BASE_EXPORT int WritePlatformFileCurPosNoBestEffort(PlatformFile file,
const char* data, int size);
// Truncates the given file to the given length. If |length| is greater than
// the current size of the file, the file is extended with zeros. If the file
// doesn't exist, |false| is returned.
BASE_EXPORT bool TruncatePlatformFile(PlatformFile file, int64 length);
// Flushes the buffers of the given file.
BASE_EXPORT bool FlushPlatformFile(PlatformFile file);
// Touches the given file.
BASE_EXPORT bool TouchPlatformFile(PlatformFile file,
const Time& last_access_time,
const Time& last_modified_time);
// Returns some information for the given file.
BASE_EXPORT bool GetPlatformFileInfo(PlatformFile file, PlatformFileInfo* info);
// Use this class to pass ownership of a PlatformFile to a receiver that may or
// may not want to accept it. This class does not own the storage for the
// PlatformFile.
//
// EXAMPLE:
//
// void MaybeProcessFile(PassPlatformFile pass_file) {
// if (...) {
// PlatformFile file = pass_file.ReleaseValue();
// // Now, we are responsible for closing |file|.
// }
// }
//
// void OpenAndMaybeProcessFile(const FilePath& path) {
// PlatformFile file = CreatePlatformFile(path, ...);
// MaybeProcessFile(PassPlatformFile(&file));
// if (file != kInvalidPlatformFileValue)
// ClosePlatformFile(file);
// }
//
class BASE_EXPORT PassPlatformFile {
public:
explicit PassPlatformFile(PlatformFile* value) : value_(value) {
}
// Called to retrieve the PlatformFile stored in this object. The caller
// gains ownership of the PlatformFile and is now responsible for closing it.
// Any subsequent calls to this method will return an invalid PlatformFile.
PlatformFile ReleaseValue() {
PlatformFile temp = *value_;
*value_ = kInvalidPlatformFileValue;
return temp;
}
private:
PlatformFile* value_;
};
} // namespace base
#endif // BASE_PLATFORM_FILE_H_

Просмотреть файл

@ -8,6 +8,10 @@
#include <stdarg.h>
#include "build/build_config.h"
// DEPRECATED: Use ...LL and ...ULL suffixes.
// TODO(viettrungluu): Delete these. These are only here until |GG_(U)INT64_C|
// are deleted (some other header files (re)define |GG_(U)INT64_C|, so our
// definitions of them must exactly match theirs).
#ifdef COMPILER_MSVC
#define GG_LONGLONG(x) x##I64
#define GG_ULONGLONG(x) x##UI64
@ -16,20 +20,10 @@
#define GG_ULONGLONG(x) x##ULL
#endif
// Per C99 7.8.14, define __STDC_CONSTANT_MACROS before including <stdint.h>
// to get the INTn_C and UINTn_C macros for integer constants. It's difficult
// to guarantee any specific ordering of header includes, so it's difficult to
// guarantee that the INTn_C macros can be defined by including <stdint.h> at
// any specific point. Provide GG_INTn_C macros instead.
#define GG_INT8_C(x) (x)
#define GG_INT16_C(x) (x)
#define GG_INT32_C(x) (x)
// DEPRECATED: In Chromium, we force-define __STDC_CONSTANT_MACROS, so you can
// just use the regular (U)INTn_C macros from <stdint.h>.
// TODO(viettrungluu): Remove the remaining GG_(U)INTn_C macros.
#define GG_INT64_C(x) GG_LONGLONG(x)
#define GG_UINT8_C(x) (x ## U)
#define GG_UINT16_C(x) (x ## U)
#define GG_UINT32_C(x) (x ## U)
#define GG_UINT64_C(x) GG_ULONGLONG(x)
// It's possible for functions that use a va_list, such as StringPrintf, to

Просмотреть файл

@ -81,12 +81,10 @@ BASE_EXPORT bool GetProcessIntegrityLevel(ProcessHandle process,
IntegrityLevel* level);
#endif
#if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_BSD)
#if defined(OS_POSIX)
// Returns the path to the executable of the given process.
BASE_EXPORT FilePath GetProcessExecutablePath(ProcessHandle process);
#endif
#if defined(OS_POSIX)
// Returns the ID for the parent of the given process.
BASE_EXPORT ProcessId GetParentProcessId(ProcessHandle process);
#endif

Просмотреть файл

@ -39,10 +39,11 @@ BASE_EXPORT double BitsToOpenEndedUnitInterval(uint64 bits);
// See crypto/ for cryptographically secure random number generation APIs.
BASE_EXPORT void RandBytes(void* output, size_t output_length);
// Fills a string of length |length| with with random data and returns it.
// Fills a string of length |length| with random data and returns it.
// |length| should be nonzero.
//
// Note that this is a variation of |RandBytes| with a different return type.
// The returned string is likely not ASCII/UTF-8. Use with care.
//
// WARNING:
// Do not use for security-sensitive purposes.

Просмотреть файл

@ -5,8 +5,6 @@
#ifndef BASE_SEQUENCE_CHECKER_H_
#define BASE_SEQUENCE_CHECKER_H_
#include "base/memory/ref_counted.h"
// See comments for the similar block in thread_checker.h.
#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON))
#define ENABLE_SEQUENCE_CHECKER 1
@ -14,14 +12,10 @@
#define ENABLE_SEQUENCE_CHECKER 0
#endif
#if ENABLE_SEQUENCE_CHECKER
#include "base/sequence_checker_impl.h"
#endif
namespace base {
class SequencedTaskRunner;
// Do nothing implementation, for use in release mode.
//
// Note: You should almost always use the SequenceChecker class to get
@ -44,7 +38,7 @@ class SequenceCheckerDoNothing {
// class MyClass {
// public:
// void Foo() {
// DCHECK(sequence_checker_.CalledOnValidSequence());
// DCHECK(sequence_checker_.CalledOnValidSequencedThread());
// ... (do stuff) ...
// }
//
@ -52,7 +46,7 @@ class SequenceCheckerDoNothing {
// SequenceChecker sequence_checker_;
// }
//
// In Release mode, CalledOnValidSequence will always return true.
// In Release mode, CalledOnValidSequencedThread() will always return true.
#if ENABLE_SEQUENCE_CHECKER
class SequenceChecker : public SequenceCheckerImpl {
};

Просмотреть файл

@ -4,106 +4,116 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// This is a stripped down version of the Chromium source file base/logging.cc
// This prevents dependency on the Chromium logging and dependency creep in
// general.
// At some point we should find a way to hook this into our own logging see
// bug 1013988.
// The formatting in this file matches the original Chromium file to aid future
// merging.
#include "base/logging.h"
#ifdef OS_WIN
#if defined(OS_WIN)
#include <windows.h>
#endif
#if defined(OS_POSIX)
#include <errno.h>
#endif
#if defined(OS_WIN)
#include "base/strings/utf_string_conversions.h"
#endif
namespace logging {
namespace {
int min_log_level = 0;
}
namespace logging
{
} // namespace
DcheckState g_dcheck_state = DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS;
DcheckState get_dcheck_state() {
return g_dcheck_state;
}
LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
int ctr) :
line_(line)
{
}
LogMessage::LogMessage(const char* file, int line, int ctr) : line_(line)
{
}
LogMessage::LogMessage(const char* file, int line, std::string* result) :
severity_(LOG_FATAL),
file_(file),
line_(line)
{
}
LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
std::string* result) :
severity_(severity),
file_(file),
line_(line)
{
}
LogMessage::~LogMessage()
{
}
int GetMinLogLevel()
{
int GetMinLogLevel() {
return min_log_level;
}
int GetVlogLevelHelper(const char* file, size_t N)
{
int GetVlogLevelHelper(const char* file, size_t N) {
return 0;
}
void RawLog(int level, const char* message)
{
// MSVC doesn't like complex extern templates and DLLs.
#if !defined(COMPILER_MSVC)
// Explicit instantiations for commonly used comparisons.
template std::string* MakeCheckOpString<int, int>(
const int&, const int&, const char* names);
template std::string* MakeCheckOpString<unsigned long, unsigned long>(
const unsigned long&, const unsigned long&, const char* names);
template std::string* MakeCheckOpString<unsigned long, unsigned int>(
const unsigned long&, const unsigned int&, const char* names);
template std::string* MakeCheckOpString<unsigned int, unsigned long>(
const unsigned int&, const unsigned long&, const char* names);
template std::string* MakeCheckOpString<std::string, std::string>(
const std::string&, const std::string&, const char* name);
#endif
#if defined(OS_WIN)
LogMessage::SaveLastError::SaveLastError() : last_error_(::GetLastError()) {
}
#ifdef OS_WIN
LogMessage::SaveLastError::SaveLastError() :
last_error_(::GetLastError())
{
}
LogMessage::SaveLastError::~SaveLastError()
{
LogMessage::SaveLastError::~SaveLastError() {
::SetLastError(last_error_);
}
#endif // defined(OS_WIN)
SystemErrorCode GetLastSystemErrorCode()
{
LogMessage::LogMessage(const char* file, int line, LogSeverity severity)
: severity_(severity), file_(file), line_(line) {
}
LogMessage::LogMessage(const char* file, int line, std::string* result)
: severity_(LOG_FATAL), file_(file), line_(line) {
delete result;
}
LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
std::string* result)
: severity_(severity), file_(file), line_(line) {
delete result;
}
LogMessage::~LogMessage() {
}
SystemErrorCode GetLastSystemErrorCode() {
#if defined(OS_WIN)
return ::GetLastError();
#elif defined(OS_POSIX)
return errno;
#else
#error Not implemented
#endif
}
Win32ErrorLogMessage::Win32ErrorLogMessage(const char* file, int line,
LogSeverity severity,
SystemErrorCode err,
const char* module) :
err_(err),
module_(module),
log_message_(file, line, severity)
{
}
#if defined(OS_WIN)
Win32ErrorLogMessage::Win32ErrorLogMessage(const char* file,
int line,
LogSeverity severity,
SystemErrorCode err) :
err_(err),
module_(NULL),
log_message_(file, line, severity)
{
SystemErrorCode err)
: err_(err),
log_message_(file, line, severity) {
}
Win32ErrorLogMessage::~Win32ErrorLogMessage()
{
Win32ErrorLogMessage::~Win32ErrorLogMessage() {
}
#endif // OS_WIN
void RawLog(int level, const char* message) {
}
#endif // OS_WIN
} // namespace logging
#if defined(OS_WIN)
std::ostream& std::operator<<(std::ostream& out, const wchar_t* wstr) {
return out << base::WideToUTF8(std::wstring(wstr));
}
#endif

Просмотреть файл

@ -0,0 +1,10 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// Blank header file as thread_local.h includes a file that should only be
// included on Android.
// Chromium issue 431339 raised.
// https://code.google.com/p/chromium/issues/detail?id=431339

Просмотреть файл

@ -0,0 +1,34 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// This is a stripped down version of Chromium source file base/win/registry.h
// Within our copy of Chromium files this is only used in base/win/windows_version.cc
// in OSInfo::processor_model_name, which we don't use.
#ifndef BASE_WIN_REGISTRY_H_
#define BASE_WIN_REGISTRY_H_
namespace base {
namespace win {
class BASE_EXPORT RegKey {
public:
RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access) {}
~RegKey() {}
LONG ReadValue(const wchar_t* name, std::wstring* out_value) const
{
return 0;
}
private:
DISALLOW_COPY_AND_ASSIGN(RegKey);
};
} // namespace win
} // namespace base
#endif // BASE_WIN_REGISTRY_H_

Просмотреть файл

@ -201,9 +201,11 @@ namespace base {
// Returns true if the container is sorted.
template <typename Container>
bool STLIsSorted(const Container& cont) {
return std::adjacent_find(cont.begin(), cont.end(),
std::greater<typename Container::value_type>())
== cont.end();
// Note: Use reverse iterator on container to ensure we only require
// value_type to implement operator<.
return std::adjacent_find(cont.rbegin(), cont.rend(),
std::less<typename Container::value_type>())
== cont.rend();
}
// Returns a new ResultType containing the difference of two sorted containers.
@ -218,6 +220,41 @@ ResultType STLSetDifference(const Arg1& a1, const Arg2& a2) {
return difference;
}
// Returns a new ResultType containing the union of two sorted containers.
template <typename ResultType, typename Arg1, typename Arg2>
ResultType STLSetUnion(const Arg1& a1, const Arg2& a2) {
DCHECK(STLIsSorted(a1));
DCHECK(STLIsSorted(a2));
ResultType result;
std::set_union(a1.begin(), a1.end(),
a2.begin(), a2.end(),
std::inserter(result, result.end()));
return result;
}
// Returns a new ResultType containing the intersection of two sorted
// containers.
template <typename ResultType, typename Arg1, typename Arg2>
ResultType STLSetIntersection(const Arg1& a1, const Arg2& a2) {
DCHECK(STLIsSorted(a1));
DCHECK(STLIsSorted(a2));
ResultType result;
std::set_intersection(a1.begin(), a1.end(),
a2.begin(), a2.end(),
std::inserter(result, result.end()));
return result;
}
// Returns true if the sorted container |a1| contains all elements of the sorted
// container |a2|.
template <typename Arg1, typename Arg2>
bool STLIncludes(const Arg1& a1, const Arg2& a2) {
DCHECK(STLIsSorted(a1));
DCHECK(STLIsSorted(a2));
return std::includes(a1.begin(), a1.end(),
a2.begin(), a2.end());
}
} // namespace base
#endif // BASE_STL_UTIL_H_

Просмотреть файл

@ -181,9 +181,4 @@ class BASE_EXPORT std::basic_string<base::char16, base::string16_char_traits>;
#endif // WCHAR_T_IS_UTF32
// TODO(brettw) update users of string16 to use the namespace and remove
// this "using".
using base::char16;
using base::string16;
#endif // BASE_STRINGS_STRING16_H_

Просмотреть файл

@ -78,24 +78,19 @@ struct IntToStringT {
// unsigned, even the presence of the unary operation causes a warning.
UINT res = ToUnsignedT<INT, UINT, NEG>::ToUnsigned(value);
for (typename STR::iterator it = outbuf.end();;) {
typename STR::iterator it(outbuf.end());
do {
--it;
DCHECK(it != outbuf.begin());
*it = static_cast<typename STR::value_type>((res % 10) + '0');
res /= 10;
// We're done..
if (res == 0) {
if (is_neg) {
--it;
DCHECK(it != outbuf.begin());
*it = static_cast<typename STR::value_type>('-');
}
return STR(it, outbuf.end());
}
} while (res != 0);
if (is_neg) {
--it;
DCHECK(it != outbuf.begin());
*it = static_cast<typename STR::value_type>('-');
}
NOTREACHED();
return STR();
return STR(it, outbuf.end());
}
};
@ -300,6 +295,11 @@ class BaseHexIteratorRangeToIntTraits
: public BaseIteratorRangeToNumberTraits<ITERATOR, int, 16> {
};
template<typename ITERATOR>
class BaseHexIteratorRangeToUIntTraits
: public BaseIteratorRangeToNumberTraits<ITERATOR, uint32, 16> {
};
template<typename ITERATOR>
class BaseHexIteratorRangeToInt64Traits
: public BaseIteratorRangeToNumberTraits<ITERATOR, int64, 16> {
@ -313,6 +313,9 @@ class BaseHexIteratorRangeToUInt64Traits
typedef BaseHexIteratorRangeToIntTraits<StringPiece::const_iterator>
HexIteratorRangeToIntTraits;
typedef BaseHexIteratorRangeToUIntTraits<StringPiece::const_iterator>
HexIteratorRangeToUIntTraits;
typedef BaseHexIteratorRangeToInt64Traits<StringPiece::const_iterator>
HexIteratorRangeToInt64Traits;
@ -385,8 +388,7 @@ string16 UintToString16(unsigned int value) {
}
std::string Int64ToString(int64 value) {
return IntToStringT<std::string, int64, uint64, true>::
IntToString(value);
return IntToStringT<std::string, int64, uint64, true>::IntToString(value);
}
string16 Int64ToString16(int64 value) {
@ -394,13 +396,19 @@ string16 Int64ToString16(int64 value) {
}
std::string Uint64ToString(uint64 value) {
return IntToStringT<std::string, uint64, uint64, false>::
IntToString(value);
return IntToStringT<std::string, uint64, uint64, false>::IntToString(value);
}
string16 Uint64ToString16(uint64 value) {
return IntToStringT<string16, uint64, uint64, false>::
IntToString(value);
return IntToStringT<string16, uint64, uint64, false>::IntToString(value);
}
std::string SizeTToString(size_t value) {
return IntToStringT<std::string, size_t, size_t, false>::IntToString(value);
}
string16 SizeTToString16(size_t value) {
return IntToStringT<string16, size_t, size_t, false>::IntToString(value);
}
std::string DoubleToString(double value) {
@ -499,6 +507,11 @@ bool HexStringToInt(const StringPiece& input, int* output) {
input.begin(), input.end(), output);
}
bool HexStringToUInt(const StringPiece& input, uint32* output) {
return IteratorRangeToNumber<HexIteratorRangeToUIntTraits>::Invoke(
input.begin(), input.end(), output);
}
bool HexStringToInt64(const StringPiece& input, int64* output) {
return IteratorRangeToNumber<HexIteratorRangeToInt64Traits>::Invoke(
input.begin(), input.end(), output);

Просмотреть файл

@ -41,6 +41,9 @@ BASE_EXPORT string16 Int64ToString16(int64 value);
BASE_EXPORT std::string Uint64ToString(uint64 value);
BASE_EXPORT string16 Uint64ToString16(uint64 value);
BASE_EXPORT std::string SizeTToString(size_t value);
BASE_EXPORT string16 SizeTToString16(size_t value);
// DoubleToString converts the double to a string format that ignores the
// locale. If you want to use locale specific formatting, use ICU.
BASE_EXPORT std::string DoubleToString(double value);
@ -99,6 +102,12 @@ BASE_EXPORT std::string HexEncode(const void* bytes, size_t size);
// -0x80000000 < |input| < 0x7FFFFFFF.
BASE_EXPORT bool HexStringToInt(const StringPiece& input, int* output);
// Best effort conversion, see StringToInt above for restrictions.
// Will only successful parse hex values that will fit into |output|, i.e.
// 0x00000000 < |input| < 0xFFFFFFFF.
// The string is not required to start with 0x.
BASE_EXPORT bool HexStringToUInt(const StringPiece& input, uint32* output);
// Best effort conversion, see StringToInt above for restrictions.
// Will only successful parse hex values that will fit into |output|, i.e.
// -0x8000000000000000 < |input| < 0x7FFFFFFFFFFFFFFF.

Просмотреть файл

@ -9,14 +9,30 @@
#include <ostream>
namespace base {
namespace {
// For each character in characters_wanted, sets the index corresponding
// to the ASCII code of that character to 1 in table. This is used by
// the find_.*_of methods below to tell whether or not a character is in
// the lookup table in constant time.
// The argument `table' must be an array that is large enough to hold all
// the possible values of an unsigned char. Thus it should be be declared
// as follows:
// bool table[UCHAR_MAX + 1]
inline void BuildLookupTable(const StringPiece& characters_wanted,
bool* table) {
const size_t length = characters_wanted.length();
const char* const data = characters_wanted.data();
for (size_t i = 0; i < length; ++i) {
table[static_cast<unsigned char>(data[i])] = true;
}
}
} // namespace
// MSVC doesn't like complex extern templates and DLLs.
#if !defined(COMPILER_MSVC)
namespace internal {
template class StringPieceDetail<std::string>;
template class StringPieceDetail<string16>;
} // namespace internal
template class BasicStringPiece<std::string>;
template class BasicStringPiece<string16>;
#endif
@ -33,101 +49,153 @@ std::ostream& operator<<(std::ostream& o, const StringPiece& piece) {
}
namespace internal {
void CopyToString(const StringPiece& self, std::string* target) {
target->assign(!self.empty() ? self.data() : "", self.size());
template<typename STR>
void CopyToStringT(const BasicStringPiece<STR>& self, STR* target) {
if (self.empty())
target->clear();
else
target->assign(self.data(), self.size());
}
void AppendToString(const StringPiece& self, std::string* target) {
void CopyToString(const StringPiece& self, std::string* target) {
CopyToStringT(self, target);
}
void CopyToString(const StringPiece16& self, string16* target) {
CopyToStringT(self, target);
}
template<typename STR>
void AppendToStringT(const BasicStringPiece<STR>& self, STR* target) {
if (!self.empty())
target->append(self.data(), self.size());
}
StringPiece::size_type copy(const StringPiece& self,
char* buf,
StringPiece::size_type n,
StringPiece::size_type pos) {
StringPiece::size_type ret = std::min(self.size() - pos, n);
memcpy(buf, self.data() + pos, ret);
void AppendToString(const StringPiece& self, std::string* target) {
AppendToStringT(self, target);
}
void AppendToString(const StringPiece16& self, string16* target) {
AppendToStringT(self, target);
}
template<typename STR>
size_t copyT(const BasicStringPiece<STR>& self,
typename STR::value_type* buf,
size_t n,
size_t pos) {
size_t ret = std::min(self.size() - pos, n);
memcpy(buf, self.data() + pos, ret * sizeof(typename STR::value_type));
return ret;
}
StringPiece::size_type find(const StringPiece& self,
const StringPiece& s,
StringPiece::size_type pos) {
if (pos > self.size())
return StringPiece::npos;
StringPiece::const_iterator result =
std::search(self.begin() + pos, self.end(), s.begin(), s.end());
const StringPiece::size_type xpos =
static_cast<size_t>(result - self.begin());
return xpos + s.size() <= self.size() ? xpos : StringPiece::npos;
size_t copy(const StringPiece& self, char* buf, size_t n, size_t pos) {
return copyT(self, buf, n, pos);
}
StringPiece::size_type find(const StringPiece& self,
char c,
StringPiece::size_type pos) {
if (pos >= self.size())
return StringPiece::npos;
size_t copy(const StringPiece16& self, char16* buf, size_t n, size_t pos) {
return copyT(self, buf, n, pos);
}
StringPiece::const_iterator result =
template<typename STR>
size_t findT(const BasicStringPiece<STR>& self,
const BasicStringPiece<STR>& s,
size_t pos) {
if (pos > self.size())
return BasicStringPiece<STR>::npos;
typename BasicStringPiece<STR>::const_iterator result =
std::search(self.begin() + pos, self.end(), s.begin(), s.end());
const size_t xpos =
static_cast<size_t>(result - self.begin());
return xpos + s.size() <= self.size() ? xpos : BasicStringPiece<STR>::npos;
}
size_t find(const StringPiece& self, const StringPiece& s, size_t pos) {
return findT(self, s, pos);
}
size_t find(const StringPiece16& self, const StringPiece16& s, size_t pos) {
return findT(self, s, pos);
}
template<typename STR>
size_t findT(const BasicStringPiece<STR>& self,
typename STR::value_type c,
size_t pos) {
if (pos >= self.size())
return BasicStringPiece<STR>::npos;
typename BasicStringPiece<STR>::const_iterator result =
std::find(self.begin() + pos, self.end(), c);
return result != self.end() ?
static_cast<size_t>(result - self.begin()) : StringPiece::npos;
static_cast<size_t>(result - self.begin()) : BasicStringPiece<STR>::npos;
}
StringPiece::size_type rfind(const StringPiece& self,
const StringPiece& s,
StringPiece::size_type pos) {
size_t find(const StringPiece& self, char c, size_t pos) {
return findT(self, c, pos);
}
size_t find(const StringPiece16& self, char16 c, size_t pos) {
return findT(self, c, pos);
}
template<typename STR>
size_t rfindT(const BasicStringPiece<STR>& self,
const BasicStringPiece<STR>& s,
size_t pos) {
if (self.size() < s.size())
return StringPiece::npos;
return BasicStringPiece<STR>::npos;
if (s.empty())
return std::min(self.size(), pos);
StringPiece::const_iterator last =
typename BasicStringPiece<STR>::const_iterator last =
self.begin() + std::min(self.size() - s.size(), pos) + s.size();
StringPiece::const_iterator result =
typename BasicStringPiece<STR>::const_iterator result =
std::find_end(self.begin(), last, s.begin(), s.end());
return result != last ?
static_cast<size_t>(result - self.begin()) : StringPiece::npos;
static_cast<size_t>(result - self.begin()) : BasicStringPiece<STR>::npos;
}
StringPiece::size_type rfind(const StringPiece& self,
char c,
StringPiece::size_type pos) {
if (self.size() == 0)
return StringPiece::npos;
size_t rfind(const StringPiece& self, const StringPiece& s, size_t pos) {
return rfindT(self, s, pos);
}
for (StringPiece::size_type i = std::min(pos, self.size() - 1); ; --i) {
size_t rfind(const StringPiece16& self, const StringPiece16& s, size_t pos) {
return rfindT(self, s, pos);
}
template<typename STR>
size_t rfindT(const BasicStringPiece<STR>& self,
typename STR::value_type c,
size_t pos) {
if (self.size() == 0)
return BasicStringPiece<STR>::npos;
for (size_t i = std::min(pos, self.size() - 1); ;
--i) {
if (self.data()[i] == c)
return i;
if (i == 0)
break;
}
return StringPiece::npos;
return BasicStringPiece<STR>::npos;
}
// For each character in characters_wanted, sets the index corresponding
// to the ASCII code of that character to 1 in table. This is used by
// the find_.*_of methods below to tell whether or not a character is in
// the lookup table in constant time.
// The argument `table' must be an array that is large enough to hold all
// the possible values of an unsigned char. Thus it should be be declared
// as follows:
// bool table[UCHAR_MAX + 1]
static inline void BuildLookupTable(const StringPiece& characters_wanted,
bool* table) {
const StringPiece::size_type length = characters_wanted.length();
const char* const data = characters_wanted.data();
for (StringPiece::size_type i = 0; i < length; ++i) {
table[static_cast<unsigned char>(data[i])] = true;
}
size_t rfind(const StringPiece& self, char c, size_t pos) {
return rfindT(self, c, pos);
}
StringPiece::size_type find_first_of(const StringPiece& self,
const StringPiece& s,
StringPiece::size_type pos) {
size_t rfind(const StringPiece16& self, char16 c, size_t pos) {
return rfindT(self, c, pos);
}
// 8-bit version using lookup table.
size_t find_first_of(const StringPiece& self,
const StringPiece& s,
size_t pos) {
if (self.size() == 0 || s.size() == 0)
return StringPiece::npos;
@ -137,7 +205,7 @@ StringPiece::size_type find_first_of(const StringPiece& self,
bool lookup[UCHAR_MAX + 1] = { false };
BuildLookupTable(s, lookup);
for (StringPiece::size_type i = pos; i < self.size(); ++i) {
for (size_t i = pos; i < self.size(); ++i) {
if (lookup[static_cast<unsigned char>(self.data()[i])]) {
return i;
}
@ -145,9 +213,21 @@ StringPiece::size_type find_first_of(const StringPiece& self,
return StringPiece::npos;
}
StringPiece::size_type find_first_not_of(const StringPiece& self,
const StringPiece& s,
StringPiece::size_type pos) {
// 16-bit brute force version.
size_t find_first_of(const StringPiece16& self,
const StringPiece16& s,
size_t pos) {
StringPiece16::const_iterator found =
std::find_first_of(self.begin() + pos, self.end(), s.begin(), s.end());
if (found == self.end())
return StringPiece16::npos;
return found - self.begin();
}
// 8-bit version using lookup table.
size_t find_first_not_of(const StringPiece& self,
const StringPiece& s,
size_t pos) {
if (self.size() == 0)
return StringPiece::npos;
@ -160,7 +240,7 @@ StringPiece::size_type find_first_not_of(const StringPiece& self,
bool lookup[UCHAR_MAX + 1] = { false };
BuildLookupTable(s, lookup);
for (StringPiece::size_type i = pos; i < self.size(); ++i) {
for (size_t i = pos; i < self.size(); ++i) {
if (!lookup[static_cast<unsigned char>(self.data()[i])]) {
return i;
}
@ -168,23 +248,56 @@ StringPiece::size_type find_first_not_of(const StringPiece& self,
return StringPiece::npos;
}
StringPiece::size_type find_first_not_of(const StringPiece& self,
char c,
StringPiece::size_type pos) {
// 16-bit brute-force version.
BASE_EXPORT size_t find_first_not_of(const StringPiece16& self,
const StringPiece16& s,
size_t pos) {
if (self.size() == 0)
return StringPiece::npos;
return StringPiece16::npos;
for (size_t self_i = pos; self_i < self.size(); ++self_i) {
bool found = false;
for (size_t s_i = 0; s_i < s.size(); ++s_i) {
if (self[self_i] == s[s_i]) {
found = true;
break;
}
}
if (!found)
return self_i;
}
return StringPiece16::npos;
}
template<typename STR>
size_t find_first_not_ofT(const BasicStringPiece<STR>& self,
typename STR::value_type c,
size_t pos) {
if (self.size() == 0)
return BasicStringPiece<STR>::npos;
for (; pos < self.size(); ++pos) {
if (self.data()[pos] != c) {
return pos;
}
}
return StringPiece::npos;
return BasicStringPiece<STR>::npos;
}
StringPiece::size_type find_last_of(const StringPiece& self,
const StringPiece& s,
StringPiece::size_type pos) {
size_t find_first_not_of(const StringPiece& self,
char c,
size_t pos) {
return find_first_not_ofT(self, c, pos);
}
size_t find_first_not_of(const StringPiece16& self,
char16 c,
size_t pos) {
return find_first_not_ofT(self, c, pos);
}
// 8-bit version using lookup table.
size_t find_last_of(const StringPiece& self, const StringPiece& s, size_t pos) {
if (self.size() == 0 || s.size() == 0)
return StringPiece::npos;
@ -194,7 +307,7 @@ StringPiece::size_type find_last_of(const StringPiece& self,
bool lookup[UCHAR_MAX + 1] = { false };
BuildLookupTable(s, lookup);
for (StringPiece::size_type i = std::min(pos, self.size() - 1); ; --i) {
for (size_t i = std::min(pos, self.size() - 1); ; --i) {
if (lookup[static_cast<unsigned char>(self.data()[i])])
return i;
if (i == 0)
@ -203,13 +316,33 @@ StringPiece::size_type find_last_of(const StringPiece& self,
return StringPiece::npos;
}
StringPiece::size_type find_last_not_of(const StringPiece& self,
const StringPiece& s,
StringPiece::size_type pos) {
// 16-bit brute-force version.
size_t find_last_of(const StringPiece16& self,
const StringPiece16& s,
size_t pos) {
if (self.size() == 0)
return StringPiece16::npos;
for (size_t self_i = std::min(pos, self.size() - 1); ;
--self_i) {
for (size_t s_i = 0; s_i < s.size(); s_i++) {
if (self.data()[self_i] == s[s_i])
return self_i;
}
if (self_i == 0)
break;
}
return StringPiece16::npos;
}
// 8-bit version using lookup table.
size_t find_last_not_of(const StringPiece& self,
const StringPiece& s,
size_t pos) {
if (self.size() == 0)
return StringPiece::npos;
StringPiece::size_type i = std::min(pos, self.size() - 1);
size_t i = std::min(pos, self.size() - 1);
if (s.size() == 0)
return i;
@ -228,27 +361,76 @@ StringPiece::size_type find_last_not_of(const StringPiece& self,
return StringPiece::npos;
}
StringPiece::size_type find_last_not_of(const StringPiece& self,
char c,
StringPiece::size_type pos) {
// 16-bit brute-force version.
size_t find_last_not_of(const StringPiece16& self,
const StringPiece16& s,
size_t pos) {
if (self.size() == 0)
return StringPiece::npos;
for (StringPiece::size_type i = std::min(pos, self.size() - 1); ; --i) {
for (size_t self_i = std::min(pos, self.size() - 1); ; --self_i) {
bool found = false;
for (size_t s_i = 0; s_i < s.size(); s_i++) {
if (self.data()[self_i] == s[s_i]) {
found = true;
break;
}
}
if (!found)
return self_i;
if (self_i == 0)
break;
}
return StringPiece16::npos;
}
template<typename STR>
size_t find_last_not_ofT(const BasicStringPiece<STR>& self,
typename STR::value_type c,
size_t pos) {
if (self.size() == 0)
return BasicStringPiece<STR>::npos;
for (size_t i = std::min(pos, self.size() - 1); ; --i) {
if (self.data()[i] != c)
return i;
if (i == 0)
break;
}
return StringPiece::npos;
return BasicStringPiece<STR>::npos;
}
size_t find_last_not_of(const StringPiece& self,
char c,
size_t pos) {
return find_last_not_ofT(self, c, pos);
}
size_t find_last_not_of(const StringPiece16& self,
char16 c,
size_t pos) {
return find_last_not_ofT(self, c, pos);
}
template<typename STR>
BasicStringPiece<STR> substrT(const BasicStringPiece<STR>& self,
size_t pos,
size_t n) {
if (pos > self.size()) pos = self.size();
if (n > self.size() - pos) n = self.size() - pos;
return BasicStringPiece<STR>(self.data() + pos, n);
}
StringPiece substr(const StringPiece& self,
StringPiece::size_type pos,
StringPiece::size_type n) {
if (pos > self.size()) pos = self.size();
if (n > self.size() - pos) n = self.size() - pos;
return StringPiece(self.data() + pos, n);
size_t pos,
size_t n) {
return substrT(self, pos, n);
}
StringPiece16 substr(const StringPiece16& self,
size_t pos,
size_t n) {
return substrT(self, pos, n);
}
} // namespace internal

Просмотреть файл

@ -5,14 +5,19 @@
//
// A string-like object that points to a sized piece of memory.
//
// Functions or methods may use const StringPiece& parameters to accept either
// a "const char*" or a "string" value that will be implicitly converted to
// a StringPiece. The implicit conversion means that it is often appropriate
// to include this .h file in other files rather than forward-declaring
// StringPiece as would be appropriate for most other Google classes.
// You can use StringPiece as a function or method parameter. A StringPiece
// parameter can receive a double-quoted string literal argument, a "const
// char*" argument, a string argument, or a StringPiece argument with no data
// copying. Systematic use of StringPiece for arguments reduces data
// copies and strlen() calls.
//
// Systematic usage of StringPiece is encouraged as it will reduce unnecessary
// conversions from "const char*" to "string" and back again.
// Prefer passing StringPieces by value:
// void MyFunction(StringPiece arg);
// If circumstances require, you may also pass by const reference:
// void MyFunction(const StringPiece& arg); // not preferred
// Both of these have the same lifetime semantics. Passing by value
// generates slightly smaller code. For more discussion, Googlers can see
// the thread go/stringpiecebyvalue on c-users.
//
// StringPiece16 is similar to StringPiece but for base::string16 instead of
// std::string. We do not define as large of a subset of the STL functions
@ -39,14 +44,124 @@ template <typename STRING_TYPE> class BasicStringPiece;
typedef BasicStringPiece<std::string> StringPiece;
typedef BasicStringPiece<string16> StringPiece16;
// internal --------------------------------------------------------------------
// Many of the StringPiece functions use different implementations for the
// 8-bit and 16-bit versions, and we don't want lots of template expansions in
// this (very common) header that will slow down compilation.
//
// So here we define overloaded functions called by the StringPiece template.
// For those that share an implementation, the two versions will expand to a
// template internal to the .cc file.
namespace internal {
BASE_EXPORT void CopyToString(const StringPiece& self, std::string* target);
BASE_EXPORT void CopyToString(const StringPiece16& self, string16* target);
BASE_EXPORT void AppendToString(const StringPiece& self, std::string* target);
BASE_EXPORT void AppendToString(const StringPiece16& self, string16* target);
BASE_EXPORT size_t copy(const StringPiece& self,
char* buf,
size_t n,
size_t pos);
BASE_EXPORT size_t copy(const StringPiece16& self,
char16* buf,
size_t n,
size_t pos);
BASE_EXPORT size_t find(const StringPiece& self,
const StringPiece& s,
size_t pos);
BASE_EXPORT size_t find(const StringPiece16& self,
const StringPiece16& s,
size_t pos);
BASE_EXPORT size_t find(const StringPiece& self,
char c,
size_t pos);
BASE_EXPORT size_t find(const StringPiece16& self,
char16 c,
size_t pos);
BASE_EXPORT size_t rfind(const StringPiece& self,
const StringPiece& s,
size_t pos);
BASE_EXPORT size_t rfind(const StringPiece16& self,
const StringPiece16& s,
size_t pos);
BASE_EXPORT size_t rfind(const StringPiece& self,
char c,
size_t pos);
BASE_EXPORT size_t rfind(const StringPiece16& self,
char16 c,
size_t pos);
BASE_EXPORT size_t find_first_of(const StringPiece& self,
const StringPiece& s,
size_t pos);
BASE_EXPORT size_t find_first_of(const StringPiece16& self,
const StringPiece16& s,
size_t pos);
BASE_EXPORT size_t find_first_not_of(const StringPiece& self,
const StringPiece& s,
size_t pos);
BASE_EXPORT size_t find_first_not_of(const StringPiece16& self,
const StringPiece16& s,
size_t pos);
BASE_EXPORT size_t find_first_not_of(const StringPiece& self,
char c,
size_t pos);
BASE_EXPORT size_t find_first_not_of(const StringPiece16& self,
char16 c,
size_t pos);
BASE_EXPORT size_t find_last_of(const StringPiece& self,
const StringPiece& s,
size_t pos);
BASE_EXPORT size_t find_last_of(const StringPiece16& self,
const StringPiece16& s,
size_t pos);
BASE_EXPORT size_t find_last_of(const StringPiece& self,
char c,
size_t pos);
BASE_EXPORT size_t find_last_of(const StringPiece16& self,
char16 c,
size_t pos);
BASE_EXPORT size_t find_last_not_of(const StringPiece& self,
const StringPiece& s,
size_t pos);
BASE_EXPORT size_t find_last_not_of(const StringPiece16& self,
const StringPiece16& s,
size_t pos);
BASE_EXPORT size_t find_last_not_of(const StringPiece16& self,
char16 c,
size_t pos);
BASE_EXPORT size_t find_last_not_of(const StringPiece& self,
char c,
size_t pos);
BASE_EXPORT StringPiece substr(const StringPiece& self,
size_t pos,
size_t n);
BASE_EXPORT StringPiece16 substr(const StringPiece16& self,
size_t pos,
size_t n);
} // namespace internal
// BasicStringPiece ------------------------------------------------------------
// Defines the types, methods, operators, and data members common to both
// StringPiece and StringPiece16. Do not refer to this class directly, but
// rather to BasicStringPiece, StringPiece, or StringPiece16.
template <typename STRING_TYPE> class StringPieceDetail {
//
// This is templatized by string class type rather than character type, so
// BasicStringPiece<std::string> or BasicStringPiece<base::string16>.
template <typename STRING_TYPE> class BasicStringPiece {
public:
// standard STL container boilerplate
// Standard STL container boilerplate.
typedef size_t size_type;
typedef typename STRING_TYPE::value_type value_type;
typedef const value_type* pointer;
@ -62,15 +177,15 @@ template <typename STRING_TYPE> class StringPieceDetail {
// We provide non-explicit singleton constructors so users can pass
// in a "const char*" or a "string" wherever a "StringPiece" is
// expected (likewise for char16, string16, StringPiece16).
StringPieceDetail() : ptr_(NULL), length_(0) {}
StringPieceDetail(const value_type* str)
BasicStringPiece() : ptr_(NULL), length_(0) {}
BasicStringPiece(const value_type* str)
: ptr_(str),
length_((str == NULL) ? 0 : STRING_TYPE::traits_type::length(str)) {}
StringPieceDetail(const STRING_TYPE& str)
BasicStringPiece(const STRING_TYPE& str)
: ptr_(str.data()), length_(str.size()) {}
StringPieceDetail(const value_type* offset, size_type len)
BasicStringPiece(const value_type* offset, size_type len)
: ptr_(offset), length_(len) {}
StringPieceDetail(const typename STRING_TYPE::const_iterator& begin,
BasicStringPiece(const typename STRING_TYPE::const_iterator& begin,
const typename STRING_TYPE::const_iterator& end)
: ptr_((end > begin) ? &(*begin) : NULL),
length_((end > begin) ? (size_type)(end - begin) : 0) {}
@ -141,213 +256,113 @@ template <typename STRING_TYPE> class StringPieceDetail {
return STRING_TYPE::traits_type::compare(p, p2, N);
}
// Sets the value of the given string target type to be the current string.
// This saves a temporary over doing |a = b.as_string()|
void CopyToString(STRING_TYPE* target) const {
internal::CopyToString(*this, target);
}
void AppendToString(STRING_TYPE* target) const {
internal::AppendToString(*this, target);
}
size_type copy(value_type* buf, size_type n, size_type pos = 0) const {
return internal::copy(*this, buf, n, pos);
}
// Does "this" start with "x"
bool starts_with(const BasicStringPiece& x) const {
return ((this->length_ >= x.length_) &&
(wordmemcmp(this->ptr_, x.ptr_, x.length_) == 0));
}
// Does "this" end with "x"
bool ends_with(const BasicStringPiece& x) const {
return ((this->length_ >= x.length_) &&
(wordmemcmp(this->ptr_ + (this->length_-x.length_),
x.ptr_, x.length_) == 0));
}
// find: Search for a character or substring at a given offset.
size_type find(const BasicStringPiece<STRING_TYPE>& s,
size_type pos = 0) const {
return internal::find(*this, s, pos);
}
size_type find(value_type c, size_type pos = 0) const {
return internal::find(*this, c, pos);
}
// rfind: Reverse find.
size_type rfind(const BasicStringPiece& s,
size_type pos = BasicStringPiece::npos) const {
return internal::rfind(*this, s, pos);
}
size_type rfind(value_type c, size_type pos = BasicStringPiece::npos) const {
return internal::rfind(*this, c, pos);
}
// find_first_of: Find the first occurence of one of a set of characters.
size_type find_first_of(const BasicStringPiece& s,
size_type pos = 0) const {
return internal::find_first_of(*this, s, pos);
}
size_type find_first_of(value_type c, size_type pos = 0) const {
return find(c, pos);
}
// find_first_not_of: Find the first occurence not of a set of characters.
size_type find_first_not_of(const BasicStringPiece& s,
size_type pos = 0) const {
return internal::find_first_not_of(*this, s, pos);
}
size_type find_first_not_of(value_type c, size_type pos = 0) const {
return internal::find_first_not_of(*this, c, pos);
}
// find_last_of: Find the last occurence of one of a set of characters.
size_type find_last_of(const BasicStringPiece& s,
size_type pos = BasicStringPiece::npos) const {
return internal::find_last_of(*this, s, pos);
}
size_type find_last_of(value_type c,
size_type pos = BasicStringPiece::npos) const {
return rfind(c, pos);
}
// find_last_not_of: Find the last occurence not of a set of characters.
size_type find_last_not_of(const BasicStringPiece& s,
size_type pos = BasicStringPiece::npos) const {
return internal::find_last_not_of(*this, s, pos);
}
size_type find_last_not_of(value_type c,
size_type pos = BasicStringPiece::npos) const {
return internal::find_last_not_of(*this, c, pos);
}
// substr.
BasicStringPiece substr(size_type pos,
size_type n = BasicStringPiece::npos) const {
return internal::substr(*this, pos, n);
}
protected:
const value_type* ptr_;
size_type length_;
};
template <typename STRING_TYPE>
const typename StringPieceDetail<STRING_TYPE>::size_type
StringPieceDetail<STRING_TYPE>::npos =
typename StringPieceDetail<STRING_TYPE>::size_type(-1);
const typename BasicStringPiece<STRING_TYPE>::size_type
BasicStringPiece<STRING_TYPE>::npos =
typename BasicStringPiece<STRING_TYPE>::size_type(-1);
// MSVC doesn't like complex extern templates and DLLs.
#if !defined(COMPILER_MSVC)
extern template class BASE_EXPORT StringPieceDetail<std::string>;
extern template class BASE_EXPORT StringPieceDetail<string16>;
#endif
BASE_EXPORT void CopyToString(const StringPiece& self, std::string* target);
BASE_EXPORT void AppendToString(const StringPiece& self, std::string* target);
BASE_EXPORT StringPieceDetail<std::string>::size_type copy(
const StringPiece& self,
char* buf,
StringPieceDetail<std::string>::size_type n,
StringPieceDetail<std::string>::size_type pos);
BASE_EXPORT StringPieceDetail<std::string>::size_type find(
const StringPiece& self,
const StringPiece& s,
StringPieceDetail<std::string>::size_type pos);
BASE_EXPORT StringPieceDetail<std::string>::size_type find(
const StringPiece& self,
char c,
StringPieceDetail<std::string>::size_type pos);
BASE_EXPORT StringPieceDetail<std::string>::size_type rfind(
const StringPiece& self,
const StringPiece& s,
StringPieceDetail<std::string>::size_type pos);
BASE_EXPORT StringPieceDetail<std::string>::size_type rfind(
const StringPiece& self,
char c,
StringPieceDetail<std::string>::size_type pos);
BASE_EXPORT StringPieceDetail<std::string>::size_type find_first_of(
const StringPiece& self,
const StringPiece& s,
StringPieceDetail<std::string>::size_type pos);
BASE_EXPORT StringPieceDetail<std::string>::size_type find_first_not_of(
const StringPiece& self,
const StringPiece& s,
StringPieceDetail<std::string>::size_type pos);
BASE_EXPORT StringPieceDetail<std::string>::size_type find_first_not_of(
const StringPiece& self,
char c,
StringPieceDetail<std::string>::size_type pos);
BASE_EXPORT StringPieceDetail<std::string>::size_type find_last_of(
const StringPiece& self,
const StringPiece& s,
StringPieceDetail<std::string>::size_type pos);
BASE_EXPORT StringPieceDetail<std::string>::size_type find_last_of(
const StringPiece& self,
char c,
StringPieceDetail<std::string>::size_type pos);
BASE_EXPORT StringPieceDetail<std::string>::size_type find_last_not_of(
const StringPiece& self,
const StringPiece& s,
StringPieceDetail<std::string>::size_type pos);
BASE_EXPORT StringPieceDetail<std::string>::size_type find_last_not_of(
const StringPiece& self,
char c,
StringPieceDetail<std::string>::size_type pos);
BASE_EXPORT StringPiece substr(const StringPiece& self,
StringPieceDetail<std::string>::size_type pos,
StringPieceDetail<std::string>::size_type n);
} // namespace internal
// Defines the template type that is instantiated as either StringPiece or
// StringPiece16.
template <typename STRING_TYPE> class BasicStringPiece :
public internal::StringPieceDetail<STRING_TYPE> {
public:
typedef typename internal::StringPieceDetail<STRING_TYPE>::value_type
value_type;
typedef typename internal::StringPieceDetail<STRING_TYPE>::size_type
size_type;
BasicStringPiece() {}
BasicStringPiece(const value_type*str)
: internal::StringPieceDetail<STRING_TYPE>(str) {}
BasicStringPiece(const STRING_TYPE& str)
: internal::StringPieceDetail<STRING_TYPE>(str) {}
BasicStringPiece(const value_type* offset, size_type len)
: internal::StringPieceDetail<STRING_TYPE>(offset, len) {}
BasicStringPiece(const typename STRING_TYPE::const_iterator& begin,
const typename STRING_TYPE::const_iterator& end)
: internal::StringPieceDetail<STRING_TYPE>(begin, end) {}
};
// Specializes BasicStringPiece for std::string to add a few operations that
// are not needed for string16.
template <> class BasicStringPiece<std::string> :
public internal::StringPieceDetail<std::string> {
public:
BasicStringPiece() {}
BasicStringPiece(const char* str)
: internal::StringPieceDetail<std::string>(str) {}
BasicStringPiece(const std::string& str)
: internal::StringPieceDetail<std::string>(str) {}
BasicStringPiece(const char* offset, size_type len)
: internal::StringPieceDetail<std::string>(offset, len) {}
BasicStringPiece(const std::string::const_iterator& begin,
const std::string::const_iterator& end)
: internal::StringPieceDetail<std::string>(begin, end) {}
// Prevent the following overload of set() from hiding the definitions in the
// base class.
using internal::StringPieceDetail<std::string>::set;
void set(const void* data, size_type len) {
ptr_ = reinterpret_cast<const value_type*>(data);
length_ = len;
}
void CopyToString(std::string* target) const {
internal::CopyToString(*this, target);
}
void AppendToString(std::string* target) const {
internal::AppendToString(*this, target);
}
// Does "this" start with "x"
bool starts_with(const BasicStringPiece& x) const {
return ((length_ >= x.length_) &&
(wordmemcmp(ptr_, x.ptr_, x.length_) == 0));
}
// Does "this" end with "x"
bool ends_with(const BasicStringPiece& x) const {
return ((length_ >= x.length_) &&
(wordmemcmp(ptr_ + (length_-x.length_), x.ptr_, x.length_) == 0));
}
size_type copy(char* buf, size_type n, size_type pos = 0) const {
return internal::copy(*this, buf, n, pos);
}
size_type find(const BasicStringPiece& s, size_type pos = 0) const {
return internal::find(*this, s, pos);
}
size_type find(char c, size_type pos = 0) const {
return internal::find(*this, c, pos);
}
size_type rfind(const BasicStringPiece& s, size_type pos = npos) const {
return internal::rfind(*this, s, pos);
}
size_type rfind(char c, size_type pos = npos) const {
return internal::rfind(*this, c, pos);
}
size_type find_first_of(const BasicStringPiece& s, size_type pos = 0) const {
return internal::find_first_of(*this, s, pos);
}
size_type find_first_of(char c, size_type pos = 0) const {
return find(c, pos);
}
size_type find_first_not_of(const BasicStringPiece& s,
size_type pos = 0) const {
return internal::find_first_not_of(*this, s, pos);
}
size_type find_first_not_of(char c, size_type pos = 0) const {
return internal::find_first_not_of(*this, c, pos);
}
size_type find_last_of(const BasicStringPiece& s,
size_type pos = npos) const {
return internal::find_last_of(*this, s, pos);
}
size_type find_last_of(char c, size_type pos = npos) const {
return rfind(c, pos);
}
size_type find_last_not_of(const BasicStringPiece& s,
size_type pos = npos) const {
return internal::find_last_not_of(*this, s, pos);
}
size_type find_last_not_of(char c, size_type pos = npos) const {
return internal::find_last_not_of(*this, c, pos);
}
BasicStringPiece substr(size_type pos, size_type n = npos) const {
return internal::substr(*this, pos, n);
}
};
// MSVC doesn't like complex extern templates and DLLs.
#if !defined(COMPILER_MSVC)
// We can't explicitly declare the std::string instantiation here because it was
// already instantiated when specialized, above. Not only is it a no-op, but
// currently it also crashes Clang (see http://crbug.com/107412).
extern template class BASE_EXPORT BasicStringPiece<std::string>;
extern template class BASE_EXPORT BasicStringPiece<string16>;
#endif
// StingPiece operators --------------------------------------------------------
BASE_EXPORT bool operator==(const StringPiece& x, const StringPiece& y);
inline bool operator!=(const StringPiece& x, const StringPiece& y) {
@ -372,6 +387,8 @@ inline bool operator>=(const StringPiece& x, const StringPiece& y) {
return !(x < y);
}
// StringPiece16 operators -----------------------------------------------------
inline bool operator==(const StringPiece16& x, const StringPiece16& y) {
if (x.size() != y.size())
return false;
@ -406,6 +423,8 @@ BASE_EXPORT std::ostream& operator<<(std::ostream& o,
} // namespace base
// Hashing ---------------------------------------------------------------------
// We provide appropriate hash functions so StringPiece and StringPiece16 can
// be used as keys in hash sets and maps.

Просмотреть файл

@ -0,0 +1,214 @@
// Copyright (c) 2012 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.
#include "base/strings/string_split.h"
#include "base/logging.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/third_party/icu/icu_utf.h"
namespace base {
namespace {
template <typename STR>
void SplitStringT(const STR& str,
const typename STR::value_type s,
bool trim_whitespace,
std::vector<STR>* r) {
r->clear();
size_t last = 0;
size_t c = str.size();
for (size_t i = 0; i <= c; ++i) {
if (i == c || str[i] == s) {
STR tmp(str, last, i - last);
if (trim_whitespace)
TrimWhitespace(tmp, TRIM_ALL, &tmp);
// Avoid converting an empty or all-whitespace source string into a vector
// of one empty string.
if (i != c || !r->empty() || !tmp.empty())
r->push_back(tmp);
last = i + 1;
}
}
}
bool SplitStringIntoKeyValue(const std::string& line,
char key_value_delimiter,
std::string* key,
std::string* value) {
key->clear();
value->clear();
// Find the delimiter.
size_t end_key_pos = line.find_first_of(key_value_delimiter);
if (end_key_pos == std::string::npos) {
DVLOG(1) << "cannot find delimiter in: " << line;
return false; // no delimiter
}
key->assign(line, 0, end_key_pos);
// Find the value string.
std::string remains(line, end_key_pos, line.size() - end_key_pos);
size_t begin_value_pos = remains.find_first_not_of(key_value_delimiter);
if (begin_value_pos == std::string::npos) {
DVLOG(1) << "cannot parse value from line: " << line;
return false; // no value
}
value->assign(remains, begin_value_pos, remains.size() - begin_value_pos);
return true;
}
template <typename STR>
void SplitStringUsingSubstrT(const STR& str,
const STR& s,
std::vector<STR>* r) {
r->clear();
typename STR::size_type begin_index = 0;
while (true) {
const typename STR::size_type end_index = str.find(s, begin_index);
if (end_index == STR::npos) {
const STR term = str.substr(begin_index);
STR tmp;
TrimWhitespace(term, TRIM_ALL, &tmp);
r->push_back(tmp);
return;
}
const STR term = str.substr(begin_index, end_index - begin_index);
STR tmp;
TrimWhitespace(term, TRIM_ALL, &tmp);
r->push_back(tmp);
begin_index = end_index + s.size();
}
}
template<typename STR>
void SplitStringAlongWhitespaceT(const STR& str, std::vector<STR>* result) {
result->clear();
const size_t length = str.length();
if (!length)
return;
bool last_was_ws = false;
size_t last_non_ws_start = 0;
for (size_t i = 0; i < length; ++i) {
switch (str[i]) {
// HTML 5 defines whitespace as: space, tab, LF, line tab, FF, or CR.
case L' ':
case L'\t':
case L'\xA':
case L'\xB':
case L'\xC':
case L'\xD':
if (!last_was_ws) {
if (i > 0) {
result->push_back(
str.substr(last_non_ws_start, i - last_non_ws_start));
}
last_was_ws = true;
}
break;
default: // Not a space character.
if (last_was_ws) {
last_was_ws = false;
last_non_ws_start = i;
}
break;
}
}
if (!last_was_ws) {
result->push_back(
str.substr(last_non_ws_start, length - last_non_ws_start));
}
}
} // namespace
void SplitString(const string16& str,
char16 c,
std::vector<string16>* r) {
DCHECK(CBU16_IS_SINGLE(c));
SplitStringT(str, c, true, r);
}
void SplitString(const std::string& str,
char c,
std::vector<std::string>* r) {
#if CHAR_MIN < 0
DCHECK(c >= 0);
#endif
DCHECK(c < 0x7F);
SplitStringT(str, c, true, r);
}
bool SplitStringIntoKeyValuePairs(const std::string& line,
char key_value_delimiter,
char key_value_pair_delimiter,
StringPairs* key_value_pairs) {
key_value_pairs->clear();
std::vector<std::string> pairs;
SplitString(line, key_value_pair_delimiter, &pairs);
bool success = true;
for (size_t i = 0; i < pairs.size(); ++i) {
// Don't add empty pairs into the result.
if (pairs[i].empty())
continue;
std::string key;
std::string value;
if (!SplitStringIntoKeyValue(pairs[i], key_value_delimiter, &key, &value)) {
// Don't return here, to allow for pairs without associated
// value or key; just record that the split failed.
success = false;
}
key_value_pairs->push_back(make_pair(key, value));
}
return success;
}
void SplitStringUsingSubstr(const string16& str,
const string16& s,
std::vector<string16>* r) {
SplitStringUsingSubstrT(str, s, r);
}
void SplitStringUsingSubstr(const std::string& str,
const std::string& s,
std::vector<std::string>* r) {
SplitStringUsingSubstrT(str, s, r);
}
void SplitStringDontTrim(const string16& str,
char16 c,
std::vector<string16>* r) {
DCHECK(CBU16_IS_SINGLE(c));
SplitStringT(str, c, false, r);
}
void SplitStringDontTrim(const std::string& str,
char c,
std::vector<std::string>* r) {
DCHECK(IsStringUTF8(str));
#if CHAR_MIN < 0
DCHECK(c >= 0);
#endif
DCHECK(c < 0x7F);
SplitStringT(str, c, false, r);
}
void SplitStringAlongWhitespace(const string16& str,
std::vector<string16>* result) {
SplitStringAlongWhitespaceT(str, result);
}
void SplitStringAlongWhitespace(const std::string& str,
std::vector<std::string>* result) {
SplitStringAlongWhitespaceT(str, result);
}
} // namespace base

Просмотреть файл

@ -0,0 +1,82 @@
// Copyright (c) 2012 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.
#ifndef BASE_STRINGS_STRING_SPLIT_H_
#define BASE_STRINGS_STRING_SPLIT_H_
#include <string>
#include <utility>
#include <vector>
#include "base/base_export.h"
#include "base/strings/string16.h"
namespace base {
// Splits |str| into a vector of strings delimited by |c|, placing the results
// in |r|. If several instances of |c| are contiguous, or if |str| begins with
// or ends with |c|, then an empty string is inserted.
//
// Every substring is trimmed of any leading or trailing white space.
// NOTE: |c| must be in BMP (Basic Multilingual Plane)
BASE_EXPORT void SplitString(const string16& str,
char16 c,
std::vector<string16>* r);
// |str| should not be in a multi-byte encoding like Shift-JIS or GBK in which
// the trailing byte of a multi-byte character can be in the ASCII range.
// UTF-8, and other single/multi-byte ASCII-compatible encodings are OK.
// Note: |c| must be in the ASCII range.
BASE_EXPORT void SplitString(const std::string& str,
char c,
std::vector<std::string>* r);
typedef std::vector<std::pair<std::string, std::string> > StringPairs;
// Splits |line| into key value pairs according to the given delimiters and
// removes whitespace leading each key and trailing each value. Returns true
// only if each pair has a non-empty key and value. |key_value_pairs| will
// include ("","") pairs for entries without |key_value_delimiter|.
BASE_EXPORT bool SplitStringIntoKeyValuePairs(const std::string& line,
char key_value_delimiter,
char key_value_pair_delimiter,
StringPairs* key_value_pairs);
// The same as SplitString, but use a substring delimiter instead of a char.
BASE_EXPORT void SplitStringUsingSubstr(const string16& str,
const string16& s,
std::vector<string16>* r);
BASE_EXPORT void SplitStringUsingSubstr(const std::string& str,
const std::string& s,
std::vector<std::string>* r);
// The same as SplitString, but don't trim white space.
// NOTE: |c| must be in BMP (Basic Multilingual Plane)
BASE_EXPORT void SplitStringDontTrim(const string16& str,
char16 c,
std::vector<string16>* r);
// |str| should not be in a multi-byte encoding like Shift-JIS or GBK in which
// the trailing byte of a multi-byte character can be in the ASCII range.
// UTF-8, and other single/multi-byte ASCII-compatible encodings are OK.
// Note: |c| must be in the ASCII range.
BASE_EXPORT void SplitStringDontTrim(const std::string& str,
char c,
std::vector<std::string>* r);
// WARNING: this uses whitespace as defined by the HTML5 spec. If you need
// a function similar to this but want to trim all types of whitespace, then
// factor this out into a function that takes a string containing the characters
// that are treated as whitespace.
//
// Splits the string along whitespace (where whitespace is the five space
// characters defined by HTML 5). Each contiguous block of non-whitespace
// characters is added to result.
BASE_EXPORT void SplitStringAlongWhitespace(const string16& str,
std::vector<string16>* result);
BASE_EXPORT void SplitStringAlongWhitespace(const std::string& str,
std::vector<std::string>* result);
} // namespace base
#endif // BASE_STRINGS_STRING_SPLIT_H_

Просмотреть файл

@ -0,0 +1,892 @@
// Copyright 2013 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.
#include "base/strings/string_util.h"
#include <ctype.h>
#include <errno.h>
#include <math.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <wchar.h>
#include <wctype.h>
#include <algorithm>
#include <vector>
#include "base/basictypes.h"
#include "base/logging.h"
#include "base/memory/singleton.h"
#include "base/strings/utf_string_conversion_utils.h"
#include "base/strings/utf_string_conversions.h"
#include "base/third_party/icu/icu_utf.h"
#include "build/build_config.h"
// Remove when this entire file is in the base namespace.
using base::char16;
using base::string16;
namespace {
// Force the singleton used by EmptyString[16] to be a unique type. This
// prevents other code that might accidentally use Singleton<string> from
// getting our internal one.
struct EmptyStrings {
EmptyStrings() {}
const std::string s;
const string16 s16;
static EmptyStrings* GetInstance() {
return Singleton<EmptyStrings>::get();
}
};
// Used by ReplaceStringPlaceholders to track the position in the string of
// replaced parameters.
struct ReplacementOffset {
ReplacementOffset(uintptr_t parameter, size_t offset)
: parameter(parameter),
offset(offset) {}
// Index of the parameter.
uintptr_t parameter;
// Starting position in the string.
size_t offset;
};
static bool CompareParameter(const ReplacementOffset& elem1,
const ReplacementOffset& elem2) {
return elem1.parameter < elem2.parameter;
}
} // namespace
namespace base {
bool IsWprintfFormatPortable(const wchar_t* format) {
for (const wchar_t* position = format; *position != '\0'; ++position) {
if (*position == '%') {
bool in_specification = true;
bool modifier_l = false;
while (in_specification) {
// Eat up characters until reaching a known specifier.
if (*++position == '\0') {
// The format string ended in the middle of a specification. Call
// it portable because no unportable specifications were found. The
// string is equally broken on all platforms.
return true;
}
if (*position == 'l') {
// 'l' is the only thing that can save the 's' and 'c' specifiers.
modifier_l = true;
} else if (((*position == 's' || *position == 'c') && !modifier_l) ||
*position == 'S' || *position == 'C' || *position == 'F' ||
*position == 'D' || *position == 'O' || *position == 'U') {
// Not portable.
return false;
}
if (wcschr(L"diouxXeEfgGaAcspn%", *position)) {
// Portable, keep scanning the rest of the format string.
in_specification = false;
}
}
}
}
return true;
}
const std::string& EmptyString() {
return EmptyStrings::GetInstance()->s;
}
const string16& EmptyString16() {
return EmptyStrings::GetInstance()->s16;
}
template<typename STR>
bool ReplaceCharsT(const STR& input,
const STR& replace_chars,
const STR& replace_with,
STR* output) {
bool removed = false;
size_t replace_length = replace_with.length();
*output = input;
size_t found = output->find_first_of(replace_chars);
while (found != STR::npos) {
removed = true;
output->replace(found, 1, replace_with);
found = output->find_first_of(replace_chars, found + replace_length);
}
return removed;
}
bool ReplaceChars(const string16& input,
const base::StringPiece16& replace_chars,
const string16& replace_with,
string16* output) {
return ReplaceCharsT(input, replace_chars.as_string(), replace_with, output);
}
bool ReplaceChars(const std::string& input,
const base::StringPiece& replace_chars,
const std::string& replace_with,
std::string* output) {
return ReplaceCharsT(input, replace_chars.as_string(), replace_with, output);
}
bool RemoveChars(const string16& input,
const base::StringPiece16& remove_chars,
string16* output) {
return ReplaceChars(input, remove_chars.as_string(), string16(), output);
}
bool RemoveChars(const std::string& input,
const base::StringPiece& remove_chars,
std::string* output) {
return ReplaceChars(input, remove_chars.as_string(), std::string(), output);
}
template<typename STR>
TrimPositions TrimStringT(const STR& input,
const STR& trim_chars,
TrimPositions positions,
STR* output) {
// Find the edges of leading/trailing whitespace as desired.
const size_t last_char = input.length() - 1;
const size_t first_good_char = (positions & TRIM_LEADING) ?
input.find_first_not_of(trim_chars) : 0;
const size_t last_good_char = (positions & TRIM_TRAILING) ?
input.find_last_not_of(trim_chars) : last_char;
// When the string was all whitespace, report that we stripped off whitespace
// from whichever position the caller was interested in. For empty input, we
// stripped no whitespace, but we still need to clear |output|.
if (input.empty() ||
(first_good_char == STR::npos) || (last_good_char == STR::npos)) {
bool input_was_empty = input.empty(); // in case output == &input
output->clear();
return input_was_empty ? TRIM_NONE : positions;
}
// Trim the whitespace.
*output =
input.substr(first_good_char, last_good_char - first_good_char + 1);
// Return where we trimmed from.
return static_cast<TrimPositions>(
((first_good_char == 0) ? TRIM_NONE : TRIM_LEADING) |
((last_good_char == last_char) ? TRIM_NONE : TRIM_TRAILING));
}
bool TrimString(const string16& input,
const base::StringPiece16& trim_chars,
string16* output) {
return TrimStringT(input, trim_chars.as_string(), TRIM_ALL, output) !=
TRIM_NONE;
}
bool TrimString(const std::string& input,
const base::StringPiece& trim_chars,
std::string* output) {
return TrimStringT(input, trim_chars.as_string(), TRIM_ALL, output) !=
TRIM_NONE;
}
void TruncateUTF8ToByteSize(const std::string& input,
const size_t byte_size,
std::string* output) {
DCHECK(output);
if (byte_size > input.length()) {
*output = input;
return;
}
DCHECK_LE(byte_size, static_cast<uint32>(kint32max));
// Note: This cast is necessary because CBU8_NEXT uses int32s.
int32 truncation_length = static_cast<int32>(byte_size);
int32 char_index = truncation_length - 1;
const char* data = input.data();
// Using CBU8, we will move backwards from the truncation point
// to the beginning of the string looking for a valid UTF8
// character. Once a full UTF8 character is found, we will
// truncate the string to the end of that character.
while (char_index >= 0) {
int32 prev = char_index;
base_icu::UChar32 code_point = 0;
CBU8_NEXT(data, char_index, truncation_length, code_point);
if (!IsValidCharacter(code_point) ||
!IsValidCodepoint(code_point)) {
char_index = prev - 1;
} else {
break;
}
}
if (char_index >= 0 )
*output = input.substr(0, char_index);
else
output->clear();
}
TrimPositions TrimWhitespace(const string16& input,
TrimPositions positions,
string16* output) {
return TrimStringT(input, base::string16(kWhitespaceUTF16), positions,
output);
}
TrimPositions TrimWhitespaceASCII(const std::string& input,
TrimPositions positions,
std::string* output) {
return TrimStringT(input, std::string(kWhitespaceASCII), positions, output);
}
// This function is only for backward-compatibility.
// To be removed when all callers are updated.
TrimPositions TrimWhitespace(const std::string& input,
TrimPositions positions,
std::string* output) {
return TrimWhitespaceASCII(input, positions, output);
}
template<typename STR>
STR CollapseWhitespaceT(const STR& text,
bool trim_sequences_with_line_breaks) {
STR result;
result.resize(text.size());
// Set flags to pretend we're already in a trimmed whitespace sequence, so we
// will trim any leading whitespace.
bool in_whitespace = true;
bool already_trimmed = true;
int chars_written = 0;
for (typename STR::const_iterator i(text.begin()); i != text.end(); ++i) {
if (IsWhitespace(*i)) {
if (!in_whitespace) {
// Reduce all whitespace sequences to a single space.
in_whitespace = true;
result[chars_written++] = L' ';
}
if (trim_sequences_with_line_breaks && !already_trimmed &&
((*i == '\n') || (*i == '\r'))) {
// Whitespace sequences containing CR or LF are eliminated entirely.
already_trimmed = true;
--chars_written;
}
} else {
// Non-whitespace chracters are copied straight across.
in_whitespace = false;
already_trimmed = false;
result[chars_written++] = *i;
}
}
if (in_whitespace && !already_trimmed) {
// Any trailing whitespace is eliminated.
--chars_written;
}
result.resize(chars_written);
return result;
}
string16 CollapseWhitespace(const string16& text,
bool trim_sequences_with_line_breaks) {
return CollapseWhitespaceT(text, trim_sequences_with_line_breaks);
}
std::string CollapseWhitespaceASCII(const std::string& text,
bool trim_sequences_with_line_breaks) {
return CollapseWhitespaceT(text, trim_sequences_with_line_breaks);
}
bool ContainsOnlyChars(const StringPiece& input,
const StringPiece& characters) {
return input.find_first_not_of(characters) == StringPiece::npos;
}
bool ContainsOnlyChars(const StringPiece16& input,
const StringPiece16& characters) {
return input.find_first_not_of(characters) == StringPiece16::npos;
}
template<class STR>
static bool DoIsStringASCII(const STR& str) {
for (size_t i = 0; i < str.length(); i++) {
typename ToUnsigned<typename STR::value_type>::Unsigned c = str[i];
if (c > 0x7F)
return false;
}
return true;
}
bool IsStringASCII(const StringPiece& str) {
return DoIsStringASCII(str);
}
bool IsStringASCII(const string16& str) {
return DoIsStringASCII(str);
}
bool IsStringUTF8(const std::string& str) {
const char *src = str.data();
int32 src_len = static_cast<int32>(str.length());
int32 char_index = 0;
while (char_index < src_len) {
int32 code_point;
CBU8_NEXT(src, char_index, src_len, code_point);
if (!IsValidCharacter(code_point))
return false;
}
return true;
}
} // namespace base
template<typename Iter>
static inline bool DoLowerCaseEqualsASCII(Iter a_begin,
Iter a_end,
const char* b) {
for (Iter it = a_begin; it != a_end; ++it, ++b) {
if (!*b || base::ToLowerASCII(*it) != *b)
return false;
}
return *b == 0;
}
// Front-ends for LowerCaseEqualsASCII.
bool LowerCaseEqualsASCII(const std::string& a, const char* b) {
return DoLowerCaseEqualsASCII(a.begin(), a.end(), b);
}
bool LowerCaseEqualsASCII(const string16& a, const char* b) {
return DoLowerCaseEqualsASCII(a.begin(), a.end(), b);
}
bool LowerCaseEqualsASCII(std::string::const_iterator a_begin,
std::string::const_iterator a_end,
const char* b) {
return DoLowerCaseEqualsASCII(a_begin, a_end, b);
}
bool LowerCaseEqualsASCII(string16::const_iterator a_begin,
string16::const_iterator a_end,
const char* b) {
return DoLowerCaseEqualsASCII(a_begin, a_end, b);
}
// TODO(port): Resolve wchar_t/iterator issues that require OS_ANDROID here.
#if !defined(OS_ANDROID)
bool LowerCaseEqualsASCII(const char* a_begin,
const char* a_end,
const char* b) {
return DoLowerCaseEqualsASCII(a_begin, a_end, b);
}
bool LowerCaseEqualsASCII(const char16* a_begin,
const char16* a_end,
const char* b) {
return DoLowerCaseEqualsASCII(a_begin, a_end, b);
}
#endif // !defined(OS_ANDROID)
bool EqualsASCII(const string16& a, const base::StringPiece& b) {
if (a.length() != b.length())
return false;
return std::equal(b.begin(), b.end(), a.begin());
}
bool StartsWithASCII(const std::string& str,
const std::string& search,
bool case_sensitive) {
if (case_sensitive)
return str.compare(0, search.length(), search) == 0;
else
return base::strncasecmp(str.c_str(), search.c_str(), search.length()) == 0;
}
template <typename STR>
bool StartsWithT(const STR& str, const STR& search, bool case_sensitive) {
if (case_sensitive) {
return str.compare(0, search.length(), search) == 0;
} else {
if (search.size() > str.size())
return false;
return std::equal(search.begin(), search.end(), str.begin(),
base::CaseInsensitiveCompare<typename STR::value_type>());
}
}
bool StartsWith(const string16& str, const string16& search,
bool case_sensitive) {
return StartsWithT(str, search, case_sensitive);
}
template <typename STR>
bool EndsWithT(const STR& str, const STR& search, bool case_sensitive) {
size_t str_length = str.length();
size_t search_length = search.length();
if (search_length > str_length)
return false;
if (case_sensitive)
return str.compare(str_length - search_length, search_length, search) == 0;
return std::equal(search.begin(), search.end(),
str.begin() + (str_length - search_length),
base::CaseInsensitiveCompare<typename STR::value_type>());
}
bool EndsWith(const std::string& str, const std::string& search,
bool case_sensitive) {
return EndsWithT(str, search, case_sensitive);
}
bool EndsWith(const string16& str, const string16& search,
bool case_sensitive) {
return EndsWithT(str, search, case_sensitive);
}
static const char* const kByteStringsUnlocalized[] = {
" B",
" kB",
" MB",
" GB",
" TB",
" PB"
};
string16 FormatBytesUnlocalized(int64 bytes) {
double unit_amount = static_cast<double>(bytes);
size_t dimension = 0;
const int kKilo = 1024;
while (unit_amount >= kKilo &&
dimension < arraysize(kByteStringsUnlocalized) - 1) {
unit_amount /= kKilo;
dimension++;
}
char buf[64];
if (bytes != 0 && dimension > 0 && unit_amount < 100) {
base::snprintf(buf, arraysize(buf), "%.1lf%s", unit_amount,
kByteStringsUnlocalized[dimension]);
} else {
base::snprintf(buf, arraysize(buf), "%.0lf%s", unit_amount,
kByteStringsUnlocalized[dimension]);
}
return base::ASCIIToUTF16(buf);
}
template<class StringType>
void DoReplaceSubstringsAfterOffset(StringType* str,
size_t start_offset,
const StringType& find_this,
const StringType& replace_with,
bool replace_all) {
if ((start_offset == StringType::npos) || (start_offset >= str->length()))
return;
DCHECK(!find_this.empty());
for (size_t offs(str->find(find_this, start_offset));
offs != StringType::npos; offs = str->find(find_this, offs)) {
str->replace(offs, find_this.length(), replace_with);
offs += replace_with.length();
if (!replace_all)
break;
}
}
void ReplaceFirstSubstringAfterOffset(string16* str,
size_t start_offset,
const string16& find_this,
const string16& replace_with) {
DoReplaceSubstringsAfterOffset(str, start_offset, find_this, replace_with,
false); // replace first instance
}
void ReplaceFirstSubstringAfterOffset(std::string* str,
size_t start_offset,
const std::string& find_this,
const std::string& replace_with) {
DoReplaceSubstringsAfterOffset(str, start_offset, find_this, replace_with,
false); // replace first instance
}
void ReplaceSubstringsAfterOffset(string16* str,
size_t start_offset,
const string16& find_this,
const string16& replace_with) {
DoReplaceSubstringsAfterOffset(str, start_offset, find_this, replace_with,
true); // replace all instances
}
void ReplaceSubstringsAfterOffset(std::string* str,
size_t start_offset,
const std::string& find_this,
const std::string& replace_with) {
DoReplaceSubstringsAfterOffset(str, start_offset, find_this, replace_with,
true); // replace all instances
}
template<typename STR>
static size_t TokenizeT(const STR& str,
const STR& delimiters,
std::vector<STR>* tokens) {
tokens->clear();
size_t start = str.find_first_not_of(delimiters);
while (start != STR::npos) {
size_t end = str.find_first_of(delimiters, start + 1);
if (end == STR::npos) {
tokens->push_back(str.substr(start));
break;
} else {
tokens->push_back(str.substr(start, end - start));
start = str.find_first_not_of(delimiters, end + 1);
}
}
return tokens->size();
}
size_t Tokenize(const string16& str,
const string16& delimiters,
std::vector<string16>* tokens) {
return TokenizeT(str, delimiters, tokens);
}
size_t Tokenize(const std::string& str,
const std::string& delimiters,
std::vector<std::string>* tokens) {
return TokenizeT(str, delimiters, tokens);
}
size_t Tokenize(const base::StringPiece& str,
const base::StringPiece& delimiters,
std::vector<base::StringPiece>* tokens) {
return TokenizeT(str, delimiters, tokens);
}
template<typename STR>
static STR JoinStringT(const std::vector<STR>& parts, const STR& sep) {
if (parts.empty())
return STR();
STR result(parts[0]);
typename std::vector<STR>::const_iterator iter = parts.begin();
++iter;
for (; iter != parts.end(); ++iter) {
result += sep;
result += *iter;
}
return result;
}
std::string JoinString(const std::vector<std::string>& parts, char sep) {
return JoinStringT(parts, std::string(1, sep));
}
string16 JoinString(const std::vector<string16>& parts, char16 sep) {
return JoinStringT(parts, string16(1, sep));
}
std::string JoinString(const std::vector<std::string>& parts,
const std::string& separator) {
return JoinStringT(parts, separator);
}
string16 JoinString(const std::vector<string16>& parts,
const string16& separator) {
return JoinStringT(parts, separator);
}
template<class FormatStringType, class OutStringType>
OutStringType DoReplaceStringPlaceholders(const FormatStringType& format_string,
const std::vector<OutStringType>& subst, std::vector<size_t>* offsets) {
size_t substitutions = subst.size();
size_t sub_length = 0;
for (typename std::vector<OutStringType>::const_iterator iter = subst.begin();
iter != subst.end(); ++iter) {
sub_length += iter->length();
}
OutStringType formatted;
formatted.reserve(format_string.length() + sub_length);
std::vector<ReplacementOffset> r_offsets;
for (typename FormatStringType::const_iterator i = format_string.begin();
i != format_string.end(); ++i) {
if ('$' == *i) {
if (i + 1 != format_string.end()) {
++i;
DCHECK('$' == *i || '1' <= *i) << "Invalid placeholder: " << *i;
if ('$' == *i) {
while (i != format_string.end() && '$' == *i) {
formatted.push_back('$');
++i;
}
--i;
} else {
uintptr_t index = 0;
while (i != format_string.end() && '0' <= *i && *i <= '9') {
index *= 10;
index += *i - '0';
++i;
}
--i;
index -= 1;
if (offsets) {
ReplacementOffset r_offset(index,
static_cast<int>(formatted.size()));
r_offsets.insert(std::lower_bound(r_offsets.begin(),
r_offsets.end(),
r_offset,
&CompareParameter),
r_offset);
}
if (index < substitutions)
formatted.append(subst.at(index));
}
}
} else {
formatted.push_back(*i);
}
}
if (offsets) {
for (std::vector<ReplacementOffset>::const_iterator i = r_offsets.begin();
i != r_offsets.end(); ++i) {
offsets->push_back(i->offset);
}
}
return formatted;
}
string16 ReplaceStringPlaceholders(const string16& format_string,
const std::vector<string16>& subst,
std::vector<size_t>* offsets) {
return DoReplaceStringPlaceholders(format_string, subst, offsets);
}
std::string ReplaceStringPlaceholders(const base::StringPiece& format_string,
const std::vector<std::string>& subst,
std::vector<size_t>* offsets) {
return DoReplaceStringPlaceholders(format_string, subst, offsets);
}
string16 ReplaceStringPlaceholders(const string16& format_string,
const string16& a,
size_t* offset) {
std::vector<size_t> offsets;
std::vector<string16> subst;
subst.push_back(a);
string16 result = ReplaceStringPlaceholders(format_string, subst, &offsets);
DCHECK_EQ(1U, offsets.size());
if (offset)
*offset = offsets[0];
return result;
}
static bool IsWildcard(base_icu::UChar32 character) {
return character == '*' || character == '?';
}
// Move the strings pointers to the point where they start to differ.
template <typename CHAR, typename NEXT>
static void EatSameChars(const CHAR** pattern, const CHAR* pattern_end,
const CHAR** string, const CHAR* string_end,
NEXT next) {
const CHAR* escape = NULL;
while (*pattern != pattern_end && *string != string_end) {
if (!escape && IsWildcard(**pattern)) {
// We don't want to match wildcard here, except if it's escaped.
return;
}
// Check if the escapement char is found. If so, skip it and move to the
// next character.
if (!escape && **pattern == '\\') {
escape = *pattern;
next(pattern, pattern_end);
continue;
}
// Check if the chars match, if so, increment the ptrs.
const CHAR* pattern_next = *pattern;
const CHAR* string_next = *string;
base_icu::UChar32 pattern_char = next(&pattern_next, pattern_end);
if (pattern_char == next(&string_next, string_end) &&
pattern_char != CBU_SENTINEL) {
*pattern = pattern_next;
*string = string_next;
} else {
// Uh oh, it did not match, we are done. If the last char was an
// escapement, that means that it was an error to advance the ptr here,
// let's put it back where it was. This also mean that the MatchPattern
// function will return false because if we can't match an escape char
// here, then no one will.
if (escape) {
*pattern = escape;
}
return;
}
escape = NULL;
}
}
template <typename CHAR, typename NEXT>
static void EatWildcard(const CHAR** pattern, const CHAR* end, NEXT next) {
while (*pattern != end) {
if (!IsWildcard(**pattern))
return;
next(pattern, end);
}
}
template <typename CHAR, typename NEXT>
static bool MatchPatternT(const CHAR* eval, const CHAR* eval_end,
const CHAR* pattern, const CHAR* pattern_end,
int depth,
NEXT next) {
const int kMaxDepth = 16;
if (depth > kMaxDepth)
return false;
// Eat all the matching chars.
EatSameChars(&pattern, pattern_end, &eval, eval_end, next);
// If the string is empty, then the pattern must be empty too, or contains
// only wildcards.
if (eval == eval_end) {
EatWildcard(&pattern, pattern_end, next);
return pattern == pattern_end;
}
// Pattern is empty but not string, this is not a match.
if (pattern == pattern_end)
return false;
// If this is a question mark, then we need to compare the rest with
// the current string or the string with one character eaten.
const CHAR* next_pattern = pattern;
next(&next_pattern, pattern_end);
if (pattern[0] == '?') {
if (MatchPatternT(eval, eval_end, next_pattern, pattern_end,
depth + 1, next))
return true;
const CHAR* next_eval = eval;
next(&next_eval, eval_end);
if (MatchPatternT(next_eval, eval_end, next_pattern, pattern_end,
depth + 1, next))
return true;
}
// This is a *, try to match all the possible substrings with the remainder
// of the pattern.
if (pattern[0] == '*') {
// Collapse duplicate wild cards (********** into *) so that the
// method does not recurse unnecessarily. http://crbug.com/52839
EatWildcard(&next_pattern, pattern_end, next);
while (eval != eval_end) {
if (MatchPatternT(eval, eval_end, next_pattern, pattern_end,
depth + 1, next))
return true;
eval++;
}
// We reached the end of the string, let see if the pattern contains only
// wildcards.
if (eval == eval_end) {
EatWildcard(&pattern, pattern_end, next);
if (pattern != pattern_end)
return false;
return true;
}
}
return false;
}
struct NextCharUTF8 {
base_icu::UChar32 operator()(const char** p, const char* end) {
base_icu::UChar32 c;
int offset = 0;
CBU8_NEXT(*p, offset, end - *p, c);
*p += offset;
return c;
}
};
struct NextCharUTF16 {
base_icu::UChar32 operator()(const char16** p, const char16* end) {
base_icu::UChar32 c;
int offset = 0;
CBU16_NEXT(*p, offset, end - *p, c);
*p += offset;
return c;
}
};
bool MatchPattern(const base::StringPiece& eval,
const base::StringPiece& pattern) {
return MatchPatternT(eval.data(), eval.data() + eval.size(),
pattern.data(), pattern.data() + pattern.size(),
0, NextCharUTF8());
}
bool MatchPattern(const string16& eval, const string16& pattern) {
return MatchPatternT(eval.c_str(), eval.c_str() + eval.size(),
pattern.c_str(), pattern.c_str() + pattern.size(),
0, NextCharUTF16());
}
// The following code is compatible with the OpenBSD lcpy interface. See:
// http://www.gratisoft.us/todd/papers/strlcpy.html
// ftp://ftp.openbsd.org/pub/OpenBSD/src/lib/libc/string/{wcs,str}lcpy.c
namespace {
template <typename CHAR>
size_t lcpyT(CHAR* dst, const CHAR* src, size_t dst_size) {
for (size_t i = 0; i < dst_size; ++i) {
if ((dst[i] = src[i]) == 0) // We hit and copied the terminating NULL.
return i;
}
// We were left off at dst_size. We over copied 1 byte. Null terminate.
if (dst_size != 0)
dst[dst_size - 1] = 0;
// Count the rest of the |src|, and return it's length in characters.
while (src[dst_size]) ++dst_size;
return dst_size;
}
} // namespace
size_t base::strlcpy(char* dst, const char* src, size_t dst_size) {
return lcpyT<char>(dst, src, dst_size);
}
size_t base::wcslcpy(wchar_t* dst, const wchar_t* src, size_t dst_size) {
return lcpyT<wchar_t>(dst, src, dst_size);
}

Просмотреть файл

@ -19,8 +19,6 @@
#include "base/strings/string16.h"
#include "base/strings/string_piece.h" // For implicit conversions.
// Safe standard library wrappers for all platforms.
namespace base {
// C standard-library functions like "strncasecmp" and "snprintf" that aren't
@ -47,14 +45,6 @@ int strncmp16(const char16* s1, const char16* s2, size_t count);
int vsnprintf(char* buffer, size_t size, const char* format, va_list arguments)
PRINTF_FORMAT(3, 0);
// vswprintf always null-terminates, but when truncation occurs, it will either
// return -1 or the number of characters that would be in an untruncated
// formatted string. The actual return value depends on the underlying
// C library's vswprintf implementation.
int vswprintf(wchar_t* buffer, size_t size,
const wchar_t* format, va_list arguments)
WPRINTF_FORMAT(3, 0);
// Some of these implementations need to be inlined.
// We separate the declaration from the implementation of this inline
@ -69,18 +59,6 @@ inline int snprintf(char* buffer, size_t size, const char* format, ...) {
return result;
}
// We separate the declaration from the implementation of this inline
// function just so the WPRINTF_FORMAT works.
inline int swprintf(wchar_t* buffer, size_t size, const wchar_t* format, ...)
WPRINTF_FORMAT(3, 4);
inline int swprintf(wchar_t* buffer, size_t size, const wchar_t* format, ...) {
va_list arguments;
va_start(arguments, format);
int result = vswprintf(buffer, size, format, arguments);
va_end(arguments);
return result;
}
// BSD-style safe and consistent string copy functions.
// Copies |src| to |dst|, where |dst_size| is the total allocated size of |dst|.
// Copies at most |dst_size|-1 characters, and always NULL terminates |dst|, as
@ -143,43 +121,39 @@ template<typename Char> struct CaseInsensitiveCompareASCII {
}
};
} // namespace base
#if defined(OS_WIN)
#include "base/strings/string_util_win.h"
#elif defined(OS_POSIX)
#include "base/strings/string_util_posix.h"
#else
#error Define string operations appropriately for your platform
#endif
// These threadsafe functions return references to globally unique empty
// strings.
//
// DO NOT USE THESE AS A GENERAL-PURPOSE SUBSTITUTE FOR DEFAULT CONSTRUCTORS.
// There is only one case where you should use these: functions which need to
// return a string by reference (e.g. as a class member accessor), and don't
// have an empty string to use (e.g. in an error case). These should not be
// used as initializers, function arguments, or return values for functions
// which return by value or outparam.
// It is likely faster to construct a new empty string object (just a few
// instructions to set the length to 0) than to get the empty string singleton
// returned by these functions (which requires threadsafe singleton access).
//
// Therefore, DO NOT USE THESE AS A GENERAL-PURPOSE SUBSTITUTE FOR DEFAULT
// CONSTRUCTORS. There is only one case where you should use these: functions
// which need to return a string by reference (e.g. as a class member
// accessor), and don't have an empty string to use (e.g. in an error case).
// These should not be used as initializers, function arguments, or return
// values for functions which return by value or outparam.
BASE_EXPORT const std::string& EmptyString();
BASE_EXPORT const std::wstring& EmptyWString();
BASE_EXPORT const string16& EmptyString16();
// Contains the set of characters representing whitespace in the corresponding
// encoding. Null-terminated.
BASE_EXPORT extern const wchar_t kWhitespaceWide[];
BASE_EXPORT extern const char16 kWhitespaceUTF16[];
BASE_EXPORT extern const char kWhitespaceASCII[];
// Null-terminated string representing the UTF-8 byte order mark.
BASE_EXPORT extern const char kUtf8ByteOrderMark[];
// Removes characters in |remove_chars| from anywhere in |input|. Returns true
// if any characters were removed. |remove_chars| must be null-terminated.
// NOTE: Safe to use the same variable for both |input| and |output|.
BASE_EXPORT bool RemoveChars(const string16& input,
const char16 remove_chars[],
const base::StringPiece16& remove_chars,
string16* output);
BASE_EXPORT bool RemoveChars(const std::string& input,
const char remove_chars[],
const base::StringPiece& remove_chars,
std::string* output);
// Replaces characters in |replace_chars| from anywhere in |input| with
@ -188,25 +162,22 @@ BASE_EXPORT bool RemoveChars(const std::string& input,
// |replace_chars| must be null-terminated.
// NOTE: Safe to use the same variable for both |input| and |output|.
BASE_EXPORT bool ReplaceChars(const string16& input,
const char16 replace_chars[],
const base::StringPiece16& replace_chars,
const string16& replace_with,
string16* output);
BASE_EXPORT bool ReplaceChars(const std::string& input,
const char replace_chars[],
const base::StringPiece& replace_chars,
const std::string& replace_with,
std::string* output);
// Removes characters in |trim_chars| from the beginning and end of |input|.
// |trim_chars| must be null-terminated.
// NOTE: Safe to use the same variable for both |input| and |output|.
BASE_EXPORT bool TrimString(const std::wstring& input,
const wchar_t trim_chars[],
std::wstring* output);
BASE_EXPORT bool TrimString(const string16& input,
const char16 trim_chars[],
const base::StringPiece16& trim_chars,
string16* output);
BASE_EXPORT bool TrimString(const std::string& input,
const char trim_chars[],
const base::StringPiece& trim_chars,
std::string* output);
// Truncates a string to the nearest UTF-8 character that will leave
@ -230,7 +201,7 @@ enum TrimPositions {
};
BASE_EXPORT TrimPositions TrimWhitespace(const string16& input,
TrimPositions positions,
string16* output);
base::string16* output);
BASE_EXPORT TrimPositions TrimWhitespaceASCII(const std::string& input,
TrimPositions positions,
std::string* output);
@ -249,9 +220,6 @@ BASE_EXPORT TrimPositions TrimWhitespace(const std::string& input,
// (2) If |trim_sequences_with_line_breaks| is true, any other whitespace
// sequences containing a CR or LF are trimmed.
// (3) All other whitespace sequences are converted to single spaces.
BASE_EXPORT std::wstring CollapseWhitespace(
const std::wstring& text,
bool trim_sequences_with_line_breaks);
BASE_EXPORT string16 CollapseWhitespace(
const string16& text,
bool trim_sequences_with_line_breaks);
@ -259,28 +227,12 @@ BASE_EXPORT std::string CollapseWhitespaceASCII(
const std::string& text,
bool trim_sequences_with_line_breaks);
// Returns true if the passed string is empty or contains only white-space
// characters.
BASE_EXPORT bool ContainsOnlyWhitespaceASCII(const std::string& str);
BASE_EXPORT bool ContainsOnlyWhitespace(const string16& str);
// Returns true if |input| is empty or contains only characters found in
// |characters|.
BASE_EXPORT bool ContainsOnlyChars(const std::wstring& input,
const std::wstring& characters);
BASE_EXPORT bool ContainsOnlyChars(const string16& input,
const string16& characters);
BASE_EXPORT bool ContainsOnlyChars(const std::string& input,
const std::string& characters);
// Converts to 7-bit ASCII by truncating. The result must be known to be ASCII
// beforehand.
BASE_EXPORT std::string WideToASCII(const std::wstring& wide);
BASE_EXPORT std::string UTF16ToASCII(const string16& utf16);
// Converts the given wide string to the corresponding Latin1. This will fail
// (return false) if any characters are more than 255.
BASE_EXPORT bool WideToLatin1(const std::wstring& wide, std::string* latin1);
BASE_EXPORT bool ContainsOnlyChars(const StringPiece& input,
const StringPiece& characters);
BASE_EXPORT bool ContainsOnlyChars(const StringPiece16& input,
const StringPiece16& characters);
// Returns true if the specified string matches the criteria. How can a wide
// string be 8-bit or UTF8? It contains only characters that are < 256 (in the
@ -294,9 +246,19 @@ BASE_EXPORT bool WideToLatin1(const std::wstring& wide, std::string* latin1);
// there's a use case for just checking the structural validity, we have to
// add a new function for that.
BASE_EXPORT bool IsStringUTF8(const std::string& str);
BASE_EXPORT bool IsStringASCII(const std::wstring& str);
BASE_EXPORT bool IsStringASCII(const StringPiece& str);
BASE_EXPORT bool IsStringASCII(const string16& str);
} // namespace base
#if defined(OS_WIN)
#include "base/strings/string_util_win.h"
#elif defined(OS_POSIX)
#include "base/strings/string_util_posix.h"
#else
#error Define string operations appropriately for your platform
#endif
// Converts the elements of the given string. This version uses a pointer to
// clearly differentiate it from the non-pointer variant.
template <class str> inline void StringToLowerASCII(str* s) {
@ -330,53 +292,40 @@ template <class str> inline str StringToUpperASCII(const str& s) {
// token, and it is optimized to avoid intermediate string copies. This API is
// borrowed from the equivalent APIs in Mozilla.
BASE_EXPORT bool LowerCaseEqualsASCII(const std::string& a, const char* b);
BASE_EXPORT bool LowerCaseEqualsASCII(const std::wstring& a, const char* b);
BASE_EXPORT bool LowerCaseEqualsASCII(const string16& a, const char* b);
BASE_EXPORT bool LowerCaseEqualsASCII(const base::string16& a, const char* b);
// Same thing, but with string iterators instead.
BASE_EXPORT bool LowerCaseEqualsASCII(std::string::const_iterator a_begin,
std::string::const_iterator a_end,
const char* b);
BASE_EXPORT bool LowerCaseEqualsASCII(std::wstring::const_iterator a_begin,
std::wstring::const_iterator a_end,
const char* b);
BASE_EXPORT bool LowerCaseEqualsASCII(string16::const_iterator a_begin,
string16::const_iterator a_end,
BASE_EXPORT bool LowerCaseEqualsASCII(base::string16::const_iterator a_begin,
base::string16::const_iterator a_end,
const char* b);
BASE_EXPORT bool LowerCaseEqualsASCII(const char* a_begin,
const char* a_end,
const char* b);
BASE_EXPORT bool LowerCaseEqualsASCII(const wchar_t* a_begin,
const wchar_t* a_end,
const char* b);
BASE_EXPORT bool LowerCaseEqualsASCII(const char16* a_begin,
const char16* a_end,
BASE_EXPORT bool LowerCaseEqualsASCII(const base::char16* a_begin,
const base::char16* a_end,
const char* b);
// Performs a case-sensitive string compare. The behavior is undefined if both
// strings are not ASCII.
BASE_EXPORT bool EqualsASCII(const string16& a, const base::StringPiece& b);
BASE_EXPORT bool EqualsASCII(const base::string16& a, const base::StringPiece& b);
// Returns true if str starts with search, or false otherwise.
BASE_EXPORT bool StartsWithASCII(const std::string& str,
const std::string& search,
bool case_sensitive);
BASE_EXPORT bool StartsWith(const std::wstring& str,
const std::wstring& search,
bool case_sensitive);
BASE_EXPORT bool StartsWith(const string16& str,
const string16& search,
BASE_EXPORT bool StartsWith(const base::string16& str,
const base::string16& search,
bool case_sensitive);
// Returns true if str ends with search, or false otherwise.
BASE_EXPORT bool EndsWith(const std::string& str,
const std::string& search,
bool case_sensitive);
BASE_EXPORT bool EndsWith(const std::wstring& str,
const std::wstring& search,
bool case_sensitive);
BASE_EXPORT bool EndsWith(const string16& str,
const string16& search,
BASE_EXPORT bool EndsWith(const base::string16& str,
const base::string16& search,
bool case_sensitive);
@ -416,25 +365,25 @@ inline Char HexDigitToInt(Char c) {
// Returns true if it's a whitespace character.
inline bool IsWhitespace(wchar_t c) {
return wcschr(kWhitespaceWide, c) != NULL;
return wcschr(base::kWhitespaceWide, c) != NULL;
}
// Return a byte string in human-readable format with a unit suffix. Not
// appropriate for use in any UI; use of FormatBytes and friends in ui/base is
// highly recommended instead. TODO(avi): Figure out how to get callers to use
// FormatBytes instead; remove this.
BASE_EXPORT string16 FormatBytesUnlocalized(int64 bytes);
BASE_EXPORT base::string16 FormatBytesUnlocalized(int64 bytes);
// Starting at |start_offset| (usually 0), replace the first instance of
// |find_this| with |replace_with|.
BASE_EXPORT void ReplaceFirstSubstringAfterOffset(
string16* str,
string16::size_type start_offset,
const string16& find_this,
const string16& replace_with);
base::string16* str,
size_t start_offset,
const base::string16& find_this,
const base::string16& replace_with);
BASE_EXPORT void ReplaceFirstSubstringAfterOffset(
std::string* str,
std::string::size_type start_offset,
size_t start_offset,
const std::string& find_this,
const std::string& replace_with);
@ -445,15 +394,14 @@ BASE_EXPORT void ReplaceFirstSubstringAfterOffset(
// characters, for example:
// std::replace(str.begin(), str.end(), 'a', 'b');
BASE_EXPORT void ReplaceSubstringsAfterOffset(
string16* str,
string16::size_type start_offset,
const string16& find_this,
const string16& replace_with);
BASE_EXPORT void ReplaceSubstringsAfterOffset(
std::string* str,
std::string::size_type start_offset,
const std::string& find_this,
const std::string& replace_with);
base::string16* str,
size_t start_offset,
const base::string16& find_this,
const base::string16& replace_with);
BASE_EXPORT void ReplaceSubstringsAfterOffset(std::string* str,
size_t start_offset,
const std::string& find_this,
const std::string& replace_with);
// Reserves enough memory in |str| to accommodate |length_with_null| characters,
// sets the size of |str| to |length_with_null - 1| characters, and returns a
@ -489,12 +437,9 @@ inline typename string_type::value_type* WriteInto(string_type* str,
// Splits a string into its fields delimited by any of the characters in
// |delimiters|. Each field is added to the |tokens| vector. Returns the
// number of tokens found.
BASE_EXPORT size_t Tokenize(const std::wstring& str,
const std::wstring& delimiters,
std::vector<std::wstring>* tokens);
BASE_EXPORT size_t Tokenize(const string16& str,
const string16& delimiters,
std::vector<string16>* tokens);
BASE_EXPORT size_t Tokenize(const base::string16& str,
const base::string16& delimiters,
std::vector<base::string16>* tokens);
BASE_EXPORT size_t Tokenize(const std::string& str,
const std::string& delimiters,
std::vector<std::string>* tokens);
@ -503,7 +448,8 @@ BASE_EXPORT size_t Tokenize(const base::StringPiece& str,
std::vector<base::StringPiece>* tokens);
// Does the opposite of SplitString().
BASE_EXPORT string16 JoinString(const std::vector<string16>& parts, char16 s);
BASE_EXPORT base::string16 JoinString(const std::vector<base::string16>& parts,
base::char16 s);
BASE_EXPORT std::string JoinString(
const std::vector<std::string>& parts, char s);
@ -511,17 +457,17 @@ BASE_EXPORT std::string JoinString(
BASE_EXPORT std::string JoinString(
const std::vector<std::string>& parts,
const std::string& separator);
BASE_EXPORT string16 JoinString(
const std::vector<string16>& parts,
const string16& separator);
BASE_EXPORT base::string16 JoinString(
const std::vector<base::string16>& parts,
const base::string16& separator);
// Replace $1-$2-$3..$9 in the format string with |a|-|b|-|c|..|i| respectively.
// Additionally, any number of consecutive '$' characters is replaced by that
// number less one. Eg $$->$, $$$->$$, etc. The offsets parameter here can be
// NULL. This only allows you to use up to nine replacements.
BASE_EXPORT string16 ReplaceStringPlaceholders(
const string16& format_string,
const std::vector<string16>& subst,
BASE_EXPORT base::string16 ReplaceStringPlaceholders(
const base::string16& format_string,
const std::vector<base::string16>& subst,
std::vector<size_t>* offsets);
BASE_EXPORT std::string ReplaceStringPlaceholders(
@ -530,9 +476,10 @@ BASE_EXPORT std::string ReplaceStringPlaceholders(
std::vector<size_t>* offsets);
// Single-string shortcut for ReplaceStringHolders. |offset| may be NULL.
BASE_EXPORT string16 ReplaceStringPlaceholders(const string16& format_string,
const string16& a,
size_t* offset);
BASE_EXPORT base::string16 ReplaceStringPlaceholders(
const base::string16& format_string,
const base::string16& a,
size_t* offset);
// Returns true if the string passed in matches the pattern. The pattern
// string can contain wildcards like * and ?
@ -541,7 +488,8 @@ BASE_EXPORT string16 ReplaceStringPlaceholders(const string16& format_string,
// ? matches 0 or 1 character, while * matches 0 or more characters.
BASE_EXPORT bool MatchPattern(const base::StringPiece& string,
const base::StringPiece& pattern);
BASE_EXPORT bool MatchPattern(const string16& string, const string16& pattern);
BASE_EXPORT bool MatchPattern(const base::string16& string,
const base::string16& pattern);
// Hack to convert any char-like type to its unsigned counterpart.
// For example, it will convert char, signed char and unsigned char to unsigned

Просмотреть файл

@ -4,34 +4,34 @@
#include "base/strings/string_util.h"
namespace base {
#define WHITESPACE_UNICODE \
0x0009, /* <control-0009> to <control-000D> */ \
0x000A, \
0x000B, \
0x000C, \
0x000D, \
0x0020, /* Space */ \
0x0085, /* <control-0085> */ \
0x00A0, /* No-Break Space */ \
0x1680, /* Ogham Space Mark */ \
0x180E, /* Mongolian Vowel Separator */ \
0x2000, /* En Quad to Hair Space */ \
0x2001, \
0x2002, \
0x2003, \
0x2004, \
0x2005, \
0x2006, \
0x2007, \
0x2008, \
0x2009, \
0x200A, \
0x200C, /* Zero Width Non-Joiner */ \
0x2028, /* Line Separator */ \
0x2029, /* Paragraph Separator */ \
0x202F, /* Narrow No-Break Space */ \
0x205F, /* Medium Mathematical Space */ \
0x3000, /* Ideographic Space */ \
0x0009, /* CHARACTER TABULATION */ \
0x000A, /* LINE FEED (LF) */ \
0x000B, /* LINE TABULATION */ \
0x000C, /* FORM FEED (FF) */ \
0x000D, /* CARRIAGE RETURN (CR) */ \
0x0020, /* SPACE */ \
0x0085, /* NEXT LINE (NEL) */ \
0x00A0, /* NO-BREAK SPACE */ \
0x1680, /* OGHAM SPACE MARK */ \
0x2000, /* EN QUAD */ \
0x2001, /* EM QUAD */ \
0x2002, /* EN SPACE */ \
0x2003, /* EM SPACE */ \
0x2004, /* THREE-PER-EM SPACE */ \
0x2005, /* FOUR-PER-EM SPACE */ \
0x2006, /* SIX-PER-EM SPACE */ \
0x2007, /* FIGURE SPACE */ \
0x2008, /* PUNCTUATION SPACE */ \
0x2009, /* THIN SPACE */ \
0x200A, /* HAIR SPACE */ \
0x2028, /* LINE SEPARATOR */ \
0x2029, /* PARAGRAPH SEPARATOR */ \
0x202F, /* NARROW NO-BREAK SPACE */ \
0x205F, /* MEDIUM MATHEMATICAL SPACE */ \
0x3000, /* IDEOGRAPHIC SPACE */ \
0
const wchar_t kWhitespaceWide[] = {
@ -43,13 +43,15 @@ const char16 kWhitespaceUTF16[] = {
};
const char kWhitespaceASCII[] = {
0x09, // <control-0009> to <control-000D>
0x0A,
0x0B,
0x0C,
0x0D,
0x20, // Space
0x09, // CHARACTER TABULATION
0x0A, // LINE FEED (LF)
0x0B, // LINE TABULATION
0x0C, // FORM FEED (FF)
0x0D, // CARRIAGE RETURN (CR)
0x20, // SPACE
0
};
const char kUtf8ByteOrderMark[] = "\xEF\xBB\xBF";
} // namespace base

Просмотреть файл

@ -1,41 +0,0 @@
#include <wchar.h>
namespace base {
bool IsWprintfFormatPortable(const wchar_t* format) {
for (const wchar_t* position = format; *position != '\0'; ++position) {
if (*position == '%') {
bool in_specification = true;
bool modifier_l = false;
while (in_specification) {
// Eat up characters until reaching a known specifier.
if (*++position == '\0') {
// The format string ended in the middle of a specification. Call
// it portable because no unportable specifications were found. The
// string is equally broken on all platforms.
return true;
}
if (*position == 'l') {
// 'l' is the only thing that can save the 's' and 'c' specifiers.
modifier_l = true;
} else if (((*position == 's' || *position == 'c') && !modifier_l) ||
*position == 'S' || *position == 'C' || *position == 'F' ||
*position == 'D' || *position == 'O' || *position == 'U') {
// Not portable.
return false;
}
if (wcschr(L"diouxXeEfgGaAcspn%", *position)) {
// Portable, keep scanning the rest of the format string.
in_specification = false;
}
}
}
}
return true;
}
} // namespace base

Просмотреть файл

@ -66,19 +66,17 @@ static void StringAppendVT(StringType* dst,
int mem_length = arraysize(stack_buf);
while (true) {
if (result < 0) {
#if !defined(OS_WIN)
#if defined(OS_WIN)
// On Windows, vsnprintfT always returns the number of characters in a
// fully-formatted string, so if we reach this point, something else is
// wrong and no amount of buffer-doubling is going to fix it.
return;
#else
if (errno != 0 && errno != EOVERFLOW)
#endif
{
// If an error other than overflow occurred, it's never going to work.
DLOG(WARNING) << "Unable to printf the requested string due to error.";
return;
}
// Try doubling the buffer size.
mem_length *= 2;
#endif
} else {
// We need exactly "result + 1" characters.
mem_length = result + 1;

Просмотреть файл

@ -182,4 +182,9 @@ string16 ASCIIToUTF16(const StringPiece& ascii) {
return string16(ascii.begin(), ascii.end());
}
std::string UTF16ToASCII(const string16& utf16) {
DCHECK(IsStringASCII(utf16)) << UTF16ToUTF8(utf16);
return std::string(utf16.begin(), utf16.end());
}
} // namespace base

Просмотреть файл

@ -39,34 +39,15 @@ BASE_EXPORT bool UTF16ToUTF8(const char16* src, size_t src_len,
std::string* output);
BASE_EXPORT std::string UTF16ToUTF8(const string16& utf16);
// We are trying to get rid of wstring as much as possible, but it's too big
// a mess to do it all at once. These conversions should be used when we
// really should just be passing a string16 around, but we haven't finished
// porting whatever module uses wstring and the conversion is being used as a
// stopcock. This makes it easy to grep for the ones that should be removed.
#if defined(OS_WIN)
# define WideToUTF16Hack
# define UTF16ToWideHack
#else
# define WideToUTF16Hack WideToUTF16
# define UTF16ToWideHack UTF16ToWide
#endif
// These convert an ASCII string, typically a hardcoded constant, to a
// UTF16/Wide string.
BASE_EXPORT std::wstring ASCIIToWide(const StringPiece& ascii);
BASE_EXPORT string16 ASCIIToUTF16(const StringPiece& ascii);
// Converts to 7-bit ASCII by truncating. The result must be known to be ASCII
// beforehand.
BASE_EXPORT std::string UTF16ToASCII(const string16& utf16);
} // namespace base
// TODO(brettw) remove these when callers are fixed up.
using base::WideToUTF8;
using base::UTF8ToWide;
using base::WideToUTF16;
using base::UTF16ToWide;
using base::UTF8ToUTF16;
using base::UTF16ToUTF8;
using base::ASCIIToWide;
using base::ASCIIToUTF16;
#endif // BASE_STRINGS_UTF_STRING_CONVERSIONS_H_

Просмотреть файл

@ -6,43 +6,34 @@
// is functionally a wrapper around the LockImpl class, so the only
// real intelligence in the class is in the debugging logic.
#if !defined(NDEBUG)
#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
#include "base/synchronization/lock.h"
#include "base/logging.h"
namespace base {
const PlatformThreadId kNoThreadId = static_cast<PlatformThreadId>(0);
Lock::Lock() : lock_() {
owned_by_thread_ = false;
owning_thread_id_ = kNoThreadId;
}
Lock::~Lock() {
DCHECK(!owned_by_thread_);
DCHECK_EQ(kNoThreadId, owning_thread_id_);
DCHECK(owning_thread_ref_.is_null());
}
void Lock::AssertAcquired() const {
DCHECK(owned_by_thread_);
DCHECK_EQ(owning_thread_id_, PlatformThread::CurrentId());
DCHECK(owning_thread_ref_ == PlatformThread::CurrentRef());
}
void Lock::CheckHeldAndUnmark() {
DCHECK(owned_by_thread_);
DCHECK_EQ(owning_thread_id_, PlatformThread::CurrentId());
owned_by_thread_ = false;
owning_thread_id_ = kNoThreadId;
DCHECK(owning_thread_ref_ == PlatformThread::CurrentRef());
owning_thread_ref_ = PlatformThreadRef();
}
void Lock::CheckUnheldAndMark() {
DCHECK(!owned_by_thread_);
owned_by_thread_ = true;
owning_thread_id_ = PlatformThread::CurrentId();
DCHECK(owning_thread_ref_.is_null());
owning_thread_ref_ = PlatformThread::CurrentRef();
}
} // namespace base
#endif // NDEBUG
#endif // !NDEBUG || DCHECK_ALWAYS_ON

Просмотреть файл

@ -16,7 +16,8 @@ namespace base {
// AssertAcquired() method.
class BASE_EXPORT Lock {
public:
#if defined(NDEBUG) // Optimized wrapper implementation
#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
// Optimized wrapper implementation
Lock() : lock_() {}
~Lock() {}
void Acquire() { lock_.Lock(); }
@ -55,7 +56,7 @@ class BASE_EXPORT Lock {
}
void AssertAcquired() const;
#endif // NDEBUG
#endif // NDEBUG && !DCHECK_ALWAYS_ON
#if defined(OS_POSIX)
// The posix implementation of ConditionVariable needs to be able
@ -69,7 +70,7 @@ class BASE_EXPORT Lock {
#endif
private:
#if !defined(NDEBUG)
#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
// Members and routines taking care of locks assertions.
// Note that this checks for recursive locks and allows them
// if the variable is set. This is allowed by the underlying implementation
@ -80,12 +81,8 @@ class BASE_EXPORT Lock {
// All private data is implicitly protected by lock_.
// Be VERY careful to only access members under that lock.
// Determines validity of owning_thread_id_. Needed as we don't have
// a null owning_thread_id_ value.
bool owned_by_thread_;
base::PlatformThreadId owning_thread_id_;
#endif // NDEBUG
base::PlatformThreadRef owning_thread_ref_;
#endif // !NDEBUG || DCHECK_ALWAYS_ON
// Platform specific underlying lock implementation.
internal::LockImpl lock_;

Просмотреть файл

@ -28,6 +28,39 @@ typedef integral_constant<bool, false> false_type;
template <class T> struct is_pointer : false_type {};
template <class T> struct is_pointer<T*> : true_type {};
// Member function pointer detection up to four params. Add more as needed
// below. This is built-in to C++ 11, and we can remove this when we switch.
template<typename T>
struct is_member_function_pointer : false_type {};
template <typename R, typename Z>
struct is_member_function_pointer<R(Z::*)()> : true_type {};
template <typename R, typename Z>
struct is_member_function_pointer<R(Z::*)() const> : true_type {};
template <typename R, typename Z, typename A>
struct is_member_function_pointer<R(Z::*)(A)> : true_type {};
template <typename R, typename Z, typename A>
struct is_member_function_pointer<R(Z::*)(A) const> : true_type {};
template <typename R, typename Z, typename A, typename B>
struct is_member_function_pointer<R(Z::*)(A, B)> : true_type {};
template <typename R, typename Z, typename A, typename B>
struct is_member_function_pointer<R(Z::*)(A, B) const> : true_type {};
template <typename R, typename Z, typename A, typename B, typename C>
struct is_member_function_pointer<R(Z::*)(A, B, C)> : true_type {};
template <typename R, typename Z, typename A, typename B, typename C>
struct is_member_function_pointer<R(Z::*)(A, B, C) const> : true_type {};
template <typename R, typename Z, typename A, typename B, typename C,
typename D>
struct is_member_function_pointer<R(Z::*)(A, B, C, D)> : true_type {};
template <typename R, typename Z, typename A, typename B, typename C,
typename D>
struct is_member_function_pointer<R(Z::*)(A, B, C, D) const> : true_type {};
template <class T, class U> struct is_same : public false_type {};
template <class T> struct is_same<T,T> : true_type {};
@ -39,6 +72,9 @@ template <class T> struct is_non_const_reference : false_type {};
template <class T> struct is_non_const_reference<T&> : true_type {};
template <class T> struct is_non_const_reference<const T&> : false_type {};
template <class T> struct is_const : false_type {};
template <class T> struct is_const<const T> : true_type {};
template <class T> struct is_void : false_type {};
template <> struct is_void<void> : true_type {};
@ -103,6 +139,12 @@ struct is_class
sizeof(internal::YesType)> {
};
template<bool B, class T = void>
struct enable_if {};
template<class T>
struct enable_if<true, T> { typedef T type; };
} // namespace base
#endif // BASE_TEMPLATE_UTIL_H_

Просмотреть файл

@ -548,8 +548,10 @@ Balloc
ACQUIRE_DTOA_LOCK(0);
/* The k > Kmax case does not need ACQUIRE_DTOA_LOCK(0), */
/* but this case seems very unlikely. */
if (k <= Kmax && (rv = freelist[k]))
if (k <= Kmax && freelist[k]) {
rv = freelist[k];
freelist[k] = rv->next;
}
else {
x = 1 << k;
#ifdef Omit_Private_Memory
@ -834,7 +836,8 @@ mult
xc0 = c->x;
#ifdef ULLong
for(; xb < xbe; xc0++) {
if ((y = *xb++)) {
y = *xb++;
if (y) {
x = xa;
xc = xc0;
carry = 0;
@ -916,16 +919,19 @@ pow5mult
int i;
static int p05[3] = { 5, 25, 125 };
if ((i = k & 3))
i = k & 3;
if (i)
b = multadd(b, p05[i-1], 0);
if (!(k >>= 2))
return b;
if (!(p5 = p5s)) {
p5 = p5s;
if (!p5) {
/* first time */
#ifdef MULTIPLE_THREADS
ACQUIRE_DTOA_LOCK(1);
if (!(p5 = p5s)) {
p5 = p5s;
if (!p5) {
p5 = p5s = i2b(625);
p5->next = 0;
}
@ -943,10 +949,12 @@ pow5mult
}
if (!(k >>= 1))
break;
if (!(p51 = p5->next)) {
p51 = p5->next;
if (!p51) {
#ifdef MULTIPLE_THREADS
ACQUIRE_DTOA_LOCK(1);
if (!(p51 = p5->next)) {
p51 = p5->next;
if (!p51) {
p51 = p5->next = mult(p5,p5);
p51->next = 0;
}
@ -997,7 +1005,8 @@ lshift
z = *x++ >> k1;
}
while(x < xe);
if ((*x1 = z))
*x1 = z;
if (*x1)
++n1;
}
#else
@ -1299,21 +1308,25 @@ d2b
z |= Exp_msk11;
#endif
#else
if ((de = (int)(d0 >> Exp_shift)))
de = (int)(d0 >> Exp_shift);
if (de)
z |= Exp_msk1;
#endif
#ifdef Pack_32
if ((y = d1)) {
if ((k = lo0bits(&y))) {
y = d1;
if (y) {
k = lo0bits(&y);
if (k) {
x[0] = y | z << (32 - k);
z >>= k;
}
else
x[0] = y;
x[1] = z;
b->wds = x[1] ? 2 : 1;
#ifndef Sudden_Underflow
i =
i = b->wds;
#endif
b->wds = (x[1] = z) ? 2 : 1;
}
else {
k = lo0bits(&z);
@ -1536,7 +1549,7 @@ match
int c, d;
CONST char *s = *sp;
while((d = *t++)) {
for(d = *t++; d; d = *t++) {
if ((c = *++s) >= 'A' && c <= 'Z')
c += 'a' - 'A';
if (c != d)
@ -1566,12 +1579,13 @@ hexnan
udx0 = 1;
s = *sp;
/* allow optional initial 0x or 0X */
while((c = *(CONST unsigned char*)(s+1)) && c <= ' ')
for(c = *(CONST unsigned char*)(s+1); c && c <= ' '; c = *(CONST unsigned char*)(s+1))
++s;
if (s[1] == '0' && (s[2] == 'x' || s[2] == 'X'))
s += 2;
while((c = *(CONST unsigned char*)++s)) {
if ((c1 = hexdig[c]))
for(c = *(CONST unsigned char*)++s; c; c = *(CONST unsigned char*)++s) {
c1 = hexdig[c];
if (c1)
c = c1 & 0xf;
else if (c <= ' ') {
if (udx0 && havedig) {
@ -1594,7 +1608,8 @@ hexnan
*sp = s + 1;
break;
}
} while((c = *++s));
c = *++s;
} while(c);
break;
}
#endif
@ -2328,7 +2343,8 @@ bigcomp
/* Now b/d = exactly half-way between the two floating-point values */
/* on either side of the input string. Compute first digit of b/d. */
if (!(dig = quorem(b,d))) {
dig = quorem(b,d);
if (!dig) {
b = multadd(b, 10, 0); /* very unlikely */
dig = quorem(b,d);
}
@ -2336,7 +2352,8 @@ bigcomp
/* Compare b/d with s0 */
for(i = 0; i < nd0; ) {
if ((dd = s0[i++] - '0' - dig))
dd = s0[i++] - '0' - dig;
if (dd)
goto ret;
if (!b->x[0] && b->wds == 1) {
if (i < nd)
@ -2347,7 +2364,8 @@ bigcomp
dig = quorem(b,d);
}
for(j = bc->dp1; i++ < nd;) {
if ((dd = s0[j++] - '0' - dig))
dd = s0[j++] - '0' - dig;
if (dd)
goto ret;
if (!b->x[0] && b->wds == 1) {
if (i < nd)
@ -2747,7 +2765,8 @@ strtod
/* Get starting approximation = rv * 10**e1 */
if (e1 > 0) {
if ((i = e1 & 15))
i = e1 & 15;
if (i)
dval(&rv) *= tens[i];
if (e1 &= ~15) {
if (e1 > DBL_MAX_10_EXP) {
@ -2805,7 +2824,8 @@ strtod
}
else if (e1 < 0) {
e1 = -e1;
if ((i = e1 & 15))
i = e1 & 15;
if (i)
dval(&rv) /= tens[i];
if (e1 >>= 4) {
if (e1 >= 1 << n_bigtens)
@ -3456,7 +3476,7 @@ nrv_alloc(CONST char *s, char **rve, int n)
char *rv, *t;
t = rv = rv_alloc(n);
while((*t = *s++)) t++;
for(*t = *s++; *t; *t = *s++) t++;
if (rve)
*rve = t;
return rv;
@ -3645,10 +3665,9 @@ dtoa
#endif
b = d2b(&u, &be, &bbits);
#ifdef Sudden_Underflow
i = (int)(word0(&u) >> Exp_shift1 & (Exp_mask>>Exp_shift1));
#else
if ((i = (int)(word0(&u) >> Exp_shift1 & (Exp_mask>>Exp_shift1)))) {
#ifndef Sudden_Underflow
if (i) {
#endif
dval(&d2) = dval(&u);
word0(&d2) &= Frac_mask1;
@ -3803,13 +3822,16 @@ dtoa
}
dval(&u) /= ds;
}
else if ((j1 = -k)) {
dval(&u) *= tens[j1 & 0xf];
for(j = j1 >> 4; j; j >>= 1, i++)
if (j & 1) {
ieps++;
dval(&u) *= bigtens[i];
}
else {
j1 = -k;
if (j1) {
dval(&u) *= tens[j1 & 0xf];
for(j = j1 >> 4; j; j >>= 1, i++)
if (j & 1) {
ieps++;
dval(&u) *= bigtens[i];
}
}
}
if (k_check && dval(&u) < 1. && ilim > 0) {
if (ilim1 <= 0)
@ -3964,7 +3986,8 @@ dtoa
Bfree(b);
b = b1;
}
if ((j = b5 - m5))
j = b5 - m5;
if (j)
b = pow5mult(b, j);
}
else
@ -4002,7 +4025,8 @@ dtoa
* can do shifts and ors to compute the numerator for q.
*/
#ifdef Pack_32
if ((i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f))
i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f;
if (i)
i = 32 - i;
#define iInc 28
#else

Просмотреть файл

@ -46,14 +46,14 @@ g_fmt(register char *b, double x)
if (sign)
*b++ = '-';
if (decpt == 9999) /* Infinity or Nan */ {
while((*b++ = *s++)) {}
for(*b = *s++; *b++; *b = *s++) {}
goto done0;
}
if (decpt <= -4 || decpt > se - s + 5) {
*b++ = *s++;
if (*s) {
*b++ = '.';
while((*b = *s++))
for(*b = *s++; *b; *b = *s++)
b++;
}
*b++ = 'e';
@ -79,10 +79,10 @@ g_fmt(register char *b, double x)
*b++ = '.';
for(; decpt < 0; decpt++)
*b++ = '0';
while((*b++ = *s++)) {}
for(*b = *s++; *b++; *b = *s++) {}
}
else {
while((*b = *s++)) {
for(*b = *s++; *b; *b = *s++) {
b++;
if (--decpt == 0 && *s)
*b++ = '.';

Просмотреть файл

@ -21,7 +21,8 @@
namespace base_icu {
typedef uint32 UChar32;
typedef int32 UChar32;
typedef uint16 UChar;
typedef int8 UBool;
// General ---------------------------------------------------------------------
@ -304,7 +305,8 @@ UChar32 utf8_nextCharSafeBody(const uint8 *s, int32 *pi, int32 length, UChar32 c
* @return lead surrogate (U+d800..U+dbff) for supplementary
* @stable ICU 2.4
*/
#define CBU16_LEAD(supplementary) (UChar)(((supplementary)>>10)+0xd7c0)
#define CBU16_LEAD(supplementary) \
(base_icu::UChar)(((supplementary)>>10)+0xd7c0)
/**
* Get the trail surrogate (0xdc00..0xdfff) for a
@ -313,7 +315,8 @@ UChar32 utf8_nextCharSafeBody(const uint8 *s, int32 *pi, int32 length, UChar32 c
* @return trail surrogate (U+dc00..U+dfff) for supplementary
* @stable ICU 2.4
*/
#define CBU16_TRAIL(supplementary) (UChar)(((supplementary)&0x3ff)|0xdc00)
#define CBU16_TRAIL(supplementary) \
(base_icu::UChar)(((supplementary)&0x3ff)|0xdc00)
/**
* How many 16-bit code units are used to encode this Unicode code point? (1 or 2)

Просмотреть файл

@ -23,12 +23,48 @@
namespace base {
// Used for logging. Always an integer value.
#if defined(OS_WIN)
typedef DWORD PlatformThreadId;
#elif defined(OS_POSIX)
typedef pid_t PlatformThreadId;
#endif
// Used for thread checking and debugging.
// Meant to be as fast as possible.
// These are produced by PlatformThread::CurrentRef(), and used to later
// check if we are on the same thread or not by using ==. These are safe
// to copy between threads, but can't be copied to another process as they
// have no meaning there. Also, the internal identifier can be re-used
// after a thread dies, so a PlatformThreadRef cannot be reliably used
// to distinguish a new thread from an old, dead thread.
class PlatformThreadRef {
public:
#if defined(OS_WIN)
typedef DWORD RefType;
#elif defined(OS_POSIX)
typedef pthread_t RefType;
#endif
PlatformThreadRef()
: id_(0) {
}
explicit PlatformThreadRef(RefType id)
: id_(id) {
}
bool operator==(PlatformThreadRef other) const {
return id_ == other.id_;
}
bool is_null() const {
return id_ == 0;
}
private:
RefType id_;
};
// Used to operate on threads.
class PlatformThreadHandle {
public:
#if defined(OS_WIN)
@ -53,15 +89,15 @@ class PlatformThreadHandle {
id_(id) {
}
bool is_equal(const PlatformThreadHandle& other) {
bool is_equal(const PlatformThreadHandle& other) const {
return handle_ == other.handle_;
}
bool is_null() {
bool is_null() const {
return !handle_;
}
Handle platform_handle() {
Handle platform_handle() const {
return handle_;
}
@ -101,6 +137,10 @@ class BASE_EXPORT PlatformThread {
// Gets the current thread id, which may be useful for logging purposes.
static PlatformThreadId CurrentId();
// Gets the current thread reference, which can be used to check if
// we're on the right thread quickly.
static PlatformThreadRef CurrentRef();
// Get the current handle.
static PlatformThreadHandle CurrentHandle();

Просмотреть файл

@ -10,7 +10,7 @@
#include "base/threading/thread_id_name_manager.h"
#include "base/threading/thread_restrictions.h"
#include "base/tracked_objects.h"
#include "base/win/scoped_handle.h"
#include "base/win/windows_version.h"
namespace base {
@ -54,28 +54,35 @@ DWORD __stdcall ThreadFunc(void* params) {
if (!thread_params->joinable)
base::ThreadRestrictions::SetSingletonAllowed(false);
/* Retrieve a copy of the thread handle to use as the key in the
* thread name mapping. */
// Retrieve a copy of the thread handle to use as the key in the
// thread name mapping.
PlatformThreadHandle::Handle platform_handle;
DuplicateHandle(
GetCurrentProcess(),
GetCurrentThread(),
GetCurrentProcess(),
&platform_handle,
0,
FALSE,
DUPLICATE_SAME_ACCESS);
BOOL did_dup = DuplicateHandle(GetCurrentProcess(),
GetCurrentThread(),
GetCurrentProcess(),
&platform_handle,
0,
FALSE,
DUPLICATE_SAME_ACCESS);
ThreadIdNameManager::GetInstance()->RegisterThread(
platform_handle,
PlatformThread::CurrentId());
win::ScopedHandle scoped_platform_handle;
if (did_dup) {
scoped_platform_handle.Set(platform_handle);
ThreadIdNameManager::GetInstance()->RegisterThread(
scoped_platform_handle.Get(),
PlatformThread::CurrentId());
}
delete thread_params;
delegate->ThreadMain();
ThreadIdNameManager::GetInstance()->RemoveName(
platform_handle,
PlatformThread::CurrentId());
if (did_dup) {
ThreadIdNameManager::GetInstance()->RemoveName(
scoped_platform_handle.Get(),
PlatformThread::CurrentId());
}
return NULL;
}
@ -122,6 +129,11 @@ PlatformThreadId PlatformThread::CurrentId() {
return GetCurrentThreadId();
}
// static
PlatformThreadRef PlatformThread::CurrentRef() {
return PlatformThreadRef(GetCurrentThreadId());
}
// static
PlatformThreadHandle PlatformThread::CurrentHandle() {
NOTIMPLEMENTED(); // See OpenThread()

Просмотреть файл

@ -69,6 +69,9 @@ class SequencedTaskRunner;
//
// Note that SequencedWorkerPool is RefCountedThreadSafe (inherited
// from TaskRunner).
//
// Test-only code should wrap this in a base::SequencedWorkerPoolOwner to avoid
// memory leaks. See http://crbug.com/273800
class BASE_EXPORT SequencedWorkerPool : public TaskRunner {
public:
// Defines what should happen to a task posted to the worker pool on

Просмотреть файл

@ -35,7 +35,7 @@ class BASE_EXPORT ThreadCheckerImpl {
mutable base::Lock lock_;
// This is mutable so that CalledOnValidThread can set it.
// It's guarded by |lock_|.
mutable PlatformThreadId valid_thread_id_;
mutable PlatformThreadRef valid_thread_id_;
};
} // namespace base

Просмотреть файл

@ -9,6 +9,7 @@
#include "base/atomicops.h"
#include "base/base_export.h"
#include "base/basictypes.h"
#include "base/compiler_specific.h"
// A helper class alongside macros to be used to verify assumptions about thread

Просмотреть файл

@ -26,6 +26,9 @@
// you must of course properly deal with safety and race conditions. This
// means a function-level static initializer is generally inappropiate.
//
// In Android, the system TLS is limited, the implementation is backed with
// ThreadLocalStorage.
//
// Example usage:
// // My class is logically attached to a single thread. We cache a pointer
// // on the thread it was created on, so we can implement current().
@ -50,27 +53,29 @@
#include "base/base_export.h"
#include "base/basictypes.h"
#include "base/threading/thread_local_storage.h"
#if defined(OS_POSIX)
#include <pthread.h>
#endif
namespace base {
namespace internal {
// Helper functions that abstract the cross-platform APIs. Do not use directly.
struct BASE_EXPORT ThreadLocalPlatform {
#if defined(OS_WIN)
typedef unsigned long SlotType;
#elif defined(OS_ANDROID)
typedef ThreadLocalStorage::StaticSlot SlotType;
#elif defined(OS_POSIX)
typedef pthread_key_t SlotType;
#endif
static void AllocateSlot(SlotType& slot);
static void FreeSlot(SlotType& slot);
static void* GetValueFromSlot(SlotType& slot);
static void SetValueInSlot(SlotType& slot, void* value);
static void AllocateSlot(SlotType* slot);
static void FreeSlot(SlotType slot);
static void* GetValueFromSlot(SlotType slot);
static void SetValueInSlot(SlotType slot, void* value);
};
} // namespace internal
@ -79,7 +84,7 @@ template <typename Type>
class ThreadLocalPointer {
public:
ThreadLocalPointer() : slot_() {
internal::ThreadLocalPlatform::AllocateSlot(slot_);
internal::ThreadLocalPlatform::AllocateSlot(&slot_);
}
~ThreadLocalPointer() {
@ -106,8 +111,8 @@ class ThreadLocalPointer {
class ThreadLocalBoolean {
public:
ThreadLocalBoolean() { }
~ThreadLocalBoolean() { }
ThreadLocalBoolean() {}
~ThreadLocalBoolean() {}
bool Get() {
return tlp_.Get() != NULL;

Просмотреть файл

@ -9,34 +9,32 @@
#include "base/logging.h"
namespace base {
namespace internal {
// static
void ThreadLocalPlatform::AllocateSlot(SlotType& slot) {
slot = TlsAlloc();
CHECK_NE(slot, TLS_OUT_OF_INDEXES);
void ThreadLocalPlatform::AllocateSlot(SlotType* slot) {
*slot = TlsAlloc();
CHECK_NE(*slot, TLS_OUT_OF_INDEXES);
}
// static
void ThreadLocalPlatform::FreeSlot(SlotType& slot) {
void ThreadLocalPlatform::FreeSlot(SlotType slot) {
if (!TlsFree(slot)) {
NOTREACHED() << "Failed to deallocate tls slot with TlsFree().";
}
}
// static
void* ThreadLocalPlatform::GetValueFromSlot(SlotType& slot) {
void* ThreadLocalPlatform::GetValueFromSlot(SlotType slot) {
return TlsGetValue(slot);
}
// static
void ThreadLocalPlatform::SetValueInSlot(SlotType& slot, void* value) {
void ThreadLocalPlatform::SetValueInSlot(SlotType slot, void* value) {
if (!TlsSetValue(slot, value)) {
LOG(FATAL) << "Failed to TlsSetValue().";
}
}
} // namespace internal
} // namespace base

Просмотреть файл

@ -47,7 +47,7 @@ class BrowserTestBase;
class GLHelper;
class GpuChannelHost;
class NestedMessagePumpAndroid;
class RenderWidgetHelper;
class RenderWidgetResizeHelper;
class ScopedAllowWaitForAndroidLayoutTests;
class TextInputClientMac;
}
@ -61,6 +61,11 @@ class InFlightIO;
namespace media {
class AudioOutputController;
}
namespace mojo {
namespace common {
class WatcherThreadManager;
}
}
namespace net {
class FileStreamPosix;
class FileStreamWin;
@ -180,12 +185,13 @@ class BASE_EXPORT ThreadRestrictions {
friend class content::BrowserShutdownProfileDumper;
friend class content::BrowserTestBase;
friend class content::NestedMessagePumpAndroid;
friend class content::RenderWidgetHelper;
friend class content::RenderWidgetResizeHelper;
friend class content::ScopedAllowWaitForAndroidLayoutTests;
friend class ::HistogramSynchronizer;
friend class ::ScopedAllowWaitForLegacyWebViewApi;
friend class ::TestingAutomationProvider;
friend class cc::CompletionEvent;
friend class mojo::common::WatcherThreadManager;
friend class remoting::AutoThread;
friend class MessagePumpDefault;
friend class SequencedWorkerPool;

Просмотреть файл

@ -8,48 +8,89 @@
#include <ostream>
#include "base/float_util.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/third_party/nspr/prtime.h"
#include "base/third_party/nspr/prtypes.h"
namespace base {
// TimeDelta ------------------------------------------------------------------
// static
TimeDelta TimeDelta::Max() {
return TimeDelta(std::numeric_limits<int64>::max());
}
int TimeDelta::InDays() const {
if (is_max()) {
// Preserve max to prevent overflow.
return std::numeric_limits<int>::max();
}
return static_cast<int>(delta_ / Time::kMicrosecondsPerDay);
}
int TimeDelta::InHours() const {
if (is_max()) {
// Preserve max to prevent overflow.
return std::numeric_limits<int>::max();
}
return static_cast<int>(delta_ / Time::kMicrosecondsPerHour);
}
int TimeDelta::InMinutes() const {
if (is_max()) {
// Preserve max to prevent overflow.
return std::numeric_limits<int>::max();
}
return static_cast<int>(delta_ / Time::kMicrosecondsPerMinute);
}
double TimeDelta::InSecondsF() const {
if (is_max()) {
// Preserve max to prevent overflow.
return std::numeric_limits<double>::infinity();
}
return static_cast<double>(delta_) / Time::kMicrosecondsPerSecond;
}
int64 TimeDelta::InSeconds() const {
if (is_max()) {
// Preserve max to prevent overflow.
return std::numeric_limits<int64>::max();
}
return delta_ / Time::kMicrosecondsPerSecond;
}
double TimeDelta::InMillisecondsF() const {
if (is_max()) {
// Preserve max to prevent overflow.
return std::numeric_limits<double>::infinity();
}
return static_cast<double>(delta_) / Time::kMicrosecondsPerMillisecond;
}
int64 TimeDelta::InMilliseconds() const {
if (is_max()) {
// Preserve max to prevent overflow.
return std::numeric_limits<int64>::max();
}
return delta_ / Time::kMicrosecondsPerMillisecond;
}
int64 TimeDelta::InMillisecondsRoundedUp() const {
if (is_max()) {
// Preserve max to prevent overflow.
return std::numeric_limits<int64>::max();
}
return (delta_ + Time::kMicrosecondsPerMillisecond - 1) /
Time::kMicrosecondsPerMillisecond;
}
int64 TimeDelta::InMicroseconds() const {
if (is_max()) {
// Preserve max to prevent overflow.
return std::numeric_limits<int64>::max();
}
return delta_;
}
@ -88,7 +129,7 @@ time_t Time::ToTimeT() const {
Time Time::FromDoubleT(double dt) {
if (dt == 0 || IsNaN(dt))
return Time(); // Preserve 0 so we can tell it doesn't exist.
if (dt == std::numeric_limits<double>::max())
if (dt == std::numeric_limits<double>::infinity())
return Max();
return Time(static_cast<int64>((dt *
static_cast<double>(kMicrosecondsPerSecond)) +
@ -100,7 +141,7 @@ double Time::ToDoubleT() const {
return 0; // Preserve 0 so we can tell it doesn't exist.
if (is_max()) {
// Preserve max without offset to prevent overflow.
return std::numeric_limits<double>::max();
return std::numeric_limits<double>::infinity();
}
return (static_cast<double>(us_ - kTimeTToMicrosecondsOffset) /
static_cast<double>(kMicrosecondsPerSecond));
@ -119,7 +160,7 @@ Time Time::FromTimeSpec(const timespec& ts) {
Time Time::FromJsTime(double ms_since_epoch) {
// The epoch is a valid time, so this constructor doesn't interpret
// 0 as the null time.
if (ms_since_epoch == std::numeric_limits<double>::max())
if (ms_since_epoch == std::numeric_limits<double>::infinity())
return Max();
return Time(static_cast<int64>(ms_since_epoch * kMicrosecondsPerMillisecond) +
kTimeTToMicrosecondsOffset);
@ -132,7 +173,7 @@ double Time::ToJsTime() const {
}
if (is_max()) {
// Preserve max without offset to prevent overflow.
return std::numeric_limits<double>::max();
return std::numeric_limits<double>::infinity();
}
return (static_cast<double>(us_ - kTimeTToMicrosecondsOffset) /
kMicrosecondsPerMillisecond);
@ -189,6 +230,29 @@ bool Time::FromStringInternal(const char* time_string,
return true;
}
// Local helper class to hold the conversion from Time to TickTime at the
// time of the Unix epoch.
class UnixEpochSingleton {
public:
UnixEpochSingleton()
: unix_epoch_(TimeTicks::Now() - (Time::Now() - Time::UnixEpoch())) {}
TimeTicks unix_epoch() const { return unix_epoch_; }
private:
const TimeTicks unix_epoch_;
DISALLOW_COPY_AND_ASSIGN(UnixEpochSingleton);
};
static LazyInstance<UnixEpochSingleton>::Leaky
leaky_unix_epoch_singleton_instance = LAZY_INSTANCE_INITIALIZER;
// Static
TimeTicks TimeTicks::UnixEpoch() {
return leaky_unix_epoch_singleton_instance.Get().unix_epoch();
}
// Time::Exploded -------------------------------------------------------------
inline bool is_in_range(int value, int lo, int hi) {

Просмотреть файл

@ -2,10 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Time represents an absolute point in time, internally represented as
// microseconds (s/1,000,000) since the Windows epoch (1601-01-01 00:00:00 UTC)
// (See http://crbug.com/14734). System-dependent clock interface routines are
// defined in time_PLATFORM.cc.
// Time represents an absolute point in coordinated universal time (UTC),
// internally represented as microseconds (s/1,000,000) since the Windows epoch
// (1601-01-01 00:00:00 UTC) (See http://crbug.com/14734). System-dependent
// clock interface routines are defined in time_PLATFORM.cc.
//
// TimeDelta represents a duration of time, internally represented in
// microseconds.
@ -61,11 +61,13 @@ class BASE_EXPORT TimeDelta {
}
// Converts units of time to TimeDeltas.
static TimeDelta FromDays(int64 days);
static TimeDelta FromHours(int64 hours);
static TimeDelta FromMinutes(int64 minutes);
static TimeDelta FromDays(int days);
static TimeDelta FromHours(int hours);
static TimeDelta FromMinutes(int minutes);
static TimeDelta FromSeconds(int64 secs);
static TimeDelta FromMilliseconds(int64 ms);
static TimeDelta FromSecondsD(double secs);
static TimeDelta FromMillisecondsD(double ms);
static TimeDelta FromMicroseconds(int64 us);
#if defined(OS_WIN)
static TimeDelta FromQPCValue(LONGLONG qpc_value);
@ -79,6 +81,11 @@ class BASE_EXPORT TimeDelta {
return TimeDelta(delta);
}
// Returns the maximum time delta, which should be greater than any reasonable
// time delta we might compare it to. Adding or subtracting the maximum time
// delta to a time or another time delta has an undefined result.
static TimeDelta Max();
// Returns the internal numeric value of the TimeDelta object. Please don't
// use this and do arithmetic on it, as it is more error prone than using the
// provided operators.
@ -87,6 +94,11 @@ class BASE_EXPORT TimeDelta {
return delta_;
}
// Returns true if the time delta is the maximum time delta.
bool is_max() const {
return delta_ == std::numeric_limits<int64>::max();
}
#if defined(OS_POSIX)
struct timespec ToTimeSpec() const;
#endif
@ -196,7 +208,7 @@ inline TimeDelta operator*(int64 a, TimeDelta td) {
// Time -----------------------------------------------------------------------
// Represents a wall clock time.
// Represents a wall clock time in UTC.
class BASE_EXPORT Time {
public:
static const int64 kMillisecondsPerSecond = 1000;
@ -493,32 +505,66 @@ class BASE_EXPORT Time {
// Inline the TimeDelta factory methods, for fast TimeDelta construction.
// static
inline TimeDelta TimeDelta::FromDays(int64 days) {
inline TimeDelta TimeDelta::FromDays(int days) {
// Preserve max to prevent overflow.
if (days == std::numeric_limits<int>::max())
return Max();
return TimeDelta(days * Time::kMicrosecondsPerDay);
}
// static
inline TimeDelta TimeDelta::FromHours(int64 hours) {
inline TimeDelta TimeDelta::FromHours(int hours) {
// Preserve max to prevent overflow.
if (hours == std::numeric_limits<int>::max())
return Max();
return TimeDelta(hours * Time::kMicrosecondsPerHour);
}
// static
inline TimeDelta TimeDelta::FromMinutes(int64 minutes) {
inline TimeDelta TimeDelta::FromMinutes(int minutes) {
// Preserve max to prevent overflow.
if (minutes == std::numeric_limits<int>::max())
return Max();
return TimeDelta(minutes * Time::kMicrosecondsPerMinute);
}
// static
inline TimeDelta TimeDelta::FromSeconds(int64 secs) {
// Preserve max to prevent overflow.
if (secs == std::numeric_limits<int64>::max())
return Max();
return TimeDelta(secs * Time::kMicrosecondsPerSecond);
}
// static
inline TimeDelta TimeDelta::FromMilliseconds(int64 ms) {
// Preserve max to prevent overflow.
if (ms == std::numeric_limits<int64>::max())
return Max();
return TimeDelta(ms * Time::kMicrosecondsPerMillisecond);
}
// static
inline TimeDelta TimeDelta::FromSecondsD(double secs) {
// Preserve max to prevent overflow.
if (secs == std::numeric_limits<double>::infinity())
return Max();
return TimeDelta(secs * Time::kMicrosecondsPerSecond);
}
// static
inline TimeDelta TimeDelta::FromMillisecondsD(double ms) {
// Preserve max to prevent overflow.
if (ms == std::numeric_limits<double>::infinity())
return Max();
return TimeDelta(ms * Time::kMicrosecondsPerMillisecond);
}
// static
inline TimeDelta TimeDelta::FromMicroseconds(int64 us) {
// Preserve max to prevent overflow.
if (us == std::numeric_limits<int64>::max())
return Max();
return TimeDelta(us);
}
@ -530,6 +576,14 @@ inline Time TimeDelta::operator+(Time t) const {
class BASE_EXPORT TimeTicks {
public:
// We define this even without OS_CHROMEOS for seccomp sandbox testing.
#if defined(OS_LINUX)
// Force definition of the system trace clock; it is a chromeos-only api
// at the moment and surfacing it in the right place requires mucking
// with glibc et al.
static const clockid_t kClockSystemTrace = 11;
#endif
TimeTicks() : ticks_(0) {
}
@ -544,9 +598,12 @@ class BASE_EXPORT TimeTicks {
// SHOULD ONLY BE USED WHEN IT IS REALLY NEEDED.
static TimeTicks HighResNow();
static bool IsHighResNowFastAndReliable();
// Returns true if ThreadNow() is supported on this system.
static bool IsThreadNowSupported() {
#if defined(_POSIX_THREAD_CPUTIME) && (_POSIX_THREAD_CPUTIME >= 0)
#if (defined(_POSIX_THREAD_CPUTIME) && (_POSIX_THREAD_CPUTIME >= 0)) || \
(defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_ANDROID)
return true;
#else
return false;
@ -602,6 +659,14 @@ class BASE_EXPORT TimeTicks {
return TimeTicks(ticks);
}
// Get the TimeTick value at the time of the UnixEpoch. This is useful when
// you need to relate the value of TimeTicks to a real time and date.
// Note: Upon first invocation, this function takes a snapshot of the realtime
// clock to establish a reference point. This function will return the same
// value for the duration of the application, but will be different in future
// application runs.
static TimeTicks UnixEpoch();
// Returns the internal numeric value of the TimeTicks object.
// For serializing, use FromInternalValue to reconstitute.
int64 ToInternalValue() const {

Просмотреть файл

@ -42,8 +42,8 @@
#include "base/basictypes.h"
#include "base/cpu.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/memory/singleton.h"
#include "base/synchronization/lock.h"
using base::Time;
@ -251,7 +251,7 @@ void Time::Explode(bool is_local, Exploded* exploded) const {
// FILETIME in local time if necessary.
bool success = true;
// FILETIME in SYSTEMTIME (exploded).
SYSTEMTIME st;
SYSTEMTIME st = {0};
if (is_local) {
SYSTEMTIME utc_st;
// We don't use FileTimeToLocalFileTime here, since it uses the current
@ -358,8 +358,14 @@ bool IsBuggyAthlon(const base::CPU& cpu) {
// retrieve and more reliable.
class HighResNowSingleton {
public:
static HighResNowSingleton* GetInstance() {
return Singleton<HighResNowSingleton>::get();
HighResNowSingleton()
: ticks_per_second_(0),
skew_(0) {
InitializeClock();
base::CPU cpu;
if (IsBuggyAthlon(cpu))
DisableHighResClock();
}
bool IsUsingHighResClock() {
@ -399,16 +405,6 @@ class HighResNowSingleton {
}
private:
HighResNowSingleton()
: ticks_per_second_(0),
skew_(0) {
InitializeClock();
base::CPU cpu;
if (IsBuggyAthlon(cpu))
DisableHighResClock();
}
// Synchronize the QPC clock with GetSystemTimeAsFileTime.
void InitializeClock() {
LARGE_INTEGER ticks_per_sec = {0};
@ -433,12 +429,17 @@ class HighResNowSingleton {
int64 ticks_per_second_; // 0 indicates QPF failed and we're broken.
int64 skew_; // Skew between lo-res and hi-res clocks (for debugging).
friend struct DefaultSingletonTraits<HighResNowSingleton>;
};
static base::LazyInstance<HighResNowSingleton>::Leaky
leaky_high_res_now_singleton = LAZY_INSTANCE_INITIALIZER;
HighResNowSingleton* GetHighResNowSingleton() {
return leaky_high_res_now_singleton.Pointer();
}
TimeDelta HighResNowWrapper() {
return HighResNowSingleton::GetInstance()->Now();
return GetHighResNowSingleton()->Now();
}
typedef TimeDelta (*NowFunction)(void);
@ -485,7 +486,12 @@ TimeTicks TimeTicks::Now() {
// static
TimeTicks TimeTicks::HighResNow() {
return TimeTicks() + HighResNowSingleton::GetInstance()->Now();
return TimeTicks() + HighResNowWrapper();
}
// static
bool TimeTicks::IsHighResNowFastAndReliable() {
return CPUReliablySupportsHighResTime();
}
// static
@ -501,18 +507,17 @@ TimeTicks TimeTicks::NowFromSystemTraceTime() {
// static
int64 TimeTicks::GetQPCDriftMicroseconds() {
return HighResNowSingleton::GetInstance()->GetQPCDriftMicroseconds();
return GetHighResNowSingleton()->GetQPCDriftMicroseconds();
}
// static
TimeTicks TimeTicks::FromQPCValue(LONGLONG qpc_value) {
return TimeTicks(
HighResNowSingleton::GetInstance()->QPCValueToMicroseconds(qpc_value));
return TimeTicks(GetHighResNowSingleton()->QPCValueToMicroseconds(qpc_value));
}
// static
bool TimeTicks::IsHighResClockWorking() {
return HighResNowSingleton::GetInstance()->IsUsingHighResClock();
return GetHighResNowSingleton()->IsUsingHighResClock();
}
TimeTicks TimeTicks::UnprotectedNow() {
@ -527,6 +532,5 @@ TimeTicks TimeTicks::UnprotectedNow() {
// static
TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) {
return TimeDelta(
HighResNowSingleton::GetInstance()->QPCValueToMicroseconds(qpc_value));
return TimeDelta(GetHighResNowSingleton()->QPCValueToMicroseconds(qpc_value));
}

Просмотреть файл

@ -31,11 +31,6 @@
#include "base/memory/scoped_ptr.h"
#include "base/strings/string16.h"
// This file declares "using base::Value", etc. at the bottom, so that
// current code can use these classes without the base namespace. In
// new code, please always use base::Value, etc. or add your own
// "using" declaration.
// http://crbug.com/88666
namespace base {
class DictionaryValue;
@ -69,13 +64,6 @@ class BASE_EXPORT Value {
virtual ~Value();
static Value* CreateNullValue();
// DEPRECATED: Do not use the following 5 functions. Instead, use
// new FundamentalValue or new StringValue.
static FundamentalValue* CreateBooleanValue(bool in_value);
static FundamentalValue* CreateIntegerValue(int in_value);
static FundamentalValue* CreateDoubleValue(double in_value);
static StringValue* CreateStringValue(const std::string& in_value);
static StringValue* CreateStringValue(const string16& in_value);
// Returns the type of the value stored by the current Value object.
// Each type will be implemented by only one subclass of Value, so it's
@ -96,6 +84,7 @@ class BASE_EXPORT Value {
virtual bool GetAsDouble(double* out_value) const;
virtual bool GetAsString(std::string* out_value) const;
virtual bool GetAsString(string16* out_value) const;
virtual bool GetAsString(const StringValue** out_value) const;
virtual bool GetAsList(ListValue** out_value);
virtual bool GetAsList(const ListValue** out_value) const;
virtual bool GetAsDictionary(DictionaryValue** out_value);
@ -137,6 +126,8 @@ class BASE_EXPORT FundamentalValue : public Value {
// Overridden from Value:
virtual bool GetAsBoolean(bool* out_value) const OVERRIDE;
virtual bool GetAsInteger(int* out_value) const OVERRIDE;
// Values of both type TYPE_INTEGER and TYPE_DOUBLE can be obtained as
// doubles.
virtual bool GetAsDouble(double* out_value) const OVERRIDE;
virtual FundamentalValue* DeepCopy() const OVERRIDE;
virtual bool Equals(const Value* other) const OVERRIDE;
@ -159,9 +150,14 @@ class BASE_EXPORT StringValue : public Value {
virtual ~StringValue();
// Returns |value_| as a pointer or reference.
std::string* GetString();
const std::string& GetString() const;
// Overridden from Value:
virtual bool GetAsString(std::string* out_value) const OVERRIDE;
virtual bool GetAsString(string16* out_value) const OVERRIDE;
virtual bool GetAsString(const StringValue** out_value) const OVERRIDE;
virtual StringValue* DeepCopy() const OVERRIDE;
virtual bool Equals(const Value* other) const OVERRIDE;
@ -266,14 +262,18 @@ class BASE_EXPORT DictionaryValue : public Value {
// through the |out_value| parameter, and the function will return true.
// Otherwise, it will return false and |out_value| will be untouched.
// Note that the dictionary always owns the value that's returned.
// |out_value| is optional and will only be set if non-NULL.
bool Get(const std::string& path, const Value** out_value) const;
bool Get(const std::string& path, Value** out_value);
// These are convenience forms of Get(). The value will be retrieved
// and the return value will be true if the path is valid and the value at
// the end of the path can be returned in the form specified.
// |out_value| is optional and will only be set if non-NULL.
bool GetBoolean(const std::string& path, bool* out_value) const;
bool GetInteger(const std::string& path, int* out_value) const;
// Values of both type TYPE_INTEGER and TYPE_DOUBLE can be obtained as
// doubles.
bool GetDouble(const std::string& path, double* out_value) const;
bool GetString(const std::string& path, std::string* out_value) const;
bool GetString(const std::string& path, string16* out_value) const;
@ -324,6 +324,11 @@ class BASE_EXPORT DictionaryValue : public Value {
virtual bool RemoveWithoutPathExpansion(const std::string& key,
scoped_ptr<Value>* out_value);
// Removes a path, clearing out all dictionaries on |path| that remain empty
// after removing the value at |path|.
virtual bool RemovePath(const std::string& path,
scoped_ptr<Value>* out_value);
// Makes a copy of |this| but doesn't include empty dictionaries and lists in
// the copy. This never returns NULL, even if |this| itself is empty.
DictionaryValue* DeepCopyWithoutEmptyChildren() const;
@ -343,6 +348,7 @@ class BASE_EXPORT DictionaryValue : public Value {
class BASE_EXPORT Iterator {
public:
explicit Iterator(const DictionaryValue& target);
~Iterator();
bool IsAtEnd() const { return it_ == target_.dictionary_.end(); }
void Advance() { ++it_; }
@ -393,14 +399,18 @@ class BASE_EXPORT ListValue : public Value {
// Gets the Value at the given index. Modifies |out_value| (and returns true)
// only if the index falls within the current list range.
// Note that the list always owns the Value passed out via |out_value|.
// |out_value| is optional and will only be set if non-NULL.
bool Get(size_t index, const Value** out_value) const;
bool Get(size_t index, Value** out_value);
// Convenience forms of Get(). Modifies |out_value| (and returns true)
// only if the index is valid and the Value at that index can be returned
// in the specified form.
// |out_value| is optional and will only be set if non-NULL.
bool GetBoolean(size_t index, bool* out_value) const;
bool GetInteger(size_t index, int* out_value) const;
// Values of both type TYPE_INTEGER and TYPE_DOUBLE can be obtained as
// doubles.
bool GetDouble(size_t index, double* out_value) const;
bool GetString(size_t index, std::string* out_value) const;
bool GetString(size_t index, string16* out_value) const;
@ -522,10 +532,4 @@ BASE_EXPORT inline std::ostream& operator<<(std::ostream& out,
} // namespace base
// http://crbug.com/88666
using base::DictionaryValue;
using base::ListValue;
using base::StringValue;
using base::Value;
#endif // BASE_VALUES_H_

Просмотреть файл

@ -1,134 +0,0 @@
// Copyright (c) 2012 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.
//
#include "base/win/event_trace_provider.h"
#include <windows.h>
#include <cguid.h>
namespace base {
namespace win {
TRACE_GUID_REGISTRATION EtwTraceProvider::obligatory_guid_registration_ = {
&GUID_NULL,
NULL
};
EtwTraceProvider::EtwTraceProvider(const GUID& provider_name)
: provider_name_(provider_name), registration_handle_(NULL),
session_handle_(NULL), enable_flags_(0), enable_level_(0) {
}
EtwTraceProvider::EtwTraceProvider()
: provider_name_(GUID_NULL), registration_handle_(NULL),
session_handle_(NULL), enable_flags_(0), enable_level_(0) {
}
EtwTraceProvider::~EtwTraceProvider() {
Unregister();
}
ULONG EtwTraceProvider::EnableEvents(void* buffer) {
session_handle_ = ::GetTraceLoggerHandle(buffer);
if (NULL == session_handle_) {
return ::GetLastError();
}
enable_flags_ = ::GetTraceEnableFlags(session_handle_);
enable_level_ = ::GetTraceEnableLevel(session_handle_);
// Give subclasses a chance to digest the state change.
OnEventsEnabled();
return ERROR_SUCCESS;
}
ULONG EtwTraceProvider::DisableEvents() {
// Give subclasses a chance to digest the state change.
OnEventsDisabled();
enable_level_ = 0;
enable_flags_ = 0;
session_handle_ = NULL;
PostEventsDisabled();
return ERROR_SUCCESS;
}
ULONG EtwTraceProvider::Callback(WMIDPREQUESTCODE request, void* buffer) {
switch (request) {
case WMI_ENABLE_EVENTS:
return EnableEvents(buffer);
case WMI_DISABLE_EVENTS:
return DisableEvents();
default:
return ERROR_INVALID_PARAMETER;
}
// Not reached.
}
ULONG WINAPI EtwTraceProvider::ControlCallback(WMIDPREQUESTCODE request,
void* context, ULONG *reserved, void* buffer) {
EtwTraceProvider *provider = reinterpret_cast<EtwTraceProvider*>(context);
return provider->Callback(request, buffer);
}
ULONG EtwTraceProvider::Register() {
if (provider_name_ == GUID_NULL)
return ERROR_INVALID_NAME;
return ::RegisterTraceGuids(ControlCallback, this, &provider_name_,
1, &obligatory_guid_registration_, NULL, NULL, &registration_handle_);
}
ULONG EtwTraceProvider::Unregister() {
// If a session is active, notify subclasses that it's going away.
if (session_handle_ != NULL)
DisableEvents();
ULONG ret = ::UnregisterTraceGuids(registration_handle_);
registration_handle_ = NULL;
return ret;
}
ULONG EtwTraceProvider::Log(const EtwEventClass& event_class,
EtwEventType type, EtwEventLevel level, const char *message) {
if (NULL == session_handle_ || enable_level_ < level)
return ERROR_SUCCESS; // No one listening.
EtwMofEvent<1> event(event_class, type, level);
event.fields[0].DataPtr = reinterpret_cast<ULONG64>(message);
event.fields[0].Length = message ?
static_cast<ULONG>(sizeof(message[0]) * (1 + strlen(message))) : 0;
return ::TraceEvent(session_handle_, &event.header);
}
ULONG EtwTraceProvider::Log(const EtwEventClass& event_class,
EtwEventType type, EtwEventLevel level, const wchar_t *message) {
if (NULL == session_handle_ || enable_level_ < level)
return ERROR_SUCCESS; // No one listening.
EtwMofEvent<1> event(event_class, type, level);
event.fields[0].DataPtr = reinterpret_cast<ULONG64>(message);
event.fields[0].Length = message ?
static_cast<ULONG>(sizeof(message[0]) * (1 + wcslen(message))) : 0;
return ::TraceEvent(session_handle_, &event.header);
}
ULONG EtwTraceProvider::Log(EVENT_TRACE_HEADER* event) {
if (enable_level_ < event->Class.Level)
return ERROR_SUCCESS;
return ::TraceEvent(session_handle_, event);
}
} // namespace win
} // namespace base

Просмотреть файл

@ -1,180 +0,0 @@
// Copyright (c) 2011 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.
//
// Declaration of a Windows event trace provider class, to allow using
// Windows Event Tracing for logging transport and control.
#ifndef BASE_WIN_EVENT_TRACE_PROVIDER_H_
#define BASE_WIN_EVENT_TRACE_PROVIDER_H_
#include <windows.h>
#include <wmistr.h>
#include <evntrace.h>
#include "base/base_export.h"
#include "base/basictypes.h"
namespace base {
namespace win {
typedef GUID EtwEventClass;
typedef UCHAR EtwEventType;
typedef UCHAR EtwEventLevel;
typedef USHORT EtwEventVersion;
typedef ULONG EtwEventFlags;
// Base class is a POD for correctness.
template <size_t N> struct EtwMofEventBase {
EVENT_TRACE_HEADER header;
MOF_FIELD fields[N];
};
// Utility class to auto-initialize event trace header structures.
template <size_t N> class EtwMofEvent: public EtwMofEventBase<N> {
public:
typedef EtwMofEventBase<N> Super;
// Clang and the C++ standard don't allow unqualified lookup into dependent
// bases, hence these using decls to explicitly pull the names out.
using EtwMofEventBase<N>::header;
using EtwMofEventBase<N>::fields;
EtwMofEvent() {
memset(static_cast<Super*>(this), 0, sizeof(Super));
}
EtwMofEvent(const EtwEventClass& event_class, EtwEventType type,
EtwEventLevel level) {
memset(static_cast<Super*>(this), 0, sizeof(Super));
header.Size = sizeof(Super);
header.Guid = event_class;
header.Class.Type = type;
header.Class.Level = level;
header.Flags = WNODE_FLAG_TRACED_GUID | WNODE_FLAG_USE_MOF_PTR;
}
EtwMofEvent(const EtwEventClass& event_class, EtwEventType type,
EtwEventVersion version, EtwEventLevel level) {
memset(static_cast<Super*>(this), 0, sizeof(Super));
header.Size = sizeof(Super);
header.Guid = event_class;
header.Class.Type = type;
header.Class.Version = version;
header.Class.Level = level;
header.Flags = WNODE_FLAG_TRACED_GUID | WNODE_FLAG_USE_MOF_PTR;
}
void SetField(int field, size_t size, const void *data) {
// DCHECK(field < N);
if ((field < N) && (size <= kuint32max)) {
fields[field].DataPtr = reinterpret_cast<ULONG64>(data);
fields[field].Length = static_cast<ULONG>(size);
}
}
EVENT_TRACE_HEADER* get() { return& header; }
private:
DISALLOW_COPY_AND_ASSIGN(EtwMofEvent);
};
// Trace provider with Event Tracing for Windows. The trace provider
// registers with ETW by its name which is a GUID. ETW calls back to
// the object whenever the trace level or enable flags for this provider
// name changes.
// Users of this class can test whether logging is currently enabled at
// a particular trace level, and whether particular enable flags are set,
// before other resources are consumed to generate and issue the log
// messages themselves.
class BASE_EXPORT EtwTraceProvider {
public:
// Creates an event trace provider identified by provider_name, which
// will be the name registered with Event Tracing for Windows (ETW).
explicit EtwTraceProvider(const GUID& provider_name);
// Creates an unnamed event trace provider, the provider must be given
// a name before registration.
EtwTraceProvider();
virtual ~EtwTraceProvider();
// Registers the trace provider with Event Tracing for Windows.
// Note: from this point forward ETW may call the provider's control
// callback. If the provider's name is enabled in some trace session
// already, the callback may occur recursively from this call, so
// call this only when you're ready to handle callbacks.
ULONG Register();
// Unregisters the trace provider with ETW.
ULONG Unregister();
// Accessors.
void set_provider_name(const GUID& provider_name) {
provider_name_ = provider_name;
}
const GUID& provider_name() const { return provider_name_; }
TRACEHANDLE registration_handle() const { return registration_handle_; }
TRACEHANDLE session_handle() const { return session_handle_; }
EtwEventFlags enable_flags() const { return enable_flags_; }
EtwEventLevel enable_level() const { return enable_level_; }
// Returns true iff logging should be performed for "level" and "flags".
// Note: flags is treated as a bitmask, and should normally have a single
// bit set, to test whether to log for a particular sub "facility".
bool ShouldLog(EtwEventLevel level, EtwEventFlags flags) {
return NULL != session_handle_ && level >= enable_level_ &&
(0 != (flags & enable_flags_));
}
// Simple wrappers to log Unicode and ANSI strings.
// Do nothing if !ShouldLog(level, 0xFFFFFFFF).
ULONG Log(const EtwEventClass& event_class, EtwEventType type,
EtwEventLevel level, const char *message);
ULONG Log(const EtwEventClass& event_class, EtwEventType type,
EtwEventLevel level, const wchar_t *message);
// Log the provided event.
ULONG Log(EVENT_TRACE_HEADER* event);
protected:
// Called after events have been enabled, override in subclasses
// to set up state or log at the start of a session.
// Note: This function may be called ETW's thread and may be racy,
// bring your own locking if needed.
virtual void OnEventsEnabled() {}
// Called just before events are disabled, override in subclasses
// to tear down state or log at the end of a session.
// Note: This function may be called ETW's thread and may be racy,
// bring your own locking if needed.
virtual void OnEventsDisabled() {}
// Called just after events have been disabled, override in subclasses
// to tear down state at the end of a session. At this point it's
// to late to log anything to the session.
// Note: This function may be called ETW's thread and may be racy,
// bring your own locking if needed.
virtual void PostEventsDisabled() {}
private:
ULONG EnableEvents(PVOID buffer);
ULONG DisableEvents();
ULONG Callback(WMIDPREQUESTCODE request, PVOID buffer);
static ULONG WINAPI ControlCallback(WMIDPREQUESTCODE request, PVOID context,
ULONG *reserved, PVOID buffer);
GUID provider_name_;
TRACEHANDLE registration_handle_;
TRACEHANDLE session_handle_;
EtwEventFlags enable_flags_;
EtwEventLevel enable_level_;
// We don't use this, but on XP we're obliged to pass one in to
// RegisterTraceGuids. Non-const, because that's how the API needs it.
static TRACE_GUID_REGISTRATION obligatory_guid_registration_;
DISALLOW_COPY_AND_ASSIGN(EtwTraceProvider);
};
} // namespace win
} // namespace base
#endif // BASE_WIN_EVENT_TRACE_PROVIDER_H_

Просмотреть файл

@ -1,483 +0,0 @@
// Copyright (c) 2012 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.
#include "base/win/registry.h"
#include <shlwapi.h>
#include <algorithm>
#include "base/logging.h"
#include "base/strings/string_util.h"
#include "base/threading/thread_restrictions.h"
#pragma comment(lib, "shlwapi.lib") // for SHDeleteKey
namespace base {
namespace win {
namespace {
// RegEnumValue() reports the number of characters from the name that were
// written to the buffer, not how many there are. This constant is the maximum
// name size, such that a buffer with this size should read any name.
const DWORD MAX_REGISTRY_NAME_SIZE = 16384;
// Registry values are read as BYTE* but can have wchar_t* data whose last
// wchar_t is truncated. This function converts the reported |byte_size| to
// a size in wchar_t that can store a truncated wchar_t if necessary.
inline DWORD to_wchar_size(DWORD byte_size) {
return (byte_size + sizeof(wchar_t) - 1) / sizeof(wchar_t);
}
} // namespace
// RegKey ----------------------------------------------------------------------
RegKey::RegKey()
: key_(NULL),
watch_event_(0) {
}
RegKey::RegKey(HKEY key)
: key_(key),
watch_event_(0) {
}
RegKey::RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access)
: key_(NULL),
watch_event_(0) {
if (rootkey) {
if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK))
Create(rootkey, subkey, access);
else
Open(rootkey, subkey, access);
} else {
DCHECK(!subkey);
}
}
RegKey::~RegKey() {
Close();
}
LONG RegKey::Create(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
DWORD disposition_value;
return CreateWithDisposition(rootkey, subkey, &disposition_value, access);
}
LONG RegKey::CreateWithDisposition(HKEY rootkey, const wchar_t* subkey,
DWORD* disposition, REGSAM access) {
DCHECK(rootkey && subkey && access && disposition);
Close();
LONG result = RegCreateKeyEx(rootkey, subkey, 0, NULL,
REG_OPTION_NON_VOLATILE, access, NULL, &key_,
disposition);
return result;
}
LONG RegKey::CreateKey(const wchar_t* name, REGSAM access) {
DCHECK(name && access);
HKEY subkey = NULL;
LONG result = RegCreateKeyEx(key_, name, 0, NULL, REG_OPTION_NON_VOLATILE,
access, NULL, &subkey, NULL);
Close();
key_ = subkey;
return result;
}
LONG RegKey::Open(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
DCHECK(rootkey && subkey && access);
Close();
LONG result = RegOpenKeyEx(rootkey, subkey, 0, access, &key_);
return result;
}
LONG RegKey::OpenKey(const wchar_t* relative_key_name, REGSAM access) {
DCHECK(relative_key_name && access);
HKEY subkey = NULL;
LONG result = RegOpenKeyEx(key_, relative_key_name, 0, access, &subkey);
// We have to close the current opened key before replacing it with the new
// one.
Close();
key_ = subkey;
return result;
}
void RegKey::Close() {
StopWatching();
if (key_) {
::RegCloseKey(key_);
key_ = NULL;
}
}
void RegKey::Set(HKEY key) {
if (key_ != key) {
Close();
key_ = key;
}
}
HKEY RegKey::Take() {
StopWatching();
HKEY key = key_;
key_ = NULL;
return key;
}
bool RegKey::HasValue(const wchar_t* name) const {
return RegQueryValueEx(key_, name, 0, NULL, NULL, NULL) == ERROR_SUCCESS;
}
DWORD RegKey::GetValueCount() const {
DWORD count = 0;
LONG result = RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL, &count,
NULL, NULL, NULL, NULL);
return (result == ERROR_SUCCESS) ? count : 0;
}
LONG RegKey::GetValueNameAt(int index, std::wstring* name) const {
wchar_t buf[256];
DWORD bufsize = arraysize(buf);
LONG r = ::RegEnumValue(key_, index, buf, &bufsize, NULL, NULL, NULL, NULL);
if (r == ERROR_SUCCESS)
*name = buf;
return r;
}
LONG RegKey::DeleteKey(const wchar_t* name) {
DCHECK(key_);
DCHECK(name);
LONG result = SHDeleteKey(key_, name);
return result;
}
LONG RegKey::DeleteValue(const wchar_t* value_name) {
DCHECK(key_);
LONG result = RegDeleteValue(key_, value_name);
return result;
}
LONG RegKey::ReadValueDW(const wchar_t* name, DWORD* out_value) const {
DCHECK(out_value);
DWORD type = REG_DWORD;
DWORD size = sizeof(DWORD);
DWORD local_value = 0;
LONG result = ReadValue(name, &local_value, &size, &type);
if (result == ERROR_SUCCESS) {
if ((type == REG_DWORD || type == REG_BINARY) && size == sizeof(DWORD))
*out_value = local_value;
else
result = ERROR_CANTREAD;
}
return result;
}
LONG RegKey::ReadInt64(const wchar_t* name, int64* out_value) const {
DCHECK(out_value);
DWORD type = REG_QWORD;
int64 local_value = 0;
DWORD size = sizeof(local_value);
LONG result = ReadValue(name, &local_value, &size, &type);
if (result == ERROR_SUCCESS) {
if ((type == REG_QWORD || type == REG_BINARY) &&
size == sizeof(local_value))
*out_value = local_value;
else
result = ERROR_CANTREAD;
}
return result;
}
LONG RegKey::ReadValue(const wchar_t* name, std::wstring* out_value) const {
DCHECK(out_value);
const size_t kMaxStringLength = 1024; // This is after expansion.
// Use the one of the other forms of ReadValue if 1024 is too small for you.
wchar_t raw_value[kMaxStringLength];
DWORD type = REG_SZ, size = sizeof(raw_value);
LONG result = ReadValue(name, raw_value, &size, &type);
if (result == ERROR_SUCCESS) {
if (type == REG_SZ) {
*out_value = raw_value;
} else if (type == REG_EXPAND_SZ) {
wchar_t expanded[kMaxStringLength];
size = ExpandEnvironmentStrings(raw_value, expanded, kMaxStringLength);
// Success: returns the number of wchar_t's copied
// Fail: buffer too small, returns the size required
// Fail: other, returns 0
if (size == 0 || size > kMaxStringLength) {
result = ERROR_MORE_DATA;
} else {
*out_value = expanded;
}
} else {
// Not a string. Oops.
result = ERROR_CANTREAD;
}
}
return result;
}
LONG RegKey::ReadValue(const wchar_t* name,
void* data,
DWORD* dsize,
DWORD* dtype) const {
LONG result = RegQueryValueEx(key_, name, 0, dtype,
reinterpret_cast<LPBYTE>(data), dsize);
return result;
}
LONG RegKey::ReadValues(const wchar_t* name,
std::vector<std::wstring>* values) {
values->clear();
DWORD type = REG_MULTI_SZ;
DWORD size = 0;
LONG result = ReadValue(name, NULL, &size, &type);
if (FAILED(result) || size == 0)
return result;
if (type != REG_MULTI_SZ)
return ERROR_CANTREAD;
std::vector<wchar_t> buffer(size / sizeof(wchar_t));
result = ReadValue(name, &buffer[0], &size, NULL);
if (FAILED(result) || size == 0)
return result;
// Parse the double-null-terminated list of strings.
// Note: This code is paranoid to not read outside of |buf|, in the case where
// it may not be properly terminated.
const wchar_t* entry = &buffer[0];
const wchar_t* buffer_end = entry + (size / sizeof(wchar_t));
while (entry < buffer_end && entry[0] != '\0') {
const wchar_t* entry_end = std::find(entry, buffer_end, L'\0');
values->push_back(std::wstring(entry, entry_end));
entry = entry_end + 1;
}
return 0;
}
LONG RegKey::WriteValue(const wchar_t* name, DWORD in_value) {
return WriteValue(
name, &in_value, static_cast<DWORD>(sizeof(in_value)), REG_DWORD);
}
LONG RegKey::WriteValue(const wchar_t * name, const wchar_t* in_value) {
return WriteValue(name, in_value,
static_cast<DWORD>(sizeof(*in_value) * (wcslen(in_value) + 1)), REG_SZ);
}
LONG RegKey::WriteValue(const wchar_t* name,
const void* data,
DWORD dsize,
DWORD dtype) {
DCHECK(data || !dsize);
LONG result = RegSetValueEx(key_, name, 0, dtype,
reinterpret_cast<LPBYTE>(const_cast<void*>(data)), dsize);
return result;
}
LONG RegKey::StartWatching() {
DCHECK(key_);
if (!watch_event_)
watch_event_ = CreateEvent(NULL, TRUE, FALSE, NULL);
DWORD filter = REG_NOTIFY_CHANGE_NAME |
REG_NOTIFY_CHANGE_ATTRIBUTES |
REG_NOTIFY_CHANGE_LAST_SET |
REG_NOTIFY_CHANGE_SECURITY;
// Watch the registry key for a change of value.
LONG result = RegNotifyChangeKeyValue(key_, TRUE, filter, watch_event_, TRUE);
if (result != ERROR_SUCCESS) {
CloseHandle(watch_event_);
watch_event_ = 0;
}
return result;
}
bool RegKey::HasChanged() {
if (watch_event_) {
if (WaitForSingleObject(watch_event_, 0) == WAIT_OBJECT_0) {
StartWatching();
return true;
}
}
return false;
}
LONG RegKey::StopWatching() {
LONG result = ERROR_INVALID_HANDLE;
if (watch_event_) {
CloseHandle(watch_event_);
watch_event_ = 0;
result = ERROR_SUCCESS;
}
return result;
}
// RegistryValueIterator ------------------------------------------------------
RegistryValueIterator::RegistryValueIterator(HKEY root_key,
const wchar_t* folder_key)
: name_(MAX_PATH, L'\0'),
value_(MAX_PATH, L'\0') {
LONG result = RegOpenKeyEx(root_key, folder_key, 0, KEY_READ, &key_);
if (result != ERROR_SUCCESS) {
key_ = NULL;
} else {
DWORD count = 0;
result = ::RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL, &count,
NULL, NULL, NULL, NULL);
if (result != ERROR_SUCCESS) {
::RegCloseKey(key_);
key_ = NULL;
} else {
index_ = count - 1;
}
}
Read();
}
RegistryValueIterator::~RegistryValueIterator() {
if (key_)
::RegCloseKey(key_);
}
DWORD RegistryValueIterator::ValueCount() const {
DWORD count = 0;
LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL,
&count, NULL, NULL, NULL, NULL);
if (result != ERROR_SUCCESS)
return 0;
return count;
}
bool RegistryValueIterator::Valid() const {
return key_ != NULL && index_ >= 0;
}
void RegistryValueIterator::operator++() {
--index_;
Read();
}
bool RegistryValueIterator::Read() {
if (Valid()) {
DWORD capacity = static_cast<DWORD>(name_.capacity());
DWORD name_size = capacity;
// |value_size_| is in bytes. Reserve the last character for a NUL.
value_size_ = static_cast<DWORD>((value_.size() - 1) * sizeof(wchar_t));
LONG result = ::RegEnumValue(
key_, index_, WriteInto(&name_, name_size), &name_size, NULL, &type_,
reinterpret_cast<BYTE*>(vector_as_array(&value_)), &value_size_);
if (result == ERROR_MORE_DATA) {
// Registry key names are limited to 255 characters and fit within
// MAX_PATH (which is 260) but registry value names can use up to 16,383
// characters and the value itself is not limited
// (from http://msdn.microsoft.com/en-us/library/windows/desktop/
// ms724872(v=vs.85).aspx).
// Resize the buffers and retry if their size caused the failure.
DWORD value_size_in_wchars = to_wchar_size(value_size_);
if (value_size_in_wchars + 1 > value_.size())
value_.resize(value_size_in_wchars + 1, L'\0');
value_size_ = static_cast<DWORD>((value_.size() - 1) * sizeof(wchar_t));
name_size = name_size == capacity ? MAX_REGISTRY_NAME_SIZE : capacity;
result = ::RegEnumValue(
key_, index_, WriteInto(&name_, name_size), &name_size, NULL, &type_,
reinterpret_cast<BYTE*>(vector_as_array(&value_)), &value_size_);
}
if (result == ERROR_SUCCESS) {
DCHECK_LT(to_wchar_size(value_size_), value_.size());
value_[to_wchar_size(value_size_)] = L'\0';
return true;
}
}
name_[0] = L'\0';
value_[0] = L'\0';
value_size_ = 0;
return false;
}
// RegistryKeyIterator --------------------------------------------------------
RegistryKeyIterator::RegistryKeyIterator(HKEY root_key,
const wchar_t* folder_key) {
LONG result = RegOpenKeyEx(root_key, folder_key, 0, KEY_READ, &key_);
if (result != ERROR_SUCCESS) {
key_ = NULL;
} else {
DWORD count = 0;
LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, &count, NULL, NULL,
NULL, NULL, NULL, NULL, NULL);
if (result != ERROR_SUCCESS) {
::RegCloseKey(key_);
key_ = NULL;
} else {
index_ = count - 1;
}
}
Read();
}
RegistryKeyIterator::~RegistryKeyIterator() {
if (key_)
::RegCloseKey(key_);
}
DWORD RegistryKeyIterator::SubkeyCount() const {
DWORD count = 0;
LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, &count, NULL, NULL,
NULL, NULL, NULL, NULL, NULL);
if (result != ERROR_SUCCESS)
return 0;
return count;
}
bool RegistryKeyIterator::Valid() const {
return key_ != NULL && index_ >= 0;
}
void RegistryKeyIterator::operator++() {
--index_;
Read();
}
bool RegistryKeyIterator::Read() {
if (Valid()) {
DWORD ncount = arraysize(name_);
FILETIME written;
LONG r = ::RegEnumKeyEx(key_, index_, name_, &ncount, NULL, NULL,
NULL, &written);
if (ERROR_SUCCESS == r)
return true;
}
name_[0] = '\0';
return false;
}
} // namespace win
} // namespace base

Просмотреть файл

@ -1,219 +0,0 @@
// Copyright (c) 2012 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.
#ifndef BASE_WIN_REGISTRY_H_
#define BASE_WIN_REGISTRY_H_
#include <windows.h>
#include <string>
#include <vector>
#include "base/base_export.h"
#include "base/basictypes.h"
#include "base/stl_util.h"
namespace base {
namespace win {
// Utility class to read, write and manipulate the Windows Registry.
// Registry vocabulary primer: a "key" is like a folder, in which there
// are "values", which are <name, data> pairs, with an associated data type.
//
// Note:
// ReadValue family of functions guarantee that the return arguments
// are not touched in case of failure.
class BASE_EXPORT RegKey {
public:
RegKey();
explicit RegKey(HKEY key);
RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access);
~RegKey();
LONG Create(HKEY rootkey, const wchar_t* subkey, REGSAM access);
LONG CreateWithDisposition(HKEY rootkey, const wchar_t* subkey,
DWORD* disposition, REGSAM access);
// Creates a subkey or open it if it already exists.
LONG CreateKey(const wchar_t* name, REGSAM access);
// Opens an existing reg key.
LONG Open(HKEY rootkey, const wchar_t* subkey, REGSAM access);
// Opens an existing reg key, given the relative key name.
LONG OpenKey(const wchar_t* relative_key_name, REGSAM access);
// Closes this reg key.
void Close();
// Replaces the handle of the registry key and takes ownership of the handle.
void Set(HKEY key);
// Transfers ownership away from this object.
HKEY Take();
// Returns false if this key does not have the specified value, of if an error
// occurrs while attempting to access it.
bool HasValue(const wchar_t* value_name) const;
// Returns the number of values for this key, of 0 if the number cannot be
// determined.
DWORD GetValueCount() const;
// Determine the nth value's name.
LONG GetValueNameAt(int index, std::wstring* name) const;
// True while the key is valid.
bool Valid() const { return key_ != NULL; }
// Kill a key and everything that live below it; please be careful when using
// it.
LONG DeleteKey(const wchar_t* name);
// Deletes a single value within the key.
LONG DeleteValue(const wchar_t* name);
// Getters:
// Returns an int32 value. If |name| is NULL or empty, returns the default
// value, if any.
LONG ReadValueDW(const wchar_t* name, DWORD* out_value) const;
// Returns an int64 value. If |name| is NULL or empty, returns the default
// value, if any.
LONG ReadInt64(const wchar_t* name, int64* out_value) const;
// Returns a string value. If |name| is NULL or empty, returns the default
// value, if any.
LONG ReadValue(const wchar_t* name, std::wstring* out_value) const;
// Reads a REG_MULTI_SZ registry field into a vector of strings. Clears
// |values| initially and adds further strings to the list. Returns
// ERROR_CANTREAD if type is not REG_MULTI_SZ.
LONG ReadValues(const wchar_t* name, std::vector<std::wstring>* values);
// Returns raw data. If |name| is NULL or empty, returns the default
// value, if any.
LONG ReadValue(const wchar_t* name,
void* data,
DWORD* dsize,
DWORD* dtype) const;
// Setters:
// Sets an int32 value.
LONG WriteValue(const wchar_t* name, DWORD in_value);
// Sets a string value.
LONG WriteValue(const wchar_t* name, const wchar_t* in_value);
// Sets raw data, including type.
LONG WriteValue(const wchar_t* name,
const void* data,
DWORD dsize,
DWORD dtype);
// Starts watching the key to see if any of its values have changed.
// The key must have been opened with the KEY_NOTIFY access privilege.
LONG StartWatching();
// If StartWatching hasn't been called, always returns false.
// Otherwise, returns true if anything under the key has changed.
// This can't be const because the |watch_event_| may be refreshed.
bool HasChanged();
// Will automatically be called by destructor if not manually called
// beforehand. Returns true if it was watching, false otherwise.
LONG StopWatching();
inline bool IsWatching() const { return watch_event_ != 0; }
HANDLE watch_event() const { return watch_event_; }
HKEY Handle() const { return key_; }
private:
HKEY key_; // The registry key being iterated.
HANDLE watch_event_;
DISALLOW_COPY_AND_ASSIGN(RegKey);
};
// Iterates the entries found in a particular folder on the registry.
class BASE_EXPORT RegistryValueIterator {
public:
RegistryValueIterator(HKEY root_key, const wchar_t* folder_key);
~RegistryValueIterator();
DWORD ValueCount() const;
// True while the iterator is valid.
bool Valid() const;
// Advances to the next registry entry.
void operator++();
const wchar_t* Name() const { return name_.c_str(); }
const wchar_t* Value() const { return vector_as_array(&value_); }
// ValueSize() is in bytes.
DWORD ValueSize() const { return value_size_; }
DWORD Type() const { return type_; }
int Index() const { return index_; }
private:
// Read in the current values.
bool Read();
// The registry key being iterated.
HKEY key_;
// Current index of the iteration.
int index_;
// Current values.
std::wstring name_;
std::vector<wchar_t> value_;
DWORD value_size_;
DWORD type_;
DISALLOW_COPY_AND_ASSIGN(RegistryValueIterator);
};
class BASE_EXPORT RegistryKeyIterator {
public:
RegistryKeyIterator(HKEY root_key, const wchar_t* folder_key);
~RegistryKeyIterator();
DWORD SubkeyCount() const;
// True while the iterator is valid.
bool Valid() const;
// Advances to the next entry in the folder.
void operator++();
const wchar_t* Name() const { return name_; }
int Index() const { return index_; }
private:
// Read in the current values.
bool Read();
// The registry key being iterated.
HKEY key_;
// Current index of the iteration.
int index_;
wchar_t name_[MAX_PATH];
DISALLOW_COPY_AND_ASSIGN(RegistryKeyIterator);
};
} // namespace win
} // namespace base
#endif // BASE_WIN_REGISTRY_H_

Просмотреть файл

@ -27,11 +27,9 @@ namespace win {
// Generic wrapper for raw handles that takes care of closing handles
// automatically. The class interface follows the style of
// the ScopedStdioHandle class with a few additions:
// the ScopedFILE class with one addition:
// - IsValid() method can tolerate multiple invalid handle values such as NULL
// and INVALID_HANDLE_VALUE (-1) for Win32 handles.
// - Receive() method allows to receive a handle value from a function that
// takes a raw handle pointer only.
template <class Traits, class Verifier>
class GenericScopedHandle {
MOVE_ONLY_TYPE_FOR_CPP_03(GenericScopedHandle, RValue)
@ -39,22 +37,6 @@ class GenericScopedHandle {
public:
typedef typename Traits::Handle Handle;
// Helper object to contain the effect of Receive() to the function that needs
// a pointer, and allow proper tracking of the handle.
class Receiver {
public:
explicit Receiver(GenericScopedHandle* owner)
: handle_(Traits::NullHandle()),
owner_(owner) {}
~Receiver() { owner_->Set(handle_); }
operator Handle*() { return &handle_; }
private:
Handle handle_;
GenericScopedHandle* owner_;
};
GenericScopedHandle() : handle_(Traits::NullHandle()) {}
explicit GenericScopedHandle(Handle handle) : handle_(Traits::NullHandle()) {
@ -102,16 +84,6 @@ class GenericScopedHandle {
return handle_;
}
// This method is intended to be used with functions that require a pointer to
// a destination handle, like so:
// void CreateRequiredHandle(Handle* out_handle);
// ScopedHandle a;
// CreateRequiredHandle(a.Receive());
Receiver Receive() {
DCHECK(!Traits::IsHandleValid(handle_)) << "Handle must be NULL";
return Receiver(this);
}
// Transfers ownership away from this object.
Handle Take() {
Handle temp = handle_;

Просмотреть файл

@ -15,7 +15,7 @@ namespace {
// Duplicates source into target, returning true upon success. |target| is
// guaranteed to be untouched in case of failure. Succeeds with no side-effects
// if source is NULL.
bool CheckAndDuplicateHandle(HANDLE source, HANDLE* target) {
bool CheckAndDuplicateHandle(HANDLE source, ScopedHandle* target) {
if (!source)
return true;
@ -26,7 +26,7 @@ bool CheckAndDuplicateHandle(HANDLE source, HANDLE* target) {
DPLOG(ERROR) << "Failed to duplicate a handle.";
return false;
}
*target = temp;
target->Set(temp);
return true;
}
@ -36,13 +36,13 @@ ScopedProcessInformation::ScopedProcessInformation()
: process_id_(0), thread_id_(0) {
}
ScopedProcessInformation::~ScopedProcessInformation() {
Close();
ScopedProcessInformation::ScopedProcessInformation(
const PROCESS_INFORMATION& process_info) : process_id_(0), thread_id_(0) {
Set(process_info);
}
ScopedProcessInformation::Receiver ScopedProcessInformation::Receive() {
DCHECK(!IsValid()) << "process_information_ must be NULL";
return Receiver(this);
ScopedProcessInformation::~ScopedProcessInformation() {
Close();
}
bool ScopedProcessInformation::IsValid() const {
@ -72,10 +72,8 @@ bool ScopedProcessInformation::DuplicateFrom(
DCHECK(!IsValid()) << "target ScopedProcessInformation must be NULL";
DCHECK(other.IsValid()) << "source ScopedProcessInformation must be valid";
if (CheckAndDuplicateHandle(other.process_handle(),
process_handle_.Receive()) &&
CheckAndDuplicateHandle(other.thread_handle(),
thread_handle_.Receive())) {
if (CheckAndDuplicateHandle(other.process_handle(), &process_handle_) &&
CheckAndDuplicateHandle(other.thread_handle(), &thread_handle_)) {
process_id_ = other.process_id();
thread_id_ = other.thread_id();
return true;

Просмотреть файл

@ -18,33 +18,10 @@ namespace win {
// structures. Allows clients to take ownership of either handle independently.
class BASE_EXPORT ScopedProcessInformation {
public:
// Helper object to contain the effect of Receive() to the funtion that needs
// a pointer.
class Receiver {
public:
explicit Receiver(ScopedProcessInformation* owner)
: info_(),
owner_(owner) {}
~Receiver() { owner_->Set(info_); }
operator PROCESS_INFORMATION*() { return &info_; }
private:
PROCESS_INFORMATION info_;
ScopedProcessInformation* owner_;
};
ScopedProcessInformation();
explicit ScopedProcessInformation(const PROCESS_INFORMATION& process_info);
~ScopedProcessInformation();
// Returns an object that may be passed to API calls such as CreateProcess.
// DCHECKs that the object is not currently holding any handles.
// HANDLEs stored in the returned PROCESS_INFORMATION will be owned by this
// instance.
// The intended use case is something like this:
// if (::CreateProcess(..., startup_info, scoped_proces_info.Receive()))
Receiver Receive();
// Returns true iff this instance is holding a thread and/or process handle.
bool IsValid() const;

Просмотреть файл

@ -10,6 +10,10 @@
#include "base/strings/utf_string_conversions.h"
#include "base/win/registry.h"
namespace {
typedef BOOL (WINAPI *GetProductInfoPtr)(DWORD, DWORD, DWORD, DWORD, PDWORD);
}
namespace base {
namespace win {
@ -34,7 +38,7 @@ OSInfo::OSInfo()
architecture_(OTHER_ARCHITECTURE),
wow64_status_(GetWOW64StatusForProcess(GetCurrentProcess())) {
OSVERSIONINFOEX version_info = { sizeof version_info };
GetVersionEx(reinterpret_cast<OSVERSIONINFO*>(&version_info));
::GetVersionEx(reinterpret_cast<OSVERSIONINFO*>(&version_info));
version_number_.major = version_info.dwMajorVersion;
version_number_.minor = version_info.dwMinorVersion;
version_number_.build = version_info.dwBuildNumber;
@ -68,7 +72,7 @@ OSInfo::OSInfo()
service_pack_.minor = version_info.wServicePackMinor;
SYSTEM_INFO system_info = { 0 };
GetNativeSystemInfo(&system_info);
::GetNativeSystemInfo(&system_info);
switch (system_info.wProcessorArchitecture) {
case PROCESSOR_ARCHITECTURE_INTEL: architecture_ = X86_ARCHITECTURE; break;
case PROCESSOR_ARCHITECTURE_AMD64: architecture_ = X64_ARCHITECTURE; break;
@ -76,6 +80,64 @@ OSInfo::OSInfo()
}
processors_ = system_info.dwNumberOfProcessors;
allocation_granularity_ = system_info.dwAllocationGranularity;
GetProductInfoPtr get_product_info;
DWORD os_type;
if (version_info.dwMajorVersion == 6) {
// Only present on Vista+.
get_product_info = reinterpret_cast<GetProductInfoPtr>(
::GetProcAddress(::GetModuleHandle(L"kernel32.dll"), "GetProductInfo"));
get_product_info(version_info.dwMajorVersion, version_info.dwMinorVersion,
0, 0, &os_type);
switch (os_type) {
case PRODUCT_CLUSTER_SERVER:
case PRODUCT_DATACENTER_SERVER:
case PRODUCT_DATACENTER_SERVER_CORE:
case PRODUCT_ENTERPRISE_SERVER:
case PRODUCT_ENTERPRISE_SERVER_CORE:
case PRODUCT_ENTERPRISE_SERVER_IA64:
case PRODUCT_SMALLBUSINESS_SERVER:
case PRODUCT_SMALLBUSINESS_SERVER_PREMIUM:
case PRODUCT_STANDARD_SERVER:
case PRODUCT_STANDARD_SERVER_CORE:
case PRODUCT_WEB_SERVER:
version_type_ = SUITE_SERVER;
break;
case PRODUCT_PROFESSIONAL:
case PRODUCT_ULTIMATE:
case PRODUCT_ENTERPRISE:
case PRODUCT_BUSINESS:
version_type_ = SUITE_PROFESSIONAL;
break;
case PRODUCT_HOME_BASIC:
case PRODUCT_HOME_PREMIUM:
case PRODUCT_STARTER:
default:
version_type_ = SUITE_HOME;
break;
}
} else if (version_info.dwMajorVersion == 5 &&
version_info.dwMinorVersion == 2) {
if (version_info.wProductType == VER_NT_WORKSTATION &&
system_info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) {
version_type_ = SUITE_PROFESSIONAL;
} else if (version_info.wSuiteMask & VER_SUITE_WH_SERVER ) {
version_type_ = SUITE_HOME;
} else {
version_type_ = SUITE_SERVER;
}
} else if (version_info.dwMajorVersion == 5 &&
version_info.dwMinorVersion == 1) {
if(version_info.wSuiteMask & VER_SUITE_PERSONAL)
version_type_ = SUITE_HOME;
else
version_type_ = SUITE_PROFESSIONAL;
} else {
// Windows is pre XP so we don't care but pick a safe default.
version_type_ = SUITE_HOME;
}
}
OSInfo::~OSInfo() {

Просмотреть файл

@ -30,6 +30,16 @@ enum Version {
VERSION_WIN_LAST, // Indicates error condition.
};
// A rough bucketing of the available types of versions of Windows. This is used
// to distinguish enterprise enabled versions from home versions and potentially
// server versions.
enum VersionType {
SUITE_HOME,
SUITE_PROFESSIONAL,
SUITE_SERVER,
SUITE_LAST,
};
// A singleton that can be used to query various pieces of information about the
// OS and process state. Note that this doesn't use the base Singleton class, so
// it can be used without an AtExitManager.
@ -74,6 +84,7 @@ class BASE_EXPORT OSInfo {
Version version() const { return version_; }
// The next two functions return arrays of values, [major, minor(, build)].
VersionNumber version_number() const { return version_number_; }
VersionType version_type() const { return version_type_; }
ServicePack service_pack() const { return service_pack_; }
WindowsArchitecture architecture() const { return architecture_; }
int processors() const { return processors_; }
@ -91,6 +102,7 @@ class BASE_EXPORT OSInfo {
Version version_;
VersionNumber version_number_;
VersionType version_type_;
ServicePack service_pack_;
WindowsArchitecture architecture_;
int processors_;

Просмотреть файл

@ -0,0 +1,65 @@
// 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.
#ifndef SANDBOX_LINUX_SECCOMP_BPF_BPF_TESTER_COMPATIBILITY_DELEGATE_H_
#define SANDBOX_LINUX_SECCOMP_BPF_BPF_TESTER_COMPATIBILITY_DELEGATE_H_
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "base/memory/scoped_ptr.h"
#include "sandbox/linux/seccomp-bpf/sandbox_bpf_compatibility_policy.h"
#include "sandbox/linux/seccomp-bpf/sandbox_bpf_test_runner.h"
#include "sandbox/linux/tests/sandbox_test_runner.h"
#include "sandbox/linux/tests/unit_tests.h"
namespace sandbox {
// This templated class allows building a BPFTesterDelegate from a
// deprecated-style BPF policy (that is a SyscallEvaluator function pointer,
// instead of a SandboxBPFPolicy class), specified in |policy_function| and a
// function pointer to a test in |test_function|.
// This allows both the policy and the test function to take a pointer to an
// object of type "Aux" as a parameter. This is used to implement the BPF_TEST
// macro and should generally not be used directly.
template <class Aux>
class BPFTesterCompatibilityDelegate : public BPFTesterDelegate {
public:
typedef Aux AuxType;
BPFTesterCompatibilityDelegate(
void (*test_function)(AuxType*),
typename CompatibilityPolicy<AuxType>::SyscallEvaluator policy_function)
: aux_(),
test_function_(test_function),
policy_function_(policy_function) {}
virtual ~BPFTesterCompatibilityDelegate() {}
virtual scoped_ptr<SandboxBPFPolicy> GetSandboxBPFPolicy() OVERRIDE {
// The current method is guaranteed to only run in the child process
// running the test. In this process, the current object is guaranteed
// to live forever. So it's ok to pass aux_pointer_for_policy_ to
// the policy, which could in turn pass it to the kernel via Trap().
return scoped_ptr<SandboxBPFPolicy>(
new CompatibilityPolicy<AuxType>(policy_function_, &aux_));
}
virtual void RunTestFunction() OVERRIDE {
// Run the actual test.
// The current object is guaranteed to live forever in the child process
// where this will run.
test_function_(&aux_);
}
private:
AuxType aux_;
void (*test_function_)(AuxType*);
typename CompatibilityPolicy<AuxType>::SyscallEvaluator policy_function_;
DISALLOW_COPY_AND_ASSIGN(BPFTesterCompatibilityDelegate);
};
} // namespace sandbox
#endif // SANDBOX_LINUX_SECCOMP_BPF_BPF_TESTER_COMPATIBILITY_DELEGATE_H_

Просмотреть файл

@ -5,110 +5,118 @@
#ifndef SANDBOX_LINUX_SECCOMP_BPF_BPF_TESTS_H__
#define SANDBOX_LINUX_SECCOMP_BPF_BPF_TESTS_H__
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "base/basictypes.h"
#include "build/build_config.h"
#include "sandbox/linux/seccomp-bpf/bpf_tester_compatibility_delegate.h"
#include "sandbox/linux/tests/unit_tests.h"
#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
namespace sandbox {
// A BPF_DEATH_TEST is just the same as a BPF_TEST, but it assumes that the
// test will fail with a particular known error condition. Use the DEATH_XXX()
// macros from unit_tests.h to specify the expected error condition.
// A BPF_DEATH_TEST is always disabled under ThreadSanitizer, see
// crbug.com/243968.
#define BPF_DEATH_TEST(test_case_name, test_name, death, policy, aux...) \
void BPF_TEST_##test_name(sandbox::BPFTests<aux>::AuxType& BPF_AUX); \
TEST(test_case_name, DISABLE_ON_TSAN(test_name)) { \
sandbox::BPFTests<aux>::TestArgs arg(BPF_TEST_##test_name, policy); \
sandbox::BPFTests<aux>::RunTestInProcess( \
sandbox::BPFTests<aux>::TestWrapper, &arg, death); \
} \
void BPF_TEST_##test_name(sandbox::BPFTests<aux>::AuxType& BPF_AUX)
// BPF_TEST_C() is a special version of SANDBOX_TEST(). It runs a test function
// in a sub-process, under a seccomp-bpf policy specified in
// |bpf_policy_class_name| without failing on configurations that are allowed
// to not support seccomp-bpf in their kernels.
// This is the preferred format for new BPF tests. |bpf_policy_class_name| is a
// class name (which will be default-constructed) that implements the
// SandboxBPFPolicy interface.
// The test function's body can simply follow. Test functions should use
// the BPF_ASSERT macros defined below, not GTEST's macros. The use of
// CHECK* macros is supported but less robust.
#define BPF_TEST_C(test_case_name, test_name, bpf_policy_class_name) \
BPF_DEATH_TEST_C( \
test_case_name, test_name, DEATH_SUCCESS(), bpf_policy_class_name)
// BPF_TEST() is a special version of SANDBOX_TEST(). It turns into a no-op,
// if the host does not have kernel support for running BPF filters.
// Also, it takes advantage of the Die class to avoid calling LOG(FATAL), from
// inside our tests, as we don't need or even want all the error handling that
// LOG(FATAL) would do.
// Identical to BPF_TEST_C but allows to specify the nature of death.
#define BPF_DEATH_TEST_C( \
test_case_name, test_name, death, bpf_policy_class_name) \
void BPF_TEST_C_##test_name(); \
TEST(test_case_name, DISABLE_ON_TSAN(test_name)) { \
sandbox::SandboxBPFTestRunner bpf_test_runner( \
new sandbox::BPFTesterSimpleDelegate<bpf_policy_class_name>( \
BPF_TEST_C_##test_name)); \
sandbox::UnitTests::RunTestInProcess(&bpf_test_runner, death); \
} \
void BPF_TEST_C_##test_name()
// This form of BPF_TEST is a little verbose and should be reserved for complex
// tests where a lot of control is required.
// |bpf_tester_delegate_class| must be a classname implementing the
// BPFTesterDelegate interface.
#define BPF_TEST_D(test_case_name, test_name, bpf_tester_delegate_class) \
BPF_DEATH_TEST_D( \
test_case_name, test_name, DEATH_SUCCESS(), bpf_tester_delegate_class)
// Identical to BPF_TEST_D but allows to specify the nature of death.
#define BPF_DEATH_TEST_D( \
test_case_name, test_name, death, bpf_tester_delegate_class) \
TEST(test_case_name, DISABLE_ON_TSAN(test_name)) { \
sandbox::SandboxBPFTestRunner bpf_test_runner( \
new bpf_tester_delegate_class()); \
sandbox::UnitTests::RunTestInProcess(&bpf_test_runner, death); \
}
// Assertions are handled exactly the same as with a normal SANDBOX_TEST()
#define BPF_ASSERT SANDBOX_ASSERT
#define BPF_ASSERT_EQ(x, y) BPF_ASSERT((x) == (y))
#define BPF_ASSERT_NE(x, y) BPF_ASSERT((x) != (y))
#define BPF_ASSERT_LT(x, y) BPF_ASSERT((x) < (y))
#define BPF_ASSERT_GT(x, y) BPF_ASSERT((x) > (y))
#define BPF_ASSERT_LE(x, y) BPF_ASSERT((x) <= (y))
#define BPF_ASSERT_GE(x, y) BPF_ASSERT((x) >= (y))
// This form of BPF_TEST is now discouraged (but still allowed) in favor of
// BPF_TEST_D and BPF_TEST_C.
// The |policy| parameter should be a SyscallEvaluator function pointer
// (which is now a deprecated way of expressing policies).
// BPF_TEST() takes a C++ data type as an optional fourth parameter. If
// present, this sets up a variable that can be accessed as "BPF_AUX". This
// variable will be passed as an argument to the "policy" function. Policies
// would typically use it as an argument to SandboxBPF::Trap(), if they want to
// communicate data between the BPF_TEST() and a Trap() function.
#define BPF_TEST(test_case_name, test_name, policy, aux...) \
// communicate data between the BPF_TEST() and a Trap() function. The life-time
// of this object is the same as the life-time of the process running under the
// seccomp-bpf policy.
// The type specified in |aux| and the last parameter of the policy function
// must be compatible. |aux| must not be void.
#define BPF_TEST(test_case_name, test_name, policy, aux) \
BPF_DEATH_TEST(test_case_name, test_name, DEATH_SUCCESS(), policy, aux)
// Assertions are handled exactly the same as with a normal SANDBOX_TEST()
#define BPF_ASSERT SANDBOX_ASSERT
// A BPF_DEATH_TEST is just the same as a BPF_TEST, but it assumes that the
// test will fail with a particular known error condition. Use the DEATH_XXX()
// macros from unit_tests.h to specify the expected error condition.
#define BPF_DEATH_TEST(test_case_name, test_name, death, policy, aux) \
void BPF_TEST_##test_name( \
sandbox::BPFTesterCompatibilityDelegate<aux>::AuxType* BPF_AUX); \
TEST(test_case_name, DISABLE_ON_TSAN(test_name)) { \
sandbox::SandboxBPFTestRunner bpf_test_runner( \
new sandbox::BPFTesterCompatibilityDelegate<aux>(BPF_TEST_##test_name, \
policy)); \
sandbox::UnitTests::RunTestInProcess(&bpf_test_runner, death); \
} \
void BPF_TEST_##test_name( \
sandbox::BPFTesterCompatibilityDelegate<aux>::AuxType* BPF_AUX)
// The "Aux" type is optional. We use an "empty" type by default, so that if
// the caller doesn't provide any type, all the BPF_AUX related data compiles
// to nothing.
template <class Aux = int[0]>
class BPFTests : public UnitTests {
// This class takes a simple function pointer as a constructor parameter and a
// class name as a template parameter to implement the BPFTesterDelegate
// interface which can be used to build BPF unittests with
// the SandboxBPFTestRunner class.
template <class PolicyClass>
class BPFTesterSimpleDelegate : public BPFTesterDelegate {
public:
typedef Aux AuxType;
explicit BPFTesterSimpleDelegate(void (*test_function)(void))
: test_function_(test_function) {}
virtual ~BPFTesterSimpleDelegate() {}
class TestArgs {
public:
TestArgs(void (*t)(AuxType&), sandbox::SandboxBPF::EvaluateSyscall p)
: test_(t), policy_(p), aux_() {}
void (*test() const)(AuxType&) { return test_; }
sandbox::SandboxBPF::EvaluateSyscall policy() const { return policy_; }
private:
friend class BPFTests;
void (*test_)(AuxType&);
sandbox::SandboxBPF::EvaluateSyscall policy_;
AuxType aux_;
};
static void TestWrapper(void* void_arg) {
TestArgs* arg = reinterpret_cast<TestArgs*>(void_arg);
sandbox::Die::EnableSimpleExit();
if (sandbox::SandboxBPF::SupportsSeccompSandbox(-1) ==
sandbox::SandboxBPF::STATUS_AVAILABLE) {
// Ensure the the sandbox is actually available at this time
int proc_fd;
BPF_ASSERT((proc_fd = open("/proc", O_RDONLY | O_DIRECTORY)) >= 0);
BPF_ASSERT(sandbox::SandboxBPF::SupportsSeccompSandbox(proc_fd) ==
sandbox::SandboxBPF::STATUS_AVAILABLE);
// Initialize and then start the sandbox with our custom policy
sandbox::SandboxBPF sandbox;
sandbox.set_proc_fd(proc_fd);
sandbox.SetSandboxPolicyDeprecated(arg->policy(), &arg->aux_);
BPF_ASSERT(sandbox.StartSandbox(
sandbox::SandboxBPF::PROCESS_SINGLE_THREADED));
arg->test()(arg->aux_);
} else {
printf("This BPF test is not fully running in this configuration!\n");
// Android and Valgrind are the only configurations where we accept not
// having kernel BPF support.
if (!IsAndroid() && !IsRunningOnValgrind()) {
const bool seccomp_bpf_is_supported = false;
BPF_ASSERT(seccomp_bpf_is_supported);
}
// Call the compiler and verify the policy. That's the least we can do,
// if we don't have kernel support.
sandbox::SandboxBPF sandbox;
sandbox.SetSandboxPolicyDeprecated(arg->policy(), &arg->aux_);
sandbox::SandboxBPF::Program* program =
sandbox.AssembleFilter(true /* force_verification */);
delete program;
sandbox::UnitTests::IgnoreThisTest();
}
virtual scoped_ptr<SandboxBPFPolicy> GetSandboxBPFPolicy() OVERRIDE {
return scoped_ptr<SandboxBPFPolicy>(new PolicyClass());
}
virtual void RunTestFunction() OVERRIDE {
DCHECK(test_function_);
test_function_();
}
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(BPFTests);
void (*test_function_)(void);
DISALLOW_COPY_AND_ASSIGN(BPFTesterSimpleDelegate);
};
} // namespace sandbox

Просмотреть файл

@ -0,0 +1,139 @@
// 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.
#include "sandbox/linux/seccomp-bpf/bpf_tests.h"
#include <errno.h>
#include <sys/ptrace.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "build/build_config.h"
#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
#include "sandbox/linux/services/linux_syscalls.h"
#include "sandbox/linux/tests/unit_tests.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace sandbox {
namespace {
class FourtyTwo {
public:
static const int kMagicValue = 42;
FourtyTwo() : value_(kMagicValue) {}
int value() { return value_; }
private:
int value_;
DISALLOW_COPY_AND_ASSIGN(FourtyTwo);
};
ErrorCode EmptyPolicyTakesClass(SandboxBPF* sandbox,
int sysno,
FourtyTwo* fourty_two) {
// |aux| should point to an instance of FourtyTwo.
BPF_ASSERT(fourty_two);
BPF_ASSERT(FourtyTwo::kMagicValue == fourty_two->value());
if (!SandboxBPF::IsValidSyscallNumber(sysno)) {
return ErrorCode(ENOSYS);
} else {
return ErrorCode(ErrorCode::ERR_ALLOWED);
}
}
BPF_TEST(BPFTest,
BPFAUXPointsToClass,
EmptyPolicyTakesClass,
FourtyTwo /* *BPF_AUX */) {
// BPF_AUX should point to an instance of FourtyTwo.
BPF_ASSERT(BPF_AUX);
BPF_ASSERT(FourtyTwo::kMagicValue == BPF_AUX->value());
}
void DummyTestFunction(FourtyTwo *fourty_two) {
}
TEST(BPFTest, BPFTesterCompatibilityDelegateLeakTest) {
// Don't do anything, simply gives dynamic tools an opportunity to detect
// leaks.
{
BPFTesterCompatibilityDelegate<FourtyTwo> simple_delegate(
DummyTestFunction, EmptyPolicyTakesClass);
}
{
// Test polymorphism.
scoped_ptr<BPFTesterDelegate> simple_delegate(
new BPFTesterCompatibilityDelegate<FourtyTwo>(DummyTestFunction,
EmptyPolicyTakesClass));
}
}
class EnosysPtracePolicy : public SandboxBPFPolicy {
public:
EnosysPtracePolicy() {
my_pid_ = syscall(__NR_getpid);
}
virtual ~EnosysPtracePolicy() {
// Policies should be able to bind with the process on which they are
// created. They should never be created in a parent process.
BPF_ASSERT_EQ(my_pid_, syscall(__NR_getpid));
}
virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox_compiler,
int system_call_number) const OVERRIDE {
if (!SandboxBPF::IsValidSyscallNumber(system_call_number)) {
return ErrorCode(ENOSYS);
} else if (system_call_number == __NR_ptrace) {
// The EvaluateSyscall function should run in the process that created
// the current object.
BPF_ASSERT_EQ(my_pid_, syscall(__NR_getpid));
return ErrorCode(ENOSYS);
} else {
return ErrorCode(ErrorCode::ERR_ALLOWED);
}
}
private:
pid_t my_pid_;
DISALLOW_COPY_AND_ASSIGN(EnosysPtracePolicy);
};
class BasicBPFTesterDelegate : public BPFTesterDelegate {
public:
BasicBPFTesterDelegate() {}
virtual ~BasicBPFTesterDelegate() {}
virtual scoped_ptr<SandboxBPFPolicy> GetSandboxBPFPolicy() OVERRIDE {
return scoped_ptr<SandboxBPFPolicy>(new EnosysPtracePolicy());
}
virtual void RunTestFunction() OVERRIDE {
errno = 0;
int ret = ptrace(PTRACE_TRACEME, -1, NULL, NULL);
BPF_ASSERT(-1 == ret);
BPF_ASSERT(ENOSYS == errno);
}
private:
DISALLOW_COPY_AND_ASSIGN(BasicBPFTesterDelegate);
};
// This is the most powerful and complex way to create a BPF test, but it
// requires a full class definition (BasicBPFTesterDelegate).
BPF_TEST_D(BPFTest, BPFTestWithDelegateClass, BasicBPFTesterDelegate);
// This is the simplest form of BPF tests.
BPF_TEST_C(BPFTest, BPFTestWithInlineTest, EnosysPtracePolicy) {
errno = 0;
int ret = ptrace(PTRACE_TRACEME, -1, NULL, NULL);
BPF_ASSERT(-1 == ret);
BPF_ASSERT(ENOSYS == errno);
}
} // namespace
} // namespace sandbox

Просмотреть файл

@ -106,6 +106,8 @@ void CodeGen::PrintProgram(const SandboxBPF::Program& program) {
fprintf(stderr, "Trap #%d\n", iter->k & SECCOMP_RET_DATA);
} else if ((iter->k & SECCOMP_RET_ACTION) == SECCOMP_RET_ERRNO) {
fprintf(stderr, "errno = %d\n", iter->k & SECCOMP_RET_DATA);
} else if ((iter->k & SECCOMP_RET_ACTION) == SECCOMP_RET_TRACE) {
fprintf(stderr, "Trace #%d\n", iter->k & SECCOMP_RET_DATA);
} else if (iter->k == SECCOMP_RET_ALLOW) {
fprintf(stderr, "Allowed\n");
} else {
@ -443,80 +445,74 @@ static int PointerCompare(const BasicBlock* block1,
// If we have reached the end of the sequence of instructions in one or
// both basic blocks, we know the relative ordering between the two blocks
// and can return.
if (iter1 == insns1.end()) {
if (iter2 == insns2.end()) {
// If the two blocks are the same length (and have elementwise-equal
// code and k fields, which is the only way we can reach this point),
// and the last instruction isn't a JMP or a RET, then we must compare
// their successors.
Instruction* const insns1_last = insns1.back();
Instruction* const insns2_last = insns2.back();
if (BPF_CLASS(insns1_last->code) != BPF_JMP &&
BPF_CLASS(insns1_last->code) != BPF_RET) {
// Non jumping instructions will always have a valid next instruction.
CHECK(insns1_last->next);
CHECK(insns2_last->next);
return PointerCompare(blocks.find(insns1_last->next)->second,
blocks.find(insns2_last->next)->second,
blocks);
} else {
return 0;
}
if (iter1 == insns1.end() || iter2 == insns2.end()) {
if (iter1 != insns1.end()) {
return 1;
}
return -1;
} else if (iter2 == insns2.end()) {
return 1;
if (iter2 != insns2.end()) {
return -1;
}
// If the two blocks are the same length (and have elementwise-equal code
// and k fields) and their last instructions are neither a JMP nor a RET
// (which is the only way we can reach this point), then we must compare
// their successors.
Instruction* const insns1_last = insns1.back();
Instruction* const insns2_last = insns2.back();
CHECK(BPF_CLASS(insns1_last->code) != BPF_JMP &&
BPF_CLASS(insns1_last->code) != BPF_RET);
// Non jumping instructions will always have a valid next instruction.
CHECK(insns1_last->next);
CHECK(insns2_last->next);
return PointerCompare(blocks.find(insns1_last->next)->second,
blocks.find(insns2_last->next)->second,
blocks);
}
// Compare the individual fields for both instructions.
const Instruction& insn1 = **iter1;
const Instruction& insn2 = **iter2;
if (insn1.code == insn2.code) {
if (insn1.k == insn2.k) {
// Only conditional jump instructions use the jt_ptr and jf_ptr
// fields.
if (BPF_CLASS(insn1.code) == BPF_JMP) {
if (BPF_OP(insn1.code) != BPF_JA) {
// Recursively compare the "true" and "false" branches.
// A well-formed BPF program can't have any cycles, so we know
// that our recursive algorithm will ultimately terminate.
// In the unlikely event that the programmer made a mistake and
// went out of the way to give us a cyclic program, we will crash
// with a stack overflow. We are OK with that.
int c = PointerCompare(blocks.find(insn1.jt_ptr)->second,
blocks.find(insn2.jt_ptr)->second,
blocks);
if (c == 0) {
c = PointerCompare(blocks.find(insn1.jf_ptr)->second,
blocks.find(insn2.jf_ptr)->second,
blocks);
if (c == 0) {
continue;
} else {
return c;
}
} else {
return c;
}
} else {
int c = PointerCompare(blocks.find(insn1.jt_ptr)->second,
blocks.find(insn2.jt_ptr)->second,
blocks);
if (c == 0) {
continue;
} else {
return c;
}
}
} else {
continue;
}
} else {
return insn1.k - insn2.k;
}
} else {
if (insn1.code != insn2.code) {
return insn1.code - insn2.code;
}
if (insn1.k != insn2.k) {
return insn1.k - insn2.k;
}
// Sanity check: If we're looking at a JMP or RET instruction, by definition
// it should be the last instruction of the basic block.
if (BPF_CLASS(insn1.code) == BPF_JMP || BPF_CLASS(insn1.code) == BPF_RET) {
CHECK_EQ(insns1.back(), &insn1);
CHECK_EQ(insns2.back(), &insn2);
}
// RET instructions terminate execution, and only JMP instructions use the
// jt_ptr and jf_ptr fields. Anything else can continue to the next
// instruction in the basic block.
if (BPF_CLASS(insn1.code) == BPF_RET) {
return 0;
} else if (BPF_CLASS(insn1.code) != BPF_JMP) {
continue;
}
// Recursively compare the "true" and "false" branches.
// A well-formed BPF program can't have any cycles, so we know
// that our recursive algorithm will ultimately terminate.
// In the unlikely event that the programmer made a mistake and
// went out of the way to give us a cyclic program, we will crash
// with a stack overflow. We are OK with that.
if (BPF_OP(insn1.code) != BPF_JA) {
int c = PointerCompare(blocks.find(insn1.jf_ptr)->second,
blocks.find(insn2.jf_ptr)->second,
blocks);
if (c != 0) {
return c;
}
}
return PointerCompare(blocks.find(insn1.jt_ptr)->second,
blocks.find(insn2.jt_ptr)->second,
blocks);
}
}

Просмотреть файл

@ -9,10 +9,10 @@
#include <set>
#include <vector>
#include "sandbox/linux/sandbox_export.h"
#include "sandbox/linux/seccomp-bpf/basicblock.h"
#include "sandbox/linux/seccomp-bpf/instruction.h"
#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
#include "sandbox/sandbox_export.h"
namespace sandbox {

Просмотреть файл

@ -26,12 +26,15 @@
#include <time.h>
#include <unistd.h>
#include "base/macros.h"
#include "base/posix/eintr_wrapper.h"
#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
#include "sandbox/linux/seccomp-bpf/sandbox_bpf_policy.h"
#include "sandbox/linux/services/linux_syscalls.h"
using sandbox::ErrorCode;
using sandbox::SandboxBPF;
using sandbox::SandboxBPFPolicy;
using sandbox::arch_seccomp_data;
#define ERR EPERM
@ -237,7 +240,17 @@ intptr_t DefaultHandler(const struct arch_seccomp_data& data, void *) {
return -ERR;
}
ErrorCode Evaluator(SandboxBPF* sandbox, int sysno, void *) {
class DemoPolicy : public SandboxBPFPolicy {
public:
DemoPolicy() {}
virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox,
int sysno) const OVERRIDE;
private:
DISALLOW_COPY_AND_ASSIGN(DemoPolicy);
};
ErrorCode DemoPolicy::EvaluateSyscall(SandboxBPF* sandbox, int sysno) const {
switch (sysno) {
#if defined(__NR_accept)
case __NR_accept: case __NR_accept4:
@ -420,7 +433,7 @@ int main(int argc, char *argv[]) {
}
SandboxBPF sandbox;
sandbox.set_proc_fd(proc_fd);
sandbox.SetSandboxPolicyDeprecated(Evaluator, NULL);
sandbox.SetSandboxPolicy(new DemoPolicy());
if (!sandbox.StartSandbox(SandboxBPF::PROCESS_SINGLE_THREADED)) {
fprintf(stderr, "StartSandbox() failed");
_exit(1);

Просмотреть файл

@ -22,7 +22,7 @@ void Die::ExitGroup() {
// Especially, since we are dealing with system call filters. Continuing
// execution would be very bad in most cases where ExitGroup() gets called.
// So, we'll try a few other strategies too.
SandboxSyscall(__NR_exit_group, 1);
Syscall::Call(__NR_exit_group, 1);
// We have no idea what our run-time environment looks like. So, signal
// handlers might or might not do the right thing. Try to reset settings
@ -30,7 +30,7 @@ void Die::ExitGroup() {
// succeeded in doing so. Nonetheless, triggering a fatal signal could help
// us terminate.
signal(SIGSEGV, SIG_DFL);
SandboxSyscall(__NR_prctl, PR_SET_DUMPABLE, (void*)0, (void*)0, (void*)0);
Syscall::Call(__NR_prctl, PR_SET_DUMPABLE, (void*)0, (void*)0, (void*)0);
if (*(volatile char*)0) {
}
@ -40,7 +40,7 @@ void Die::ExitGroup() {
// We in fact retry the system call inside of our loop so that it will
// stand out when somebody tries to diagnose the problem by using "strace".
for (;;) {
SandboxSyscall(__NR_exit_group, 1);
Syscall::Call(__NR_exit_group, 1);
}
}
@ -75,7 +75,7 @@ void Die::LogToStderr(const char* msg, const char* file, int line) {
// No need to loop. Short write()s are unlikely and if they happen we
// probably prefer them over a loop that blocks.
ignore_result(
HANDLE_EINTR(SandboxSyscall(__NR_write, 2, s.c_str(), s.length())));
HANDLE_EINTR(Syscall::Call(__NR_write, 2, s.c_str(), s.length())));
}
}

Просмотреть файл

@ -6,7 +6,7 @@
#define SANDBOX_LINUX_SECCOMP_BPF_DIE_H__
#include "base/basictypes.h"
#include "sandbox/linux/sandbox_export.h"
#include "sandbox/sandbox_export.h"
namespace sandbox {

Просмотреть файл

@ -18,6 +18,11 @@ ErrorCode::ErrorCode(int err) {
error_type_ = ET_SIMPLE;
break;
default:
if ((err & ~SECCOMP_RET_DATA) == ERR_TRACE) {
err_ = SECCOMP_RET_TRACE + (err & SECCOMP_RET_DATA);
error_type_ = ET_SIMPLE;
break;
}
SANDBOX_DIE("Invalid use of ErrorCode object");
}
}

Просмотреть файл

@ -5,9 +5,9 @@
#ifndef SANDBOX_LINUX_SECCOMP_BPF_ERRORCODE_H__
#define SANDBOX_LINUX_SECCOMP_BPF_ERRORCODE_H__
#include "sandbox/linux/sandbox_export.h"
#include "sandbox/linux/seccomp-bpf/linux_seccomp.h"
#include "sandbox/linux/seccomp-bpf/trap.h"
#include "sandbox/sandbox_export.h"
namespace sandbox {
@ -30,6 +30,12 @@ class SANDBOX_EXPORT ErrorCode {
// "errno" (see below) value instead.
ERR_ALLOWED = 0x04000000,
// If the progress is being ptraced with PTRACE_O_TRACESECCOMP, then the
// tracer will be notified of a PTRACE_EVENT_SECCOMP and allowed to change
// or skip the system call. The lower 16 bits of err will be available to
// the tracer via PTRACE_GETEVENTMSG.
ERR_TRACE = 0x08000000,
// Deny the system call with a particular "errno" value.
// N.B.: It is also possible to return "0" here. That would normally
// indicate success, but it won't actually run the system call.

Просмотреть файл

@ -24,6 +24,17 @@ SANDBOX_TEST(ErrorCode, ErrnoConstructor) {
SandboxBPF sandbox;
ErrorCode e3 = sandbox.Trap(NULL, NULL);
SANDBOX_ASSERT((e3.err() & SECCOMP_RET_ACTION) == SECCOMP_RET_TRAP);
uint16_t data = 0xdead;
ErrorCode e4(ErrorCode::ERR_TRACE + data);
SANDBOX_ASSERT(e4.err() == SECCOMP_RET_TRACE + data);
}
SANDBOX_DEATH_TEST(ErrorCode,
InvalidSeccompRetTrace,
DEATH_MESSAGE("Invalid use of ErrorCode object")) {
// Should die if the trace data does not fit in 16 bits.
ErrorCode e(ErrorCode::ERR_TRACE + (1 << 16));
}
SANDBOX_TEST(ErrorCode, Trap) {

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше