diff --git a/src/native/corehost/hostmisc/pal.h b/src/native/corehost/hostmisc/pal.h index bde8446cc22cdf..4189f77d934fc0 100644 --- a/src/native/corehost/hostmisc/pal.h +++ b/src/native/corehost/hostmisc/pal.h @@ -6,7 +6,6 @@ #include #include -#include #include #include #include @@ -118,14 +117,6 @@ namespace pal typedef wchar_t char_t; typedef std::wstring string_t; typedef std::wstringstream stringstream_t; - // TODO: Agree on the correct encoding of the files: The PoR for now is to - // temporarily wchar for Windows and char for Unix. Current implementation - // implicitly expects the contents on both Windows and Unix as char and - // converts them to wchar in code for Windows. This line should become: - // typedef std::basic_ifstream ifstream_t. - typedef std::basic_ifstream ifstream_t; - typedef std::istreambuf_iterator istreambuf_iterator_t; - typedef std::basic_istream istream_t; typedef HRESULT hresult_t; typedef HMODULE dll_t; typedef FARPROC proc_t; @@ -207,9 +198,6 @@ namespace pal typedef char char_t; typedef std::string string_t; typedef std::stringstream stringstream_t; - typedef std::basic_ifstream ifstream_t; - typedef std::istreambuf_iterator istreambuf_iterator_t; - typedef std::basic_istream istream_t; typedef int hresult_t; typedef void* dll_t; typedef void* proc_t; diff --git a/src/native/corehost/hostmisc/pal.unix.cpp b/src/native/corehost/hostmisc/pal.unix.cpp index 613902b5eaf3ac..0ffc859cb9a5a0 100644 --- a/src/native/corehost/hostmisc/pal.unix.cpp +++ b/src/native/corehost/hostmisc/pal.unix.cpp @@ -456,7 +456,7 @@ bool get_install_location_from_file(const pal::string_t& file_path, bool& file_f { file_found = true; bool install_location_found = false; - FILE* install_location_file = pal::file_open(file_path, "r"); + FILE* install_location_file = pal::file_open(file_path, _X("r")); if (install_location_file != nullptr) { if (!get_line_from_file(install_location_file, install_location)) @@ -819,12 +819,10 @@ pal::string_t pal::get_current_os_rid_platform() { // Read the file to get ID and VERSION_ID data that will be used // to construct the RID. - std::fstream fsVersionFile; - - fsVersionFile.open(versionFile, std::fstream::in); + FILE* fsVersionFile = pal::file_open(versionFile, _X("r")); // Proceed only if we were able to open the file - if (fsVersionFile.good()) + if (fsVersionFile != nullptr) { pal::string_t line; pal::string_t strID(_X("ID=")); @@ -834,11 +832,8 @@ pal::string_t pal::get_current_os_rid_platform() bool fFoundID = false, fFoundVersion = false; - // Read the first line - std::getline(fsVersionFile, line); - // Loop until we are at the end of file - while (!fsVersionFile.eof()) + while (get_line_from_file(fsVersionFile, line)) { // Look for ID if we have not found it already if (!fFoundID) @@ -872,13 +867,10 @@ pal::string_t pal::get_current_os_rid_platform() // We have everything we need to form the RID - break out of the loop. break; } - - // Read the next line - std::getline(fsVersionFile, line); } // Close the file now that we are done with it. - fsVersionFile.close(); + fclose(fsVersionFile); if (fFoundID) { diff --git a/src/native/corehost/json_parser.cpp b/src/native/corehost/json_parser.cpp index 6ea3cdc24f5486..748f566e55b414 100644 --- a/src/native/corehost/json_parser.cpp +++ b/src/native/corehost/json_parser.cpp @@ -17,33 +17,9 @@ namespace { -// Try to match 0xEF 0xBB 0xBF byte sequence (no endianness here.) -std::streampos get_utf8_bom_length(pal::istream_t& stream) -{ - if (stream.eof()) - { - return 0; - } - - auto peeked = stream.peek(); - if (peeked == EOF || ((peeked & 0xFF) != 0xEF)) - { - return 0; - } - - unsigned char bytes[3]; - stream.read(reinterpret_cast(bytes), 3); - if ((stream.gcount() < 3) || (bytes[1] != 0xBB) || (bytes[2] != 0xBF)) - { - return 0; - } - - return 3; -} - void get_line_column_from_offset(const char* data, uint64_t size, size_t offset, int *line, int *column) { - assert(offset < size); + assert(offset <= size); *line = *column = 1; @@ -68,12 +44,6 @@ void get_line_column_from_offset(const char* data, uint64_t size, size_t offset, } // empty namespace -void json_parser_t::realloc_buffer(size_t size) -{ - m_json.resize(size + 1); - m_json[size] = '\0'; -} - bool json_parser_t::parse_raw_data(char* data, int64_t size, const pal::string_t& context) { assert(data != nullptr); @@ -115,7 +85,7 @@ bool json_parser_t::parse_file(const pal::string_t& path) { // This code assumes that the caller has checked that the file `path` exists // either within the bundle, or as a real file on disk. - assert(m_bundle_data == nullptr); + assert(m_data == nullptr); assert(m_bundle_location == nullptr); if (bundle::info_t::is_single_file_bundle()) @@ -123,43 +93,56 @@ bool json_parser_t::parse_file(const pal::string_t& path) // Due to in-situ parsing on Linux, // * The json file is mapped as copy-on-write. // * The mapping cannot be immediately released, and will be unmapped by the json_parser destructor. - m_bundle_data = bundle::info_t::config_t::map(path, m_bundle_location); + m_data = bundle::info_t::config_t::map(path, m_bundle_location); - if (m_bundle_data != nullptr) + if (m_data != nullptr) { - bool result = parse_raw_data(m_bundle_data, m_bundle_location->size, path); - return result; + m_size = (size_t)m_bundle_location->size; } } - pal::ifstream_t file{ path }; - if (!file.good()) + if (m_data == nullptr) { - trace::error(_X("Cannot use file stream for [%s]: %s"), path.c_str(), pal::strerror(errno).c_str()); - return false; - } +#ifdef _WIN32 + // We can't use in-situ parsing on Windows, as JSON data is encoded in + // UTF-8 and the host expects wide strings. + // We do not need copy-on-write, so read-only mapping will be enough. + m_data = (char*)pal::mmap_read(path, &m_size); +#else // _WIN32 + m_data = (char*)pal::mmap_copy_on_write(path, &m_size); +#endif // _WIN32 - auto current_pos = ::get_utf8_bom_length(file); - file.seekg(0, file.end); - auto stream_size = file.tellg(); - if (stream_size == -1) - { - trace::error(_X("Failed to get size of file [%s]"), path.c_str()); - return false; + if (m_data == nullptr) + { + trace::error(_X("Cannot use file stream for [%s]: %s"), path.c_str(), pal::strerror(errno).c_str()); + return false; + } } - file.seekg(current_pos, file.beg); + char *data = m_data; + size_t size = m_size; - realloc_buffer(static_cast(stream_size - current_pos)); - file.read(m_json.data(), stream_size - current_pos); + // Skip over UTF-8 BOM, if present + if (size >= 3 && data[0] == 0xEF && data[1] == 0xBB && data[1] == 0xBF) + { + size -= 3; + data += 3; + } - return parse_raw_data(m_json.data(), m_json.size(), path); + return parse_raw_data(data, size, path); } json_parser_t::~json_parser_t() { - if (m_bundle_data != nullptr) + if (m_data != nullptr) { - bundle::info_t::config_t::unmap(m_bundle_data, m_bundle_location); + if (m_bundle_location != nullptr) + { + bundle::info_t::config_t::unmap(m_data, m_bundle_location); + } + else + { + pal::munmap((void*)m_data, m_size); + } } } diff --git a/src/native/corehost/json_parser.h b/src/native/corehost/json_parser.h index e57bfa9e2fd7f8..eb0b5d19a67963 100644 --- a/src/native/corehost/json_parser.h +++ b/src/native/corehost/json_parser.h @@ -40,24 +40,22 @@ class json_parser_t { bool parse_file(const pal::string_t& path); json_parser_t() - : m_bundle_data(nullptr) + : m_data(nullptr) , m_bundle_location(nullptr) {} ~json_parser_t(); private: - // This is a vector of char and not pal::char_t because JSON data - // parsed by this class is always encoded in UTF-8. On Windows, - // where wide strings are used, m_json is kept in UTF-8, but converted + char* m_data; // The memory mapped bytes of the file + size_t m_size; // Size of the mapped memory + + // On Windows, where wide strings are used, m_data is kept in UTF-8, but converted // to UTF-16 by m_document during load. - std::vector m_json; document_t m_document; - // If a json file is parsed from a single-file bundle, the following two fields represent: - char* m_bundle_data; // The memory mapped bytes of the application bundle. - const bundle::location_t* m_bundle_location; // Location of this json file within the bundle. - - void realloc_buffer(size_t size); + // If a json file is parsed from a single-file bundle, the following fields represents + // the location of this json file within the bundle. + const bundle::location_t* m_bundle_location; }; #endif // __JSON_PARSER_H__ diff --git a/src/native/corehost/test/nativehost/host_context_test.cpp b/src/native/corehost/test/nativehost/host_context_test.cpp index cf05ff2cc5d9de..85e62d15c6af7b 100644 --- a/src/native/corehost/test/nativehost/host_context_test.cpp +++ b/src/native/corehost/test/nativehost/host_context_test.cpp @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. #include +#include #include #include #include