blob: 7267c89f79a5c1ecb929f9756602233071bd1934 [file] [log] [blame]
// Copyright 2014 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "third_party/skia/include/core/SkOSFile.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/optional.h"
#include "base/path_service.h"
// Implement functionality declared in SkOSFile.h via primitives provided
// by Chromium. In doing this, we need only ensure that support for Chromium
// file utilities is working and then Skia file utilities will also work.
namespace {
base::PlatformFile ToPlatformFile(SkFILE* sk_file) {
#if defined(OS_STARBOARD)
// PlatformFile is a pointer type in Starboard, so we cannot use static_cast
// from intptr_t.
return reinterpret_cast<base::PlatformFile>(sk_file);
#else
// PlatformFile is an int in POSIX Emulation, so we must use a static_cast
// from intptr_t.
return static_cast<base::PlatformFile>(reinterpret_cast<intptr_t>(sk_file));
#endif
}
SkFILE* ToSkFILE(base::PlatformFile platform_file) {
return reinterpret_cast<SkFILE*>(platform_file);
}
int ToPlatformFlags(SkFILE_Flags sk_flags) {
int flags = 0;
if (sk_flags & kRead_SkFILE_Flag) {
if (sk_flags & kWrite_SkFILE_Flag) {
flags |= base::PLATFORM_FILE_WRITE;
}
flags |= base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ;
} else if (sk_flags & kWrite_SkFILE_Flag) {
flags |= base::PLATFORM_FILE_CREATE_ALWAYS | base::PLATFORM_FILE_WRITE;
}
return flags;
}
} // namespace
SkFILE* sk_fopen(const char path[], SkFILE_Flags sk_flags) {
base::PlatformFile platform_file = base::CreatePlatformFile(
FilePath(path), ToPlatformFlags(sk_flags), NULL, NULL);
if (platform_file == base::kInvalidPlatformFileValue) {
return NULL;
}
return ToSkFILE(platform_file);
}
void sk_fclose(SkFILE* sk_file) {
SkASSERT(sk_file);
base::ClosePlatformFile(ToPlatformFile(sk_file));
}
size_t sk_fgetsize(SkFILE* sk_file) {
SkASSERT(sk_file);
base::PlatformFile file = ToPlatformFile(sk_file);
// Save current position so we can restore it.
int64_t current_position =
SeekPlatformFile(file, base::PLATFORM_FILE_FROM_CURRENT, 0);
if (current_position < 0) {
return 0;
}
// Find the file size by seeking to the end.
int64_t size = base::SeekPlatformFile(file, base::PLATFORM_FILE_FROM_END, 0);
if (size < 0) {
size = 0;
}
// Restore original file position.
SeekPlatformFile(file, base::PLATFORM_FILE_FROM_BEGIN, current_position);
return size;
}
bool sk_frewind(SkFILE* sk_file) {
SkASSERT(sk_file);
base::PlatformFile file = ToPlatformFile(sk_file);
int64_t position = SeekPlatformFile(file, base::PLATFORM_FILE_FROM_BEGIN, 0);
return position == 0;
}
size_t sk_fread(void* buffer, size_t byteCount, SkFILE* sk_file) {
SkASSERT(sk_file);
base::PlatformFile file = ToPlatformFile(sk_file);
return base::ReadPlatformFileAtCurrentPos(
file, reinterpret_cast<char*>(buffer), byteCount);
}
size_t sk_fwrite(const void* buffer, size_t byteCount, SkFILE* sk_file) {
SkASSERT(sk_file);
base::PlatformFile file = ToPlatformFile(sk_file);
return base::WritePlatformFileAtCurrentPos(
file, reinterpret_cast<const char*>(buffer), byteCount);
}
char* sk_fgets(char* str, int size, SkFILE* sk_file) {
SkASSERT(sk_file);
char* p = str;
size--;
while (size > 0) {
if (1 != sk_fread(p, 1, sk_file)) {
break;
}
size--;
char c = *p++;
if (c == '\n') {
break;
}
}
if (p == str) {
// Didn't read any characters.
return NULL;
}
*p = '\0';
return str;
}
void sk_fflush(SkFILE* sk_file) {
SkASSERT(sk_file);
base::PlatformFile file = ToPlatformFile(sk_file);
base::FlushPlatformFile(file);
}
bool sk_fseek(SkFILE* sk_file, size_t position) {
SkASSERT(sk_file);
base::PlatformFile file = ToPlatformFile(sk_file);
int64_t new_position =
SeekPlatformFile(file, base::PLATFORM_FILE_FROM_BEGIN, position);
return new_position == position;
}
bool sk_fmove(SkFILE* sk_file, long position) { // NOLINT[runtime/int]
SkASSERT(sk_file);
base::PlatformFile file = ToPlatformFile(sk_file);
int64_t new_position =
SeekPlatformFile(file, base::PLATFORM_FILE_FROM_CURRENT, position);
return true;
}
size_t sk_ftell(SkFILE* sk_file) {
SkASSERT(sk_file);
base::PlatformFile file = ToPlatformFile(sk_file);
return SeekPlatformFile(file, base::PLATFORM_FILE_FROM_CURRENT, 0);
}
void* sk_fmmap(SkFILE* sk_file, size_t* length) {
// Not supported, but clients may try to call to see if it is supported.
return NULL;
}
void* sk_fdmmap(int fd, size_t* length) {
NOTREACHED() << __FUNCTION__;
return NULL;
}
void sk_fmunmap(const void* addr, size_t length) {
NOTREACHED() << __FUNCTION__;
}
bool sk_fidentical(SkFILE* sk_file_a, SkFILE* sk_file_b) {
NOTREACHED() << __FUNCTION__;
return false;
}
int sk_fileno(SkFILE* sk_file_a) {
NOTREACHED() << __FUNCTION__;
return -1;
}
bool sk_exists(const char* path, SkFILE_Flags /*flags*/) {
return file_util::PathExists(FilePath(path));
}
bool sk_isdir(const char* path) {
return file_util::DirectoryExists(FilePath(path));
}
int sk_feof(SkFILE* sk_file) {
SkASSERT(sk_file);
size_t size = sk_fgetsize(sk_file);
size_t position = sk_ftell(sk_file);
return (position >= size);
}
bool sk_mkdir(const char* path) {
// Strange linking error on windows when calling file_util::CreateDirectory,
// having something to do with a system #define. This isn't used, anyway.
NOTREACHED() << __FUNCTION__;
return false;
}
// SkOSFile::Iter::Pimpl represents our private implementation of Skia's file
// iterator class. We implement it in terms of Chromium's FileEnumerator,
// which provides very similar functionality.
class SkOSFile::Iter::Pimpl {
public:
Pimpl(const char path[], const char suffix[])
: path_(path ? path : ""), suffix_(suffix ? suffix : "") {}
bool next(SkString* name, bool get_dir) {
if (file_enumerator_ == base::nullopt) {
// We lazily initialize the FileEnumerator here because we need to wait
// until next() is called before we know whether we're looking for
// directories or files.
file_enumerator_.emplace(FilePath(path_.c_str()), false,
get_dir ? file_util::FileEnumerator::DIRECTORIES
: file_util::FileEnumerator::FILES);
get_dir_ = get_dir;
} else {
DCHECK_EQ(*get_dir_, get_dir)
<< "get_dir should be consistent between calls.";
}
while (true) {
FilePath next_file = file_enumerator_->Next();
if (next_file.empty()) {
// We are done iterating, return false to indicate that.
return false;
} else {
// Check if this file has the correct suffix.
const FilePath::StringType& file_str = next_file.value();
if (std::equal(suffix_.rbegin(), suffix_.rend(), file_str.rbegin())) {
*name = SkString(next_file.BaseName().value().c_str());
return true;
}
// If the file does not have the correct suffix, continue to the next
// file.
}
}
}
private:
base::optional<file_util::FileEnumerator> file_enumerator_;
// Only valid if file_enumerator_ is constructed. Specifies whether we are
// searching for directories or files.
base::optional<bool> get_dir_;
std::string path_;
std::string suffix_;
};
SkOSFile::Iter::Iter() {}
SkOSFile::Iter::Iter(const char path[], const char suffix[])
: fPimpl(new Pimpl(path, suffix)) {}
SkOSFile::Iter::~Iter() {}
void SkOSFile::Iter::reset(const char path[], const char suffix[]) {
fPimpl.reset(new Pimpl(path, suffix));
}
bool SkOSFile::Iter::next(SkString* name, bool getDir) {
if (fPimpl.get()) {
return fPimpl->next(name, getDir);
} else {
return false;
}
}