blob: e6326103141cb19514efd42b4a7119664c11db6d [file] [log] [blame]
// Copyright 2017 The Cobalt Authors. 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 "starboard/directory.h"
#include <windows.h>
#include "starboard/common/log.h"
#include "starboard/common/string.h"
#include "starboard/configuration_constants.h"
#include "starboard/shared/win32/directory_internal.h"
#include "starboard/shared/win32/wchar_utils.h"
namespace {
// One of the entries of FILE_ID_BOTH_DIR_INFO is a file path, so make the
// buffer at-least one path big.
const std::size_t kDirectoryInfoBufferSize =
kSbFileMaxPath + sizeof(FILE_ID_BOTH_DIR_INFO);
std::deque<std::string> GetDirectoryEntries(HANDLE directory_handle) {
// According to
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa364226(v=vs.85).aspx,
// FILE_ID_BOTH_DIR_INFO must be aligned on a DWORDLONG boundary.
alignas(sizeof(DWORDLONG)) std::vector<char> directory_info_buffer(
kDirectoryInfoBufferSize);
std::deque<std::string> entries;
BOOL directory_info_success = GetFileInformationByHandleEx(
directory_handle, FileIdBothDirectoryInfo, directory_info_buffer.data(),
static_cast<int>(directory_info_buffer.size()));
if (!directory_info_success) {
return entries;
}
const char* directory_info_pointer = directory_info_buffer.data();
DWORD next_entry_offset = 0;
do {
auto directory_info =
reinterpret_cast<const FILE_ID_BOTH_DIR_INFO*>(directory_info_pointer);
// FileName is in Unicode, so divide by 2 to get the real length.
DWORD number_characters_in_filename = directory_info->FileNameLength / 2;
std::string ascii_path = starboard::shared::win32::wchar_tToUTF8(
directory_info->FileName, number_characters_in_filename);
SB_DCHECK(ascii_path.size() == number_characters_in_filename);
bool is_dotted_directory =
!ascii_path.compare(".") || !ascii_path.compare("..");
if (!is_dotted_directory) {
entries.emplace_back(std::move(ascii_path));
}
next_entry_offset = directory_info->NextEntryOffset;
directory_info_pointer += next_entry_offset;
} while (next_entry_offset != 0);
return entries;
}
} // namespace
bool SbDirectoryGetNext(SbDirectory directory,
char* out_entry,
size_t out_entry_size) {
if (!SbDirectoryIsValid(directory) || out_entry == nullptr ||
out_entry_size < kSbFileMaxName) {
return false;
}
auto& next_directory_entries = directory->next_directory_entries;
if (next_directory_entries.empty()) {
next_directory_entries = GetDirectoryEntries(directory->directory_handle);
}
if (next_directory_entries.empty()) {
return false;
}
bool success = true;
if (starboard::strlcpy(out_entry, next_directory_entries.rbegin()->c_str(),
static_cast<int>(out_entry_size)) >= out_entry_size) {
success = false;
}
directory->next_directory_entries.pop_back();
return success;
}