mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-18 15:55:36 +00:00
Bug 1041775 Part 1: Update Chromium sandbox code to commit 9522fad406dd161400daa518075828e47bd47f60. r=jld,aklotz
--HG-- rename : security/sandbox/chromium/sandbox/linux/sandbox_export.h => security/sandbox/chromium/sandbox/sandbox_export.h
This commit is contained in:
parent
50c3d078f0
commit
af79dfc438
@ -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.
|
||||
|
5
security/sandbox/chromium-commit-status.txt
Normal file
5
security/sandbox/chromium-commit-status.txt
Normal file
@ -0,0 +1,5 @@
|
||||
Chromium Commit Directory / File (relative to security/sandbox/)
|
||||
---------------------------------------- ------------------------------------------------
|
||||
9522fad406dd161400daa518075828e47bd47f60 build
|
||||
9522fad406dd161400daa518075828e47bd47f60 chromium
|
||||
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.)
|
||||
@ -115,9 +137,11 @@
|
||||
// method in the parent class.
|
||||
// Use like:
|
||||
// virtual void foo() OVERRIDE;
|
||||
#if defined(COMPILER_MSVC)
|
||||
#if defined(__clang__) || defined(COMPILER_MSVC)
|
||||
#define OVERRIDE override
|
||||
#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 OVERRIDE override
|
||||
#else
|
||||
#define OVERRIDE
|
||||
@ -128,10 +152,11 @@
|
||||
// Use like:
|
||||
// virtual void foo() FINAL;
|
||||
// class B FINAL : public A {};
|
||||
#if defined(COMPILER_MSVC)
|
||||
// TODO(jered): Change this to "final" when chromium no longer uses MSVC 2010.
|
||||
#define FINAL sealed
|
||||
#elif defined(__clang__)
|
||||
#if defined(__clang__) || defined(COMPILER_MSVC)
|
||||
#define FINAL final
|
||||
#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 +191,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 +203,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
|
34
security/sandbox/chromium/base/shim/base/win/registry.h
Normal file
34
security/sandbox/chromium/base/shim/base/win/registry.h
Normal file
@ -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.
|
||||
|
||||
|
214
security/sandbox/chromium/base/strings/string_split.cc
Normal file
214
security/sandbox/chromium/base/strings/string_split.cc
Normal file
@ -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
|
82
security/sandbox/chromium/base/strings/string_split.h
Normal file
82
security/sandbox/chromium/base/strings/string_split.h
Normal file
@ -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_
|
892
security/sandbox/chromium/base/strings/string_util.cc
Normal file
892
security/sandbox/chromium/base/strings/string_util.cc
Normal file
@ -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, ®istration_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) {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user